From ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250 Mon Sep 17 00:00:00 2001 From: Apple <opensource@apple.com> Date: Wed, 5 Aug 2015 00:41:38 +0000 Subject: [PATCH] JavaScriptCore-7601.1.46.3.tar.gz --- API/JSAPIWrapperObject.h | 2 - API/JSAPIWrapperObject.mm | 4 +- API/JSBase.cpp | 18 +- API/JSBase.h | 9 - API/JSCallbackConstructor.cpp | 2 +- API/JSCallbackConstructor.h | 2 +- API/JSCallbackFunction.cpp | 2 +- API/JSCallbackObject.cpp | 15 +- API/JSCallbackObject.h | 24 +- API/JSCallbackObjectFunctions.h | 40 +- API/JSClassRef.cpp | 12 +- API/JSClassRef.h | 8 +- API/JSContext.h | 4 - API/JSContext.mm | 2 +- API/JSContextRef.cpp | 67 +- API/JSContextRef.h | 2 +- API/JSContextRefInspectorSupport.h | 43 + API/JSManagedValue.h | 4 - API/JSManagedValue.mm | 1 + API/JSObjectRef.cpp | 147 +- API/JSProfilerPrivate.cpp | 6 +- API/JSRemoteInspector.cpp | 78 + API/JSRemoteInspector.h | 49 + API/JSRetainPtr.h | 10 + API/JSScriptRef.cpp | 32 +- API/JSStringRef.cpp | 14 +- API/JSStringRefCF.cpp | 8 +- API/JSValue.h | 28 +- API/JSValue.mm | 22 +- API/JSValueRef.cpp | 135 +- API/JSValueRef.h | 18 + API/JSVirtualMachine.h | 4 - API/JSVirtualMachine.mm | 1 + API/JSVirtualMachineInternal.h | 2 + API/JSWeakObjectMapRefInternal.h | 9 +- API/JSWeakObjectMapRefPrivate.cpp | 3 +- API/JSWrapperMap.mm | 108 +- API/ObjCCallbackFunction.h | 6 +- API/ObjCCallbackFunction.mm | 147 +- API/ObjcRuntimeExtras.h | 3 +- API/OpaqueJSString.cpp | 15 +- API/OpaqueJSString.h | 22 +- API/WebKitAvailability.h | 12 +- API/tests/CompareAndSwapTest.cpp | 118 + .../tests/CompareAndSwapTest.h | 31 +- API/tests/DateTests.mm | 4 - API/tests/ExecutionTimeLimitTest.cpp | 268 + API/tests/ExecutionTimeLimitTest.h | 40 + API/tests/GlobalContextWithFinalizerTest.cpp | 56 + API/tests/GlobalContextWithFinalizerTest.h | 42 + .../tests/Regress141275.h | 14 +- API/tests/Regress141275.mm | 388 + API/tests/testapi.c | 296 +- API/tests/testapi.js | 14 + API/tests/testapi.mm | 156 +- CMakeLists.txt | 457 +- ChangeLog | 16919 +------- ChangeLog-2014-10-07 | 30352 ++++++++++++++ ChangeLog-2015-07-23 | 34401 ++++++++++++++++ Configurations/Base.xcconfig | 74 +- .../CompileRuntimeToLLVMIR.xcconfig | 2 - Configurations/DebugRelease.xcconfig | 22 +- Configurations/FeatureDefines.xcconfig | 253 +- Configurations/JSC.xcconfig | 3 +- Configurations/JavaScriptCore.xcconfig | 17 +- Configurations/LLVMForJSC.xcconfig | 37 +- Configurations/ToolExecutable.xcconfig | 13 +- Configurations/Version.xcconfig | 19 +- Configurations/iOS.xcconfig | 1 - DerivedSources.make | 87 +- Info.plist | 2 +- JavaScriptCore.order | 62 +- JavaScriptCore.vcxproj/JavaScriptCore.proj | 22 +- JavaScriptCore.vcxproj/JavaScriptCore.sln | 100 +- .../JavaScriptCore.submit.sln | 91 +- JavaScriptCore.vcxproj/JavaScriptCore.vcxproj | 380 +- .../JavaScriptCore.vcxproj.filters | 882 +- .../JavaScriptCoreCommon.props | 4 +- JavaScriptCore.vcxproj/JavaScriptCoreDLL.cpp | 50 + .../JavaScriptCoreGenerated.make | 14 +- .../JavaScriptCoreGenerated.vcxproj | 12 +- .../JavaScriptCorePostBuild.cmd | 2 +- .../JavaScriptCorePreBuild.cmd | 4 +- .../LLInt/LLIntAssembly/LLIntAssembly.make | 2 +- .../LLInt/LLIntAssembly/LLIntAssembly.vcxproj | 10 +- .../LLIntAssembly/build-LLIntAssembly.pl | 2 +- .../LLIntDesiredOffsets.make | 2 +- .../LLIntDesiredOffsets.vcxproj | 10 +- .../build-LLIntDesiredOffsets.pl | 2 +- .../LLIntOffsetsExtractor.vcxproj | 8 +- .../build-generated-files.pl | 12 +- JavaScriptCore.vcxproj/copy-files.cmd | 39 +- .../jsc/DLLLauncherMain.cpp | 244 + .../jsc/DLLLauncherWinCairo.props | 12 + JavaScriptCore.vcxproj/jsc/jsc.vcxproj | 80 +- JavaScriptCore.vcxproj/jsc/jscCommon.props | 4 +- .../jsc/jscLauncher.vcxproj | 206 + .../jsc/jscLauncherPostBuild.cmd | 1 + .../jsc/jscLauncherPreBuild.cmd | 6 + .../jsc/jscLauncherPreLink.cmd | 0 JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd | 2 +- .../libllvmForJSC/libllvmForJSC.vcxproj | 8 +- .../testRegExp/testRegExp.vcxproj | 80 +- .../testRegExp/testRegExpCommon.props | 4 +- .../testRegExp/testRegExpLauncher.vcxproj | 210 + .../testRegExpLauncherPostBuild.cmd | 3 + .../testRegExp/testRegExpLauncherPreBuild.cmd | 6 + .../testRegExp/testRegExpLauncherPreLink.cmd | 0 .../testRegExp/testRegExpPreBuild.cmd | 2 +- .../testapi/testapi.vcxproj | 38 +- .../testapi/testapi.vcxproj.filters | 4 + .../testapi/testapiCommon.props | 6 +- .../testapi/testapiCommonCFLite.props | 6 +- .../testapi/testapiLauncher.vcxproj | 206 + .../testapi/testapiLauncherPostBuild.cmd | 3 + .../testapi/testapiLauncherPreBuild.cmd | 6 + .../testapi/testapiLauncherPreLink.cmd | 0 .../testapi/testapiPostBuild.cmd | 2 +- .../testapi/testapiPreBuild.cmd | 4 +- JavaScriptCore.xcodeproj/project.pbxproj | 2166 +- KeywordLookupGenerator.py | 6 +- PlatformEfl.cmake | 11 + PlatformGTK.cmake | 21 +- PlatformMac.cmake | 41 + PlatformWin.cmake | 29 + UpdateContents.py | 48 + assembler/ARM64Assembler.h | 60 +- assembler/ARMAssembler.h | 131 +- assembler/ARMv7Assembler.h | 211 +- assembler/AbortReason.h | 3 +- assembler/AbstractMacroAssembler.h | 374 +- assembler/AssemblerBuffer.h | 4 +- assembler/LinkBuffer.cpp | 27 +- assembler/LinkBuffer.h | 12 +- assembler/MacroAssembler.h | 22 +- assembler/MacroAssemblerARM.cpp | 75 +- assembler/MacroAssemblerARM.h | 43 +- assembler/MacroAssemblerARM64.h | 55 +- assembler/MacroAssemblerARMv7.cpp | 73 +- assembler/MacroAssemblerARMv7.h | 51 +- assembler/MacroAssemblerCodeRef.h | 18 +- assembler/MacroAssemblerMIPS.h | 18 +- assembler/MacroAssemblerSH4.h | 106 +- assembler/MacroAssemblerX86.h | 58 +- assembler/MacroAssemblerX86Common.cpp | 123 +- assembler/MacroAssemblerX86Common.h | 63 +- assembler/MacroAssemblerX86_64.h | 102 +- assembler/X86Assembler.h | 190 +- bindings/ScriptFunctionCall.cpp | 8 +- bindings/ScriptFunctionCall.h | 2 +- bindings/ScriptValue.cpp | 24 +- bindings/ScriptValue.h | 5 +- build-symbol-table-index.py | 70 +- build-symbol-table-index.sh | 37 - builtins/Array.prototype.js | 456 +- builtins/ArrayConstructor.js | 109 + builtins/ArrayIterator.prototype.js | 59 + builtins/BuiltinExecutables.cpp | 44 +- builtins/BuiltinExecutables.h | 27 +- builtins/BuiltinNames.h | 43 +- builtins/GlobalObject.js | 57 + builtins/Iterator.prototype.js | 30 + builtins/ObjectConstructor.js | 58 + builtins/Operations.Promise.js | 214 + builtins/Promise.prototype.js | 38 +- builtins/PromiseConstructor.js | 139 + builtins/StringConstructor.js | 59 + builtins/StringIterator.prototype.js | 63 + bytecode/ArrayProfile.cpp | 28 +- bytecode/ArrayProfile.h | 58 +- bytecode/ByValInfo.h | 45 +- bytecode/BytecodeBasicBlock.cpp | 3 - bytecode/BytecodeIntrinsicRegistry.cpp | 54 + bytecode/BytecodeIntrinsicRegistry.h | 56 + bytecode/BytecodeKills.h | 180 + bytecode/BytecodeList.json | 60 +- bytecode/BytecodeLivenessAnalysis.cpp | 199 +- bytecode/BytecodeLivenessAnalysis.h | 14 +- bytecode/BytecodeLivenessAnalysisInlines.h | 23 +- bytecode/BytecodeUseDef.h | 123 +- bytecode/CallEdge.cpp | 37 + bytecode/CallEdge.h | 71 + bytecode/CallLinkInfo.cpp | 66 +- bytecode/CallLinkInfo.h | 233 +- bytecode/CallLinkStatus.cpp | 257 +- bytecode/CallLinkStatus.h | 77 +- bytecode/CallVariant.cpp | 97 + bytecode/CallVariant.h | 203 + bytecode/CodeBlock.cpp | 1331 +- bytecode/CodeBlock.h | 223 +- bytecode/CodeBlockJettisoningWatchpoint.cpp | 4 +- bytecode/CodeBlockJettisoningWatchpoint.h | 2 +- bytecode/CodeOrigin.cpp | 60 +- bytecode/CodeOrigin.h | 103 +- bytecode/ComplexGetStatus.cpp | 78 + bytecode/ComplexGetStatus.h | 120 + ...chpoint.cpp => ConstantStructureCheck.cpp} | 70 +- bytecode/ConstantStructureCheck.h | 74 + bytecode/DFGExitProfile.cpp | 4 +- bytecode/DFGExitProfile.h | 3 +- bytecode/DataFormat.h | 5 +- bytecode/DeferredCompilationCallback.cpp | 22 + bytecode/DeferredCompilationCallback.h | 9 + bytecode/DeferredSourceDump.cpp | 66 + bytecode/DeferredSourceDump.h | 52 + bytecode/EvalCodeCache.h | 10 +- bytecode/ExecutionCounter.cpp | 2 - bytecode/ExecutionCounter.h | 2 +- bytecode/ExitKind.cpp | 23 +- bytecode/ExitKind.h | 24 +- bytecode/FullBytecodeLiveness.h | 22 +- bytecode/GetByIdStatus.cpp | 325 +- bytecode/GetByIdStatus.h | 18 +- bytecode/GetByIdVariant.cpp | 78 +- bytecode/GetByIdVariant.h | 39 +- bytecode/HandlerInfo.h | 62 +- bytecode/Instruction.h | 23 +- bytecode/LLIntCallLinkInfo.h | 2 +- bytecode/LazyOperandValueProfile.cpp | 2 +- bytecode/LazyOperandValueProfile.h | 3 +- bytecode/ObjectAllocationProfile.h | 20 +- bytecode/Operands.h | 23 +- bytecode/OperandsInlines.h | 16 + bytecode/PolymorphicGetByIdList.cpp | 29 +- bytecode/PolymorphicGetByIdList.h | 3 +- bytecode/PolymorphicPutByIdList.cpp | 2 +- bytecode/PolymorphicPutByIdList.h | 15 +- bytecode/PreciseJumpTargets.cpp | 6 - bytecode/PutByIdStatus.cpp | 307 +- bytecode/PutByIdStatus.h | 17 +- bytecode/PutByIdVariant.cpp | 202 +- bytecode/PutByIdVariant.h | 89 +- bytecode/SamplingTool.h | 4 +- bytecode/SpecialPointer.h | 5 + bytecode/SpeculatedType.cpp | 70 +- bytecode/SpeculatedType.h | 60 +- bytecode/StructureSet.cpp | 109 + bytecode/StructureSet.h | 168 +- bytecode/StructureStubClearingWatchpoint.cpp | 6 +- bytecode/StructureStubClearingWatchpoint.h | 14 +- bytecode/StructureStubInfo.cpp | 6 - bytecode/StructureStubInfo.h | 21 +- .../ToThisStatus.cpp | 63 +- bytecode/ToThisStatus.h | 50 + bytecode/TrackedReferences.cpp | 81 + bytecode/TrackedReferences.h | 56 + bytecode/TypeLocation.h | 63 + bytecode/UnlinkedCodeBlock.cpp | 214 +- bytecode/UnlinkedCodeBlock.h | 221 +- bytecode/UnlinkedInstructionStream.cpp | 2 +- bytecode/UnlinkedInstructionStream.h | 2 +- bytecode/ValueRecovery.cpp | 23 +- bytecode/ValueRecovery.h | 29 +- bytecode/VariableWatchpointSet.h | 92 - .../VariableWriteFireDetail.cpp | 18 +- bytecode/VariableWriteFireDetail.h | 55 + ...hpointSetInlines.h => VirtualRegister.cpp} | 55 +- bytecode/VirtualRegister.h | 47 +- bytecode/Watchpoint.cpp | 25 +- bytecode/Watchpoint.h | 146 +- bytecompiler/BytecodeGenerator.cpp | 1763 +- bytecompiler/BytecodeGenerator.h | 430 +- bytecompiler/Label.h | 4 +- bytecompiler/NodesCodegen.cpp | 1474 +- bytecompiler/RegisterID.h | 1 - bytecompiler/StaticPropertyAnalysis.h | 4 +- config.h | 14 +- copy-llvm-ir-to-derived-sources.sh | 8 +- create-llvm-ir-from-source-file.py | 41 + create-symbol-table-index.py | 106 + create_hash_table | 12 +- create_jit_stubs | 101 - create_regex_tables | 10 +- debugger/Breakpoint.h | 2 +- debugger/Debugger.cpp | 85 +- debugger/Debugger.h | 48 +- debugger/DebuggerActivation.cpp | 98 - debugger/DebuggerCallFrame.cpp | 79 +- debugger/DebuggerCallFrame.h | 21 +- debugger/DebuggerEvalEnabler.h | 63 + debugger/DebuggerScope.cpp | 192 + debugger/DebuggerScope.h | 120 + dfg/DFGAbstractHeap.cpp | 4 +- dfg/DFGAbstractHeap.h | 97 +- dfg/DFGAbstractInterpreter.h | 61 +- dfg/DFGAbstractInterpreterInlines.h | 1443 +- dfg/DFGAbstractValue.cpp | 263 +- dfg/DFGAbstractValue.h | 271 +- dfg/DFGAdjacencyList.h | 58 +- dfg/DFGAllocator.h | 15 +- dfg/DFGAnalysis.h | 10 +- dfg/DFGArgumentPosition.h | 14 +- dfg/DFGArgumentsEliminationPhase.cpp | 626 + dfg/DFGArgumentsEliminationPhase.h | 45 + dfg/DFGArgumentsSimplificationPhase.cpp | 797 - dfg/DFGArgumentsUtilities.cpp | 98 + ...uctureChains.h => DFGArgumentsUtilities.h} | 34 +- dfg/DFGArithMode.h | 18 + dfg/DFGArrayMode.cpp | 169 +- dfg/DFGArrayMode.h | 25 +- dfg/DFGArrayifySlowPathGenerator.h | 5 +- dfg/DFGAtTailAbstractState.cpp | 7 +- dfg/DFGAtTailAbstractState.h | 8 +- dfg/DFGAvailability.h | 27 + dfg/DFGAvailabilityMap.cpp | 109 + dfg/DFGAvailabilityMap.h | 91 + dfg/DFGBackwardsPropagationPhase.cpp | 48 +- dfg/DFGBasicBlock.cpp | 43 +- dfg/DFGBasicBlock.h | 130 +- dfg/DFGBasicBlockInlines.h | 12 +- dfg/DFGBinarySwitch.cpp | 198 - dfg/DFGBlockMap.h | 110 + dfg/DFGBlockMapInlines.h | 46 + dfg/DFGBlockSet.cpp | 43 + dfg/DFGBlockSet.h | 151 + dfg/DFGBlockSetInlines.h | 46 + dfg/DFGBlockWorklist.cpp | 86 + dfg/DFGBlockWorklist.h | 184 + dfg/DFGBranchDirection.h | 16 +- dfg/DFGByteCodeParser.cpp | 2511 +- dfg/DFGByteCodeParser.h | 11 +- dfg/DFGCFAPhase.cpp | 69 +- dfg/DFGCFGSimplificationPhase.cpp | 72 +- dfg/DFGCPSRethreadingPhase.cpp | 96 +- dfg/DFGCSEPhase.cpp | 1935 +- dfg/DFGCSEPhase.h | 24 +- dfg/DFGCallArrayAllocatorSlowPathGenerator.h | 2 +- ...llCreateDirectArgumentsSlowPathGenerator.h | 83 + dfg/DFGCapabilities.cpp | 83 +- dfg/DFGCapabilities.h | 17 +- ...alidationPhase.cpp => DFGCleanUpPhase.cpp} | 63 +- dfg/DFGCleanUpPhase.h | 43 + dfg/DFGClobberSet.cpp | 21 +- dfg/DFGClobberSet.h | 6 +- dfg/DFGClobberize.cpp | 37 +- dfg/DFGClobberize.h | 799 +- dfg/DFGCombinedLiveness.cpp | 81 + ...coveryOverride.h => DFGCombinedLiveness.h} | 30 +- dfg/DFGCommon.cpp | 56 +- dfg/DFGCommon.h | 70 +- dfg/DFGCommonData.cpp | 25 +- dfg/DFGCommonData.h | 14 +- dfg/DFGConstantFoldingPhase.cpp | 598 +- dfg/DFGConstantHoistingPhase.cpp | 149 + dfg/DFGConstantHoistingPhase.h | 43 + dfg/DFGCriticalEdgeBreakingPhase.cpp | 2 +- dfg/DFGDCEPhase.cpp | 244 +- dfg/DFGDesiredIdentifiers.cpp | 10 +- dfg/DFGDesiredIdentifiers.h | 8 +- dfg/DFGDesiredWatchpoints.cpp | 26 +- dfg/DFGDesiredWatchpoints.h | 129 +- dfg/DFGDesiredWeakReferences.cpp | 22 +- dfg/DFGDesiredWeakReferences.h | 6 +- dfg/DFGDisassembler.cpp | 2 - dfg/DFGDisassembler.h | 1 + dfg/DFGDoesGC.cpp | 258 + dfg/DFGDoesGC.h | 43 + dfg/DFGDominators.cpp | 465 +- dfg/DFGDominators.h | 168 +- dfg/DFGDriver.cpp | 15 +- dfg/DFGEdge.cpp | 4 +- dfg/DFGEdge.h | 8 +- dfg/DFGEdgeDominates.h | 4 +- dfg/DFGEpoch.cpp | 43 + dfg/DFGEpoch.h | 124 + dfg/DFGFiltrationResult.h | 14 +- dfg/DFGFixupPhase.cpp | 728 +- dfg/DFGFlushFormat.cpp | 5 +- dfg/DFGFlushFormat.h | 28 +- dfg/DFGFlushedAt.cpp | 4 +- dfg/DFGFlushedAt.h | 2 - dfg/DFGForAllKills.h | 190 + dfg/DFGFrozenValue.cpp | 55 + dfg/DFGFrozenValue.h | 129 + dfg/DFGFunctionWhitelist.cpp | 9 +- dfg/DFGGenerationInfo.h | 15 +- dfg/DFGGraph.cpp | 866 +- dfg/DFGGraph.h | 716 +- dfg/DFGHeapLocation.cpp | 150 + dfg/DFGHeapLocation.h | 164 + dfg/DFGInPlaceAbstractState.cpp | 166 +- dfg/DFGInPlaceAbstractState.h | 14 +- dfg/DFGInsertOSRHintsForUpdate.cpp | 60 + dfg/DFGInsertOSRHintsForUpdate.h | 45 + dfg/DFGInsertionSet.h | 63 +- dfg/DFGIntegerCheckCombiningPhase.cpp | 42 +- dfg/DFGIntegerRangeOptimizationPhase.cpp | 1337 + dfg/DFGIntegerRangeOptimizationPhase.h | 47 + dfg/DFGInvalidationPointInjectionPhase.cpp | 15 +- dfg/DFGJITCode.cpp | 31 +- dfg/DFGJITCode.h | 11 +- dfg/DFGJITCompiler.cpp | 172 +- dfg/DFGJITCompiler.h | 59 +- dfg/DFGJITFinalizer.cpp | 14 +- dfg/DFGJITFinalizer.h | 4 +- dfg/DFGLICMPhase.cpp | 77 +- dfg/DFGLazyJSValue.cpp | 44 +- dfg/DFGLazyJSValue.h | 35 +- dfg/DFGLazyNode.cpp | 48 + dfg/DFGLazyNode.h | 187 + dfg/DFGLivenessAnalysisPhase.cpp | 12 +- dfg/DFGLoopPreHeaderCreationPhase.cpp | 18 +- dfg/DFGMayExit.cpp | 133 + ...entsSimplificationPhase.h => DFGMayExit.h} | 17 +- ...ructureChains.cpp => DFGMinifiedGraph.cpp} | 25 +- dfg/DFGMinifiedGraph.h | 16 +- dfg/DFGMinifiedID.h | 9 +- dfg/DFGMinifiedNode.cpp | 12 +- dfg/DFGMinifiedNode.h | 31 +- dfg/DFGMovHintRemovalPhase.cpp | 146 + dfg/DFGMovHintRemovalPhase.h | 44 + dfg/DFGNaiveDominators.cpp | 135 + dfg/DFGNaiveDominators.h | 71 + dfg/DFGNaturalLoops.cpp | 9 +- dfg/DFGNaturalLoops.h | 1 + dfg/DFGNode.cpp | 121 +- dfg/DFGNode.h | 849 +- dfg/DFGNodeFlags.cpp | 9 - dfg/DFGNodeFlags.h | 17 +- dfg/DFGNodeOrigin.h | 1 + dfg/DFGNodeType.h | 220 +- dfg/DFGOSRAvailabilityAnalysisPhase.cpp | 181 +- dfg/DFGOSRAvailabilityAnalysisPhase.h | 22 +- dfg/DFGOSREntry.cpp | 57 +- dfg/DFGOSREntry.h | 5 +- dfg/DFGOSRExit.h | 7 +- dfg/DFGOSRExitBase.cpp | 8 +- dfg/DFGOSRExitBase.h | 9 +- dfg/DFGOSRExitCompiler.cpp | 79 +- dfg/DFGOSRExitCompiler.h | 23 +- dfg/DFGOSRExitCompiler32_64.cpp | 152 +- dfg/DFGOSRExitCompiler64.cpp | 162 +- dfg/DFGOSRExitCompilerCommon.cpp | 211 +- dfg/DFGOSRExitCompilerCommon.h | 14 +- dfg/DFGOSRExitFuzz.cpp | 50 + dfg/DFGOSRExitFuzz.h | 53 + dfg/DFGOSRExitPreparation.cpp | 4 +- dfg/DFGObjectAllocationSinkingPhase.cpp | 1165 + dfg/DFGObjectAllocationSinkingPhase.h | 47 + dfg/DFGObjectMaterializationData.cpp | 63 + dfg/DFGObjectMaterializationData.h | 77 + dfg/DFGOperations.cpp | 390 +- dfg/DFGOperations.h | 39 +- dfg/DFGPhantomInsertionPhase.cpp | 188 + dfg/DFGPhantomInsertionPhase.h | 43 + dfg/DFGPhase.cpp | 9 +- dfg/DFGPhase.h | 2 + dfg/DFGPhiChildren.cpp | 64 + dfg/DFGPhiChildren.h | 92 + dfg/DFGPlan.cpp | 222 +- dfg/DFGPlan.h | 8 +- dfg/DFGPrePostNumbering.cpp | 89 + dfg/DFGPrePostNumbering.h | 108 + dfg/DFGPreciseLocalClobberize.h | 175 + dfg/DFGPredictionPropagationPhase.cpp | 236 +- dfg/DFGPromoteHeapAccess.h | 101 + dfg/DFGPromotedHeapLocation.cpp | 113 + dfg/DFGPromotedHeapLocation.h | 184 + dfg/DFGPureValue.cpp | 52 + dfg/DFGPureValue.h | 145 + dfg/DFGPutStackSinkingPhase.cpp | 539 + dfg/DFGPutStackSinkingPhase.h | 46 + dfg/DFGSSACalculator.cpp | 150 + dfg/DFGSSACalculator.h | 263 + dfg/DFGSSAConversionPhase.cpp | 610 +- dfg/DFGSSAConversionPhase.h | 9 +- dfg/DFGSSALoweringPhase.cpp | 1 + dfg/DFGSafeToExecute.h | 112 +- dfg/DFGScoreBoard.h | 16 +- dfg/DFGSlowPathGenerator.h | 80 +- dfg/DFGSpeculativeJIT.cpp | 1766 +- dfg/DFGSpeculativeJIT.h | 438 +- dfg/DFGSpeculativeJIT32_64.cpp | 1850 +- dfg/DFGSpeculativeJIT64.cpp | 1908 +- dfg/DFGStackLayoutPhase.cpp | 157 +- ...DFGStaticExecutionCountEstimationPhase.cpp | 9 +- dfg/DFGStoreBarrierElisionPhase.cpp | 154 - dfg/DFGStoreBarrierInsertionPhase.cpp | 528 + dfg/DFGStoreBarrierInsertionPhase.h | 51 + dfg/DFGStrengthReductionPhase.cpp | 140 +- dfg/DFGStructureAbstractValue.cpp | 399 + dfg/DFGStructureAbstractValue.h | 361 +- dfg/DFGStructureClobberState.h | 73 + dfg/DFGStructureRegistrationPhase.cpp | 175 + ...hase.h => DFGStructureRegistrationPhase.h} | 28 +- dfg/DFGTierUpCheckInjectionPhase.cpp | 94 +- dfg/DFGToFTLDeferredCompilationCallback.cpp | 5 +- dfg/DFGToFTLDeferredCompilationCallback.h | 3 +- ...ForOSREntryDeferredCompilationCallback.cpp | 5 +- ...TLForOSREntryDeferredCompilationCallback.h | 3 +- dfg/DFGTransition.cpp | 48 + dfg/DFGTransition.h | 68 + dfg/DFGTypeCheckHoistingPhase.cpp | 48 +- dfg/DFGUnificationPhase.cpp | 3 +- dfg/DFGUseKind.cpp | 61 +- dfg/DFGUseKind.h | 44 +- dfg/DFGValidate.cpp | 222 +- dfg/DFGValidate.h | 2 +- dfg/DFGValueSource.cpp | 17 +- dfg/DFGValueSource.h | 14 +- dfg/DFGValueStrength.cpp | 51 + dfg/DFGValueStrength.h | 70 + dfg/DFGVarargsForwardingPhase.cpp | 321 + dfg/DFGVarargsForwardingPhase.h | 45 + dfg/DFGVariableAccessData.cpp | 19 +- dfg/DFGVariableAccessData.h | 33 +- dfg/DFGVariableAccessDataDump.cpp | 6 +- dfg/DFGVariableAccessDataDump.h | 2 +- dfg/DFGVariableEvent.cpp | 9 +- dfg/DFGVariableEvent.h | 21 +- dfg/DFGVariableEventStream.cpp | 40 +- dfg/DFGVariableEventStream.h | 5 +- dfg/DFGVirtualRegisterAllocationPhase.cpp | 6 + dfg/DFGWatchpointCollectionPhase.cpp | 98 +- dfg/DFGWorklist.cpp | 8 +- dfg/DFGWorklist.h | 3 +- disassembler/ARM64/A64DOpcode.cpp | 6 + disassembler/ARM64/A64DOpcode.h | 4 +- disassembler/ARM64Disassembler.cpp | 1 + disassembler/ARMv7/ARMv7DOpcode.cpp | 148 + disassembler/ARMv7/ARMv7DOpcode.h | 87 + disassembler/Disassembler.cpp | 114 +- disassembler/Disassembler.h | 13 +- features.json | 211 + ftl/FTLAbbreviatedTypes.h | 1 + ftl/FTLAbbreviations.h | 103 +- ftl/FTLAbstractHeap.cpp | 33 +- ftl/FTLAbstractHeap.h | 20 +- ftl/FTLAbstractHeapRepository.cpp | 20 +- ftl/FTLAbstractHeapRepository.h | 38 +- ftl/FTLCapabilities.cpp | 120 +- ftl/FTLCompile.cpp | 484 +- ftl/FTLExitArgument.cpp | 2 +- ftl/FTLExitArgumentForOperand.cpp | 2 +- ftl/FTLExitPropertyValue.cpp | 51 + ftl/FTLExitPropertyValue.h | 74 + ftl/FTLExitTimeObjectMaterialization.cpp | 82 + ftl/FTLExitTimeObjectMaterialization.h | 73 + ftl/FTLExitValue.cpp | 74 +- ftl/FTLExitValue.h | 73 +- ftl/FTLFail.cpp | 2 +- ftl/FTLForOSREntryJITCode.cpp | 2 + ftl/FTLInlineCacheDescriptor.h | 41 +- ftl/FTLInlineCacheSize.cpp | 67 +- ftl/FTLInlineCacheSize.h | 17 +- ftl/FTLIntrinsicRepository.h | 37 +- ftl/FTLJITCode.cpp | 10 +- ftl/FTLJITCode.h | 24 +- ftl/FTLJITFinalizer.cpp | 8 +- ftl/FTLJITFinalizer.h | 23 +- ftl/FTLJSCall.cpp | 62 +- ftl/FTLJSCall.h | 18 +- ftl/FTLJSCallBase.cpp | 86 + ftl/FTLJSCallBase.h | 67 + ftl/FTLJSCallVarargs.cpp | 220 + ftl/FTLJSCallVarargs.h | 77 + ftl/FTLLink.cpp | 36 +- ftl/FTLLowerDFGToLLVM.cpp | 4395 +- ftl/FTLLowerDFGToLLVM.h | 2 +- ftl/FTLOSREntry.cpp | 5 +- ftl/FTLOSRExit.cpp | 9 + ftl/FTLOSRExit.h | 52 +- ftl/FTLOSRExitCompiler.cpp | 273 +- ftl/FTLOperations.cpp | 285 + ftl/FTLOperations.h | 50 + ftl/FTLOutput.cpp | 13 +- ftl/FTLOutput.h | 58 +- ftl/FTLSlowPathCall.cpp | 17 +- ftl/FTLSlowPathCall.h | 8 +- ftl/FTLState.cpp | 35 +- ftl/FTLState.h | 18 +- ftl/FTLSwitchCase.h | 10 +- ftl/FTLUnwindInfo.cpp | 871 +- ftl/FTLUnwindInfo.h | 2 + ftl/FTLWeight.h | 10 + generate-js-builtins | 40 +- heap/BlockAllocator.cpp | 173 - heap/BlockAllocator.h | 253 - heap/CodeBlockSet.cpp | 7 +- heap/CodeBlockSet.h | 5 +- heap/CopiedBlock.h | 56 +- heap/CopiedBlockInlines.h | 4 +- heap/CopiedSpace.cpp | 28 +- heap/CopiedSpace.h | 13 +- heap/CopiedSpaceInlines.h | 11 +- heap/CopyToken.h | 5 +- heap/CopyWorkList.h | 30 +- heap/CopyWriteBarrier.h | 3 +- heap/DelayedReleaseScope.h | 103 - heap/EdenGCActivityCallback.h | 2 +- heap/FullGCActivityCallback.cpp | 9 +- heap/FullGCActivityCallback.h | 7 +- heap/GCActivityCallback.h | 8 +- heap/GCLogging.cpp | 29 +- heap/GCLogging.h | 10 +- heap/GCSegmentedArray.h | 20 +- heap/GCSegmentedArrayInlines.h | 27 +- heap/GCThread.cpp | 12 +- heap/GCThread.h | 7 +- heap/GCThreadSharedData.cpp | 7 +- heap/GCThreadSharedData.h | 7 +- heap/Handle.h | 4 +- heap/HandleBlock.h | 12 +- heap/HandleBlockInlines.h | 19 +- heap/HandleSet.cpp | 4 +- heap/HandleStack.h | 2 +- heap/Heap.cpp | 500 +- heap/Heap.h | 91 +- heap/HeapInlines.h | 103 +- heap/HeapStatistics.cpp | 42 +- heap/HeapTimer.cpp | 3 +- heap/HeapVerifier.cpp | 300 + heap/HeapVerifier.h | 134 + heap/IncrementalSweeper.cpp | 38 +- heap/IncrementalSweeper.h | 18 +- heap/ListableHandler.h | 3 +- heap/MachineStackMarker.cpp | 498 +- heap/MachineStackMarker.h | 14 +- heap/MarkStack.cpp | 4 +- heap/MarkStack.h | 2 +- heap/MarkedAllocator.cpp | 84 +- heap/MarkedAllocator.h | 11 +- heap/MarkedBlock.cpp | 76 +- heap/MarkedBlock.h | 102 +- heap/MarkedBlockSet.h | 2 +- heap/MarkedSpace.cpp | 63 +- heap/MarkedSpace.h | 119 +- heap/Region.h | 321 - heap/SlotVisitor.cpp | 2 +- heap/SlotVisitor.h | 2 +- heap/SlotVisitorInlines.h | 29 +- heap/Strong.h | 4 +- heap/SuperRegion.cpp | 83 - heap/WeakBlock.cpp | 37 +- heap/WeakBlock.h | 36 +- heap/WeakSet.cpp | 19 +- heap/WeakSet.h | 7 +- heap/WriteBarrierBuffer.cpp | 1 - heap/WriteBarrierBuffer.h | 21 +- inspector/ConsoleMessage.cpp | 99 +- inspector/ConsoleMessage.h | 13 +- inspector/ContentSearchUtilities.cpp | 22 +- inspector/ContentSearchUtilities.h | 8 +- inspector/IdentifiersFactory.cpp | 3 - inspector/IdentifiersFactory.h | 4 - inspector/InjectedScript.cpp | 141 +- inspector/InjectedScript.h | 30 +- inspector/InjectedScriptBase.cpp | 57 +- inspector/InjectedScriptBase.h | 8 +- inspector/InjectedScriptHost.cpp | 4 - inspector/InjectedScriptHost.h | 8 +- inspector/InjectedScriptManager.cpp | 40 +- inspector/InjectedScriptManager.h | 5 +- inspector/InjectedScriptModule.cpp | 4 - inspector/InjectedScriptModule.h | 4 - inspector/InjectedScriptSource.js | 1205 +- inspector/InspectorAgentBase.h | 14 +- inspector/InspectorAgentRegistry.cpp | 22 +- inspector/InspectorAgentRegistry.h | 28 +- inspector/InspectorBackendDispatcher.cpp | 165 +- inspector/InspectorBackendDispatcher.h | 59 +- inspector/InspectorEnvironment.h | 11 +- inspector/InspectorFrontendChannel.h | 4 +- inspector/InspectorProtocolTypes.h | 178 + inspector/InspectorTypeBuilder.h | 337 - inspector/InspectorValues.cpp | 371 +- inspector/InspectorValues.h | 242 +- inspector/JSConsoleClient.cpp | 147 - inspector/JSGlobalObjectConsoleClient.cpp | 109 + ...Client.h => JSGlobalObjectConsoleClient.h} | 23 +- .../JSGlobalObjectInspectorController.cpp | 126 +- inspector/JSGlobalObjectInspectorController.h | 63 +- inspector/JSGlobalObjectScriptDebugServer.cpp | 3 - inspector/JSGlobalObjectScriptDebugServer.h | 8 +- inspector/JSInjectedScriptHost.cpp | 341 +- inspector/JSInjectedScriptHost.h | 18 +- inspector/JSInjectedScriptHostPrototype.cpp | 88 +- inspector/JSInjectedScriptHostPrototype.h | 8 +- inspector/JSJavaScriptCallFrame.cpp | 58 +- inspector/JSJavaScriptCallFrame.h | 8 +- inspector/JSJavaScriptCallFramePrototype.cpp | 19 +- inspector/JSJavaScriptCallFramePrototype.h | 8 +- inspector/JavaScriptCallFrame.cpp | 3 - inspector/JavaScriptCallFrame.h | 14 +- inspector/ScriptArguments.cpp | 4 +- inspector/ScriptArguments.h | 2 +- inspector/ScriptCallFrame.cpp | 7 +- inspector/ScriptCallFrame.h | 9 +- inspector/ScriptCallStack.cpp | 16 +- inspector/ScriptCallStack.h | 13 +- inspector/ScriptCallStackFactory.cpp | 23 +- inspector/ScriptCallStackFactory.h | 9 +- inspector/ScriptDebugListener.h | 2 +- inspector/ScriptDebugServer.cpp | 118 +- inspector/ScriptDebugServer.h | 25 +- inspector/agents/InspectorAgent.cpp | 71 +- inspector/agents/InspectorAgent.h | 43 +- inspector/agents/InspectorConsoleAgent.cpp | 66 +- inspector/agents/InspectorConsoleAgent.h | 32 +- inspector/agents/InspectorDebuggerAgent.cpp | 376 +- inspector/agents/InspectorDebuggerAgent.h | 102 +- inspector/agents/InspectorProfilerAgent.cpp | 289 - inspector/agents/InspectorProfilerAgent.h | 119 - inspector/agents/InspectorRuntimeAgent.cpp | 266 +- inspector/agents/InspectorRuntimeAgent.h | 43 +- .../agents/JSGlobalObjectConsoleAgent.cpp | 12 +- inspector/agents/JSGlobalObjectConsoleAgent.h | 8 +- .../agents/JSGlobalObjectDebuggerAgent.cpp | 11 +- .../agents/JSGlobalObjectDebuggerAgent.h | 6 +- .../agents/JSGlobalObjectRuntimeAgent.cpp | 20 +- inspector/agents/JSGlobalObjectRuntimeAgent.h | 15 +- .../augmentable/AlternateDispatchableAgent.h | 70 + .../AugmentableInspectorController.h | 55 + .../AugmentableInspectorControllerClient.h} | 30 +- inspector/protocol/ApplicationCache.json | 87 + inspector/protocol/CSS.json | 423 + inspector/protocol/Console.json | 18 +- inspector/protocol/DOM.json | 531 + inspector/protocol/DOMDebugger.json | 73 + inspector/protocol/DOMStorage.json | 88 + inspector/protocol/Database.json | 71 + inspector/protocol/Debugger.json | 42 +- inspector/protocol/IndexedDB.json | 145 + .../{InspectorDomain.json => Inspector.json} | 11 + inspector/protocol/LayerTree.json | 113 + inspector/protocol/Network.json | 336 + inspector/protocol/OverlayTypes.json | 129 + inspector/protocol/Page.json | 357 + inspector/protocol/Profiler.json | 103 - inspector/protocol/Replay.json | 264 + inspector/protocol/Runtime.json | 181 +- inspector/protocol/Timeline.json | 120 + inspector/protocol/Worker.json | 71 + inspector/remote/RemoteInspector.h | 12 +- inspector/remote/RemoteInspector.mm | 199 +- inspector/remote/RemoteInspectorConstants.h | 9 + .../remote/RemoteInspectorDebuggable.cpp | 28 +- inspector/remote/RemoteInspectorDebuggable.h | 10 +- .../RemoteInspectorDebuggableConnection.h | 5 +- .../RemoteInspectorDebuggableConnection.mm | 16 +- .../remote/RemoteInspectorXPCConnection.h | 2 +- .../remote/RemoteInspectorXPCConnection.mm | 18 +- inspector/scripts/CodeGeneratorInspector.py | 2614 -- .../scripts/CodeGeneratorInspectorStrings.py | 348 - inspector/scripts/codegen/__init__.py | 24 + inspector/scripts/codegen/cpp_generator.py | 314 + .../codegen/cpp_generator_templates.py | 263 + ...cpp_alternate_backend_dispatcher_header.py | 92 + .../generate_cpp_backend_dispatcher_header.py | 208 + ...e_cpp_backend_dispatcher_implementation.py | 310 + ...generate_cpp_frontend_dispatcher_header.py | 117 + ..._cpp_frontend_dispatcher_implementation.py | 121 + .../generate_cpp_protocol_types_header.py | 352 + ...erate_cpp_protocol_types_implementation.py | 183 + .../codegen/generate_js_backend_commands.py | 137 + ...generate_objc_backend_dispatcher_header.py | 106 + ..._objc_backend_dispatcher_implementation.py | 195 + .../generate_objc_configuration_header.py | 87 + ...erate_objc_configuration_implementation.py | 150 + .../generate_objc_conversion_helpers.py | 155 + ...objc_frontend_dispatcher_implementation.py | 157 + .../scripts/codegen/generate_objc_header.py | 229 + .../codegen/generate_objc_internal_header.py | 75 + ...rate_objc_protocol_types_implementation.py | 160 + inspector/scripts/codegen/generator.py | 241 + .../scripts/codegen/generator_templates.py | 61 + inspector/scripts/codegen/models.py | 591 + inspector/scripts/codegen/objc_generator.py | 523 + .../codegen/objc_generator_templates.py | 155 + .../generate-inspector-protocol-bindings.py | 211 + .../tests/commands-with-async-attribute.json | 109 + ...-with-optional-call-return-parameters.json | 85 + .../domains-with-varying-command-sizes.json | 54 + inspector/scripts/tests/enum-values.json | 35 + .../events-with-optional-parameters.json | 59 + .../commands-with-async-attribute.json-result | 1637 + ...ptional-call-return-parameters.json-result | 1486 + ...ins-with-varying-command-sizes.json-result | 1318 + .../tests/expected/enum-values.json-result | 1172 + ...vents-with-optional-parameters.json-result | 1108 + .../fail-on-domain-availability.json-error | 1 + ...te-command-call-parameter-names.json-error | 1 + ...-command-return-parameter-names.json-error | 1 + ...duplicate-event-parameter-names.json-error | 1 + ...-on-duplicate-type-declarations.json-error | 1 + ...-on-duplicate-type-member-names.json-error | 1 + .../fail-on-enum-with-no-values.json-error | 1 + ...g-typed-optional-parameter-flag.json-error | 1 + ...ring-typed-optional-type-member.json-error | 1 + ...eclaration-using-type-reference.json-error | 1 + ...ail-on-type-with-lowercase-name.json-error | 1 + ...e-reference-in-type-declaration.json-error | 1 + ...n-type-reference-in-type-member.json-error | 1 + ...te-domains-with-feature-guards.json-result | 1159 + .../same-type-id-different-domain.json-result | 841 + ...shadowed-optional-type-setters.json-result | 984 + ...aration-aliased-primitive-type.json-result | 826 + .../type-declaration-array-type.json-result | 893 + .../type-declaration-enum-type.json-result | 925 + .../type-declaration-object-type.json-result | 1736 + .../type-requiring-runtime-casts.json-result | 1372 + .../tests/fail-on-domain-availability.json | 9 + ...uplicate-command-call-parameter-names.json | 16 + ...licate-command-return-parameter-names.json | 16 + ...il-on-duplicate-event-parameter-names.json | 12 + .../fail-on-duplicate-type-declarations.json | 15 + .../fail-on-duplicate-type-member-names.json | 15 + .../tests/fail-on-enum-with-no-values.json | 10 + ...-string-typed-optional-parameter-flag.json | 18 + ...-on-string-typed-optional-type-member.json | 16 + ...type-declaration-using-type-reference.json | 13 + .../fail-on-type-with-lowercase-name.json | 10 + ...wn-type-reference-in-type-declaration.json | 12 + ...unknown-type-reference-in-type-member.json | 15 + .../generate-domains-with-feature-guards.json | 36 + .../tests/same-type-id-different-domain.json | 22 + .../tests/shadowed-optional-type-setters.json | 31 + ...pe-declaration-aliased-primitive-type.json | 10 + .../tests/type-declaration-array-type.json | 50 + .../tests/type-declaration-enum-type.json | 15 + .../tests/type-declaration-object-type.json | 83 + .../tests/type-requiring-runtime-casts.json | 51 + interpreter/CallFrame.cpp | 26 +- interpreter/CallFrame.h | 141 +- interpreter/CallFrameClosure.h | 5 - interpreter/CallFrameInlines.h | 6 + interpreter/Interpreter.cpp | 446 +- interpreter/Interpreter.h | 117 +- interpreter/JSStack.cpp | 5 +- interpreter/JSStack.h | 1 - interpreter/ProtoCallFrame.cpp | 18 +- interpreter/ProtoCallFrame.h | 13 +- interpreter/Register.h | 11 +- interpreter/StackVisitor.cpp | 268 +- interpreter/StackVisitor.h | 43 +- .../VMEntryRecord.h | 44 +- interpreter/VMInspector.cpp | 573 - interpreter/VMInspector.h | 89 - jit/AccessorCallJITStubRoutine.h | 3 +- jit/ArityCheckFailReturnThunks.cpp | 3 +- jit/AssemblyHelpers.cpp | 20 +- jit/AssemblyHelpers.h | 491 +- jit/BinarySwitch.cpp | 329 + dfg/DFGBinarySwitch.h => jit/BinarySwitch.h | 25 +- jit/CCallHelpers.h | 330 +- jit/CompactJITCodeMap.h | 34 +- jit/ExecutableAllocationFuzz.cpp | 73 + jit/ExecutableAllocationFuzz.h | 51 + jit/ExecutableAllocator.cpp | 9 +- jit/ExecutableAllocator.h | 16 +- jit/ExecutableAllocatorFixedVMPool.cpp | 62 +- jit/GPRInfo.h | 33 +- jit/JIT.cpp | 185 +- jit/JIT.h | 134 +- jit/JITCall.cpp | 167 +- jit/JITCall32_64.cpp | 199 +- jit/JITCode.cpp | 60 +- jit/JITCode.h | 6 +- jit/JITCompilationEffort.h | 2 +- jit/JITExceptions.cpp | 9 +- jit/JITExceptions.h | 2 +- jit/JITInlines.h | 209 +- jit/JITOpcodes.cpp | 731 +- jit/JITOpcodes32_64.cpp | 585 +- jit/JITOperations.cpp | 885 +- jit/JITOperations.h | 169 +- jit/JITPropertyAccess.cpp | 267 +- jit/JITPropertyAccess32_64.cpp | 212 +- jit/JITStubRoutine.h | 7 +- jit/JITStubs.h | 6 +- jit/JITStubsARM.h | 8 +- jit/JITStubsARMv7.h | 21 +- jit/JITStubsX86.h | 38 +- jit/JITStubsX86Common.h | 78 +- jit/JITStubsX86_64.h | 54 +- jit/JITThunks.cpp | 21 +- jit/JITThunks.h | 11 +- jit/JITToDFGDeferredCompilationCallback.cpp | 4 +- jit/JITToDFGDeferredCompilationCallback.h | 2 +- jit/JITWriteBarrier.h | 4 +- jit/JSInterfaceJIT.h | 4 +- jit/PolymorphicCallStubRoutine.cpp | 137 + jit/PolymorphicCallStubRoutine.h | 115 + jit/RegisterSet.cpp | 12 + jit/Repatch.cpp | 697 +- jit/Repatch.h | 11 +- jit/SetupVarargsFrame.cpp | 134 + jit/SetupVarargsFrame.h | 53 + jit/SlowPathCall.h | 4 +- jit/SpecializedThunkJIT.h | 7 - jit/ThunkGenerators.cpp | 313 +- jit/ThunkGenerators.h | 18 +- jsc.cpp | 401 +- llint/LLIntData.cpp | 28 +- llint/LLIntOfflineAsmConfig.h | 13 +- llint/LLIntOffsetsExtractor.cpp | 10 +- llint/LLIntSlowPaths.cpp | 365 +- llint/LLIntSlowPaths.h | 8 +- llint/LLIntThunks.cpp | 18 +- llint/LLIntThunks.h | 4 +- llint/LowLevelInterpreter.asm | 761 +- llint/LowLevelInterpreter.cpp | 3 +- llint/LowLevelInterpreter32_64.asm | 723 +- llint/LowLevelInterpreter64.asm | 564 +- llvm/InitializeLLVM.cpp | 32 +- llvm/InitializeLLVM.h | 15 +- llvm/InitializeLLVMLinux.cpp | 5 +- ...ializeLLVMMac.mm => InitializeLLVMMac.cpp} | 26 +- llvm/InitializeLLVMPOSIX.cpp | 38 +- llvm/InitializeLLVMPOSIX.h | 6 +- llvm/InitializeLLVMWin.cpp | 12 +- llvm/LLVMAPI.cpp | 3 +- llvm/LLVMAPI.h | 6 +- llvm/LLVMAPIFunctions.h | 22 +- llvm/LLVMHeaders.h | 5 + llvm/library/LLVMExports.cpp | 47 +- llvm/library/LLVMOverrides.cpp | 6 +- llvm/library/LLVMTrapCallback.h | 4 +- llvm/library/libllvmForJSC.version | 4 + offlineasm/arm.rb | 12 - offlineasm/arm64.rb | 85 +- offlineasm/ast.rb | 40 + offlineasm/backends.rb | 31 + offlineasm/cloop.rb | 3 - offlineasm/generate_offset_extractor.rb | 6 + offlineasm/instructions.rb | 12 +- offlineasm/mips.rb | 177 +- offlineasm/parser.rb | 12 +- offlineasm/settings.rb | 31 +- offlineasm/sh4.rb | 12 - offlineasm/transform.rb | 5 + offlineasm/x86.rb | 34 +- parser/ASTBuilder.h | 633 +- parser/Keywords.table | 6 +- parser/Lexer.cpp | 823 +- parser/Lexer.h | 75 +- parser/NodeConstructors.h | 218 +- parser/NodeInfo.h | 62 - parser/Nodes.cpp | 131 +- parser/Nodes.h | 455 +- parser/Parser.cpp | 1300 +- parser/Parser.h | 262 +- parser/ParserArena.cpp | 47 - parser/ParserArena.h | 33 +- parser/ParserError.h | 57 +- parser/ParserFunctionInfo.h | 63 + parser/ParserModes.h | 10 +- parser/ParserTokens.h | 26 +- parser/SourceCode.h | 13 + parser/SourceProvider.cpp | 4 +- parser/SourceProvider.h | 8 +- parser/SourceProviderCache.h | 2 - parser/SourceProviderCacheItem.h | 67 +- parser/SyntaxChecker.h | 118 +- postprocess-headers.sh | 9 +- profiler/LegacyProfiler.cpp | 62 +- profiler/LegacyProfiler.h | 12 +- profiler/Profile.cpp | 42 +- profiler/Profile.h | 22 +- profiler/ProfileGenerator.cpp | 121 +- profiler/ProfileGenerator.h | 28 +- profiler/ProfileNode.cpp | 128 +- profiler/ProfileNode.h | 147 +- profiler/ProfilerBytecodeSequence.cpp | 2 +- profiler/ProfilerCompilation.cpp | 15 + profiler/ProfilerCompilation.h | 12 +- profiler/ProfilerDatabase.cpp | 8 +- replay/EmptyInputCursor.h | 6 +- replay/EncodedValue.cpp | 62 +- replay/EncodedValue.h | 17 +- replay/InputCursor.h | 19 +- replay/JSInputs.json | 60 +- replay/NondeterministicInput.h | 7 +- replay/scripts/CodeGeneratorReplayInputs.py | 188 +- .../CodeGeneratorReplayInputsTemplates.py | 48 +- ...fail-on-c-style-enum-no-storage.json-error | 2 +- .../expected/fail-on-no-inputs.json-error | 1 - .../expected/fail-on-no-types.json-error | 1 - ...h-guarded-values.json-TestReplayInputs.cpp | 77 +- ...ith-guarded-values.json-TestReplayInputs.h | 15 +- ...encoding-helpers.json-TestReplayInputs.cpp | 112 +- ...m-encoding-helpers.json-TestReplayInputs.h | 39 +- ...-enum-with-guard.json-TestReplayInputs.cpp | 27 +- ...te-enum-with-guard.json-TestReplayInputs.h | 25 +- ...h-same-base-name.json-TestReplayInputs.cpp | 95 +- ...ith-same-base-name.json-TestReplayInputs.h | 41 +- ...input-with-guard.json-TestReplayInputs.cpp | 8 +- ...e-input-with-guard.json-TestReplayInputs.h | 22 +- ...h-vector-members.json-TestReplayInputs.cpp | 35 +- ...ith-vector-members.json-TestReplayInputs.h | 38 +- ...nputs-with-flags.json-TestReplayInputs.cpp | 8 +- ...-inputs-with-flags.json-TestReplayInputs.h | 20 +- ...oized-type-modes.json-TestReplayInputs.cpp | 8 +- ...emoized-type-modes.json-TestReplayInputs.h | 20 +- .../fail-on-c-style-enum-no-storage.json | 24 +- .../tests/fail-on-duplicate-enum-type.json | 22 +- .../tests/fail-on-duplicate-input-names.json | 38 +- .../tests/fail-on-duplicate-type-names.json | 28 +- .../fail-on-enum-type-missing-values.json | 22 +- .../fail-on-missing-input-member-name.json | 26 +- .../tests/fail-on-missing-input-name.json | 26 +- .../tests/fail-on-missing-input-queue.json | 26 +- .../tests/fail-on-missing-type-mode.json | 28 +- .../tests/fail-on-missing-type-name.json | 28 +- replay/scripts/tests/fail-on-no-inputs.json | 7 - replay/scripts/tests/fail-on-no-types.json | 15 - .../tests/fail-on-unknown-input-queue.json | 28 +- .../tests/fail-on-unknown-member-type.json | 28 +- .../tests/fail-on-unknown-type-mode.json | 28 +- ...-encoding-helpers-with-guarded-values.json | 22 +- .../tests/generate-enum-encoding-helpers.json | 35 +- .../tests/generate-enum-with-guard.json | 29 +- .../generate-enums-with-same-base-name.json | 48 +- .../generate-event-loop-shape-types.json | 54 +- .../tests/generate-input-with-guard.json | 40 +- .../generate-input-with-vector-members.json | 40 +- .../tests/generate-inputs-with-flags.json | 40 +- .../tests/generate-memoized-type-modes.json | 38 +- runtime/Arguments.cpp | 445 - runtime/Arguments.h | 334 - runtime/ArgumentsIteratorPrototype.cpp | 62 - runtime/ArgumentsMode.h | 39 + runtime/ArrayBuffer.cpp | 2 +- runtime/ArrayBufferNeuteringWatchpoint.cpp | 9 +- runtime/ArrayBufferNeuteringWatchpoint.h | 14 +- runtime/ArrayBufferView.h | 18 +- runtime/ArrayConstructor.cpp | 6 +- runtime/ArrayConstructor.h | 2 +- runtime/ArrayConventions.h | 9 +- runtime/ArrayIteratorPrototype.cpp | 31 +- runtime/ArrayIteratorPrototype.h | 3 + runtime/ArrayPrototype.cpp | 845 +- runtime/ArrayPrototype.h | 6 +- runtime/BasicBlockLocation.cpp | 89 + .../BasicBlockLocation.h | 61 +- runtime/BooleanConstructor.cpp | 2 +- runtime/BooleanObject.cpp | 2 +- runtime/BooleanPrototype.cpp | 4 +- runtime/BooleanPrototype.h | 2 +- runtime/BundlePath.cpp | 52 + runtime/BundlePath.h | 39 + runtime/BundlePath.mm | 56 + runtime/CallData.cpp | 5 +- runtime/CallData.h | 4 +- runtime/ClassInfo.h | 34 +- runtime/ClonedArguments.cpp | 230 + runtime/ClonedArguments.h | 79 + runtime/CodeCache.cpp | 106 +- runtime/CodeCache.h | 52 +- runtime/CommonIdentifiers.cpp | 29 +- runtime/CommonIdentifiers.h | 93 +- runtime/CommonSlowPaths.cpp | 201 +- runtime/CommonSlowPaths.h | 58 +- runtime/Completion.cpp | 16 +- runtime/Completion.h | 25 +- runtime/ConsoleClient.cpp | 49 +- runtime/ConsoleClient.h | 31 +- runtime/ConsolePrototype.cpp | 10 +- runtime/ConsoleTypes.h | 2 + runtime/ConstantMode.cpp | 46 + runtime/ConstantMode.h | 15 +- runtime/ConstructData.h | 46 +- runtime/ControlFlowProfiler.cpp | 121 + runtime/ControlFlowProfiler.h | 112 + runtime/CustomGetterSetter.cpp | 2 +- runtime/CustomGetterSetter.h | 3 +- runtime/DataView.cpp | 6 +- runtime/DataView.h | 4 +- runtime/DateConstructor.cpp | 26 +- runtime/DateConstructor.h | 50 +- runtime/DateConversion.h | 2 +- runtime/DateInstance.cpp | 6 +- runtime/DateInstance.h | 120 +- runtime/DateInstanceCache.h | 95 +- runtime/DatePrototype.cpp | 154 +- runtime/DatePrototype.h | 56 +- runtime/DirectArguments.cpp | 178 + runtime/DirectArguments.h | 157 + runtime/DirectArgumentsOffset.cpp | 42 + .../DirectArgumentsOffset.h | 50 +- runtime/EnumerationMode.h | 87 + runtime/Error.cpp | 207 +- runtime/Error.h | 203 +- runtime/ErrorConstructor.cpp | 12 +- runtime/ErrorConstructor.h | 44 +- runtime/ErrorInstance.cpp | 154 +- runtime/ErrorInstance.h | 67 +- runtime/ErrorPrototype.cpp | 8 +- runtime/ErrorPrototype.h | 57 +- runtime/Exception.cpp | 83 + .../{JSArgumentsIterator.h => Exception.h} | 75 +- runtime/ExceptionFuzz.cpp | 57 + .../ExceptionFuzz.h | 36 +- runtime/ExceptionHelpers.cpp | 216 +- runtime/ExceptionHelpers.h | 40 +- runtime/Executable.cpp | 190 +- runtime/Executable.h | 154 +- runtime/FunctionConstructor.cpp | 36 +- runtime/FunctionConstructor.h | 50 +- runtime/FunctionHasExecutedCache.cpp | 100 + runtime/FunctionHasExecutedCache.h | 65 + runtime/FunctionPrototype.cpp | 35 +- runtime/FunctionPrototype.h | 54 +- runtime/FunctionRareData.cpp | 97 + runtime/FunctionRareData.h | 103 + .../GenericArguments.h | 47 +- runtime/GenericArgumentsInlines.h | 230 + runtime/GenericOffset.h | 112 + runtime/GenericTypedArrayView.h | 12 +- runtime/GenericTypedArrayViewInlines.h | 28 +- runtime/GetterSetter.cpp | 43 +- runtime/GetterSetter.h | 172 +- runtime/Identifier.cpp | 18 +- runtime/Identifier.h | 423 +- runtime/IdentifierInlines.h | 96 +- runtime/IndexingHeader.h | 2 +- runtime/IndexingType.h | 40 +- runtime/InferredValue.cpp | 132 + runtime/InferredValue.h | 138 + runtime/InitializeThreading.h | 6 +- runtime/IntendedStructureChain.cpp | 72 +- runtime/IntendedStructureChain.h | 25 +- runtime/InternalFunction.cpp | 2 +- runtime/InternalFunction.h | 49 +- runtime/IntlObject.cpp | 71 + heap/SuperRegion.h => runtime/IntlObject.h | 40 +- runtime/Intrinsic.h | 7 +- runtime/IterationStatus.h | 38 + runtime/IteratorOperations.cpp | 142 + runtime/IteratorOperations.h | 44 + ...rConstructor.cpp => IteratorPrototype.cpp} | 22 +- ...ratorConstructor.h => IteratorPrototype.h} | 27 +- runtime/JSAPIValueWrapper.cpp | 2 +- runtime/JSAPIValueWrapper.h | 71 +- runtime/JSActivation.h | 208 - runtime/JSArray.cpp | 732 +- runtime/JSArray.h | 69 +- runtime/JSArrayBuffer.cpp | 4 +- runtime/JSArrayBuffer.h | 3 +- runtime/JSArrayBufferConstructor.cpp | 8 +- runtime/JSArrayBufferPrototype.cpp | 8 +- runtime/JSArrayBufferView.cpp | 6 +- runtime/JSArrayBufferView.h | 3 +- runtime/JSArrayIterator.cpp | 138 +- runtime/JSArrayIterator.h | 29 +- runtime/JSBoundFunction.cpp | 9 +- runtime/JSBoundFunction.h | 5 +- runtime/JSCInlines.h | 1 + runtime/JSCJSValue.cpp | 58 +- runtime/JSCJSValue.h | 57 +- runtime/JSCJSValueInlines.h | 64 +- runtime/JSCallee.cpp | 69 + runtime/JSCallee.h | 108 + runtime/JSCatchScope.cpp | 36 + runtime/JSCatchScope.h | 62 + runtime/JSCell.cpp | 28 +- runtime/JSCell.h | 41 +- runtime/JSCellInlines.h | 53 +- runtime/JSConsole.cpp | 2 +- runtime/JSDataView.cpp | 13 +- runtime/JSDataViewPrototype.cpp | 96 +- runtime/JSDataViewPrototype.h | 3 +- runtime/JSDateMath.cpp | 37 +- runtime/JSDateMath.h | 10 +- runtime/JSDestructibleObject.h | 8 - ...ableObject.cpp => JSEnvironmentRecord.cpp} | 14 +- runtime/JSEnvironmentRecord.h | 117 + runtime/JSFunction.cpp | 137 +- runtime/JSFunction.h | 297 +- runtime/JSFunctionInlines.h | 19 +- runtime/JSFunctionNameScope.cpp | 36 + runtime/JSFunctionNameScope.h | 62 + runtime/JSGenericTypedArrayView.h | 4 +- runtime/JSGenericTypedArrayViewInlines.h | 37 +- runtime/JSGlobalObject.cpp | 497 +- runtime/JSGlobalObject.h | 155 +- runtime/JSGlobalObjectDebuggable.cpp | 20 +- runtime/JSGlobalObjectDebuggable.h | 10 +- runtime/JSGlobalObjectFunctions.cpp | 183 +- runtime/JSGlobalObjectFunctions.h | 6 +- runtime/{JSPromiseReaction.h => JSJob.cpp} | 68 +- .../JSJob.h | 18 +- ...ctivation.cpp => JSLexicalEnvironment.cpp} | 128 +- runtime/JSLexicalEnvironment.h | 108 + runtime/JSLock.cpp | 16 +- runtime/JSLock.h | 204 +- runtime/JSMap.cpp | 54 +- runtime/JSMap.h | 74 +- runtime/JSMapIterator.cpp | 23 +- runtime/JSMapIterator.h | 45 +- runtime/JSNameScope.cpp | 23 +- runtime/JSNameScope.h | 58 +- runtime/JSNotAnObject.cpp | 2 +- runtime/JSNotAnObject.h | 72 +- runtime/JSONObject.cpp | 118 +- runtime/JSONObject.h | 52 +- runtime/JSObject.cpp | 495 +- runtime/JSObject.h | 350 +- runtime/JSPromise.cpp | 118 +- runtime/JSPromise.h | 55 +- runtime/JSPromiseConstructor.cpp | 442 +- runtime/JSPromiseConstructor.h | 2 +- runtime/JSPromiseDeferred.cpp | 184 +- runtime/JSPromiseDeferred.h | 21 +- runtime/JSPromiseFunctions.cpp | 275 - runtime/JSPromisePrototype.cpp | 108 +- runtime/JSPromisePrototype.h | 2 +- runtime/JSPromiseReaction.cpp | 162 - runtime/JSPropertyNameEnumerator.cpp | 94 + runtime/JSPropertyNameEnumerator.h | 142 + runtime/JSPropertyNameIterator.cpp | 114 - runtime/JSPropertyNameIterator.h | 120 - runtime/JSProxy.cpp | 25 +- runtime/JSProxy.h | 6 +- runtime/JSScope.cpp | 68 +- runtime/JSScope.h | 33 +- runtime/JSSegmentedVariableObject.cpp | 32 +- runtime/JSSegmentedVariableObject.h | 30 +- runtime/JSSet.cpp | 45 +- runtime/JSSet.h | 72 +- runtime/JSSetIterator.cpp | 23 +- runtime/JSSetIterator.h | 34 +- runtime/JSString.cpp | 177 +- runtime/JSString.h | 1115 +- runtime/JSStringBuilder.h | 44 +- runtime/JSStringIterator.cpp | 61 + runtime/JSStringIterator.h | 66 + runtime/JSStringJoiner.cpp | 139 +- runtime/JSStringJoiner.h | 110 +- runtime/JSSymbolTableObject.cpp | 14 +- runtime/JSSymbolTableObject.h | 60 +- runtime/JSTemplateRegistryKey.cpp | 57 + ...NameInstance.h => JSTemplateRegistryKey.h} | 44 +- runtime/JSType.h | 14 +- runtime/JSTypeInfo.h | 172 +- runtime/JSTypedArrayConstructors.cpp | 2 +- runtime/JSTypedArrayPrototypes.cpp | 2 +- runtime/JSTypedArrays.cpp | 2 +- runtime/JSWeakMap.cpp | 2 +- runtime/JSWeakMap.h | 2 - ...tIteratorConstructor.cpp => JSWeakSet.cpp} | 24 +- runtime/JSWeakSet.h | 81 + runtime/JSWithScope.cpp | 5 +- runtime/JSWithScope.h | 20 - runtime/JSWrapperObject.cpp | 3 - runtime/JSWrapperObject.h | 93 +- runtime/LiteralParser.cpp | 50 +- runtime/LiteralParser.h | 4 +- runtime/Lookup.cpp | 32 +- runtime/Lookup.h | 483 +- runtime/MapConstructor.cpp | 90 +- runtime/MapData.cpp | 258 - runtime/MapData.h | 222 +- runtime/MapDataInlines.h | 288 + runtime/MapIteratorPrototype.cpp | 20 +- runtime/MapPrototype.cpp | 92 +- runtime/MathCommon.cpp | 431 + runtime/MathCommon.h | 63 + runtime/MathObject.cpp | 568 +- runtime/MathObject.h | 53 +- runtime/NamePrototype.cpp | 81 - runtime/NativeErrorConstructor.cpp | 17 +- runtime/NativeErrorConstructor.h | 57 +- runtime/NativeErrorPrototype.h | 39 +- runtime/NullGetterFunction.cpp | 52 + ...atorConstructor.h => NullGetterFunction.h} | 31 +- runtime/NullSetterFunction.cpp | 90 + runtime/NullSetterFunction.h | 62 + runtime/NumberConstructor.cpp | 114 +- runtime/NumberConstructor.h | 63 +- runtime/NumberObject.cpp | 2 +- runtime/NumberObject.h | 48 +- runtime/NumberPrototype.cpp | 47 +- runtime/NumberPrototype.h | 52 +- runtime/NumericStrings.h | 104 +- runtime/ObjectConstructor.cpp | 228 +- runtime/ObjectConstructor.h | 98 +- runtime/ObjectPrototype.cpp | 53 +- runtime/ObjectPrototype.h | 30 +- runtime/Operations.cpp | 19 +- runtime/Operations.h | 46 +- runtime/Options.cpp | 245 +- runtime/Options.h | 564 +- runtime/PrivateName.h | 23 +- runtime/PropertyDescriptor.cpp | 14 +- runtime/PropertyDescriptor.h | 124 +- runtime/PropertyMapHashTable.h | 87 +- runtime/PropertyName.h | 94 +- runtime/PropertyNameArray.cpp | 55 - runtime/PropertyNameArray.h | 170 +- runtime/PropertySlot.h | 29 +- runtime/PropertyTable.cpp | 27 +- runtime/Protect.h | 58 +- runtime/PrototypeMap.cpp | 10 +- runtime/PrototypeMap.h | 7 + runtime/PutPropertySlot.h | 153 +- runtime/RegExp.cpp | 26 +- runtime/RegExp.h | 128 +- runtime/RegExpCache.h | 6 +- runtime/RegExpCachedResult.cpp | 32 +- runtime/RegExpCachedResult.h | 91 +- runtime/RegExpConstructor.cpp | 17 +- runtime/RegExpConstructor.h | 146 +- runtime/RegExpMatchesArray.cpp | 105 +- runtime/RegExpMatchesArray.h | 115 +- runtime/RegExpObject.cpp | 174 +- runtime/RegExpObject.h | 144 +- runtime/RegExpPrototype.cpp | 234 +- runtime/RegExpPrototype.h | 50 +- runtime/RuntimeFlags.h | 102 + runtime/RuntimeType.cpp | 85 + runtime/RuntimeType.h | 60 + runtime/ScopeOffset.cpp | 42 + runtime/ScopeOffset.h | 51 + runtime/ScopedArguments.cpp | 154 + runtime/ScopedArguments.h | 157 + runtime/ScopedArgumentsTable.cpp | 109 + runtime/ScopedArgumentsTable.h | 96 + runtime/SetConstructor.cpp | 77 +- runtime/SetIteratorPrototype.cpp | 20 +- runtime/SetPrototype.cpp | 92 +- runtime/SmallStrings.cpp | 16 +- runtime/SmallStrings.h | 120 +- runtime/SparseArrayValueMap.cpp | 8 +- runtime/SparseArrayValueMap.h | 6 +- runtime/StrictEvalActivation.cpp | 6 +- runtime/StrictEvalActivation.h | 14 +- runtime/StringConstructor.cpp | 46 +- runtime/StringConstructor.h | 65 +- runtime/StringIteratorPrototype.cpp | 65 + runtime/StringIteratorPrototype.h | 64 + runtime/StringObject.cpp | 11 +- runtime/StringObject.h | 102 +- runtime/StringPrototype.cpp | 368 +- runtime/StringPrototype.h | 33 +- runtime/StringRecursionChecker.h | 20 +- runtime/Structure.cpp | 589 +- runtime/Structure.h | 269 +- runtime/StructureChain.cpp | 3 +- runtime/StructureChain.h | 102 +- runtime/StructureIDTable.cpp | 7 +- runtime/StructureIDTable.h | 6 +- runtime/StructureInlines.h | 101 +- runtime/StructureRareData.cpp | 35 +- runtime/StructureRareData.h | 33 +- runtime/StructureTransitionTable.h | 13 +- runtime/Symbol.cpp | 96 + runtime/Symbol.h | 108 + runtime/SymbolConstructor.cpp | 128 + ...{NameConstructor.h => SymbolConstructor.h} | 31 +- runtime/SymbolObject.cpp | 56 + runtime/SymbolObject.h | 67 + runtime/SymbolPrototype.cpp | 105 + .../{NamePrototype.h => SymbolPrototype.h} | 29 +- runtime/SymbolTable.cpp | 196 +- runtime/SymbolTable.h | 405 +- ...meConstructor.cpp => TemplateRegistry.cpp} | 60 +- .../{NameInstance.cpp => TemplateRegistry.h} | 31 +- runtime/TemplateRegistryKey.h | 103 + runtime/TestRunnerUtils.h | 5 +- runtime/Tracing.d | 6 +- runtime/Tracing.h | 4 +- runtime/TypeLocationCache.cpp | 61 + runtime/TypeLocationCache.h | 68 + runtime/TypeProfiler.cpp | 168 + runtime/TypeProfiler.h | 121 + runtime/TypeProfilerLog.cpp | 98 + .../{JSVariableObject.h => TypeProfilerLog.h} | 77 +- runtime/TypeSet.cpp | 587 + runtime/TypeSet.h | 110 + runtime/TypedArrayBase.h | 18 +- runtime/TypeofType.cpp | 63 + runtime/TypeofType.h | 52 + runtime/VM.cpp | 379 +- runtime/VM.h | 829 +- runtime/VMEntryScope.cpp | 15 +- runtime/VMEntryScope.h | 6 +- runtime/VarOffset.cpp | 76 + runtime/VarOffset.h | 247 + runtime/Watchdog.cpp | 16 +- runtime/Watchdog.h | 13 +- runtime/WatchdogMac.cpp | 4 +- runtime/WatchdogNone.cpp | 2 +- runtime/WeakGCMap.h | 69 +- runtime/WeakGCMapInlines.h | 59 + runtime/WeakMapConstructor.cpp | 89 +- runtime/WeakMapData.cpp | 4 +- runtime/WeakMapData.h | 15 +- runtime/WeakMapPrototype.cpp | 27 +- runtime/WeakSetConstructor.cpp | 125 + ...atorConstructor.h => WeakSetConstructor.h} | 24 +- runtime/WeakSetPrototype.cpp | 97 + ...IteratorPrototype.h => WeakSetPrototype.h} | 16 +- runtime/WriteBarrier.h | 13 +- testRegExp.cpp | 68 +- tested-symbols.symlst | 87 + tests/controlFlowProfiler.yaml | 26 + tests/controlFlowProfiler/brace-location.js | 159 + .../conditional-expression.js | 44 + tests/controlFlowProfiler/driver/driver.js | 14 + tests/controlFlowProfiler/if-statement.js | 56 + tests/controlFlowProfiler/loop-statements.js | 76 + .../controlFlowProfiler/switch-statements.js | 28 + tests/controlFlowProfiler/test-jit.js | 46 + tests/exceptionFuzz.yaml | 2 +- tests/exceptionFuzz/3d-cube.js | 3 + tests/exceptionFuzz/date-format-xparb.js | 3 + tests/exceptionFuzz/earley-boyer.js | 2 + tests/executableAllocationFuzz.yaml | 31 + tests/executableAllocationFuzz/v8-raytrace.js | 902 + tests/mozilla/ecma/Date/15.9.1.1-1.js | 2 +- tests/mozilla/ecma/Date/15.9.1.1-2.js | 2 +- tests/mozilla/ecma/Date/15.9.2.1.js | 121 +- tests/mozilla/ecma/Date/15.9.2.2-1.js | 50 +- tests/mozilla/ecma/Date/15.9.2.2-2.js | 49 +- tests/mozilla/ecma/Date/15.9.2.2-3.js | 39 +- tests/mozilla/ecma/Date/15.9.2.2-4.js | 32 +- tests/mozilla/ecma/Date/15.9.2.2-5.js | 35 +- tests/mozilla/ecma/Date/15.9.2.2-6.js | 26 +- tests/mozilla/ecma_3/Unicode/uc-003.js | 5 - tests/mozilla/js1_2/function/tostring-1.js | 2 +- tests/mozilla/mozilla-tests.yaml | 48 +- tests/stress/activation-sink-default-value.js | 31 + .../activation-sink-osrexit-default-value.js | 37 + tests/stress/activation-sink-osrexit.js | 25 + tests/stress/activation-sink.js | 24 + tests/stress/add-overflows-after-not-equal.js | 16 + tests/stress/arguments-bizarre-behavior.js | 25 + ...bizarre-behaviour-disable-enumerability.js | 30 + .../stress/arguments-callee-uninitialized.js | 11 + tests/stress/arguments-captured.js | 23 + .../stress/arguments-custom-properties-gc.js | 36 + tests/stress/arguments-exit-fixed.js | 16 + .../arguments-exit-strict-mode-fixed.js | 18 + tests/stress/arguments-exit-strict-mode.js | 18 + tests/stress/arguments-exit.js | 16 + ...rguments-inlined-exit-strict-mode-fixed.js | 22 + .../arguments-inlined-exit-strict-mode.js | 22 + tests/stress/arguments-inlined-exit.js | 20 + tests/stress/arguments-interference-cfg.js | 24 + tests/stress/arguments-interference.js | 18 + tests/stress/arguments-iterator.js | 70 + tests/stress/arith-add-with-constants.js | 271 + tests/stress/arith-modulo-node-behaviors.js | 106 + tests/stress/arith-mul-with-constants.js | 222 + tests/stress/array-copywithin.js | 281 + tests/stress/array-fill-put-by-val.js | 44 + .../stress/array-filter-put-by-val-direct.js | 27 + .../array-find-does-not-lookup-twice.js | 47 + tests/stress/array-from-abs-and-floor.js | 42 + tests/stress/array-from-put-by-val-direct.js | 25 + tests/stress/array-from-set-length.js | 45 + tests/stress/array-from-with-accessors.js | 22 + tests/stress/array-from-with-iterable.js | 69 + tests/stress/array-from-with-iterator.js | 129 + .../stress/array-iterators-next-with-call.js | 115 + tests/stress/array-iterators-next.js | 108 + ...array-length-array-storage-plain-object.js | 16 + tests/stress/array-length-plain-object.js | 15 + tests/stress/array-map-put-by-val-direct.js | 27 + .../arrayify-to-structure-contradiction.js | 16 + ...ssignment-in-function-call-bracket-node.js | 126 + ...ay-exit-due-to-object-or-other-use-kind.js | 46 + ...builtin-function-is-construct-type-none.js | 18 + tests/stress/cached-prototype-setter.js | 45 + ...d-varargs-for-inlined-escaped-arguments.js | 23 + tests/stress/call-varargs-length-effects.js | 24 + ...different-arguments-length-after-warmup.js | 91 + ...lass-syntax-derived-default-constructor.js | 26 + tests/stress/class-syntax-no-loop-tdz.js | 20 + tests/stress/class-syntax-no-tdz-in-catch.js | 19 + .../class-syntax-no-tdz-in-conditional.js | 18 + tests/stress/class-syntax-no-tdz-in-eval.js | 18 + ...s-syntax-no-tdz-in-loop-no-inline-super.js | 25 + tests/stress/class-syntax-no-tdz-in-loop.js | 23 + tests/stress/class-syntax-no-tdz.js | 16 + tests/stress/class-syntax-tdz-in-catch.js | 30 + .../stress/class-syntax-tdz-in-conditional.js | 28 + tests/stress/class-syntax-tdz-in-eval.js | 26 + tests/stress/class-syntax-tdz-in-loop.js | 30 + tests/stress/class-syntax-tdz.js | 26 + ...loned-arguments-get-by-val-double-array.js | 13 + ...arguments-should-visit-callee-during-gc.js | 34 + tests/stress/closure-call-exit.js | 15 + ...d-varargs-for-inlined-escaped-arguments.js | 23 + .../construct-varargs-inline-smaller-Foo.js | 35 + tests/stress/construct-varargs-inline.js | 39 + tests/stress/construct-varargs-no-inline.js | 41 + tests/stress/constructor-with-return.js | 39 + .../create-this-with-callee-variants.js | 18 + tests/stress/custom-iterators.js | 322 + tests/stress/dead-get-closure-var.js | 23 + tests/stress/dead-osr-entry-value.js | 16 + tests/stress/dead-speculating-argument-use.js | 17 + ...tructuring-assignment-accepts-iterables.js | 441 + ...dfg-put-by-val-direct-with-edge-numbers.js | 104 + tests/stress/dfg-rare-data.js | 9 + tests/stress/dfg-to-primitive-pass-symbol.js | 35 + .../stress/disable-function-dot-arguments.js | 20 + tests/stress/double-rep-with-non-cell.js | 32 + tests/stress/double-rep-with-null.js | 107 + tests/stress/double-rep-with-undefined.js | 131 + ...lidable-new-object-roflcopter-then-exit.js | 23 + .../stress/elide-new-object-dag-then-exit.js | 43 + tests/stress/empty_eos_regex_split.js | 3 + tests/stress/equality-type-checking.js | 34 + tests/stress/equals-masquerader.js | 18 +- .../escape-object-in-diamond-then-exit.js | 40 + .../eval-script-contains-null-character.js | 13 + ...ould-be-handled-early-in-object-methods.js | 73 + ...to-property-key-should-be-handled-early.js | 139 + tests/stress/exit-from-getter.js | 23 + tests/stress/exit-from-setter.js | 23 + .../fold-based-on-int32-proof-mul-branch.js | 17 + tests/stress/fold-based-on-int32-proof-mul.js | 14 + .../fold-based-on-int32-proof-or-zero.js | 15 + tests/stress/fold-based-on-int32-proof.js | 14 + ...ld-load-varargs-arity-check-fail-barely.js | 28 + .../fold-load-varargs-arity-check-fail.js | 29 + ...set-without-folding-the-structure-check.js | 50 + ...set-without-folding-the-structure-check.js | 56 + tests/stress/fold-profiled-call-to-call.js | 24 + tests/stress/fold-typed-array-properties.js | 33 +- tests/stress/for-in-array-mode.js | 89 + ...e-reassigned-later-and-change-structure.js | 18 + tests/stress/for-in-base-reassigned-later.js | 18 + tests/stress/for-in-base-reassigned.js | 17 + .../stress/for-in-capture-string-loop-var.js | 22 + .../stress/for-in-delete-during-iteration.js | 69 + tests/stress/for-in-modify-int-loop-var.js | 21 + tests/stress/for-in-modify-string-loop-var.js | 19 + tests/stress/for-in-prototype.js | 57 + .../for-in-proxy-target-changed-structure.js | 32 + tests/stress/for-in-proxy.js | 16 + .../for-in-shadow-prototype-property.js | 22 + tests/stress/for-in-string.js | 16 + tests/stress/for-in-tests.js | 100 + tests/stress/for-in-typed-array.js | 18 + ...d-varargs-for-inlined-escaped-arguments.js | 21 + tests/stress/freeze_leek.js | 41 + tests/stress/ftl-arithcos.js | 2 + tests/stress/ftl-checkin-variable.js | 17 + tests/stress/ftl-checkin.js | 17 + .../stress/ftl-getmyargumentslength-inline.js | 9 + tests/stress/ftl-in-overflow.js | 13 + tests/stress/ftl-library-exception.js | 21 + .../ftl-library-inline-gettimezoneoffset.js | 16 + ...tl-library-inlining-exceptions-dataview.js | 26 + .../stress/ftl-library-inlining-exceptions.js | 19 + tests/stress/ftl-library-inlining-loops.js | 28 + tests/stress/ftl-library-inlining-random.js | 11 + tests/stress/ftl-library-substring.js | 15 + .../ftl-switch-string-slow-duplicate-cases.js | 31 + tests/stress/function-expression-exit.js | 16 + tests/stress/function-name-scope.js | 40 + .../stress/function-reentry-infer-on-self.js | 28 + .../function-sinking-no-double-allocate.js | 28 + tests/stress/function-sinking-osrexit.js | 21 + tests/stress/function-sinking-put.js | 28 + ...l-in-inlined-varargs-call-out-of-bounds.js | 31 + ...e-in-inlined-varargs-call-out-of-bounds.js | 35 + .../stress/get-by-val-out-of-bounds-basics.js | 221 + ...d-unpassed-argument-in-direct-arguments.js | 13 + ...d-unpassed-argument-in-scoped-arguments.js | 15 + tests/stress/get-local-elimination.js | 15 + ...et-my-argument-by-val-creates-arguments.js | 42 + ...nt-by-val-for-inlined-escaped-arguments.js | 18 + ...rgument-by-val-out-of-bounds-no-warm-up.js | 9 + .../get-my-argument-by-val-out-of-bounds.js | 15 + ...t-my-argument-by-val-safe-out-of-bounds.js | 17 + ...get-my-argument-by-val-safe-wrap-around.js | 17 + ...-argument-by-val-wrap-around-no-warm-up.js | 9 + .../get-my-argument-by-val-wrap-around.js | 15 + .../get-stack-identity-due-to-sinking.js | 18 + .../get-stack-mapping-with-dead-get-stack.js | 27 + tests/stress/get-stack-mapping.js | 26 + ...l-environment-does-not-trap-unscopables.js | 19 + ...fy-function-reentry-incorrect-inference.js | 25 + tests/stress/has-custom-properties.js | 13 + .../stress/infer-constant-global-property.js | 18 + tests/stress/infer-constant-property.js | 22 + .../stress/infer-uninitialized-closure-var.js | 26 + .../initialize_functions_after_arguments.js | 8 + .../inline-call-that-doesnt-use-all-args.js | 27 + tests/stress/inline-varargs-get-arguments.js | 23 + tests/stress/int32array-transition-on-nan.js | 88 + tests/stress/iterator-functions.js | 33 + tests/stress/iterator-names.js | 35 + tests/stress/iterator-prototype.js | 53 + ...return-beyond-multiple-iteration-scopes.js | 172 + tests/stress/iterators-shape.js | 63 + ...then-cache-get-and-fold-then-invalidate.js | 33 + ...then-cache-get-and-fold-then-invalidate.js | 30 + ...cope-global-cache-watchpoint-invalidate.js | 26 + ...uning-needed-for-osr-availability-eager.js | 16 + ...ess-pruning-needed-for-osr-availability.js | 15 + ...then-cache-get-and-fold-then-invalidate.js | 26 + ...cope-global-cache-watchpoint-invalidate.js | 22 + ...varargs-elimination-bounds-check-barely.js | 35 + .../load-varargs-elimination-bounds-check.js | 35 + ...rargs-then-inlined-call-and-exit-strict.js | 43 + ...load-varargs-then-inlined-call-and-exit.js | 41 + ...d-varargs-then-inlined-call-exit-in-foo.js | 46 + .../load-varargs-then-inlined-call-inlined.js | 43 + .../stress/load-varargs-then-inlined-call.js | 39 + tests/stress/logical-not-masquerades.js | 33 + tests/stress/many-sunken-locals.js | 27 + tests/stress/map-constructor-adder.js | 46 + tests/stress/map-constructor.js | 133 + tests/stress/map-iterators-next.js | 111 + .../materialize-past-butterfly-allocation.js | 89 + .../stress/materialize-past-put-structure.js | 14 + tests/stress/math-abs-positive.js | 11 + tests/stress/math-clz32-basics.js | 222 + tests/stress/math-log-basics.js | 128 + tests/stress/math-log-with-constants.js | 128 + tests/stress/math-pow-basics.js | 286 + .../math-pow-becomes-custom-function.js | 18 + .../math-pow-integer-exponent-fastpath.js | 56 + tests/stress/math-pow-nan-behaviors.js | 209 + tests/stress/math-pow-with-constants.js | 215 + .../math-pow-with-never-NaN-exponent.js | 24 + .../stress/math-round-arith-rounding-mode.js | 44 + tests/stress/math-round-basics.js | 257 + ...ble-architecture-specific-optimizations.js | 48 + tests/stress/math-sqrt-basics.js | 45 + tests/stress/misc-is-object-or-null.js | 13 + tests/stress/modify-map-during-iteration.js | 97 + tests/stress/modify-set-during-iteration.js | 91 + tests/stress/multi-get-by-offset-dce.js | 22 + ...ulti-put-by-offset-multiple-transitions.js | 30 + .../new-array-storage-array-with-size.js | 8 +- tests/stress/new-array-then-exit.js | 14 + ...new-largeish-contiguous-array-with-size.js | 47 + tests/stress/no-abc-skippy-loop.js | 24 + tests/stress/no-abc-skippy-paired-loop.js | 20 + ...with-uninitialized-property-on-one-path.js | 53 + tests/stress/object-escapes-in-loop.js | 17 + .../stress/object-freeze-accept-non-object.js | 15 + ...n-property-descriptor-perform-to-object.js | 43 + ...et-own-property-names-perform-to-object.js | 39 + ...-own-property-symbols-perform-to-object.js | 39 + .../stress/object-get-own-property-symbols.js | 35 + ...ject-get-prototype-of-perform-to-object.js | 29 + .../object-is-extensible-accept-non-object.js | 15 + .../object-is-frozen-accept-non-object.js | 15 + .../object-is-sealed-accept-non-object.js | 15 + tests/stress/object-keys-perform-to-object.js | 39 + ...ct-prevent-extensions-accept-non-object.js | 15 + tests/stress/object-seal-accept-non-object.js | 15 + ...obviously-elidable-new-object-then-exit.js | 23 + .../op-push-name-scope-crashes-profiler.js | 17 + tests/stress/other-is-object-or-null.js | 13 + ...direct-arguments-clobber-argument-count.js | 20 + ...phantom-direct-arguments-clobber-callee.js | 21 + tests/stress/phantom-inadequacy.js | 33 + tests/stress/poly-call-exit-this.js | 29 + tests/stress/poly-call-exit.js | 29 + tests/stress/poly-chain-getter.js | 30 + tests/stress/poly-chain-setter.js | 32 + tests/stress/poly-chain-then-getter.js | 31 + tests/stress/poly-chain-then-setter.js | 33 + tests/stress/poly-getter-combo.js | 40 + tests/stress/poly-getter-then-chain.js | 31 + tests/stress/poly-getter-then-self.js | 26 + tests/stress/poly-self-getter.js | 31 + tests/stress/poly-self-then-getter.js | 26 + tests/stress/poly-setter-combo.js | 77 + tests/stress/poly-setter-then-self.js | 28 + tests/stress/proto-setter.js | 8 + ...by-offset-replace-or-transition-variant.js | 58 + .../put-by-id-build-list-order-recurse.js | 35 + ...t-should-be-done-for-non-index-property.js | 41 + ...t-after-prototype-transition-non-strict.js | 31 + ...bject-after-prototype-transition-strict.js | 33 + .../put-by-id-strict-build-list-order.js | 16 + .../stress/put-by-val-out-of-bounds-basics.js | 87 + tests/stress/put-local-conservative.js | 47 + tests/stress/raise-error-in-iterator-close.js | 118 + ...d-varargs-for-inlined-escaped-arguments.js | 25 + ...property_redefine_during_inline_caching.js | 23 + tests/stress/regress-141883.js | 15 + tests/stress/remove-phantom-after-setlocal.js | 18 + ...l-with-same-value-watchpoint-invalidate.js | 23 + tests/stress/repeated-arity-check-fail.js | 2 +- tests/stress/reserved-word-with-escape.js | 141 + tests/stress/rest-elements.js | 223 + tests/stress/scoped-arguments-array-length.js | 17 + ...direct-arguments-get-by-val-in-baseline.js | 30 + tests/stress/set-constructor-adder.js | 34 + tests/stress/set-constructor.js | 69 + tests/stress/set-iterators-next.js | 115 + ...gs-mandatory-minimum-smaller-than-limit.js | 15 + .../stress/singleton-scope-then-overwrite.js | 20 + ...gleton-scope-then-realloc-and-overwrite.js | 20 + tests/stress/singleton-scope-then-realloc.js | 20 + .../sink-arguments-past-invalid-check-dfg.js | 17 + ...-arguments-past-invalid-check-int32-dfg.js | 12 + ...sink-arguments-past-invalid-check-int32.js | 24 + ...k-arguments-past-invalid-check-sneakier.js | 37 + .../sink-arguments-past-invalid-check.js | 23 + ...nk-function-past-invalid-check-sneakier.js | 35 + ...sink-function-past-invalid-check-sneaky.js | 13 + .../sink-object-past-invalid-check-int32.js | 24 + ...sink-object-past-invalid-check-sneakier.js | 32 + .../sink-object-past-invalid-check-sneaky.js | 20 + .../stress/sink-object-past-invalid-check.js | 20 + tests/stress/sink_checkstructure.js | 17 + tests/stress/sort-array-with-undecided.js | 1 + tests/stress/sparse_splice.js | 12 + tests/stress/static-function-delete.js | 10 + tests/stress/static-function-put.js | 11 + tests/stress/static-getter-delete.js | 47 + tests/stress/static-getter-descriptors.js | 12 + tests/stress/static-getter-enumeration.js | 8 + tests/stress/static-getter-get.js | 22 + tests/stress/static-getter-in-names.js | 7 + tests/stress/static-getter-names.js | 16 + tests/stress/static-getter-put.js | 38 + tests/stress/string-from-code-point.js | 135 + tests/stress/string-iterators.js | 212 + tests/stress/string-raw.js | 154 + tests/stress/sub-overflows-after-not-equal.js | 16 + tests/stress/switch-typeof-indirect.js | 41 + .../stress/switch-typeof-slightly-indirect.js | 39 + tests/stress/switch-typeof.js | 36 + tests/stress/symbol-and-string-constructor.js | 10 + tests/stress/symbol-define-property.js | 33 + tests/stress/symbol-registry.js | 125 + tests/stress/symbol-seal-and-freeze.js | 26 + tests/stress/symbol-with-json.js | 14 + tests/stress/tagged-templates-identity.js | 59 + tests/stress/tagged-templates-raw-strings.js | 63 + tests/stress/tagged-templates-syntax.js | 70 + .../tagged-templates-template-object.js | 43 + tests/stress/tagged-templates-this.js | 26 + tests/stress/tagged-templates.js | 67 + .../template-literal-line-terminators.js | 57 + tests/stress/template-literal-syntax.js | 83 + tests/stress/template-literal.js | 207 + tests/stress/throw-from-ftl-in-loop.js | 13 + tests/stress/throw-from-ftl.js | 25 + tests/stress/toprimitive-speculated-types.js | 27 + tests/stress/trailing-comma-in-patterns.js | 157 + tests/stress/type-of-functions-and-objects.js | 86 + tests/stress/typed-array-byte-offset.js | 17 + .../typed-array-get-by-val-profiling.js | 91 + .../typed-array-put-by-val-profiling.js | 98 + tests/stress/typeof-symbol.js | 16 + tests/stress/unscopables.js | 239 + tests/stress/values-unscopables.js | 53 + ...arargs-closure-inlined-exit-strict-mode.js | 26 + tests/stress/varargs-closure-inlined-exit.js | 24 + tests/stress/varargs-exit.js | 21 + tests/stress/varargs-inlined-exit.js | 25 + ...imple-exit-aliasing-weird-reversed-args.js | 42 + ...args-inlined-simple-exit-aliasing-weird.js | 42 + .../varargs-inlined-simple-exit-aliasing.js | 41 + tests/stress/varargs-inlined-simple-exit.js | 28 + tests/stress/varargs-inlining-underflow.js | 18 + tests/stress/varargs-then-slow-call.js | 40 + tests/stress/varargs-too-few-arguments.js | 16 + .../varargs-varargs-closure-inlined-exit.js | 24 + ...arargs-varargs-inlined-exit-strict-mode.js | 27 + tests/stress/varargs-varargs-inlined-exit.js | 25 + tests/stress/weak-map-constructor-adder.js | 51 + tests/stress/weak-map-constructor.js | 144 + tests/stress/weak-set-constructor-adder.js | 51 + tests/stress/weak-set-constructor.js | 146 + tests/stress/weird-getter-counter.js | 24 + tests/stress/weird-put-stack-varargs.js | 26 + .../stress/weird-setter-counter-syntactic.js | 29 + tests/stress/weird-setter-counter.js | 26 + tests/typeProfiler.yaml | 25 + tests/typeProfiler/basic.js | 42 + tests/typeProfiler/captured.js | 32 + tests/typeProfiler/classes.js | 29 + tests/typeProfiler/dfg-jit-optimizations.js | 52 + tests/typeProfiler/dictionary-mode.js | 27 + tests/typeProfiler/driver/driver.js | 27 + tests/typeProfiler/inheritance.js | 51 + tests/typeProfiler/loop.js | 57 + tests/typeProfiler/optional-fields.js | 52 + tests/typeProfiler/overflow.js | 36 + tests/typeProfiler/return.js | 34 + tests/typeProfiler/symbol.js | 44 + tools/CodeProfile.cpp | 4 +- tools/CodeProfile.h | 12 +- tools/CodeProfiling.cpp | 4 +- tools/FunctionOverrides.cpp | 250 + .../FunctionOverrides.h | 63 +- .../JSDollarVM.cpp | 17 +- .../JSDollarVM.h | 43 +- tools/JSDollarVMPrototype.cpp | 424 + tools/JSDollarVMPrototype.h | 81 + yarr/RegularExpression.cpp | 11 +- yarr/Yarr.h | 2 +- yarr/YarrCanonicalizeUCS2.cpp | 2 +- yarr/YarrCanonicalizeUCS2.h | 2 +- yarr/YarrInterpreter.cpp | 18 +- yarr/YarrInterpreter.h | 13 +- yarr/YarrJIT.cpp | 17 +- yarr/YarrPattern.cpp | 42 +- yarr/YarrPattern.h | 69 +- 1804 files changed, 196146 insertions(+), 65701 deletions(-) create mode 100644 API/JSContextRefInspectorSupport.h create mode 100644 API/JSRemoteInspector.cpp create mode 100644 API/JSRemoteInspector.h create mode 100644 API/tests/CompareAndSwapTest.cpp rename runtime/JSPromiseFunctions.h => API/tests/CompareAndSwapTest.h (64%) create mode 100644 API/tests/ExecutionTimeLimitTest.cpp create mode 100644 API/tests/ExecutionTimeLimitTest.h create mode 100644 API/tests/GlobalContextWithFinalizerTest.cpp create mode 100644 API/tests/GlobalContextWithFinalizerTest.h rename assembler/ARMv7Assembler.cpp => API/tests/Regress141275.h (86%) create mode 100644 API/tests/Regress141275.mm create mode 100644 ChangeLog-2014-10-07 create mode 100644 ChangeLog-2015-07-23 delete mode 100644 Configurations/iOS.xcconfig create mode 100644 JavaScriptCore.vcxproj/JavaScriptCoreDLL.cpp create mode 100644 JavaScriptCore.vcxproj/jsc/DLLLauncherMain.cpp create mode 100644 JavaScriptCore.vcxproj/jsc/DLLLauncherWinCairo.props create mode 100644 JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj create mode 100644 JavaScriptCore.vcxproj/jsc/jscLauncherPostBuild.cmd create mode 100644 JavaScriptCore.vcxproj/jsc/jscLauncherPreBuild.cmd create mode 100644 JavaScriptCore.vcxproj/jsc/jscLauncherPreLink.cmd create mode 100644 JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj create mode 100644 JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPostBuild.cmd create mode 100644 JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreBuild.cmd create mode 100644 JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreLink.cmd create mode 100644 JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj create mode 100644 JavaScriptCore.vcxproj/testapi/testapiLauncherPostBuild.cmd create mode 100644 JavaScriptCore.vcxproj/testapi/testapiLauncherPreBuild.cmd create mode 100644 JavaScriptCore.vcxproj/testapi/testapiLauncherPreLink.cmd create mode 100644 PlatformMac.cmake create mode 100644 PlatformWin.cmake create mode 100644 UpdateContents.py delete mode 100755 build-symbol-table-index.sh create mode 100644 builtins/ArrayConstructor.js create mode 100644 builtins/ArrayIterator.prototype.js create mode 100644 builtins/GlobalObject.js create mode 100644 builtins/Iterator.prototype.js create mode 100644 builtins/ObjectConstructor.js create mode 100644 builtins/Operations.Promise.js create mode 100644 builtins/PromiseConstructor.js create mode 100644 builtins/StringConstructor.js create mode 100644 builtins/StringIterator.prototype.js create mode 100644 bytecode/BytecodeIntrinsicRegistry.cpp create mode 100644 bytecode/BytecodeIntrinsicRegistry.h create mode 100644 bytecode/BytecodeKills.h create mode 100644 bytecode/CallEdge.cpp create mode 100644 bytecode/CallEdge.h create mode 100644 bytecode/CallVariant.cpp create mode 100644 bytecode/CallVariant.h create mode 100644 bytecode/ComplexGetStatus.cpp create mode 100644 bytecode/ComplexGetStatus.h rename bytecode/{ProfiledCodeBlockJettisoningWatchpoint.cpp => ConstantStructureCheck.cpp} (51%) create mode 100644 bytecode/ConstantStructureCheck.h create mode 100644 bytecode/DeferredSourceDump.cpp create mode 100644 bytecode/DeferredSourceDump.h create mode 100644 bytecode/StructureSet.cpp rename jit/ClosureCallStubRoutine.cpp => bytecode/ToThisStatus.cpp (61%) create mode 100644 bytecode/ToThisStatus.h create mode 100644 bytecode/TrackedReferences.cpp create mode 100644 bytecode/TrackedReferences.h create mode 100644 bytecode/TypeLocation.h delete mode 100644 bytecode/VariableWatchpointSet.h rename runtime/JSArgumentsIterator.cpp => bytecode/VariableWriteFireDetail.cpp (77%) create mode 100644 bytecode/VariableWriteFireDetail.h rename bytecode/{VariableWatchpointSetInlines.h => VirtualRegister.cpp} (66%) create mode 100644 create-llvm-ir-from-source-file.py create mode 100755 create-symbol-table-index.py delete mode 100644 create_jit_stubs delete mode 100644 debugger/DebuggerActivation.cpp create mode 100644 debugger/DebuggerEvalEnabler.h create mode 100644 debugger/DebuggerScope.cpp create mode 100644 debugger/DebuggerScope.h create mode 100644 dfg/DFGArgumentsEliminationPhase.cpp create mode 100644 dfg/DFGArgumentsEliminationPhase.h delete mode 100644 dfg/DFGArgumentsSimplificationPhase.cpp create mode 100644 dfg/DFGArgumentsUtilities.cpp rename dfg/{DFGDesiredStructureChains.h => DFGArgumentsUtilities.h} (70%) create mode 100644 dfg/DFGAvailabilityMap.cpp create mode 100644 dfg/DFGAvailabilityMap.h delete mode 100644 dfg/DFGBinarySwitch.cpp create mode 100644 dfg/DFGBlockMap.h create mode 100644 dfg/DFGBlockMapInlines.h create mode 100644 dfg/DFGBlockSet.cpp create mode 100644 dfg/DFGBlockSet.h create mode 100644 dfg/DFGBlockSetInlines.h create mode 100644 dfg/DFGBlockWorklist.cpp create mode 100644 dfg/DFGBlockWorklist.h create mode 100644 dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h rename dfg/{DFGResurrectionForValidationPhase.cpp => DFGCleanUpPhase.cpp} (53%) create mode 100644 dfg/DFGCleanUpPhase.h create mode 100644 dfg/DFGCombinedLiveness.cpp rename dfg/{DFGValueRecoveryOverride.h => DFGCombinedLiveness.h} (72%) create mode 100644 dfg/DFGConstantHoistingPhase.cpp create mode 100644 dfg/DFGConstantHoistingPhase.h create mode 100644 dfg/DFGDoesGC.cpp create mode 100644 dfg/DFGDoesGC.h create mode 100644 dfg/DFGEpoch.cpp create mode 100644 dfg/DFGEpoch.h create mode 100644 dfg/DFGForAllKills.h create mode 100644 dfg/DFGFrozenValue.cpp create mode 100644 dfg/DFGFrozenValue.h create mode 100644 dfg/DFGHeapLocation.cpp create mode 100644 dfg/DFGHeapLocation.h create mode 100644 dfg/DFGInsertOSRHintsForUpdate.cpp create mode 100644 dfg/DFGInsertOSRHintsForUpdate.h create mode 100644 dfg/DFGIntegerRangeOptimizationPhase.cpp create mode 100644 dfg/DFGIntegerRangeOptimizationPhase.h create mode 100644 dfg/DFGLazyNode.cpp create mode 100644 dfg/DFGLazyNode.h create mode 100644 dfg/DFGMayExit.cpp rename dfg/{DFGArgumentsSimplificationPhase.h => DFGMayExit.h} (78%) rename dfg/{DFGDesiredStructureChains.cpp => DFGMinifiedGraph.cpp} (72%) create mode 100644 dfg/DFGMovHintRemovalPhase.cpp create mode 100644 dfg/DFGMovHintRemovalPhase.h create mode 100644 dfg/DFGNaiveDominators.cpp create mode 100644 dfg/DFGNaiveDominators.h create mode 100644 dfg/DFGOSRExitFuzz.cpp create mode 100644 dfg/DFGOSRExitFuzz.h create mode 100644 dfg/DFGObjectAllocationSinkingPhase.cpp create mode 100644 dfg/DFGObjectAllocationSinkingPhase.h create mode 100644 dfg/DFGObjectMaterializationData.cpp create mode 100644 dfg/DFGObjectMaterializationData.h create mode 100644 dfg/DFGPhantomInsertionPhase.cpp create mode 100644 dfg/DFGPhantomInsertionPhase.h create mode 100644 dfg/DFGPhiChildren.cpp create mode 100644 dfg/DFGPhiChildren.h create mode 100644 dfg/DFGPrePostNumbering.cpp create mode 100644 dfg/DFGPrePostNumbering.h create mode 100644 dfg/DFGPreciseLocalClobberize.h create mode 100644 dfg/DFGPromoteHeapAccess.h create mode 100644 dfg/DFGPromotedHeapLocation.cpp create mode 100644 dfg/DFGPromotedHeapLocation.h create mode 100644 dfg/DFGPureValue.cpp create mode 100644 dfg/DFGPureValue.h create mode 100644 dfg/DFGPutStackSinkingPhase.cpp create mode 100644 dfg/DFGPutStackSinkingPhase.h create mode 100644 dfg/DFGSSACalculator.cpp create mode 100644 dfg/DFGSSACalculator.h delete mode 100644 dfg/DFGStoreBarrierElisionPhase.cpp create mode 100644 dfg/DFGStoreBarrierInsertionPhase.cpp create mode 100644 dfg/DFGStoreBarrierInsertionPhase.h create mode 100644 dfg/DFGStructureAbstractValue.cpp create mode 100644 dfg/DFGStructureClobberState.h create mode 100644 dfg/DFGStructureRegistrationPhase.cpp rename dfg/{DFGResurrectionForValidationPhase.h => DFGStructureRegistrationPhase.h} (59%) create mode 100644 dfg/DFGTransition.cpp create mode 100644 dfg/DFGTransition.h create mode 100644 dfg/DFGValueStrength.cpp create mode 100644 dfg/DFGValueStrength.h create mode 100644 dfg/DFGVarargsForwardingPhase.cpp create mode 100644 dfg/DFGVarargsForwardingPhase.h create mode 100644 features.json create mode 100644 ftl/FTLExitPropertyValue.cpp create mode 100644 ftl/FTLExitPropertyValue.h create mode 100644 ftl/FTLExitTimeObjectMaterialization.cpp create mode 100644 ftl/FTLExitTimeObjectMaterialization.h create mode 100644 ftl/FTLJSCallBase.cpp create mode 100644 ftl/FTLJSCallBase.h create mode 100644 ftl/FTLJSCallVarargs.cpp create mode 100644 ftl/FTLJSCallVarargs.h create mode 100644 ftl/FTLOperations.cpp create mode 100644 ftl/FTLOperations.h delete mode 100644 heap/BlockAllocator.cpp delete mode 100644 heap/BlockAllocator.h delete mode 100644 heap/DelayedReleaseScope.h create mode 100644 heap/HeapVerifier.cpp create mode 100644 heap/HeapVerifier.h delete mode 100644 heap/Region.h delete mode 100644 heap/SuperRegion.cpp create mode 100644 inspector/InspectorProtocolTypes.h delete mode 100644 inspector/InspectorTypeBuilder.h delete mode 100644 inspector/JSConsoleClient.cpp create mode 100644 inspector/JSGlobalObjectConsoleClient.cpp rename inspector/{JSConsoleClient.h => JSGlobalObjectConsoleClient.h} (76%) delete mode 100644 inspector/agents/InspectorProfilerAgent.cpp delete mode 100644 inspector/agents/InspectorProfilerAgent.h create mode 100644 inspector/augmentable/AlternateDispatchableAgent.h create mode 100644 inspector/augmentable/AugmentableInspectorController.h rename inspector/{agents/JSGlobalObjectProfilerAgent.cpp => augmentable/AugmentableInspectorControllerClient.h} (75%) create mode 100644 inspector/protocol/ApplicationCache.json create mode 100644 inspector/protocol/CSS.json create mode 100644 inspector/protocol/DOM.json create mode 100644 inspector/protocol/DOMDebugger.json create mode 100644 inspector/protocol/DOMStorage.json create mode 100644 inspector/protocol/Database.json create mode 100644 inspector/protocol/IndexedDB.json rename inspector/protocol/{InspectorDomain.json => Inspector.json} (70%) create mode 100644 inspector/protocol/LayerTree.json create mode 100644 inspector/protocol/Network.json create mode 100644 inspector/protocol/OverlayTypes.json create mode 100644 inspector/protocol/Page.json delete mode 100644 inspector/protocol/Profiler.json create mode 100644 inspector/protocol/Replay.json create mode 100644 inspector/protocol/Timeline.json create mode 100644 inspector/protocol/Worker.json delete mode 100755 inspector/scripts/CodeGeneratorInspector.py delete mode 100644 inspector/scripts/CodeGeneratorInspectorStrings.py create mode 100644 inspector/scripts/codegen/__init__.py create mode 100644 inspector/scripts/codegen/cpp_generator.py create mode 100755 inspector/scripts/codegen/cpp_generator_templates.py create mode 100755 inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py create mode 100755 inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py create mode 100755 inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py create mode 100755 inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py create mode 100755 inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py create mode 100755 inspector/scripts/codegen/generate_cpp_protocol_types_header.py create mode 100755 inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py create mode 100755 inspector/scripts/codegen/generate_js_backend_commands.py create mode 100755 inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py create mode 100755 inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py create mode 100755 inspector/scripts/codegen/generate_objc_configuration_header.py create mode 100755 inspector/scripts/codegen/generate_objc_configuration_implementation.py create mode 100755 inspector/scripts/codegen/generate_objc_conversion_helpers.py create mode 100755 inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py create mode 100755 inspector/scripts/codegen/generate_objc_header.py create mode 100755 inspector/scripts/codegen/generate_objc_internal_header.py create mode 100755 inspector/scripts/codegen/generate_objc_protocol_types_implementation.py create mode 100755 inspector/scripts/codegen/generator.py create mode 100644 inspector/scripts/codegen/generator_templates.py create mode 100755 inspector/scripts/codegen/models.py create mode 100755 inspector/scripts/codegen/objc_generator.py create mode 100755 inspector/scripts/codegen/objc_generator_templates.py create mode 100755 inspector/scripts/generate-inspector-protocol-bindings.py create mode 100644 inspector/scripts/tests/commands-with-async-attribute.json create mode 100644 inspector/scripts/tests/commands-with-optional-call-return-parameters.json create mode 100644 inspector/scripts/tests/domains-with-varying-command-sizes.json create mode 100644 inspector/scripts/tests/enum-values.json create mode 100644 inspector/scripts/tests/events-with-optional-parameters.json create mode 100644 inspector/scripts/tests/expected/commands-with-async-attribute.json-result create mode 100644 inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result create mode 100644 inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result create mode 100644 inspector/scripts/tests/expected/enum-values.json-result create mode 100644 inspector/scripts/tests/expected/events-with-optional-parameters.json-result create mode 100644 inspector/scripts/tests/expected/fail-on-domain-availability.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-duplicate-command-call-parameter-names.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-duplicate-command-return-parameter-names.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-duplicate-event-parameter-names.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-duplicate-type-declarations.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-duplicate-type-member-names.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-enum-with-no-values.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-string-typed-optional-parameter-flag.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-string-typed-optional-type-member.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-type-declaration-using-type-reference.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-type-with-lowercase-name.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-declaration.json-error create mode 100644 inspector/scripts/tests/expected/fail-on-unknown-type-reference-in-type-member.json-error create mode 100644 inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result create mode 100644 inspector/scripts/tests/expected/same-type-id-different-domain.json-result create mode 100644 inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result create mode 100644 inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result create mode 100644 inspector/scripts/tests/expected/type-declaration-array-type.json-result create mode 100644 inspector/scripts/tests/expected/type-declaration-enum-type.json-result create mode 100644 inspector/scripts/tests/expected/type-declaration-object-type.json-result create mode 100644 inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result create mode 100644 inspector/scripts/tests/fail-on-domain-availability.json create mode 100644 inspector/scripts/tests/fail-on-duplicate-command-call-parameter-names.json create mode 100644 inspector/scripts/tests/fail-on-duplicate-command-return-parameter-names.json create mode 100644 inspector/scripts/tests/fail-on-duplicate-event-parameter-names.json create mode 100644 inspector/scripts/tests/fail-on-duplicate-type-declarations.json create mode 100644 inspector/scripts/tests/fail-on-duplicate-type-member-names.json create mode 100644 inspector/scripts/tests/fail-on-enum-with-no-values.json create mode 100644 inspector/scripts/tests/fail-on-string-typed-optional-parameter-flag.json create mode 100644 inspector/scripts/tests/fail-on-string-typed-optional-type-member.json create mode 100644 inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json create mode 100644 inspector/scripts/tests/fail-on-type-with-lowercase-name.json create mode 100644 inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json create mode 100644 inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json create mode 100644 inspector/scripts/tests/generate-domains-with-feature-guards.json create mode 100644 inspector/scripts/tests/same-type-id-different-domain.json create mode 100644 inspector/scripts/tests/shadowed-optional-type-setters.json create mode 100644 inspector/scripts/tests/type-declaration-aliased-primitive-type.json create mode 100644 inspector/scripts/tests/type-declaration-array-type.json create mode 100644 inspector/scripts/tests/type-declaration-enum-type.json create mode 100644 inspector/scripts/tests/type-declaration-object-type.json create mode 100644 inspector/scripts/tests/type-requiring-runtime-casts.json rename runtime/ArgumentsIteratorConstructor.cpp => interpreter/VMEntryRecord.h (64%) delete mode 100644 interpreter/VMInspector.cpp delete mode 100644 interpreter/VMInspector.h create mode 100644 jit/BinarySwitch.cpp rename dfg/DFGBinarySwitch.h => jit/BinarySwitch.h (90%) create mode 100644 jit/ExecutableAllocationFuzz.cpp create mode 100644 jit/ExecutableAllocationFuzz.h create mode 100644 jit/PolymorphicCallStubRoutine.cpp create mode 100644 jit/PolymorphicCallStubRoutine.h create mode 100644 jit/SetupVarargsFrame.cpp create mode 100644 jit/SetupVarargsFrame.h rename llvm/{InitializeLLVMMac.mm => InitializeLLVMMac.cpp} (71%) create mode 100644 llvm/library/libllvmForJSC.version delete mode 100644 parser/NodeInfo.h create mode 100644 parser/ParserFunctionInfo.h delete mode 100644 replay/scripts/tests/expected/fail-on-no-inputs.json-error delete mode 100644 replay/scripts/tests/expected/fail-on-no-types.json-error delete mode 100644 replay/scripts/tests/fail-on-no-inputs.json delete mode 100644 replay/scripts/tests/fail-on-no-types.json delete mode 100644 runtime/Arguments.cpp delete mode 100644 runtime/Arguments.h delete mode 100644 runtime/ArgumentsIteratorPrototype.cpp create mode 100644 runtime/ArgumentsMode.h create mode 100644 runtime/BasicBlockLocation.cpp rename jit/ClosureCallStubRoutine.h => runtime/BasicBlockLocation.h (55%) create mode 100644 runtime/BundlePath.cpp create mode 100644 runtime/BundlePath.h create mode 100644 runtime/BundlePath.mm create mode 100644 runtime/ClonedArguments.cpp create mode 100644 runtime/ClonedArguments.h create mode 100644 runtime/ConstantMode.cpp create mode 100644 runtime/ControlFlowProfiler.cpp create mode 100644 runtime/ControlFlowProfiler.h create mode 100644 runtime/DirectArguments.cpp create mode 100644 runtime/DirectArguments.h create mode 100644 runtime/DirectArgumentsOffset.cpp rename heap/HeapBlock.h => runtime/DirectArgumentsOffset.h (63%) create mode 100644 runtime/EnumerationMode.h create mode 100644 runtime/Exception.cpp rename runtime/{JSArgumentsIterator.h => Exception.h} (50%) create mode 100644 runtime/ExceptionFuzz.cpp rename inspector/agents/JSGlobalObjectProfilerAgent.h => runtime/ExceptionFuzz.h (70%) create mode 100644 runtime/FunctionHasExecutedCache.cpp create mode 100644 runtime/FunctionHasExecutedCache.h create mode 100644 runtime/FunctionRareData.cpp create mode 100644 runtime/FunctionRareData.h rename debugger/DebuggerActivation.h => runtime/GenericArguments.h (62%) create mode 100644 runtime/GenericArgumentsInlines.h create mode 100644 runtime/GenericOffset.h create mode 100644 runtime/InferredValue.cpp create mode 100644 runtime/InferredValue.h create mode 100644 runtime/IntlObject.cpp rename heap/SuperRegion.h => runtime/IntlObject.h (68%) create mode 100644 runtime/IterationStatus.h create mode 100644 runtime/IteratorOperations.cpp create mode 100644 runtime/IteratorOperations.h rename runtime/{MapIteratorConstructor.cpp => IteratorPrototype.cpp} (66%) rename runtime/{MapIteratorConstructor.h => IteratorPrototype.h} (70%) delete mode 100644 runtime/JSActivation.h create mode 100644 runtime/JSCallee.cpp create mode 100644 runtime/JSCallee.h create mode 100644 runtime/JSCatchScope.cpp create mode 100644 runtime/JSCatchScope.h rename runtime/{JSVariableObject.cpp => JSEnvironmentRecord.cpp} (73%) create mode 100644 runtime/JSEnvironmentRecord.h create mode 100644 runtime/JSFunctionNameScope.cpp create mode 100644 runtime/JSFunctionNameScope.h rename runtime/{JSPromiseReaction.h => JSJob.cpp} (54%) rename dfg/DFGStoreBarrierElisionPhase.h => runtime/JSJob.h (85%) rename runtime/{JSActivation.cpp => JSLexicalEnvironment.cpp} (50%) create mode 100644 runtime/JSLexicalEnvironment.h delete mode 100644 runtime/JSPromiseFunctions.cpp delete mode 100644 runtime/JSPromiseReaction.cpp create mode 100644 runtime/JSPropertyNameEnumerator.cpp create mode 100644 runtime/JSPropertyNameEnumerator.h delete mode 100644 runtime/JSPropertyNameIterator.cpp delete mode 100644 runtime/JSPropertyNameIterator.h create mode 100644 runtime/JSStringIterator.cpp create mode 100644 runtime/JSStringIterator.h create mode 100644 runtime/JSTemplateRegistryKey.cpp rename runtime/{NameInstance.h => JSTemplateRegistryKey.h} (63%) rename runtime/{SetIteratorConstructor.cpp => JSWeakSet.cpp} (71%) create mode 100644 runtime/JSWeakSet.h delete mode 100644 runtime/MapData.cpp create mode 100644 runtime/MapDataInlines.h create mode 100644 runtime/MathCommon.cpp create mode 100644 runtime/MathCommon.h delete mode 100644 runtime/NamePrototype.cpp create mode 100644 runtime/NullGetterFunction.cpp rename runtime/{ArrayIteratorConstructor.h => NullGetterFunction.h} (68%) create mode 100644 runtime/NullSetterFunction.cpp create mode 100644 runtime/NullSetterFunction.h delete mode 100644 runtime/PropertyNameArray.cpp create mode 100644 runtime/RuntimeFlags.h create mode 100644 runtime/RuntimeType.cpp create mode 100644 runtime/RuntimeType.h create mode 100644 runtime/ScopeOffset.cpp create mode 100644 runtime/ScopeOffset.h create mode 100644 runtime/ScopedArguments.cpp create mode 100644 runtime/ScopedArguments.h create mode 100644 runtime/ScopedArgumentsTable.cpp create mode 100644 runtime/ScopedArgumentsTable.h create mode 100644 runtime/StringIteratorPrototype.cpp create mode 100644 runtime/StringIteratorPrototype.h create mode 100644 runtime/Symbol.cpp create mode 100644 runtime/Symbol.h create mode 100644 runtime/SymbolConstructor.cpp rename runtime/{NameConstructor.h => SymbolConstructor.h} (69%) create mode 100644 runtime/SymbolObject.cpp create mode 100644 runtime/SymbolObject.h create mode 100644 runtime/SymbolPrototype.cpp rename runtime/{NamePrototype.h => SymbolPrototype.h} (69%) rename runtime/{NameConstructor.cpp => TemplateRegistry.cpp} (50%) rename runtime/{NameInstance.cpp => TemplateRegistry.h} (72%) create mode 100644 runtime/TemplateRegistryKey.h create mode 100644 runtime/TypeLocationCache.cpp create mode 100644 runtime/TypeLocationCache.h create mode 100644 runtime/TypeProfiler.cpp create mode 100644 runtime/TypeProfiler.h create mode 100644 runtime/TypeProfilerLog.cpp rename runtime/{JSVariableObject.h => TypeProfilerLog.h} (54%) create mode 100644 runtime/TypeSet.cpp create mode 100644 runtime/TypeSet.h create mode 100644 runtime/TypeofType.cpp create mode 100644 runtime/TypeofType.h create mode 100644 runtime/VarOffset.cpp create mode 100644 runtime/VarOffset.h create mode 100644 runtime/WeakGCMapInlines.h create mode 100644 runtime/WeakSetConstructor.cpp rename runtime/{ArgumentsIteratorConstructor.h => WeakSetConstructor.h} (70%) create mode 100644 runtime/WeakSetPrototype.cpp rename runtime/{ArgumentsIteratorPrototype.h => WeakSetPrototype.h} (76%) create mode 100644 tested-symbols.symlst create mode 100644 tests/controlFlowProfiler.yaml create mode 100644 tests/controlFlowProfiler/brace-location.js create mode 100644 tests/controlFlowProfiler/conditional-expression.js create mode 100644 tests/controlFlowProfiler/driver/driver.js create mode 100644 tests/controlFlowProfiler/if-statement.js create mode 100644 tests/controlFlowProfiler/loop-statements.js create mode 100644 tests/controlFlowProfiler/switch-statements.js create mode 100644 tests/controlFlowProfiler/test-jit.js create mode 100644 tests/executableAllocationFuzz.yaml create mode 100644 tests/executableAllocationFuzz/v8-raytrace.js create mode 100644 tests/stress/activation-sink-default-value.js create mode 100644 tests/stress/activation-sink-osrexit-default-value.js create mode 100644 tests/stress/activation-sink-osrexit.js create mode 100644 tests/stress/activation-sink.js create mode 100644 tests/stress/add-overflows-after-not-equal.js create mode 100644 tests/stress/arguments-bizarre-behavior.js create mode 100644 tests/stress/arguments-bizarre-behaviour-disable-enumerability.js create mode 100644 tests/stress/arguments-callee-uninitialized.js create mode 100644 tests/stress/arguments-captured.js create mode 100644 tests/stress/arguments-custom-properties-gc.js create mode 100644 tests/stress/arguments-exit-fixed.js create mode 100644 tests/stress/arguments-exit-strict-mode-fixed.js create mode 100644 tests/stress/arguments-exit-strict-mode.js create mode 100644 tests/stress/arguments-exit.js create mode 100644 tests/stress/arguments-inlined-exit-strict-mode-fixed.js create mode 100644 tests/stress/arguments-inlined-exit-strict-mode.js create mode 100644 tests/stress/arguments-inlined-exit.js create mode 100644 tests/stress/arguments-interference-cfg.js create mode 100644 tests/stress/arguments-interference.js create mode 100644 tests/stress/arguments-iterator.js create mode 100644 tests/stress/arith-add-with-constants.js create mode 100644 tests/stress/arith-modulo-node-behaviors.js create mode 100644 tests/stress/arith-mul-with-constants.js create mode 100644 tests/stress/array-copywithin.js create mode 100644 tests/stress/array-fill-put-by-val.js create mode 100644 tests/stress/array-filter-put-by-val-direct.js create mode 100644 tests/stress/array-find-does-not-lookup-twice.js create mode 100644 tests/stress/array-from-abs-and-floor.js create mode 100644 tests/stress/array-from-put-by-val-direct.js create mode 100644 tests/stress/array-from-set-length.js create mode 100644 tests/stress/array-from-with-accessors.js create mode 100644 tests/stress/array-from-with-iterable.js create mode 100644 tests/stress/array-from-with-iterator.js create mode 100644 tests/stress/array-iterators-next-with-call.js create mode 100644 tests/stress/array-iterators-next.js create mode 100644 tests/stress/array-length-array-storage-plain-object.js create mode 100644 tests/stress/array-length-plain-object.js create mode 100644 tests/stress/array-map-put-by-val-direct.js create mode 100644 tests/stress/arrayify-to-structure-contradiction.js create mode 100644 tests/stress/assignment-in-function-call-bracket-node.js create mode 100644 tests/stress/branch-may-exit-due-to-object-or-other-use-kind.js create mode 100644 tests/stress/builtin-function-is-construct-type-none.js create mode 100644 tests/stress/cached-prototype-setter.js create mode 100644 tests/stress/call-forward-varargs-for-inlined-escaped-arguments.js create mode 100644 tests/stress/call-varargs-length-effects.js create mode 100644 tests/stress/call-varargs-with-different-arguments-length-after-warmup.js create mode 100644 tests/stress/class-syntax-derived-default-constructor.js create mode 100644 tests/stress/class-syntax-no-loop-tdz.js create mode 100644 tests/stress/class-syntax-no-tdz-in-catch.js create mode 100644 tests/stress/class-syntax-no-tdz-in-conditional.js create mode 100644 tests/stress/class-syntax-no-tdz-in-eval.js create mode 100644 tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js create mode 100644 tests/stress/class-syntax-no-tdz-in-loop.js create mode 100644 tests/stress/class-syntax-no-tdz.js create mode 100644 tests/stress/class-syntax-tdz-in-catch.js create mode 100644 tests/stress/class-syntax-tdz-in-conditional.js create mode 100644 tests/stress/class-syntax-tdz-in-eval.js create mode 100644 tests/stress/class-syntax-tdz-in-loop.js create mode 100644 tests/stress/class-syntax-tdz.js create mode 100644 tests/stress/cloned-arguments-get-by-val-double-array.js create mode 100644 tests/stress/cloned-arguments-should-visit-callee-during-gc.js create mode 100644 tests/stress/closure-call-exit.js create mode 100644 tests/stress/construct-forward-varargs-for-inlined-escaped-arguments.js create mode 100644 tests/stress/construct-varargs-inline-smaller-Foo.js create mode 100644 tests/stress/construct-varargs-inline.js create mode 100644 tests/stress/construct-varargs-no-inline.js create mode 100644 tests/stress/constructor-with-return.js create mode 100644 tests/stress/create-this-with-callee-variants.js create mode 100644 tests/stress/custom-iterators.js create mode 100644 tests/stress/dead-get-closure-var.js create mode 100644 tests/stress/dead-osr-entry-value.js create mode 100644 tests/stress/dead-speculating-argument-use.js create mode 100644 tests/stress/destructuring-assignment-accepts-iterables.js create mode 100644 tests/stress/dfg-put-by-val-direct-with-edge-numbers.js create mode 100644 tests/stress/dfg-rare-data.js create mode 100644 tests/stress/dfg-to-primitive-pass-symbol.js create mode 100644 tests/stress/disable-function-dot-arguments.js create mode 100644 tests/stress/double-rep-with-non-cell.js create mode 100644 tests/stress/double-rep-with-null.js create mode 100644 tests/stress/double-rep-with-undefined.js create mode 100644 tests/stress/elidable-new-object-roflcopter-then-exit.js create mode 100644 tests/stress/elide-new-object-dag-then-exit.js create mode 100644 tests/stress/empty_eos_regex_split.js create mode 100644 tests/stress/equality-type-checking.js create mode 100644 tests/stress/escape-object-in-diamond-then-exit.js create mode 100644 tests/stress/eval-script-contains-null-character.js create mode 100644 tests/stress/exception-in-to-property-key-should-be-handled-early-in-object-methods.js create mode 100644 tests/stress/exception-in-to-property-key-should-be-handled-early.js create mode 100644 tests/stress/exit-from-getter.js create mode 100644 tests/stress/exit-from-setter.js create mode 100644 tests/stress/fold-based-on-int32-proof-mul-branch.js create mode 100644 tests/stress/fold-based-on-int32-proof-mul.js create mode 100644 tests/stress/fold-based-on-int32-proof-or-zero.js create mode 100644 tests/stress/fold-based-on-int32-proof.js create mode 100644 tests/stress/fold-load-varargs-arity-check-fail-barely.js create mode 100644 tests/stress/fold-load-varargs-arity-check-fail.js create mode 100644 tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js create mode 100644 tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js create mode 100644 tests/stress/fold-profiled-call-to-call.js create mode 100644 tests/stress/for-in-array-mode.js create mode 100644 tests/stress/for-in-base-reassigned-later-and-change-structure.js create mode 100644 tests/stress/for-in-base-reassigned-later.js create mode 100644 tests/stress/for-in-base-reassigned.js create mode 100644 tests/stress/for-in-capture-string-loop-var.js create mode 100644 tests/stress/for-in-delete-during-iteration.js create mode 100644 tests/stress/for-in-modify-int-loop-var.js create mode 100644 tests/stress/for-in-modify-string-loop-var.js create mode 100644 tests/stress/for-in-prototype.js create mode 100644 tests/stress/for-in-proxy-target-changed-structure.js create mode 100644 tests/stress/for-in-proxy.js create mode 100644 tests/stress/for-in-shadow-prototype-property.js create mode 100644 tests/stress/for-in-string.js create mode 100644 tests/stress/for-in-tests.js create mode 100644 tests/stress/for-in-typed-array.js create mode 100644 tests/stress/forward-varargs-for-inlined-escaped-arguments.js create mode 100644 tests/stress/freeze_leek.js create mode 100644 tests/stress/ftl-checkin-variable.js create mode 100644 tests/stress/ftl-checkin.js create mode 100644 tests/stress/ftl-getmyargumentslength-inline.js create mode 100644 tests/stress/ftl-in-overflow.js create mode 100644 tests/stress/ftl-library-exception.js create mode 100644 tests/stress/ftl-library-inline-gettimezoneoffset.js create mode 100644 tests/stress/ftl-library-inlining-exceptions-dataview.js create mode 100644 tests/stress/ftl-library-inlining-exceptions.js create mode 100644 tests/stress/ftl-library-inlining-loops.js create mode 100644 tests/stress/ftl-library-inlining-random.js create mode 100644 tests/stress/ftl-library-substring.js create mode 100644 tests/stress/ftl-switch-string-slow-duplicate-cases.js create mode 100644 tests/stress/function-expression-exit.js create mode 100644 tests/stress/function-name-scope.js create mode 100644 tests/stress/function-reentry-infer-on-self.js create mode 100644 tests/stress/function-sinking-no-double-allocate.js create mode 100644 tests/stress/function-sinking-osrexit.js create mode 100644 tests/stress/function-sinking-put.js create mode 100644 tests/stress/get-argument-by-val-in-inlined-varargs-call-out-of-bounds.js create mode 100644 tests/stress/get-argument-by-val-safe-in-inlined-varargs-call-out-of-bounds.js create mode 100644 tests/stress/get-by-val-out-of-bounds-basics.js create mode 100644 tests/stress/get-declared-unpassed-argument-in-direct-arguments.js create mode 100644 tests/stress/get-declared-unpassed-argument-in-scoped-arguments.js create mode 100644 tests/stress/get-local-elimination.js create mode 100644 tests/stress/get-my-argument-by-val-creates-arguments.js create mode 100644 tests/stress/get-my-argument-by-val-for-inlined-escaped-arguments.js create mode 100644 tests/stress/get-my-argument-by-val-out-of-bounds-no-warm-up.js create mode 100644 tests/stress/get-my-argument-by-val-out-of-bounds.js create mode 100644 tests/stress/get-my-argument-by-val-safe-out-of-bounds.js create mode 100644 tests/stress/get-my-argument-by-val-safe-wrap-around.js create mode 100644 tests/stress/get-my-argument-by-val-wrap-around-no-warm-up.js create mode 100644 tests/stress/get-my-argument-by-val-wrap-around.js create mode 100644 tests/stress/get-stack-identity-due-to-sinking.js create mode 100644 tests/stress/get-stack-mapping-with-dead-get-stack.js create mode 100644 tests/stress/get-stack-mapping.js create mode 100644 tests/stress/global-environment-does-not-trap-unscopables.js create mode 100644 tests/stress/goofy-function-reentry-incorrect-inference.js create mode 100644 tests/stress/has-custom-properties.js create mode 100644 tests/stress/infer-constant-global-property.js create mode 100644 tests/stress/infer-constant-property.js create mode 100644 tests/stress/infer-uninitialized-closure-var.js create mode 100644 tests/stress/initialize_functions_after_arguments.js create mode 100644 tests/stress/inline-call-that-doesnt-use-all-args.js create mode 100644 tests/stress/inline-varargs-get-arguments.js create mode 100644 tests/stress/int32array-transition-on-nan.js create mode 100644 tests/stress/iterator-functions.js create mode 100644 tests/stress/iterator-names.js create mode 100644 tests/stress/iterator-prototype.js create mode 100644 tests/stress/iterator-return-beyond-multiple-iteration-scopes.js create mode 100644 tests/stress/iterators-shape.js create mode 100644 tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js create mode 100644 tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js create mode 100644 tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js create mode 100644 tests/stress/liveness-pruning-needed-for-osr-availability-eager.js create mode 100644 tests/stress/liveness-pruning-needed-for-osr-availability.js create mode 100644 tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js create mode 100644 tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js create mode 100644 tests/stress/load-varargs-elimination-bounds-check-barely.js create mode 100644 tests/stress/load-varargs-elimination-bounds-check.js create mode 100644 tests/stress/load-varargs-then-inlined-call-and-exit-strict.js create mode 100644 tests/stress/load-varargs-then-inlined-call-and-exit.js create mode 100644 tests/stress/load-varargs-then-inlined-call-exit-in-foo.js create mode 100644 tests/stress/load-varargs-then-inlined-call-inlined.js create mode 100644 tests/stress/load-varargs-then-inlined-call.js create mode 100644 tests/stress/logical-not-masquerades.js create mode 100644 tests/stress/many-sunken-locals.js create mode 100644 tests/stress/map-constructor-adder.js create mode 100644 tests/stress/map-constructor.js create mode 100644 tests/stress/map-iterators-next.js create mode 100644 tests/stress/materialize-past-butterfly-allocation.js create mode 100644 tests/stress/materialize-past-put-structure.js create mode 100644 tests/stress/math-abs-positive.js create mode 100644 tests/stress/math-clz32-basics.js create mode 100644 tests/stress/math-log-basics.js create mode 100644 tests/stress/math-log-with-constants.js create mode 100644 tests/stress/math-pow-basics.js create mode 100644 tests/stress/math-pow-becomes-custom-function.js create mode 100644 tests/stress/math-pow-integer-exponent-fastpath.js create mode 100644 tests/stress/math-pow-nan-behaviors.js create mode 100644 tests/stress/math-pow-with-constants.js create mode 100644 tests/stress/math-pow-with-never-NaN-exponent.js create mode 100644 tests/stress/math-round-arith-rounding-mode.js create mode 100644 tests/stress/math-round-basics.js create mode 100644 tests/stress/math-sqrt-basics-disable-architecture-specific-optimizations.js create mode 100644 tests/stress/math-sqrt-basics.js create mode 100644 tests/stress/misc-is-object-or-null.js create mode 100644 tests/stress/modify-map-during-iteration.js create mode 100644 tests/stress/modify-set-during-iteration.js create mode 100644 tests/stress/multi-get-by-offset-dce.js create mode 100644 tests/stress/multi-put-by-offset-multiple-transitions.js create mode 100644 tests/stress/new-array-then-exit.js create mode 100644 tests/stress/new-largeish-contiguous-array-with-size.js create mode 100644 tests/stress/no-abc-skippy-loop.js create mode 100644 tests/stress/no-abc-skippy-paired-loop.js create mode 100644 tests/stress/object-allocation-sinking-with-uninitialized-property-on-one-path.js create mode 100644 tests/stress/object-escapes-in-loop.js create mode 100644 tests/stress/object-freeze-accept-non-object.js create mode 100644 tests/stress/object-get-own-property-descriptor-perform-to-object.js create mode 100644 tests/stress/object-get-own-property-names-perform-to-object.js create mode 100644 tests/stress/object-get-own-property-symbols-perform-to-object.js create mode 100644 tests/stress/object-get-own-property-symbols.js create mode 100644 tests/stress/object-get-prototype-of-perform-to-object.js create mode 100644 tests/stress/object-is-extensible-accept-non-object.js create mode 100644 tests/stress/object-is-frozen-accept-non-object.js create mode 100644 tests/stress/object-is-sealed-accept-non-object.js create mode 100644 tests/stress/object-keys-perform-to-object.js create mode 100644 tests/stress/object-prevent-extensions-accept-non-object.js create mode 100644 tests/stress/object-seal-accept-non-object.js create mode 100644 tests/stress/obviously-elidable-new-object-then-exit.js create mode 100644 tests/stress/op-push-name-scope-crashes-profiler.js create mode 100644 tests/stress/other-is-object-or-null.js create mode 100644 tests/stress/phantom-direct-arguments-clobber-argument-count.js create mode 100644 tests/stress/phantom-direct-arguments-clobber-callee.js create mode 100644 tests/stress/phantom-inadequacy.js create mode 100644 tests/stress/poly-call-exit-this.js create mode 100644 tests/stress/poly-call-exit.js create mode 100644 tests/stress/poly-chain-getter.js create mode 100644 tests/stress/poly-chain-setter.js create mode 100644 tests/stress/poly-chain-then-getter.js create mode 100644 tests/stress/poly-chain-then-setter.js create mode 100644 tests/stress/poly-getter-combo.js create mode 100644 tests/stress/poly-getter-then-chain.js create mode 100644 tests/stress/poly-getter-then-self.js create mode 100644 tests/stress/poly-self-getter.js create mode 100644 tests/stress/poly-self-then-getter.js create mode 100644 tests/stress/poly-setter-combo.js create mode 100644 tests/stress/poly-setter-then-self.js create mode 100644 tests/stress/proto-setter.js create mode 100644 tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js create mode 100644 tests/stress/put-by-id-build-list-order-recurse.js create mode 100644 tests/stress/put-by-id-direct-should-be-done-for-non-index-property.js create mode 100644 tests/stress/put-by-id-on-new-object-after-prototype-transition-non-strict.js create mode 100644 tests/stress/put-by-id-on-new-object-after-prototype-transition-strict.js create mode 100644 tests/stress/put-by-id-strict-build-list-order.js create mode 100644 tests/stress/put-by-val-out-of-bounds-basics.js create mode 100644 tests/stress/put-local-conservative.js create mode 100644 tests/stress/raise-error-in-iterator-close.js create mode 100644 tests/stress/real-forward-varargs-for-inlined-escaped-arguments.js create mode 100644 tests/stress/recursive_property_redefine_during_inline_caching.js create mode 100644 tests/stress/regress-141883.js create mode 100644 tests/stress/remove-phantom-after-setlocal.js create mode 100644 tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js create mode 100644 tests/stress/reserved-word-with-escape.js create mode 100644 tests/stress/rest-elements.js create mode 100644 tests/stress/scoped-arguments-array-length.js create mode 100644 tests/stress/scoped-then-direct-arguments-get-by-val-in-baseline.js create mode 100644 tests/stress/set-constructor-adder.js create mode 100644 tests/stress/set-constructor.js create mode 100644 tests/stress/set-iterators-next.js create mode 100644 tests/stress/simplify-varargs-mandatory-minimum-smaller-than-limit.js create mode 100644 tests/stress/singleton-scope-then-overwrite.js create mode 100644 tests/stress/singleton-scope-then-realloc-and-overwrite.js create mode 100644 tests/stress/singleton-scope-then-realloc.js create mode 100644 tests/stress/sink-arguments-past-invalid-check-dfg.js create mode 100644 tests/stress/sink-arguments-past-invalid-check-int32-dfg.js create mode 100644 tests/stress/sink-arguments-past-invalid-check-int32.js create mode 100644 tests/stress/sink-arguments-past-invalid-check-sneakier.js create mode 100644 tests/stress/sink-arguments-past-invalid-check.js create mode 100644 tests/stress/sink-function-past-invalid-check-sneakier.js create mode 100644 tests/stress/sink-function-past-invalid-check-sneaky.js create mode 100644 tests/stress/sink-object-past-invalid-check-int32.js create mode 100644 tests/stress/sink-object-past-invalid-check-sneakier.js create mode 100644 tests/stress/sink-object-past-invalid-check-sneaky.js create mode 100644 tests/stress/sink-object-past-invalid-check.js create mode 100644 tests/stress/sink_checkstructure.js create mode 100644 tests/stress/sort-array-with-undecided.js create mode 100644 tests/stress/sparse_splice.js create mode 100644 tests/stress/static-function-delete.js create mode 100644 tests/stress/static-function-put.js create mode 100644 tests/stress/static-getter-delete.js create mode 100644 tests/stress/static-getter-descriptors.js create mode 100644 tests/stress/static-getter-enumeration.js create mode 100644 tests/stress/static-getter-get.js create mode 100644 tests/stress/static-getter-in-names.js create mode 100644 tests/stress/static-getter-names.js create mode 100644 tests/stress/static-getter-put.js create mode 100644 tests/stress/string-from-code-point.js create mode 100644 tests/stress/string-iterators.js create mode 100644 tests/stress/string-raw.js create mode 100644 tests/stress/sub-overflows-after-not-equal.js create mode 100644 tests/stress/switch-typeof-indirect.js create mode 100644 tests/stress/switch-typeof-slightly-indirect.js create mode 100644 tests/stress/switch-typeof.js create mode 100644 tests/stress/symbol-and-string-constructor.js create mode 100644 tests/stress/symbol-define-property.js create mode 100644 tests/stress/symbol-registry.js create mode 100644 tests/stress/symbol-seal-and-freeze.js create mode 100644 tests/stress/symbol-with-json.js create mode 100644 tests/stress/tagged-templates-identity.js create mode 100644 tests/stress/tagged-templates-raw-strings.js create mode 100644 tests/stress/tagged-templates-syntax.js create mode 100644 tests/stress/tagged-templates-template-object.js create mode 100644 tests/stress/tagged-templates-this.js create mode 100644 tests/stress/tagged-templates.js create mode 100644 tests/stress/template-literal-line-terminators.js create mode 100644 tests/stress/template-literal-syntax.js create mode 100644 tests/stress/template-literal.js create mode 100644 tests/stress/throw-from-ftl-in-loop.js create mode 100644 tests/stress/throw-from-ftl.js create mode 100644 tests/stress/toprimitive-speculated-types.js create mode 100644 tests/stress/trailing-comma-in-patterns.js create mode 100644 tests/stress/type-of-functions-and-objects.js create mode 100644 tests/stress/typed-array-byte-offset.js create mode 100644 tests/stress/typed-array-get-by-val-profiling.js create mode 100644 tests/stress/typed-array-put-by-val-profiling.js create mode 100644 tests/stress/typeof-symbol.js create mode 100644 tests/stress/unscopables.js create mode 100644 tests/stress/values-unscopables.js create mode 100644 tests/stress/varargs-closure-inlined-exit-strict-mode.js create mode 100644 tests/stress/varargs-closure-inlined-exit.js create mode 100644 tests/stress/varargs-exit.js create mode 100644 tests/stress/varargs-inlined-exit.js create mode 100644 tests/stress/varargs-inlined-simple-exit-aliasing-weird-reversed-args.js create mode 100644 tests/stress/varargs-inlined-simple-exit-aliasing-weird.js create mode 100644 tests/stress/varargs-inlined-simple-exit-aliasing.js create mode 100644 tests/stress/varargs-inlined-simple-exit.js create mode 100644 tests/stress/varargs-inlining-underflow.js create mode 100644 tests/stress/varargs-then-slow-call.js create mode 100644 tests/stress/varargs-too-few-arguments.js create mode 100644 tests/stress/varargs-varargs-closure-inlined-exit.js create mode 100644 tests/stress/varargs-varargs-inlined-exit-strict-mode.js create mode 100644 tests/stress/varargs-varargs-inlined-exit.js create mode 100644 tests/stress/weak-map-constructor-adder.js create mode 100644 tests/stress/weak-map-constructor.js create mode 100644 tests/stress/weak-set-constructor-adder.js create mode 100644 tests/stress/weak-set-constructor.js create mode 100644 tests/stress/weird-getter-counter.js create mode 100644 tests/stress/weird-put-stack-varargs.js create mode 100644 tests/stress/weird-setter-counter-syntactic.js create mode 100644 tests/stress/weird-setter-counter.js create mode 100644 tests/typeProfiler.yaml create mode 100644 tests/typeProfiler/basic.js create mode 100644 tests/typeProfiler/captured.js create mode 100644 tests/typeProfiler/classes.js create mode 100644 tests/typeProfiler/dfg-jit-optimizations.js create mode 100644 tests/typeProfiler/dictionary-mode.js create mode 100644 tests/typeProfiler/driver/driver.js create mode 100644 tests/typeProfiler/inheritance.js create mode 100644 tests/typeProfiler/loop.js create mode 100644 tests/typeProfiler/optional-fields.js create mode 100644 tests/typeProfiler/overflow.js create mode 100644 tests/typeProfiler/return.js create mode 100644 tests/typeProfiler/symbol.js create mode 100644 tools/FunctionOverrides.cpp rename bytecode/ProfiledCodeBlockJettisoningWatchpoint.h => tools/FunctionOverrides.h (59%) rename runtime/ArrayIteratorConstructor.cpp => tools/JSDollarVM.cpp (78%) rename runtime/SetIteratorConstructor.h => tools/JSDollarVM.h (69%) create mode 100644 tools/JSDollarVMPrototype.cpp create mode 100644 tools/JSDollarVMPrototype.h diff --git a/API/JSAPIWrapperObject.h b/API/JSAPIWrapperObject.h index 9090397..14194b6 100644 --- a/API/JSAPIWrapperObject.h +++ b/API/JSAPIWrapperObject.h @@ -45,8 +45,6 @@ public: void setWrappedObject(void*); protected: - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - JSAPIWrapperObject(VM&, Structure*); private: diff --git a/API/JSAPIWrapperObject.mm b/API/JSAPIWrapperObject.mm index 897e96f..ef54602 100644 --- a/API/JSAPIWrapperObject.mm +++ b/API/JSAPIWrapperObject.mm @@ -26,7 +26,6 @@ #include "config.h" #include "JSAPIWrapperObject.h" -#include "DelayedReleaseScope.h" #include "JSCInlines.h" #include "JSCallbackObject.h" #include "JSVirtualMachineInternal.h" @@ -68,7 +67,7 @@ bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC:: namespace JSC { -template <> const ClassInfo JSCallbackObject<JSAPIWrapperObject>::s_info = { "JSAPIWrapperObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject<JSAPIWrapperObject>::s_info = { "JSAPIWrapperObject", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; template<> const bool JSCallbackObject<JSAPIWrapperObject>::needsDestruction = true; @@ -99,7 +98,6 @@ void JSAPIWrapperObject::setWrappedObject(void* wrappedObject) void JSAPIWrapperObject::visitChildren(JSCell* cell, JSC::SlotVisitor& visitor) { JSAPIWrapperObject* thisObject = JSC::jsCast<JSAPIWrapperObject*>(cell); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); Base::visitChildren(cell, visitor); if (thisObject->wrappedObject()) diff --git a/API/JSBase.cpp b/API/JSBase.cpp index 31bdf2b..3c5594b 100644 --- a/API/JSBase.cpp +++ b/API/JSBase.cpp @@ -30,6 +30,8 @@ #include "APICast.h" #include "CallFrame.h" #include "Completion.h" +#include "Exception.h" +#include "GCActivityCallback.h" #include "InitializeThreading.h" #include "JSGlobalObject.h" #include "JSLock.h" @@ -60,14 +62,14 @@ JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef th // evaluate sets "this" to the global object if it is NULL JSGlobalObject* globalObject = exec->vmEntryGlobalObject(); - SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); - JSValue evaluationException; - JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, &evaluationException); + NakedPtr<Exception> evaluationException; + JSValue returnValue = evaluate(globalObject->globalExec(), source, jsThisObject, evaluationException); if (evaluationException) { if (exception) - *exception = toRef(exec, evaluationException); + *exception = toRef(exec, evaluationException->value()); #if ENABLE(REMOTE_INSPECTOR) // FIXME: If we have a debugger attached we could learn about ParseError exceptions through // ScriptDebugServer::sourceParsed and this path could produce a duplicate warning. The @@ -97,7 +99,7 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc startingLineNumber = std::max(1, startingLineNumber); - SourceCode source = makeSource(script->string(), sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + SourceCode source = makeSource(script->string(), sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); JSValue syntaxException; bool isValidSyntax = checkSyntax(exec->vmEntryGlobalObject()->globalExec(), source, &syntaxException); @@ -106,7 +108,8 @@ bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourc if (exception) *exception = toRef(exec, syntaxException); #if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, syntaxException); + Exception* exception = Exception::create(exec->vm(), syntaxException); + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); #endif return false; } @@ -138,7 +141,8 @@ void JSReportExtraMemoryCost(JSContextRef ctx, size_t size) } ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - exec->vm().heap.reportExtraMemoryCost(size); + + exec->vm().heap.deprecatedReportExtraMemory(size); } extern "C" JS_EXPORT void JSSynchronousGarbageCollectForDebugging(JSContextRef); diff --git a/API/JSBase.h b/API/JSBase.h index 7d0ea3a..4c96088 100644 --- a/API/JSBase.h +++ b/API/JSBase.h @@ -84,11 +84,6 @@ typedef struct OpaqueJSValue* JSObjectRef; #define JS_EXPORT #endif /* defined(JS_NO_EXPORT) */ -/* JS tests uses WTF but has no config.h, so we need to set the export defines here. */ -#ifndef WTF_EXPORT_PRIVATE -#define WTF_EXPORT_PRIVATE JS_EXPORT -#endif - #ifdef __cplusplus extern "C" { #endif @@ -141,11 +136,7 @@ JS_EXPORT void JSGarbageCollect(JSContextRef ctx); /* Enable the Objective-C API for platforms with a modern runtime. */ #if !defined(JSC_OBJC_API_ENABLED) -#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 #define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE))) -#else -#define JSC_OBJC_API_ENABLED (defined(__clang__) && defined(__APPLE__) && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 && !defined(__i386__)) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE))) -#endif #endif #endif /* JSBase_h */ diff --git a/API/JSCallbackConstructor.cpp b/API/JSCallbackConstructor.cpp index b5aeee4..65e66dc 100644 --- a/API/JSCallbackConstructor.cpp +++ b/API/JSCallbackConstructor.cpp @@ -37,7 +37,7 @@ namespace JSC { -const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) }; +const ClassInfo JSCallbackConstructor::s_info = { "CallbackConstructor", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackConstructor) }; JSCallbackConstructor::JSCallbackConstructor(JSGlobalObject* globalObject, Structure* structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback) : JSDestructibleObject(globalObject->vm(), structure) diff --git a/API/JSCallbackConstructor.h b/API/JSCallbackConstructor.h index d2792f8..f178936 100644 --- a/API/JSCallbackConstructor.h +++ b/API/JSCallbackConstructor.h @@ -34,6 +34,7 @@ namespace JSC { class JSCallbackConstructor : public JSDestructibleObject { public: typedef JSDestructibleObject Base; + static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance; static JSCallbackConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, JSObjectCallAsConstructorCallback callback) { @@ -56,7 +57,6 @@ public: protected: JSCallbackConstructor(JSGlobalObject*, Structure*, JSClassRef, JSObjectCallAsConstructorCallback); void finishCreation(JSGlobalObject*, JSClassRef); - static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; private: friend struct APICallbackFunction; diff --git a/API/JSCallbackFunction.cpp b/API/JSCallbackFunction.cpp index afdac63..047fcd0 100644 --- a/API/JSCallbackFunction.cpp +++ b/API/JSCallbackFunction.cpp @@ -42,7 +42,7 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSCallbackFunction); -const ClassInfo JSCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackFunction) }; +const ClassInfo JSCallbackFunction::s_info = { "CallbackFunction", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(JSCallbackFunction) }; JSCallbackFunction::JSCallbackFunction(VM& vm, Structure* structure, JSObjectCallAsFunctionCallback callback) : InternalFunction(vm, structure) diff --git a/API/JSCallbackObject.cpp b/API/JSCallbackObject.cpp index 53e51e7..02b38fd 100644 --- a/API/JSCallbackObject.cpp +++ b/API/JSCallbackObject.cpp @@ -34,8 +34,8 @@ namespace JSC { // Define the two types of JSCallbackObjects we support. -template <> const ClassInfo JSCallbackObject<JSDestructibleObject>::s_info = { "CallbackObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; -template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject<JSDestructibleObject>::s_info = { "CallbackObject", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; +template <> const ClassInfo JSCallbackObject<JSGlobalObject>::s_info = { "CallbackGlobalObject", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallbackObject) }; template<> const bool JSCallbackObject<JSDestructibleObject>::needsDestruction = true; template<> const bool JSCallbackObject<JSGlobalObject>::needsDestruction = false; @@ -61,15 +61,4 @@ Structure* JSCallbackObject<JSGlobalObject>::createStructure(VM& vm, JSGlobalObj return Structure::create(vm, globalObject, proto, TypeInfo(GlobalObjectType, StructureFlags), info()); } -void JSCallbackObjectData::finalize(Handle<Unknown> handle, void* context) -{ - JSClassRef jsClass = static_cast<JSClassRef>(context); - JSObjectRef thisRef = toRef(static_cast<JSObject*>(handle.get().asCell())); - - for (; jsClass; jsClass = jsClass->parentClass) - if (JSObjectFinalizeCallback finalize = jsClass->finalize) - finalize(thisRef); - WeakSet::deallocate(WeakImpl::asWeakImpl(handle.slot())); -} - } // namespace JSC diff --git a/API/JSCallbackObject.h b/API/JSCallbackObject.h index 9c92588..33b4262 100644 --- a/API/JSCallbackObject.h +++ b/API/JSCallbackObject.h @@ -30,11 +30,12 @@ #include "JSObjectRef.h" #include "JSValueRef.h" #include "JSObject.h" -#include <wtf/PassOwnPtr.h> namespace JSC { -struct JSCallbackObjectData : WeakHandleOwner { +struct JSCallbackObjectData { + WTF_MAKE_FAST_ALLOCATED; +public: JSCallbackObjectData(void* privateData, JSClassRef jsClass) : privateData(privateData) , jsClass(jsClass) @@ -42,7 +43,7 @@ struct JSCallbackObjectData : WeakHandleOwner { JSClassRetain(jsClass); } - virtual ~JSCallbackObjectData() + ~JSCallbackObjectData() { JSClassRelease(jsClass); } @@ -57,7 +58,7 @@ struct JSCallbackObjectData : WeakHandleOwner { void setPrivateProperty(VM& vm, JSCell* owner, const Identifier& propertyName, JSValue value) { if (!m_privateProperties) - m_privateProperties = adoptPtr(new JSPrivatePropertyMap); + m_privateProperties = std::make_unique<JSPrivatePropertyMap>(); m_privateProperties->setPrivateProperty(vm, owner, propertyName, value); } @@ -106,11 +107,10 @@ struct JSCallbackObjectData : WeakHandleOwner { } private: - typedef HashMap<RefPtr<StringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap; + typedef HashMap<RefPtr<UniquedStringImpl>, WriteBarrier<Unknown>, IdentifierRepHash> PrivatePropertyMap; PrivatePropertyMap m_propertyMap; }; - OwnPtr<JSPrivatePropertyMap> m_privateProperties; - virtual void finalize(Handle<Unknown>, void*) override; + std::unique_ptr<JSPrivatePropertyMap> m_privateProperties; }; @@ -125,6 +125,9 @@ protected: public: typedef Parent Base; + static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesGetPropertyNames | TypeOfShouldCallGetCallData; + + ~JSCallbackObject(); static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data) { @@ -168,9 +171,6 @@ public: using Parent::methodTable; -protected: - static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Parent::StructureFlags; - private: static String className(const JSObject*); @@ -196,8 +196,6 @@ private: { JSCallbackObject* thisObject = jsCast<JSCallbackObject*>(cell); ASSERT_GC_OBJECT_INHERITS((static_cast<Parent*>(thisObject)), JSCallbackObject<Parent>::info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->Parent::structure()->typeInfo().overridesVisitChildren()); Parent::visitChildren(thisObject, visitor); thisObject->m_callbackObjectData->visitChildren(visitor); } @@ -214,7 +212,7 @@ private: static EncodedJSValue staticFunctionGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); static EncodedJSValue callbackGetter(ExecState*, JSObject*, EncodedJSValue, PropertyName); - OwnPtr<JSCallbackObjectData> m_callbackObjectData; + std::unique_ptr<JSCallbackObjectData> m_callbackObjectData; }; } // namespace JSC diff --git a/API/JSCallbackObjectFunctions.h b/API/JSCallbackObjectFunctions.h index 58c4eb5..280fa40 100644 --- a/API/JSCallbackObjectFunctions.h +++ b/API/JSCallbackObjectFunctions.h @@ -58,19 +58,31 @@ inline JSCallbackObject<Parent>* JSCallbackObject<Parent>::asCallbackObject(Enco template <class Parent> JSCallbackObject<Parent>::JSCallbackObject(ExecState* exec, Structure* structure, JSClassRef jsClass, void* data) : Parent(exec->vm(), structure) - , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(data, jsClass))) + , m_callbackObjectData(std::make_unique<JSCallbackObjectData>(data, jsClass)) { } +extern const GlobalObjectMethodTable javaScriptCoreAPIGlobalObjectMethodTable; + // Global object constructor. // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. template <class Parent> JSCallbackObject<Parent>::JSCallbackObject(VM& vm, JSClassRef jsClass, Structure* structure) - : Parent(vm, structure) - , m_callbackObjectData(adoptPtr(new JSCallbackObjectData(0, jsClass))) + : Parent(vm, structure, &javaScriptCoreAPIGlobalObjectMethodTable) + , m_callbackObjectData(std::make_unique<JSCallbackObjectData>(nullptr, jsClass)) { } +template <class Parent> +JSCallbackObject<Parent>::~JSCallbackObject() +{ + JSObjectRef thisRef = toRef(static_cast<JSObject*>(this)); + for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { + if (JSObjectFinalizeCallback finalize = jsClass->finalize) + finalize(thisRef); + } +} + template <class Parent> void JSCallbackObject<Parent>::finishCreation(ExecState* exec) { @@ -107,13 +119,6 @@ void JSCallbackObject<Parent>::init(ExecState* exec) JSObjectInitializeCallback initialize = initRoutines[i]; initialize(toRef(exec), toRef(this)); } - - for (JSClassRef jsClassPtr = classRef(); jsClassPtr; jsClassPtr = jsClassPtr->parentClass) { - if (jsClassPtr->finalize) { - WeakSet::allocate(this, m_callbackObjectData.get(), classRef()); - break; - } - } } template <class Parent> @@ -265,6 +270,9 @@ void JSCallbackObject<Parent>::put(JSCell* cell, ExecState* exec, PropertyName p if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { if (StaticFunctionEntry* entry = staticFunctions->get(name)) { + PropertySlot getSlot(thisObject); + if (Parent::getOwnPropertySlot(thisObject, exec, propertyName, getSlot)) + return Parent::put(thisObject, exec, propertyName, value, slot); if (entry->attributes & kJSPropertyAttributeReadOnly) return; thisObject->JSCallbackObject<Parent>::putDirect(exec->vm(), propertyName, value); // put as override property @@ -516,8 +524,10 @@ void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, Exe for (iterator it = staticValues->begin(); it != end; ++it) { StringImpl* name = it->key.get(); StaticValueEntry* entry = it->value.get(); - if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) - propertyNames.add(Identifier(exec, name)); + if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || mode.includeDontEnumProperties())) { + ASSERT(!name->isSymbol()); + propertyNames.add(Identifier::fromString(exec, String(name))); + } } } @@ -527,8 +537,10 @@ void JSCallbackObject<Parent>::getOwnNonIndexPropertyNames(JSObject* object, Exe for (iterator it = staticFunctions->begin(); it != end; ++it) { StringImpl* name = it->key.get(); StaticFunctionEntry* entry = it->value.get(); - if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, name)); + if (!(entry->attributes & kJSPropertyAttributeDontEnum) || mode.includeDontEnumProperties()) { + ASSERT(!name->isSymbol()); + propertyNames.add(Identifier::fromString(exec, String(name))); + } } } } diff --git a/API/JSClassRef.cpp b/API/JSClassRef.cpp index 452412e..e0dbe60 100644 --- a/API/JSClassRef.cpp +++ b/API/JSClassRef.cpp @@ -62,7 +62,7 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* initializeThreading(); if (const JSStaticValue* staticValue = definition->staticValues) { - m_staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable); + m_staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>(); while (staticValue->name) { String valueName = String::fromUTF8(staticValue->name); if (!valueName.isNull()) @@ -72,7 +72,7 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* } if (const JSStaticFunction* staticFunction = definition->staticFunctions) { - m_staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable); + m_staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>(); while (staticFunction->name) { String functionName = String::fromUTF8(staticFunction->name); if (!functionName.isNull()) @@ -108,12 +108,12 @@ OpaqueJSClass::~OpaqueJSClass() JSClassRelease(prototypeClass); } -PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition) +Ref<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition) { - return adoptRef(new OpaqueJSClass(definition, 0)); + return adoptRef(*new OpaqueJSClass(definition, 0)); } -PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition) +Ref<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition) { JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy. @@ -124,7 +124,7 @@ PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientD // We are supposed to use JSClassRetain/Release but since we know that we currently have // the only reference to this class object we cheat and use a RefPtr instead. RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0)); - return adoptRef(new OpaqueJSClass(&definition, protoClass.get())); + return adoptRef(*new OpaqueJSClass(&definition, protoClass.get())); } OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsClass) diff --git a/API/JSClassRef.h b/API/JSClassRef.h index 926f082..fa024d3 100644 --- a/API/JSClassRef.h +++ b/API/JSClassRef.h @@ -85,8 +85,8 @@ public: }; struct OpaqueJSClass : public ThreadSafeRefCounted<OpaqueJSClass> { - static PassRefPtr<OpaqueJSClass> create(const JSClassDefinition*); - static PassRefPtr<OpaqueJSClass> createNoAutomaticPrototype(const JSClassDefinition*); + static Ref<OpaqueJSClass> create(const JSClassDefinition*); + static Ref<OpaqueJSClass> createNoAutomaticPrototype(const JSClassDefinition*); JS_EXPORT_PRIVATE ~OpaqueJSClass(); String className(); @@ -120,8 +120,8 @@ private: // Strings in these data members should not be put into any AtomicStringTable. String m_className; - OwnPtr<OpaqueJSClassStaticValuesTable> m_staticValues; - OwnPtr<OpaqueJSClassStaticFunctionsTable> m_staticFunctions; + std::unique_ptr<OpaqueJSClassStaticValuesTable> m_staticValues; + std::unique_ptr<OpaqueJSClassStaticFunctionsTable> m_staticFunctions; }; #endif // JSClassRef_h diff --git a/API/JSContext.h b/API/JSContext.h index d9dcc21..7095f91 100644 --- a/API/JSContext.h +++ b/API/JSContext.h @@ -44,11 +44,7 @@ that reference a particular JSContext have been deallocated the JSContext will be deallocated unless it has been previously retained. */ -#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 NS_CLASS_AVAILABLE(10_9, 7_0) -#else -OBJC_VISIBLE -#endif @interface JSContext : NSObject /*! diff --git a/API/JSContext.mm b/API/JSContext.mm index 701bdd1..b3a4b7a 100644 --- a/API/JSContext.mm +++ b/API/JSContext.mm @@ -192,7 +192,7 @@ if (!name) return nil; - return [(NSString *)JSStringCopyCFString(kCFAllocatorDefault, name) autorelease]; + return (NSString *)adoptCF(JSStringCopyCFString(kCFAllocatorDefault, name)).autorelease(); } - (void)setName:(NSString *)name diff --git a/API/JSContextRef.cpp b/API/JSContextRef.cpp index 637b99d..4976c29 100644 --- a/API/JSContextRef.cpp +++ b/API/JSContextRef.cpp @@ -35,6 +35,7 @@ #include "JSGlobalObject.h" #include "JSObject.h" #include "JSCInlines.h" +#include "RuntimeFlags.h" #include "SourceProvider.h" #include "StackVisitor.h" #include <wtf/text/StringBuilder.h> @@ -43,6 +44,11 @@ #if ENABLE(REMOTE_INSPECTOR) #include "JSGlobalObjectDebuggable.h" #include "JSGlobalObjectInspectorController.h" +#include "JSRemoteInspector.h" +#endif + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "JSContextRefInspectorSupport.h" #endif #if OS(DARWIN) @@ -53,6 +59,15 @@ static const int32_t webkitFirstVersionWithConcurrentGlobalContexts = 0x2100500; using namespace JSC; +static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject* globalObject) +{ + RuntimeFlags runtimeFlags = JSGlobalObject::javaScriptRuntimeFlags(globalObject); + runtimeFlags.setPromiseDisabled(true); + return runtimeFlags; +} + +const GlobalObjectMethodTable JSC::javaScriptCoreAPIGlobalObjectMethodTable = { &JSGlobalObject::allowsAccessFrom, &JSGlobalObject::supportsProfiling, &JSGlobalObject::supportsRichSourceInfo, &JSGlobalObject::shouldInterruptScript, &javaScriptRuntimeFlags, nullptr, &JSGlobalObject::shouldInterruptScriptBeforeTimeout }; + // From the API's perspective, a context group remains alive iff // (a) it has been JSContextGroupRetained // OR @@ -61,7 +76,7 @@ using namespace JSC; JSContextGroupRef JSContextGroupCreate() { initializeThreading(); - return toRef(VM::createContextGroup().leakRef()); + return toRef(&VM::createContextGroup().leakRef()); } JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group) @@ -86,28 +101,38 @@ static bool internalScriptTimeoutCallback(ExecState* exec, void* callbackPtr, vo return callback(contextRef, callbackData); } +static void createWatchdogIfNeeded(VM& vm) +{ + if (!vm.watchdog) { + vm.watchdog = std::make_unique<Watchdog>(); + + // The LLINT peeks into the Watchdog object directly. In order to do that, + // the LLINT assumes that the internal shape of a std::unique_ptr is the + // same as a plain C++ pointer, and loads the address of Watchdog from it. + RELEASE_ASSERT(*reinterpret_cast<Watchdog**>(&vm.watchdog) == vm.watchdog.get()); + } +} + void JSContextGroupSetExecutionTimeLimit(JSContextGroupRef group, double limit, JSShouldTerminateCallback callback, void* callbackData) { VM& vm = *toJS(group); JSLockHolder locker(&vm); - if (!vm.watchdog) - vm.watchdog = std::make_unique<Watchdog>(); + createWatchdogIfNeeded(vm); Watchdog& watchdog = *vm.watchdog; if (callback) { void* callbackPtr = reinterpret_cast<void*>(callback); - watchdog.setTimeLimit(vm, limit, internalScriptTimeoutCallback, callbackPtr, callbackData); + watchdog.setTimeLimit(vm, std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit)), internalScriptTimeoutCallback, callbackPtr, callbackData); } else - watchdog.setTimeLimit(vm, limit); + watchdog.setTimeLimit(vm, std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(limit))); } void JSContextGroupClearExecutionTimeLimit(JSContextGroupRef group) { VM& vm = *toJS(group); JSLockHolder locker(&vm); - if (!vm.watchdog) - vm.watchdog = std::make_unique<Watchdog>(); + createWatchdogIfNeeded(vm); Watchdog& watchdog = *vm.watchdog; - watchdog.setTimeLimit(vm, std::numeric_limits<double>::infinity()); + watchdog.setTimeLimit(vm, std::chrono::microseconds::max()); } // From the API's perspective, a global context remains alive iff it has been JSGlobalContextRetained. @@ -134,10 +159,13 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass RefPtr<VM> vm = group ? PassRefPtr<VM>(toJS(group)) : VM::createContextGroup(); JSLockHolder locker(vm.get()); - vm->makeUsableFromMultipleThreads(); if (!globalObjectClass) { - JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull())); + JSGlobalObject* globalObject = JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()), &javaScriptCoreAPIGlobalObjectMethodTable); +#if ENABLE(REMOTE_INSPECTOR) + if (JSRemoteInspectorGetInspectionEnabledByDefault()) + globalObject->setRemoteDebuggingEnabled(true); +#endif return JSGlobalContextRetain(toGlobalRef(globalObject->globalExec())); } @@ -147,6 +175,10 @@ JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClass if (!prototype) prototype = jsNull(); globalObject->resetPrototype(*vm, prototype); +#if ENABLE(REMOTE_INSPECTOR) + if (JSRemoteInspectorGetInspectionEnabledByDefault()) + globalObject->setRemoteDebuggingEnabled(true); +#endif return JSGlobalContextRetain(toGlobalRef(exec)); } @@ -404,4 +436,19 @@ void JSGlobalContextSetDebuggerRunLoop(JSGlobalContextRef ctx, CFRunLoopRef runL UNUSED_PARAM(runLoop); #endif } +#endif // USE(CF) + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspectorController(JSGlobalContextRef ctx) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return nullptr; + } + + ExecState* exec = toJS(ctx); + JSLockHolder lock(exec); + + return &exec->vmEntryGlobalObject()->inspectorController(); +} #endif diff --git a/API/JSContextRef.h b/API/JSContextRef.h index cb25c00..0c800bc 100644 --- a/API/JSContextRef.h +++ b/API/JSContextRef.h @@ -48,7 +48,7 @@ extern "C" { synchronization is required. @result The created JSContextGroup. */ -JS_EXPORT JSContextGroupRef JSContextGroupCreate() CF_AVAILABLE(10_6, 7_0); +JS_EXPORT JSContextGroupRef JSContextGroupCreate(void) CF_AVAILABLE(10_6, 7_0); /*! @function diff --git a/API/JSContextRefInspectorSupport.h b/API/JSContextRefInspectorSupport.h new file mode 100644 index 0000000..a09d828 --- /dev/null +++ b/API/JSContextRefInspectorSupport.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 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 JSContextRefInspectorSupport_h +#define JSContextRefInspectorSupport_h + +#ifndef __cplusplus +#error Requires C++ Support. +#endif + +#include <JavaScriptCore/JSContextRefPrivate.h> + +namespace Inspector { +class AugmentableInspectorController; +} + +extern "C" { +JS_EXPORT Inspector::AugmentableInspectorController* JSGlobalContextGetAugmentableInspectorController(JSGlobalContextRef); +} + +#endif // JSContextRefInspectorSupport_h diff --git a/API/JSManagedValue.h b/API/JSManagedValue.h index 8665846..97764ee 100644 --- a/API/JSManagedValue.h +++ b/API/JSManagedValue.h @@ -50,11 +50,7 @@ Objective-C heap object, as this can very easily create a reference cycle, keeping the entire JSContext alive. */ -#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 NS_CLASS_AVAILABLE(10_9, 7_0) -#else -OBJC_VISIBLE -#endif @interface JSManagedValue : NSObject /*! diff --git a/API/JSManagedValue.mm b/API/JSManagedValue.mm index 953cb5f..a72d19b 100644 --- a/API/JSManagedValue.mm +++ b/API/JSManagedValue.mm @@ -37,6 +37,7 @@ #import "WeakHandleOwner.h" #import "ObjcRuntimeExtras.h" #import "JSCInlines.h" +#import <wtf/spi/cocoa/NSMapTableSPI.h> class JSManagedValueHandleOwner : public JSC::WeakHandleOwner { public: diff --git a/API/JSObjectRef.cpp b/API/JSObjectRef.cpp index dfad3bd..faf38ff 100644 --- a/API/JSObjectRef.cpp +++ b/API/JSObjectRef.cpp @@ -34,6 +34,7 @@ #include "CopiedSpaceInlines.h" #include "DateConstructor.h" #include "ErrorConstructor.h" +#include "Exception.h" #include "FunctionConstructor.h" #include "Identifier.h" #include "InitializeThreading.h" @@ -61,6 +62,26 @@ using namespace JSC; +enum class ExceptionStatus { + DidThrow, + DidNotThrow +}; + +static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef) +{ + if (exec->hadException()) { + Exception* exception = exec->exception(); + if (returnedExceptionRef) + *returnedExceptionRef = toRef(exec, exception->value()); + exec->clearException(); +#if ENABLE(REMOTE_INSPECTOR) + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); +#endif + return ExceptionStatus::DidThrow; + } + return ExceptionStatus::DidNotThrow; +} + JSClassRef JSClassCreate(const JSClassDefinition* definition) { initializeThreading(); @@ -140,24 +161,16 @@ JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned pa JSLockHolder locker(exec); startingLineNumber = std::max(1, startingLineNumber); - Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier(exec, "anonymous"); + Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier::fromString(exec, "anonymous"); MarkedArgumentBuffer args; for (unsigned i = 0; i < parameterCount; i++) args.append(jsString(exec, parameterNames[i]->string())); args.append(jsString(exec, body->string())); - JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL ? sourceURL->string() : String(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first())); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -180,16 +193,8 @@ JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSVa } else result = constructEmptyArray(exec, 0); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -208,16 +213,8 @@ JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSVal argList.append(toJS(exec, arguments[i])); JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), argList); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -235,16 +232,8 @@ JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSVa Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure(); JSObject* result = ErrorInstance::create(exec, errorStructure, message); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -263,16 +252,8 @@ JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSV argList.append(toJS(exec, arguments[i])); JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(), argList); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return toRef(result); } @@ -339,15 +320,7 @@ JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef JSObject* jsObject = toJS(object); JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm())); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); return toRef(exec, jsValue); } @@ -372,15 +345,7 @@ void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope jsObject->methodTable()->put(jsObject, exec, name, jsValue, slot); } - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); } JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception) @@ -395,15 +360,7 @@ JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsi JSObject* jsObject = toJS(object); JSValue jsValue = jsObject->get(exec, propertyIndex); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); return toRef(exec, jsValue); } @@ -421,15 +378,7 @@ void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned p JSValue jsValue = toJS(exec, value); jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); } bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) @@ -444,15 +393,7 @@ bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr JSObject* jsObject = toJS(object); bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm())); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); return result; } @@ -616,16 +557,8 @@ JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObject return 0; JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList)); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return result; } @@ -657,16 +590,8 @@ JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(exec, arguments[i])); JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList)); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) result = 0; - } return result; } @@ -698,7 +623,7 @@ JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef o JSObject* jsObject = toJS(object); JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(vm); PropertyNameArray array(vm); - jsObject->methodTable()->getPropertyNames(jsObject, exec, array, ExcludeDontEnumProperties); + jsObject->methodTable()->getPropertyNames(jsObject, exec, array, EnumerationMode()); size_t size = array.size(); propertyNames->array.reserveInitialCapacity(size); diff --git a/API/JSProfilerPrivate.cpp b/API/JSProfilerPrivate.cpp index 2a5ec2c..ac112ae 100644 --- a/API/JSProfilerPrivate.cpp +++ b/API/JSProfilerPrivate.cpp @@ -34,7 +34,11 @@ using namespace JSC; void JSStartProfiling(JSContextRef ctx, JSStringRef title) { - LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string()); + // Use an independent stopwatch for API-initiated profiling, since the user will expect it + // to be relative to when their command was issued. + RefPtr<Stopwatch> stopwatch = Stopwatch::create(); + stopwatch->start(); + LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string(), stopwatch.release()); } void JSEndProfiling(JSContextRef ctx, JSStringRef title) diff --git a/API/JSRemoteInspector.cpp b/API/JSRemoteInspector.cpp new file mode 100644 index 0000000..faebc5d --- /dev/null +++ b/API/JSRemoteInspector.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 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 "JSRemoteInspector.h" + +#include "JSGlobalObjectConsoleClient.h" + +#if ENABLE(REMOTE_INSPECTOR) +#include "RemoteInspector.h" +#endif + +using namespace Inspector; + +static bool remoteInspectionEnabledByDefault = true; + +void JSRemoteInspectorDisableAutoStart(void) +{ +#if ENABLE(REMOTE_INSPECTOR) + RemoteInspector::startDisabled(); +#endif +} + +void JSRemoteInspectorStart(void) +{ +#if ENABLE(REMOTE_INSPECTOR) + RemoteInspector::singleton(); +#endif +} + +void JSRemoteInspectorSetParentProcessInformation(pid_t pid, const UInt8* auditData, size_t auditLength) +{ +#if ENABLE(REMOTE_INSPECTOR) + RetainPtr<CFDataRef> auditDataRef = adoptCF(CFDataCreate(kCFAllocatorDefault, auditData, auditLength)); + RemoteInspector::singleton().setParentProcessInformation(pid, auditDataRef); +#else + UNUSED_PARAM(pid); + UNUSED_PARAM(auditData); + UNUSED_PARAM(auditLength); +#endif +} + +void JSRemoteInspectorSetLogToSystemConsole(bool logToSystemConsole) +{ + JSGlobalObjectConsoleClient::setLogToSystemConsole(logToSystemConsole); +} + +bool JSRemoteInspectorGetInspectionEnabledByDefault(void) +{ + return remoteInspectionEnabledByDefault; +} + +void JSRemoteInspectorSetInspectionEnabledByDefault(bool enabledByDefault) +{ + remoteInspectionEnabledByDefault = enabledByDefault; +} diff --git a/API/JSRemoteInspector.h b/API/JSRemoteInspector.h new file mode 100644 index 0000000..2bde479 --- /dev/null +++ b/API/JSRemoteInspector.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 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 JSRemoteInspector_h +#define JSRemoteInspector_h + +#include <JavaScriptCore/JSBase.h> +#include <JavaScriptCore/WebKitAvailability.h> + +#ifdef __cplusplus +extern "C" { +#endif + +JS_EXPORT void JSRemoteInspectorDisableAutoStart(void) CF_AVAILABLE(10_11, 9_0); +JS_EXPORT void JSRemoteInspectorStart(void) CF_AVAILABLE(10_11, 9_0); +JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(pid_t, const uint8_t* auditData, size_t auditLength) CF_AVAILABLE(10_11, 9_0); + +JS_EXPORT void JSRemoteInspectorSetLogToSystemConsole(bool) CF_AVAILABLE(10_11, 9_0); + +JS_EXPORT bool JSRemoteInspectorGetInspectionEnabledByDefault(void) CF_AVAILABLE(10_11, 9_0); +JS_EXPORT void JSRemoteInspectorSetInspectionEnabledByDefault(bool) CF_AVAILABLE(10_11, 9_0); + +#ifdef __cplusplus +} +#endif + +#endif /* JSRemoteInspector_h */ diff --git a/API/JSRetainPtr.h b/API/JSRetainPtr.h index f23e32f..262c4d5 100644 --- a/API/JSRetainPtr.h +++ b/API/JSRetainPtr.h @@ -75,6 +75,16 @@ private: T m_ptr; }; +inline JSRetainPtr<JSStringRef> adopt(JSStringRef o) +{ + return JSRetainPtr<JSStringRef>(Adopt, o); +} + +inline JSRetainPtr<JSGlobalContextRef> adopt(JSGlobalContextRef o) +{ + return JSRetainPtr<JSGlobalContextRef>(Adopt, o); +} + template<typename T> inline JSRetainPtr<T>::JSRetainPtr(const JSRetainPtr& o) : m_ptr(o.m_ptr) { diff --git a/API/JSScriptRef.cpp b/API/JSScriptRef.cpp index 1e872c7..a7baf14 100644 --- a/API/JSScriptRef.cpp +++ b/API/JSScriptRef.cpp @@ -27,6 +27,7 @@ #include "APICast.h" #include "Completion.h" +#include "Exception.h" #include "JSBasePrivate.h" #include "VM.h" #include "JSScriptRefPrivate.h" @@ -40,9 +41,9 @@ using namespace JSC; struct OpaqueJSScript : public SourceProvider { public: - static WTF::PassRefPtr<OpaqueJSScript> create(VM* vm, const String& url, int startingLineNumber, const String& source) + static WTF::RefPtr<OpaqueJSScript> create(VM* vm, const String& url, int startingLineNumber, const String& source) { - return WTF::adoptRef(new OpaqueJSScript(vm, url, startingLineNumber, source)); + return WTF::adoptRef(*new OpaqueJSScript(vm, url, startingLineNumber, source)); } virtual const String& source() const override @@ -68,7 +69,10 @@ private: static bool parseScript(VM* vm, const SourceCode& source, ParserError& error) { - return JSC::parse<JSC::ProgramNode>(vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error); + return !!JSC::parse<JSC::ProgramNode>( + vm, source, 0, Identifier(), JSParserBuiltinMode::NotBuiltin, + JSParserStrictMode::NotStrict, JSParserCodeType::Program, + error); } extern "C" { @@ -84,15 +88,15 @@ JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef context startingLineNumber = std::max(1, startingLineNumber); - RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, String(StringImpl::createFromLiteral(source, length))); + RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url ? url->string() : String(), startingLineNumber, String(StringImpl::createFromLiteral(source, length))); ParserError error; if (!parseScript(vm, SourceCode(result), error)) { if (errorMessage) - *errorMessage = OpaqueJSString::create(error.m_message).leakRef(); + *errorMessage = OpaqueJSString::create(error.message()).leakRef(); if (errorLine) - *errorLine = error.m_line; - return 0; + *errorLine = error.line(); + return nullptr; } return result.release().leakRef(); @@ -105,15 +109,15 @@ JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef startingLineNumber = std::max(1, startingLineNumber); - RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url->string(), startingLineNumber, source->string()); + RefPtr<OpaqueJSScript> result = OpaqueJSScript::create(vm, url ? url->string() : String(), startingLineNumber, source->string()); ParserError error; if (!parseScript(vm, SourceCode(result), error)) { if (errorMessage) - *errorMessage = OpaqueJSString::create(error.m_message).leakRef(); + *errorMessage = OpaqueJSString::create(error.message()).leakRef(); if (errorLine) - *errorLine = error.m_line; - return 0; + *errorLine = error.line(); + return nullptr; } return result.release().leakRef(); @@ -139,12 +143,12 @@ JSValueRef JSScriptEvaluate(JSContextRef context, JSScriptRef script, JSValueRef RELEASE_ASSERT_NOT_REACHED(); return 0; } - JSValue internalException; + NakedPtr<Exception> internalException; JSValue thisValue = thisValueRef ? toJS(exec, thisValueRef) : jsUndefined(); - JSValue result = evaluate(exec, SourceCode(script), thisValue, &internalException); + JSValue result = evaluate(exec, SourceCode(script), thisValue, internalException); if (internalException) { if (exception) - *exception = toRef(exec, internalException); + *exception = toRef(exec, internalException->value()); return 0; } ASSERT(result); diff --git a/API/JSStringRef.cpp b/API/JSStringRef.cpp index f31ed3d..c9b380c 100644 --- a/API/JSStringRef.cpp +++ b/API/JSStringRef.cpp @@ -37,7 +37,7 @@ using namespace WTF::Unicode; JSStringRef JSStringCreateWithCharacters(const JSChar* chars, size_t numChars) { initializeThreading(); - return OpaqueJSString::create(chars, numChars).leakRef(); + return &OpaqueJSString::create(chars, numChars).leakRef(); } JSStringRef JSStringCreateWithUTF8CString(const char* string) @@ -51,12 +51,12 @@ JSStringRef JSStringCreateWithUTF8CString(const char* string) const LChar* stringStart = reinterpret_cast<const LChar*>(string); if (conversionOK == convertUTF8ToUTF16(&string, string + length, &p, p + length, &sourceIsAllASCII)) { if (sourceIsAllASCII) - return OpaqueJSString::create(stringStart, length).leakRef(); - return OpaqueJSString::create(buffer.data(), p - buffer.data()).leakRef(); + return &OpaqueJSString::create(stringStart, length).leakRef(); + return &OpaqueJSString::create(buffer.data(), p - buffer.data()).leakRef(); } } - return OpaqueJSString::create().leakRef(); + return &OpaqueJSString::create().leakRef(); } JSStringRef JSStringCreateWithCharactersNoCopy(const JSChar* chars, size_t numChars) @@ -78,11 +78,15 @@ void JSStringRelease(JSStringRef string) size_t JSStringGetLength(JSStringRef string) { + if (!string) + return 0; return string->length(); } const JSChar* JSStringGetCharactersPtr(JSStringRef string) { + if (!string) + return nullptr; return string->characters(); } @@ -94,7 +98,7 @@ size_t JSStringGetMaximumUTF8CStringSize(JSStringRef string) size_t JSStringGetUTF8CString(JSStringRef string, char* buffer, size_t bufferSize) { - if (!bufferSize) + if (!string || !buffer || !bufferSize) return 0; char* destination = buffer; diff --git a/API/JSStringRefCF.cpp b/API/JSStringRefCF.cpp index 1d30608..0587259 100644 --- a/API/JSStringRefCF.cpp +++ b/API/JSStringRefCF.cpp @@ -41,23 +41,23 @@ JSStringRef JSStringCreateWithCFString(CFStringRef string) // it can hold. (<rdar://problem/6806478>) size_t length = CFStringGetLength(string); if (!length) - return OpaqueJSString::create(reinterpret_cast<const LChar*>(""), 0).leakRef(); + return &OpaqueJSString::create(reinterpret_cast<const LChar*>(""), 0).leakRef(); Vector<LChar, 1024> lcharBuffer(length); CFIndex usedBufferLength; CFIndex convertedSize = CFStringGetBytes(string, CFRangeMake(0, length), kCFStringEncodingISOLatin1, 0, false, lcharBuffer.data(), length, &usedBufferLength); if (static_cast<size_t>(convertedSize) == length && static_cast<size_t>(usedBufferLength) == length) - return OpaqueJSString::create(lcharBuffer.data(), length).leakRef(); + return &OpaqueJSString::create(lcharBuffer.data(), length).leakRef(); auto buffer = std::make_unique<UniChar[]>(length); CFStringGetCharacters(string, CFRangeMake(0, length), buffer.get()); static_assert(sizeof(UniChar) == sizeof(UChar), "UniChar and UChar must be same size"); - return OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.get()), length).leakRef(); + return &OpaqueJSString::create(reinterpret_cast<UChar*>(buffer.get()), length).leakRef(); } CFStringRef JSStringCopyCFString(CFAllocatorRef allocator, JSStringRef string) { - if (!string->length()) + if (!string || !string->length()) return CFSTR(""); if (string->is8Bit()) diff --git a/API/JSValue.h b/API/JSValue.h index c5a824d..803d105 100644 --- a/API/JSValue.h +++ b/API/JSValue.h @@ -50,11 +50,7 @@ from a different JSVirtualMachine will result in an Objective-C exception being raised. */ -#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 NS_CLASS_AVAILABLE(10_9, 7_0) -#else -OBJC_VISIBLE -#endif @interface JSValue : NSObject /*! @@ -380,19 +376,19 @@ OBJC_VISIBLE @method @abstract Check if a JSValue corresponds to the JavaScript value <code>undefined</code>. */ -- (BOOL)isUndefined; +@property (readonly) BOOL isUndefined; /*! @method @abstract Check if a JSValue corresponds to the JavaScript value <code>null</code>. */ -- (BOOL)isNull; +@property (readonly) BOOL isNull; /*! @method @abstract Check if a JSValue is a boolean. */ -- (BOOL)isBoolean; +@property (readonly) BOOL isBoolean; /*! @method @@ -401,19 +397,31 @@ OBJC_VISIBLE Semantically all numbers behave like doubles except in special cases like bit operations. */ -- (BOOL)isNumber; +@property (readonly) BOOL isNumber; /*! @method @abstract Check if a JSValue is a string. */ -- (BOOL)isString; +@property (readonly) BOOL isString; /*! @method @abstract Check if a JSValue is an object. */ -- (BOOL)isObject; +@property (readonly) BOOL isObject; + +/*! +@method +@abstract Check if a JSValue is an array. +*/ +@property (readonly) BOOL isArray NS_AVAILABLE(10_11, 9_0); + +/*! +@method +@abstract Check if a JSValue is a date. +*/ +@property (readonly) BOOL isDate NS_AVAILABLE(10_11, 9_0); /*! @method diff --git a/API/JSValue.mm b/API/JSValue.mm index 11019ad..11be6b6 100644 --- a/API/JSValue.mm +++ b/API/JSValue.mm @@ -28,6 +28,7 @@ #import "APICast.h" #import "DateInstance.h" #import "Error.h" +#import "Exception.h" #import "JavaScriptCore.h" #import "JSContextInternal.h" #import "JSVirtualMachineInternal.h" @@ -41,8 +42,8 @@ #import <wtf/HashMap.h> #import <wtf/HashSet.h> #import <wtf/ObjcRuntimeExtras.h> +#import <wtf/SpinLock.h> #import <wtf/Vector.h> -#import <wtf/TCSpinLock.h> #import <wtf/text/WTFString.h> #import <wtf/text/StringHash.h> @@ -356,6 +357,16 @@ NSString * const JSPropertyDescriptorSetKey = @"set"; return JSValueIsObject([_context JSGlobalContextRef], m_value); } +- (BOOL)isArray +{ + return JSValueIsArray([_context JSGlobalContextRef], m_value); +} + +- (BOOL)isDate +{ + return JSValueIsDate([_context JSGlobalContextRef], m_value); +} + - (BOOL)isEqualToObject:(id)value { return JSValueIsStrictEqual([_context JSGlobalContextRef], m_value, objectToValue(_context, value)); @@ -635,9 +646,10 @@ JSContainerConvertor::Task JSContainerConvertor::take() } #if ENABLE(REMOTE_INSPECTOR) -static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exception) +static void reportExceptionToInspector(JSGlobalContextRef context, JSC::JSValue exceptionValue) { JSC::ExecState* exec = toJS(context); + JSC::Exception* exception = JSC::Exception::create(exec->vm(), exceptionValue); exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); } #endif @@ -767,9 +779,9 @@ id valueToString(JSGlobalContextRef context, JSValueRef value, JSValueRef* excep return nil; } - NSString *stringNS = CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, jsstring)); + RetainPtr<CFStringRef> stringCF = adoptCF(JSStringCopyCFString(kCFAllocatorDefault, jsstring)); JSStringRelease(jsstring); - return stringNS; + return (NSString *)stringCF.autorelease(); } id valueToDate(JSGlobalContextRef context, JSValueRef value, JSValueRef* exception) @@ -1102,7 +1114,7 @@ static StructHandlers* createStructHandlerMap() static StructTagHandler* handerForStructTag(const char* encodedType) { - static SpinLock handerForStructTagLock = SPINLOCK_INITIALIZER; + static StaticSpinLock handerForStructTagLock; SpinLockHolder lockHolder(&handerForStructTagLock); static StructHandlers* structHandlers = createStructHandlerMap(); diff --git a/API/JSValueRef.cpp b/API/JSValueRef.cpp index a0be8f0..54405e2 100644 --- a/API/JSValueRef.cpp +++ b/API/JSValueRef.cpp @@ -27,22 +27,22 @@ #include "JSValueRef.h" #include "APICast.h" +#include "DateInstance.h" +#include "Exception.h" #include "JSAPIWrapperObject.h" +#include "JSCInlines.h" #include "JSCJSValue.h" #include "JSCallbackObject.h" #include "JSGlobalObject.h" #include "JSONObject.h" #include "JSString.h" #include "LiteralParser.h" -#include "JSCInlines.h" #include "Protect.h" - +#include <algorithm> #include <wtf/Assertions.h> #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> -#include <algorithm> // for std::min - #if PLATFORM(MAC) #include <mach-o/dyld.h> #endif @@ -53,6 +53,26 @@ using namespace JSC; +enum class ExceptionStatus { + DidThrow, + DidNotThrow +}; + +static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef) +{ + if (exec->hadException()) { + Exception* exception = exec->exception(); + if (returnedExceptionRef) + *returnedExceptionRef = toRef(exec, exception->value()); + exec->clearException(); +#if ENABLE(REMOTE_INSPECTOR) + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); +#endif + return ExceptionStatus::DidThrow; + } + return ExceptionStatus::DidNotThrow; +} + #if PLATFORM(MAC) static bool evernoteHackNeeded() { @@ -98,8 +118,7 @@ bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isUndefined(); + return toJS(exec, value).isUndefined(); } bool JSValueIsNull(JSContextRef ctx, JSValueRef value) @@ -111,8 +130,7 @@ bool JSValueIsNull(JSContextRef ctx, JSValueRef value) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isNull(); + return toJS(exec, value).isNull(); } bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) @@ -124,8 +142,7 @@ bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isBoolean(); + return toJS(exec, value).isBoolean(); } bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) @@ -137,8 +154,7 @@ bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isNumber(); + return toJS(exec, value).isNumber(); } bool JSValueIsString(JSContextRef ctx, JSValueRef value) @@ -150,8 +166,7 @@ bool JSValueIsString(JSContextRef ctx, JSValueRef value) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isString(); + return toJS(exec, value).isString(); } bool JSValueIsObject(JSContextRef ctx, JSValueRef value) @@ -163,8 +178,31 @@ bool JSValueIsObject(JSContextRef ctx, JSValueRef value) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - JSValue jsValue = toJS(exec, value); - return jsValue.isObject(); + return toJS(exec, value).isObject(); +} + +bool JSValueIsArray(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).inherits(JSArray::info()); +} + +bool JSValueIsDate(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).inherits(DateInstance::info()); } bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) @@ -207,15 +245,8 @@ bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* ex JSValue jsB = toJS(exec, b); bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); + return result; } @@ -249,15 +280,7 @@ bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObject if (!jsConstructor->structure()->typeInfo().implementsHasInstance()) return false; bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - } + handleExceptionIfNeeded(exec, exception); return result; } @@ -318,7 +341,7 @@ JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string) ExecState* exec = toJS(ctx); JSLockHolder locker(exec); - return toRef(exec, jsString(exec, string->string())); + return toRef(exec, jsString(exec, string ? string->string() : String())); } JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) @@ -351,16 +374,8 @@ JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsig String result = JSONStringify(exec, value, indent); if (exception) *exception = 0; - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) return 0; - } return OpaqueJSString::create(result).leakRef(); } @@ -389,16 +404,8 @@ double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception JSValue jsValue = toJS(exec, value); double number = jsValue.toNumber(exec); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) number = PNaN; - } return number; } @@ -414,16 +421,8 @@ JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* JSValue jsValue = toJS(exec, value); RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec))); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif - stringRef.clear(); - } + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) + stringRef = nullptr; return stringRef.release().leakRef(); } @@ -439,16 +438,8 @@ JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exce JSValue jsValue = toJS(exec, value); JSObjectRef objectRef = toRef(jsValue.toObject(exec)); - if (exec->hadException()) { - JSValue exceptionValue = exec->exception(); - if (exception) - *exception = toRef(exec, exceptionValue); - exec->clearException(); -#if ENABLE(REMOTE_INSPECTOR) - exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue); -#endif + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) objectRef = 0; - } return objectRef; } diff --git a/API/JSValueRef.h b/API/JSValueRef.h index 538e6e0..9c4fa58 100644 --- a/API/JSValueRef.h +++ b/API/JSValueRef.h @@ -129,6 +129,24 @@ JS_EXPORT bool JSValueIsObject(JSContextRef ctx, JSValueRef value); */ JS_EXPORT bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass); +/*! +@function +@abstract Tests whether a JavaScript value is an array. +@param ctx The execution context to use. +@param value The JSValue to test. +@result true if value is an array, otherwise false. +*/ +JS_EXPORT bool JSValueIsArray(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0); + +/*! +@function +@abstract Tests whether a JavaScript value is a date. +@param ctx The execution context to use. +@param value The JSValue to test. +@result true if value is a date, otherwise false. +*/ +JS_EXPORT bool JSValueIsDate(JSContextRef ctx, JSValueRef value) CF_AVAILABLE(10_11, 9_0); + /* Comparing values */ /*! diff --git a/API/JSVirtualMachine.h b/API/JSVirtualMachine.h index dc9becb..ccf9264 100644 --- a/API/JSVirtualMachine.h +++ b/API/JSVirtualMachine.h @@ -34,11 +34,7 @@ virtual machine, with concurrent JavaScript execution supported by allocating separate instances of JSVirtualMachine. */ -#ifndef JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 NS_CLASS_AVAILABLE(10_9, 7_0) -#else -OBJC_VISIBLE -#endif @interface JSVirtualMachine : NSObject /*! diff --git a/API/JSVirtualMachine.mm b/API/JSVirtualMachine.mm index 26e709a..d4995ad 100644 --- a/API/JSVirtualMachine.mm +++ b/API/JSVirtualMachine.mm @@ -37,6 +37,7 @@ #import "SlotVisitorInlines.h" #import <mutex> #import <wtf/NeverDestroyed.h> +#import <wtf/spi/cocoa/NSMapTableSPI.h> static NSMapTable *globalWrapperCache = 0; diff --git a/API/JSVirtualMachineInternal.h b/API/JSVirtualMachineInternal.h index 009d8e4..5a4fbef 100644 --- a/API/JSVirtualMachineInternal.h +++ b/API/JSVirtualMachineInternal.h @@ -36,6 +36,8 @@ class SlotVisitor; } #if defined(__OBJC__) +@class NSMapTable; + @interface JSVirtualMachine(Internal) JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *); diff --git a/API/JSWeakObjectMapRefInternal.h b/API/JSWeakObjectMapRefInternal.h index f7b91da..9037947 100644 --- a/API/JSWeakObjectMapRefInternal.h +++ b/API/JSWeakObjectMapRefInternal.h @@ -41,9 +41,9 @@ typedef JSC::WeakGCMap<void*, JSC::JSObject> WeakMapType; struct OpaqueJSWeakObjectMap : public RefCounted<OpaqueJSWeakObjectMap> { public: - static PassRefPtr<OpaqueJSWeakObjectMap> create(void* data, JSWeakMapDestroyedCallback callback) + static Ref<OpaqueJSWeakObjectMap> create(JSC::VM& vm, void* data, JSWeakMapDestroyedCallback callback) { - return adoptRef(new OpaqueJSWeakObjectMap(data, callback)); + return adoptRef(*new OpaqueJSWeakObjectMap(vm, data, callback)); } WeakMapType& map() { return m_map; } @@ -54,8 +54,9 @@ public: } private: - OpaqueJSWeakObjectMap(void* data, JSWeakMapDestroyedCallback callback) - : m_data(data) + OpaqueJSWeakObjectMap(JSC::VM& vm, void* data, JSWeakMapDestroyedCallback callback) + : m_map(vm) + , m_data(data) , m_callback(callback) { } diff --git a/API/JSWeakObjectMapRefPrivate.cpp b/API/JSWeakObjectMapRefPrivate.cpp index 446cf90..925c00f 100644 --- a/API/JSWeakObjectMapRefPrivate.cpp +++ b/API/JSWeakObjectMapRefPrivate.cpp @@ -32,6 +32,7 @@ #include "JSWeakObjectMapRefInternal.h" #include "JSCInlines.h" #include "Weak.h" +#include "WeakGCMapInlines.h" #include <wtf/HashMap.h> #include <wtf/text/StringHash.h> @@ -46,7 +47,7 @@ JSWeakObjectMapRef JSWeakObjectMapCreate(JSContextRef context, void* privateData { ExecState* exec = toJS(context); JSLockHolder locker(exec); - RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(privateData, callback); + RefPtr<OpaqueJSWeakObjectMap> map = OpaqueJSWeakObjectMap::create(exec->vm(), privateData, callback); exec->lexicalGlobalObject()->registerWeakMap(map.get()); return map.get(); } diff --git a/API/JSWrapperMap.mm b/API/JSWrapperMap.mm index 069de82..2cb0ec1 100644 --- a/API/JSWrapperMap.mm +++ b/API/JSWrapperMap.mm @@ -30,16 +30,17 @@ #import "APICast.h" #import "JSAPIWrapperObject.h" +#import "JSCInlines.h" #import "JSCallbackObject.h" #import "JSContextInternal.h" #import "JSWrapperMap.h" #import "ObjCCallbackFunction.h" #import "ObjcRuntimeExtras.h" -#import "JSCInlines.h" #import "WeakGCMap.h" -#import <wtf/TCSpinLock.h> -#import <wtf/Vector.h> +#import "WeakGCMapInlines.h" #import <wtf/HashSet.h> +#import <wtf/Vector.h> +#import <wtf/spi/cocoa/NSMapTableSPI.h> #include <mach-o/dyld.h> @@ -107,7 +108,7 @@ static bool constructorHasInstance(JSContextRef ctx, JSObjectRef constructorRef, return JSC::JSObject::defaultHasInstance(exec, instance, constructor->get(exec, exec->propertyNames().prototype)); } -static JSObjectRef makeWrapper(JSContextRef ctx, JSClassRef jsClass, id wrappedObject) +static JSC::JSObject* makeWrapper(JSContextRef ctx, JSClassRef jsClass, id wrappedObject) { JSC::ExecState* exec = toJS(ctx); JSC::JSLockHolder locker(exec); @@ -118,33 +119,33 @@ static JSObjectRef makeWrapper(JSContextRef ctx, JSClassRef jsClass, id wrappedO if (JSC::JSObject* prototype = jsClass->prototype(exec)) object->setPrototype(exec->vm(), prototype); - return toRef(object); + return object; } // Make an object that is in all ways a completely vanilla JavaScript object, // other than that it has a native brand set that will be displayed by the default // Object.prototype.toString conversion. -static JSValue *objectWithCustomBrand(JSContext *context, NSString *brand, Class cls = 0) +static JSC::JSObject *objectWithCustomBrand(JSContext *context, NSString *brand, Class cls = 0) { JSClassDefinition definition; definition = kJSClassDefinitionEmpty; definition.className = [brand UTF8String]; JSClassRef classRef = JSClassCreate(&definition); - JSObjectRef result = makeWrapper([context JSGlobalContextRef], classRef, cls); + JSC::JSObject* result = makeWrapper([context JSGlobalContextRef], classRef, cls); JSClassRelease(classRef); - return [JSValue valueWithJSValueRef:result inContext:context]; + return result; } -static JSValue *constructorWithCustomBrand(JSContext *context, NSString *brand, Class cls) +static JSC::JSObject *constructorWithCustomBrand(JSContext *context, NSString *brand, Class cls) { JSClassDefinition definition; definition = kJSClassDefinitionEmpty; definition.className = [brand UTF8String]; definition.hasInstance = constructorHasInstance; JSClassRef classRef = JSClassCreate(&definition); - JSObjectRef result = makeWrapper([context JSGlobalContextRef], classRef, cls); + JSC::JSObject* result = makeWrapper([context JSGlobalContextRef], classRef, cls); JSClassRelease(classRef); - return [JSValue valueWithJSValueRef:result inContext:context]; + return result; } // Look for @optional properties in the prototype containing a selector to property @@ -364,8 +365,8 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco } - (id)initWithContext:(JSContext *)context forClass:(Class)cls; -- (JSValue *)wrapperForObject:(id)object; -- (JSValue *)constructor; +- (JSC::JSObject *)wrapperForObject:(id)object; +- (JSC::JSObject *)constructor; - (JSC::JSObject *)prototype; @end @@ -396,7 +397,7 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco [super dealloc]; } -static JSValue *allocateConstructorForCustomClass(JSContext *context, const char* className, Class cls) +static JSC::JSObject* allocateConstructorForCustomClass(JSContext *context, const char* className, Class cls) { if (!supportsInitMethodConstructors()) return constructorWithCustomBrand(context, [NSString stringWithFormat:@"%sConstructor", className], cls); @@ -443,7 +444,7 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char } JSObjectRef method = objCCallbackFunctionForInit(context, cls, initProtocol, initMethod, types); - return [JSValue valueWithJSValueRef:method inContext:context]; + return toJS(method); } return constructorWithCustomBrand(context, [NSString stringWithFormat:@"%sConstructor", className], cls); } @@ -456,36 +457,32 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; ASSERT(!m_constructor || !m_prototype); ASSERT((m_class == [NSObject class]) == !superClassInfo); + + JSC::JSObject* jsPrototype = m_prototype.get(); + JSC::JSObject* jsConstructor = m_constructor.get(); + if (!superClassInfo) { JSContextRef cContext = [m_context JSGlobalContextRef]; JSValue *constructor = m_context[@"Object"]; - if (!m_constructor) - m_constructor = toJS(JSValueToObject(cContext, valueInternalValue(constructor), 0)); + if (!jsConstructor) + jsConstructor = toJS(JSValueToObject(cContext, valueInternalValue(constructor), 0)); - if (!m_prototype) { + if (!jsPrototype) { JSValue *prototype = constructor[@"prototype"]; - m_prototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0)); + jsPrototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0)); } } else { const char* className = class_getName(m_class); // Create or grab the prototype/constructor pair. - JSValue *prototype; - JSValue *constructor; - if (m_prototype) - prototype = [JSValue valueWithJSValueRef:toRef(m_prototype.get()) inContext:m_context]; - else - prototype = objectWithCustomBrand(m_context, [NSString stringWithFormat:@"%sPrototype", className]); - - if (m_constructor) - constructor = [JSValue valueWithJSValueRef:toRef(m_constructor.get()) inContext:m_context]; - else - constructor = allocateConstructorForCustomClass(m_context, className, m_class); + if (!jsPrototype) + jsPrototype = objectWithCustomBrand(m_context, [NSString stringWithFormat:@"%sPrototype", className]); - JSContextRef cContext = [m_context JSGlobalContextRef]; - m_prototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0)); - m_constructor = toJS(JSValueToObject(cContext, valueInternalValue(constructor), 0)); + if (!jsConstructor) + jsConstructor = allocateConstructorForCustomClass(m_context, className, m_class); + JSValue* prototype = [JSValue valueWithJSValueRef:toRef(jsPrototype) inContext:m_context]; + JSValue* constructor = [JSValue valueWithJSValueRef:toRef(jsConstructor) inContext:m_context]; putNonEnumerable(prototype, @"constructor", constructor); putNonEnumerable(constructor, @"prototype", prototype); @@ -497,12 +494,15 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; // Set [Prototype]. JSC::JSObject* superClassPrototype = [superClassInfo prototype]; - JSObjectSetPrototype([m_context JSGlobalContextRef], toRef(m_prototype.get()), toRef(superClassPrototype)); + JSObjectSetPrototype([m_context JSGlobalContextRef], toRef(jsPrototype), toRef(superClassPrototype)); } - return ConstructorPrototypePair(m_constructor.get(), m_prototype.get()); + + m_prototype = jsPrototype; + m_constructor = jsConstructor; + return ConstructorPrototypePair(jsConstructor, jsPrototype); } -- (JSValue *)wrapperForObject:(id)object +- (JSC::JSObject*)wrapperForObject:(id)object { ASSERT([object isKindOfClass:m_class]); ASSERT(m_block == [object isKindOfClass:getNSBlockClass()]); @@ -512,24 +512,24 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; JSValue *prototype = [JSValue valueWithNewObjectInContext:m_context]; putNonEnumerable(constructor, @"prototype", prototype); putNonEnumerable(prototype, @"constructor", constructor); - return constructor; + return toJS(method); } } JSC::JSObject* prototype = [self prototype]; - JSObjectRef wrapper = makeWrapper([m_context JSGlobalContextRef], m_classRef, object); - JSObjectSetPrototype([m_context JSGlobalContextRef], wrapper, toRef(prototype)); - return [JSValue valueWithJSValueRef:wrapper inContext:m_context]; + JSC::JSObject* wrapper = makeWrapper([m_context JSGlobalContextRef], m_classRef, object); + JSObjectSetPrototype([m_context JSGlobalContextRef], toRef(wrapper), toRef(prototype)); + return wrapper; } -- (JSValue *)constructor +- (JSC::JSObject*)constructor { JSC::JSObject* constructor = m_constructor.get(); if (!constructor) constructor = [self allocateConstructorAndPrototype].first; ASSERT(!!constructor); - return [JSValue valueWithJSValueRef:toRef(constructor) inContext:m_context]; + return constructor; } - (JSC::JSObject*)prototype @@ -546,7 +546,7 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; @implementation JSWrapperMap { JSContext *m_context; NSMutableDictionary *m_classMap; - JSC::WeakGCMap<id, JSC::JSObject> m_cachedJSWrappers; + std::unique_ptr<JSC::WeakGCMap<id, JSC::JSObject>> m_cachedJSWrappers; NSMapTable *m_cachedObjCWrappers; } @@ -559,7 +559,9 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality; NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality; m_cachedObjCWrappers = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; - + + m_cachedJSWrappers = std::make_unique<JSC::WeakGCMap<id, JSC::JSObject>>(toJS([context JSGlobalContextRef])->vm()); + m_context = context; m_classMap = [[NSMutableDictionary alloc] init]; return self; @@ -590,16 +592,15 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; - (JSValue *)jsWrapperForObject:(id)object { - JSC::JSObject* jsWrapper = m_cachedJSWrappers.get(object); + JSC::JSObject* jsWrapper = m_cachedJSWrappers->get(object); if (jsWrapper) return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:m_context]; - JSValue *wrapper; if (class_isMetaClass(object_getClass(object))) - wrapper = [[self classInfoForClass:(Class)object] constructor]; + jsWrapper = [[self classInfoForClass:(Class)object] constructor]; else { JSObjCClassInfo* classInfo = [self classInfoForClass:[object class]]; - wrapper = [classInfo wrapperForObject:object]; + jsWrapper = [classInfo wrapperForObject:object]; } // FIXME: https://bugs.webkit.org/show_bug.cgi?id=105891 @@ -607,10 +608,8 @@ typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; // (1) For immortal objects JSValues will effectively leak and this results in error output being logged - we should avoid adding associated objects to immortal objects. // (2) A long lived object may rack up many JSValues. When the contexts are released these will unprotect the associated JavaScript objects, // but still, would probably nicer if we made it so that only one associated object was required, broadcasting object dealloc. - JSC::ExecState* exec = toJS([m_context JSGlobalContextRef]); - jsWrapper = toJS(exec, valueInternalValue(wrapper)).toObject(exec); - m_cachedJSWrappers.set(object, jsWrapper); - return wrapper; + m_cachedJSWrappers->set(object, jsWrapper); + return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:m_context]; } - (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value @@ -648,6 +647,11 @@ NS_ROOT_CLASS @interface JSExport <JSExport> bool supportsInitMethodConstructors() { +#if PLATFORM(APPLETV) + // There are no old clients on Apple TV, so there's no need for backwards compatibility. + return true; +#endif + static int32_t versionOfLinkTimeLibrary = 0; if (!versionOfLinkTimeLibrary) versionOfLinkTimeLibrary = NSVersionOfLinkTimeLibrary("JavaScriptCore"); diff --git a/API/ObjCCallbackFunction.h b/API/ObjCCallbackFunction.h index 046bf65..adb167c 100644 --- a/API/ObjCCallbackFunction.h +++ b/API/ObjCCallbackFunction.h @@ -48,7 +48,7 @@ class ObjCCallbackFunction : public InternalFunction { public: typedef InternalFunction Base; - static ObjCCallbackFunction* create(VM&, JSGlobalObject*, const String& name, PassOwnPtr<ObjCCallbackFunctionImpl>); + static ObjCCallbackFunction* create(VM&, JSGlobalObject*, const String& name, std::unique_ptr<ObjCCallbackFunctionImpl>); static void destroy(JSCell*); static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) @@ -62,7 +62,7 @@ public: ObjCCallbackFunctionImpl* impl() const { return m_impl.get(); } protected: - ObjCCallbackFunction(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, PassOwnPtr<ObjCCallbackFunctionImpl>); + ObjCCallbackFunction(VM&, JSGlobalObject*, JSObjectCallAsFunctionCallback, JSObjectCallAsConstructorCallback, std::unique_ptr<ObjCCallbackFunctionImpl>); private: static CallType getCallData(JSCell*, CallData&); @@ -73,7 +73,7 @@ private: JSObjectCallAsFunctionCallback m_functionCallback; JSObjectCallAsConstructorCallback m_constructCallback; - OwnPtr<ObjCCallbackFunctionImpl> m_impl; + std::unique_ptr<ObjCCallbackFunctionImpl> m_impl; }; } // namespace JSC diff --git a/API/ObjCCallbackFunction.mm b/API/ObjCCallbackFunction.mm index c62b731..bba9294 100644 --- a/API/ObjCCallbackFunction.mm +++ b/API/ObjCCallbackFunction.mm @@ -30,7 +30,6 @@ #import "APICallbackFunction.h" #import "APICast.h" -#import "DelayedReleaseScope.h" #import "Error.h" #import "JSCJSValueInlines.h" #import "JSCell.h" @@ -48,7 +47,7 @@ public: virtual ~CallbackArgument(); virtual void set(NSInvocation *, NSInteger, JSContext *, JSValueRef, JSValueRef*) = 0; - OwnPtr<CallbackArgument> m_next; + std::unique_ptr<CallbackArgument> m_next; }; CallbackArgument::~CallbackArgument() @@ -100,24 +99,17 @@ class CallbackArgumentId : public CallbackArgument { class CallbackArgumentOfClass : public CallbackArgument { public: CallbackArgumentOfClass(Class cls) - : CallbackArgument() - , m_class(cls) + : m_class(cls) { - [m_class retain]; } private: - virtual ~CallbackArgumentOfClass() - { - [m_class release]; - } - virtual void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override { JSGlobalContextRef contextRef = [context JSGlobalContextRef]; id object = tryUnwrapObjcObject(contextRef, argument); - if (object && [object isKindOfClass:m_class]) { + if (object && [object isKindOfClass:m_class.get()]) { [invocation setArgument:&object atIndex:argumentNumber]; return; } @@ -131,7 +123,7 @@ private: *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Argument does not match Objective-C Class"))); } - Class m_class; + RetainPtr<Class> m_class; }; class CallbackArgumentNSNumber : public CallbackArgument { @@ -197,34 +189,34 @@ private: class ArgumentTypeDelegate { public: - typedef CallbackArgument* ResultType; + typedef std::unique_ptr<CallbackArgument> ResultType; template<typename T> static ResultType typeInteger() { - return new CallbackArgumentInteger<T>; + return std::make_unique<CallbackArgumentInteger<T>>(); } template<typename T> static ResultType typeDouble() { - return new CallbackArgumentDouble<T>; + return std::make_unique<CallbackArgumentDouble<T>>(); } static ResultType typeBool() { - return new CallbackArgumentBoolean; + return std::make_unique<CallbackArgumentBoolean>(); } static ResultType typeVoid() { RELEASE_ASSERT_NOT_REACHED(); - return 0; + return nullptr; } static ResultType typeId() { - return new CallbackArgumentId; + return std::make_unique<CallbackArgumentId>(); } static ResultType typeOfClass(const char* begin, const char* end) @@ -232,35 +224,35 @@ public: StringRange copy(begin, end); Class cls = objc_getClass(copy); if (!cls) - return 0; + return nullptr; if (cls == [JSValue class]) - return new CallbackArgumentJSValue; + return std::make_unique<CallbackArgumentJSValue>(); if (cls == [NSString class]) - return new CallbackArgumentNSString; + return std::make_unique<CallbackArgumentNSString>(); if (cls == [NSNumber class]) - return new CallbackArgumentNSNumber; + return std::make_unique<CallbackArgumentNSNumber>(); if (cls == [NSDate class]) - return new CallbackArgumentNSDate; + return std::make_unique<CallbackArgumentNSDate>(); if (cls == [NSArray class]) - return new CallbackArgumentNSArray; + return std::make_unique<CallbackArgumentNSArray>(); if (cls == [NSDictionary class]) - return new CallbackArgumentNSDictionary; + return std::make_unique<CallbackArgumentNSDictionary>(); - return new CallbackArgumentOfClass(cls); + return std::make_unique<CallbackArgumentOfClass>(cls); } static ResultType typeBlock(const char*, const char*) { - return nil; + return nullptr; } static ResultType typeStruct(const char* begin, const char* end) { StringRange copy(begin, end); if (NSInvocation *invocation = valueToTypeInvocationFor(copy)) - return new CallbackArgumentStruct(invocation, copy); - return 0; + return std::make_unique<CallbackArgumentStruct>(invocation, copy); + return nullptr; } }; @@ -336,51 +328,51 @@ private: class ResultTypeDelegate { public: - typedef CallbackResult* ResultType; + typedef std::unique_ptr<CallbackResult> ResultType; template<typename T> static ResultType typeInteger() { - return new CallbackResultNumeric<T>; + return std::make_unique<CallbackResultNumeric<T>>(); } template<typename T> static ResultType typeDouble() { - return new CallbackResultNumeric<T>; + return std::make_unique<CallbackResultNumeric<T>>(); } static ResultType typeBool() { - return new CallbackResultBoolean; + return std::make_unique<CallbackResultBoolean>(); } static ResultType typeVoid() { - return new CallbackResultVoid; + return std::make_unique<CallbackResultVoid>(); } static ResultType typeId() { - return new CallbackResultId(); + return std::make_unique<CallbackResultId>(); } static ResultType typeOfClass(const char*, const char*) { - return new CallbackResultId(); + return std::make_unique<CallbackResultId>(); } static ResultType typeBlock(const char*, const char*) { - return new CallbackResultId(); + return std::make_unique<CallbackResultId>(); } static ResultType typeStruct(const char* begin, const char* end) { StringRange copy(begin, end); if (NSInvocation *invocation = typeToValueInvocationFor(copy)) - return new CallbackResultStruct(invocation, copy); - return 0; + return std::make_unique<CallbackResultStruct>(invocation, copy); + return nullptr; } }; @@ -395,12 +387,12 @@ namespace JSC { class ObjCCallbackFunctionImpl { public: - ObjCCallbackFunctionImpl(NSInvocation *invocation, CallbackType type, Class instanceClass, PassOwnPtr<CallbackArgument> arguments, PassOwnPtr<CallbackResult> result) + ObjCCallbackFunctionImpl(NSInvocation *invocation, CallbackType type, Class instanceClass, std::unique_ptr<CallbackArgument> arguments, std::unique_ptr<CallbackResult> result) : m_type(type) - , m_instanceClass([instanceClass retain]) + , m_instanceClass(instanceClass) , m_invocation(invocation) - , m_arguments(arguments) - , m_result(result) + , m_arguments(WTF::move(arguments)) + , m_result(WTF::move(result)) { ASSERT((type != CallbackInstanceMethod && type != CallbackInitMethod) || instanceClass); } @@ -411,7 +403,7 @@ public: // -retainArguments on m_invocation (and we don't want to do so). if (m_type == CallbackBlock || m_type == CallbackClassMethod) heap.releaseSoon(adoptNS([m_invocation.get() target])); - [m_instanceClass release]; + m_instanceClass = nil; } JSValueRef call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); @@ -427,7 +419,7 @@ public: case CallbackBlock: return [m_invocation target]; case CallbackInitMethod: - return m_instanceClass; + return m_instanceClass.get(); default: return nil; } @@ -442,10 +434,10 @@ public: private: CallbackType m_type; - Class m_instanceClass; + RetainPtr<Class> m_instanceClass; RetainPtr<NSInvocation> m_invocation; - OwnPtr<CallbackArgument> m_arguments; - OwnPtr<CallbackResult> m_result; + std::unique_ptr<CallbackArgument> m_arguments; + std::unique_ptr<CallbackResult> m_result; }; static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -483,8 +475,8 @@ static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerCont CallbackData callbackData; JSValueRef result; @autoreleasepool { - [context beginCallbackWithData:&callbackData calleeValue:constructor thisValue:nil argumentCount:argumentCount arguments:arguments]; - result = impl->call(context, NULL, argumentCount, arguments, exception); + [context beginCallbackWithData:&callbackData calleeValue:constructor thisValue:nullptr argumentCount:argumentCount arguments:arguments]; + result = impl->call(context, nullptr, argumentCount, arguments, exception); if (context.exception) *exception = valueInternalValue(context.exception); [context endCallbackWithData:&callbackData]; @@ -492,28 +484,28 @@ static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerCont JSGlobalContextRef contextRef = [context JSGlobalContextRef]; if (*exception) - return 0; + return nullptr; if (!JSValueIsObject(contextRef, result)) { *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Objective-C blocks called as constructors must return an object."))); - return 0; + return nullptr; } return (JSObjectRef)result; } -const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ObjCCallbackFunction) }; +const JSC::ClassInfo ObjCCallbackFunction::s_info = { "CallbackFunction", &Base::s_info, 0, CREATE_METHOD_TABLE(ObjCCallbackFunction) }; -ObjCCallbackFunction::ObjCCallbackFunction(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback functionCallback, JSObjectCallAsConstructorCallback constructCallback, PassOwnPtr<ObjCCallbackFunctionImpl> impl) +ObjCCallbackFunction::ObjCCallbackFunction(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSObjectCallAsFunctionCallback functionCallback, JSObjectCallAsConstructorCallback constructCallback, std::unique_ptr<ObjCCallbackFunctionImpl> impl) : Base(vm, globalObject->objcCallbackFunctionStructure()) , m_functionCallback(functionCallback) , m_constructCallback(constructCallback) - , m_impl(impl) + , m_impl(WTF::move(impl)) { } -ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const String& name, PassOwnPtr<ObjCCallbackFunctionImpl> impl) +ObjCCallbackFunction* ObjCCallbackFunction::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, const String& name, std::unique_ptr<ObjCCallbackFunctionImpl> impl) { - ObjCCallbackFunction* function = new (NotNull, allocateCell<ObjCCallbackFunction>(vm.heap)) ObjCCallbackFunction(vm, globalObject, objCCallbackFunctionCallAsFunction, objCCallbackFunctionCallAsConstructor, impl); + ObjCCallbackFunction* function = new (NotNull, allocateCell<ObjCCallbackFunction>(vm.heap)) ObjCCallbackFunction(vm, globalObject, objCCallbackFunctionCallAsFunction, objCCallbackFunctionCallAsConstructor, WTF::move(impl)); function->finishCreation(vm, name); return function; } @@ -544,7 +536,7 @@ ConstructType ObjCCallbackFunction::getConstructData(JSCell* cell, ConstructData String ObjCCallbackFunctionImpl::name() { if (m_type == CallbackInitMethod) - return class_getName(m_instanceClass); + return class_getName(m_instanceClass.get()); // FIXME: Maybe we could support having the selector as the name of the non-init // functions to make it a bit more user-friendly from the JS side? return ""; @@ -560,7 +552,7 @@ JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisOb case CallbackInitMethod: { RELEASE_ASSERT(!thisObject); target = [m_instanceClass alloc]; - if (!target || ![target isKindOfClass:m_instanceClass]) { + if (!target || ![target isKindOfClass:m_instanceClass.get()]) { *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method"))); return JSValueMakeUndefined(contextRef); } @@ -570,7 +562,7 @@ JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisOb } case CallbackInstanceMethod: { target = tryUnwrapObjcObject(contextRef, thisObject); - if (!target || ![target isKindOfClass:m_instanceClass]) { + if (!target || ![target isKindOfClass:m_instanceClass.get()]) { *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("self type check failed for Objective-C instance method"))); return JSValueMakeUndefined(contextRef); } @@ -621,7 +613,7 @@ static bool blockSignatureContainsClass() return containsClass; } -inline bool skipNumber(const char*& position) +static inline bool skipNumber(const char*& position) { if (!isASCIIDigit(*position)) return false; @@ -632,13 +624,13 @@ inline bool skipNumber(const char*& position) static JSObjectRef objCCallbackFunctionForInvocation(JSContext *context, NSInvocation *invocation, CallbackType type, Class instanceClass, const char* signatureWithObjcClasses) { if (!signatureWithObjcClasses) - return nil; + return nullptr; const char* position = signatureWithObjcClasses; - OwnPtr<CallbackResult> result = adoptPtr(parseObjCType<ResultTypeDelegate>(position)); + auto result = parseObjCType<ResultTypeDelegate>(position); if (!result || !skipNumber(position)) - return nil; + return nullptr; switch (type) { case CallbackInitMethod: @@ -646,35 +638,36 @@ static JSObjectRef objCCallbackFunctionForInvocation(JSContext *context, NSInvoc case CallbackClassMethod: // Methods are passed two implicit arguments - (id)self, and the selector. if ('@' != *position++ || !skipNumber(position) || ':' != *position++ || !skipNumber(position)) - return nil; + return nullptr; break; case CallbackBlock: // Blocks are passed one implicit argument - the block, of type "@?". if (('@' != *position++) || ('?' != *position++) || !skipNumber(position)) - return nil; + return nullptr; // Only allow arguments of type 'id' if the block signature contains the NS type information. if ((!blockSignatureContainsClass() && strchr(position, '@'))) - return nil; + return nullptr; break; } - OwnPtr<CallbackArgument> arguments = 0; - OwnPtr<CallbackArgument>* nextArgument = &arguments; + std::unique_ptr<CallbackArgument> arguments; + auto* nextArgument = &arguments; unsigned argumentCount = 0; while (*position) { - OwnPtr<CallbackArgument> argument = adoptPtr(parseObjCType<ArgumentTypeDelegate>(position)); + auto argument = parseObjCType<ArgumentTypeDelegate>(position); if (!argument || !skipNumber(position)) - return nil; + return nullptr; - *nextArgument = argument.release(); + *nextArgument = WTF::move(argument); nextArgument = &(*nextArgument)->m_next; ++argumentCount; } JSC::ExecState* exec = toJS([context JSGlobalContextRef]); JSC::JSLockHolder locker(exec); - OwnPtr<JSC::ObjCCallbackFunctionImpl> impl = adoptPtr(new JSC::ObjCCallbackFunctionImpl(invocation, type, instanceClass, arguments.release(), result.release())); - return toRef(JSC::ObjCCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), impl->name(), impl.release())); + auto impl = std::make_unique<JSC::ObjCCallbackFunctionImpl>(invocation, type, instanceClass, WTF::move(arguments), WTF::move(result)); + const String& name = impl->name(); + return toRef(JSC::ObjCCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), name, WTF::move(impl))); } JSObjectRef objCCallbackFunctionForInit(JSContext *context, Class cls, Protocol *protocol, SEL sel, const char* types) @@ -688,8 +681,8 @@ JSObjectRef objCCallbackFunctionForMethod(JSContext *context, Class cls, Protoco { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:types]]; [invocation setSelector:sel]; - // We need to retain the target Class because m_invocation doesn't retain it - // by default (and we don't want it to). + // We need to retain the target Class because m_invocation doesn't retain it by default (and we don't want it to). + // FIXME: What releases it? if (!isInstanceMethod) [invocation setTarget:[cls retain]]; return objCCallbackFunctionForInvocation(context, invocation, isInstanceMethod ? CallbackInstanceMethod : CallbackClassMethod, isInstanceMethod ? cls : nil, _protocol_getMethodTypeEncoding(protocol, sel, YES, isInstanceMethod)); @@ -698,7 +691,7 @@ JSObjectRef objCCallbackFunctionForMethod(JSContext *context, Class cls, Protoco JSObjectRef objCCallbackFunctionForBlock(JSContext *context, id target) { if (!_Block_has_signature(target)) - return 0; + return nullptr; const char* signature = _Block_signature(target); NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:signature]]; diff --git a/API/ObjcRuntimeExtras.h b/API/ObjcRuntimeExtras.h index c85bc92..128df5c 100644 --- a/API/ObjcRuntimeExtras.h +++ b/API/ObjcRuntimeExtras.h @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#import <objc/Protocol.h> #import <objc/runtime.h> #import <wtf/HashSet.h> #import <wtf/Vector.h> @@ -163,7 +164,7 @@ typename DelegateType::ResultType parseObjCType(const char*& position) case 'l': return DelegateType::template typeInteger<long>(); case 'q': - return DelegateType::template typeDouble<unsigned long long>(); + return DelegateType::template typeDouble<long long>(); case 'C': return DelegateType::template typeInteger<unsigned char>(); case 'I': diff --git a/API/OpaqueJSString.cpp b/API/OpaqueJSString.cpp index bf48d69..07a79ad 100644 --- a/API/OpaqueJSString.cpp +++ b/API/OpaqueJSString.cpp @@ -28,12 +28,13 @@ #include "CallFrame.h" #include "Identifier.h" +#include "IdentifierInlines.h" #include "JSGlobalObject.h" #include <wtf/text/StringView.h> using namespace JSC; -PassRefPtr<OpaqueJSString> OpaqueJSString::create(const String& string) +RefPtr<OpaqueJSString> OpaqueJSString::create(const String& string) { if (string.isNull()) return nullptr; @@ -56,32 +57,26 @@ OpaqueJSString::~OpaqueJSString() String OpaqueJSString::string() const { - if (!this) - return String(); - // Return a copy of the wrapped string, because the caller may make it an Identifier. return m_string.isolatedCopy(); } Identifier OpaqueJSString::identifier(VM* vm) const { - if (!this || m_string.isNull()) + if (m_string.isNull()) return Identifier(); if (m_string.isEmpty()) return Identifier(Identifier::EmptyIdentifier); if (m_string.is8Bit()) - return Identifier(vm, m_string.characters8(), m_string.length()); + return Identifier::fromString(vm, m_string.characters8(), m_string.length()); - return Identifier(vm, m_string.characters16(), m_string.length()); + return Identifier::fromString(vm, m_string.characters16(), m_string.length()); } const UChar* OpaqueJSString::characters() { - if (!this) - return nullptr; - // m_characters is put in a local here to avoid an extra atomic load. UChar* characters = m_characters; if (characters) diff --git a/API/OpaqueJSString.h b/API/OpaqueJSString.h index 8fd90ae..208131b 100644 --- a/API/OpaqueJSString.h +++ b/API/OpaqueJSString.h @@ -36,29 +36,29 @@ namespace JSC { } struct OpaqueJSString : public ThreadSafeRefCounted<OpaqueJSString> { - static PassRefPtr<OpaqueJSString> create() + static Ref<OpaqueJSString> create() { - return adoptRef(new OpaqueJSString); + return adoptRef(*new OpaqueJSString); } - static PassRefPtr<OpaqueJSString> create(const LChar* characters, unsigned length) + static Ref<OpaqueJSString> create(const LChar* characters, unsigned length) { - return adoptRef(new OpaqueJSString(characters, length)); + return adoptRef(*new OpaqueJSString(characters, length)); } - static PassRefPtr<OpaqueJSString> create(const UChar* characters, unsigned length) + static Ref<OpaqueJSString> create(const UChar* characters, unsigned length) { - return adoptRef(new OpaqueJSString(characters, length)); + return adoptRef(*new OpaqueJSString(characters, length)); } - JS_EXPORT_PRIVATE static PassRefPtr<OpaqueJSString> create(const String&); + JS_EXPORT_PRIVATE static RefPtr<OpaqueJSString> create(const String&); JS_EXPORT_PRIVATE ~OpaqueJSString(); - bool is8Bit() { return this ? m_string.is8Bit() : false; } - const LChar* characters8() { return this ? m_string.characters8() : nullptr; } - const UChar* characters16() { return this ? m_string.characters16() : nullptr; } - unsigned length() { return this ? m_string.length() : 0; } + bool is8Bit() { return m_string.is8Bit(); } + const LChar* characters8() { return m_string.characters8(); } + const UChar* characters16() { return m_string.characters16(); } + unsigned length() { return m_string.length(); } const UChar* characters(); diff --git a/API/WebKitAvailability.h b/API/WebKitAvailability.h index 24695ed..250d410 100644 --- a/API/WebKitAvailability.h +++ b/API/WebKitAvailability.h @@ -31,15 +31,19 @@ #include <AvailabilityMacros.h> #include <CoreFoundation/CoreFoundation.h> -#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 +#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100 /* To support availability macros that mention newer OS X versions when building on older OS X versions, we provide our own definitions of the underlying macros that the availability macros expand to. We're free to expand the macros as no-ops since frameworks built on older OS X versions only ship bundled with an application rather than as part of the system. */ -#ifndef __NSi_10_10 -#define __NSi_10_10 introduced=10.0 +#ifndef __NSi_10_10 // Building from trunk rather than SDK. +#define __NSi_10_10 introduced=10.0 // Use 10.0 to indicate that everything is available. +#endif + +#ifndef __NSi_10_11 // Building from trunk rather than SDK. +#define __NSi_10_11 introduced=10.0 // Use 10.0 to indicate that everything is available. #endif #ifndef __AVAILABILITY_INTERNAL__MAC_10_9 @@ -58,7 +62,7 @@ #define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER #endif -#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 */ +#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED <= 101100 */ #else #define CF_AVAILABLE(_mac, _ios) diff --git a/API/tests/CompareAndSwapTest.cpp b/API/tests/CompareAndSwapTest.cpp new file mode 100644 index 0000000..c78d47d --- /dev/null +++ b/API/tests/CompareAndSwapTest.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CompareAndSwapTest.h" + +#include <stdio.h> +#include <wtf/Atomics.h> +#include <wtf/Threading.h> + +class Bitmap { +public: + Bitmap() { clearAll(); } + + inline void clearAll(); + inline bool concurrentTestAndSet(size_t n); + inline size_t numBits() const { return words * wordSize; } + +private: + static const size_t Size = 4096*10; + + static const unsigned wordSize = sizeof(uint8_t) * 8; + static const unsigned words = (Size + wordSize - 1) / wordSize; + static const uint8_t one = 1; + + uint8_t bits[words]; +}; + +inline void Bitmap::clearAll() +{ + memset(&bits, 0, sizeof(bits)); +} + +inline bool Bitmap::concurrentTestAndSet(size_t n) +{ + uint8_t mask = one << (n % wordSize); + size_t index = n / wordSize; + uint8_t* wordPtr = &bits[index]; + uint8_t oldValue; + do { + oldValue = *wordPtr; + if (oldValue & mask) + return true; + } while (!WTF::weakCompareAndSwap(wordPtr, oldValue, oldValue | mask)); + return false; +} + +struct Data { + Bitmap* bitmap; + int id; + int numThreads; +}; + +static void setBitThreadFunc(void* p) +{ + Data* data = reinterpret_cast<Data*>(p); + Bitmap* bitmap = data->bitmap; + size_t numBits = bitmap->numBits(); + + // The computed start index here is heuristic that seems to maximize (anecdotally) + // the chance for the CAS issue to manifest. + size_t start = (numBits * (data->numThreads - data->id)) / data->numThreads; + + printf(" started Thread %d\n", data->id); + for (size_t i = start; i < numBits; i++) + while (!bitmap->concurrentTestAndSet(i)) { } + for (size_t i = 0; i < start; i++) + while (!bitmap->concurrentTestAndSet(i)) { } + + printf(" finished Thread %d\n", data->id); +} + +void testCompareAndSwap() +{ + Bitmap bitmap; + const int numThreads = 5; + ThreadIdentifier threadIDs[numThreads]; + Data data[numThreads]; + + WTF::initializeThreading(); + + printf("Starting %d threads for CompareAndSwap test. Test should complete without hanging.\n", numThreads); + for (int i = 0; i < numThreads; i++) { + data[i].bitmap = &bitmap; + data[i].id = i; + data[i].numThreads = numThreads; + std::function<void()> threadFunc = std::bind(setBitThreadFunc, &data[i]); + threadIDs[i] = createThread("setBitThreadFunc", threadFunc); + } + + printf("Waiting for %d threads to join\n", numThreads); + for (int i = 0; i < numThreads; i++) + waitForThreadCompletion(threadIDs[i]); + + printf("PASS: CompareAndSwap test completed without a hang\n"); +} diff --git a/runtime/JSPromiseFunctions.h b/API/tests/CompareAndSwapTest.h similarity index 64% rename from runtime/JSPromiseFunctions.h rename to API/tests/CompareAndSwapTest.h index 8021219..73fa0de 100644 --- a/runtime/JSPromiseFunctions.h +++ b/API/tests/CompareAndSwapTest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,25 +23,18 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSPromiseFunctions_h -#define JSPromiseFunctions_h +#ifndef CompareAndSwapTest_h +#define CompareAndSwapTest_h -#if ENABLE(PROMISES) +#ifdef __cplusplus +extern "C" { +#endif -#include "JSFunction.h" +/* Regression test for webkit.org/b/142513 */ +void testCompareAndSwap(); -namespace JSC { +#ifdef __cplusplus +} /* extern "C" */ +#endif -JSFunction* createDeferredConstructionFunction(VM&, JSGlobalObject*); -JSFunction* createIdentifyFunction(VM&, JSGlobalObject*); -JSFunction* createPromiseAllCountdownFunction(VM&, JSGlobalObject*); -JSFunction* createPromiseResolutionHandlerFunction(VM&, JSGlobalObject*); -JSFunction* createRejectPromiseFunction(VM&, JSGlobalObject*); -JSFunction* createResolvePromiseFunction(VM&, JSGlobalObject*); -JSFunction* createThrowerFunction(VM&, JSGlobalObject*); - -} // namespace JSC - -#endif // ENABLE(PROMISES) - -#endif // JSPromiseFunctions_h +#endif /* CompareAndSwapTest_h */ diff --git a/API/tests/DateTests.mm b/API/tests/DateTests.mm index b4bc9ec..e2837a6 100644 --- a/API/tests/DateTests.mm +++ b/API/tests/DateTests.mm @@ -37,11 +37,7 @@ extern "C" void checkResult(NSString *description, bool passed); + (void) roundTripThroughObjCDateTest; @end -#if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000) || (TARGET_OS_MAC && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) static unsigned unitFlags = NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear; -#else -static unsigned unitFlags = NSSecondCalendarUnit | NSMinuteCalendarUnit | NSHourCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit; -#endif @implementation DateTests + (void) NSDateToJSDateTest diff --git a/API/tests/ExecutionTimeLimitTest.cpp b/API/tests/ExecutionTimeLimitTest.cpp new file mode 100644 index 0000000..6ff98d4 --- /dev/null +++ b/API/tests/ExecutionTimeLimitTest.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ExecutionTimeLimitTest.h" + +#if OS(DARWIN) + +#include "JSContextRefPrivate.h" +#include "JavaScriptCore.h" + +#include <mach/mach.h> +#include <mach/mach_time.h> +#include <stdio.h> +#include <sys/time.h> + +static JSGlobalContextRef context = nullptr; + +static double currentCPUTime() +{ + mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + + /* Get thread information */ + mach_port_t threadPort = mach_thread_self(); + thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount); + mach_port_deallocate(mach_task_self(), threadPort); + + double time = info.user_time.seconds + info.user_time.microseconds / 1000000.; + time += info.system_time.seconds + info.system_time.microseconds / 1000000.; + + return time; +} + +static JSValueRef currentCPUTimeAsJSFunctionCallback(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + UNUSED_PARAM(functionObject); + UNUSED_PARAM(thisObject); + UNUSED_PARAM(argumentCount); + UNUSED_PARAM(arguments); + UNUSED_PARAM(exception); + + ASSERT(JSContextGetGlobalContext(ctx) == context); + return JSValueMakeNumber(ctx, currentCPUTime()); +} + +bool shouldTerminateCallbackWasCalled = false; +static bool shouldTerminateCallback(JSContextRef ctx, void* context) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(context); + shouldTerminateCallbackWasCalled = true; + return true; +} + +bool cancelTerminateCallbackWasCalled = false; +static bool cancelTerminateCallback(JSContextRef ctx, void* context) +{ + UNUSED_PARAM(ctx); + UNUSED_PARAM(context); + cancelTerminateCallbackWasCalled = true; + return false; +} + +int extendTerminateCallbackCalled = 0; +static bool extendTerminateCallback(JSContextRef ctx, void* context) +{ + UNUSED_PARAM(context); + extendTerminateCallbackCalled++; + if (extendTerminateCallbackCalled == 1) { + JSContextGroupRef contextGroup = JSContextGetGroup(ctx); + JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); + return false; + } + return true; +} + + +int testExecutionTimeLimit() +{ + context = JSGlobalContextCreateInGroup(nullptr, nullptr); + + JSContextGroupRef contextGroup = JSContextGetGroup(context); + JSObjectRef globalObject = JSContextGetGlobalObject(context); + ASSERT(JSValueIsObject(context, globalObject)); + + JSValueRef v = nullptr; + JSValueRef exception = nullptr; + bool failed = false; + + JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); + JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTimeAsJSFunctionCallback); + JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, nullptr); + JSStringRelease(currentCPUTimeStr); + + /* Test script timeout: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) + printf("PASS: script timed out as expected.\n"); + else { + if (!((endTime - startTime) < .150f)) + printf("FAIL: script did not time out as expected.\n"); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: script timeout callback was not called.\n"); + failed = true; + } + + if (!exception) { + printf("FAIL: TerminatedExecutionException was not thrown.\n"); + failed = true; + } + } + + /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }"; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = nullptr; + shouldTerminateCallbackWasCalled = false; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) { + if (!((endTime - startTime) < .150f)) + printf("FAIL: script did not time out as expected.\n"); + if (!shouldTerminateCallbackWasCalled) + printf("FAIL: script timeout callback was not called.\n"); + failed = true; + } + + if (exception) + printf("PASS: TerminatedExecutionException was not catchable as expected.\n"); + else { + printf("FAIL: TerminatedExecutionException was caught.\n"); + failed = true; + } + } + + /* Test script timeout with no callback: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = nullptr; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) + printf("PASS: script timed out as expected when no callback is specified.\n"); + else { + if (!((endTime - startTime) < .150f)) + printf("FAIL: script did not time out as expected when no callback is specified.\n"); + failed = true; + } + + if (!exception) { + printf("FAIL: TerminatedExecutionException was not thrown.\n"); + failed = true; + } + } + + /* Test script timeout cancellation: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + exception = nullptr; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + endTime = currentCPUTime(); + + if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception) + printf("PASS: script timeout was cancelled as expected.\n"); + else { + if (((endTime - startTime) < .150) || exception) + printf("FAIL: script timeout was not cancelled.\n"); + if (!cancelTerminateCallbackWasCalled) + printf("FAIL: script timeout callback was not called.\n"); + failed = true; + } + + if (exception) { + printf("FAIL: Unexpected TerminatedExecutionException thrown.\n"); + failed = true; + } + } + + /* Test script timeout extension: */ + JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0); + { + const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } "; + JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); + double startTime; + double endTime; + double deltaTime; + exception = nullptr; + startTime = currentCPUTime(); + v = JSEvaluateScript(context, script, nullptr, nullptr, 1, &exception); + endTime = currentCPUTime(); + deltaTime = endTime - startTime; + + if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception) + printf("PASS: script timeout was extended as expected.\n"); + else { + if (deltaTime < .200f) + printf("FAIL: script timeout was not extended as expected.\n"); + else if (deltaTime >= .500f) + printf("FAIL: script did not timeout.\n"); + + if (extendTerminateCallbackCalled < 1) + printf("FAIL: script timeout callback was not called.\n"); + if (extendTerminateCallbackCalled < 2) + printf("FAIL: script timeout callback was not called after timeout extension.\n"); + + if (!exception) + printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n"); + + failed = true; + } + } + + JSGlobalContextRelease(context); + return failed; +} + +#endif // OS(DARWIN) diff --git a/API/tests/ExecutionTimeLimitTest.h b/API/tests/ExecutionTimeLimitTest.h new file mode 100644 index 0000000..8294a86 --- /dev/null +++ b/API/tests/ExecutionTimeLimitTest.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ExecutionTimeLimitTest_h +#define ExecutionTimeLimitTest_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns 1 if failures were encountered. Else, returns 0. */ +int testExecutionTimeLimit(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ExecutionTimeLimitTest_h */ diff --git a/API/tests/GlobalContextWithFinalizerTest.cpp b/API/tests/GlobalContextWithFinalizerTest.cpp new file mode 100644 index 0000000..7023bc3 --- /dev/null +++ b/API/tests/GlobalContextWithFinalizerTest.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlobalContextWithFinalizerTest.h" + +#include "JavaScriptCore.h" +#include <wtf/DataLog.h> + +static bool failed = true; + +static void finalize(JSObjectRef) +{ + failed = false; +} + +int testGlobalContextWithFinalizer() +{ + JSClassDefinition def = kJSClassDefinitionEmpty; + def.className = "testClass"; + def.finalize = finalize; + JSClassRef classRef = JSClassCreate(&def); + + JSGlobalContextRef ref = JSGlobalContextCreateInGroup(nullptr, classRef); + JSGlobalContextRelease(ref); + JSClassRelease(classRef); + + if (failed) + printf("FAIL: JSGlobalContextRef did not call its JSClassRef finalizer.\n"); + else + printf("PASS: JSGlobalContextRef called its JSClassRef finalizer as expected.\n"); + + return failed; +} diff --git a/API/tests/GlobalContextWithFinalizerTest.h b/API/tests/GlobalContextWithFinalizerTest.h new file mode 100644 index 0000000..55b439f --- /dev/null +++ b/API/tests/GlobalContextWithFinalizerTest.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GlobalContextWithFinalizerTest_h +#define GlobalContextWithFinalizerTest_h + +#include "JSContextRefPrivate.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns 1 if failures were encountered. Else, returns 0. */ +int testGlobalContextWithFinalizer(); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GlobalContextWithFinalizerTest_h */ diff --git a/assembler/ARMv7Assembler.cpp b/API/tests/Regress141275.h similarity index 86% rename from assembler/ARMv7Assembler.cpp rename to API/tests/Regress141275.h index faca664..bf3492a 100644 --- a/assembler/ARMv7Assembler.cpp +++ b/API/tests/Regress141275.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,14 +23,12 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JavaScriptCore.h> -#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) +#if JSC_OBJC_API_ENABLED -#include "ARMv7Assembler.h" +void runRegress141275(); -namespace JSC { +#endif // JSC_OBJC_API_ENABLED -} - -#endif diff --git a/API/tests/Regress141275.mm b/API/tests/Regress141275.mm new file mode 100644 index 0000000..18e186a --- /dev/null +++ b/API/tests/Regress141275.mm @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "Regress141275.h" + +#import <Foundation/Foundation.h> +#import <objc/objc.h> +#import <objc/runtime.h> + +#if JSC_OBJC_API_ENABLED + +extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef); + +extern int failed; + +static const NSUInteger scriptToEvaluate = 50; + +@interface JSTEvaluator : NSObject +- (instancetype)initWithScript:(NSString*)script; + +- (void)insertSignPostWithCompletion:(void(^)(NSError* error))completionHandler; + +- (void)evaluateScript:(NSString*)script completion:(void(^)(NSError* error))completionHandler; +- (void)evaluateBlock:(void(^)(JSContext* context))evaluationBlock completion:(void(^)(NSError* error))completionHandler; + +- (void)waitForTasksDoneAndReportResults; +@end + + +static const NSString* JSTEvaluatorThreadContextKey = @"JSTEvaluatorThreadContextKey"; + +/* + * A JSTEvaluatorThreadContext is kept in the thread dictionary of threads used by JSEvaluator. + * + * This includes the run loop thread, and any threads used by _jsSourcePerformQueue to execute a task. + */ +@interface JSTEvaluatorThreadContext : NSObject +@property (weak) JSTEvaluator* evaluator; +@property (strong) JSContext* jsContext; +@end + +@implementation JSTEvaluatorThreadContext +@end + + +/*! + * A JSTEvaluatorTask is a single task to be executed. + * + * JSTEvaluator keeps a list of pending tasks. The run loop thread is repsonsible for feeding pending tasks to the _jsSourcePerformQueue, while respecting sign posts. + */ +@interface JSTEvaluatorTask : NSObject + +@property (nonatomic, copy) void (^evaluateBlock)(JSContext* jsContext); +@property (nonatomic, copy) void (^completionHandler)(NSError* error); +@property (nonatomic, copy) NSError* error; + ++ (instancetype)evaluatorTaskWithEvaluateBlock:(void (^)(JSContext*))block completionHandler:(void (^)(NSError* error))completionBlock; + +@end + +@implementation JSTEvaluatorTask + ++ (instancetype)evaluatorTaskWithEvaluateBlock:(void (^)(JSContext*))evaluationBlock completionHandler:(void (^)(NSError* error))completionHandler +{ + JSTEvaluatorTask* task = [self new]; + task.evaluateBlock = evaluationBlock; + task.completionHandler = completionHandler; + return task; +} + +@end + +@implementation JSTEvaluator { + dispatch_queue_t _jsSourcePerformQueue; + dispatch_semaphore_t _allScriptsDone; + CFRunLoopRef _jsThreadRunLoop; + CFRunLoopSourceRef _jsThreadRunLoopSource; + JSContext* _jsContext; + NSMutableArray* __pendingTasks; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _jsSourcePerformQueue = dispatch_queue_create("JSTEval", DISPATCH_QUEUE_CONCURRENT); + + _allScriptsDone = dispatch_semaphore_create(0); + + _jsContext = [JSContext new]; + _jsContext.name = @"JSTEval"; + __pendingTasks = [NSMutableArray new]; + + NSThread* jsThread = [[NSThread alloc] initWithTarget:self selector:@selector(_jsThreadMain) object:nil]; + [jsThread setName:@"JSTEval"]; + [jsThread start]; + + } + return self; +} + +- (instancetype)initWithScript:(NSString*)script +{ + self = [self init]; + if (self) { + __block NSError* scriptError = nil; + dispatch_semaphore_t dsema = dispatch_semaphore_create(0); + [self evaluateScript:script + completion:^(NSError* error) { + scriptError = error; + dispatch_semaphore_signal(dsema); + }]; + dispatch_semaphore_wait(dsema, DISPATCH_TIME_FOREVER); + } + return self; +} + +- (void)_accessPendingTasksWithBlock:(void(^)(NSMutableArray* pendingTasks))block +{ + @synchronized(self) { + block(__pendingTasks); + if (__pendingTasks.count > 0) { + if (_jsThreadRunLoop && _jsThreadRunLoopSource) { + CFRunLoopSourceSignal(_jsThreadRunLoopSource); + CFRunLoopWakeUp(_jsThreadRunLoop); + } + } + } +} + +- (void)insertSignPostWithCompletion:(void(^)(NSError* error))completionHandler +{ + [self _accessPendingTasksWithBlock:^(NSMutableArray* pendingTasks) { + JSTEvaluatorTask* task = [JSTEvaluatorTask evaluatorTaskWithEvaluateBlock:nil + completionHandler:completionHandler]; + + [pendingTasks addObject:task]; + }]; +} + +- (void)evaluateScript:(NSString*)script completion:(void(^)(NSError* error))completionHandler +{ + [self evaluateBlock:^(JSContext* context) { + [context evaluateScript:script]; + } completion:completionHandler]; +} + +- (void)evaluateBlock:(void(^)(JSContext* context))evaluationBlock completion:(void(^)(NSError* error))completionHandler +{ + NSParameterAssert(evaluationBlock != nil); + [self _accessPendingTasksWithBlock:^(NSMutableArray* pendingTasks) { + JSTEvaluatorTask* task = [JSTEvaluatorTask evaluatorTaskWithEvaluateBlock:evaluationBlock + completionHandler:completionHandler]; + + [pendingTasks addObject:task]; + }]; +} + +- (void)waitForTasksDoneAndReportResults +{ + NSString* passFailString = @"PASSED"; + + if (!dispatch_semaphore_wait(_allScriptsDone, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC))) { + int totalScriptsRun = [_jsContext[@"counter"] toInt32]; + + if (totalScriptsRun != scriptToEvaluate) { + passFailString = @"FAILED"; + failed = 1; + } + + NSLog(@" Ran a total of %d scripts: %@", totalScriptsRun, passFailString); + } else { + passFailString = @"FAILED"; + failed = 1; + NSLog(@" Error, timeout waiting for all tasks to complete: %@", passFailString); + } +} + +static void __JSTRunLoopSourceScheduleCallBack(void* info, CFRunLoopRef rl, CFStringRef) +{ + @autoreleasepool { + [(__bridge JSTEvaluator*)info _sourceScheduledOnRunLoop:rl]; + } +} + +static void __JSTRunLoopSourcePerformCallBack(void* info ) +{ + @autoreleasepool { + [(__bridge JSTEvaluator*)info _sourcePerform]; + } +} + +static void __JSTRunLoopSourceCancelCallBack(void* info, CFRunLoopRef rl, CFStringRef) +{ + @autoreleasepool { + [(__bridge JSTEvaluator*)info _sourceCanceledOnRunLoop:rl]; + } +} + +- (void)_jsThreadMain +{ + @autoreleasepool { + const CFIndex kRunLoopSourceContextVersion = 0; + CFRunLoopSourceContext sourceContext = { + kRunLoopSourceContextVersion, (__bridge void*)(self), + NULL, NULL, NULL, NULL, NULL, + __JSTRunLoopSourceScheduleCallBack, + __JSTRunLoopSourceCancelCallBack, + __JSTRunLoopSourcePerformCallBack + }; + + @synchronized(self) { + _jsThreadRunLoop = CFRunLoopGetCurrent(); + CFRetain(_jsThreadRunLoop); + + _jsThreadRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sourceContext); + CFRunLoopAddSource(_jsThreadRunLoop, _jsThreadRunLoopSource, kCFRunLoopDefaultMode); + } + + CFRunLoopRun(); + + @synchronized(self) { + NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; + [threadDict removeObjectForKey:threadDict[JSTEvaluatorThreadContextKey]]; + + CFRelease(_jsThreadRunLoopSource); + _jsThreadRunLoopSource = NULL; + + CFRelease(_jsThreadRunLoop); + _jsThreadRunLoop = NULL; + + __pendingTasks = nil; + } + } +} + +- (void)_sourceScheduledOnRunLoop:(CFRunLoopRef)runLoop +{ + UNUSED_PARAM(runLoop); + assert([[[NSThread currentThread] name] isEqualToString:@"JSTEval"]); + + // Wake up the run loop in case requests were submitted prior to the + // run loop & run loop source getting created. + CFRunLoopSourceSignal(_jsThreadRunLoopSource); + CFRunLoopWakeUp(_jsThreadRunLoop); +} + +- (void)_setupEvaluatorThreadContextIfNeeded +{ + NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; + JSTEvaluatorThreadContext* context = threadDict[JSTEvaluatorThreadContextKey]; + // The evaluator may be other evualuator, or nil if this thread has not been used before. Eaither way take ownership. + if (context.evaluator != self) { + context = [JSTEvaluatorThreadContext new]; + context.evaluator = self; + threadDict[JSTEvaluatorThreadContextKey] = context; + } +} + +- (void)_callCompletionHandler:(void(^)(NSError* error))completionHandler ifNeededWithError:(NSError*)error +{ + if (completionHandler) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + completionHandler(error); + }); + } +} + +- (void)_sourcePerform +{ + assert([[[NSThread currentThread] name] isEqualToString:@"JSTEval"]); + + __block NSArray* tasks = nil; + [self _accessPendingTasksWithBlock:^(NSMutableArray* pendingTasks) { + // No signpost, take all tasks. + tasks = [pendingTasks copy]; + [pendingTasks removeAllObjects]; + }]; + + if (tasks.count > 0) { + for (JSTEvaluatorTask* task in tasks) { + dispatch_block_t block = ^{ + NSError* error = nil; + if (task.evaluateBlock) { + [self _setupEvaluatorThreadContextIfNeeded]; + task.evaluateBlock(_jsContext); + if (_jsContext.exception) { + NSLog(@"Did fail on JSContext: %@", _jsContext.name); + NSDictionary* userInfo = @{ NSLocalizedDescriptionKey : [_jsContext.exception[@"message"] toString] }; + error = [NSError errorWithDomain:@"JSTEvaluator" code:1 userInfo:userInfo]; + _jsContext.exception = nil; + } + } + [self _callCompletionHandler:task.completionHandler ifNeededWithError:error]; + }; + + if (task.evaluateBlock) + dispatch_async(_jsSourcePerformQueue, block); + else + dispatch_barrier_async(_jsSourcePerformQueue, block); + } + + dispatch_barrier_sync(_jsSourcePerformQueue, ^{ + if ([_jsContext[@"counter"] toInt32] == scriptToEvaluate) + dispatch_semaphore_signal(_allScriptsDone); + }); + } +} + +- (void)_sourceCanceledOnRunLoop:(CFRunLoopRef)runLoop +{ + UNUSED_PARAM(runLoop); + assert([[[NSThread currentThread] name] isEqualToString:@"JSTEval"]); + + @synchronized(self) { + assert(_jsThreadRunLoop); + assert(_jsThreadRunLoopSource); + + CFRunLoopRemoveSource(_jsThreadRunLoop, _jsThreadRunLoopSource, kCFRunLoopDefaultMode); + CFRunLoopStop(_jsThreadRunLoop); + } +} + +@end + +void runRegress141275() +{ + // Test that we can execute the same script from multiple threads with a shared context. + // See <https://webkit.org/b/141275> + NSLog(@"TEST: Testing multiple threads executing the same script with a shared context"); + + @autoreleasepool { + JSTEvaluator* evaluator = [[JSTEvaluator alloc] initWithScript:@"this['counter'] = 0;"]; + + void (^showErrorIfNeeded)(NSError* error) = ^(NSError* error) { + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSLog(@"Error: %@", error); + }); + } + }; + + [evaluator evaluateBlock:^(JSContext* context) { + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + } completion:showErrorIfNeeded]; + + [evaluator evaluateBlock:^(JSContext* context) { + context[@"wait"] = ^{ + [NSThread sleepForTimeInterval:0.01]; + }; + } completion:^(NSError* error) { + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSLog(@"Error: %@", error); + }); + } + for (unsigned i = 0; i < scriptToEvaluate; i++) + [evaluator evaluateScript:@"this['counter']++; this['wait']();" completion:showErrorIfNeeded]; + }]; + + [evaluator waitForTasksDoneAndReportResults]; + } +} + +#endif // JSC_OBJC_API_ENABLED diff --git a/API/tests/testapi.c b/API/tests/testapi.c index 60d7dc0..fc4914b 100644 --- a/API/tests/testapi.c +++ b/API/tests/testapi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,17 +35,17 @@ #define ASSERT_DISABLED 0 #include <wtf/Assertions.h> -#if OS(DARWIN) -#include <mach/mach.h> -#include <mach/mach_time.h> -#include <sys/time.h> -#endif - #if OS(WINDOWS) #include <windows.h> #endif +#include "CompareAndSwapTest.h" #include "CustomGlobalObjectClassTest.h" +#include "GlobalContextWithFinalizerTest.h" + +#if OS(DARWIN) +#include "ExecutionTimeLimitTest.h" +#endif #if JSC_OBJC_API_ENABLED void testObjectiveCAPI(void); @@ -84,11 +84,13 @@ static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString); char* jsBuffer = (char*)malloc(jsSize); JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize); - + unsigned i; for (i = 0; jsBuffer[i]; i++) { if (jsBuffer[i] != expectedValue[i]) { fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]); + fprintf(stderr, "value: %s\n", jsBuffer); + fprintf(stderr, "expectedValue: %s\n", expectedValue); failed = 1; } } @@ -123,7 +125,11 @@ static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedVa } if (jsLength != (size_t)cfLength) { - fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength); +#if OS(WINDOWS) + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%Iu) != cfLength(%Iu)\n", jsLength, (size_t)cfLength); +#else + fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%zu) != cfLength(%zu)\n", jsLength, (size_t)cfLength); +#endif failed = 1; } @@ -954,6 +960,7 @@ static JSStaticValue globalObject_staticValues[] = { static JSStaticFunction globalObject_staticFunctions[] = { { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, + { "globalStaticFunction2", globalObject_call, kJSPropertyAttributeNone }, { "gc", functionGC, kJSPropertyAttributeNone }, { 0, 0, 0 } }; @@ -1108,77 +1115,27 @@ static void checkConstnessInJSObjectNames() val.name = "something"; } -#if OS(DARWIN) -static double currentCPUTime() -{ - mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; - thread_basic_info_data_t info; - - /* Get thread information */ - mach_port_t threadPort = mach_thread_self(); - thread_info(threadPort, THREAD_BASIC_INFO, (thread_info_t)(&info), &infoCount); - mach_port_deallocate(mach_task_self(), threadPort); - - double time = info.user_time.seconds + info.user_time.microseconds / 1000000.; - time += info.system_time.seconds + info.system_time.microseconds / 1000000.; - - return time; -} - -static JSValueRef currentCPUTime_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - UNUSED_PARAM(functionObject); - UNUSED_PARAM(thisObject); - UNUSED_PARAM(argumentCount); - UNUSED_PARAM(arguments); - UNUSED_PARAM(exception); - - ASSERT(JSContextGetGlobalContext(ctx) == context); - return JSValueMakeNumber(ctx, currentCPUTime()); -} - -bool shouldTerminateCallbackWasCalled = false; -static bool shouldTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(ctx); - UNUSED_PARAM(context); - shouldTerminateCallbackWasCalled = true; - return true; -} - -bool cancelTerminateCallbackWasCalled = false; -static bool cancelTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(ctx); - UNUSED_PARAM(context); - cancelTerminateCallbackWasCalled = true; - return false; -} - -int extendTerminateCallbackCalled = 0; -static bool extendTerminateCallback(JSContextRef ctx, void* context) -{ - UNUSED_PARAM(context); - extendTerminateCallbackCalled++; - if (extendTerminateCallbackCalled == 1) { - JSContextGroupRef contextGroup = JSContextGetGroup(ctx); - JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0); - return false; - } - return true; -} -#endif /* OS(DARWIN) */ - int main(int argc, char* argv[]) { #if OS(WINDOWS) +#if defined(_M_X64) || defined(__x86_64__) + // The VS2013 runtime has a bug where it mis-detects AVX-capable processors + // if the feature has been disabled in firmware. This causes us to crash + // in some of the math functions. For now, we disable those optimizations + // because Microsoft is not going to fix the problem in VS2013. + // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+. + _set_FMA3_enable(0); +#endif + // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. ::SetErrorMode(0); #endif + testCompareAndSwap(); + #if JSC_OBJC_API_ENABLED testObjectiveCAPI(); #endif @@ -1292,6 +1249,8 @@ int main(int argc, char* argv[]) ASSERT(!JSValueIsBoolean(context, NULL)); ASSERT(!JSValueIsObject(context, NULL)); + ASSERT(!JSValueIsArray(context, NULL)); + ASSERT(!JSValueIsDate(context, NULL)); ASSERT(!JSValueIsString(context, NULL)); ASSERT(!JSValueIsNumber(context, NULL)); ASSERT(!JSValueIsUndefined(context, NULL)); @@ -1452,8 +1411,10 @@ int main(int argc, char* argv[]) } else printf("PASS: Correctly serialised with indent of 4.\n"); JSStringRelease(str); - JSStringRef src = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); - JSValueRef unstringifiableObj = JSEvaluateScript(context, src, NULL, NULL, 1, NULL); + + str = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); + JSValueRef unstringifiableObj = JSEvaluateScript(context, str, NULL, NULL, 1, NULL); + JSStringRelease(str); str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0); if (str) { @@ -1636,7 +1597,7 @@ int main(int argc, char* argv[]) ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); ASSERT(JSValueIsObject(context, exception)); v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); - assertEqualsAsNumber(v, 1); + assertEqualsAsNumber(v, 2); JSStringRelease(functionBody); JSStringRelease(line); @@ -1646,7 +1607,7 @@ int main(int argc, char* argv[]) ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception)); ASSERT(JSValueIsObject(context, exception)); v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); - assertEqualsAsNumber(v, 1); + assertEqualsAsNumber(v, 2); JSStringRelease(functionBody); JSStringRelease(line); @@ -1656,7 +1617,7 @@ int main(int argc, char* argv[]) ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); ASSERT(JSValueIsObject(context, exception)); v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); - assertEqualsAsNumber(v, 2); + assertEqualsAsNumber(v, 3); JSStringRelease(functionBody); JSStringRelease(line); @@ -1690,7 +1651,7 @@ int main(int argc, char* argv[]) JSStringRelease(functionBody); string = JSValueToStringCopy(context, function, NULL); - assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) { return foo;\n}"); + assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {\nreturn foo;\n}"); JSStringRelease(string); JSStringRef print = JSStringCreateWithUTF8CString("print"); @@ -1821,6 +1782,16 @@ int main(int argc, char* argv[]) ASSERT(JSValueIsEqual(context, v, o, NULL)); JSStringRelease(script); + script = JSStringCreateWithUTF8CString("[ ]"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsArray(context, v)); + JSStringRelease(script); + + script = JSStringCreateWithUTF8CString("new Date"); + v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsDate(context, v)); + JSStringRelease(script); + exception = NULL; script = JSStringCreateWithUTF8CString("rreturn Array;"); JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js"); @@ -1878,158 +1849,32 @@ int main(int argc, char* argv[]) free(scriptUTF8); } -#if OS(DARWIN) - JSStringRef currentCPUTimeStr = JSStringCreateWithUTF8CString("currentCPUTime"); - JSObjectRef currentCPUTimeFunction = JSObjectMakeFunctionWithCallback(context, currentCPUTimeStr, currentCPUTime_callAsFunction); - JSObjectSetProperty(context, globalObject, currentCPUTimeStr, currentCPUTimeFunction, kJSPropertyAttributeNone, NULL); - JSStringRelease(currentCPUTimeStr); - - /* Test script timeout: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, shouldTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - shouldTerminateCallbackWasCalled = false; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) - printf("PASS: script timed out as expected.\n"); - else { - if (!((endTime - startTime) < .150f)) - printf("FAIL: script did not timed out as expected.\n"); - if (!shouldTerminateCallbackWasCalled) - printf("FAIL: script timeout callback was not called.\n"); - failed = true; - } - - if (!exception) { - printf("FAIL: TerminatedExecutionException was not thrown.\n"); - failed = true; - } - } - - /* Test the script timeout's TerminatedExecutionException should NOT be catchable: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, shouldTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); try { while (true) { if (currentCPUTime() - startTime > .150) break; } } catch(e) { }"; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - shouldTerminateCallbackWasCalled = false; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) >= .150f) || !shouldTerminateCallbackWasCalled) { - if (!((endTime - startTime) < .150f)) - printf("FAIL: script did not timed out as expected.\n"); - if (!shouldTerminateCallbackWasCalled) - printf("FAIL: script timeout callback was not called.\n"); - failed = true; - } - - if (exception) - printf("PASS: TerminatedExecutionException was not catchable as expected.\n"); - else { - printf("FAIL: TerminatedExecutionException was caught.\n"); - failed = true; - } - } - - /* Test script timeout with no callback: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, .10f, 0, 0); + // Check Promise is not exposed. { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) < .150f) && shouldTerminateCallbackWasCalled) - printf("PASS: script timed out as expected when no callback is specified.\n"); - else { - if (!((endTime - startTime) < .150f)) - printf("FAIL: script did not timed out as expected when no callback is specified.\n"); - failed = true; - } - - if (!exception) { - printf("FAIL: TerminatedExecutionException was not thrown.\n"); - failed = true; - } - } - - /* Test script timeout cancellation: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.10f, cancelTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .150) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - exception = NULL; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - - if (((endTime - startTime) >= .150f) && cancelTerminateCallbackWasCalled && !exception) - printf("PASS: script timeout was cancelled as expected.\n"); - else { - if (((endTime - startTime) < .150) || exception) - printf("FAIL: script timeout was not cancelled.\n"); - if (!cancelTerminateCallbackWasCalled) - printf("FAIL: script timeout callback was not called.\n"); - failed = true; + JSObjectRef globalObject = JSContextGetGlobalObject(context); + { + JSStringRef promiseProperty = JSStringCreateWithUTF8CString("Promise"); + ASSERT(!JSObjectHasProperty(context, globalObject, promiseProperty)); + JSStringRelease(promiseProperty); } - - if (exception) { - printf("FAIL: Unexpected TerminatedExecutionException thrown.\n"); - failed = true; + { + JSStringRef script = JSStringCreateWithUTF8CString("typeof Promise"); + JSStringRef undefined = JSStringCreateWithUTF8CString("undefined"); + JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); + ASSERT(JSValueIsString(context, value)); + JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); + ASSERT(JSStringIsEqual(valueAsString, undefined)); + JSStringRelease(valueAsString); + JSStringRelease(undefined); + JSStringRelease(script); } + printf("PASS: Promise is not exposed under JSContext API.\n"); } - /* Test script timeout extension: */ - JSContextGroupSetExecutionTimeLimit(contextGroup, 0.100f, extendTerminateCallback, 0); - { - const char* loopForeverScript = "var startTime = currentCPUTime(); while (true) { if (currentCPUTime() - startTime > .500) break; } "; - JSStringRef script = JSStringCreateWithUTF8CString(loopForeverScript); - double startTime; - double endTime; - double deltaTime; - exception = NULL; - startTime = currentCPUTime(); - v = JSEvaluateScript(context, script, NULL, NULL, 1, &exception); - endTime = currentCPUTime(); - deltaTime = endTime - startTime; - - if ((deltaTime >= .300f) && (deltaTime < .500f) && (extendTerminateCallbackCalled == 2) && exception) - printf("PASS: script timeout was extended as expected.\n"); - else { - if (deltaTime < .200f) - printf("FAIL: script timeout was not extended as expected.\n"); - else if (deltaTime >= .500f) - printf("FAIL: script did not timeout.\n"); - - if (extendTerminateCallbackCalled < 1) - printf("FAIL: script timeout callback was not called.\n"); - if (extendTerminateCallbackCalled < 2) - printf("FAIL: script timeout callback was not called after timeout extension.\n"); - - if (!exception) - printf("FAIL: TerminatedExecutionException was not thrown during timeout extension test.\n"); - - failed = true; - } - } +#if OS(DARWIN) + failed = testExecutionTimeLimit() || failed; #endif /* OS(DARWIN) */ + failed = testGlobalContextWithFinalizer() || failed; // Clear out local variables pointing at JSObjectRefs to allow their values to be collected function = NULL; @@ -2121,3 +1966,10 @@ static char* createStringWithContentsOfFile(const char* fileName) return buffer; } + +#if OS(WINDOWS) +extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]) +{ + return main(argc, const_cast<char**>(argv)); +} +#endif diff --git a/API/tests/testapi.js b/API/tests/testapi.js index f9cc7b4..88d3701 100644 --- a/API/tests/testapi.js +++ b/API/tests/testapi.js @@ -74,6 +74,20 @@ function globalStaticFunction() shouldBe("globalStaticValue", 3); shouldBe("globalStaticFunction()", 4); +shouldBe("this.globalStaticFunction()", 4); + +function globalStaticFunction2() { + return 10; +} +shouldBe("globalStaticFunction2();", 10); +this.globalStaticFunction2 = function() { return 20; } +shouldBe("globalStaticFunction2();", 20); +shouldBe("this.globalStaticFunction2();", 20); + +function iAmNotAStaticFunction() { return 10; } +shouldBe("iAmNotAStaticFunction();", 10); +this.iAmNotAStaticFunction = function() { return 20; } +shouldBe("iAmNotAStaticFunction();", 20); shouldBe("typeof MyObject", "function"); // our object implements 'call' MyObject.cantFind = 1; diff --git a/API/tests/testapi.mm b/API/tests/testapi.mm index 724867c..01bb7d7 100644 --- a/API/tests/testapi.mm +++ b/API/tests/testapi.mm @@ -28,6 +28,7 @@ #import "CurrentThisInsideBlockGetterTest.h" #import "DateTests.h" #import "JSExportTests.h" +#import "Regress141275.h" #import "Regress141809.h" #import <pthread.h> @@ -483,10 +484,35 @@ static void* threadMain(void* contextPtr) pthread_exit(nullptr); } -void testObjectiveCAPI() +// This test is flaky. Since GC marks C stack and registers as roots conservatively, +// objects not referenced logically can be accidentally marked and alive. +// To avoid this situation as possible as we can, +// 1. run this test first before stack is polluted, +// 2. extract this test as a function to suppress stack height. +static void testWeakValue() { - NSLog(@"Testing Objective-C API"); + @autoreleasepool { + JSVirtualMachine *vm = [[JSVirtualMachine alloc] init]; + TestObject *testObject = [TestObject testObject]; + JSManagedValue *weakValue; + @autoreleasepool { + JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; + context[@"testObject"] = testObject; + weakValue = [[JSManagedValue alloc] initWithValue:context[@"testObject"]]; + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; + context[@"testObject"] = testObject; + JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); + checkResult(@"weak value == nil", ![weakValue value]); + checkResult(@"root is still alive", !context[@"testObject"].isUndefined); + } + } +} +static void testObjectiveCAPIMain() +{ @autoreleasepool { JSVirtualMachine* vm = [[JSVirtualMachine alloc] init]; JSContext* context = [[JSContext alloc] initWithVirtualMachine:vm]; @@ -496,7 +522,7 @@ void testObjectiveCAPI() @autoreleasepool { JSContext *context = [[JSContext alloc] init]; JSValue *result = [context evaluateScript:@"2 + 2"]; - checkResult(@"2 + 2", [result isNumber] && [result toInt32] == 4); + checkResult(@"2 + 2", result.isNumber && [result toInt32] == 4); } @autoreleasepool { @@ -509,19 +535,38 @@ void testObjectiveCAPI() JSContext *context = [[JSContext alloc] init]; context[@"message"] = @"Hello"; JSValue *result = [context evaluateScript:@"message + ', World!'"]; - checkResult(@"Hello, World!", [result isString] && [result isEqualToObject:@"Hello, World!"]); + checkResult(@"Hello, World!", result.isString && [result isEqualToObject:@"Hello, World!"]); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + checkResult(@"Promise is not exposed", [context[@"Promise"] isUndefined]); + JSValue *result = [context evaluateScript:@"typeof Promise"]; + checkResult(@"typeof Promise is 'undefined'", result.isString && [result isEqualToObject:@"undefined"]); } @autoreleasepool { JSContext *context = [[JSContext alloc] init]; JSValue *result = [context evaluateScript:@"({ x:42 })"]; - checkResult(@"({ x:42 })", [result isObject] && [result[@"x"] isEqualToObject:@42]); + checkResult(@"({ x:42 })", result.isObject && [result[@"x"] isEqualToObject:@42]); id obj = [result toObject]; checkResult(@"Check dictionary literal", [obj isKindOfClass:[NSDictionary class]]); id num = (NSDictionary *)obj[@"x"]; checkResult(@"Check numeric literal", [num isKindOfClass:[NSNumber class]]); } + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *result = [context evaluateScript:@"[ ]"]; + checkResult(@"[ ]", result.isArray); + } + + @autoreleasepool { + JSContext *context = [[JSContext alloc] init]; + JSValue *result = [context evaluateScript:@"new Date"]; + checkResult(@"new Date", result.isDate); + } + @autoreleasepool { JSCollection* myPrivateProperties = [[JSCollection alloc] init]; @@ -543,11 +588,11 @@ void testObjectiveCAPI() JSValue *myNumber = [myPrivateProperties valueForKey:@"my_number"]; JSValue *definitelyNull = [myPrivateProperties valueForKey:@"definitely_null"]; JSValue *notSureIfUndefined = [myPrivateProperties valueForKey:@"not_sure_if_undefined"]; - checkResult(@"is_ham is true", [isHam isBoolean] && [isHam toBool]); - checkResult(@"message is hello!", [message isString] && [@"hello!" isEqualToString:[message toString]]); - checkResult(@"my_number is 42", [myNumber isNumber] && [myNumber toInt32] == 42); - checkResult(@"definitely_null is null", [definitelyNull isNull]); - checkResult(@"not_sure_if_undefined is undefined", [notSureIfUndefined isUndefined]); + checkResult(@"is_ham is true", isHam.isBoolean && [isHam toBool]); + checkResult(@"message is hello!", message.isString && [@"hello!" isEqualToString:[message toString]]); + checkResult(@"my_number is 42", myNumber.isNumber && [myNumber toInt32] == 42); + checkResult(@"definitely_null is null", definitelyNull.isNull); + checkResult(@"not_sure_if_undefined is undefined", notSureIfUndefined.isUndefined); } checkResult(@"is_ham is nil", ![myPrivateProperties valueForKey:@"is_ham"]); @@ -633,7 +678,7 @@ void testObjectiveCAPI() JSContext *context = [[JSContext alloc] init]; __block bool emptyExceptionSourceURL = false; context.exceptionHandler = ^(JSContext *, JSValue *exception) { - emptyExceptionSourceURL = [exception[@"sourceURL"] isUndefined]; + emptyExceptionSourceURL = exception[@"sourceURL"].isUndefined; }; [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"]; checkResult(@"evaluteScript: exception has no sourceURL", emptyExceptionSourceURL); @@ -694,7 +739,7 @@ void testObjectiveCAPI() return result; \ })"]; JSValue *result = [mulAddFunction callWithArguments:@[ @[ @2, @4, @8 ], @{ @"x":@0.5, @"y":@42 } ]]; - checkResult(@"mulAddFunction", [result isObject] && [[result toString] isEqual:@"43,44,46"]); + checkResult(@"mulAddFunction", result.isObject && [[result toString] isEqual:@"43,44,46"]); } @autoreleasepool { @@ -719,7 +764,7 @@ void testObjectiveCAPI() checkResult(@"array.length after put to maxLength + 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength); if (sizeof(NSUInteger) == 8) - checkResult(@"valueAtIndex:0 is undefined", [[array valueAtIndex:0] isUndefined]); + checkResult(@"valueAtIndex:0 is undefined", [array valueAtIndex:0].isUndefined); else checkResult(@"valueAtIndex:0", [[array valueAtIndex:0] toInt32] == 24); checkResult(@"valueAtIndex:lowIndex", [[array valueAtIndex:lowIndex] toInt32] == 42); @@ -843,7 +888,7 @@ void testObjectiveCAPI() context[@"testObjectA"] = testObject; context[@"testObjectB"] = testObject; JSValue *result = [context evaluateScript:@"testObjectA == testObjectB"]; - checkResult(@"testObjectA == testObjectB", [result isBoolean] && [result toBool]); + checkResult(@"testObjectA == testObjectB", result.isBoolean && [result toBool]); } @autoreleasepool { @@ -863,7 +908,7 @@ void testObjectiveCAPI() context[@"testObject"] = testObject; context[@"mul"] = ^(int x, int y){ return x * y; }; JSValue *result = [context evaluateScript:@"mul(testObject.six, 7)"]; - checkResult(@"mul(testObject.six, 7)", [result isNumber] && [result toInt32] == 42); + checkResult(@"mul(testObject.six, 7)", result.isNumber && [result toInt32] == 42); } @autoreleasepool { @@ -894,7 +939,7 @@ void testObjectiveCAPI() TestObject* testObject = [TestObject testObject]; context[@"testObject"] = testObject; JSValue *result = [context evaluateScript:@"testObject.getString()"]; - checkResult(@"testObject.getString()", [result isString] && [result toInt32] == 42); + checkResult(@"testObject.getString()", result.isString && [result toInt32] == 42); } @autoreleasepool { @@ -910,7 +955,7 @@ void testObjectiveCAPI() TestObject* testObject = [TestObject testObject]; context[@"testObject"] = testObject; JSValue *result = [context evaluateScript:@"testObject.getString.call(testObject)"]; - checkResult(@"testObject.getString.call(testObject)", [result isString] && [result toInt32] == 42); + checkResult(@"testObject.getString.call(testObject)", result.isString && [result toInt32] == 42); } @autoreleasepool { @@ -927,9 +972,9 @@ void testObjectiveCAPI() TestObject* testObject = [TestObject testObject]; context[@"testObject"] = testObject; JSValue *result = [context evaluateScript:@"var result = 0; testObject.callback(function(x){ result = x; }); result"]; - checkResult(@"testObject.callback", [result isNumber] && [result toInt32] == 42); + checkResult(@"testObject.callback", result.isNumber && [result toInt32] == 42); result = [context evaluateScript:@"testObject.bogusCallback"]; - checkResult(@"testObject.bogusCallback == undefined", [result isUndefined]); + checkResult(@"testObject.bogusCallback == undefined", result.isUndefined); } @autoreleasepool { @@ -937,7 +982,7 @@ void testObjectiveCAPI() TestObject *testObject = [TestObject testObject]; context[@"testObject"] = testObject; JSValue *result = [context evaluateScript:@"Function.prototype.toString.call(testObject.callback)"]; - checkResult(@"Function.prototype.toString", !context.exception && ![result isUndefined]); + checkResult(@"Function.prototype.toString", !context.exception && !result.isUndefined); } @autoreleasepool { @@ -1018,13 +1063,13 @@ void testObjectiveCAPI() @autoreleasepool { JSValue *result = [context evaluateScript:@"testXYZ.onclick"]; - checkResult(@"onclick still around after GC", !([result isNull] || [result isUndefined])); + checkResult(@"onclick still around after GC", !(result.isNull || result.isUndefined)); } @autoreleasepool { JSValue *result = [context evaluateScript:@"testXYZ.weakOnclick"]; - checkResult(@"weakOnclick not around after GC", [result isNull] || [result isUndefined]); + checkResult(@"weakOnclick not around after GC", result.isNull || result.isUndefined); } @autoreleasepool { @@ -1043,25 +1088,6 @@ void testObjectiveCAPI() } } - @autoreleasepool { - JSVirtualMachine *vm = [[JSVirtualMachine alloc] init]; - TestObject *testObject = [TestObject testObject]; - JSManagedValue *weakValue; - @autoreleasepool { - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - context[@"testObject"] = testObject; - weakValue = [[JSManagedValue alloc] initWithValue:context[@"testObject"]]; - } - - @autoreleasepool { - JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm]; - context[@"testObject"] = testObject; - JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); - checkResult(@"weak value == nil", ![weakValue value]); - checkResult(@"root is still alive", ![context[@"testObject"] isUndefined]); - } - } - @autoreleasepool { JSContext *context = [[JSContext alloc] init]; TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine]; @@ -1088,7 +1114,7 @@ void testObjectiveCAPI() JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"]; - checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42); + checkResult(@"My custom property == 42", myCustomProperty.isNumber && [myCustomProperty toInt32] == 42); } @autoreleasepool { @@ -1120,7 +1146,7 @@ void testObjectiveCAPI() JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]); JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"]; - checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42); + checkResult(@"duplicate calls to addManagedReference don't cause things to die", myCustomProperty.isNumber && [myCustomProperty toInt32] == 42); } @autoreleasepool { @@ -1209,7 +1235,7 @@ void testObjectiveCAPI() NSLog(@"I'm intentionally not returning anything."); }; JSValue *result = [context evaluateScript:@"new MyClass()"]; - checkResult(@"result === undefined", [result isUndefined]); + checkResult(@"result === undefined", result.isUndefined); checkResult(@"exception.message is correct'", context.exception && [@"Objective-C blocks called as constructors must return an object." isEqualToString:[context.exception[@"message"] toString]]); } @@ -1331,7 +1357,7 @@ void testObjectiveCAPI() return [[UnexportedObject alloc] init]; }; JSValue *result = [context evaluateScript:@"(makeObject() instanceof UnexportedObject)"]; - checkResult(@"makeObject() instanceof UnexportedObject", [result isBoolean] && [result toBool]); + checkResult(@"makeObject() instanceof UnexportedObject", result.isBoolean && [result toBool]); } @autoreleasepool { @@ -1386,9 +1412,49 @@ void testObjectiveCAPI() currentThisInsideBlockGetterTest(); runDateTests(); runJSExportTests(); + runRegress141275(); runRegress141809(); } +@protocol NumberProtocol <JSExport> + +@property (nonatomic) NSInteger number; + +@end + +@interface NumberObject : NSObject <NumberProtocol> + +@property (nonatomic) NSInteger number; + +@end + +@implementation NumberObject + +@end + +// Check that negative NSIntegers retain the correct value when passed into JS code. +static void checkNegativeNSIntegers() +{ + NumberObject *container = [[NumberObject alloc] init]; + container.number = -1; + JSContext *context = [[JSContext alloc] init]; + context[@"container"] = container; + NSString *jsID = @"var getContainerNumber = function() { return container.number }"; + [context evaluateScript:jsID]; + JSValue *jsFunction = context[@"getContainerNumber"]; + JSValue *result = [jsFunction callWithArguments:@[]]; + + checkResult(@"Negative number maintained its original value", [[result toString] isEqualToString:@"-1"]); +} + +void testObjectiveCAPI() +{ + NSLog(@"Testing Objective-C API"); + checkNegativeNSIntegers(); + testWeakValue(); + testObjectiveCAPIMain(); +} + #else void testObjectiveCAPI() diff --git a/CMakeLists.txt b/CMakeLists.txt index cc45c2f..8ae8665 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,8 @@ set(JavaScriptCore_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/debugger" "${JAVASCRIPTCORE_DIR}/inspector" "${JAVASCRIPTCORE_DIR}/inspector/agents" + "${JAVASCRIPTCORE_DIR}/inspector/augmentable" + "${JAVASCRIPTCORE_DIR}/inspector/remote" "${JAVASCRIPTCORE_DIR}/interpreter" "${JAVASCRIPTCORE_DIR}/jit" "${JAVASCRIPTCORE_DIR}/llint" @@ -26,9 +28,15 @@ set(JavaScriptCore_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/tools" "${JAVASCRIPTCORE_DIR}/yarr" "${WTF_DIR}" + "${DERIVED_SOURCES_DIR}" + "${DERIVED_SOURCES_DIR}/ForwardingHeaders" "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" + "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector" "${CMAKE_SOURCE_DIR}/Source" - ${ICU_INCLUDE_DIRS} +) + +set(JavaScriptCore_SYSTEM_INCLUDE_DIRECTORIES + "${ICU_INCLUDE_DIRS}" ) set(JavaScriptCore_SOURCES @@ -47,8 +55,11 @@ set(JavaScriptCore_SOURCES API/JSWeakObjectMapRefPrivate.cpp API/OpaqueJSString.cpp + assembler/ARMAssembler.cpp assembler/LinkBuffer.cpp assembler/MacroAssembler.cpp + assembler/MacroAssemblerARM.cpp + assembler/MacroAssemblerARMv7.cpp assembler/MacroAssemblerX86Common.cpp bindings/ScriptFunctionCall.cpp @@ -60,16 +71,22 @@ set(JavaScriptCore_SOURCES bytecode/ArrayAllocationProfile.cpp bytecode/ArrayProfile.cpp bytecode/BytecodeBasicBlock.cpp + bytecode/BytecodeIntrinsicRegistry.cpp bytecode/BytecodeLivenessAnalysis.cpp + bytecode/CallEdge.cpp bytecode/CallLinkInfo.cpp bytecode/CallLinkStatus.cpp + bytecode/CallVariant.cpp bytecode/CodeBlock.cpp bytecode/CodeBlockHash.cpp bytecode/CodeBlockJettisoningWatchpoint.cpp bytecode/CodeOrigin.cpp bytecode/CodeType.cpp + bytecode/ComplexGetStatus.cpp + bytecode/ConstantStructureCheck.cpp bytecode/DFGExitProfile.cpp bytecode/DeferredCompilationCallback.cpp + bytecode/DeferredSourceDump.cpp bytecode/ExecutionCounter.cpp bytecode/ExitKind.cpp bytecode/ExitingJITType.cpp @@ -83,73 +100,88 @@ set(JavaScriptCore_SOURCES bytecode/PolymorphicGetByIdList.cpp bytecode/PolymorphicPutByIdList.cpp bytecode/PreciseJumpTargets.cpp - bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp bytecode/PutByIdStatus.cpp bytecode/PutByIdVariant.cpp bytecode/ReduceWhitespace.cpp bytecode/SamplingTool.cpp bytecode/SpecialPointer.cpp bytecode/SpeculatedType.cpp + bytecode/StructureSet.cpp bytecode/StructureStubClearingWatchpoint.cpp bytecode/StructureStubInfo.cpp + bytecode/ToThisStatus.cpp + bytecode/TrackedReferences.cpp bytecode/UnlinkedCodeBlock.cpp bytecode/UnlinkedInstructionStream.cpp bytecode/ValueRecovery.cpp + bytecode/VariableWriteFireDetail.cpp + bytecode/VirtualRegister.cpp bytecode/Watchpoint.cpp bytecompiler/BytecodeGenerator.cpp bytecompiler/NodesCodegen.cpp debugger/Debugger.cpp - debugger/DebuggerActivation.cpp debugger/DebuggerCallFrame.cpp + debugger/DebuggerScope.cpp dfg/DFGAbstractHeap.cpp dfg/DFGAbstractValue.cpp - dfg/DFGArgumentsSimplificationPhase.cpp + dfg/DFGArgumentsEliminationPhase.cpp + dfg/DFGArgumentsUtilities.cpp dfg/DFGArithMode.cpp dfg/DFGArrayMode.cpp dfg/DFGAtTailAbstractState.cpp dfg/DFGAvailability.cpp + dfg/DFGAvailabilityMap.cpp dfg/DFGBackwardsPropagationPhase.cpp dfg/DFGBasicBlock.cpp - dfg/DFGBinarySwitch.cpp dfg/DFGBlockInsertionSet.cpp + dfg/DFGBlockSet.cpp + dfg/DFGBlockWorklist.cpp dfg/DFGByteCodeParser.cpp dfg/DFGCFAPhase.cpp dfg/DFGCFGSimplificationPhase.cpp dfg/DFGCPSRethreadingPhase.cpp dfg/DFGCSEPhase.cpp dfg/DFGCapabilities.cpp + dfg/DFGCleanUpPhase.cpp dfg/DFGClobberSet.cpp dfg/DFGClobberize.cpp + dfg/DFGCombinedLiveness.cpp dfg/DFGCommon.cpp dfg/DFGCommonData.cpp dfg/DFGCompilationKey.cpp dfg/DFGCompilationMode.cpp dfg/DFGConstantFoldingPhase.cpp + dfg/DFGConstantHoistingPhase.cpp dfg/DFGCriticalEdgeBreakingPhase.cpp dfg/DFGDCEPhase.cpp dfg/DFGDesiredIdentifiers.cpp - dfg/DFGDesiredStructureChains.cpp dfg/DFGDesiredTransitions.cpp dfg/DFGDesiredWatchpoints.cpp dfg/DFGDesiredWeakReferences.cpp dfg/DFGDesiredWriteBarriers.cpp dfg/DFGDisassembler.cpp + dfg/DFGDoesGC.cpp dfg/DFGDominators.cpp dfg/DFGDriver.cpp dfg/DFGEdge.cpp + dfg/DFGEpoch.cpp dfg/DFGFailedFinalizer.cpp dfg/DFGFinalizer.cpp dfg/DFGFixupPhase.cpp dfg/DFGFlushFormat.cpp dfg/DFGFlushedAt.cpp + dfg/DFGFrozenValue.cpp dfg/DFGFunctionWhitelist.cpp dfg/DFGGraph.cpp dfg/DFGGraphSafepoint.cpp + dfg/DFGHeapLocation.cpp dfg/DFGInPlaceAbstractState.cpp + dfg/DFGInsertOSRHintsForUpdate.cpp dfg/DFGIntegerCheckCombiningPhase.cpp + dfg/DFGIntegerRangeOptimizationPhase.cpp dfg/DFGInvalidationPointInjectionPhase.cpp dfg/DFGJITCode.cpp dfg/DFGJITCompiler.cpp @@ -157,10 +189,15 @@ set(JavaScriptCore_SOURCES dfg/DFGJumpReplacement.cpp dfg/DFGLICMPhase.cpp dfg/DFGLazyJSValue.cpp + dfg/DFGLazyNode.cpp dfg/DFGLivenessAnalysisPhase.cpp dfg/DFGLongLivedState.cpp dfg/DFGLoopPreHeaderCreationPhase.cpp + dfg/DFGMayExit.cpp + dfg/DFGMinifiedGraph.cpp dfg/DFGMinifiedNode.cpp + dfg/DFGMovHintRemovalPhase.cpp + dfg/DFGNaiveDominators.cpp dfg/DFGNaturalLoops.cpp dfg/DFGNode.cpp dfg/DFGNodeFlags.cpp @@ -173,14 +210,23 @@ set(JavaScriptCore_SOURCES dfg/DFGOSRExitCompiler32_64.cpp dfg/DFGOSRExitCompiler64.cpp dfg/DFGOSRExitCompilerCommon.cpp + dfg/DFGOSRExitFuzz.cpp dfg/DFGOSRExitJumpPlaceholder.cpp dfg/DFGOSRExitPreparation.cpp + dfg/DFGObjectAllocationSinkingPhase.cpp + dfg/DFGObjectMaterializationData.cpp dfg/DFGOperations.cpp + dfg/DFGPhantomInsertionPhase.cpp dfg/DFGPhase.cpp + dfg/DFGPhiChildren.cpp dfg/DFGPlan.cpp + dfg/DFGPrePostNumbering.cpp dfg/DFGPredictionInjectionPhase.cpp dfg/DFGPredictionPropagationPhase.cpp - dfg/DFGResurrectionForValidationPhase.cpp + dfg/DFGPromotedHeapLocation.cpp + dfg/DFGPureValue.cpp + dfg/DFGPutStackSinkingPhase.cpp + dfg/DFGSSACalculator.cpp dfg/DFGSSAConversionPhase.cpp dfg/DFGSSALoweringPhase.cpp dfg/DFGSafepoint.cpp @@ -189,16 +235,21 @@ set(JavaScriptCore_SOURCES dfg/DFGSpeculativeJIT64.cpp dfg/DFGStackLayoutPhase.cpp dfg/DFGStaticExecutionCountEstimationPhase.cpp - dfg/DFGStoreBarrierElisionPhase.cpp + dfg/DFGStoreBarrierInsertionPhase.cpp dfg/DFGStrengthReductionPhase.cpp + dfg/DFGStructureAbstractValue.cpp + dfg/DFGStructureRegistrationPhase.cpp dfg/DFGThreadData.cpp dfg/DFGThunks.cpp dfg/DFGTierUpCheckInjectionPhase.cpp + dfg/DFGTransition.cpp dfg/DFGTypeCheckHoistingPhase.cpp dfg/DFGUnificationPhase.cpp dfg/DFGUseKind.cpp dfg/DFGValidate.cpp dfg/DFGValueSource.cpp + dfg/DFGValueStrength.cpp + dfg/DFGVarargsForwardingPhase.cpp dfg/DFGVariableAccessData.cpp dfg/DFGVariableAccessDataDump.cpp dfg/DFGVariableEvent.cpp @@ -207,14 +258,16 @@ set(JavaScriptCore_SOURCES dfg/DFGWatchpointCollectionPhase.cpp dfg/DFGWorklist.cpp - disassembler/ARMv7/ARMv7DOpcode.cpp + disassembler/ARM64Disassembler.cpp disassembler/ARMv7Disassembler.cpp disassembler/Disassembler.cpp disassembler/LLVMDisassembler.cpp - disassembler/UDis86Disassembler.cpp disassembler/X86Disassembler.cpp - heap/BlockAllocator.cpp + disassembler/ARM64/A64DOpcode.cpp + + disassembler/ARMv7/ARMv7DOpcode.cpp + heap/CodeBlockSet.cpp heap/ConservativeRoots.cpp heap/CopiedSpace.cpp @@ -231,6 +284,7 @@ set(JavaScriptCore_SOURCES heap/Heap.cpp heap/HeapStatistics.cpp heap/HeapTimer.cpp + heap/HeapVerifier.cpp heap/IncrementalSweeper.cpp heap/JITStubRoutineSet.cpp heap/MachineStackMarker.cpp @@ -239,7 +293,6 @@ set(JavaScriptCore_SOURCES heap/MarkedBlock.cpp heap/MarkedSpace.cpp heap/SlotVisitor.cpp - heap/SuperRegion.cpp heap/Weak.cpp heap/WeakBlock.cpp heap/WeakHandleOwner.cpp @@ -249,6 +302,7 @@ set(JavaScriptCore_SOURCES inspector/ConsoleMessage.cpp inspector/ContentSearchUtilities.cpp + inspector/EventLoop.cpp inspector/IdentifiersFactory.cpp inspector/InjectedScript.cpp inspector/InjectedScriptBase.cpp @@ -258,6 +312,9 @@ set(JavaScriptCore_SOURCES inspector/InspectorAgentRegistry.cpp inspector/InspectorBackendDispatcher.cpp inspector/InspectorValues.cpp + inspector/JSGlobalObjectConsoleClient.cpp + inspector/JSGlobalObjectInspectorController.cpp + inspector/JSGlobalObjectScriptDebugServer.cpp inspector/JSInjectedScriptHost.cpp inspector/JSInjectedScriptHostPrototype.cpp inspector/JSJavaScriptCallFrame.cpp @@ -268,11 +325,14 @@ set(JavaScriptCore_SOURCES inspector/ScriptCallStack.cpp inspector/ScriptCallStackFactory.cpp inspector/ScriptDebugServer.cpp + inspector/agents/InspectorAgent.cpp inspector/agents/InspectorConsoleAgent.cpp inspector/agents/InspectorDebuggerAgent.cpp - inspector/agents/InspectorProfilerAgent.cpp inspector/agents/InspectorRuntimeAgent.cpp + inspector/agents/JSGlobalObjectConsoleAgent.cpp + inspector/agents/JSGlobalObjectDebuggerAgent.cpp + inspector/agents/JSGlobalObjectRuntimeAgent.cpp interpreter/AbstractPC.cpp interpreter/CallFrame.cpp @@ -280,12 +340,12 @@ set(JavaScriptCore_SOURCES interpreter/JSStack.cpp interpreter/ProtoCallFrame.cpp interpreter/StackVisitor.cpp - interpreter/VMInspector.cpp jit/AccessorCallJITStubRoutine.cpp - jit/AssemblyHelpers.cpp jit/ArityCheckFailReturnThunks.cpp - jit/ClosureCallStubRoutine.cpp + jit/AssemblyHelpers.cpp + jit/BinarySwitch.cpp + jit/ExecutableAllocationFuzz.cpp jit/ExecutableAllocator.cpp jit/ExecutableAllocatorFixedVMPool.cpp jit/GCAwareJITStubRoutine.cpp @@ -308,11 +368,13 @@ set(JavaScriptCore_SOURCES jit/JITStubs.cpp jit/JITThunks.cpp jit/JITToDFGDeferredCompilationCallback.cpp + jit/PolymorphicCallStubRoutine.cpp jit/Reg.cpp jit/RegisterPreservationWrapperGenerator.cpp jit/RegisterSet.cpp jit/Repatch.cpp jit/ScratchRegisterAllocator.cpp + jit/SetupVarargsFrame.cpp jit/TempRegisterSet.cpp jit/ThunkGenerators.cpp @@ -342,21 +404,35 @@ set(JavaScriptCore_SOURCES profiler/ProfilerOriginStack.cpp profiler/ProfilerProfiledBytecodes.cpp + tools/CodeProfile.cpp + tools/CodeProfiling.cpp + tools/FunctionOverrides.cpp + tools/JSDollarVM.cpp + tools/JSDollarVMPrototype.cpp + + yarr/RegularExpression.cpp + yarr/YarrCanonicalizeUCS2.cpp + yarr/YarrInterpreter.cpp + yarr/YarrJIT.cpp + yarr/YarrPattern.cpp + yarr/YarrSyntaxChecker.cpp +) + +set(JavaScriptCore_RUNTIME_SOURCES runtime/ArgList.cpp - runtime/Arguments.cpp - runtime/ArgumentsIteratorConstructor.cpp - runtime/ArgumentsIteratorPrototype.cpp runtime/ArrayBuffer.cpp runtime/ArrayBufferNeuteringWatchpoint.cpp runtime/ArrayBufferView.cpp runtime/ArrayConstructor.cpp - runtime/ArrayIteratorConstructor.cpp runtime/ArrayIteratorPrototype.cpp runtime/ArrayPrototype.cpp + runtime/BasicBlockLocation.cpp runtime/BooleanConstructor.cpp runtime/BooleanObject.cpp runtime/BooleanPrototype.cpp + runtime/BundlePath.cpp runtime/CallData.cpp + runtime/ClonedArguments.cpp runtime/CodeCache.cpp runtime/CodeSpecializationKind.cpp runtime/CommonIdentifiers.cpp @@ -366,34 +442,43 @@ set(JavaScriptCore_SOURCES runtime/Completion.cpp runtime/ConsoleClient.cpp runtime/ConsolePrototype.cpp + runtime/ConstantMode.cpp runtime/ConstructData.cpp + runtime/ControlFlowProfiler.cpp runtime/CustomGetterSetter.cpp runtime/DataView.cpp - runtime/DataView.h runtime/DateConstructor.cpp runtime/DateConversion.cpp runtime/DateInstance.cpp runtime/DatePrototype.cpp + runtime/DirectArguments.cpp + runtime/DirectArgumentsOffset.cpp runtime/DumpContext.cpp runtime/Error.cpp runtime/ErrorConstructor.cpp runtime/ErrorHandlingScope.cpp runtime/ErrorInstance.cpp runtime/ErrorPrototype.cpp + runtime/Exception.cpp + runtime/ExceptionFuzz.cpp runtime/ExceptionHelpers.cpp runtime/Executable.cpp runtime/FunctionConstructor.cpp runtime/FunctionExecutableDump.cpp + runtime/FunctionHasExecutedCache.cpp runtime/FunctionPrototype.cpp + runtime/FunctionRareData.cpp runtime/GetterSetter.cpp runtime/Identifier.cpp runtime/IndexingType.cpp + runtime/InferredValue.cpp runtime/InitializeThreading.cpp runtime/IntendedStructureChain.cpp runtime/InternalFunction.cpp + runtime/IntlObject.cpp + runtime/IteratorOperations.cpp + runtime/IteratorPrototype.cpp runtime/JSAPIValueWrapper.cpp - runtime/JSActivation.cpp - runtime/JSArgumentsIterator.cpp runtime/JSArray.cpp runtime/JSArrayBuffer.cpp runtime/JSArrayBufferConstructor.cpp @@ -402,14 +487,21 @@ set(JavaScriptCore_SOURCES runtime/JSArrayIterator.cpp runtime/JSBoundFunction.cpp runtime/JSCJSValue.cpp + runtime/JSCallee.cpp + runtime/JSCatchScope.cpp runtime/JSCell.cpp runtime/JSConsole.cpp runtime/JSDataView.cpp runtime/JSDataViewPrototype.cpp runtime/JSDateMath.cpp + runtime/JSEnvironmentRecord.cpp runtime/JSFunction.cpp + runtime/JSFunctionNameScope.cpp runtime/JSGlobalObject.cpp + runtime/JSGlobalObjectDebuggable.cpp runtime/JSGlobalObjectFunctions.cpp + runtime/JSJob.cpp + runtime/JSLexicalEnvironment.cpp runtime/JSLock.cpp runtime/JSMap.cpp runtime/JSMapIterator.cpp @@ -420,39 +512,37 @@ set(JavaScriptCore_SOURCES runtime/JSPromise.cpp runtime/JSPromiseConstructor.cpp runtime/JSPromiseDeferred.cpp - runtime/JSPromiseFunctions.cpp - runtime/JSPromiseReaction.cpp runtime/JSPromisePrototype.cpp - runtime/JSPropertyNameIterator.cpp + runtime/JSPropertyNameEnumerator.cpp runtime/JSProxy.cpp runtime/JSScope.cpp runtime/JSSegmentedVariableObject.cpp runtime/JSSet.cpp runtime/JSSetIterator.cpp runtime/JSString.cpp + runtime/JSStringIterator.cpp runtime/JSStringJoiner.cpp runtime/JSSymbolTableObject.cpp + runtime/JSTemplateRegistryKey.cpp runtime/JSTypedArrayConstructors.cpp runtime/JSTypedArrayPrototypes.cpp runtime/JSTypedArrays.cpp - runtime/JSVariableObject.cpp runtime/JSWeakMap.cpp + runtime/JSWeakSet.cpp runtime/JSWithScope.cpp runtime/JSWrapperObject.cpp runtime/LiteralParser.cpp runtime/Lookup.cpp runtime/MapConstructor.cpp - runtime/MapData.cpp - runtime/MapIteratorConstructor.cpp runtime/MapIteratorPrototype.cpp runtime/MapPrototype.cpp + runtime/MathCommon.cpp runtime/MathObject.cpp runtime/MemoryStatistics.cpp - runtime/NameConstructor.cpp - runtime/NameInstance.cpp - runtime/NamePrototype.cpp runtime/NativeErrorConstructor.cpp runtime/NativeErrorPrototype.cpp + runtime/NullGetterFunction.cpp + runtime/NullSetterFunction.cpp runtime/NumberConstructor.cpp runtime/NumberObject.cpp runtime/NumberPrototype.cpp @@ -461,7 +551,6 @@ set(JavaScriptCore_SOURCES runtime/Operations.cpp runtime/Options.cpp runtime/PropertyDescriptor.cpp - runtime/PropertyNameArray.cpp runtime/PropertySlot.cpp runtime/PropertyTable.cpp runtime/PrototypeMap.cpp @@ -472,9 +561,12 @@ set(JavaScriptCore_SOURCES runtime/RegExpMatchesArray.cpp runtime/RegExpObject.cpp runtime/RegExpPrototype.cpp + runtime/RuntimeType.cpp runtime/SamplingCounter.cpp + runtime/ScopeOffset.cpp + runtime/ScopedArguments.cpp + runtime/ScopedArgumentsTable.cpp runtime/SetConstructor.cpp - runtime/SetIteratorConstructor.cpp runtime/SetIteratorPrototype.cpp runtime/SetPrototype.cpp runtime/SimpleTypedArrayController.cpp @@ -482,6 +574,7 @@ set(JavaScriptCore_SOURCES runtime/SparseArrayValueMap.cpp runtime/StrictEvalActivation.cpp runtime/StringConstructor.cpp + runtime/StringIteratorPrototype.cpp runtime/StringObject.cpp runtime/StringPrototype.cpp runtime/StringRecursionChecker.cpp @@ -489,32 +582,39 @@ set(JavaScriptCore_SOURCES runtime/StructureChain.cpp runtime/StructureIDTable.cpp runtime/StructureRareData.cpp + runtime/Symbol.cpp + runtime/SymbolConstructor.cpp + runtime/SymbolObject.cpp + runtime/SymbolPrototype.cpp runtime/SymbolTable.cpp + runtime/TemplateRegistry.cpp runtime/TestRunnerUtils.cpp + runtime/TypeLocationCache.cpp + runtime/TypeProfiler.cpp + runtime/TypeProfilerLog.cpp + runtime/TypeSet.cpp runtime/TypedArrayController.cpp runtime/TypedArrayType.cpp + runtime/TypeofType.cpp runtime/VM.cpp runtime/VMEntryScope.cpp + runtime/VarOffset.cpp runtime/Watchdog.cpp runtime/WatchdogNone.cpp runtime/WeakMapConstructor.cpp runtime/WeakMapData.cpp runtime/WeakMapPrototype.cpp + runtime/WeakSetConstructor.cpp + runtime/WeakSetPrototype.cpp +) - tools/CodeProfile.cpp - tools/CodeProfiling.cpp - - yarr/RegularExpression.cpp - yarr/YarrCanonicalizeUCS2.cpp - yarr/YarrInterpreter.cpp - yarr/YarrJIT.cpp - yarr/YarrPattern.cpp - yarr/YarrSyntaxChecker.cpp +list(APPEND JavaScriptCore_SOURCES + ${JavaScriptCore_RUNTIME_SOURCES} ) set(JavaScriptCore_LUT_FILES runtime/ArrayConstructor.cpp - runtime/ArrayPrototype.cpp + runtime/ArrayIteratorPrototype.cpp runtime/BooleanPrototype.cpp runtime/DateConstructor.cpp runtime/DatePrototype.cpp @@ -524,14 +624,15 @@ set(JavaScriptCore_LUT_FILES runtime/JSONObject.cpp runtime/JSPromiseConstructor.cpp runtime/JSPromisePrototype.cpp - runtime/NamePrototype.cpp runtime/NumberConstructor.cpp runtime/NumberPrototype.cpp runtime/ObjectConstructor.cpp runtime/RegExpConstructor.cpp - runtime/RegExpObject.cpp runtime/RegExpPrototype.cpp runtime/StringConstructor.cpp + runtime/StringIteratorPrototype.cpp + runtime/SymbolConstructor.cpp + runtime/SymbolPrototype.cpp ) set(JavaScriptCore_LIBRARIES @@ -539,7 +640,7 @@ set(JavaScriptCore_LIBRARIES ${ICU_I18N_LIBRARIES} ) -if (WTF_USE_UDIS86) +if (USE_UDIS86) set(UDIS_GEN_DEP disassembler/udis86/ud_opcode.py disassembler/udis86/ud_optable.py @@ -559,6 +660,8 @@ if (WTF_USE_UDIS86) ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/udis86_itab.h ) list(APPEND JavaScriptCore_SOURCES + disassembler/UDis86Disassembler.cpp + disassembler/udis86/udis86.c disassembler/udis86/udis86_decode.c disassembler/udis86/udis86_input.c @@ -569,13 +672,6 @@ if (WTF_USE_UDIS86) ) endif () -# We cannot check for RUBY_FOUND because it is set only when the full package is installed and -# the only thing we need is the interpreter. Unlike Python, cmake does not provide a macro -# for finding the only Ruby interpreter. -if (NOT RUBY_EXECUTABLE) - message(FATAL_ERROR "The Ruby interpreter is needed to generate LLInt files.") -endif () - set(LLINT_ASM llint/LowLevelInterpreter.asm llint/LowLevelInterpreter32_64.asm @@ -584,11 +680,13 @@ set(LLINT_ASM set(OFFLINE_ASM offlineasm/arm.rb + offlineasm/arm64.rb offlineasm/ast.rb offlineasm/backends.rb offlineasm/cloop.rb offlineasm/config.rb offlineasm/instructions.rb + offlineasm/mips.rb offlineasm/offsets.rb offlineasm/opt.rb offlineasm/parser.rb @@ -596,6 +694,7 @@ set(OFFLINE_ASM offlineasm/risc.rb offlineasm/self_hash.rb offlineasm/settings.rb + offlineasm/sh4.rb offlineasm/transform.rb offlineasm/x86.rb ) @@ -635,21 +734,41 @@ target_link_libraries(LLIntOffsetsExtractor WTF) # 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. +if (MSVC) + set(LLIntOutput LowLevelInterpreterWin.asm) +else () + set(LLIntOutput LLIntAssembly.h) +endif () + add_custom_command( - OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${LLIntOutput} MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb DEPENDS LLIntOffsetsExtractor ${LLINT_ASM} ${OFFLINE_ASM} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InitBytecodes.asm - COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb -I${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/ ${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 + COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/offlineasm/asm.rb -I${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/ ${JAVASCRIPTCORE_DIR}/llint/LowLevelInterpreter.asm $<TARGET_FILE:LLIntOffsetsExtractor> ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${LLIntOutput} + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/${LLIntOutput} VERBATIM) # The explanation for not making LLIntAssembly.h part of the OBJECT_DEPENDS property of some of # the .cpp files below is similar to the one in the previous comment. However, since these .cpp # files are used to build JavaScriptCore itself, we can just add LLIntAssembly.h to JSC_HEADERS # since it is used in the add_library() call at the end of this file. -list(APPEND JavaScriptCore_HEADERS - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h -) +if (MSVC) + enable_language(ASM_MASM) + list(APPEND JavaScriptCore_SOURCES + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LowLevelInterpreterWin.asm + ) + # Win32 needs /safeseh with assembly, but Win64 does not. + if (CMAKE_SIZEOF_VOID_P EQUAL 4) + set_source_files_properties(${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LowLevelInterpreterWin.asm + PROPERTIES COMPILE_FLAGS "/safeseh" + ) + endif () +else () + list(APPEND JavaScriptCore_HEADERS + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/LLIntAssembly.h + ) +endif () + list(APPEND JavaScriptCore_SOURCES llint/LLIntCLoop.cpp llint/LLIntData.cpp @@ -683,14 +802,50 @@ if (ENABLE_FTL_JIT) COMMAND ${CMAKE_COMMAND} -E touch ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/WebKitLLVMLibraryToken.h VERBATIM) + if (ENABLE_FTL_NATIVE_CALL_INLINING) + function(JOIN VALUES GLUE OUTPUT) + string(REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}") + set(${OUTPUT} "${_TMP_STR}" PARENT_SCOPE) + endfunction() + + JOIN("${JavaScriptCore_INCLUDE_DIRECTORIES}" " -I" JSC_INCLUDES) + + set(LLVM_BITCODE_FILES) + + foreach (_file ${JavaScriptCore_RUNTIME_SOURCES}) + get_filename_component(_name ${_file} NAME_WE) + add_custom_command( + OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/runtime/${_name}.bc + COMMAND ${PYTHON_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create-llvm-ir-from-source-file.py ${_file} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${CLANG_EXE} "${JSC_INCLUDES}" + WORKING_DIRECTORY "${JAVASCRIPTCORE_DIR}" + VERBATIM) + + ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/ftl/FTLState.cpp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/runtime/${_name}.bc) + list(APPEND LLVM_BITCODE_FILES + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/runtime/${_name}.bc + ) + endforeach () + + get_filename_component(LLVM_BINS ${LLVM_CONFIG_EXE} PATH) + + add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InlineRuntimeSymbolTable.h + MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/create-symbol-table-index.py + DEPENDS ${LLVM_BITCODE_FILES} + COMMAND ${PYTHON_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create-symbol-table-index.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${JAVASCRIPTCORE_DIR} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR} ${LLVM_BINS} + WORKING_DIRECTORY "${JAVASCRIPTCORE_DIR}" + VERBATIM) + + ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/ftl/FTLState.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InlineRuntimeSymbolTable.h) + endif () + WEBKIT_WRAP_SOURCELIST(${llvmForJSC_SOURCES}) add_library(llvmForJSC SHARED ${llvmForJSC_SOURCES} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/WebKitLLVMLibraryToken.h) - target_link_libraries(llvmForJSC ${LLVM_STATIC_LIBRARIES} "pthread" "dl") + target_link_libraries(llvmForJSC ${LLVM_STATIC_LIBRARIES} "pthread" "dl" -Wl,--version-script=${JAVASCRIPTCORE_DIR}/llvm/library/libllvmForJSC.version) # Added extra items for JavaScriptCore - list(APPEND JavaScriptCore_INCLUDE_DIRECTORIES + list(APPEND JavaScriptCore_SYSTEM_INCLUDE_DIRECTORIES ${LLVM_INCLUDE_DIRS} - ${LIBCXXABI_INCLUDE_DIRS} ) list(APPEND JavaScriptCore_SOURCES @@ -711,7 +866,9 @@ if (ENABLE_FTL_JIT) ftl/FTLDataSection.cpp ftl/FTLExitArgument.cpp ftl/FTLExitArgumentForOperand.cpp + ftl/FTLExitPropertyValue.cpp ftl/FTLExitThunkGenerator.cpp + ftl/FTLExitTimeObjectMaterialization.cpp ftl/FTLExitValue.cpp ftl/FTLFail.cpp ftl/FTLForOSREntryJITCode.cpp @@ -720,12 +877,15 @@ if (ENABLE_FTL_JIT) ftl/FTLJITCode.cpp ftl/FTLJITFinalizer.cpp ftl/FTLJSCall.cpp + ftl/FTLJSCallBase.cpp + ftl/FTLJSCallVarargs.cpp ftl/FTLLink.cpp ftl/FTLLocation.cpp ftl/FTLLowerDFGToLLVM.cpp ftl/FTLOSREntry.cpp - ftl/FTLOSRExitCompiler.cpp ftl/FTLOSRExit.cpp + ftl/FTLOSRExitCompiler.cpp + ftl/FTLOperations.cpp ftl/FTLOutput.cpp ftl/FTLRecoveryOpcode.cpp ftl/FTLRegisterAtOffset.cpp @@ -769,7 +929,6 @@ set(JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES debugger heap inspector - inspector/agents interpreter jit llint @@ -779,35 +938,72 @@ set(JavaScriptCore_FORWARDING_HEADERS_DIRECTORIES yarr collector/handles + + inspector/agents + inspector/augmentable + inspector/remote + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR} ) set(JavaScriptCore_FORWARDING_HEADERS_FILES + API/APICallbackFunction.h API/APICast.h + API/JSAPIWrapperObject.h API/JSBase.h + API/JSBasePrivate.h API/JSCTestRunnerUtils.h + API/JSCallbackConstructor.h + API/JSCallbackFunction.h + API/JSCallbackObject.h + API/JSCallbackObjectFunctions.h + API/JSClassRef.h + API/JSContext.h + API/JSContextInternal.h + API/JSContextPrivate.h API/JSContextRef.h + API/JSContextRefInternal.h API/JSContextRefPrivate.h + API/JSExport.h + API/JSManagedValue.h + API/JSManagedValueInternal.h API/JSObjectRef.h API/JSObjectRefPrivate.h + API/JSProfilerPrivate.h API/JSRetainPtr.h API/JSScriptRefPrivate.h API/JSStringRef.h API/JSStringRefBSTR.h API/JSStringRefCF.h + API/JSStringRefPrivate.h + API/JSValue.h + API/JSValueInternal.h API/JSValueRef.h + API/JSVirtualMachine.h + API/JSVirtualMachineInternal.h API/JSWeakObjectMapRefInternal.h API/JSWeakObjectMapRefPrivate.h + API/JSWrapperMap.h API/JavaScript.h API/JavaScriptCore.h + API/ObjcRuntimeExtras.h API/OpaqueJSString.h API/WebKitAvailability.h assembler/LinkBuffer.h assembler/MacroAssembler.h assembler/MacroAssemblerCodeRef.h - assembler/MacroAssemblerCodeRef.h + + inspector/augmentable/AugmentableInspectorController.h + + inspector/remote/RemoteInspector.h + inspector/remote/RemoteInspectorConstants.h + inspector/remote/RemoteInspectorDebuggable.h + inspector/remote/RemoteInspectorDebuggableConnection.h + inspector/remote/RemoteInspectorXPCConnection.h + jit/GPRInfo.h + runtime/VM.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.h @@ -832,6 +1028,7 @@ ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/yarr/YarrPattern.cpp ${DERIV add_custom_command( OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/KeywordLookupGenerator.py + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/parser/Keywords.table COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/KeywordLookupGenerator.py ${CMAKE_CURRENT_SOURCE_DIR}/parser/Keywords.table > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h VERBATIM) ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/parser/Lexer.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/KeywordLookup.h) @@ -841,57 +1038,97 @@ ADD_SOURCE_DEPENDENCIES(${CMAKE_CURRENT_SOURCE_DIR}/parser/Lexer.cpp ${DERIVED_S set(JavaScriptCore_INSPECTOR_SCRIPTS_DIR "${JAVASCRIPTCORE_DIR}/inspector/scripts") +set(JavaScriptCore_INSPECTOR_PROTOCOL_SCRIPTS + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-inspector-protocol-bindings.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/cpp_generator.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/cpp_generator_templates.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_js_backend_commands.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_cpp_backend_dispatcher_header.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_cpp_backend_dispatcher_implementation.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_cpp_frontend_dispatcher_header.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_cpp_frontend_dispatcher_implementation.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_cpp_protocol_types_header.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generate_cpp_protocol_types_implementation.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generator.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/generator_templates.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/__init__.py + ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/codegen/models.py +) + set(JavaScriptCore_INSPECTOR_DOMAINS + ${JAVASCRIPTCORE_DIR}/inspector/protocol/ApplicationCache.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/CSS.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Console.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOM.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOMDebugger.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOMStorage.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Database.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Debugger.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/GenericTypes.json - ${JAVASCRIPTCORE_DIR}/inspector/protocol/InspectorDomain.json - ${JAVASCRIPTCORE_DIR}/inspector/protocol/Profiler.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Inspector.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/LayerTree.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Network.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/OverlayTypes.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Page.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Runtime.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Timeline.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Worker.json ) +if (ENABLE_INDEXED_DATABASE) + list(APPEND JavaScriptCore_INSPECTOR_DOMAINS + ${JAVASCRIPTCORE_DIR}/inspector/protocol/IndexedDB.json + ) +endif () + +if (ENABLE_WEB_REPLAY) + list(APPEND JavaScriptCore_INSPECTOR_DOMAINS + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Replay.json + ) +endif () + add_custom_command( - OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/CombinedDomains.json MAIN_DEPENDENCY ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-combined-inspector-json.py DEPENDS ${JavaScriptCore_INSPECTOR_DOMAINS} - COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-combined-inspector-json.py ${JavaScriptCore_INSPECTOR_DOMAINS} > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json + COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-combined-inspector-json.py ${JavaScriptCore_INSPECTOR_DOMAINS} > ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/CombinedDomains.json VERBATIM) # Inspector Backend Dispatchers, Frontend Dispatchers, Type Builders +file(MAKE_DIRECTORY ${DERIVED_SOURCES_WEBINSPECTORUI_DIR}/UserInterface/Protocol) +file(MAKE_DIRECTORY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector) add_custom_command( - OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.cpp - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.h - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.cpp - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.h - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.cpp - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.h - ${DERIVED_SOURCES_WEBINSPECTORUI_DIR}/UserInterface/Protocol/InspectorJSBackendCommands.js - MAIN_DEPENDENCY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json - DEPENDS ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/CodeGeneratorInspector.py - ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/CodeGeneratorInspectorStrings.py - COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/CodeGeneratorInspector.py ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJS.json --output_h_dir "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" --output_cpp_dir "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}" --output_js_dir "${DERIVED_SOURCES_WEBINSPECTORUI_DIR}/UserInterface/Protocol" --output_type JavaScript --write_always && mkdir -p ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector && cp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorBackendDispatchers.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorBackendDispatchers.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorFrontendDispatchers.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorFrontendDispatchers.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorProtocolObjects.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorProtocolObjects.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorBackendCommands.js + MAIN_DEPENDENCY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/CombinedDomains.json + DEPENDS ${JavaScriptCore_INSPECTOR_PROTOCOL_SCRIPTS} + COMMAND ${PYTHON_EXECUTABLE} ${JavaScriptCore_INSPECTOR_SCRIPTS_DIR}/generate-inspector-protocol-bindings.py --outputDir "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector" --framework JavaScriptCore ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/CombinedDomains.json VERBATIM) # JSCBuiltins -file(GLOB JSCBuiltins_js_files "${CMAKE_CURRENT_SOURCE_DIR}/builtins/*.js") add_custom_command( OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.h MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/generate-js-builtins - DEPENDS ${JSCBuiltins_js_files} - COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generate-js-builtins ${JSCBuiltins_js_files} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.cpp + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/builtins + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generate-js-builtins --input-directory ${CMAKE_CURRENT_SOURCE_DIR}/builtins --output ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.cpp VERBATIM) list(APPEND JavaScriptCore_SOURCES - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.cpp - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.cpp - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorBackendDispatchers.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorFrontendDispatchers.cpp + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorProtocolObjects.cpp ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.cpp ) list(APPEND JavaScriptCore_HEADERS - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSBackendDispatchers.h - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSFrontendDispatchers.h - ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/InspectorJSTypeBuilders.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorBackendDispatchers.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorFrontendDispatchers.h + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/inspector/InspectorProtocolObjects.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/JSCBuiltins.h ) @@ -924,34 +1161,16 @@ if (ENABLE_WEB_REPLAY) endif () if (WTF_CPU_ARM) - list(APPEND JavaScriptCore_SOURCES - assembler/ARMAssembler.cpp - assembler/ARMv7Assembler.cpp - assembler/MacroAssemblerARM.cpp - ) - if (MSVC AND ENABLE_JIT) - add_custom_command( - OUTPUT ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm - MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/create_jit_stubs - DEPENDS ${JAVASCRIPTCORE_DIR}/jit/JITStubsARM.h - DEPENDS ${JAVASCRIPTCORE_DIR}/jit/JITStubs.cpp - COMMAND ${PERL_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/create_jit_stubs --prefix=MSVC --header ${JAVASCRIPTCORE_DIR}/jit/JITStubsARM.h ${JAVASCRIPTCORE_DIR}/jit/JITStubs.cpp > ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm - VERBATIM) - - add_custom_command( - OUTPUT ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj - MAIN_DEPENDENCY ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm - COMMAND armasm -nologo ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.asm ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj - VERBATIM) - - list(APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_DIR}/GeneratedJITStubs.obj) - endif () +elseif (WTF_CPU_ARM64) +elseif (WTF_CPU_HPPA) +elseif (WTF_CPU_PPC) +elseif (WTF_CPU_PPC64) +elseif (WTF_CPU_PPC64LE) +elseif (WTF_CPU_S390) +elseif (WTF_CPU_S390X) elseif (WTF_CPU_MIPS) elseif (WTF_CPU_SH4) elseif (WTF_CPU_X86) - list(APPEND JavaScriptCore_SOURCES - assembler/MacroAssemblerX86Common.cpp - ) elseif (WTF_CPU_X86_64) if (MSVC AND ENABLE_JIT) add_custom_command( @@ -962,9 +1181,6 @@ elseif (WTF_CPU_X86_64) list(APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_DIR}/JITStubsMSVC64.obj) endif () - list(APPEND JavaScriptCore_SOURCES - assembler/MacroAssemblerX86Common.cpp - ) else () message(FATAL_ERROR "Unknown CPU") endif () @@ -979,12 +1195,11 @@ add_subdirectory(shell) WEBKIT_WRAP_SOURCELIST(${JavaScriptCore_SOURCES}) include_directories(${JavaScriptCore_INCLUDE_DIRECTORIES}) -add_definitions(-DSTATICALLY_LINKED_WITH_WTF) +include_directories(SYSTEM ${JavaScriptCore_SYSTEM_INCLUDE_DIRECTORIES}) add_library(JavaScriptCore ${JavaScriptCore_LIBRARY_TYPE} ${JavaScriptCore_HEADERS} ${JavaScriptCore_SOURCES}) target_link_libraries(JavaScriptCore ${JavaScriptCore_LIBRARIES}) set_target_properties(JavaScriptCore PROPERTIES COMPILE_DEFINITIONS "BUILDING_JavaScriptCore") set_target_properties(JavaScriptCore PROPERTIES FOLDER "JavaScriptCore") -set_target_properties(JavaScriptCore PROPERTIES LINK_INTERFACE_LIBRARIES "") if (JavaScriptCore_OUTPUT_NAME) set_target_properties(JavaScriptCore PROPERTIES OUTPUT_NAME ${JavaScriptCore_OUTPUT_NAME}) @@ -999,3 +1214,5 @@ endif () if (ENABLE_FTL_JIT) add_dependencies(JavaScriptCore llvmForJSC) endif () + + diff --git a/ChangeLog b/ChangeLog index 8abbeb7..1622ee2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,16893 +1,78 @@ -2015-07-27 Babak Shafiei <bshafiei@apple.com> +2015-07-31 Lucas Forschler <lforschler@apple.com> - Roll out r182829. + Merge r187579 -2015-07-08 Matthew Hanson <matthew_hanson@apple.com> + 2015-07-29 Filip Pizlo <fpizlo@apple.com> - Merge r183128. rdar://problem/21716620 + DFG::ArgumentsEliminationPhase should emit a PutStack for all of the GetStacks that the ByteCodeParser emitted + https://bugs.webkit.org/show_bug.cgi?id=147433 + rdar://problem/21668986 - 2015-04-22 Mark Lam <mark.lam@apple.com> - - SparseArrayEntry's write barrier owner should be the SparseArrayValueMap. - https://bugs.webkit.org/show_bug.cgi?id=144067 - - Reviewed by Michael Saboff. - - Currently, there are a few places where the JSObject that owns the - SparseArrayValueMap is designated as the owner of the SparseArrayEntry - write barrier. This is a bug and can result in the GC collecting the - SparseArrayEntry even though it is being referenced by the - SparseArrayValueMap. This patch fixes the bug. - - * runtime/JSObject.cpp: - (JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists): - (JSC::JSObject::putIndexedDescriptor): - * tests/stress/sparse-array-entry-update-144067.js: Added. - (useMemoryToTriggerGCs): - (foo): - -2015-07-08 Matthew Hanson <matthew_hanson@apple.com> - - Merge r182829. rdar://problem/21716511 - - 2015-04-14 Chris Dumez <cdumez@apple.com> - - Regression(r180020): Web Inspector crashes on pages that have a stylesheet with an invalid MIME type - https://bugs.webkit.org/show_bug.cgi?id=143745 - <rdar://problem/20243916> - - Reviewed by Joseph Pecoraro. - - Add assertion in ContentSearchUtilities::findMagicComment() to make - sure the content String is not null or we would crash in - JSC::Yarr::interpret() later. - - * inspector/ContentSearchUtilities.cpp: - (Inspector::ContentSearchUtilities::findMagicComment): - -2015-03-06 Lucas Forschler <lforschler@apple.com> - - Merge r180234 - - 2015-02-17 Filip Pizlo <fpizlo@apple.com> - - Throwing from an FTL call IC slow path may result in tag registers being clobbered on 64-bit CPUs - https://bugs.webkit.org/show_bug.cgi?id=141717 - rdar://problem/19863382 - - Reviewed by Geoffrey Garen. - - The best solution is to ensure that the engine catching an exception restores tag registers. - - Each of these new test cases reliably crashed prior to this patch and they don't crash at all now. - - * jit/JITOpcodes.cpp: - (JSC::JIT::emit_op_catch): - * llint/LowLevelInterpreter.asm: - * llint/LowLevelInterpreter64.asm: - * tests/stress/throw-from-ftl-call-ic-slow-path-cells.js: Added. - * tests/stress/throw-from-ftl-call-ic-slow-path-undefined.js: Added. - * tests/stress/throw-from-ftl-call-ic-slow-path.js: Added. - -2015-03-06 Lucas Forschler <lforschler@apple.com> - - Merge r181030 - - 2015-03-04 Filip Pizlo <fpizlo@apple.com> - - [FTL] inlined GetMyArgumentByVal with no arguments passed causes instant crash - https://bugs.webkit.org/show_bug.cgi?id=141180 - rdar://problem/19677552 + Reviewed by Mark Lam. - Reviewed by Benjamin Poulain. + Ideally, the ByteCodeParser would only emit SetArgument nodes for named arguments. But + currently that's not what it does - it emits a SetArgument for every argument that a varargs + call may pass. Each SetArgument gets turned into a GetStack. This means that if + ArgumentsEliminationPhase optimizes away PutStacks for those varargs arguments that didn't + get passed or used, we get degenerate IR where we have a GetStack of something that didn't + have a PutStack. - If we do a GetMyArgumentByVal on an inlined call frame that has no arguments, then the - bounds check already terminates execution. This means we can skip the part where we - previously did an out-of-bound array access on the inlined call frame arguments vector. + This fixes the bug by removing the code to optimize away PutStacks in + ArgumentsEliminationPhase. - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::safelyInvalidateAfterTermination): - (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): - (JSC::FTL::LowerDFGToLLVM::terminate): - (JSC::FTL::LowerDFGToLLVM::didAlreadyTerminate): - (JSC::FTL::LowerDFGToLLVM::crash): - * tests/stress/get-my-argument-by-val-inlined-no-formal-parameters.js: Added. - (foo): + * dfg/DFGArgumentsEliminationPhase.cpp: + * tests/stress/varargs-inlining-underflow.js: Added. + (baz): (bar): - -2015-03-04 Matthew Hanson <matthew_hanson@apple.com> - - Merge r180101. rdar://problem/19913017 - - 2015-02-13 Joseph Pecoraro <pecoraro@apple.com> - - JSContext Inspector: Do not stash console messages for non-debuggable JSContext - https://bugs.webkit.org/show_bug.cgi?id=141589 - - Reviewed by Timothy Hatcher. - - Consider developer extras disabled for JSContext inspection if the - RemoteInspector server is not enabled (typically a non-debuggable - process rejected by webinspectord) or if remote debugging on the - JSContext was explicitly disabled via SPI. - - When developer extras are disabled, console message will not be stashed. - - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::developerExtrasEnabled): - * inspector/JSGlobalObjectInspectorController.h: - -2015-02-26 Lucas Forschler <lforschler@apple.com> - - Merge r180452 - - 2015-02-20 Mark Lam <mark.lam@apple.com> - - [JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate super class prototype chain. - <https://webkit.org/b/141809> - - Reviewed by Geoffrey Garen. - - A ObjC class that implement the JSExport protocol will have a JS prototype - chain and constructor automatically synthesized for its JS wrapper object. - However, if there are no more instances of that ObjC class reachable by a - JS GC root scan, then its synthesized prototype chain and constructors may - be released by the GC. If a new instance of that ObjC class is subsequently - instantiated, then [JSObjCClassInfo reallocateConstructorAndOrPrototype] - should re-construct the prototype chain and constructor (if they were - previously released). However, the current implementation only - re-constructs the immediate prototype, but not every other prototype - object upstream in the prototype chain. - - To fix this, we do the following: - 1. We no longer allocate the JSObjCClassInfo's prototype and constructor - eagerly. Hence, -initWithContext:forClass: will no longer call - -allocateConstructorAndPrototypeWithSuperClassInfo:. - 2. Instead, we'll always access the prototype and constructor thru - accessor methods. The accessor methods will call - -allocateConstructorAndPrototype: if needed. - 3. -allocateConstructorAndPrototype: will fetch the needed superClassInfo - from the JSWrapperMap itself. This makes it so that we no longer - need to pass the superClassInfo all over. - 4. -allocateConstructorAndPrototype: will get the super class prototype - by invoking -prototype: on the superClassInfo, thereby allowing the - super class to allocate its prototype and constructor if needed and - fixing the issue in this bug. - - 5. Also removed the GC warning comments, and ensured that needed JS - objects are kept alive by having a local var pointing to it from the - stack (which makes a GC root). - - * API/JSWrapperMap.mm: - (-[JSObjCClassInfo initWithContext:forClass:]): - (-[JSObjCClassInfo allocateConstructorAndPrototype]): - (-[JSObjCClassInfo wrapperForObject:]): - (-[JSObjCClassInfo constructor]): - (-[JSObjCClassInfo prototype]): - (-[JSWrapperMap classInfoForClass:]): - (-[JSObjCClassInfo initWithContext:forClass:superClassInfo:]): Deleted. - (-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): Deleted. - (-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): Deleted. - * API/tests/Regress141809.h: Added. - * API/tests/Regress141809.mm: Added. - (-[TestClassB name]): - (-[TestClassC name]): - (runRegress141809): - * API/tests/testapi.mm: - * JavaScriptCore.xcodeproj/project.pbxproj: - -2015-02-25 Babak Shafiei <bshafiei@apple.com> - - Merge patch for r180247 and r180249. - - 2015-02-20 Michael Saboff <msaboff@apple.com> - - CrashTracer: DFG_CRASH beneath JSC::FTL::LowerDFGToLLVM::compileNode - https://bugs.webkit.org/show_bug.cgi?id=141730 - - Reviewed by Geoffrey Garen. - - Added a new failure handler, loweringFailed(), to LowerDFGToLLVM that reports failures - while processing DFG lowering. For debug builds, the failures are logged identical - to the way the DFG_CRASH() reports them. For release builds, the failures are reported - and that FTL compilation is terminated, but the process is allowed to continue. - Wrapped calls to loweringFailed() in a macro LOWERING_FAILED so the function and - line number are reported at the point of the inconsistancy. - - Converted instances of DFG_CRASH to LOWERING_FAILED. - - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::compileInThreadImpl): Added lowerDFGToLLVM() failure check that - will fail the FTL compile. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM): - Added new member variable, m_loweringSucceeded, to stop compilation on the first - reported failure. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::lower): - * ftl/FTLLowerDFGToLLVM.h: - Added check for compilation failures and now report those failures via a boolean - return value. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::createPhiVariables): - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileUpsilon): - (JSC::FTL::LowerDFGToLLVM::compilePhi): - (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): - (JSC::FTL::LowerDFGToLLVM::compileValueRep): - (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): - (JSC::FTL::LowerDFGToLLVM::compilePutLocal): - (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): - (JSC::FTL::LowerDFGToLLVM::compileArithMul): - (JSC::FTL::LowerDFGToLLVM::compileArithDiv): - (JSC::FTL::LowerDFGToLLVM::compileArithMod): - (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): - (JSC::FTL::LowerDFGToLLVM::compileArithAbs): - (JSC::FTL::LowerDFGToLLVM::compileArithNegate): - (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): - (JSC::FTL::LowerDFGToLLVM::compileGetById): - (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): - (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength): - (JSC::FTL::LowerDFGToLLVM::compileGetByVal): - (JSC::FTL::LowerDFGToLLVM::compilePutByVal): - (JSC::FTL::LowerDFGToLLVM::compileArrayPush): - (JSC::FTL::LowerDFGToLLVM::compileArrayPop): - (JSC::FTL::LowerDFGToLLVM::compileNewArray): - (JSC::FTL::LowerDFGToLLVM::compileToString): - (JSC::FTL::LowerDFGToLLVM::compileMakeRope): - (JSC::FTL::LowerDFGToLLVM::compileCompareEq): - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::compileSwitch): - (JSC::FTL::LowerDFGToLLVM::compare): - (JSC::FTL::LowerDFGToLLVM::boolify): - (JSC::FTL::LowerDFGToLLVM::opposite): - (JSC::FTL::LowerDFGToLLVM::lowJSValue): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::isArrayType): - (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability): - (JSC::FTL::LowerDFGToLLVM::exitValueForNode): - (JSC::FTL::LowerDFGToLLVM::setInt52): - Changed DFG_CRASH() to LOWERING_FAILED(). Updated related control flow as appropriate. - - (JSC::FTL::LowerDFGToLLVM::loweringFailed): New error reporting member function. - -2015-02-25 Babak Shafiei <bshafiei@apple.com> - - Merge r180516. - - 2015-02-23 Matthew Mirman <mmirman@apple.com> - - r9 is volatile on ARMv7 for iOS 3 and up. - https://bugs.webkit.org/show_bug.cgi?id=141489 - rdar://problem/19432916 - - Reviewed by Michael Saboff. - - * jit/RegisterSet.cpp: - (JSC::RegisterSet::calleeSaveRegisters): removed r9 from the list of ARMv7 callee save registers. - * tests/stress/regress-141489.js: Added. (foo): -2015-02-20 Lucas Forschler <lforschler@apple.com> - - Merge r180237 - - 2015-02-17 Filip Pizlo <fpizlo@apple.com> - - StackLayoutPhase should use CodeBlock::usesArguments rather than FunctionExecutable::usesArguments - https://bugs.webkit.org/show_bug.cgi?id=141721 - rdar://problem/17198633 - - Reviewed by Michael Saboff. - - I've seen cases where the two are out of sync. We know we can trust the CodeBlock::usesArguments because - we use it everywhere else. - - No test because I could never reproduce the crash. - - * dfg/DFGGraph.h: - (JSC::DFG::Graph::usesArguments): - * dfg/DFGStackLayoutPhase.cpp: - (JSC::DFG::StackLayoutPhase::run): - -2015-02-20 Babak Shafiei <bshafiei@apple.com> - - Merge r178224. - - 2015-01-09 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Uncaught Exception in ProbeManager deleting breakpoint - https://bugs.webkit.org/show_bug.cgi?id=140279 - rdar://problem/19422299 - - Reviewed by Oliver Hunt. - - * runtime/MapData.cpp: - (JSC::MapData::replaceAndPackBackingStore): - The cell table also needs to have its values fixed. - -2015-02-20 Babak Shafiei <bshafiei@apple.com> - - Merge patch for rdar://problem/19828630. - - 2015-02-13 Filip Pizlo <fpizlo@apple.com> - - Effectful calls to length should only happen once on the varargs path. - rdar://problem/19828518 - - Reviewed by Michael Saboff. - - * interpreter/Interpreter.cpp: - (JSC::sizeFrameForVarargs): - (JSC::loadVarargs): - * runtime/VM.cpp: - (JSC::VM::VM): - * runtime/VM.h: - -2015-02-10 Babak Shafiei <bshafiei@apple.com> - - Merge r179576, r179648. - - 2015-02-04 Mark Lam <mark.lam@apple.com> - - r179576 introduce a deadlock potential during GC thread suspension. - <https://webkit.org/b/141268> - - Reviewed by Michael Saboff. - - http://trac.webkit.org/r179576 introduced a potential for deadlocking. - In the GC thread suspension loop, we currently delete - MachineThreads::Thread that we detect to be invalid. This is unsafe - because we may have already suspended some threads, and one of those - suspended threads may still be holding the C heap lock which we need - for deleting the invalid thread. - - The fix is to put the invalid threads in a separate toBeDeleted list, - and delete them only after GC has resumed all threads. - - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::removeCurrentThread): - - Undo refactoring removeThreadWithLockAlreadyAcquired() out of - removeCurrentThread() since it is no longer needed. - - (JSC::MachineThreads::tryCopyOtherThreadStacks): - - Put invalid Threads on a threadsToBeDeleted list, and delete those - Threads only after all threads have been resumed. - - (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): Deleted. - * heap/MachineStackMarker.h: - - 2015-02-03 Mark Lam <mark.lam@apple.com> - - Workaround a thread library bug where thread destructors may not get called. - <https://webkit.org/b/141209> - - Reviewed by Michael Saboff. - - There's a bug where thread destructors may not get called. As far as - we know, this only manifests on darwin ports. We will work around this - by checking at GC time if the platform thread is still valid. If not, - we'll purge it from the VM's registeredThreads list before proceeding - with thread scanning activity. - - Note: it is important that we do this invalid thread detection during - suspension, because the validity (and liveness) of the other thread is - only guaranteed while it is suspended. - - * API/tests/testapi.mm: - (threadMain): - - Added a test to enter the VM from another thread before we GC on - the main thread. - - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): - (JSC::MachineThreads::removeCurrentThread): - - refactored removeThreadWithLockAlreadyAcquired() out from - removeCurrentThread() so that we can also call it for purging invalid - threads. - (JSC::suspendThread): - - Added a return status to tell if the suspension succeeded or not. - (JSC::MachineThreads::tryCopyOtherThreadStacks): - - Check if the suspension failed, and purge the thread if we can't - suspend it. Failure to suspend implies that the thread has - terminated without calling its destructor. - * heap/MachineStackMarker.h: - -2015-02-10 Babak Shafiei <bshafiei@apple.com> - - Merge r179187. - - 2015-01-27 Csaba Osztrogonác <ossy@webkit.org> - - [ARM] Typo fix after r176083 - https://bugs.webkit.org/show_bug.cgi?id=140937 - - Reviewed by Anders Carlsson. - - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::ldrh): - -2015-02-10 Babak Shafiei <bshafiei@apple.com> - - Merge r176083. - - 2014-11-13 Benjamin Poulain <benjamin@webkit.org> - - ARMv7(s) Assembler: LDRH with immediate offset is loading from the wrong offset - https://bugs.webkit.org/show_bug.cgi?id=136914 - - Reviewed by Michael Saboff. - - TLDR: the immediate offset of half-word load was divided by 2. - - Story time: So I started getting those weird reports of :nth-child() behaving bizarrely - on ARMv7 and ARMv7s. To make things worse, the behavior changes depending on style updates. - - I started looking the disassembly on the tests cases... - - The first thing I noticed was that the computation of An+B looked wrong. For example, - in the case of n+6, the instruction should have been: - subs r1, r1, #6 - but was - subs r1, r1, #2 - - After spending a lot of time trying to find the error in the assembler, I discovered - the problem was not real, but just a bug in the disassembler. - This is the first fix: ARMv7DOpcodeAddSubtractImmediate3's immediate3() was truncating - the value to 2 bits instead of 3 bits. - - The disassembler being fixed, I still have no lead on the weird bug. Some disassembly later, - I realize the LDRH instruction is not decoded at all. The reason is that both LDRH and STRH - were under the umbrella ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord but the pattern - only matched SRTH. - - I fix that next, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord is split into - ARMv7DOpcodeStoreRegisterImmediateHalfWord and ARMv7DOpcodeLoadRegisterImmediateHalfWord, - each with their own pattern and their instruction group. - - Now that I can see the LDRHs correctly, there is something fishy about them, their offset - is way too small for the data I load. - - This time, looking at the binary, the generated code is indeed incorrect. It turns out that - the ARMv7 assembler shifted the offset of half-word load as if they were byte load: divided by 4. - As a result, all the load of half-words with more than zero offset were loading - values with a smaller offset than what they should have. - - That being fixed, I dump the assembly: still wrong. I am ready to throw my keyboard through - my screen at that point. - - Looking at the disassembler, there is yet again a bug. The computation of the scale() adjustment - of the offset was incorrect for anything but word loads. - I replaced it by a switch-case to make it explicit. - - STRH is likely incorrect too. I'll fix that in a follow up, I want to survey all the 16 bits cases - that are not directly used by the CSS JIT. - - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::ldrh): - Fix the immediate scaling. Add an assertion to make sure the alignment of the input is correct. - - * disassembler/ARMv7/ARMv7DOpcode.cpp: - (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): - Fix the scaling code. Just hardcode instruction-to-scale table. - - * disassembler/ARMv7/ARMv7DOpcode.h: - (JSC::ARMv7Disassembler::ARMv7DOpcodeAddSubtractImmediate3::immediate3): - The mask for a 3 bits immediate is not 3 :) - - (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): Deleted. - -2015-02-05 Lucas Forschler <lforschler@apple.com> +2015-07-24 Matthew Hanson <matthew_hanson@apple.com> - Merge r178953 + Merge r187139. rdar://problem/21847618 - 2015-01-21 Joseph Pecoraro <pecoraro@apple.com> + 2015-07-21 Filip Pizlo <fpizlo@apple.com> - Web Inspector: ASSERT expanding objects in console PrimitiveBindingTraits<T>::assertValueHasExpectedType - https://bugs.webkit.org/show_bug.cgi?id=140746 + Unreviewed, fix a lot of tests. Need to initialize WTF threading sooner. - Reviewed by Timothy Hatcher. - - * inspector/InjectedScriptSource.js: - Do not add impure properties to the descriptor object that will - eventually be sent to the frontend. - -2015-02-05 Lucas Forschler <lforschler@apple.com> - - Merge r178768 - - 2015-01-20 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Expanding event objects in console shows undefined for most values, it should have real values - https://bugs.webkit.org/show_bug.cgi?id=137306 - - Reviewed by Timothy Hatcher. - - Provide another optional parameter to getProperties, to gather a list - of all own and getter properties. - - * inspector/InjectedScript.cpp: - (Inspector::InjectedScript::getProperties): - * inspector/InjectedScript.h: - * inspector/InjectedScriptSource.js: - * inspector/agents/InspectorRuntimeAgent.cpp: - (Inspector::InspectorRuntimeAgent::getProperties): - * inspector/agents/InspectorRuntimeAgent.h: - * inspector/protocol/Runtime.json: - -2015-02-04 Lucas Forschler <lforschler@apple.com> - - Merge r179329 - - 2015-01-13 Geoffrey Garen <ggaren@apple.com> - - Out of bounds access in BytecodeGenerator::emitGetById under DotAccessorNode::emitBytecode - https://bugs.webkit.org/show_bug.cgi?id=140397 - - Reviewed by Geoffrey Garen. - - Patch by Alexey Proskuryakov. - - Reviewed, performance tested, and ChangeLogged by Geoffrey Garen. - - No performance change. - - No test, since this is a small past-the-end read, which is very - difficult to turn into a reproducible failing test -- and existing tests - crash reliably using ASan. - - * bytecompiler/NodesCodegen.cpp: - (JSC::BracketAccessorNode::emitBytecode): - (JSC::DotAccessorNode::emitBytecode): - (JSC::FunctionCallBracketNode::emitBytecode): - (JSC::PostfixNode::emitResolve): - (JSC::DeleteBracketNode::emitBytecode): - (JSC::DeleteDotNode::emitBytecode): - (JSC::PrefixNode::emitResolve): - (JSC::UnaryOpNode::emitBytecode): - (JSC::BitwiseNotNode::emitBytecode): - (JSC::BinaryOpNode::emitBytecode): - (JSC::EqualNode::emitBytecode): - (JSC::StrictEqualNode::emitBytecode): - (JSC::ThrowableBinaryOpNode::emitBytecode): - (JSC::AssignDotNode::emitBytecode): - (JSC::AssignBracketNode::emitBytecode): Use RefPtr in more places. Any - register used across a call to a function that might allocate a new - temporary register must be held in a RefPtr. - -2015-02-04 Lucas Forschler <lforschler@apple.com> - - Merge r178311 - - 2015-01-12 Geoffrey Garen <ggaren@apple.com> - - Out of bounds read in IdentifierArena::makeIdentifier - https://bugs.webkit.org/show_bug.cgi?id=140376 - - Patch by Alexey Proskuryakov. - - Reviewed and ChangeLogged by Geoffrey Garen. - - No test, since this is a small past-the-end read, which is very - difficult to turn into a reproducible failing test -- and existing tests - crash reliably using ASan. - - * parser/ParserArena.h: - (JSC::IdentifierArena::makeIdentifier): - (JSC::IdentifierArena::makeIdentifierLCharFromUChar): Check for a - zero-length string input, like we do in the literal parser, since it is - not valid to dereference characters in a zero-length string. - - A zero-length string is allowed in JavaScript -- for example, "". - -2015-01-28 Lucas Forschler <lforschler@apple.com> - - Merge r178364 - - 2015-01-12 Michael Saboff <msaboff@apple.com> - - Local JSArray* "keys" in objectConstructorKeys() is not marked during garbage collection - https://bugs.webkit.org/show_bug.cgi?id=140348 - - Reviewed by Mark Lam. - - We used to read registers in MachineThreads::gatherFromCurrentThread(), but that is too late - because those registers may have been spilled on the stack and replaced with other values by - the time we call down to gatherFromCurrentThread(). - - Now we get the register contents at the same place that we demarcate the current top of - stack using the address of a local variable, in Heap::markRoots(). The register contents - buffer is passed along with the demarcation pointer. These need to be done at this level - in the call tree and no lower, as markRoots() calls various functions that visit object - pointers that may be latter proven dead. Any of those pointers that are left on the - stack or in registers could be incorrectly marked as live if we scan the stack contents - from a called function or one of its callees. The stack demarcation pointer and register - saving need to be done in the same function so that we have a consistent stack, active - and spilled registers. - - Because we don't want to make unnecessary calls to get the register contents, we use - a macro to allocated, and possibly align, the register structure and get the actual - register contents. - - - * heap/Heap.cpp: - (JSC::Heap::markRoots): - (JSC::Heap::gatherStackRoots): - * heap/Heap.h: - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::gatherFromCurrentThread): - (JSC::MachineThreads::gatherConservativeRoots): - * heap/MachineStackMarker.h: - -2015-01-27 Lucas Forschler <lforschler@apple.com> - - Merge r177455 - - 2014-12-17 Chris Dumez <cdumez@apple.com> - - [iOS] Make it possible to toggle FeatureCounter support at runtime - https://bugs.webkit.org/show_bug.cgi?id=139688 - <rdar://problem/19266254> - - Reviewed by Andreas Kling. - - Stop linking against AppSupport framework as the functionality is no - longer in WTF (it was moved to WebCore). - - * Configurations/JavaScriptCore.xcconfig: - -2015-01-26 Lucas Forschler <lforschler@apple.com> - - Merge r177328 - - 2014-12-15 Chris Dumez <cdumez@apple.com> - - [iOS] Add feature counting support - https://bugs.webkit.org/show_bug.cgi?id=139652 - <rdar://problem/19255690> - - Reviewed by Gavin Barraclough. - - Link against AppSupport framework on iOS as we need it to implement - the new FeatureCounter API in WTF. - - * Configurations/JavaScriptCore.xcconfig: - -2015-01-21 Babak Shafiei <bshafiei@apple.com> - - Merge r176972. - - 2014-12-08 Mark Lam <mark.lam@apple.com> - - CFA wrongly assumes that a speculation for SlowPutArrayStorageShape disallows ArrayStorageShape arrays. - <https://webkit.org/b/139327> - - Reviewed by Michael Saboff. - - The code generator and runtime slow paths expects otherwise. This patch fixes - CFA to match the code generator's expectation. - - * dfg/DFGArrayMode.h: - (JSC::DFG::ArrayMode::arrayModesThatPassFiltering): - (JSC::DFG::ArrayMode::arrayModesWithIndexingShapes): - -2015-01-20 Babak Shafiei <bshafiei@apple.com> - - Merge r171691. - - 2014-07-28 Mark Hahnenberg <mhahnenberg@apple.com> - - REGRESSION: JSObjectSetPrototype() does not work on result of JSGetGlobalObject() - https://bugs.webkit.org/show_bug.cgi?id=135322 - - Reviewed by Oliver Hunt. - - The prototype chain of the JSProxy object should match that of the JSGlobalObject. - - This is a separate but related issue with JSObjectSetPrototype which doesn't correctly - account for JSProxies. I also audited the rest of the C API to check that we correctly - handle JSProxies in all other situations where we expect a JSCallbackObject of some sort - and found some SPI calls (JSObject*PrivateProperty) that didn't behave correctly when - passed a JSProxy. - - I also added some new tests for these cases. - - * API/JSObjectRef.cpp: - (JSObjectSetPrototype): - (JSObjectGetPrivateProperty): - (JSObjectSetPrivateProperty): - (JSObjectDeletePrivateProperty): - * API/JSWeakObjectMapRefPrivate.cpp: - * API/tests/CustomGlobalObjectClassTest.c: - (globalObjectSetPrototypeTest): - (globalObjectPrivatePropertyTest): - * API/tests/CustomGlobalObjectClassTest.h: - * API/tests/testapi.c: + * jsc.cpp: (main): -2015-01-11 Mark Lam <mark.lam@apple.com> - - Update WebKit branch to build with newer LLVM. - <https://webkit.org/b/140341> - - Reviewed by Filip Pizlo. - - * Configurations/LLVMForJSC.xcconfig: - - Add the ability to pick up LLVM_LIBS_iphoneos from AspenLLVM.xcconfig. - * llvm/LLVMAPIFunctions.h: - - Removed some erroneous and unused APIs. - * llvm/library/LLVMExports.cpp: - (initializeAndGetJSCLLVMAPI): - - Removed an unneeded option that is also not supported by the new LLVM. - -2014-12-10 Babak Shafiei <bshafiei@apple.com> - - Merge r176803. - - 2014-12-04 Oliver Hunt <oliver@apple.com> - - Serialization of MapData object provides unsafe access to internal types - https://bugs.webkit.org/show_bug.cgi?id=138653 - - Reviewed by Geoffrey Garen. - - Converting these ASSERTs into RELEASE_ASSERTs, as it is now obvious - that despite trying hard to be safe in all cases it's simply to easy - to use an iterator in an unsafe state. - - * runtime/MapData.h: - (JSC::MapData::const_iterator::key): - (JSC::MapData::const_iterator::value): - -2014-09-15 Babak Shafiei <bshafiei@apple.com> - - <rdar://problem/18327341> Disable Web Timing on this branch. - - Reviewed originally by Sam Weinig. - - Disable: - - WEB_TIMING - - * Configurations/FeatureDefines.xcconfig: - -2014-08-03 Babak Shafiei <bshafiei@apple.com> - - Merge patch for <rdar://problem/17887398>. - - 2014-07-30 Filip Pizlo <fpizlo@apple.com> - - NewFunctionExpression and NewFunctionNoCheck should setHaveStructures(true) - https://bugs.webkit.org/show_bug.cgi?id=135430 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * tests/stress/new-function-expression-has-structures.js: Added. - (foo.f): - (foo.f.prototype.f): - (foo): - -2014-08-03 Babak Shafiei <bshafiei@apple.com> - - Merge r171949. - - 2014-08-01 Csaba Osztrogonác <ossy@webkit.org> - - URTBF after r171946 to fix non-Apple builds. - - * bytecode/InlineCallFrameSet.cpp: +2015-07-23 Lucas Forschler <lforschler@apple.com> -2014-08-03 Babak Shafiei <bshafiei@apple.com> + Merge r187125 - Merge r171946. + 2015-07-21 Filip Pizlo <fpizlo@apple.com> - 2014-08-01 Mark Hahnenberg <mhahnenberg@apple.com> - - CodeBlock fails to visit the Executables of its InlineCallFrames - https://bugs.webkit.org/show_bug.cgi?id=135471 + Fixed VM pool allocation should have a reserve for allocations that cannot fail + https://bugs.webkit.org/show_bug.cgi?id=147154 + rdar://problem/21847618 Reviewed by Geoffrey Garen. - CodeBlock needs to visit its InlineCallFrames' owner Executables. If it doesn't, they - can be prematurely collected and cause crashes. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::stronglyVisitStrongReferences): - * bytecode/CodeOrigin.h: - (JSC::InlineCallFrame::visitAggregate): - * bytecode/InlineCallFrameSet.cpp: - (JSC::InlineCallFrameSet::visitAggregate): - * bytecode/InlineCallFrameSet.h: - -2014-07-29 Matthew Hanson <matthew_hanson@apple.com> - - Merge r171689. <rdar://problem/17844890> - - 2014-07-28 Filip Pizlo <fpizlo@apple.com> - - Make sure that we don't use non-speculative BooleanToNumber for a speculative Branch - https://bugs.webkit.org/show_bug.cgi?id=135350 - <rdar://problem/17509889> - - Reviewed by Mark Hahnenberg and Oliver Hunt. - - If we have an exiting node that uses a conversion node, then that exiting node - needs to have a Phantom after it for the the original node. But we can't do that - for Branch because https://bugs.webkit.org/show_bug.cgi?id=126778. - - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::clearPhantomsAtEnd): - * tests/stress/branch-check-int32-on-boolean-to-number-untyped.js: Added. - (foo): - (test): - * tests/stress/branch-check-number-on-boolean-to-number-untyped.js: Added. - (foo): - (test): - -2014-07-29 Matthew Hanson <matthew_hanson@apple.com> - - Merge r171688. <rdar://problem/17364180> - - 2014-07-28 Joseph Pecoraro <pecoraro@apple.com> - - JSContext Inspector: crash when using step-into - https://bugs.webkit.org/show_bug.cgi?id=135345 - - Reviewed by Timothy Hatcher. - - * inspector/agents/InspectorDebuggerAgent.cpp: - (Inspector::InspectorDebuggerAgent::stepInto): - Null check m_listener since it may not be set. - -2014-07-25 Lucas Forschler <lforschler@apple.com> - - Merge r171578 - - 2014-07-24 Brent Fulgham <bfulgham@apple.com> - - [Win] Correct build order in JavaScriptCore.submit.sln - https://bugs.webkit.org/show_bug.cgi?id=135282 - <rdar://problem/17805592> - - Unreviewed build fix. - - * JavaScriptCore.vcxproj/JavaScriptCore.submit.sln: Correct build order - such that LLIntDesiredOffset is built prior to the rest of JSC. - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171564 - - 2014-07-24 Mark Lam <mark.lam@apple.com> - - JSWrapperMap's jsWrapperForObject() needs to keep weak prototype and constructors from being GCed. - <https://webkit.org/b/135258> - - Reviewed by Mark Hahnenberg. - - Where needed, we cache the prototype object pointer in a stack local var. - This allows it to be scanned by the GC, and hence be kept alive until - we use it. The constructor object will in turn be kept alive by the - prototype object. - - Also added some comments to warn against future code additions that could - regress this issue. - - * API/JSWrapperMap.mm: - (-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): - (-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): - (-[JSObjCClassInfo wrapperForObject:]): - (-[JSObjCClassInfo constructor]): - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171558 - - 2014-07-24 Joseph Pecoraro <pecoraro@apple.com> - - JSLock release should only modify the AtomicStringTable if it modified in acquire - https://bugs.webkit.org/show_bug.cgi?id=135143 - - Reviewed by Darin Adler. - - * runtime/JSLock.cpp: - (JSC::JSLock::JSLock): - Initialize the member variable to nullptr. - - (JSC::JSLock::willDestroyVM): - Update style to use nullptr instead of 0. - - (JSC::JSLock::willReleaseLock): - We should only reset the thread data's atomic string table if - didAcquireLock changed it. m_entryAtomicStringTable will have - been set by didAcquireLock if it changed, or nullptr if it didn't. - This way we are sure we are balanced, regardless of m_vm changes. - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171543 - - 2014-07-24 Mark Hahnenberg <mhahnenberg@apple.com> - - Creating a JSGlobalObject with a custom JSClassRef results in a JSProxy with the wrong prototype - https://bugs.webkit.org/show_bug.cgi?id=135250 - - Reviewed by Geoffrey Garen. - - JSGlobalObject::resetPrototype (which is called from JSGlobalContextCreateInGroup) doesn't change its - JSProxy's prototype as well. This results in a JSProxy where no properties in the original prototype - chain (as created from the JSClassRef hierarchy) are accessible. Changing resetPrototype to also change - the JSProxy's prototype fixes the issue. - - * API/JSValueRef.cpp: - (JSValueIsObjectOfClass): Also fixed a bug where a JSProxy for a JSGlobalObject with a custom JSClassRef - would claim it wasn't of the specified class, even if the target was of the specified class. - * API/tests/CustomGlobalObjectClassTest.c: Added. - (jsDoSomething): - (customGlobalObjectClassTest): - * API/tests/CustomGlobalObjectClassTest.h: Added. - * API/tests/testapi.c: - (assertTrue): + This adds the notion of a JIT pool reserve fraction. Some fraction, currently 1/4, of + the JIT pool is reserved for allocations that cannot fail. It makes sense to make this + a fraction rather than a constant because each allocation that can fail may cause some + number of allocations that cannot fail (for example, the OSR exit thunks that we + compile when we exit from some CodeBlock cannot fail). + + I've tested this by adding a test mode where we artificially limit the JIT pool size. + Prior to the fix, we had >20 failures. Now we have none. + + * heap/GCLogging.cpp: + (WTF::printInternal): I needed a dump method on Options members when debugging this. + * heap/GCLogging.h: + * jit/ExecutableAllocator.h: Raise the ARM64 limit to 32MB because 16MB is cutting it too close. + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): Add the ability to artificially limit JIT pool size for testing. + (JSC::ExecutableAllocator::memoryPressureMultiplier): Implement the reserve when computing memory pressure for JIT tier-up heuristics. + (JSC::ExecutableAllocator::allocate): Implement the reserve when allocating can-fail things. + * jsc.cpp: Rewire some options parsing so that CommandLine happens before we create the JIT pool. (main): - * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: - * JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::resetPrototype): - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171395 - - 2014-07-22 Brent Fulgham <bfulgham@apple.com> - - Build fix for non-clang compile. - - * jsc.cpp: - (WTF::RuntimeArray::put): Remove incorrect return statement - I added. - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171393 - - 2014-07-22 Brent Fulgham <bfulgham@apple.com> - - Build fix for non-clang compile. - - * jsc.cpp: - (WTF::RuntimeArray::deleteProperty): Need (fake) return - value when NO_RETURN_DUE_TO_CRASH is not defined. - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171390 - - 2014-07-22 Mark Lam <mark.lam@apple.com> - - Array.concat() should work on runtime arrays too. - <https://webkit.org/b/135179> - - Reviewed by Geoffrey Garen. - - * jsc.cpp: - (WTF::RuntimeArray::create): - (WTF::RuntimeArray::~RuntimeArray): - (WTF::RuntimeArray::destroy): - (WTF::RuntimeArray::getOwnPropertySlot): - (WTF::RuntimeArray::getOwnPropertySlotByIndex): - (WTF::RuntimeArray::put): - (WTF::RuntimeArray::deleteProperty): - (WTF::RuntimeArray::getLength): - (WTF::RuntimeArray::createPrototype): - (WTF::RuntimeArray::createStructure): - (WTF::RuntimeArray::finishCreation): - (WTF::RuntimeArray::RuntimeArray): - (WTF::RuntimeArray::lengthGetter): - (GlobalObject::finishCreation): - (functionCreateRuntimeArray): - - Added support to create a runtime array for testing purpose. - * runtime/ArrayPrototype.cpp: - (JSC::getLength): - - Added fast case for when the array object is a JSArray. - (JSC::arrayProtoFuncJoin): - - Added a needed but missing exception check. - (JSC::arrayProtoFuncConcat): - - Use getLength() to compute the array length instead of assuming that - the array is a JSArray instance. - * tests/stress/regexp-matches-array.js: Added. - (testArrayConcat): - * tests/stress/runtime-array.js: Added. - (testArrayConcat): - -2014-07-24 Lucas Forschler <lforschler@apple.com> - - Merge r171328 - - 2014-07-21 Mark Lam <mark.lam@apple.com> - - Refactor ArrayPrototype to use getLength() and putLength() utility functions. - https://bugs.webkit.org/show_bug.cgi?id=135139. - - Reviewed by Oliver Hunt. - - - Specialize putProperty() to putLength() because it is only used for setting - the length property. - - Added a getLength() utility function to get the value of the length property. - - Use these getLength() and putLength() functions instead of the existing code - to get and put the length property. Less code to read, easier to understand. - - * runtime/ArrayPrototype.cpp: - (JSC::getLength): - (JSC::putLength): - (JSC::arrayProtoFuncToString): - (JSC::arrayProtoFuncToLocaleString): - (JSC::arrayProtoFuncJoin): - (JSC::arrayProtoFuncPop): - (JSC::arrayProtoFuncPush): - (JSC::arrayProtoFuncReverse): - (JSC::arrayProtoFuncShift): - (JSC::arrayProtoFuncSlice): - (JSC::arrayProtoFuncSort): - (JSC::arrayProtoFuncSplice): - (JSC::arrayProtoFuncUnShift): - (JSC::arrayProtoFuncReduce): - (JSC::arrayProtoFuncReduceRight): - (JSC::arrayProtoFuncIndexOf): - (JSC::arrayProtoFuncLastIndexOf): - (JSC::putProperty): Deleted. - -2014-07-23 Matthew Hanson <matthew_hanson@apple.com> - - Merge r171474 (rollout r171367 from trunk) - -2014-07-23 Lucas Forschler <lforschler@apple.com> - - Merge r171367 - - 2014-07-22 Joseph Pecoraro <pecoraro@apple.com> - - JSLock release should only modify the AtomicStringTable if it modified in acquire - https://bugs.webkit.org/show_bug.cgi?id=135143 - - Reviewed by Pratik Solanki. - - * runtime/JSLock.cpp: - (JSC::JSLock::willDestroyVM): - (JSC::JSLock::willReleaseLock): - Only set the AtomicStringTable when there was a VM, to balance JSLock::didAcquireLock. - -2014-07-23 Lucas Forschler <lforschler@apple.com> - - Merge r171355 - - 2014-07-21 Sam Weinig <sam@webkit.org> - - [Cocoa] WKScriptMessageHandlers don't seem to function properly after navigating - https://bugs.webkit.org/show_bug.cgi?id=135148 - - Reviewed by Geoffrey Garen. - - * runtime/CommonIdentifiers.h: - Add a common identifier for the string "webkit". - -2014-07-23 Lucas Forschler <lforschler@apple.com> - - Merge r171354 - - 2014-07-22 Filip Pizlo <fpizlo@apple.com> - - ASSERTION FAILED: info.spillFormat() & DataFormatJS in JSC::DFG::SpeculativeJIT::fillSpeculateCell - https://bugs.webkit.org/show_bug.cgi?id=135155 - <rdar://problem/17763909> - - Reviewed by Oliver Hunt. - - The DFG fillSpeculate code paths all need to be mindful of the fact that they may be stumbling upon a - contradiction, and that this is OK. In this case, we were speculating cell on an int. - - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::fillSpeculateCell): - * tests/stress/regress-135155.js: Added. - (run.t.length): - (run): - -2014-07-22 Dana Burkart <dburkart@apple.com> - - Merge r171228. - - 2014-07-18 Filip Pizlo <fpizlo@apple.com> - - Fix cloop build. - - * jsc.cpp: - (jscmain): - -2014-07-22 Dana Burkart <dburkart@apple.com> - - Merge r171213. - - 2014-07-15 Filip Pizlo <fpizlo@apple.com> - - Need ability to fuzz exception throwing - https://bugs.webkit.org/show_bug.cgi?id=134945 - <rdar://problem/17722027> - - Reviewed by Sam Weinig. - - Adds the ability to instrument exception checks, and to force some random - exception check to artificially throw an exception. Also adds new tests that - are suitable for testing this. Note that this is closely tied to the Tools - directory changes that are also part of this changeset. - - This also fixes an activation tear-off bug that arises if we ever throw an - exception from operationOptimize, or if due to some other bug it's only due - to the operationOptimize exception check that we realize that there is an - exception to be thrown. - - * dfg/DFGJITCompiler.h: - (JSC::DFG::JITCompiler::fastExceptionCheck): - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::callCheck): - * interpreter/Interpreter.cpp: - (JSC::unwindCallFrame): - * jit/AssemblyHelpers.cpp: - (JSC::AssemblyHelpers::callExceptionFuzz): - (JSC::AssemblyHelpers::emitExceptionCheck): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::emitExceptionCheck): Deleted. - * jit/JIT.cpp: - (JSC::JIT::privateCompileMainPass): - * jit/JITOpcodes.cpp: - (JSC::JIT::emit_op_enter): - * jit/JITOperations.cpp: - (JSC::numberOfExceptionFuzzChecks): - * jit/JITOperations.h: - * jsc.cpp: + (CommandLine::parseArguments): (jscmain): + * runtime/Options.cpp: + (JSC::OptionRange::dump): I needed a dump method on Options members when debugging this. + (JSC::Options::initialize): This can now be called more than once. * runtime/Options.h: - * runtime/TestRunnerUtils.h: - * tests/exceptionFuzz.yaml: Added. - * tests/exceptionFuzz: Added. - * tests/exceptionFuzz/3d-cube.js: Added. - * tests/exceptionFuzz/date-format-xparb.js: Added. - * tests/exceptionFuzz/earley-boyer.js: Added. - -2014-07-22 Dana Burkart <dburkart@apple.com> - - Merge r171204. - - 2014-07-17 Joseph Pecoraro <pecoraro@apple.com> - - Follow-up fix to r171195 to prevent ASSERT in fast/profiler/profile-with-no-title.html - - Rubber-stamped by Alexey Proskuryakov. - - Null / empty titles should be fine. Tests pass in release builds - which allowed empty titles, and it looks like the LegacyProfiler - stopProfiling handles empty titles as expected already. - - * profiler/LegacyProfiler.cpp: - (JSC::LegacyProfiler::startProfiling): - -2014-07-22 Dana Burkart <dburkart@apple.com> - - Merge r171190. - - 2014-07-16 Filip Pizlo <fpizlo@apple.com> - - DFG Flush(SetLocal) store elimination is overzealous for captured variables in the presence of nodes that have no effects but may throw - https://bugs.webkit.org/show_bug.cgi?id=134988 - <rdar://problem/17706349> - - Reviewed by Oliver Hunt. - - Luckily, we also don't need this optimization to be super powerful: the only place - where it really matters is for getting rid of the redundancy between op_enter and - op_init_lazy_reg, and in that case, there is a small set of possible nodes between the - two things. This change updates the store eliminator to know about only that small, - obviously safe, set of nodes over which we can store-eliminate. - - This shouldn't have any performance impact in the DFG because this optimization kicks - in relatively rarely already. And once we tier up into the FTL, we get a much better - store elimination over LLVM IR, so this really shouldn't matter at all. - - The tricky part of this patch is that there is a close relative of this optimization, - for uncaptured variables that got flushed. This happens for arguments to inlined calls. - I make this work by splitting it into two different store eliminators. - - Note that in the process of crafting the tests, I realized that we were incorrectly - DCEing NewArrayWithSize. That's not cool, since that can throw an exception for - negative array sizes. If we ever did want to DCE this node, we'd need to lower the node - to a check node followed by the actual allocation. - - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::uncapturedSetLocalStoreElimination): - (JSC::DFG::CSEPhase::capturedSetLocalStoreElimination): - (JSC::DFG::CSEPhase::setLocalStoreElimination): - (JSC::DFG::CSEPhase::performNodeCSE): - (JSC::DFG::CSEPhase::SetLocalStoreEliminationResult::SetLocalStoreEliminationResult): Deleted. - * dfg/DFGNodeType.h: - * tests/stress/capture-escape-and-throw.js: Added. - (foo.f): - (foo): - * tests/stress/new-array-with-size-throw-exception-and-tear-off-arguments.js: Added. - (foo): - (bar): - -2014-07-17 Dean Jackson <dino@apple.com> - - <rdar://problem/17675068> Disable some features on this branch. - - Reviewed originally by Simon Fraser. - - Disable: - - CSS_EXCLUSIONS - - CSS_GRID_LAYOUT - - INPUT_TYPE_COLOR - - INPUT_TYPE_COLOR_POPUP - - CANVAS_PATH - - CSS_TRANSFORMS_ANIMATIONS_UNPREFIXED - - INDIE_UI - - SHARED_WORKERS - - NAVIGATOR_HWCONCURRENCY - - GAMEPAD - - PICTURE_SIZES - - CSS3_CONDITIONAL_RULES - - WILL_REVEAL_EDGE_EVENTS - - * Configurations/FeatureDefines.xcconfig: - -2014-07-15 Benjamin Poulain <benjamin@webkit.org> - - Reduce the overhead of updating the AssemblerBuffer - https://bugs.webkit.org/show_bug.cgi?id=134659 - - Reviewed by Gavin Barraclough. - - In r164548, the linker was changed to allow the LinkBuffer to survive its MacroAssembler. - That feature is useful for JSC to get offsets inside a linked buffer in order to jump directly - there. - - On ARM, we use branch compaction and we need to keep the "compaction offset" somewher to be able - to get the real address of a lable. That is done by reusing the memory of AssemblerData. - - To share the memory between LinkBuffer and the Assembler, r164548 moved the AssemblerData into - a ref-counted object. Unfortunately, the extra complexity related to the new AssemblerData was enough - to make clang give up a bunch of optimizations. - - This patch solve (some of) the problems by making AssemblerBuffer and AssemblerData super low overhead structures. - In particular, the grow() function becomes 8 Thumb instructions, which is easily inlined everywhere it is used. - - Instead of sharing ownership between the Assembler and LinkBuffer, LinkBuffer now takes full ownership of - the AssemblerData. I feel this is also safer since LinkBuffer is reusing the AssemblerData is a very - specific way that would make it unusable for the Assembler. - - -- Technical details -- - - From LinkBuffer, we don't want to ever access the Assembler after releasing its buffer (or writting anything - into it really). This was obviously already the case, but that was hard to prove from LinkBuffer::copyCompactAndLinkCode(). - To make this easier to work with, I changed all the assembler specific function to be static. This way we know - exactly what code access the Assembler instance. The code that does access the instance is then moved - at the beginning, before we modify anything. - - The function recordLinkOffsets() that was on the MacroAssembler and copied in Assembler was moved directly - to LinkBuffer. This make the modification of AssemblerData completely explicit, and that code is specific - to LinkBuffer anyway (see LinkBuffer::executableOffsetFor()). - - -- Perf impact -- - - This does not put us exactly at before r164548 due to the missing inline buffer. Still, it is very close. - On ARMv7, this reduces the time spent in Assembler by half. On the CSS JIT, this reduces the compilation - time by ~20%. - - I could not measure any difference on x86_64. - - * assembler/ARM64Assembler.h: - (JSC::ARM64Assembler::jumpSizeDelta): - (JSC::ARM64Assembler::canCompact): - (JSC::ARM64Assembler::computeJumpType): - (JSC::ARM64Assembler::link): - (JSC::ARM64Assembler::recordLinkOffsets): Deleted. - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::ifThenElseConditionBit): - (JSC::ARMv7Assembler::ifThenElse): - (JSC::ARMv7Assembler::jumpSizeDelta): - (JSC::ARMv7Assembler::canCompact): - (JSC::ARMv7Assembler::computeJumpType): - (JSC::ARMv7Assembler::link): - (JSC::ARMv7Assembler::linkJumpT1): - (JSC::ARMv7Assembler::linkJumpT3): - (JSC::ARMv7Assembler::linkConditionalJumpT4): - (JSC::ARMv7Assembler::linkConditionalBX): - (JSC::ARMv7Assembler::recordLinkOffsets): Deleted. - * assembler/AssemblerBuffer.h: - (JSC::AssemblerData::AssemblerData): - (JSC::AssemblerData::operator=): - (JSC::AssemblerData::~AssemblerData): - (JSC::AssemblerData::buffer): - (JSC::AssemblerData::capacity): - (JSC::AssemblerData::grow): - (JSC::AssemblerBuffer::AssemblerBuffer): - (JSC::AssemblerBuffer::isAvailable): - (JSC::AssemblerBuffer::data): - (JSC::AssemblerBuffer::releaseAssemblerData): - (JSC::AssemblerBuffer::putIntegral): - (JSC::AssemblerBuffer::putIntegralUnchecked): - (JSC::AssemblerBuffer::append): - (JSC::AssemblerBuffer::grow): - (JSC::AssemblerBuffer::~AssemblerBuffer): Deleted. - (JSC::AssemblerBuffer::storage): Deleted. - * assembler/LinkBuffer.cpp: - (JSC::recordLinkOffsets): - (JSC::LinkBuffer::copyCompactAndLinkCode): - * assembler/LinkBuffer.h: - (JSC::LinkBuffer::LinkBuffer): - (JSC::LinkBuffer::executableOffsetFor): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::canCompact): - (JSC::MacroAssemblerARM64::computeJumpType): - (JSC::MacroAssemblerARM64::jumpSizeDelta): - (JSC::MacroAssemblerARM64::link): - (JSC::MacroAssemblerARM64::recordLinkOffsets): Deleted. - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::canCompact): - (JSC::MacroAssemblerARMv7::computeJumpType): - (JSC::MacroAssemblerARMv7::jumpSizeDelta): - (JSC::MacroAssemblerARMv7::link): - (JSC::MacroAssemblerARMv7::recordLinkOffsets): Deleted. - -2014-07-15 Mark Hahnenberg <mhahnenberg@apple.com> - - Stores to PropertyTable use the Structure as the owner - https://bugs.webkit.org/show_bug.cgi?id=134595 - - Reviewed by Darin Adler. - - Since PropertyTable is the object that does the marking of these references, it should be the owner. - - Also removed some unused parameters to other methods that historically used the Structure as the owner. - - * runtime/JSPropertyNameIterator.h: - (JSC::StructureRareData::setEnumerationCache): - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncToString): - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::copy): - * runtime/PropertyTable.cpp: - (JSC::PropertyTable::clone): - (JSC::PropertyTable::PropertyTable): - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::materializePropertyMap): - (JSC::Structure::addPropertyTransition): - (JSC::Structure::changePrototypeTransition): - (JSC::Structure::despecifyFunctionTransition): - (JSC::Structure::attributeChangeTransition): - (JSC::Structure::toDictionaryTransition): - (JSC::Structure::preventExtensionsTransition): - (JSC::Structure::takePropertyTableOrCloneIfPinned): - (JSC::Structure::nonPropertyTransition): - (JSC::Structure::copyPropertyTable): - (JSC::Structure::copyPropertyTableForPinning): - (JSC::Structure::putSpecificValue): - * runtime/Structure.h: - (JSC::Structure::setObjectToStringValue): - (JSC::Structure::setPreviousID): - * runtime/StructureInlines.h: - (JSC::Structure::setEnumerationCache): - * runtime/StructureRareData.h: - * runtime/StructureRareDataInlines.h: - (JSC::StructureRareData::setPreviousID): - (JSC::StructureRareData::setObjectToStringValue): - -2014-07-15 Mark Hahnenberg <mhahnenberg@apple.com> - - ScriptExecutable::forEachCodeBlock can dereference null CodeBlocks - https://bugs.webkit.org/show_bug.cgi?id=134928 - - Reviewed by Andreas Kling. - - * bytecode/CodeBlock.h: - (JSC::ScriptExecutable::forEachCodeBlock): Check for null CodeBlocks before calling forEachRelatedCodeBlock. - -2014-07-15 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> - - Buildfix if LLINT_SLOW_PATH_TRACING is enabled - https://bugs.webkit.org/show_bug.cgi?id=133790 - - Reviewed by Mark Lam. - - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - -2014-07-14 Filip Pizlo <fpizlo@apple.com> - - Allow for Int52Rep to see things other than Int32, and make this testable - https://bugs.webkit.org/show_bug.cgi?id=134873 - <rdar://problem/17641915> - - Reviewed by Geoffrey Garen and Mark Hahnenberg. - - A major premise of our type inference is that prediction propagation can say whatever it - wants and we'll still have valid IR after Fixup. This previously didn't work with Int52s. - We required some kind of agreement between prediction propagation and fixup over which - data flow paths were Int52 and which weren't. - - It turns out that we basically had such an agreement, with the exception of code that was - unreachable due to ForceOSRExit. Then, fixup and prediction propagation would disagree. It - might be nice to fix that bug - but it's only in the case of Int52 that such a thing would - be a bug! Normally, we allow sloppiness in prediction propagation. - - This patch allows us to be sloppy with Int52 prediction propagation by giving Int52Rep the - ability to see inputs other than Int32. This fixes the particular ForceOSRExit bug (see - int52-force-osr-exit-path.js for the reduced test case). To make sure that the newly - empowered Int52Rep is actually correct - in case we end up using it on paths other than - ForceOSRExit - this patch introduces an internal intrinsic called fiatInt52() that forces - us to attempt Int52 conversion on the input. This patch adds a bunch of tests that stress - this intrinsic. This means that we're now stressing Int52Rep more so than ever before! - - Note that it would still be a bug for prediction propagation to ever cause us to create an - Int52Rep node for a non-Int32 input. But, this will now be a performance bug, rather than - a crash bug. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGAbstractValue.cpp: - (JSC::DFG::AbstractValue::fixTypeForRepresentation): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): - * dfg/DFGGraph.h: - (JSC::DFG::Graph::isMachineIntConstant): - * dfg/DFGNode.h: - (JSC::DFG::Node::isMachineIntConstant): - * dfg/DFGNodeType.h: - * dfg/DFGOperations.cpp: - * dfg/DFGOperations.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::SafeToExecuteEdge::operator()): - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::speculate): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::callOperation): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::convertMachineInt): - (JSC::DFG::SpeculativeJIT::speculateMachineInt): - (JSC::DFG::SpeculativeJIT::speculateDoubleRepMachineInt): - * dfg/DFGStrengthReductionPhase.cpp: - (JSC::DFG::StrengthReductionPhase::handleNode): - * dfg/DFGUseKind.cpp: - (WTF::printInternal): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - (JSC::DFG::isNumerical): - (JSC::DFG::isDouble): - * dfg/DFGValidate.cpp: - (JSC::DFG::Validate::validate): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileInt52Rep): - (JSC::FTL::LowerDFGToLLVM::doubleToInt32): - (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): - (JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52): - (JSC::FTL::LowerDFGToLLVM::doubleToStrictInt52): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateMachineInt): - (JSC::FTL::LowerDFGToLLVM::speculateDoubleRepMachineInt): - * jit/JITOperations.h: - * jsc.cpp: - (GlobalObject::finishCreation): - (functionIdentity): - * runtime/Intrinsic.h: - * runtime/JSCJSValue.h: - * runtime/JSCJSValueInlines.h: - (JSC::tryConvertToInt52): - (JSC::isInt52): - (JSC::JSValue::isMachineInt): - * tests/stress/dead-fiat-double-to-int52-then-exit-not-int52.js: Added. - (foo): - * tests/stress/dead-fiat-double-to-int52.js: Added. - (foo): - * tests/stress/dead-fiat-int32-to-int52.js: Added. - (foo): - * tests/stress/dead-fiat-value-to-int52-double-path.js: Added. - (foo): - (bar): - * tests/stress/dead-fiat-value-to-int52-then-exit-not-double.js: Added. - (foo): - (bar): - * tests/stress/dead-fiat-value-to-int52-then-exit-not-int52.js: Added. - (foo): - (bar): - * tests/stress/dead-fiat-value-to-int52.js: Added. - (foo): - (bar): - * tests/stress/fiat-double-to-int52-then-exit-not-int52.js: Added. - (foo): - * tests/stress/fiat-double-to-int52-then-fail-to-fold.js: Added. - (foo): - * tests/stress/fiat-double-to-int52-then-fold.js: Added. - (foo): - * tests/stress/fiat-double-to-int52.js: Added. - (foo): - * tests/stress/fiat-int32-to-int52.js: Added. - (foo): - * tests/stress/fiat-value-to-int52-double-path.js: Added. - (foo): - (bar): - * tests/stress/fiat-value-to-int52-then-exit-not-double.js: Added. - (foo): - (bar): - * tests/stress/fiat-value-to-int52-then-exit-not-int52.js: Added. - (foo): - (bar): - * tests/stress/fiat-value-to-int52-then-fail-to-fold.js: Added. - (foo): - * tests/stress/fiat-value-to-int52-then-fold.js: Added. - (foo): - * tests/stress/fiat-value-to-int52.js: Added. - (foo): - (bar): - * tests/stress/int52-force-osr-exit-path.js: Added. - (foo): - -2014-07-14 Mark Hahnenberg <mhahnenberg@apple.com> - - Flattening dictionaries with oversize backing stores can cause crashes - https://bugs.webkit.org/show_bug.cgi?id=134906 - - Reviewed by Filip Pizlo. - - The collector expects any pointers into CopiedSpace passed to copyLater are within 32 KB - of the CopiedBlock header. This was always the case except for when flattening a dictionary - caused the size of the Butterfly to decrease. This was equivalent to moving the base of the - Butterfly to higher addresses. If the object was reduced sufficiently in size, the base - would no longer be within the first 32 KB of the CopiedBlock and the next collection would - choke on the Butterfly pointer. - - This patch fixes this issue by detect this situation during flattening and memmove-ing - the Butterfly down to where the old base was. - - * runtime/JSObject.cpp: - (JSC::JSObject::shiftButterflyAfterFlattening): - * runtime/JSObject.h: - (JSC::JSObject::butterflyPreCapacity): - (JSC::JSObject::butterflyTotalSize): - * runtime/Structure.cpp: - (JSC::Structure::flattenDictionaryStructure): - * tests/stress/flatten-oversize-dictionary-object.js: Added. - (foo): - -2014-07-14 Benjamin Poulain <benjamin@webkit.org> - - Remove some dead code from FTLJITFinalizer - https://bugs.webkit.org/show_bug.cgi?id=134874 - - Reviewed by Geoffrey Garen. - - Not sure what that code was for...but it does not do anything :) - - * ftl/FTLJITFinalizer.cpp: - (JSC::FTL::JITFinalizer::finalizeFunction): - The pointer of the label is computed but never used. - - * ftl/FTLJITFinalizer.h: - * ftl/FTLLink.cpp: - (JSC::FTL::link): - The label is never set to anything. - -2014-07-14 Bear Travis <betravis@adobe.com> - - [Feature Queries] Enable Feature Queries on Mac - https://bugs.webkit.org/show_bug.cgi?id=134404 - - Reviewed by Antti Koivisto. - - Enable Feature Queries on Mac and resume running the - feature tests. - - * Configurations/FeatureDefines.xcconfig: Turn on - ENABLE_CSS3_CONDITIONAL_RULES. - -2014-07-11 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Debugger Pause button does not work - https://bugs.webkit.org/show_bug.cgi?id=134785 - - Reviewed by Timothy Hatcher. - - * CMakeLists.txt: - * DerivedSources.make: - Minification strips the sourceURL command. Add it back with minification. - -2014-07-11 peavo@outlook.com <peavo@outlook.com> - - [Win] Enable DFG JIT. - https://bugs.webkit.org/show_bug.cgi?id=123615 - - Reviewed by Mark Lam. - - When the return type of a JIT generated function call is larger than 64-bit (e.g. SlowPathReturnType), - the normal call() implementation cannot be used on 64-bit Windows, because the 64-bit Windows ABI is different in this case. - Also, when generating calls with double arguments, we need to make sure the arguments are put in the correct registers, - since the register allocation differs on 64-bit Windows. - - * assembler/MacroAssemblerX86_64.h: - (JSC::MacroAssemblerX86_64::callWithSlowPathReturnType): Added method to handle function calls where the return value type size is larger than 64-bit. - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): Move arguments to correct registers when there are floating point arguments. - (JSC::CCallHelpers::setupArgumentsWithExecStateForCallWithSlowPathReturnType): Added method. - * jit/JIT.h: - (JSC::JIT::appendCallWithSlowPathReturnType): Added method. - * jit/JITInlines.h: - (JSC::JIT::appendCallWithExceptionCheckAndSlowPathReturnType): Added method. - (JSC::JIT::callOperation): Call new method. - -2014-07-09 Benjamin Poulain <benjamin@webkit.org> - - Use 16bits instructions for push/pop on ARMv7 when possible - https://bugs.webkit.org/show_bug.cgi?id=134753 - - Reviewed by Geoffrey Garen. - - The patch r170839 mixed the code for push/pop pair and single push/pop. - That part was reverted in r170909. - - This patch puts the code back but specialized for single push/pop. - - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::pop): - (JSC::ARMv7Assembler::push): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::pop): - (JSC::MacroAssemblerARMv7::push): - -2014-07-09 Brent Fulgham <bfulgham@apple.com> - - [Win] Remove uses of 'bash' in build system - https://bugs.webkit.org/show_bug.cgi?id=134782 - <rdar://problem/17615533> - - Reviewed by Dean Jackson. - - Remove uses of 'bash' by replacing Windows-specific bash scripts - with Perl equivalents. - - * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make: - * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj.filters: - * JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd: - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make: - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj: - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh. - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: Removed. - * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make: - * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj: - * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.sh. - * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.sh: Removed. - * JavaScriptCore.vcxproj/build-generated-files.pl: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/build-generated-files.sh. - * JavaScriptCore.vcxproj/build-generated-files.sh: Removed. - * JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd: - * JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd: - * JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd: - -2014-07-09 Brent Fulgham <bfulgham@apple.com> - - [Win] Remove use of 'grep' in build steps - https://bugs.webkit.org/show_bug.cgi?id=134770 - <rdar://problem/17608783> - - Reviewed by Tim Horton. - - Replace uses of the grep command in Windows builds with the equivalent - Perl program. - - * JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd: - * JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd: - * JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd: - * JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd: - -2014-07-08 Benjamin Poulain <benjamin@webkit.org> - - Restore the assertion changed with 170839 - - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::pop): - (JSC::ARMv7Assembler::push): - Revert the Assembler part of 170839. The assertions do not match both encoding. - - I'll add specific version of push and pop instead. - -2014-07-08 Jon Honeycutt <jhoneycutt@apple.com> - - RemoteInspector::shared() should not call WTF::initializeMainThread() - <https://bugs.webkit.org/show_bug.cgi?id=134747> - <rdar://problem/17161482> - - Reviewed by Joseph Pecoraro. - - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::shared): - Don't call WTF::initializeMainThread(). WTF threading is initialized by - JSC::initializeThreading(). - -2014-07-08 Andreas Kling <akling@apple.com> - - VM::lastCachedString should be a Strong, not a Weak. - <https://webkit.org/b/134746> - - Using Weak<JSString> for this regressed some of our bindings perf tests - due to Weak having to allocate a new WeakImpl every time the last cached - string changed. Make it a Strong instead should make that problem go away. - - Reviewed by Geoffrey Garen. - - * runtime/JSString.cpp: - (JSC::jsStringWithCacheSlowCase): - * runtime/VM.h: - -2014-07-07 Benjamin Poulain <bpoulain@apple.com> - - Fix the build after r170876 - - * assembler/LinkBuffer.cpp: - (JSC::LinkBuffer::linkCode): - -2014-07-07 Benjamin Poulain <benjamin@webkit.org> - - LinkBuffer should not keep a reference to the MacroAssembler - https://bugs.webkit.org/show_bug.cgi?id=134668 - - Reviewed by Geoffrey Garen. - - In FTL, the LinkBuffer can outlive the MacroAssembler that was used for code generation. - When that happens, the pointer m_assembler points to released memory. That was not causing - issues because the attribute is not used after linking, but that was not particularily - future proof. - - This patch refactors LinkBuffer to avoid any lifetime risk. The MacroAssembler is now passed - as a reference, it is used for linking but no reference is ever stored with the LinkBuffer. - - While fixing the call sites to use a reference, I also discovered LinkBuffer.h was included - everywhere. I refactored some #include to avoid that. - - * assembler/LinkBuffer.cpp: - (JSC::LinkBuffer::copyCompactAndLinkCode): - (JSC::LinkBuffer::linkCode): - * assembler/LinkBuffer.h: - (JSC::LinkBuffer::LinkBuffer): - * bytecode/Watchpoint.cpp: - * dfg/DFGDisassembler.cpp: - * dfg/DFGDisassembler.h: - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::link): - (JSC::DFG::JITCompiler::linkFunction): - * dfg/DFGOSRExitCompiler.cpp: - * dfg/DFGPlan.cpp: - * dfg/DFGThunks.cpp: - (JSC::DFG::osrExitGenerationThunkGenerator): - (JSC::DFG::osrEntryThunkGenerator): - * ftl/FTLCompile.cpp: - (JSC::FTL::generateICFastPath): - (JSC::FTL::fixFunctionBasedOnStackMaps): - * ftl/FTLJSCall.cpp: - * ftl/FTLJSCall.h: - * ftl/FTLLink.cpp: - (JSC::FTL::link): - * ftl/FTLLowerDFGToLLVM.cpp: - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileStub): - * ftl/FTLThunks.cpp: - (JSC::FTL::osrExitGenerationThunkGenerator): - (JSC::FTL::slowPathCallThunkGenerator): - * jit/ArityCheckFailReturnThunks.cpp: - (JSC::ArityCheckFailReturnThunks::returnPCsFor): - * jit/JIT.cpp: - (JSC::JIT::privateCompile): - * jit/JITCall.cpp: - (JSC::JIT::privateCompileClosureCall): - * jit/JITCall32_64.cpp: - (JSC::JIT::privateCompileClosureCall): - * jit/JITDisassembler.cpp: - * jit/JITDisassembler.h: - * jit/JITOpcodes.cpp: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::stringGetByValStubGenerator): - (JSC::JIT::privateCompileGetByVal): - (JSC::JIT::privateCompilePutByVal): - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::stringGetByValStubGenerator): - * jit/RegisterPreservationWrapperGenerator.cpp: - (JSC::generateRegisterPreservationWrapper): - (JSC::registerRestorationThunkGenerator): - * jit/Repatch.cpp: - (JSC::generateByIdStub): - (JSC::tryCacheGetByID): - (JSC::emitPutReplaceStub): - (JSC::emitPutTransitionStub): - (JSC::tryRepatchIn): - (JSC::linkClosureCall): - * jit/SpecializedThunkJIT.h: - (JSC::SpecializedThunkJIT::finalize): - * jit/ThunkGenerators.cpp: - (JSC::throwExceptionFromCallSlowPathGenerator): - (JSC::linkForThunkGenerator): - (JSC::linkClosureCallForThunkGenerator): - (JSC::virtualForThunkGenerator): - (JSC::nativeForGenerator): - (JSC::arityFixup): - * llint/LLIntThunks.cpp: - (JSC::LLInt::generateThunkWithJumpTo): - * yarr/YarrJIT.cpp: - (JSC::Yarr::YarrGenerator::compile): - -2014-07-07 Andreas Kling <akling@apple.com> - - Fast path for jsStringWithCache() when asked for the same string repeatedly. - <https://webkit.org/b/134635> - - Reviewed by Darin Adler. - - Follow-up to r170818 addressing a review comment by Geoff Garen. - - * runtime/JSString.cpp: - (JSC::jsStringWithCacheSlowCase): - -2014-07-07 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> - - Add missing ENABLE(FTL_JIT) guards - https://bugs.webkit.org/show_bug.cgi?id=134680 - - Reviewed by Darin Adler. - - * ftl/FTLDWARFDebugLineInfo.cpp: - * ftl/FTLDWARFDebugLineInfo.h: - * ftl/FTLGeneratedFunction.h: - -2014-07-07 Zan Dobersek <zdobersek@igalia.com> - - Enable ARMv7 disassembler for the GTK port - https://bugs.webkit.org/show_bug.cgi?id=134676 - - Reviewed by Benjamin Poulain. - - * CMakeLists.txt: Add ARMv7DOpcode.cpp file to the build. - * disassembler/ARMv7/ARMv7DOpcode.cpp: Include the string.h header for strlen(). - -2014-07-06 Benjamin Poulain <benjamin@webkit.org> - - [ARMv7] Use 16 bits instructions for push/pop when possible - https://bugs.webkit.org/show_bug.cgi?id=134656 - - Reviewed by Andreas Kling. - - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::pop): - (JSC::ARMv7Assembler::push): - (JSC::ARMv7Assembler::ARMInstructionFormatter::oneWordOp7Imm9): - Add the 16 bits version of push and pop. - - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::pop): - (JSC::MacroAssemblerARMv7::push): - Use the new push/pop instead of a regular load/store. - - * disassembler/ARMv7/ARMv7DOpcode.cpp: - (JSC::ARMv7Disassembler::ARMv7DOpcode::appendRegisterList): - * disassembler/ARMv7/ARMv7DOpcode.h: - (JSC::ARMv7Disassembler::ARMv7DOpcodeMiscPushPop::registerMask): - Fix the disassembler for push/pop: - -The register mask was on 7 bits for some reason. - -The code printing the registers was comparing a register ID with a register - mask. - -2014-07-06 Yoav Weiss <yoav@yoav.ws> - - Turn on img@sizes compile flag - https://bugs.webkit.org/show_bug.cgi?id=134634 - - Reviewed by Benjamin Poulain. - - * Configurations/FeatureDefines.xcconfig: Moved compile flag to alphabetical order. - -2014-07-06 Daewoong Jang <daewoong.jang@navercorp.com> - - Flags value of SourceCodeKey should be unique for each case. - https://bugs.webkit.org/show_bug.cgi?id=134435 - - Reviewed by Darin Adler. - - Different combinations of CodeType and JSParserStrictness could generate same m_flags value because - the value of CodeType and the value of JSParserStrictness shares a bit inside m_flags member variable. - Shift the value of CodeType one bit farther to the left so those values don't overlap. - - * runtime/CodeCache.h: - (JSC::SourceCodeKey::SourceCodeKey): - -2014-07-04 Andreas Kling <akling@apple.com> - - Fast path for jsStringWithCache() when asked for the same string repeatedly. - <https://webkit.org/b/134635> - - Also moved the whole thing from WebCore to JavaScriptCore since it - makes more sense here, and inline the lightweight checks, leaving only - the hashmap stuff out of line. - - Reviewed by Darin Adler. - - * runtime/JSString.cpp: - (JSC::jsStringWithCacheSlowCase): - * runtime/JSString.h: - (JSC::jsStringWithCache): - * runtime/VM.h: - -2014-07-03 Daniel Bates <dabates@apple.com> - - Add WTF::move() - https://bugs.webkit.org/show_bug.cgi?id=134500 - - Rubber-stamped by Anders Carlsson. - - Substitute WTF::move() for std::move(). - - * bytecode/CodeBlock.h: - * bytecode/UnlinkedCodeBlock.cpp: - * bytecompiler/BytecodeGenerator.cpp: - * dfg/DFGGraph.cpp: - * dfg/DFGJITCompiler.cpp: - * dfg/DFGStackLayoutPhase.cpp: - * dfg/DFGWorklist.cpp: - * heap/DelayedReleaseScope.h: - * heap/HeapInlines.h: - [...] - -2014-07-03 Filip Pizlo <fpizlo@apple.com> - - SSA DCE should process blocks in forward order - https://bugs.webkit.org/show_bug.cgi?id=134611 - - Reviewed by Andreas Kling. - - * dfg/DFGDCEPhase.cpp: - (JSC::DFG::DCEPhase::run): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode): - * tests/stress/dead-value-with-mov-hint-in-another-block.js: Added. - (foo): - -2014-07-03 Filip Pizlo <fpizlo@apple.com> - - JSActivation::symbolTablePut() should invalidate variable watchpoints - https://bugs.webkit.org/show_bug.cgi?id=134602 - - Reviewed by Oliver Hunt. - - Usually stores to captured variables cause us to invalidate the variable watchpoint because CodeBlock does so - during linking - we essentially assume that if it's at all possible for an inner function to store to a - variable we declare then this variable cannot be a constant. But this misses the dynamic store case, i.e. - JSActivation::symbolTablePut(). Part of the problem here is that JSActivation duplicates - JSSymbolTableObject's symbolTablePut() logic, which did have the invalidation. This patch keeps that code - duplicated, but fixes JSActivation::symbolTablePut() to do the right thing. - - * runtime/JSActivation.cpp: - (JSC::JSActivation::symbolTablePut): - * runtime/JSSymbolTableObject.h: - (JSC::symbolTablePut): - * tests/stress/constant-closure-var-with-dynamic-invalidation.js: Added. - (.): - -2014-07-01 Mark Lam <mark.lam@apple.com> - - Debugger's breakpoint list should not be a Vector. - <https://webkit.org/b/134514> - - Reviewed by Geoffrey Garen. - - The debugger currently stores breakpoint data as entries in a Vector (see - BreakpointsInLine). It also keeps a fast map look up of breakpoint IDs to - the breakpoint data (see m_breakpointIDToBreakpoint). Because a Vector can - compact or reallocate its backing store, this can causes all sorts of havoc. - The m_breakpointIDToBreakpoint map assumes that the breakpoint data doesn't - move in memory. - - The fix is to replace the BreakpointsInLine Vector with a BreakpointsList - doubly linked list. - - * debugger/Breakpoint.h: - (JSC::Breakpoint::Breakpoint): - (JSC::BreakpointsList::~BreakpointsList): - * debugger/Debugger.cpp: - (JSC::Debugger::setBreakpoint): - (JSC::Debugger::removeBreakpoint): - (JSC::Debugger::hasBreakpoint): - * debugger/Debugger.h: - -2014-06-30 Michael Saboff <msaboff@apple.com> - - Add option to run-jsc-stress-testes to filter out tests that use large heaps - https://bugs.webkit.org/show_bug.cgi?id=134458 - - Reviewed by Filip Pizlo. - - Added test to skip js1_5/Regress/regress-159334.js when testing on a memory limited device. - - * tests/mozilla/mozilla-tests.yaml: - -2014-06-30 Daniel Bates <dabates@apple.com> - - Avoid copying closed variables vector; actually use move semantics - - Rubber-stamped by Oliver Hunt. - - Currently we always copy the closed variables vector passed by Parser::closedVariables() - to ProgramNode::setClosedVariables() because these member functions return and take a const - rvalue reference, respectively. Instead, these member functions should take an return a non- - constant rvalue reference so that we actually move the closed variables vector from the Parser - object to the Node object. - - * parser/Nodes.cpp: - (JSC::ProgramNode::setClosedVariables): Remove const qualifier for argument. - * parser/Nodes.h: - (JSC::ScopeNode::setClosedVariables): Ditto. - * parser/Parser.h: - (JSC::Parser::closedVariables): Remove const qualifier on return type. - (JSC::parse): Remove extraneous call to std::move(). Calling std::move() is unnecessary here - because Parser::closedVariables() returns an rvalue reference. - -2014-06-30 Joseph Pecoraro <pecoraro@apple.com> - - JSContext Inspection: Provide a way to use a non-Main RunLoop for Inspector JavaScript Evaluations - https://bugs.webkit.org/show_bug.cgi?id=134371 - - Reviewed by Timothy Hatcher. - - * API/JSContextPrivate.h: - * API/JSContext.mm: - (-[JSContext _debuggerRunLoop]): - (-[JSContext _setDebuggerRunLoop:]): - Private API for setting the CFRunLoop for a debugger to evaluate in. - - * API/JSContextRefInternal.h: Added. - * API/JSContextRef.cpp: - (JSGlobalContextGetDebuggerRunLoop): - (JSGlobalContextSetDebuggerRunLoop): - Internal API for setting a CFRunLoop on a JSContextRef. - Set this on the debuggable. - - * inspector/remote/RemoteInspectorDebuggable.h: - * inspector/remote/RemoteInspectorDebuggableConnection.h: - (Inspector::RemoteInspectorBlock::RemoteInspectorBlock): - (Inspector::RemoteInspectorBlock::~RemoteInspectorBlock): - (Inspector::RemoteInspectorBlock::operator=): - (Inspector::RemoteInspectorBlock::operator()): - Moved into the header. - - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::inspectorDebuggable): - Lets store the RunLoop on the debuggable instead of this core - platform agnostic class, so expose the debuggable. - - * inspector/remote/RemoteInspectorDebuggableConnection.mm: - (Inspector::RemoteInspectorHandleRunSourceGlobal): - (Inspector::RemoteInspectorQueueTaskOnGlobalQueue): - (Inspector::RemoteInspectorInitializeGlobalQueue): - Rename the global functions for clarity. - - (Inspector::RemoteInspectorHandleRunSourceWithInfo): - Handler for private run loops. - - (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): - (Inspector::RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection): - (Inspector::RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable): - (Inspector::RemoteInspectorDebuggableConnection::setupRunLoop): - (Inspector::RemoteInspectorDebuggableConnection::teardownRunLoop): - (Inspector::RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop): - Setup and teardown and use private run loop sources if the debuggable needs it. - -2014-06-30 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> - - Add missing ENABLE(DFG_JIT) guards - https://bugs.webkit.org/show_bug.cgi?id=134444 - - Reviewed by Darin Adler. - - * dfg/DFGFunctionWhitelist.cpp: - * dfg/DFGFunctionWhitelist.h: - -2014-06-29 Yoav Weiss <yoav@yoav.ws> - - Add support for HTMLImageElement's sizes attribute - https://bugs.webkit.org/show_bug.cgi?id=133620 - - Reviewed by Dean Jackson. - - Added an ENABLE_PICTURE_SIZES compile flag. - - * Configurations/FeatureDefines.xcconfig: - -2014-06-27 Filip Pizlo <fpizlo@apple.com> - - Don't fold a UInt32ToNumber with DoOverflow to Identity since that would result in an Identity that takes an Int32 and returns a DoubleRep - https://bugs.webkit.org/show_bug.cgi?id=134412 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::setReplacement): - * dfg/DFGStrengthReductionPhase.cpp: - (JSC::DFG::StrengthReductionPhase::handleNode): - * dfg/DFGValidate.cpp: - (JSC::DFG::Validate::validate): - * tests/stress/uint32-to-number-fold-constant-with-do-overflow.js: Added. - (foo): - (bar): - (baz): - -2014-06-27 Peyton Randolph <prandolph@apple.com> - - Add feature flag for link long-press gesture. - https://bugs.webkit.org/show_bug.cgi?id=134262 - - Reviewed by Enrica Casucci. - - * Configurations/FeatureDefines.xcconfig: - Add ENABLE_LINK_LONG_PRESS. - -2014-06-27 László Langó <llango.u-szeged@partner.samsung.com> - - [JavaScriptCore] FTL buildfix for EFL platform. - https://bugs.webkit.org/show_bug.cgi?id=133546 - - Reviewed by Darin Adler. - - * ftl/FTLAbstractHeap.cpp: - (JSC::FTL::IndexedAbstractHeap::IndexedAbstractHeap): - * ftl/FTLLocation.cpp: - (JSC::FTL::Location::forStackmaps): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::opposite): - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileStub): - * ftl/FTLStackMaps.cpp: - (JSC::FTL::StackMaps::Constant::dump): - * llvm/InitializeLLVMPOSIX.cpp: - (JSC::initializeLLVMPOSIX): - -2014-06-26 Benjamin Poulain <benjamin@webkit.org> - - iOS 8 beta 2 ES6 'Set' clear() broken - https://bugs.webkit.org/show_bug.cgi?id=134346 - - Reviewed by Oliver Hunt. - - The object map was not cleared :(. - - Kudos to Ashley Gullen for tracking this and making a regression test. - Credit to Oliver for finding the missing code. - - * runtime/MapData.h: - (JSC::MapData::clear): - -2014-06-25 Brent Fulgham <bfulgham@apple.com> - - [Win] Expose Cache Information to WinLauncher - https://bugs.webkit.org/show_bug.cgi?id=134318 - - Reviewed by Dean Jackson. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Add missing - MemoryStatistics files to the WIndows build. - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - -2014-06-26 David Kilzer <ddkilzer@apple.com> - - DFG::FunctionWhitelist::parseFunctionNamesInFile does not close file - <http://webkit.org/b/134343> - <rdar://problem/17459487> - - Reviewed by Michael Saboff. - - * dfg/DFGFunctionWhitelist.cpp: - (JSC::DFG::FunctionWhitelist::parseFunctionNamesInFile): - Close the file handle, and log an error on failure. - -2014-06-25 Dana Burkart <dburkart@apple.com> - - Add support for 5-tuple versioning. - - Reviewed by David Farler. - - * Configurations/Version.xcconfig: - -2014-06-25 Geoffrey Garen <ggaren@apple.com> - - Build fix. - - Unreviewed. - - * runtime/JSDateMath.cpp: - (JSC::parseDateFromNullTerminatedCharacters): - * runtime/VM.cpp: - (JSC::VM::resetDateCache): Use std::numeric_limits instead of QNaN - constant since that constant doesn't exist anymore. - -2014-06-25 Geoffrey Garen <ggaren@apple.com> - - Unreviewed, rolling out r166876. - - Caused some ECMA test262 failures - - Reverted changeset: - - "Date object needs to check for ES5 15.9.1.14 TimeClip limit." - https://bugs.webkit.org/show_bug.cgi?id=131248 - http://trac.webkit.org/changeset/166876 - -2014-06-25 Brent Fulgham <bfulgham@apple.com> - - [Win] Unreviewed gardening. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Update to - put various files in proper IDE categories. - -2014-06-25 peavo@outlook.com <peavo@outlook.com> - - [Win64] ASM LLINT is not enabled. - https://bugs.webkit.org/show_bug.cgi?id=130638 - - This patch adds a new LLINT assembler backend for Win64, and implements it. - It makes adjustments to follow the Win64 ABI spec. where it's found to be needed. - Also, LLINT and JIT is enabled for Win64. - - Reviewed by Mark Lam. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Added JITStubsMSVC64.asm. - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Ditto. - * JavaScriptCore/JavaScriptCore.vcxproj/jsc/jscCommon.props: Increased stack size to avoid stack overflow in tests. - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: Generate assembler source file for Win64. - * assembler/MacroAssemblerX86_64.h: - (JSC::MacroAssemblerX86_64::call): Follow Win64 ABI spec. - * jit/JITStubsMSVC64.asm: Added. - * jit/Repatch.cpp: - (JSC::emitPutTransitionStub): Compile fix. - * jit/ThunkGenerators.cpp: - (JSC::nativeForGenerator): Follow Win64 ABI spec. - * llint/LLIntData.cpp: - (JSC::LLInt::Data::performAssertions): Ditto. - * llint/LLIntOfflineAsmConfig.h: Enable new llint backend for Win64. - * llint/LowLevelInterpreter.asm: Implement new Win64 backend, and follow Win64 ABI spec. - * llint/LowLevelInterpreter64.asm: Ditto. - * offlineasm/asm.rb: Compile fix. - * offlineasm/backends.rb: Add new llint backend for Win64. - * offlineasm/settings.rb: Compile fix. - * offlineasm/x86.rb: Implement new llint Win64 backend. - -2014-06-25 Laszlo Gombos <l.gombos@samsung.com> - - Remove build guard for progress element - https://bugs.webkit.org/show_bug.cgi?id=134292 - - Reviewed by Benjamin Poulain. - - * Configurations/FeatureDefines.xcconfig: - -2014-06-24 Michael Saboff <msaboff@apple.com> - - Add support routines to provide descriptive JavaScript backtraces - https://bugs.webkit.org/show_bug.cgi?id=134278 - - Reviewed by Mark Lam. - - * interpreter/CallFrame.cpp: - (JSC::CallFrame::dump): - (JSC::CallFrame::describeFrame): - * interpreter/CallFrame.h: - * runtime/JSCJSValue.cpp: - (JSC::JSValue::dumpForBacktrace): - * runtime/JSCJSValue.h: - -2014-06-24 Brady Eidson <beidson@apple.com> - - Enable GAMEPAD in the Mac build, but disabled at runtime. - https://bugs.webkit.org/show_bug.cgi?id=134255 - - Reviewed by Dean Jackson. - - * Configurations/FeatureDefines.xcconfig: - - * runtime/JSObject.h: Export JSObject::removeDirect() to allow disabling - functions at runtime. - -2014-06-24 Mark Hahnenberg <mhahnenberg@apple.com> - - REGRESSION (r169703): Invalid cast in JSC::asGetterSetter / JSC::JSObject::defineOwnNonIndexProperty - https://bugs.webkit.org/show_bug.cgi?id=134046 - - Reviewed by Filip Pizlo. - - * runtime/GetterSetter.h: - (JSC::asGetterSetter): - * runtime/JSObject.cpp: - (JSC::JSObject::defineOwnNonIndexProperty): We need to check for a CustomGetterSetter here as well as - a normal GetterSetter. If we encounter a CustomGetterSetter, we delete it, create a new normal GetterSetter, - and insert it like normal. We also need to check for CustomAccessors when checking for unconfigurable properties. - -2014-06-24 Brent Fulgham <bfulgham@apple.com> - - [Win] MSVC mishandles enums in bitfields - https://bugs.webkit.org/show_bug.cgi?id=134237 - - Reviewed by Michael Saboff. - - Replace uses of enum types in bit fields with unsigned to - avoid losing a bit to hold the sign value. This can result - in Windows interpreting the value of the field improperly. - - * bytecode/StructureStubInfo.h: - * parser/Nodes.h: - -2014-06-23 Andreas Kling <akling@apple.com> - - Inline the UnlinkedInstructionStream::Reader logic. - <https://webkit.org/b/134203> - - This class is only used by CodeBlock to unpack the unlinked instructions, - and we were spending 0.5% of total time on PLT calling Reader::next(). - Move the logic to the header file and mark it ALWAYS_INLINE. - - Reviewed by Geoffrey Garen. - - * bytecode/UnlinkedInstructionStream.cpp: - * bytecode/UnlinkedInstructionStream.h: - (JSC::UnlinkedInstructionStream::Reader::Reader): - (JSC::UnlinkedInstructionStream::Reader::read8): - (JSC::UnlinkedInstructionStream::Reader::read32): - (JSC::UnlinkedInstructionStream::Reader::next): - -2014-06-20 Sam Weinig <sam@webkit.org> - - Remove static tables for bindings that use eager reification - https://bugs.webkit.org/show_bug.cgi?id=134126 - - Reviewed by Oliver Hunt. - - * runtime/JSObject.cpp: - (JSC::JSObject::putDirectCustomAccessor): - * runtime/Structure.h: - (JSC::Structure::setHasCustomGetterSetterProperties): - Change setHasCustomGetterSetterProperties to behave like setHasGetterSetterProperties, and set - the m_hasReadOnlyOrGetterSetterPropertiesExcludingProto bit if the property is not __proto__. - Without this, JSObject::put() won't think there are any setters on the prototype chain of an - object that has no static lookup table and uses eagerly reified custom getter/setter properties. - -2014-06-21 Brady Eidson <beidson@apple.com> - - Gamepad API - Deprecate the existing implementation - https://bugs.webkit.org/show_bug.cgi?id=134108 - - Reviewed by Timothy Hatcher. - - -Add new "GAMEPAD_DEPRECATED" build flag, moving the existing implementation to use it - -Move some implementation files into a "deprecated" subdirectory. - - * Configurations/FeatureDefines.xcconfig: - -2014-06-21 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r170244. - https://bugs.webkit.org/show_bug.cgi?id=134157 - - GTK/EFL bindings generator works differently, making this - patch not work there. Will fix entire patch after a rollout. - (Requested by bradee-oh on #webkit). - - Reverted changeset: - - "Gamepad API - Deprecate the existing implementation" - https://bugs.webkit.org/show_bug.cgi?id=134108 - http://trac.webkit.org/changeset/170244 - -2014-06-21 Brady Eidson <beidson@apple.com> - - Gamepad API - Deprecate the existing implementation - https://bugs.webkit.org/show_bug.cgi?id=134108 - - Reviewed by Timothy Hatcher. - - -Add new "GAMEPAD_DEPRECATED" build flag, moving the existing implementation to use it - -Add the "Deprecated" suffix to some implementation files - - * Configurations/FeatureDefines.xcconfig: - -2014-06-21 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> - - Removing PAGE_VISIBILITY_API compile guard. - https://bugs.webkit.org/show_bug.cgi?id=133844 - - Reviewed by Gavin Barraclough. - - * Configurations/FeatureDefines.xcconfig: - -2014-06-21 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> - - ARM traditional buildfix after r169942. - https://bugs.webkit.org/show_bug.cgi?id=134100 - - Reviewed by Zoltan Herczeg. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::abortWithReason): Added. - -2014-06-20 Andreas Kling <akling@apple.com> - - [Cocoa] Release freed up blocks from the JS heap after simulated memory pressure. - <https://webkit.org/b/134112> - - Reviewed by Mark Hahnenberg. - - * heap/BlockAllocator.h: - -2014-06-19 Alex Christensen <achristensen@webkit.org> - - Unreviewed fix after r170130. - - * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj: - Corrected directory so it can find common.props when opening Visual Studio. - -2014-06-19 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> - - Remove ENABLE(LLINT) and ENABLE(LLINT_C_LOOP) guards - https://bugs.webkit.org/show_bug.cgi?id=130389 - - Reviewed by Mark Lam. - - Removed ENABLE(LLINT) since we always build with it, and changed ENABLE(LLINT_C_LOOP) - into !ENABLE(JIT) since they are mutually exclusive. - - * CMakeLists.txt: - * assembler/MacroAssemblerCodeRef.h: - (JSC::MacroAssemblerCodePtr::createLLIntCodePtr): - (JSC::MacroAssemblerCodeRef::createLLIntCodeRef): - * assembler/MaxFrameExtentForSlowPathCall.h: - * bytecode/CallLinkStatus.cpp: - (JSC::CallLinkStatus::computeFromLLInt): - * bytecode/CodeBlock.cpp: - (JSC::dumpStructure): - (JSC::CodeBlock::printGetByIdCacheStatus): - (JSC::CodeBlock::printCallOp): - (JSC::CodeBlock::CodeBlock): - (JSC::CodeBlock::~CodeBlock): - (JSC::CodeBlock::propagateTransitions): - (JSC::CodeBlock::finalizeUnconditionally): - (JSC::CodeBlock::unlinkCalls): - (JSC::CodeBlock::unlinkIncomingCalls): - (JSC::CodeBlock::linkIncomingCall): - (JSC::CodeBlock::frameRegisterCount): - * bytecode/CodeBlock.h: - * bytecode/GetByIdStatus.cpp: - (JSC::GetByIdStatus::computeFromLLInt): - * bytecode/Opcode.h: - (JSC::padOpcodeName): - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeFromLLInt): - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::emitCall): - (JSC::BytecodeGenerator::emitConstruct): - * heap/Heap.cpp: - (JSC::Heap::gatherJSStackRoots): - * interpreter/Interpreter.cpp: - (JSC::Interpreter::initialize): - (JSC::Interpreter::isOpcode): - * interpreter/Interpreter.h: - (JSC::Interpreter::getOpcodeID): - * interpreter/JSStack.cpp: - (JSC::JSStack::JSStack): - (JSC::JSStack::committedByteCount): - * interpreter/JSStack.h: - * interpreter/JSStackInlines.h: - (JSC::JSStack::ensureCapacityFor): - (JSC::JSStack::topOfFrameFor): - (JSC::JSStack::setStackLimit): - * jit/ExecutableAllocatorFixedVMPool.cpp: - (JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): - * jit/JIT.h: - (JSC::JIT::compileCTINativeCall): - * jit/JITExceptions.h: - * jit/JITThunks.cpp: - (JSC::JITThunks::ctiNativeCall): - (JSC::JITThunks::ctiNativeConstruct): - * llint/LLIntCLoop.cpp: - * llint/LLIntCLoop.h: - * llint/LLIntData.cpp: - (JSC::LLInt::initialize): - (JSC::LLInt::Data::performAssertions): - * llint/LLIntData.h: - (JSC::LLInt::Data::performAssertions): Deleted. - * llint/LLIntEntrypoint.cpp: - * llint/LLIntEntrypoint.h: - * llint/LLIntExceptions.cpp: - * llint/LLIntExceptions.h: - * llint/LLIntOfflineAsmConfig.h: - * llint/LLIntOffsetsExtractor.cpp: - (JSC::LLIntOffsetsExtractor::dummy): - * llint/LLIntOpcode.h: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * llint/LLIntSlowPaths.h: - * llint/LLIntThunks.cpp: - * llint/LLIntThunks.h: - * llint/LowLevelInterpreter.cpp: - * llint/LowLevelInterpreter.h: - * runtime/CommonSlowPaths.cpp: - * runtime/CommonSlowPaths.h: - * runtime/ErrorHandlingScope.cpp: - (JSC::ErrorHandlingScope::ErrorHandlingScope): - (JSC::ErrorHandlingScope::~ErrorHandlingScope): - * runtime/Executable.cpp: - (JSC::setupLLInt): - * runtime/InitializeThreading.cpp: - (JSC::initializeThreading): - * runtime/JSCJSValue.h: - * runtime/JSCJSValueInlines.h: - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): - * runtime/VM.cpp: - (JSC::VM::VM): - (JSC::sanitizeStackForVM): - * runtime/VM.h: - (JSC::VM::canUseJIT): Deleted. - -2014-06-18 Alex Christensen <achristensen@webkit.org> - - Add FTL to Windows build. - https://bugs.webkit.org/show_bug.cgi?id=134015 - - Reviewed by Filip Pizlo. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - Added ftl source files. - * JavaScriptCore.vcxproj/JavaScriptCoreCommon.props: - Added ftl and llvm directories to include path. - * JavaScriptCore.vcxproj/libllvmForJSC: Added. - * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.props: Added. - * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj: Added. - * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj.filters: Added. - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): - MSVC doesn't like to divide by zero while compiling. Use std::nan instead. - * llvm/InitializeLLVMWin.cpp: Added. - (JSC::initializeLLVMImpl): - Implemented dynamic loading and linking for Windows. - -2014-06-18 Alex Christensen <achristensen@webkit.org> - - Unreviewed build fix after r170107. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileArithMod): - Use non-template sub for armv7s. - -2014-06-18 David Kilzer <ddkilzer@apple.com> - - -[JSContext setName:] leaks NSString - <http://webkit.org/b/134038> - - Reviewed by Joseph Pecoraro. - - Fixes the following static analyzer warning: - - JavaScriptCore/API/JSContext.mm:200:73: warning: Potential leak of an object - JSStringRef nameJS = name ? JSStringCreateWithCFString((CFStringRef)[name copy]) : nullptr; - ^ - - * API/JSContext.mm: - (-[JSContext setName:]): Autorelease the copy of |name|. - -2014-06-18 Mark Lam <mark.lam@apple.com> - - DFGGraph::m_doubleConstantMap will not map 0 values correctly. - <https://webkit.org/b/133994> - - Reviewed by Geoffrey Garen. - - DFGGraph::m_doubleConstantsMap should not use a double as a key to its HashMap, - because it means two unfortunate things: - - It will probably break for zero. - - It will think that -0 is the same as +0 under some circumstances, size - -0==+0 even though they are distinct values (for example 1/-0 != 1/+0). - - The fix is to use std::unordered_map which does not require special empty - and deleted values, and to use the raw bits instead of the double value as - the key. - - * dfg/DFGGraph.h: - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::addressOfDoubleConstant): - -2014-06-18 Alex Christensen <achristensen@webkit.org> - - Remove duplicate code using sdiv. - https://bugs.webkit.org/show_bug.cgi?id=133764 - - Reviewed by Daniel Bates. - - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::sdiv): - Make sdiv a template to match arm64. - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileArithDiv): - (JSC::DFG::SpeculativeJIT::compileArithMod): - Remove duplicate code that was identical except for sdiv not being a template. - -2014-06-17 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r170082. - https://bugs.webkit.org/show_bug.cgi?id=134006 - - Breaks build. (Requested by mlam on #webkit). - - Reverted changeset: - - "DFGGraph::m_doubleConstantMap will not map 0 values - correctly." - https://bugs.webkit.org/show_bug.cgi?id=133994 - http://trac.webkit.org/changeset/170082 - -2014-06-17 Mark Lam <mark.lam@apple.com> - - DFGGraph::m_doubleConstantMap will not map 0 values correctly. - <https://webkit.org/b/133994> - - Reviewed by Geoffrey Garen. - - DFGGraph::m_doubleConstantsMap should not use a double as a key to its HashMap, - because it means two unfortunate things: - - It will probably break for zero. - - It will think that -0 is the same as +0 under some circumstances, size - -0==+0 even though they are distinct values (for example 1/-0 != 1/+0). - - The fix is to use std::unordered_map which does not require special empty - and deleted values, and to use the raw bits instead of the double value as - the key. - - * dfg/DFGGraph.h: - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::addressOfDoubleConstant): - -2014-06-17 Oliver Hunt <oliver@apple.com> - - Fix error messages for incorrect hex literals - https://bugs.webkit.org/show_bug.cgi?id=133998 - - Reviewed by Mark Lam. - - Ensure that the error messages for bogus hex literals actually - make sense. - - * parser/Lexer.cpp: - (JSC::Lexer<T>::lex): - * parser/ParserTokens.h: - -2014-06-17 Matthew Mirman <mmirman@apple.com> - - Fixes bug where building JSC sometimes crashes at build-symbol-table-index.py. Also adds licenses. - https://bugs.webkit.org/show_bug.cgi?id=133814 - - Reviewed by Filip Pizlo. - - Adds the "shopt -s nullglob" line necessary to prevent the loop in the shell - script from using "*.o" as a file when no other files in the directory exist. - - * build-symbol-table-index.sh: Added license. - * copy-llvm-ir-to-derived-sources.sh: Added license and "shopt -s nullglob" line. - -2014-06-16 Sam Weinig <sam@webkit.org> - - Move forward declaration of bindings static functions into their implementation files - https://bugs.webkit.org/show_bug.cgi?id=133943 - - Reviewed by Geoffrey Garen. - - * runtime/CommonIdentifiers.h: - Add a few identifiers that are needed by the DOM. - -2014-06-16 Mark Lam <mark.lam@apple.com> - - Parser statementDepth accounting needs to account for when a function body excludes its braces. - <https://webkit.org/b/133832> - - Reviewed by Oliver Hunt. - - In some cases (e.g. when a Function object is instantiated from a string), the - function body source may not include its braces. The parser needs to account - for this when calculating its statementDepth. - - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::generateFunctionCodeBlock): - (JSC::UnlinkedFunctionExecutable::codeBlockFor): - * bytecode/UnlinkedCodeBlock.h: - * parser/Parser.cpp: - (JSC::Parser<LexerType>::parseStatement): - - Also fixed the error message for declaring nested functions in strict mode - to be more accurate. - * parser/Parser.h: - (JSC::Parser<LexerType>::parse): - (JSC::parse): - * runtime/Executable.cpp: - (JSC::ScriptExecutable::newCodeBlockFor): - -2014-06-16 Juergen Ributzka <juergen@apple.com> - - Change the order of the alias analysis passes to align with the opt pipeline of LLVM - https://bugs.webkit.org/show_bug.cgi?id=133753 - - Reviewed by Geoffrey Garen. - - The order in which the alias analysis passes are added affects also the - order in which they are utilized. Change the order to align with the - one use by LLVM itself. The last alias analysis pass added will be - evaluated first. With this change we first perform a basic alias - analysis and then use the type-based alias analysis (if required). - - * ftl/FTLCompile.cpp: - (JSC::FTL::compile): - -2014-06-16 Juergen Ributzka <juergen@apple.com> - - Fix the arguments passed to the LLVM dylib - https://bugs.webkit.org/show_bug.cgi?id=133757 - - Reviewed by Geoffrey Garen. - - The LLVM command line argument parser assumes that the first argument - is the program name. We need to add a fake program name, otherwise the - first argument will be parsed as program name and ignored. - - * llvm/library/LLVMExports.cpp: - (initializeAndGetJSCLLVMAPI): - -2014-06-16 Michael Saboff <msaboff@apple.com> - - Convert ASSERT in inlineFunctionForCapabilityLevel to early return - https://bugs.webkit.org/show_bug.cgi?id=133903 - - Reviewed by Mark Hahnenberg. - - Hardened code by Converting ASSERT to return CannotCompile. - - * dfg/DFGCapabilities.h: - (JSC::DFG::inlineFunctionForCapabilityLevel): - -2014-06-13 Sam Weinig <sam@webkit.org> - - Store DOM constants directly in the JS object rather than jumping through a custom accessor - https://bugs.webkit.org/show_bug.cgi?id=133898 - - Reviewed by Oliver Hunt. - - * runtime/Lookup.h: - (JSC::HashTableValue::attributes): - Switch attributes to be stored as an unsigned rather than an unsigned char, since there is no difference in memory use - and will make adding more flags possibles. - - (JSC::HashTableValue::propertyGetter): - (JSC::HashTableValue::propertyPutter): - Change assertion to use BuiltinOrFunctionOrConstant. - - (JSC::HashTableValue::constantInteger): - Added. - - (JSC::getStaticPropertySlot): - (JSC::getStaticValueSlot): - Use PropertySlot::setValue() for constants during static lookup. - - (JSC::reifyStaticProperties): - Put the constant directly on the object when eagerly reifying. - - * runtime/PropertySlot.h: - Add ConstantInteger flag and BuiltinOrFunctionOrConstant helper. - -2014-06-14 Michael Saboff <msaboff@apple.com> - - operationCreateArguments could cause a GC during OSR exit - https://bugs.webkit.org/show_bug.cgi?id=133905 - - Reviewed by Filip Pizlo. - - Defer GC via new wrapper functions for operationCreateArguments and operationCreateInlinedArguments - for use by OSR exit stubs. - - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): - * dfg/DFGOperations.cpp: - * dfg/DFGOperations.h: - * jit/JITOperations.cpp: - * jit/JITOperations.h: - -2014-06-13 Mark Hahnenberg <mhahnenberg@apple.com> - - OSR exit should barrier the Executables for all InlineCallFrames, not just those on the stack at the time of exit - https://bugs.webkit.org/show_bug.cgi?id=133880 - - Reviewed by Filip Pizlo. - - We could have exited due to a value received from an inlined block that's no longer on - the stack, so we should just barrier all InlineCallFrames. - - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::adjustAndJumpToTarget): - -2014-06-13 Alex Christensen <achristensen@webkit.org> - - Make css jit compile for armv7. - https://bugs.webkit.org/show_bug.cgi?id=133596 - - Reviewed by Benjamin Poulain. - - * assembler/MacroAssembler.h: - Use branchPtr on ARM_THUMB2. - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::addPtrNoFlags): - (JSC::MacroAssemblerARMv7::or32): - (JSC::MacroAssemblerARMv7::test32): - (JSC::MacroAssemblerARMv7::branch): - (JSC::MacroAssemblerARMv7::branchPtr): - Added macros necessary for css jit. - -2014-06-13 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix ARMv7. - - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::abortWithReason): - -2014-06-12 Filip Pizlo <fpizlo@apple.com> - - Even better diagnostics from DFG traps - https://bugs.webkit.org/show_bug.cgi?id=133836 - - Reviewed by Oliver Hunt. - - We now stuff the DFG::NodeType into a register before bailing. Also made the - DFGBailed abort reason a bit more specific. As planned, the new abort reasons use - different numbers than any previous abort reasons. - - * assembler/AbortReason.h: - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::abortWithReason): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::abortWithReason): - * assembler/MacroAssemblerX86.h: - (JSC::MacroAssemblerX86::abortWithReason): - * assembler/MacroAssemblerX86_64.h: - (JSC::MacroAssemblerX86_64::abortWithReason): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::SpeculativeJIT): - (JSC::DFG::SpeculativeJIT::bail): - (JSC::DFG::SpeculativeJIT::compileCurrentBlock): - * dfg/DFGSpeculativeJIT.h: - -2014-06-12 Simon Fraser <simon.fraser@apple.com> - - Fix assertions under JSC::setNeverInline() when running js tests in WebKitTestRunner - https://bugs.webkit.org/show_bug.cgi?id=133840 - - Reviewed by Filip Pizlo. - - Fix ASSERT(exec->vm().currentThreadIsHoldingAPILock()); under JSC::setNeverInline() - when running DFG tests. - - * API/JSCTestRunnerUtils.cpp: - (JSC::numberOfDFGCompiles): - (JSC::setNeverInline): - -2014-06-12 Brent Fulgham <bfulgham@apple.com> - - [Win] Avoid fork bomb during build - https://bugs.webkit.org/show_bug.cgi?id=133837 - <rdar://problem/17296034> - - Reviewed by Tim Horton. - - * JavaScriptCore.vcxproj/build-generated-files.sh: Use a - reasonable default value when the 'num-cpus' script is not available. - -2014-06-12 Mark Lam <mark.lam@apple.com> - - Remove some dead / unused code. - <https://webkit.org/b/133828> - - Reviewed by Filip Pizlo. - - * builtins/BuiltinExecutables.cpp: - (JSC::BuiltinExecutables::createBuiltinExecutable): - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): - * bytecode/UnlinkedCodeBlock.h: - (JSC::UnlinkedFunctionExecutable::create): - * bytecompiler/BytecodeGenerator.h: - (JSC::BytecodeGenerator::makeFunction): - * parser/Parser.h: - (JSC::DepthManager::DepthManager): Deleted. - (JSC::DepthManager::~DepthManager): Deleted. - * runtime/CodeCache.cpp: - (JSC::CodeCache::getFunctionExecutableFromGlobalCode): - -2014-06-12 Mark Hahnenberg <mhahnenberg@apple.com> - - Move structureHasRareData out of TypeInfo - https://bugs.webkit.org/show_bug.cgi?id=133800 - - Reviewed by Andreas Kling. - - StructureHasRareData was originally put in TypeInfo to avoid making Structure bigger, - but we have a few spare bits in Structure so it would be nice to remove this hack. - - * runtime/JSTypeInfo.h: - (JSC::TypeInfo::newImpurePropertyFiresWatchpoints): - (JSC::TypeInfo::structureHasRareData): Deleted. - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::allocateRareData): - (JSC::Structure::cloneRareDataFrom): - * runtime/Structure.h: - (JSC::Structure::previousID): - (JSC::Structure::objectToStringValue): - (JSC::Structure::setObjectToStringValue): - (JSC::Structure::setPreviousID): - (JSC::Structure::clearPreviousID): - (JSC::Structure::previous): - (JSC::Structure::rareData): - * runtime/StructureInlines.h: - (JSC::Structure::setEnumerationCache): - (JSC::Structure::enumerationCache): - -2014-06-12 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> - - Allow enum guards to be generated from the replay json files - https://bugs.webkit.org/show_bug.cgi?id=133399 - - Reviewed by Csaba Osztrogonác. - - * replay/scripts/CodeGeneratorReplayInputs.py: - (Type.__init__): - (InputsModel.parse_type_with_framework_name): - (Generator.generate_header): - (Generator.generate_implementation): - * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.cpp: Added. - (Test::HandleWheelEvent::HandleWheelEvent): - (Test::HandleWheelEvent::~HandleWheelEvent): - (JSC::InputTraits<Test::HandleWheelEvent>::type): - (JSC::InputTraits<Test::HandleWheelEvent>::encode): - (JSC::InputTraits<Test::HandleWheelEvent>::decode): - (JSC::EncodingTraits<WebCore::PlatformWheelEventPhase>::encodeValue): - (JSC::EncodingTraits<WebCore::PlatformWheelEventPhase>::decodeValue): - * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.h: Added. - (JSC::InputTraits<Test::HandleWheelEvent>::queue): - (Test::HandleWheelEvent::platformEvent): - * replay/scripts/tests/generate-enum-with-guard.json: Added. - -2014-06-12 Carlos Garcia Campos <cgarcia@igalia.com> - - Unreviewed. Fix GTK+ build after r169823. - - Include StructureInlines.h in a few more files to fix linking - issues due to JSC::Structure::get undefined symbol. - - * runtime/ArrayIteratorConstructor.cpp: - * runtime/ArrayIteratorPrototype.cpp: - * runtime/JSConsole.cpp: - * runtime/JSMapIterator.cpp: - * runtime/JSSet.cpp: - * runtime/JSSetIterator.cpp: - * runtime/JSWeakMap.cpp: - * runtime/MapIteratorPrototype.cpp: - * runtime/MapPrototype.cpp: - * runtime/SetIteratorPrototype.cpp: - * runtime/SetPrototype.cpp: - * runtime/WeakMapPrototype.cpp: - -2014-06-12 Csaba Osztrogonác <ossy@webkit.org> - - [EFL] One more URTBF after r169823 to make ARM64 build happy too. - - * runtime/JSMap.cpp: - -2014-06-11 Mark Hahnenberg <mhahnenberg@apple.com> - - Inline caching should try to flatten uncacheable dictionaries - https://bugs.webkit.org/show_bug.cgi?id=133683 - - Reviewed by Geoffrey Garen. - - There exists a body of JS code that deletes properties off of objects (especially function/constructor objects), - which puts them into an uncacheable dictionary state. This prevents all future inline caching for these objects. - If properties are deleted out of the object during its initialization, we can enable caching for that object by - attempting to flatten it when we see we're trying to do inline caching with that object. We then record that we - performed this flattening optimization in the object's Structure. If it ever re-enters the uncacheable dictionary - state then we can just give up on caching that object. - - In refactoring some of the code in tryCacheGetById and tryBuildGetByIdList to reduce some duplication, I added - the InlineCacheAction enum, a new way to indicate the success or failure of an inline caching attempt. I changed - the other inline caching functions to return this enum rather than the opaque booleans that we were previously - returning. - - * jit/Repatch.cpp: - (JSC::actionForCell): - (JSC::tryCacheGetByID): - (JSC::repatchGetByID): - (JSC::tryBuildGetByIDList): - (JSC::buildGetByIDList): - (JSC::tryCachePutByID): - (JSC::repatchPutByID): - (JSC::tryBuildPutByIdList): - (JSC::buildPutByIdList): - (JSC::tryRepatchIn): - (JSC::repatchIn): - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::flattenDictionaryStructure): - * runtime/Structure.h: - (JSC::Structure::hasBeenFlattenedBefore): - -2014-06-11 Csaba Osztrogonác <ossy@webkit.org> - - [EFL] URTBF after r169823. - - * bindings/ScriptValue.cpp: Missing include added. - -2014-06-11 Ryosuke Niwa <rniwa@webkit.org> - - Remove an unnecessary asObject(this) call inside JSObject::fastGetOwnPropertySlot. - - Rubber-stamped by Andreas Kling. - - * runtime/JSObject.h: - (JSC::JSObject::fastGetOwnPropertySlot): - -2014-06-11 Ryosuke Niwa <rniwa@webkit.org> - - Turning on DUMP_PROPERTYMAP_STATS causes a build failure - https://bugs.webkit.org/show_bug.cgi?id=133673 - - Reviewed by Andreas Kling. - - Rewrote the property map statistics code because the old code wasn't building, - and it was also mixing numbers for lookups and insertions/removals. - - New logging code records the number of calls to PropertyTable::find (finds) and - PropertyTable::get/PropertyTable::findWithString separately so that we can quantify - the number of probing during updates and lookups. - - * jsc.cpp: - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::find): - (JSC::PropertyTable::get): - (JSC::PropertyTable::findWithString): - (JSC::PropertyTable::add): - (JSC::PropertyTable::remove): - (JSC::PropertyTable::reinsert): - (JSC::PropertyTable::rehash): - * runtime/Structure.cpp: - (JSC::PropertyMapStatisticsExitLogger::PropertyMapStatisticsExitLogger): - (JSC::PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger): - -2014-06-11 Andreas Kling <akling@apple.com> - - Always inline JSValue::get() and Structure::get(). - <https://webkit.org/b/133755> - - Reviewed by Ryosuke Niwa. - - These functions get really hot, so ask the compiler to be more - aggressive about inlining them. - - ~28% speed-up on Ryosuke's microbenchmark for accessing nextSibling - through GetByVal. - - * runtime/JSArrayIterator.cpp: - * runtime/JSCJSValue.cpp: - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::get): - * runtime/JSPromiseDeferred.cpp: - * runtime/StructureInlines.h: - (JSC::Structure::get): - -2014-06-11 Ryosuke Niwa <rniwa@webkit.org> - - Structure::get should instantiate DeferGC only when materializing property map - https://bugs.webkit.org/show_bug.cgi?id=133727 - - Rubber-stamped by Andreas Kling. - - Make materializePropertyMapIfNecessary always inline. - - This is ~12% improvement on the microbenchmark attached in the bug. - - * runtime/Structure.h: - (JSC::Structure::materializePropertyMapIfNecessary): - (JSC::Structure::materializePropertyMapIfNecessaryForPinning): - -2014-06-11 Ryosuke Niwa <rniwa@webkit.org> - - Structure::get should instantiate DeferGC only when materializing property map - https://bugs.webkit.org/show_bug.cgi?id=133727 - - Reviewed by Geoffrey Garen. - - DeferGC instances in Structure::get was added in http://trac.webkit.org/r157539 in order to avoid - collecting the property table newly created by materializePropertyMapIfNecessary since GC can happen - when GCSafeConcurrentJITLocker goes out of scope. - - However, always instantiating DeferGC inside Structure::get introduced a new performance bottleneck - in JSObject::getPropertySlot because frequently incrementing and decrementing a counter in vm.m_heap - and running a release assertion inside Heap::incrementDeferralDepth() is expensive. - - Work around this by instantiating DeferGC only when we're actually calling materializePropertyMap, - and immediately storing a pointer to the newly created property table in the stack before DeferGC - goes out of scope so that the property table will be marked. - - This shows 13-16% improvement on the microbenchmark attached in the bug. - - * runtime/JSCJSValue.cpp: - * runtime/JSObject.h: - (JSC::JSObject::fastGetOwnPropertySlot): - * runtime/Structure.h: - (JSC::Structure::materializePropertyMapIfNecessary): - * runtime/StructureInlines.h: - (JSC::Structure::get): - -2014-06-11 Andreas Kling <akling@apple.com> - - Some JSValue::get() micro-optimzations. - <https://webkit.org/b/133739> - - Tighten some of the property lookup code to improve performance of the - eagerly reified prototype attributes: - - - Instead of converting the property name to an integer at every step - in the prototype chain, move that to a separate pass at the end - since it should be a rare case. - - - Cache the StructureIDTable in a local instead of fetching it from - the Heap on every step. - - - Make fillCustomGetterPropertySlot inline. It was out-of-lined based - on the assumption that clients would mostly be cacheable GetByIds, - and it gets pretty hot (~1%) in GetByVal. - - - Pass the Structure directly to fillCustomGetterPropertySlot instead - of refetching it from the StructureIDTable. - - Reviewed by Geoff Garen. - - * runtime/JSObject.cpp: - (JSC::JSObject::fillCustomGetterPropertySlot): Deleted. - * runtime/JSObject.h: - (JSC::JSObject::inlineGetOwnPropertySlot): - (JSC::JSObject::fillCustomGetterPropertySlot): - (JSC::JSObject::getOwnPropertySlot): - (JSC::JSObject::fastGetOwnPropertySlot): - (JSC::JSObject::getPropertySlot): - (JSC::JSObject::getOwnPropertySlotSlow): Deleted. - -2014-06-10 Sam Weinig <sam@webkit.org> - - Don't create a HashTable for JSObjects that use eager reification - https://bugs.webkit.org/show_bug.cgi?id=133705 - - Reviewed by Geoffrey Garen. - - * runtime/Lookup.h: - (JSC::reifyStaticProperties): - Add a version of reifyStaticProperties that takes an array of HashTableValues - rather than a HashTable. - -2014-06-10 Filip Pizlo <fpizlo@apple.com> - - Prediction propagator should make sure everyone knows that a variable that is in an argument position where other versions of that variable are not MachineInts cannot possibly be flushed as Int52 - https://bugs.webkit.org/show_bug.cgi?id=133698 - - Reviewed by Geoffrey Garen and Mark Hahnenberg. - - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): Use the new utility to figure out if a variable could ever represent an Int52. - * dfg/DFGVariableAccessData.cpp: - (JSC::DFG::VariableAccessData::couldRepresentInt52): Add a new utility to detect early on if a variable could possibly be Int52. - (JSC::DFG::VariableAccessData::couldRepresentInt52Impl): - (JSC::DFG::VariableAccessData::flushFormat): - * dfg/DFGVariableAccessData.h: - * tests/stress/int52-inlined-call-argument.js: Added. - (foo): - (bar): - -2014-06-10 Mark Lam <mark.lam@apple.com> - - Assertion failure at JSC::Structure::checkOffsetConsistency() const + 234. - <https://webkit.org/b/133356> - - Reviewed by Mark Hahnenberg. - - The root cause of this issue is that a nonPropertyTransition can transition - a pinned dictionary structure to an unpinned dictionary structure. The new - structure will get a copy of the property table from the original structure. - However, when a GC occurs, the property table in the new structure will be - cleared because it is unpinned. This leads to complications in subsequent - derivative structures when flattening occurs, which eventually leads to the - assertion failure in this bug. - - The fix is to ensure that the new dictionary structure generated by the - nonPropertyTransition will have a copy of its predecessor's property table - and is pinned. - - * runtime/Structure.cpp: - (JSC::Structure::nonPropertyTransition): - -2014-06-10 Michael Saboff <msaboff@apple.com> - - In a certain app state, Array.prototype.filter() returns incorrect results - https://bugs.webkit.org/show_bug.cgi?id=133577 - - Reviewed by Oliver Hunt. - - Fixed the LLInt processing of op_put_by_val_direct to have the same hole check as op_put_by_val. - - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: - -2014-06-09 Mark Hahnenberg <mhahnenberg@apple.com> - - Global HashTables contain references to atomic StringImpls - https://bugs.webkit.org/show_bug.cgi?id=133661 - - Reviewed by Geoffrey Garen. - - This was a long-standing bug revealed by bug 133558. The issue is that the global static HashTables - cache their set of keys as StringImpls that are associated with a particular VM. This is obviously - incompatible with using multiple VMs on multiple threads (e.g. when using workers). The fix is to - change the "keys" field of the static HashTables to be char** instead of StringImpl**. - - * runtime/JSObject.cpp: - (JSC::getClassPropertyNames): - * runtime/Lookup.cpp: - (JSC::HashTable::createTable): - (JSC::HashTable::deleteTable): - * runtime/Lookup.h: - (JSC::HashTable::ConstIterator::key): - (JSC::HashTable::entry): - -2014-06-09 Mark Hahnenberg <mhahnenberg@apple.com> - - Build fix after r169703 - - * JavaScriptCore.xcodeproj/project.pbxproj: - -2014-06-05 Mark Hahnenberg <mhahnenberg@apple.com> - - Eagerly reify DOM prototype attributes - https://bugs.webkit.org/show_bug.cgi?id=133558 - - Reviewed by Oliver Hunt. - - This allows us to get rid of a lot of the additional overhead of pushing DOM attributes up into the prototype. - By eagerly reifying the custom getters and setters into the actual JSObject we avoid having to override - getOwnPropertySlot for all of the DOM prototypes, which is a lot of the overhead of doing property lookups on - DOM wrappers. - - * CMakeLists.txt: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * llint/LLIntData.cpp: - (JSC::LLInt::Data::performAssertions): - * llint/LowLevelInterpreter.asm: - * runtime/BatchedTransitionOptimizer.h: - (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): - * runtime/CustomGetterSetter.cpp: Added. - (JSC::callCustomSetter): - * runtime/CustomGetterSetter.h: Added. - (JSC::CustomGetterSetter::create): - (JSC::CustomGetterSetter::getter): - (JSC::CustomGetterSetter::setter): - (JSC::CustomGetterSetter::createStructure): - (JSC::CustomGetterSetter::CustomGetterSetter): - * runtime/JSCJSValue.cpp: - (JSC::JSValue::putToPrimitive): - * runtime/JSCJSValue.h: - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::isCustomGetterSetter): - * runtime/JSCell.h: - * runtime/JSCellInlines.h: - (JSC::JSCell::isCustomGetterSetter): - (JSC::JSCell::canUseFastGetOwnProperty): - * runtime/JSFunction.cpp: - (JSC::JSFunction::isHostOrBuiltinFunction): Deleted. - (JSC::JSFunction::isBuiltinFunction): Deleted. - * runtime/JSFunction.h: - * runtime/JSFunctionInlines.h: Inlined some random functions that appeared hot during profiling. - (JSC::JSFunction::isBuiltinFunction): - (JSC::JSFunction::isHostOrBuiltinFunction): - * runtime/JSObject.cpp: - (JSC::JSObject::put): - (JSC::JSObject::putDirectCustomAccessor): - (JSC::JSObject::fillGetterPropertySlot): - (JSC::JSObject::fillCustomGetterPropertySlot): - (JSC::JSObject::getOwnPropertySlotSlow): Deleted. - * runtime/JSObject.h: - (JSC::JSObject::hasCustomGetterSetterProperties): - (JSC::JSObject::convertToDictionary): - (JSC::JSObject::inlineGetOwnPropertySlot): - (JSC::JSObject::getOwnPropertySlotSlow): Inlined because it looked hot during profiling. - (JSC::JSObject::putOwnDataProperty): - (JSC::JSObject::putDirect): - (JSC::JSObject::putDirectWithoutTransition): - * runtime/JSType.h: - * runtime/Lookup.h: - (JSC::reifyStaticProperties): - * runtime/PropertyDescriptor.h: - (JSC::PropertyDescriptor::PropertyDescriptor): - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::nextOutOfLineStorageCapacity): Deleted. - (JSC::Structure::suggestedNewOutOfLineStorageCapacity): Deleted. - (JSC::Structure::get): Deleted. - * runtime/Structure.h: - (JSC::Structure::hasCustomGetterSetterProperties): - (JSC::Structure::setHasCustomGetterSetterProperties): - * runtime/StructureInlines.h: - (JSC::Structure::get): Inlined due to hotness. - (JSC::nextOutOfLineStorageCapacity): Inlined due to hotness. - (JSC::Structure::suggestedNewOutOfLineStorageCapacity): Inlined due to hotness. - * runtime/VM.cpp: - (JSC::VM::VM): - * runtime/VM.h: - * runtime/WriteBarrier.h: - (JSC::WriteBarrierBase<Unknown>::isCustomGetterSetter): - -2014-06-07 Mark Lam <mark.lam@apple.com> - - Structure should initialize its previousID in its constructor. - <https://webkit.org/b/133606> - - Reviewed by Mark Hahnenberg. - - Currently, the Structure constructor that takes a previous structure will - initialize its previousID to point to the previous structure's previousID. - This is incorrect. However, the caller of the Structure::create() factory - method (which instantiated the Structure) will later call setPreviousID() - to set the previousID to the correct previous structure. This makes the - code confusing to read and more error prone in that the structure relies - on client code to fix its invalid previousID. - - This patch fixes this by making the Structure constructor initialize - previousID correctly. - - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::addPropertyTransition): - (JSC::Structure::nonPropertyTransition): - * runtime/Structure.h: - * runtime/StructureInlines.h: - (JSC::Structure::create): - -2014-06-06 Andreas Kling <akling@apple.com> - - Indexed getters should return values directly on the PropertySlot. - <https://webkit.org/b/133586> - - Remove PropertySlot's custom index mode. - - Reviewed by Darin Adler. - - * runtime/JSObject.h: - (JSC::PropertySlot::getValue): - * runtime/PropertySlot.h: - (JSC::PropertySlot::setCustomIndex): Deleted. - -2014-06-04 Timothy Horton <timothy_horton@apple.com> - - iOS Debug build fix - - Rubber-stamped by Filip Pizlo. - - * Configurations/LLVMForJSC.xcconfig: - Dead-code strip the llvmForJSC library unconditionally, to work around <rdar://problem/16920916>. - -2014-06-04 Oliver Hunt <oliver@apple.com> - - ArrayIterator should not be exposed in Safari 8 - https://bugs.webkit.org/show_bug.cgi?id=133494 - - Reviewed by Michael Saboff. - - Separate out types that require constructor objects, and don't - include the iterator types in that list. - - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::reset): - * runtime/JSGlobalObject.h: - -2014-06-04 Filip Pizlo <fpizlo@apple.com> - - DFG::Safepoint::begin() should set m_didCallBegin before releasing the rightToRun lock, because otherwise, Safepoint::checkLivenessAndVisitChildren() may assert due to a race - https://bugs.webkit.org/show_bug.cgi?id=133525 - <rdar://problem/16790296> - - Reviewed by Oliver Hunt. - - * dfg/DFGSafepoint.cpp: - (JSC::DFG::Safepoint::begin): - -2014-06-03 Filip Pizlo <fpizlo@apple.com> - - LLVM soft-linking should be truly fail-silent - https://bugs.webkit.org/show_bug.cgi?id=133482 - - Reviewed by Mark Lam. - - * llvm/InitializeLLVMPOSIX.cpp: - (JSC::initializeLLVMPOSIX): Missing return statement in the dlsym() returning null case. - -2014-06-03 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> - - REGRESSION(r169092 and r169102): Skip failing JSC tests poperly on non-x86 Darwin platforms - https://bugs.webkit.org/show_bug.cgi?id=133149 - - Reviewed by Csaba Osztrogonác. - - * tests/mozilla/mozilla-tests.yaml: Skip js1_5/Regress/regress-159334.js only if the architecture isn't x86 and the host is Darwin. - -2014-05-31 Anders Carlsson <andersca@apple.com> - - Add a LazyNeverDestroyed class template and use it - https://bugs.webkit.org/show_bug.cgi?id=133425 - - Reviewed by Darin Adler. - - * dfg/DFGFunctionWhitelist.cpp: - (JSC::DFG::FunctionWhitelist::ensureGlobalWhitelist): - * dfg/DFGFunctionWhitelist.h: - -2014-05-28 Filip Pizlo <fpizlo@apple.com> - - DFG::DCEPhase inserts into an insertion set in reverse, causing hilarious basic block corruption if you kill a lot of NewArrays - https://bugs.webkit.org/show_bug.cgi?id=133368 - - Reviewed by Mark Lam. - - * dfg/DFGDCEPhase.cpp: - (JSC::DFG::DCEPhase::fixupBlock): Loop in the right order so that we insert in the right order. - * tests/stress/new-array-dead.js: Added. - (foo): - -2014-05-28 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix not-x86 32-bit. - - * llint/LowLevelInterpreter32_64.asm: - -2014-05-27 Filip Pizlo <fpizlo@apple.com> - - Arrayify neglects to inform the clobberizer that it might fire watchpoints - https://bugs.webkit.org/show_bug.cgi?id=133340 - - Reviewed by Mark Lam. - - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): Be honest. - * llint/LowLevelInterpreter32_64.asm: Profile the object, not its structure. - * tests/stress/arrayify-fires-watchpoint.js: Added. - (foo): - (test): - (makeObjectArray): - * tests/stress/arrayify-structure-bad-test.js: Added. - (foo): - (test): - -2014-05-27 Jon Lee <jonlee@apple.com> - - Update ENABLE(MEDIA_SOURCE) on Mac - https://bugs.webkit.org/show_bug.cgi?id=133141 - - Reviewed by Darin Adler. - - * Configurations/FeatureDefines.xcconfig: - -2014-05-27 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> - - Remove BLOB guards - https://bugs.webkit.org/show_bug.cgi?id=132863 - - Reviewed by Csaba Osztrogonác. - - * Configurations/FeatureDefines.xcconfig: - -2014-05-27 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> - - Allow building CMake based ports with WEB_REPLAY - https://bugs.webkit.org/show_bug.cgi?id=133154 - - Reviewed by Csaba Osztrogonác. - - * CMakeLists.txt: - -2014-05-25 Filip Pizlo <fpizlo@apple.com> - - Latest emscripten life benchmark is 4x slower because the DFG doesn't realize that arithmetic on booleans is a thing - https://bugs.webkit.org/show_bug.cgi?id=133136 - - Reviewed by Oliver Hunt. - - Some key concepts: - - - Except for the prediction propagation and type fixup phases, which are super early in - the pipeline, nobody has to know about the fact that booleans may flow into numerical - operations because there will just be a BooleanToNumber node that will take a value - and, if that value is a boolean, will convert it to the equivalent numerical value. It - will have a BooleanUse mode where it will also speculate that the input is a boolean - but it can also do UntypedUse in which case it will pass through any non-booleans. - This operation is very easy to model in all of the compiler tiers. - - - No changes to the baseline JIT. The Baseline JIT will still believe that boolean - inputs require taking the slow path and it will still report that it took slow path - for any such operations. The DFG will now be smart enough to ignore baseline JIT slow - path profiling on operations that were known to have had boolean inputs. That's a - little quirky, but it's probably easier than modifying the baseline JIT to track - booleans correctly. - - 4.1x speed-up on the emscripten "life" benchmark. Up to 10x speed-up on microbenchmarks. - - * bytecode/SpeculatedType.h: - (JSC::isInt32OrBooleanSpeculation): - (JSC::isInt32SpeculationForArithmetic): - (JSC::isInt32OrBooleanSpeculationForArithmetic): - (JSC::isInt32OrBooleanSpeculationExpectingDefined): - (JSC::isInt52Speculation): - (JSC::isMachineIntSpeculation): - (JSC::isFullNumberOrBooleanSpeculation): - (JSC::isFullNumberOrBooleanSpeculationExpectingDefined): - (JSC::isInt32SpeculationExpectingDefined): Deleted. - (JSC::isMachineIntSpeculationExpectingDefined): Deleted. - (JSC::isMachineIntSpeculationForArithmetic): Deleted. - (JSC::isBytecodeNumberSpeculationExpectingDefined): Deleted. - (JSC::isFullNumberSpeculationExpectingDefined): Deleted. - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGAllocator.h: - (JSC::DFG::Allocator<T>::indexOf): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::makeSafe): - (JSC::DFG::ByteCodeParser::makeDivSafe): - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::performNodeCSE): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGCommon.h: - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::fixIntConvertingEdge): - (JSC::DFG::FixupPhase::fixIntOrBooleanEdge): - (JSC::DFG::FixupPhase::fixDoubleOrBooleanEdge): - (JSC::DFG::FixupPhase::attemptToMakeIntegerAdd): - (JSC::DFG::FixupPhase::fixIntEdge): Deleted. - * dfg/DFGGraph.h: - (JSC::DFG::Graph::addSpeculationMode): - (JSC::DFG::Graph::valueAddSpeculationMode): - (JSC::DFG::Graph::arithAddSpeculationMode): - (JSC::DFG::Graph::addShouldSpeculateInt32): - (JSC::DFG::Graph::mulShouldSpeculateInt32): - (JSC::DFG::Graph::mulShouldSpeculateMachineInt): - (JSC::DFG::Graph::negateShouldSpeculateInt32): - (JSC::DFG::Graph::negateShouldSpeculateMachineInt): - (JSC::DFG::Graph::addImmediateShouldSpeculateInt32): - (JSC::DFG::Graph::mulImmediateShouldSpeculateInt32): Deleted. - * dfg/DFGNode.h: - (JSC::DFG::Node::sawBooleans): - (JSC::DFG::Node::shouldSpeculateInt32OrBoolean): - (JSC::DFG::Node::shouldSpeculateInt32ForArithmetic): - (JSC::DFG::Node::shouldSpeculateInt32OrBooleanForArithmetic): - (JSC::DFG::Node::shouldSpeculateInt32OrBooleanExpectingDefined): - (JSC::DFG::Node::shouldSpeculateMachineInt): - (JSC::DFG::Node::shouldSpeculateDouble): - (JSC::DFG::Node::shouldSpeculateNumberOrBoolean): - (JSC::DFG::Node::shouldSpeculateNumberOrBooleanExpectingDefined): - (JSC::DFG::Node::shouldSpeculateNumber): - (JSC::DFG::Node::canSpeculateInt32): - (JSC::DFG::Node::canSpeculateInt52): - (JSC::DFG::Node::sourceFor): - (JSC::DFG::Node::shouldSpeculateInt32ExpectingDefined): Deleted. - (JSC::DFG::Node::shouldSpeculateMachineIntForArithmetic): Deleted. - (JSC::DFG::Node::shouldSpeculateMachineIntExpectingDefined): Deleted. - (JSC::DFG::Node::shouldSpeculateDoubleForArithmetic): Deleted. - (JSC::DFG::Node::shouldSpeculateNumberExpectingDefined): Deleted. - * dfg/DFGNodeFlags.cpp: - (JSC::DFG::dumpNodeFlags): - * dfg/DFGNodeFlags.h: - (JSC::DFG::nodeMayOverflow): - (JSC::DFG::nodeMayNegZero): - (JSC::DFG::nodeCanSpeculateInt32): - (JSC::DFG::nodeCanSpeculateInt52): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::run): - (JSC::DFG::PredictionPropagationPhase::propagateToFixpoint): - (JSC::DFG::PredictionPropagationPhase::speculatedDoubleTypeForPrediction): - (JSC::DFG::PredictionPropagationPhase::propagate): - (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileValueToInt32): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): - (JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber): - * runtime/JSCJSValue.h: - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::asInt32ForArithmetic): - * tests/stress/max-boolean-exit.js: Added. - (foo): - (test): - * tests/stress/mul-boolean-exit.js: Added. - (foo): - (test): - * tests/stress/plus-boolean-exit.js: Added. - (foo): - (test): - * tests/stress/plus-boolean-or-double.js: Added. - (foo): - (test): - * tests/stress/plus-boolean-or-int.js: Added. - (foo): - (test): - -2014-05-26 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> - - Remove dead code from VM.cpp - https://bugs.webkit.org/show_bug.cgi?id=133284 - - Reviewed by Darin Adler. - - This workaround was added in r127505. Since the clang is the - only used compiler in this case, this workaround is obsolete. - - * runtime/VM.cpp: - (JSC::enableAssembler): - -2014-05-26 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> - - JSC CLoop warning fix - https://bugs.webkit.org/show_bug.cgi?id=133259 - - Reviewed by Darin Adler. - - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - -2014-05-24 Andreas Kling <akling@apple.com> - - Object.prototype.toString() should use cached strings for null/undefined. - <https://webkit.org/b/133261> - - Normally, when calling Object.prototype.toString() on a regular object, - we'd cache the result of the stringification on the object's structure, - making repeated calls fast. - - For null and undefined, we were not as smart. We'd instead construct a - new string with either "[object Null]" or "[object Undefined]" each time. - - This was exposed by Dromaeo's JS library tests, where some prototype.js - subtests generate millions of strings this way. - - This patch adds two VM-permanent cached strings to the SmallStrings. - Looks like ~10% speed-up on Dromaeo/jslib-traverse-prototype.html - - Reviewed by Darin Adler. - - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncToString): - * runtime/SmallStrings.cpp: - (JSC::SmallStrings::SmallStrings): - (JSC::SmallStrings::initializeCommonStrings): - (JSC::SmallStrings::visitStrongReferences): - * runtime/SmallStrings.h: - (JSC::SmallStrings::nullObjectString): - (JSC::SmallStrings::undefinedObjectString): - -2014-05-23 Mark Hahnenberg <mhahnenberg@apple.com> - - Remove operationCallGetter - - Rubber stamped by Filip Pizlo. - - Nobody calls this function. - - * JavaScriptCore.order: - * jit/JITOperations.cpp: - * jit/JITOperations.h: - -2014-05-23 Andreas Kling <akling@apple.com> - - Templatize GC's destructor invocation for dtor type. - <https://webkit.org/b/133231> - - Get rid of a branch in callDestructor() by templatizing it for - the DestructorType. Removed JSCell::methodTableForDestruction() - since this was the only call site and it was jumping through - a bunch of unnecessary hoops. - - Reviewed by Geoffrey Garen. - - * heap/MarkedBlock.cpp: - (JSC::MarkedBlock::callDestructor): - (JSC::MarkedBlock::specializedSweep): - * heap/MarkedBlock.h: - * runtime/JSCell.h: - * runtime/JSCellInlines.h: - (JSC::JSCell::methodTableForDestruction): Deleted. - -2014-05-23 Andreas Kling <akling@apple.com> - - Support inline caching of RegExpMatchesArray.length - <https://webkit.org/b/133234> - - Give RegExpMatchesArray.length the same treatment as JSArray in - repatch so we don't have to go out of line on every access. - - ~13% speed-up on Octane/regexp. - - Reviewed by Geoffrey Garen. - - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - * runtime/RegExpMatchesArray.h: - (JSC::isRegExpMatchesArray): - -2014-05-22 Mark Lam <mark.lam@apple.com> - - REGRESSION(r154797): Debugger crashes when stepping over an uncaught exception. - <https://webkit.org/b/133182> - - Reviewed by Oliver Hunt. - - Before r154797, we used to clear the VM exception before calling into the - debugger. After r154797, we don't. This patch will restore this clearing - of the exception before calling into the debugger. - - Also added assertions after returning from calls into the debugger to - ensure that the debugger did not introduce any exceptions. - - * interpreter/Interpreter.cpp: - (JSC::unwindCallFrame): - (JSC::Interpreter::unwind): - (JSC::Interpreter::debug): - - Fixed the assertion here. Interpreter::debug() should never be called - with a pending exception. Debugger callbacks for exceptions should be - handled by Interpreter::unwind() and Interpreter::unwindCallFrame(). - -2014-05-21 Filip Pizlo <fpizlo@apple.com> - - Store barrier elision should run after DCE in both the DFG path and the FTL path - https://bugs.webkit.org/show_bug.cgi?id=129718 - - Rubber stamped by Mark Hahnenberg. - - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::compileInThreadImpl): - -2014-05-21 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> - - [EFL] Add include path of compact_unwind_encoding.h if FTL JIT is enabled - https://bugs.webkit.org/show_bug.cgi?id=132907 - - Reviewed by Gyuyoung Kim. - - * CMakeLists.txt: - -2014-05-16 Martin Robinson <mrobinson@igalia.com> - - [CMake] Improve handling of LIB_INSTALL_DIR, EXEC_INSTALL_DIR, and LIBEXEC_INSTALL_DIR - https://bugs.webkit.org/show_bug.cgi?id=132819 - - Reviewed by Carlos Garcia Campos. - - * javascriptcoregtk.pc.in: Instead of using the special pkg-config variables, - use the common CMake ones directly. - -2014-05-21 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, roll out http://trac.webkit.org/changeset/169159. - - This was a unilateral change and wasn't properly reviewed. - - * tests/mozilla/mozilla-tests.yaml: - -2014-05-21 Antoine Quint <graouts@webkit.org> - - Array.prototype.find and findIndex should skip holes - https://bugs.webkit.org/show_bug.cgi?id=132658 - - Reviewed by Geoffrey Garen. - - Skip holes in the array when iterating such that callback isn't called. - - * builtins/Array.prototype.js: - (find): - (findIndex): - -2014-05-21 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> - - REGRESSION(r169092 and r169102): Skip failing JSC tests on ARM64 properly - https://bugs.webkit.org/show_bug.cgi?id=133149 - - Reviewed by Csaba Osztrogonác. - - * tests/mozilla/mozilla-tests.yaml: - -2014-05-20 Geoffrey Garen <ggaren@apple.com> - - Rolled out <http://trac.webkit.org/changeset/166184> - https://bugs.webkit.org/show_bug.cgi?id=133144 - - Reviewed by Gavin Barraclough. - - It caused a performance regression. - - * heap/BlockAllocator.cpp: - (JSC::BlockAllocator::blockFreeingThreadStartFunc): - -2014-05-20 Filip Pizlo <fpizlo@apple.com> - - DFG prediction propagation should agree with fixup phase over the return type of GetByVal - https://bugs.webkit.org/show_bug.cgi?id=133134 - - Reviewed by Mark Hahnenberg. - - Make prediction propagator use ArrayMode refinement to decide the return type. - - Also introduce a heap prediction intrinsic that allows us to test weird corner cases - like this. The only way we'll see a mismatch like this in the real world is probably - through a gnarly race condition. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * dfg/DFGNode.h: - (JSC::DFG::Node::setHeapPrediction): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * jsc.cpp: - (GlobalObject::finishCreation): - (functionFalse1): - (functionFalse2): - (functionUndefined1): - (functionUndefined2): - (functionFalse): Deleted. - (functionOtherFalse): Deleted. - (functionUndefined): Deleted. - * runtime/Intrinsic.h: - * tests/stress/get-by-val-double-predicted-int.js: Added. - (foo): - -2014-05-20 Mark Hahnenberg <mhahnenberg@apple.com> - - Watchdog timer should be lazily allocated - https://bugs.webkit.org/show_bug.cgi?id=133135 - - Reviewed by Geoffrey Garen. - - We incur a noticeable amount of overhead on some benchmarks due to checking if the Watchdog ever fired. - There is no reason to do this checking if we never activated the Watchdog, which can only be done through - JSContextGroupSetExecutionTimeLimit or JSContextGroupClearExecutionTimeLimit. - - By allocating the Watchdog lazily on the VM we can avoid all of the associated overhead when we don't use - these two API functions (which is true of most clients). - - * API/JSContextRef.cpp: - (JSContextGroupSetExecutionTimeLimit): - (JSContextGroupClearExecutionTimeLimit): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * interpreter/Interpreter.cpp: - (JSC::Interpreter::execute): - (JSC::Interpreter::executeCall): - (JSC::Interpreter::executeConstruct): - * jit/JITOpcodes.cpp: - (JSC::JIT::emit_op_loop_hint): - (JSC::JIT::emitSlow_op_loop_hint): - * jit/JITOperations.cpp: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * runtime/VM.h: - * runtime/Watchdog.cpp: - (JSC::Watchdog::Scope::Scope): Deleted. - (JSC::Watchdog::Scope::~Scope): Deleted. - * runtime/Watchdog.h: - (JSC::Watchdog::Scope::Scope): - (JSC::Watchdog::Scope::~Scope): - -2014-05-19 Mark Hahnenberg <mhahnenberg@apple.com> - - JSArray::shiftCountWith* could be more efficient - https://bugs.webkit.org/show_bug.cgi?id=133011 - - Reviewed by Geoffrey Garen. - - Our current implementations of shiftCountWithAnyIndexingType and shiftCountWithArrayStorage - are scared of the presence of any holes in the array. We can mitigate this somewhat by enabling - them to correctly handle holes, thus avoiding the slowest of slow paths in most cases. - - * runtime/ArrayStorage.h: - (JSC::ArrayStorage::indexingHeader): - (JSC::ArrayStorage::length): - (JSC::ArrayStorage::hasHoles): - * runtime/IndexingHeader.h: - (JSC::IndexingHeader::publicLength): - (JSC::IndexingHeader::from): - * runtime/JSArray.cpp: - (JSC::JSArray::shiftCountWithArrayStorage): - (JSC::JSArray::shiftCountWithAnyIndexingType): - (JSC::JSArray::unshiftCountWithArrayStorage): - * runtime/JSArray.h: - (JSC::JSArray::shiftCountForShift): - (JSC::JSArray::shiftCountForSplice): - (JSC::JSArray::shiftCount): - * runtime/Structure.cpp: - (JSC::Structure::holesRequireSpecialBehavior): - * runtime/Structure.h: - -2014-05-19 Filip Pizlo <fpizlo@apple.com> - - Test gardening: skip some failing tests on not-X86. - - * tests/mozilla/mozilla-tests.yaml: - -2014-05-19 Mark Lam <mark.lam@apple.com> - - operationOptimize() should defer the GC for a while. - <https://webkit.org/b/133103> - - Reviewed by Filip Pizlo. - - Currently, operationOptimize() only defers the GC until its end. As a result, - a GC may be triggered just before we return from operationOptimize(), and it may - jettison the optimize codeBlock that we're planning to OSR enter into when we - return from this function. This is because the OSR entry on-ramp code hasn't - been executed yet, and hence, there is not yet a reference to this new codeBlock - from the stack, and there won't be until we've had a chance to return out of - operationOptimize() to run the OSR entry on-ramp code. - - This issue is now fixed by using DeferGCForAWhile instead of DeferGC. This - ensures that the GC will be deferred until after the OSR entry on-ramp can be - executed. - - * jit/JITOperations.cpp: - -2014-05-19 Filip Pizlo <fpizlo@apple.com> - - Take care of some ARM64 test failures - https://bugs.webkit.org/show_bug.cgi?id=133090 - - Reviewed by Geoffrey Garen. - - Constant blinding on ARM64 cannot use the scratch register. - - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::convertInt32ToDouble): - (JSC::MacroAssembler::branchPtr): - (JSC::MacroAssembler::storePtr): - (JSC::MacroAssembler::store64): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::scratchRegisterForBlinding): - -2014-05-19 Tanay C <tanay.c@samsung.com> - - Removing some check-webkit-style warnings from ./dfg - https://bugs.webkit.org/show_bug.cgi?id=132854 - - Reviewed by Darin Adler. - - * dfg/DFGAbstractInterpreter.h: - * dfg/DFGAbstractValue.h: - * dfg/DFGBlockInsertionSet.h: - * dfg/DFGCommonData.h: - * dfg/DFGDominators.h: - * dfg/DFGGraph.h: - * dfg/DFGInPlaceAbstractState.h: - * dfg/DFGPredictionPropagationPhase.h: - -2014-05-18 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, remove bogus comment. We already made the FTL use our calling convention. - That was a long time ago. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileReturn): - -2014-05-18 Rik Cabanier <cabanier@adobe.com> - - support for navigator.hardwareConcurrency - https://bugs.webkit.org/show_bug.cgi?id=132588 - - Reviewed by Filip Pizlo. - - * Configurations/FeatureDefines.xcconfig: - -2014-05-16 Michael Saboff <msaboff@apple.com> - - Crash in JSC::Yarr::YarrGenerator<(JSC::Yarr::YarrJITCompileMode)0>::generatePatternCharacterFixed() due to WTF::CrashOnOverflow::overflowed + 9 - https://bugs.webkit.org/show_bug.cgi?id=133009 - - Reviewed by Oliver Hunt. - - If we determine that any alternative requires a minumum match size greater than - INT_MAX, we handle the match in the interpreter. - - Check to see if the pattern has unsigned lengths before invoking YARR JIT. - * runtime/RegExp.cpp: - (JSC::RegExp::compile): - (JSC::RegExp::compileMatchOnly): - - * tests/stress/large-regexp.js: New test added. - - Set m_containsUnsignedLengthPattern flag if any alternative's minimum length - doesn't fit in an int. - * yarr/YarrPattern.cpp: - (JSC::Yarr::YarrPatternConstructor::setupDisjunctionOffsets): - - Clear new m_containsUnsignedLengthPattern flag. - * yarr/YarrPattern.cpp: - (JSC::Yarr::YarrPattern::YarrPattern): - * yarr/YarrPattern.h: - (JSC::Yarr::YarrPattern::reset): - (JSC::Yarr::YarrPattern::containsUnsignedLengthPattern): - -2014-05-15 Mark Hahnenberg <mhahnenberg@apple.com> - - JSDOMWindow should not claim HasImpureGetOwnPropertySlot - https://bugs.webkit.org/show_bug.cgi?id=132918 - - Reviewed by Geoffrey Garen. - - * jit/Repatch.cpp: - (JSC::tryRepatchIn): We forgot to check for watchpoints when repatching "in". - -2014-05-15 Alex Christensen <achristensen@webkit.org> - - Add pointer lock to features without enabling it. - https://bugs.webkit.org/show_bug.cgi?id=132961 - - Reviewed by Sam Weinig. - - * Configurations/FeatureDefines.xcconfig: - Added ENABLE_POINTER_LOCK to list of features. - -2014-05-14 Mark Hahnenberg <mhahnenberg@apple.com> - - Inline caching for proxies clobbers baseGPR too early - https://bugs.webkit.org/show_bug.cgi?id=132916 - - Reviewed by Filip Pizlo. - - We clobber baseGPR prior to the Structure checks, so if any of the checks fail then the slow path - gets the target of the proxy rather than the proxy itself. We need to delay the clobbering of baseGPR - until we know the inline cache is going to succeed. - - * jit/Repatch.cpp: - (JSC::generateByIdStub): - -2014-05-14 Brent Fulgham <bfulgham@apple.com> - - [Win] Unreviewed build fix. - - * JavaScriptCore.vcxproj/JavaScriptCore.submit.sln: This solution - was missing commands to build LLInt portions of JSC. - * llint/LLIntData.cpp: 64-bit build fix. - -2014-05-14 Martin Hodovan <mhodovan.u-szeged@partner.samsung.com> - - ARM Traditional buildfix after r168776. - https://bugs.webkit.org/show_bug.cgi?id=132903 - - Reviewed by Darin Adler. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::abortWithReason): Added. - -2014-05-14 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> - - Remove CSS_STICKY_POSITION guards - https://bugs.webkit.org/show_bug.cgi?id=132676 - - Reviewed by Simon Fraser. - - * Configurations/FeatureDefines.xcconfig: - -2014-05-13 Filip Pizlo <fpizlo@apple.com> - - JIT breakpoints should be more informative - https://bugs.webkit.org/show_bug.cgi?id=132882 - - Reviewed by Oliver Hunt. - - Introduce the notion of an AbortReason, which is a nice enumeration of coded assertion - failure names. This means that all you need to figure out why the JIT SIGTRAP'd is to look - at that platform's abort reason register (r11 on X86-64 for example). - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * assembler/AbortReason.h: Added. - * assembler/AbstractMacroAssembler.h: - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::abortWithReason): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::abortWithReason): - * assembler/MacroAssemblerX86.h: - (JSC::MacroAssemblerX86::abortWithReason): - * assembler/MacroAssemblerX86_64.h: - (JSC::MacroAssemblerX86_64::abortWithReason): - * dfg/DFGSlowPathGenerator.h: - (JSC::DFG::SlowPathGenerator::generate): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::bail): - (JSC::DFG::SpeculativeJIT::compileCurrentBlock): - (JSC::DFG::SpeculativeJIT::compileMakeRope): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::emitAllocateBasicStorage): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::fillSpeculateCell): - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGThunks.cpp: - (JSC::DFG::osrEntryThunkGenerator): - * jit/AssemblyHelpers.cpp: - (JSC::AssemblyHelpers::jitAssertIsInt32): - (JSC::AssemblyHelpers::jitAssertIsJSInt32): - (JSC::AssemblyHelpers::jitAssertIsJSNumber): - (JSC::AssemblyHelpers::jitAssertIsJSDouble): - (JSC::AssemblyHelpers::jitAssertIsCell): - (JSC::AssemblyHelpers::jitAssertTagsInPlace): - (JSC::AssemblyHelpers::jitAssertHasValidCallFrame): - (JSC::AssemblyHelpers::jitAssertIsNull): - (JSC::AssemblyHelpers::jitAssertArgumentCountSane): - (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::checkStackPointerAlignment): - (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): Deleted. - * jit/JIT.h: - * jit/JITArithmetic.cpp: - (JSC::JIT::emitSlow_op_div): - * jit/JITOpcodes.cpp: - (JSC::JIT::emitSlow_op_loop_hint): - * jit/JITOpcodes32_64.cpp: - (JSC::JIT::privateCompileCTINativeCall): - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emit_op_get_by_val): - (JSC::JIT::compileGetDirectOffset): - (JSC::JIT::addStructureTransitionCheck): Deleted. - (JSC::JIT::testPrototype): Deleted. - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emit_op_get_by_val): - (JSC::JIT::compileGetDirectOffset): - * jit/RegisterPreservationWrapperGenerator.cpp: - (JSC::generateRegisterRestoration): - * jit/Repatch.cpp: - (JSC::addStructureTransitionCheck): - (JSC::linkClosureCall): - * jit/ThunkGenerators.cpp: - (JSC::emitPointerValidation): - (JSC::nativeForGenerator): - * yarr/YarrJIT.cpp: - (JSC::Yarr::YarrGenerator::generate): - -2014-05-13 peavo@outlook.com <peavo@outlook.com> - - [Win] Enum type with value zero is compatible with void*, potential cause of crashes. - https://bugs.webkit.org/show_bug.cgi?id=132772 - - Reviewed by Geoffrey Garen. - - Using the MSVC compiler, an instance of an enum type with value zero, is compatible with void* (see bug 132683 for a code example). - This has caused crashes on Windows on two occasions (bug 132683, and bug 121001). - This patch tries to prevent these type of crashes by using a type with explicit constructors instead of void*. - The void* parameter in the loadDouble and storeDouble methods are replaced with TrustedImmPtr. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::loadDouble): - (JSC::MacroAssemblerARM::storeDouble): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::loadDouble): - (JSC::MacroAssemblerARM64::storeDouble): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::loadDouble): - (JSC::MacroAssemblerARMv7::storeDouble): - * assembler/MacroAssemblerMIPS.h: - (JSC::MacroAssemblerMIPS::loadDouble): - (JSC::MacroAssemblerMIPS::storeDouble): - * assembler/MacroAssemblerSH4.h: - (JSC::MacroAssemblerSH4::loadDouble): - (JSC::MacroAssemblerSH4::storeDouble): - * assembler/MacroAssemblerX86.h: - (JSC::MacroAssemblerX86::storeDouble): - * assembler/MacroAssemblerX86Common.h: - (JSC::MacroAssemblerX86Common::absDouble): - (JSC::MacroAssemblerX86Common::negateDouble): - (JSC::MacroAssemblerX86Common::loadDouble): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::silentFill): - (JSC::DFG::compileClampDoubleToByte): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): - (JSC::DFG::SpeculativeJIT::compile): - * jit/AssemblyHelpers.cpp: - (JSC::AssemblyHelpers::purifyNaN): - * jit/JITInlines.h: - (JSC::JIT::emitLoadDouble): - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emitFloatTypedArrayGetByVal): - * jit/ThunkGenerators.cpp: - (JSC::floorThunkGenerator): - (JSC::roundThunkGenerator): - (JSC::powThunkGenerator): - -2014-05-12 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r168642. - https://bugs.webkit.org/show_bug.cgi?id=132839 - - Broke ARM build (Requested by jpfau on #webkit). - - Reverted changeset: - - "[Win] Enum type with value zero is compatible with void*, - potential cause of crashes." - https://bugs.webkit.org/show_bug.cgi?id=132772 - http://trac.webkit.org/changeset/168642 - -2014-05-12 peavo@outlook.com <peavo@outlook.com> - - [Win] Enum type with value zero is compatible with void*, potential cause of crashes. - https://bugs.webkit.org/show_bug.cgi?id=132772 - - Reviewed by Geoffrey Garen. - - Using the MSVC compiler, an instance of an enum type with value zero, is compatible with void* (see bug 132683 for a code example). - This has caused crashes on Windows on two occasions (bug 132683, and bug 121001). - This patch tries to prevent these type of crashes by using a type with explicit constructors instead of void*. - The void* parameter in the loadDouble and storeDouble methods are replaced with TrustedImmPtr. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::loadDouble): - (JSC::MacroAssemblerARM::storeDouble): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::loadDouble): - (JSC::MacroAssemblerARM64::storeDouble): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::loadDouble): - (JSC::MacroAssemblerARMv7::storeDouble): - * assembler/MacroAssemblerMIPS.h: - (JSC::MacroAssemblerMIPS::loadDouble): - (JSC::MacroAssemblerMIPS::storeDouble): - * assembler/MacroAssemblerSH4.h: - (JSC::MacroAssemblerSH4::loadDouble): - (JSC::MacroAssemblerSH4::storeDouble): - * assembler/MacroAssemblerX86.h: - (JSC::MacroAssemblerX86::storeDouble): - * assembler/MacroAssemblerX86Common.h: - (JSC::MacroAssemblerX86Common::absDouble): - (JSC::MacroAssemblerX86Common::negateDouble): - (JSC::MacroAssemblerX86Common::loadDouble): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::silentFill): - (JSC::DFG::compileClampDoubleToByte): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): - (JSC::DFG::SpeculativeJIT::compile): - * jit/AssemblyHelpers.cpp: - (JSC::AssemblyHelpers::purifyNaN): - * jit/JITInlines.h: - (JSC::JIT::emitLoadDouble): - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emitFloatTypedArrayGetByVal): - * jit/ThunkGenerators.cpp: - (JSC::floorThunkGenerator): - (JSC::roundThunkGenerator): - (JSC::powThunkGenerator): - -2014-05-12 Andreas Kling <akling@apple.com> - - 0.4% of PLT3 in JSCell::structure() below JSObject::visitChildren(). - <https://webkit.org/b/132828> - <rdar://problem/16886285> - - Reviewed by Michael Saboff. - - * runtime/JSObject.cpp: - (JSC::JSObject::visitButterfly): - (JSC::JSObject::visitChildren): - - Use JSCell::structure(VM&) to reduce the number of hoops we jump - through to find Structures during marking. - -2014-05-12 László Langó <llango.u-szeged@partner.samsung.com> - - [cmake] Add missing FTL source files to the build system. - - Reviewed by Csaba Osztrogonác. - - * CMakeLists.txt: - -2014-05-09 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Allow Remote Inspector to entitlement check UIProcess through WebProcess - https://bugs.webkit.org/show_bug.cgi?id=132409 - - Reviewed by Timothy Hatcher. - - Proxy applications are applications which hold WebViews for other - applications. The WebProcess (Web Content Service) is a proxy application. - For legacy reasons we were supporting a scenario where proxy applications - could potentially host WebViews for more then one other application. That - was never the case for WebProcess and it is now a scenario we don't need - to worry about supporting. - - With this change, a proxy application more naturally only holds WebViews - for a single parent / host application. The proxy process can set the - parent pid / audit_token data on the RemoteInspector singleton, and - that data will be sent on to webinspectord later on to be validated. - In the WebProcess<->UIProcess relationship that information is known - and set immediately. In the Legacy iOS case that information is set - soon after, but not immediately known at the point the WebView is created. - - This allows us to simplify the RemoteInspectorDebuggable interface. - We no longer need a pid per-Debuggable. - - * inspector/remote/RemoteInspector.h: - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::RemoteInspector): - (Inspector::RemoteInspector::setParentProcessInformation): - (Inspector::RemoteInspector::xpcConnectionReceivedMessage): - (Inspector::RemoteInspector::listingForDebuggable): - (Inspector::RemoteInspector::receivedProxyApplicationSetupMessage): - Handle new proxy application setup message, and provide an API - for a proxy application to set the parent process information. - - * inspector/remote/RemoteInspectorConstants.h: - New setup and response message for proxy applications to pass - their parent / host application information to webinspectord. - - * inspector/remote/RemoteInspectorDebuggable.cpp: - (Inspector::RemoteInspectorDebuggable::info): - * inspector/remote/RemoteInspectorDebuggable.h: - (Inspector::RemoteInspectorDebuggableInfo::RemoteInspectorDebuggableInfo): - (Inspector::RemoteInspectorDebuggableInfo::hasParentProcess): Deleted. - pid per debuggable is no longer needed. - -2014-05-09 Mark Hahnenberg <mhahnenberg@apple.com> - - JSDOMWindow should disable property caching after a certain point - https://bugs.webkit.org/show_bug.cgi?id=132751 - - Reviewed by Filip Pizlo. - - This is part of removing HasImpureGetOwnPropertySlot from JSDOMWindow. After the lookup in the static - hash table for JSDOMWindow fails we want to disable property caching even if the code that follows thinks - that it has provided a cacheable value. - - * runtime/PropertySlot.h: - (JSC::PropertySlot::PropertySlot): - (JSC::PropertySlot::isCacheable): - (JSC::PropertySlot::disableCaching): - -2014-05-09 Andreas Kling <akling@apple.com> - - 8.8% spent in Object.prototype.hasOwnProperty() on sbperftest. - <https://webkit.org/b/132749> - - Leverage the fast-resolve-to-AtomicString optimization for JSRopeString - in Object.prototype.* by using JSString::toIdentifier() in the cases where - we are converting JSString -> String -> Identifier. - - This brings time spent in hasOwnProperty() from 8.8% to 1.3% on - "The Great HTML5 Gaming Performance Test: 2014 edition" - <http://www.scirra.com/demos/c2/sbperftest/> - - Reviewed by Oliver Hunt. - - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncHasOwnProperty): - (JSC::objectProtoFuncDefineGetter): - (JSC::objectProtoFuncDefineSetter): - (JSC::objectProtoFuncLookupGetter): - (JSC::objectProtoFuncLookupSetter): - -2014-05-08 Mark Hahnenberg <mhahnenberg@apple.com> - - JSDOMWindow should have a WatchpointSet to fire on window close - https://bugs.webkit.org/show_bug.cgi?id=132721 - - Reviewed by Filip Pizlo. - - This patch allows us to reset the inline caches that assumed they could skip - the first part of JSDOMWindow::getOwnPropertySlot that checks if the window has - been closed. This is part of getting rid of HasImpureGetOwnPropertySlot on JSDOMWindow. - - PropertySlot now accepts a WatchpointSet which the inline cache code can look for - to see if it should create a new Watchpoint for that particular inline cache site. - - * bytecode/Watchpoint.h: - * jit/Repatch.cpp: - (JSC::generateByIdStub): - (JSC::tryBuildGetByIDList): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - * runtime/PropertySlot.h: - (JSC::PropertySlot::PropertySlot): - (JSC::PropertySlot::watchpointSet): - (JSC::PropertySlot::setWatchpointSet): - -2014-05-09 Tanay C <tanay.c@samsung.com> - - Fix build warning (uninitialized variable) in DFGFixupPhase.cpp - https://bugs.webkit.org/show_bug.cgi?id=132331 - - Reviewed by Darin Adler. - - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): - -2014-05-09 peavo@outlook.com <peavo@outlook.com> - - [Win] Crash when enabling DFG JIT. - https://bugs.webkit.org/show_bug.cgi?id=132683 - - Reviewed by Geoffrey Garen. - - On windows, using register GPRInfo::regT0 as parameter to e.g. JIT::storeDouble(..., GPRInfo::regT0)), - results in a call to JIT::storeDouble(FPRegisterID src, const void* address), - where the address parameter gets the value of GPRInfo::regT0, which is 0 (eax on Windows). - This causes the register to be written to address 0, hence the crash. - - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): Use address in regT0 as parameter. - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): Ditto. - -2014-05-09 Martin Hodovan <mhodovan.u-szeged@partner.samsung.com> - - REGRESSION(r167094): JSC crashes on ARM Traditional - https://bugs.webkit.org/show_bug.cgi?id=132738 - - Reviewed by Zoltan Herczeg. - - PC is two instructions ahead of the current instruction - on ARM Traditional, so the distance is 8 bytes not 2. - - * llint/LowLevelInterpreter.asm: - -2014-05-09 Alberto Garcia <berto@igalia.com> - - jsmin.py license header confusing, mentions non-free license - https://bugs.webkit.org/show_bug.cgi?id=123665 - - Reviewed by Darin Adler. - - Pull the most recent version from upstream, which has a clear - license. - - * inspector/scripts/jsmin.py: - -2014-05-08 Mark Hahnenberg <mhahnenberg@apple.com> - - Base case for get-by-id inline cache doesn't check for HasImpureGetOwnPropertySlot - https://bugs.webkit.org/show_bug.cgi?id=132695 - - Reviewed by Filip Pizlo. - - We check in the case where we're accessing something other than the base object (e.g. the prototype), - but we fail to do so for the base object. - - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - (JSC::tryBuildGetByIDList): - * jsc.cpp: Added some infrastructure to support this test. We don't currently trigger this bug anywhere in WebKit - because all of the values that are returned that could be impure are set to uncacheable anyways. - (WTF::ImpureGetter::ImpureGetter): - (WTF::ImpureGetter::createStructure): - (WTF::ImpureGetter::create): - (WTF::ImpureGetter::finishCreation): - (WTF::ImpureGetter::getOwnPropertySlot): - (WTF::ImpureGetter::visitChildren): - (WTF::ImpureGetter::setDelegate): - (GlobalObject::finishCreation): - (functionCreateImpureGetter): - (functionSetImpureGetterDelegate): - * tests/stress/impure-get-own-property-slot-inline-cache.js: Added. - (foo): - -2014-05-08 Filip Pizlo <fpizlo@apple.com> - - deleteAllCompiledCode() shouldn't use the suspension worklist - https://bugs.webkit.org/show_bug.cgi?id=132708 - - Reviewed by Mark Hahnenberg. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::setOptimizationThresholdBasedOnCompilationResult): - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::isStillValid): - * heap/Heap.cpp: - (JSC::Heap::deleteAllCompiledCode): - -2014-05-08 Filip Pizlo <fpizlo@apple.com> - - SSA conversion should delete PhantomLocals for captured variables - https://bugs.webkit.org/show_bug.cgi?id=132693 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGCommon.cpp: - (JSC::DFG::startCrashing): Parallel JIT and a JIT bug means that we man dump IR in parallel. This is the workaround. This patch uses it in all of the places where we dump IR and crash. - * dfg/DFGCommon.h: - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): Use the workaround. - * dfg/DFGLivenessAnalysisPhase.cpp: - (JSC::DFG::LivenessAnalysisPhase::run): Use the workaround. - * dfg/DFGSSAConversionPhase.cpp: - (JSC::DFG::SSAConversionPhase::run): Fix the bug - it's true that PhantomLocal for captured variables doesn't need anything done to it, but it's wrong that we didn't delete it outright. - * dfg/DFGValidate.cpp: Use the workaround. - * tests/stress/phantom-local-captured-but-not-flushed-to-ssa.js: Added. - (foo): - (bar): - -2014-05-07 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r168451. - https://bugs.webkit.org/show_bug.cgi?id=132670 - - Not a speed-up, just do what other compilers do. (Requested by - kling on #webkit). - - Reverted changeset: - - "[X86] Emit BT instruction for single-bit tests." - https://bugs.webkit.org/show_bug.cgi?id=132650 - http://trac.webkit.org/changeset/168451 - -2014-05-07 Filip Pizlo <fpizlo@apple.com> - - Make Executable::clearCode() actually clear all of the entrypoints, and - clean up some other FTL-related calling convention stuff. - <rdar://problem/16720172> - - Rubber stamped by Mark Hahnenberg. - - * dfg/DFGOperations.cpp: - * dfg/DFGOperations.h: - * dfg/DFGWorklist.cpp: - (JSC::DFG::Worklist::Worklist): - (JSC::DFG::Worklist::finishCreation): - (JSC::DFG::Worklist::create): - (JSC::DFG::ensureGlobalDFGWorklist): - (JSC::DFG::ensureGlobalFTLWorklist): - * dfg/DFGWorklist.h: - * heap/CodeBlockSet.cpp: - (JSC::CodeBlockSet::dump): - * heap/CodeBlockSet.h: - * runtime/Executable.cpp: - (JSC::ExecutableBase::clearCode): - -2014-05-07 Andreas Kling <akling@apple.com> - - [X86] Emit BT instruction for single-bit tests. - <https://webkit.org/b/132650> - - Implement test-bit-and-branch slightly more efficiently by using - BT + JC/JNC instead of TEST + JZ/JNZ when we're only testing for - a single bit. - - Reviewed by Michael Saboff. - - * assembler/MacroAssemblerX86Common.h: - (JSC::MacroAssemblerX86Common::singleBitIndex): - (JSC::MacroAssemblerX86Common::branchTest32): - * assembler/X86Assembler.h: - (JSC::X86Assembler::bt_i8r): - (JSC::X86Assembler::bt_i8m): - -2014-05-07 Mark Lam <mark.lam@apple.com> - - REGRESSION(r166678): Dromaeo/cssquery-dojo.html crashes regularly. - <https://webkit.org/b/131356> - - Reviewed by Geoffrey Garen. - - The issue is that GC needs to be made aware of writes to m_inferredValue - in the VariableWatchpointSet, but was not. As a result, if a JSCell* - is written to a VariableWatchpointSet m_inferredValue, and that JSCell - does not survive an eden GC shortly after, we will end up with a stale - JSCell pointer left in the m_inferredValue. - - This issue can be detected more easily by running Dromaeo/cssquery-dojo.html - using DumpRenderTree with the VM heap in zombie mode. - - The fix is to change VariableWatchpointSet m_inferredValue to type - WriteBarrier<Unknown> and ensure that VariableWatchpointSet::notifyWrite() - is executed by all the execution engines so that the WriteBarrier semantics - are honored. - - We still check if the value to be written is the same as the one in the - inferredValue. We'll by-pass calling the slow path notifyWrite() if the - values are the same. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::CodeBlock): - - need to pass the symbolTable to prepareToWatch() because it will be needed - for instantiating the VariableWatchpointSet in prepareToWatch(). - - * bytecode/VariableWatchpointSet.h: - (JSC::VariableWatchpointSet::VariableWatchpointSet): - - VariableWatchpointSet now tracks its owner symbol table for its m_inferredValue - write barrier, and yes, m_inferredValue is now of type WriteBarrier<Unknown>. - (JSC::VariableWatchpointSet::inferredValue): - (JSC::VariableWatchpointSet::invalidate): - (JSC::VariableWatchpointSet::finalizeUnconditionally): - (JSC::VariableWatchpointSet::addressOfInferredValue): - (JSC::VariableWatchpointSet::notifyWrite): Deleted. - * bytecode/VariableWatchpointSetInlines.h: Added. - (JSC::VariableWatchpointSet::notifyWrite): - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::cellConstant): - - Added an assert in case we try to make constants of zombified JSCells again. - - * dfg/DFGOperations.cpp: - * dfg/DFGOperations.h: - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::callOperation): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - - We now let the slow path handle the cases when the VariableWatchpointSet is - in state ClearWatchpoint and IsWatched, and the slow path will ensure that - we handle the needed write barrier semantics correctly. - We will by-pass the slow path if the value being written is the same as the - inferred value. - - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite): - - Let the slow path handle the cases when the VariableWatchpointSet is - in state ClearWatchpoint and IsWatched. - We will by-pass the slow path if the value being written is the same as the - inferred value. - - * heap/Heap.cpp: - (JSC::Zombify::operator()): - - Use a different value for the zombified bits (to distinguish it from 0xbbadbeef - which is used everywhere else). - * heap/Heap.h: - (JSC::Heap::isZombified): - - Provide a convenience test function to check if JSCells are zombified. This is - currently only used in an assertion in the DFG bytecode parser, but the intent - it that we'll apply this test in other strategic places later to help with early - detection of usage of GC'ed objects when we run in zombie mode. - - * jit/JITOpcodes.cpp: - (JSC::JIT::emitSlow_op_captured_mov): - * jit/JITOperations.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emitNotifyWrite): - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emitNotifyWrite): - (JSC::JIT::emitSlow_op_put_to_scope): - - Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet - is in state ClearWatchpoint and IsWatched. - We will by-pass the slow path if the value being written is the same as the - inferred value. - - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: - - Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet - is in state ClearWatchpoint and IsWatched. - We will by-pass the slow path if the value being written is the same as the - inferred value. - - * runtime/CommonSlowPaths.cpp: - - * runtime/JSCJSValue.h: Fixed some typos in the comments. - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::addGlobalVar): - (JSC::JSGlobalObject::addFunction): - * runtime/JSSymbolTableObject.h: - (JSC::symbolTablePut): - (JSC::symbolTablePutWithAttributes): - * runtime/SymbolTable.cpp: - (JSC::SymbolTableEntry::prepareToWatch): - (JSC::SymbolTableEntry::notifyWriteSlow): - * runtime/SymbolTable.h: - (JSC::SymbolTableEntry::notifyWrite): - -2014-05-06 Michael Saboff <msaboff@apple.com> - - Unreviewd build fix for C-LOOP after r168396. - - * runtime/TestRunnerUtils.cpp: - (JSC::optimizeNextInvocation): Wrapped actual call inside #if ENABLE(JIT) - -2014-05-06 Michael Saboff <msaboff@apple.com> - - Add test for deleteAllCompiledCode - https://bugs.webkit.org/show_bug.cgi?id=132632 - - Reviewed by Phil Pizlo. - - Added two new hooks to jsc, one to call Heap::deleteAllCompiledCode() and - the other to call CodeBlock::optimizeNextInvocation(). Used these two hooks - to write a test that will queue up loads of DFG compiles and then call - Heap::deleteAllCompiledCode() to make sure that it can handle compiled - code as well as code being compiled. - - * jsc.cpp: - (GlobalObject::finishCreation): - (functionDeleteAllCompiledCode): - (functionOptimizeNextInvocation): - * runtime/TestRunnerUtils.cpp: - (JSC::optimizeNextInvocation): - * runtime/TestRunnerUtils.h: - * tests/stress/deleteAllCompiledCode.js: Added. - (functionList): - (runTest): - -2014-05-06 Andreas Kling <akling@apple.com> - - JSString::toAtomicString() should return AtomicString. - <https://webkit.org/b/132627> - - Remove premature optimization where I was trying to avoid refcount - churn when returning an already atomicized String. - - Instead of using reinterpret_cast to mangle the String member into - a const AtomicString& return value, just return AtomicString. - - Reviewed by Geoff Garen. - - * runtime/JSString.h: - (JSC::JSString::toAtomicString): - -2014-05-06 Mark Hahnenberg <mhahnenberg@apple.com> - - Roll out r167889 - - Rubber stamped by Geoff Garen. - - It broke some websites. - - * runtime/JSPropertyNameIterator.cpp: - (JSC::JSPropertyNameIterator::create): - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::hasDeletedOffset): - (JSC::PropertyTable::hadDeletedOffset): Deleted. - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::materializePropertyMap): - (JSC::Structure::removePropertyTransition): - (JSC::Structure::changePrototypeTransition): - (JSC::Structure::despecifyFunctionTransition): - (JSC::Structure::attributeChangeTransition): - (JSC::Structure::toDictionaryTransition): - (JSC::Structure::preventExtensionsTransition): - (JSC::Structure::addPropertyWithoutTransition): - (JSC::Structure::removePropertyWithoutTransition): - (JSC::Structure::pin): - (JSC::Structure::pinAndPreventTransitions): Deleted. - * runtime/Structure.h: - * runtime/StructureInlines.h: - (JSC::Structure::setEnumerationCache): - (JSC::Structure::propertyTable): - (JSC::Structure::checkOffsetConsistency): - (JSC::Structure::hadDeletedOffsets): Deleted. - * tests/stress/for-in-after-delete.js: - (foo): Deleted. - -2014-05-05 Andreas Kling <akling@apple.com> - - Fix debug build. - - * runtime/JSCellInlines.h: - (JSC::JSCell::fastGetOwnProperty): - -2014-05-05 Andreas Kling <akling@apple.com> - - Optimize GetByVal when subscript is a rope string. - <https://webkit.org/b/132590> - - Use JSString::toIdentifier() in the various GetByVal implementations - to try and avoid allocating extra strings. - - Added canUseFastGetOwnProperty() and wrap calls to fastGetOwnProperty() - in that, to avoid calling JSString::value() which always resolves ropes - into new strings and de-optimizes subsequent toIdentifier() calls. - - My iMac says ~9% progression on Dromaeo/dom-attr.html - - Reviewed by Phil Pizlo. - - * dfg/DFGOperations.cpp: - * jit/JITOperations.cpp: - (JSC::getByVal): - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::getByVal): - * runtime/JSCell.h: - * runtime/JSCellInlines.h: - (JSC::JSCell::fastGetOwnProperty): - (JSC::JSCell::canUseFastGetOwnProperty): - -2014-05-05 Andreas Kling <akling@apple.com> - - REGRESSION (r168256): ASSERTION FAILED: (buffer + m_length) == position loading vanityfair.com article. - <https://webkit.org/b/168256> - <rdar://problem/16816316> - - Make resolveRopeSlowCase8() behave like its 16-bit counterpart and not - clear the fibers. The caller takes care of this. - - Test: fast/dom/getElementById-with-rope-string-arg.html - - Reviewed by Geoffrey Garen. - - * runtime/JSString.cpp: - (JSC::JSRopeString::resolveRopeSlowCase8): - -2014-05-05 Michael Saboff <msaboff@apple.com> - - REGRESSION: RELEASE_ASSERT in CodeBlock::baselineVersion @ cnn.com - https://bugs.webkit.org/show_bug.cgi?id=132581 - - Reviewed by Filip Pizlo. - - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::isStillValid): Check that the alternative codeBlock we - started compiling for is still the same at the end of compilation. - Also did some minor restructuring. - -2014-05-05 Andreas Kling <akling@apple.com> - - Optimize PutByVal when subscript is a rope string. - <https://webkit.org/b/132572> - - Add a JSString::toIdentifier() that is smarter when the JSString is - really a rope string. Use this in baseline & DFG's PutByVal to avoid - allocating new StringImpls that we immediately deduplicate anyway. - - Reviewed by Antti Koivisto. - - * dfg/DFGOperations.cpp: - (JSC::DFG::operationPutByValInternal): - * jit/JITOperations.cpp: - * runtime/JSString.h: - (JSC::JSString::toIdentifier): - -2014-05-05 Andreas Kling <akling@apple.com> - - Remove two now-incorrect assertions after r168256. - - * runtime/JSString.cpp: - (JSC::JSRopeString::resolveRopeSlowCase8): - (JSC::JSRopeString::resolveRopeSlowCase): - -2014-05-04 Andreas Kling <akling@apple.com> - - Optimize JSRopeString for resolving directly to AtomicString. - <https://webkit.org/b/132548> - - If we know that the JSRopeString we are resolving is going to be used - as an AtomicString, we can try to avoid creating a new string. - - We do this by first resolving the rope into a stack buffer, and using - that buffer as a key into the AtomicString table. If there is already - an AtomicString with the same characters, we reuse that instead of - constructing a new StringImpl. - - JSString gains these two public functions: - - - AtomicString toAtomicString() - - Returns an AtomicString, tries to avoid allocating a new string - if possible. - - - AtomicStringImpl* toExistingAtomicString() - - Returns a non-null AtomicStringImpl* if one already exists in the - AtomicString table. If none is found, the rope is left unresolved. - - Reviewed by Filip Pizlo. - - * runtime/JSString.cpp: - (JSC::JSRopeString::resolveRopeInternal8): - (JSC::JSRopeString::resolveRopeInternal16): - (JSC::JSRopeString::resolveRopeToAtomicString): - (JSC::JSRopeString::clearFibers): - (JSC::JSRopeString::resolveRopeToExistingAtomicString): - (JSC::JSRopeString::resolveRope): - (JSC::JSRopeString::outOfMemory): - * runtime/JSString.h: - (JSC::JSString::toAtomicString): - (JSC::JSString::toExistingAtomicString): - -2014-05-04 Andreas Kling <akling@apple.com> - - Unreviewed, rolling out r168254. - - Very crashy on debug JSC tests. - - Reverted changeset: - - "jsSubstring() should be lazy" - https://bugs.webkit.org/show_bug.cgi?id=132556 - http://trac.webkit.org/changeset/168254 - -2014-05-04 Filip Pizlo <fpizlo@apple.com> - - jsSubstring() should be lazy - https://bugs.webkit.org/show_bug.cgi?id=132556 - - Reviewed by Andreas Kling. - - jsSubstring() is now lazy by using a special rope that is a substring instead of a - concatenation. To make this patch super simple, we require that a substring's base is - never a rope. Hence, when resolving a rope, we either go down a non-recursive substring - path, or we go down a concatenation path which may see exactly one level of substrings in - its fibers. - - This is up to a 50% speed-up on microbenchmarks and a 10% speed-up on Octane/regexp. - - * heap/MarkedBlock.cpp: - (JSC::MarkedBlock::specializedSweep): - * runtime/JSString.cpp: - (JSC::JSRopeString::visitFibers): - (JSC::JSRopeString::resolveRope): - (JSC::JSRopeString::resolveRopeSlowCase8): - (JSC::JSRopeString::resolveRopeSlowCase): - (JSC::JSRopeString::outOfMemory): - * runtime/JSString.h: - (JSC::JSRopeString::finishCreation): - (JSC::JSRopeString::append): - (JSC::JSRopeString::create): - (JSC::JSRopeString::offsetOfFibers): - (JSC::JSRopeString::fiber): - (JSC::JSRopeString::substringBase): - (JSC::JSRopeString::substringOffset): - (JSC::JSRopeString::substringSentinel): - (JSC::JSRopeString::isSubstring): - (JSC::jsSubstring): - * runtime/RegExpMatchesArray.cpp: - (JSC::RegExpMatchesArray::reifyAllProperties): - * runtime/StringPrototype.cpp: - (JSC::stringProtoFuncSubstring): - -2014-05-02 Michael Saboff <msaboff@apple.com> - - "arm64 function not 4-byte aligned" warnings when building JSC - https://bugs.webkit.org/show_bug.cgi?id=132495 - - Reviewed by Geoffrey Garen. - - Added ".align 4" for both ARM Thumb2 and ARM 64 to silence the linker. - - * llint/LowLevelInterpreter.cpp: - -2014-05-02 Mark Hahnenberg <mhahnenberg@apple.com> - - Fix cloop build after r168178 - - * bytecode/CodeBlock.cpp: - -2014-05-01 Mark Hahnenberg <mhahnenberg@apple.com> - - Add a DFG function whitelist - https://bugs.webkit.org/show_bug.cgi?id=132437 - - Reviewed by Geoffrey Garen. - - Often times when debugging, using bytecode ranges isn't enough to narrow down to the - particular DFG block that's causing issues. This patch adds the ability to whitelist - specific functions specified in a file to enable further filtering without having to recompile. - - * CMakeLists.txt: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGCapabilities.cpp: - (JSC::DFG::isSupported): - (JSC::DFG::mightInlineFunctionForCall): - (JSC::DFG::mightInlineFunctionForClosureCall): - (JSC::DFG::mightInlineFunctionForConstruct): - * dfg/DFGFunctionWhitelist.cpp: Added. - (JSC::DFG::FunctionWhitelist::ensureGlobalWhitelist): - (JSC::DFG::FunctionWhitelist::FunctionWhitelist): - (JSC::DFG::FunctionWhitelist::parseFunctionNamesInFile): - (JSC::DFG::FunctionWhitelist::contains): - * dfg/DFGFunctionWhitelist.h: Added. - * runtime/Options.cpp: - (JSC::parse): - (JSC::Options::dumpOption): - * runtime/Options.h: - -2014-05-02 Filip Pizlo <fpizlo@apple.com> - - DFGAbstractInterpreter should not claim Int52 arithmetic creates Int52s - https://bugs.webkit.org/show_bug.cgi?id=132446 - - Reviewed by Mark Hahnenberg. - - Basically any arithmetic operation can turn an Int52 into an Int32 or vice-versa, and - our modeling of Int52Rep nodes is such that they can have either Int32 or Int52 type - to indicate a bound on the value. This is useful for knowing, for example, that - Int52Rep(Int32:) returns a value that cannot be outside the Int32 range. Also, - ValueRep(Int52Rep:) uses this to determine whether it may return a double or an int. - But this means that all arithmetic operations must be careful to note that they may - turn Int32 inputs into an Int52 output or vice-versa, as these new tests show. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::makeSafe): - * tests/stress/int52-ai-add-then-filter-int32.js: Added. - (foo): - * tests/stress/int52-ai-mul-and-clean-neg-zero-then-filter-int32.js: Added. - (foo): - * tests/stress/int52-ai-mul-then-filter-int32-directly.js: Added. - (foo): - * tests/stress/int52-ai-mul-then-filter-int32.js: Added. - (foo): - * tests/stress/int52-ai-neg-then-filter-int32.js: Added. - (foo): - * tests/stress/int52-ai-sub-then-filter-int32.js: Added. - (foo): - -2014-05-01 Geoffrey Garen <ggaren@apple.com> - - JavaScriptCore fails to build with some versions of clang - https://bugs.webkit.org/show_bug.cgi?id=132436 - - Reviewed by Anders Carlsson. - - * runtime/ArgumentsIteratorConstructor.cpp: Since we call - putDirectWithoutTransition, and it calls putWillGrowOutOfLineStorage, - and both are marked inline, it's valid for the compiler to decide - to inline both and emit neither in the binary. Therefore, we need - both inline definitions to be available in the translation unit at - compile time, or we'll try to link against a function that doesn't exist. - -2014-05-01 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r167964. - https://bugs.webkit.org/show_bug.cgi?id=132431 - - Memory improvements should not regress memory usage (Requested - by olliej on #webkit). - - Reverted changeset: - - "Don't hold on to parameter BindingNodes forever" - https://bugs.webkit.org/show_bug.cgi?id=132360 - http://trac.webkit.org/changeset/167964 - -2014-05-01 Filip Pizlo <fpizlo@apple.com> - - Fix trivial debug-only race-that-crashes in CallLinkStatus and explain why the remaining races are totally awesome - https://bugs.webkit.org/show_bug.cgi?id=132427 - - Reviewed by Mark Hahnenberg. - - * bytecode/CallLinkStatus.cpp: - (JSC::CallLinkStatus::computeFor): - -2014-04-30 Simon Fraser <simon.fraser@apple.com> - - Remove ENABLE_PLUGIN_PROXY_FOR_VIDEO - https://bugs.webkit.org/show_bug.cgi?id=132396 - - Reviewed by Eric Carlson. - - Remove ENABLE_PLUGIN_PROXY_FOR_VIDEO and related code. - - * Configurations/FeatureDefines.xcconfig: - -2014-04-30 Filip Pizlo <fpizlo@apple.com> - - Argument flush formats should not be presumed to be JSValue since 'this' is weird - https://bugs.webkit.org/show_bug.cgi?id=132404 - - Reviewed by Michael Saboff. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileCurrentBlock): Don't assume that arguments are flushed as JSValue. Use the logic for locals instead. - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): SetArgument "changes" the format because before this we wouldn't know we had arguments. - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): Ditto. - * dfg/DFGValueSource.cpp: - (JSC::DFG::ValueSource::dumpInContext): Make this easier to dump. - * dfg/DFGValueSource.h: - (JSC::DFG::ValueSource::operator!): Make this easier to dump because Operands<T> uses T::operator!(). - * ftl/FTLOSREntry.cpp: - (JSC::FTL::prepareOSREntry): This had a useful assertion for everything except 'this'. - * tests/stress/strict-to-this-int.js: Added. - (foo): - (Number.prototype.valueOf): - (test): - -2014-04-29 Oliver Hunt <oliver@apple.com> - - Don't hold on to parameterBindingNodes forever - https://bugs.webkit.org/show_bug.cgi?id=132360 - - Reviewed by Geoffrey Garen. - - Don't keep the parameter nodes anymore. Instead we store the - original parameter string and reparse whenever we actually - need them. Because we only actually need them for compilation - this only results in a single extra parse. - - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::generateFunctionCodeBlock): - (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): - (JSC::UnlinkedFunctionExecutable::visitChildren): - (JSC::UnlinkedFunctionExecutable::finishCreation): - (JSC::UnlinkedFunctionExecutable::paramString): - (JSC::UnlinkedFunctionExecutable::parameters): - (JSC::UnlinkedFunctionExecutable::parameterCount): Deleted. - * bytecode/UnlinkedCodeBlock.h: - (JSC::UnlinkedFunctionExecutable::create): - (JSC::UnlinkedFunctionExecutable::parameterCount): - (JSC::UnlinkedFunctionExecutable::parameters): Deleted. - (JSC::UnlinkedFunctionExecutable::finishCreation): Deleted. - * parser/ASTBuilder.h: - (JSC::ASTBuilder::ASTBuilder): - (JSC::ASTBuilder::setFunctionBodyParameters): - * parser/Nodes.h: - (JSC::FunctionBodyNode::parametersStartOffset): - (JSC::FunctionBodyNode::parametersEndOffset): - (JSC::FunctionBodyNode::setParameterLocation): - * parser/Parser.cpp: - (JSC::Parser<LexerType>::parseFunctionInfo): - (JSC::parseParameters): - * parser/Parser.h: - (JSC::parse): - * parser/SourceCode.h: - (JSC::SourceCode::subExpression): - * parser/SyntaxChecker.h: - (JSC::SyntaxChecker::setFunctionBodyParameters): - -2014-04-29 Mark Hahnenberg <mhahnenberg@apple.com> - - JSProxies should be cacheable - https://bugs.webkit.org/show_bug.cgi?id=132351 - - Reviewed by Geoffrey Garen. - - Whenever we encounter a proxy in an inline cache we should try to cache on the - proxy's target instead of giving up. - - This patch adds support for a simple "recursive" inline cache if the base object - we're accessing is a pure forwarding proxy. JSGlobalObject and its subclasses - are the only ones to benefit from this right now. - - This is performance neutral on the benchmarks we track. Currently we won't - cache on JSDOMWindow due to HasImpureGetOwnPropertySlot, but this issue will be fixed soon. - - * jit/Repatch.cpp: - (JSC::generateByIdStub): - (JSC::tryBuildGetByIDList): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - * jsc.cpp: - (GlobalObject::finishCreation): - (functionCreateProxy): - * runtime/IntendedStructureChain.cpp: - (JSC::IntendedStructureChain::isNormalized): - * runtime/JSCellInlines.h: - (JSC::JSCell::isProxy): - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::finishCreation): - * runtime/JSProxy.h: - (JSC::JSProxy::createStructure): - (JSC::JSProxy::targetOffset): - * runtime/JSType.h: - * runtime/Operations.h: - (JSC::isPrototypeChainNormalized): - * runtime/Structure.h: - (JSC::Structure::isProxy): - * tests/stress/proxy-inline-cache.js: Added. - (cacheOnTarget.getX): - (cacheOnTarget): - (cacheOnPrototypeOfTarget.getX): - (cacheOnPrototypeOfTarget): - (dontCacheOnProxyInPrototypeChain.getX): - (dontCacheOnProxyInPrototypeChain): - (dontCacheOnTargetOfProxyInPrototypeChainOfTarget.getX): - (dontCacheOnTargetOfProxyInPrototypeChainOfTarget): - -2014-04-29 Filip Pizlo <fpizlo@apple.com> - - Use LLVM as a backend for the fourth-tier DFG JIT (a.k.a. the FTL JIT) - https://bugs.webkit.org/show_bug.cgi?id=112840 - - Rubber stamped by Geoffrey Garen. - - * Configurations/FeatureDefines.xcconfig: - -2014-04-29 Geoffrey Garen <ggaren@apple.com> - - String.prototype.trim removes U+200B from strings. - https://bugs.webkit.org/show_bug.cgi?id=130184 - - Reviewed by Michael Saboff. - - * runtime/StringPrototype.cpp: - (JSC::trimString): - (JSC::isTrimWhitespace): Deleted. - -2014-04-29 Mark Lam <mark.lam@apple.com> - - Zombifying sweep should ignore retired blocks. - <https://webkit.org/b/132344> - - Reviewed by Mark Hahnenberg. - - By definition, retired blocks do not have "dead" objects, or at least - none that we know of yet until the next marking phase has been run - over it. So, we should not be sweeping them (even for zombie mode). - - * heap/Heap.cpp: - (JSC::Heap::zombifyDeadObjects): - * heap/MarkedSpace.cpp: - (JSC::MarkedSpace::zombifySweep): - * heap/MarkedSpace.h: - (JSC::ZombifySweep::operator()): - -2014-04-29 Mark Lam <mark.lam@apple.com> - - Fix bit rot in zombie mode heap code. - <https://webkit.org/b/132342> - - Reviewed by Mark Hahnenberg. - - Need to enter a DelayedReleaseScope before doing a sweep. - - * heap/Heap.cpp: - (JSC::Heap::zombifyDeadObjects): - -2014-04-29 Tomas Popela <tpopela@redhat.com> - - LLINT loadisFromInstruction doesn't need special case for big endians - https://bugs.webkit.org/show_bug.cgi?id=132330 - - Reviewed by Mark Lam. - - The change introduced in r167076 was wrong. We should not apply the offset - adjustment on loadisFromInstruction usage as the instruction - (UnlinkedInstruction) is declared as an union (i.e. with the int32_t - operand variable). The offset of the other union members will be the - same as the offset of the first one, that is 0. The behavior here is the - same on little and big endian architectures. Thus we don't need - special case for big endians. - - * llint/LowLevelInterpreter.asm: - -2014-04-28 Mark Hahnenberg <mhahnenberg@apple.com> - - Simplify tryCacheGetById - https://bugs.webkit.org/show_bug.cgi?id=132314 - - Reviewed by Oliver Hunt and Filip Pizlo. - - This is neutral across all benchmarks we track, although it looks like a wee 0.5% progression on sunspider. - - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): If we fail to cache on self, we just repatch to call tryBuildGetByIDList next time. - -2014-04-28 Michael Saboff <msaboff@apple.com> - - REGRESSION(r153142) ASSERT from CodeBlock::dumpBytecode dumping String Switch Jump Tables - https://bugs.webkit.org/show_bug.cgi?id=132315 - - Reviewed by Mark Hahnenberg. - - Used the StringImpl version of utf8() instead of creating a String first. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::dumpBytecode): - -2014-04-28 Filip Pizlo <fpizlo@apple.com> - - The LLInt is awesome and it should get more of the action. - - Rubber stamped by Geoffrey Garen. - - 5% speed-up on JSBench and no meaningful regressions. Should be a PLT/DYE speed-up also. - - * runtime/Options.h: - -2014-04-27 Filip Pizlo <fpizlo@apple.com> - - GC should be able to remove things from the DFG worklist and cancel on-going compilations if it knows that the compilation would already be invalidated - https://bugs.webkit.org/show_bug.cgi?id=132166 - - Reviewed by Oliver Hunt and Mark Hahnenberg. - - The GC can aid type inference by removing structures that are dead and jettisoning - code that relies on those structures. This can dramatically accelerate type inference - for some tricky programs. - - Unfortunately, we previously pinned any structures that enqueued compilations depended - on. This means that if you're on a machine that only runs a single compilation thread - and where compilations are relatively slow, you have a high chance of large numbers of - structures being pinned during any GC since the compilation queue is likely to be full - of random stuff. - - This comprehensively fixes this issue by allowing the GC to remove compilation plans - if the things they depend on are dead, and to even cancel safepointed compilations. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan): - (JSC::CodeBlock::isKnownToBeLiveDuringGC): - (JSC::CodeBlock::finalizeUnconditionally): - * bytecode/CodeBlock.h: - (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan): Deleted. - * dfg/DFGDesiredIdentifiers.cpp: - (JSC::DFG::DesiredIdentifiers::DesiredIdentifiers): - * dfg/DFGDesiredIdentifiers.h: - * dfg/DFGDesiredWatchpoints.h: - * dfg/DFGDesiredWeakReferences.cpp: - (JSC::DFG::DesiredWeakReferences::DesiredWeakReferences): - * dfg/DFGDesiredWeakReferences.h: - * dfg/DFGGraphSafepoint.cpp: - (JSC::DFG::GraphSafepoint::GraphSafepoint): - * dfg/DFGGraphSafepoint.h: - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::Plan): - (JSC::DFG::Plan::compileInThread): - (JSC::DFG::Plan::compileInThreadImpl): - (JSC::DFG::Plan::notifyCompiling): - (JSC::DFG::Plan::notifyCompiled): - (JSC::DFG::Plan::notifyReady): - (JSC::DFG::Plan::checkLivenessAndVisitChildren): - (JSC::DFG::Plan::isKnownToBeLiveDuringGC): - (JSC::DFG::Plan::cancel): - (JSC::DFG::Plan::visitChildren): Deleted. - * dfg/DFGPlan.h: - * dfg/DFGSafepoint.cpp: - (JSC::DFG::Safepoint::Result::~Result): - (JSC::DFG::Safepoint::Result::didGetCancelled): - (JSC::DFG::Safepoint::Safepoint): - (JSC::DFG::Safepoint::~Safepoint): - (JSC::DFG::Safepoint::checkLivenessAndVisitChildren): - (JSC::DFG::Safepoint::isKnownToBeLiveDuringGC): - (JSC::DFG::Safepoint::cancel): - (JSC::DFG::Safepoint::visitChildren): Deleted. - * dfg/DFGSafepoint.h: - (JSC::DFG::Safepoint::Result::Result): - * dfg/DFGWorklist.cpp: - (JSC::DFG::Worklist::compilationState): - (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady): - (JSC::DFG::Worklist::removeAllReadyPlansForVM): - (JSC::DFG::Worklist::completeAllReadyPlansForVM): - (JSC::DFG::Worklist::visitWeakReferences): - (JSC::DFG::Worklist::removeDeadPlans): - (JSC::DFG::Worklist::runThread): - (JSC::DFG::Worklist::visitChildren): Deleted. - * dfg/DFGWorklist.h: - * ftl/FTLCompile.cpp: - (JSC::FTL::compile): - * ftl/FTLCompile.h: - * heap/CodeBlockSet.cpp: - (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): - * heap/Heap.cpp: - (JSC::Heap::markRoots): - (JSC::Heap::visitCompilerWorklistWeakReferences): - (JSC::Heap::removeDeadCompilerWorklistEntries): - (JSC::Heap::visitWeakHandles): - (JSC::Heap::collect): - (JSC::Heap::visitCompilerWorklists): Deleted. - * heap/Heap.h: - -2014-04-28 Mark Hahnenberg <mhahnenberg@apple.com> - - Deleting properties poisons objects - https://bugs.webkit.org/show_bug.cgi?id=131551 - - Reviewed by Oliver Hunt. - - This is ~3% progression on Dromaeo with a ~6% progression on the jslib portion of Dromaeo in particular. - - * runtime/JSPropertyNameIterator.cpp: - (JSC::JSPropertyNameIterator::create): - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::hasDeletedOffset): - (JSC::PropertyTable::hadDeletedOffset): If we ever had deleted properties we can no longer cache offsets when - iterating properties because we're required to iterate properties in insertion order. - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::materializePropertyMap): We now re-use deleted properties when materializing the property map. - (JSC::Structure::removePropertyTransition): We allow up to 5 deletes for a particular path through the tree of - Structure transitions. After that, we convert to an uncacheable dictionary like we used to. We don't cache - delete transitions, but we allow transitioning from them. - (JSC::Structure::changePrototypeTransition): - (JSC::Structure::despecifyFunctionTransition): - (JSC::Structure::attributeChangeTransition): - (JSC::Structure::toDictionaryTransition): - (JSC::Structure::preventExtensionsTransition): - (JSC::Structure::addPropertyWithoutTransition): - (JSC::Structure::removePropertyWithoutTransition): - (JSC::Structure::pin): Now does only what it says it does--marks the property table as pinned. - (JSC::Structure::pinAndPreventTransitions): More descriptive version of what the old pin() was doing. - * runtime/Structure.h: - * runtime/StructureInlines.h: - (JSC::Structure::setEnumerationCache): - (JSC::Structure::hadDeletedOffsets): - (JSC::Structure::propertyTable): - (JSC::Structure::checkOffsetConsistency): Rearranged variables to be more sensible. - * tests/stress/for-in-after-delete.js: Added. - (foo): - -2014-04-25 Andreas Kling <akling@apple.com> - - Inline (C++) GetByVal with numeric indices more aggressively. - <https://webkit.org/b/132218> - - We were already inlining the string indexed GetByVal path pretty well, - while the path for numeric indices got neglected. No more! - - ~9.5% improvement on Dromaeo/dom-traverse.html on my MBP: - - Before: 199.50 runs/s - After: 218.58 runs/s - - Reviewed by Phil Pizlo. - - * dfg/DFGOperations.cpp: - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::get): - - ALWAYS_INLINE all the things. - - * runtime/JSObject.h: - (JSC::JSObject::getPropertySlot): - - Avoid fetching the Structure more than once. We have the same - optimization in the string-indexed code path. - -2014-04-25 Oliver Hunt <oliver@apple.com> - - Need earlier cell test - https://bugs.webkit.org/show_bug.cgi?id=132211 - - Reviewed by Mark Lam. - - Move cell test to before the function call repatch - location, as the repatch logic for 32bit assumes that the - caller will already have performed a cell check. - - * jit/JITCall32_64.cpp: - (JSC::JIT::compileOpCall): - -2014-04-25 Andreas Kling <akling@apple.com> - - Un-fast-allocate JSGlobalObjectRareData because Windows doesn't build and I'm not in the mood. - - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::JSGlobalObjectRareData::JSGlobalObjectRareData): - (JSC::JSGlobalObject::JSGlobalObjectRareData::~JSGlobalObjectRareData): Deleted. - -2014-04-25 Andreas Kling <akling@apple.com> - - Windows build fix attempt. - - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::JSGlobalObjectRareData::~JSGlobalObjectRareData): - -2014-04-25 Mark Lam <mark.lam@apple.com> - - Refactor debugging code to use BreakpointActions instead of Vector<ScriptBreakpointAction>. - <https://webkit.org/b/132201> - - Reviewed by Joseph Pecoraro. - - BreakpointActions is Vector<ScriptBreakpointAction>. Let's just consistently use - BreakpointActions everywhere. - - * inspector/ScriptBreakpoint.h: - (Inspector::ScriptBreakpoint::ScriptBreakpoint): - * inspector/ScriptDebugServer.cpp: - (Inspector::ScriptDebugServer::setBreakpoint): - (Inspector::ScriptDebugServer::getActionsForBreakpoint): - * inspector/ScriptDebugServer.h: - * inspector/agents/InspectorDebuggerAgent.cpp: - (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): - (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): - (Inspector::InspectorDebuggerAgent::setBreakpoint): - (Inspector::InspectorDebuggerAgent::removeBreakpoint): - * inspector/agents/InspectorDebuggerAgent.h: - -2014-04-24 Filip Pizlo <fpizlo@apple.com> - - DFG worklist scanning should not treat the key as a separate entity - https://bugs.webkit.org/show_bug.cgi?id=132167 - - Reviewed by Mark Hahnenberg. - - This simplifies the interface to the GC and will enable more optimizations. - - * dfg/DFGCompilationKey.cpp: - (JSC::DFG::CompilationKey::visitChildren): Deleted. - * dfg/DFGCompilationKey.h: - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::visitChildren): - * dfg/DFGWorklist.cpp: - (JSC::DFG::Worklist::visitChildren): - -2014-04-25 Oliver Hunt <oliver@apple.com> - - Remove unused parameter from codeblock linking function - https://bugs.webkit.org/show_bug.cgi?id=132199 - - Reviewed by Anders Carlsson. - - No change in behaviour. This is just a small change to make it - slightly easier to reason about what the offsets in UnlinkedFunctionExecutable - actually mean. - - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::UnlinkedFunctionExecutable::link): - * bytecode/UnlinkedCodeBlock.h: - * runtime/Executable.cpp: - (JSC::ProgramExecutable::initializeGlobalProperties): - -2014-04-25 Andreas Kling <akling@apple.com> - - Mark some things with WTF_MAKE_FAST_ALLOCATED. - <https://webkit.org/b/132198> - - Use FastMalloc for more things. - - Reviewed by Anders Carlsson. - - * builtins/BuiltinExecutables.h: - * heap/GCThreadSharedData.h: - * inspector/JSConsoleClient.h: - * inspector/agents/InspectorAgent.h: - * runtime/CodeCache.h: - * runtime/JSGlobalObject.h: - * runtime/Lookup.cpp: - (JSC::HashTable::createTable): - (JSC::HashTable::deleteTable): - * runtime/WeakGCMap.h: - -2014-04-25 Antoine Quint <graouts@webkit.org> - - Implement Array.prototype.find() - https://bugs.webkit.org/show_bug.cgi?id=130966 - - Reviewed by Oliver Hunt. - - Implement Array.prototype.find() and Array.prototype.findIndex() as proposed in the Harmony spec. - - * builtins/Array.prototype.js: - (find): - (findIndex): - * runtime/ArrayPrototype.cpp: - -2014-04-24 Brady Eidson <beidson@apple.com> - - Rename "IMAGE_CONTROLS" feature to "SERVICE_CONTROLS" - https://bugs.webkit.org/show_bug.cgi?id=132155 - - Reviewed by Tim Horton. - - * Configurations/FeatureDefines.xcconfig: - -2014-04-24 Michael Saboff <msaboff@apple.com> - - REGRESSION: Apparent hang of PCE.js Mac OS System 7.0.1 on ARM64 devices - https://bugs.webkit.org/show_bug.cgi?id=132147 - - Reviewed by Mark Lam. - - Fixed or64(), eor32( ) and eor64() to use "src" register when we have a valid logicalImm. - - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::or64): - (JSC::MacroAssemblerARM64::xor32): - (JSC::MacroAssemblerARM64::xor64): - * tests/stress/regress-132147.js: Added test. - -2014-04-24 Mark Lam <mark.lam@apple.com> - - Make slowPathAllocsBetweenGCs a runtime option. - <https://webkit.org/b/132137> - - Reviewed by Mark Hahnenberg. - - This will make it easier to more casually run tests with this configuration - as well as to reproduce issues (instead of requiring a code mod and rebuild). - We will now take --slowPathAllocsBetweenGCs=N where N is the number of - slow path allocations before we trigger a collection. - - The option defaults to 0, which is reserved to mean that we will not trigger - any collections there. - - * heap/Heap.h: - * heap/MarkedAllocator.cpp: - (JSC::MarkedAllocator::doTestCollectionsIfNeeded): - (JSC::MarkedAllocator::allocateSlowCase): - * heap/MarkedAllocator.h: - * runtime/Options.h: - -2014-04-23 Mark Lam <mark.lam@apple.com> - - The GC should only resume compiler threads that it suspended in the same GC pass. - <https://webkit.org/b/132088> - - Reviewed by Mark Hahnenberg. - - Previously, this scenario can occur: - 1. Thread 1 starts a GC and tries to suspend DFG worklist threads. However, - no worklists were created yet at the that time. - 2. Thread 2 starts to compile some functions and creates a DFG worklist, and - acquires the worklist thread's lock. - 3. Thread 1's GC completes and tries to resume suspended DFG worklist thread. - This time, it sees the worklist created by Thread 2 and ends up unlocking - the worklist thread's lock that is supposedly held by Thread 2. - Thereafter, chaos ensues. - - The fix is to cache the worklists that were actually suspended by each GC pass, - and only resume those when the GC is done. - - This issue was discovered by enabling COLLECT_ON_EVERY_ALLOCATION and running - the fast/workers layout tests. - - * heap/Heap.cpp: - (JSC::Heap::visitCompilerWorklists): - (JSC::Heap::deleteAllCompiledCode): - (JSC::Heap::suspendCompilerThreads): - (JSC::Heap::resumeCompilerThreads): - * heap/Heap.h: - -2014-04-23 Mark Hahnenberg <mhahnenberg@apple.com> - - Arguments::copyBackingStore needs to update m_registers in tandem with m_registerArray - https://bugs.webkit.org/show_bug.cgi?id=132079 - - Reviewed by Michael Saboff. - - Since we're moving the register backing store, we don't want to leave a dangling pointer into a random CopiedBlock. - - Also added a test that previously triggered this bug. - - * runtime/Arguments.cpp: - (JSC::Arguments::copyBackingStore): D'oh! - * tests/stress/arguments-copy-register-array-backing-store.js: Added. - (foo): - (bar): - -2014-04-23 Mark Rowe <mrowe@apple.com> - - [Mac] REGRESSION (r164823): Building JavaScriptCore creates files under /tmp/JavaScriptCore.dst - <https://webkit.org/b/132053> - - Reviewed by Dan Bernstein. - - * JavaScriptCore.xcodeproj/project.pbxproj: Don't try to create a symlink at /usr/local/bin/jsc inside - the DSTROOT unless we're building to the deployment location. Also remove the unnecessary -x argument - from /bin/sh since that generates unnecessary output. - -2014-04-22 Mark Lam <mark.lam@apple.com> - - DFG::Worklist should acquire the m_lock before iterating DFG plans. - <https://webkit.org/b/132032> - - Reviewed by Filip Pizlo. - - Currently, there's a rightToRun mechanism that ensures that no compilation - threads are running when the GC is iterating through the DFG worklists. - However, this does not prevent a Worker thread from doing a DFG compilation - and modifying the plans in the worklists thereby invalidating the plan - iterator that the GC is using. This patch fixes the issue by acquiring - the worklist m_lock before iterating the worklist plans. - - This issue was uncovered by running the fast/workers layout tests with - COLLECT_ON_EVERY_ALLOCATION enabled. - - * dfg/DFGWorklist.cpp: - (JSC::DFG::Worklist::isActiveForVM): - (JSC::DFG::Worklist::visitChildren): - -2014-04-22 Brent Fulgham <bfulgham@apple.com> - - [Win] Support Python 2.7 in Cygwin - https://bugs.webkit.org/show_bug.cgi?id=132023 - - Reviewed by Michael Saboff. - - * DerivedSources.make: Use a conditional variable to define - the path to Python/Perl. - -2014-04-22 Filip Pizlo <fpizlo@apple.com> - - Switch the LLVMForJSC target to using the LLVM in /usr/local rather than /usr/local/LLVMForJavaScriptCore on iOS - https://bugs.webkit.org/show_bug.cgi?id=130867 - <rdar://problem/16432456> - - Reviewed by Mark Hahnenberg. - - * Configurations/Base.xcconfig: - * Configurations/LLVMForJSC.xcconfig: - -2014-04-22 Alex Christensen <achristensen@webkit.org> - - [Win] Unreviewed build fix after my r167666. - - * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractorCommon.props: - Added ../../../ again to include headers in Source/JavaScriptCore. - -2014-04-22 Alex Christensen <achristensen@webkit.org> - - Removed old stdbool and inttypes headers. - https://bugs.webkit.org/show_bug.cgi?id=131966 - - Reviewed by Brent Fulgham. - - * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractorCommon.props: - * JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props: - Removed references to os-win32 directory. - * os-win32: Removed. - * os-win32/inttypes.h: Removed. - * os-win32/stdbool.h: Removed. - -2014-04-21 Filip Pizlo <fpizlo@apple.com> - - DFG::clobberize() should honestly admit that profiler and debugger nodes are effectful - https://bugs.webkit.org/show_bug.cgi?id=131971 - <rdar://problem/16676511> - - Reviewed by Mark Lam. - - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - -2014-04-21 Filip Pizlo <fpizlo@apple.com> - - Switch statements that skip the baseline JIT should work - https://bugs.webkit.org/show_bug.cgi?id=131965 - - Reviewed by Mark Hahnenberg. - - * bytecode/JumpTable.h: - (JSC::SimpleJumpTable::ensureCTITable): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::emitSwitchIntJump): - * jit/JITOpcodes.cpp: - (JSC::JIT::emit_op_switch_imm): - (JSC::JIT::emit_op_switch_char): - * jit/JITOpcodes32_64.cpp: - (JSC::JIT::emit_op_switch_imm): - (JSC::JIT::emit_op_switch_char): - * tests/stress/inline-llint-with-switch.js: Added. - (foo): - (bar): - (test): - -2014-04-21 Mark Hahnenberg <mhahnenberg@apple.com> - - Arguments objects shouldn't need a destructor - https://bugs.webkit.org/show_bug.cgi?id=131899 - - Reviewed by Oliver Hunt. - - This patch rids Arguments objects of their destructors. It does this by - switching their backing stores to use CopiedSpace rather than malloc memory. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::emitAllocateArguments): Fix the code emitted for inline - Arguments allocation so that it only emits an extra write for strict mode code rather - than unconditionally. - * heap/CopyToken.h: New CopyTokens for the two different types of Arguments backing stores. - * runtime/Arguments.cpp: - (JSC::Arguments::visitChildren): We need to tell the collector to copy the back stores now. - (JSC::Arguments::copyBackingStore): Do the actual copying of the backing stores. - (JSC::Arguments::deletePropertyByIndex): Update all the accesses to SlowArgumentData and m_registerArray. - (JSC::Arguments::deleteProperty): - (JSC::Arguments::defineOwnProperty): - (JSC::Arguments::allocateRegisterArray): - (JSC::Arguments::tearOff): - (JSC::Arguments::destroy): Deleted. We don't need the destructor any more. - * runtime/Arguments.h: - (JSC::Arguments::registerArraySizeInBytes): - (JSC::Arguments::SlowArgumentData::SlowArgumentData): Switch SlowArgumentData to being allocated - in CopiedSpace. Now the SlowArgumentData and its backing store are a single contiguous CopiedSpace - allocation. - (JSC::Arguments::SlowArgumentData::slowArguments): - (JSC::Arguments::SlowArgumentData::bytecodeToMachineCaptureOffset): - (JSC::Arguments::SlowArgumentData::setBytecodeToMachineCaptureOffset): - (JSC::Arguments::SlowArgumentData::sizeForNumArguments): - (JSC::Arguments::Arguments): - (JSC::Arguments::allocateSlowArguments): - (JSC::Arguments::tryDeleteArgument): - (JSC::Arguments::isDeletedArgument): - (JSC::Arguments::isArgument): - (JSC::Arguments::argument): - (JSC::Arguments::finishCreation): - * runtime/SymbolTable.h: - -2014-04-21 Eric Carlson <eric.carlson@apple.com> - - [Mac] implement WebKitDataCue - https://bugs.webkit.org/show_bug.cgi?id=131799 - - Reviewed by Dean Jackson. - - * Configurations/FeatureDefines.xcconfig: Define ENABLE_DATACUE_VALUE. - -2014-04-21 Filip Pizlo <fpizlo@apple.com> - - Unreviewed test gardening, run the repeat-out-of-bounds tests again. - - * tests/stress/float32-repeat-out-of-bounds.js: - * tests/stress/int8-repeat-out-of-bounds.js: - -2014-04-21 Filip Pizlo <fpizlo@apple.com> - - OSR exit should know about Int52 and Double constants - https://bugs.webkit.org/show_bug.cgi?id=131945 - - Reviewed by Oliver Hunt. - - The DFG OSR exit machinery's ignorance would lead to some constants becoming - jsUndefined() after OSR exit. - - The FTL OSR exit machinery's ignorance just meant that we would sometimes use a - stackmap constant rather than baking the constant into the OSRExit data structure. - So, not a big deal, but worth fixing. - - Also added some helpful hacks to jsc.cpp for testing such OSR exit pathologies. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * dfg/DFGMinifiedNode.h: - (JSC::DFG::belongsInMinifiedGraph): - (JSC::DFG::MinifiedNode::hasConstantNumber): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument): - * jsc.cpp: - (GlobalObject::finishCreation): - (functionOtherFalse): - (functionUndefined): - * runtime/Intrinsic.h: - * tests/stress/fold-to-double-constant-then-exit.js: Added. - (foo): - * tests/stress/fold-to-int52-constant-then-exit.js: Added. - (foo): - -2014-04-21 Filip Pizlo <fpizlo@apple.com> - - Provide feedback when we encounter an unrecognied node in the FTL backend. - - Rubber stamped by Alexey Proskuryakov. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - -2014-04-21 Andreas Kling <akling@apple.com> - - Move the JSString cache from DOMWrapperWorld to VM. - <https://webkit.org/b/131940> - - Reviewed by Geoff Garen. - - * runtime/VM.h: - -2014-04-19 Filip Pizlo <fpizlo@apple.com> - - Take block execution count estimates into account when voting double - https://bugs.webkit.org/show_bug.cgi?id=131906 - - Reviewed by Geoffrey Garen. - - This was a drama in three acts. - - Act I: Slurp in BasicBlock::executionCount and use it as a weight when counting the - number of uses of a variable that want double or non-double. Easy as pie. This - gave me a huge speed-up on FloatMM and a huge slow-down on basically everything - else. - - Act II: Realize that there were some programs where our previous double voting was - just on the edge of disaster and making it more precise tipped it over. In - particular, if you had an integer variable that would infrequently be used in a - computation that resulted in a variable that was frequently used as an array index, - the outer infrequentness would be the thing we'd use in the vote. So, an array - index would become double. We fix this by reviving global backwards propagation - and introducing the concept of ReallyWantsInt, which is used just for array - indices. Any variable transitively flagged as ReallyWantsInt will never be forced - double. We need that flag to be separate from UsedAsInt, since UsedAsInt needs to - be set in bitops for RageConversion but using it for double forcing is too much. - Basically, it's cheaper to have to convert a double to an int for a bitop than it - is to convert a double to an int for an array index; also a variable being used as - an array index is a much stronger hint that it ought to be an int. This recovered - performance on everything except programs that used FTL OSR entry. - - Act III: Realize that OSR entrypoint creation creates blocks that have NaN execution - count, which then completely pollutes the weighting - essentially all votes go - NaN. Fix this with some surgical defenses. Basically, any client of execution - counts should allow for them to be NaN and shouldn't completely fall off a cliff - when it happens. - - This is awesome. 75% speed-up on FloatMM. 11% speed-up on audio-dft. This leads to - 7% speed-up on AsmBench and 2% speed-up on Kraken. - - * CMakeLists.txt: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGBackwardsPropagationPhase.cpp: - (JSC::DFG::BackwardsPropagationPhase::run): - (JSC::DFG::BackwardsPropagationPhase::propagate): - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::dumpBlockHeader): - * dfg/DFGGraph.h: - (JSC::DFG::Graph::voteNode): - (JSC::DFG::Graph::voteChildren): - * dfg/DFGNodeFlags.cpp: - (JSC::DFG::dumpNodeFlags): - * dfg/DFGNodeFlags.h: - * dfg/DFGOSREntrypointCreationPhase.cpp: - (JSC::DFG::OSREntrypointCreationPhase::run): - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::compileInThreadImpl): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): - (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): - * dfg/DFGVariableAccessData.cpp: Added. - (JSC::DFG::VariableAccessData::VariableAccessData): - (JSC::DFG::VariableAccessData::mergeIsCaptured): - (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox): - (JSC::DFG::VariableAccessData::predict): - (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): - (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): - (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): - (JSC::DFG::VariableAccessData::mergeDoubleFormatState): - (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): - (JSC::DFG::VariableAccessData::flushFormat): - * dfg/DFGVariableAccessData.h: - (JSC::DFG::VariableAccessData::vote): - (JSC::DFG::VariableAccessData::VariableAccessData): Deleted. - (JSC::DFG::VariableAccessData::mergeIsCaptured): Deleted. - (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox): Deleted. - (JSC::DFG::VariableAccessData::predict): Deleted. - (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): Deleted. - (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): Deleted. - (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): Deleted. - (JSC::DFG::VariableAccessData::mergeDoubleFormatState): Deleted. - (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): Deleted. - (JSC::DFG::VariableAccessData::flushFormat): Deleted. - -2014-04-21 Michael Saboff <msaboff@apple.com> - - REGRESSION(r167591): ARM64 and ARM traditional builds broken - https://bugs.webkit.org/show_bug.cgi?id=131935 - - Reviewed by Mark Hahnenberg. - - Added store8(TrustedImm32, MacroAssembler::Address) to the ARM traditional and ARM64 - macro assemblers. Added a new test for the original patch. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::store8): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::store8): - * tests/stress/dfg-create-arguments-inline-alloc.js: New test. - -2014-04-21 Mark Hahnenberg <mhahnenberg@apple.com> - - Inline allocate Arguments objects in the DFG - https://bugs.webkit.org/show_bug.cgi?id=131897 - - Reviewed by Geoffrey Garen. - - Many libraries/frameworks depend on the arguments object for overloaded API entry points. - This is the first step to making Arguments fast(er). We'll duplicate the logic in Arguments::create - for now and take the slow path for complicated cases like slow arguments, tearing off for strict mode, etc. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::emitAllocateArguments): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::emitAllocateDestructibleObject): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * runtime/Arguments.h: - (JSC::Arguments::offsetOfActivation): - (JSC::Arguments::offsetOfOverrodeLength): - (JSC::Arguments::offsetOfIsStrictMode): - (JSC::Arguments::offsetOfRegisterArray): - (JSC::Arguments::offsetOfCallee): - (JSC::Arguments::allocationSize): - -2014-04-20 Andreas Kling <akling@apple.com> - - Speed up jsStringWithCache() through WeakGCMap inlining. - <https://webkit.org/b/131923> - - Always inline WeakGCMap::add() but move the slow garbage collecting - path out-of-line. - - Reviewed by Darin Adler. - - * runtime/WeakGCMap.h: - (JSC::WeakGCMap::add): - (JSC::WeakGCMap::gcMap): - -2014-04-20 László Langó <llango.u-szeged@partner.samsung.com> - - JavaScriptCore: ARM build fix after r167094. - https://bugs.webkit.org/show_bug.cgi?id=131612 - - Reviewed by Michael Saboff. - - After r167094 there are many build errors on ARM like these: - - /tmp/ccgtHRno.s:370: Error: invalid constant (425a) after fixup - /tmp/ccgtHRno.s:374: Error: invalid constant (426e) after fixup - /tmp/ccgtHRno.s:378: Error: invalid constant (4282) after fixup - /tmp/ccgtHRno.s:382: Error: invalid constant (4296) after fixup - - Problem is caused by the wrong generated assembly like: - "\tmov r2, (" LOCAL_LABEL_STRING(llint_op_strcat) " - " LOCAL_LABEL_STRING(relativePCBase) ")\n" // /home/webkit/WebKit/Source/JavaScriptCore/llint/LowLevelInterpreter.asm:741 - - `mov` can only move 8 bit immediate, but not every constant fit into 8 bit. Clang converts - the mov to a single movw or a movw and a movt, depending on the immediate, but binutils doesn't. - Add a new ARM specific offline assembler instruction (`mvlbl`) for the following llint_entry - use case: move rn, (label1-label2) which is translated to movw and movt. - - * llint/LowLevelInterpreter.asm: - * offlineasm/arm.rb: - * offlineasm/instructions.rb: - -2014-04-20 Csaba Osztrogonác <ossy@webkit.org> - - [ARM] Unreviewed build fix after r167336. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::branchAdd32): - -2014-04-20 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r167501. - https://bugs.webkit.org/show_bug.cgi?id=131913 - - It broke DYEBench (Requested by mhahnenberg on #webkit). - - Reverted changeset: - - "Deleting properties poisons objects" - https://bugs.webkit.org/show_bug.cgi?id=131551 - http://trac.webkit.org/changeset/167501 - -2014-04-19 Filip Pizlo <fpizlo@apple.com> - - It should be OK to store new fields into objects that have no prototypes - https://bugs.webkit.org/show_bug.cgi?id=131905 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::emitPrototypeChecks): - * tests/stress/put-by-id-transition-null-prototype.js: Added. - (foo): - -2014-04-19 Benjamin Poulain <bpoulain@apple.com> - - Make the CSS JIT compile for ARM64 - https://bugs.webkit.org/show_bug.cgi?id=131834 - - Reviewed by Gavin Barraclough. - - Extend the ARM64 MacroAssembler to support the code generation required by - the CSS JIT. - - * assembler/MacroAssembler.h: - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::addPtrNoFlags): - (JSC::MacroAssemblerARM64::or32): - (JSC::MacroAssemblerARM64::branchPtr): - (JSC::MacroAssemblerARM64::test32): - (JSC::MacroAssemblerARM64::branch): - * assembler/MacroAssemblerX86Common.h: - (JSC::MacroAssemblerX86Common::test32): - -2014-04-19 Andreas Kling <akling@apple.com> - - Two little shortcuts to the JSType. - <https://webkit.org/b/131896> - - Tweak two sites that take the long road through JSCell::structure()->typeInfo() - to look at data that's already in JSCell::type(). - - Reviewed by Darin Adler. - - * runtime/NameInstance.h: - (JSC::isName): - * runtime/NumberPrototype.cpp: - (JSC::toThisNumber): - -2014-04-19 Filip Pizlo <fpizlo@apple.com> - - Make it easier to check if an integer sum would overflow - https://bugs.webkit.org/show_bug.cgi?id=131900 - - Reviewed by Darin Adler. - - * dfg/DFGOperations.cpp: - * runtime/Operations.h: - (JSC::jsString): - -2014-04-19 Filip Pizlo <fpizlo@apple.com> - - Address some feedback on https://bugs.webkit.org/show_bug.cgi?id=130684. - - * dfg/DFGOperations.cpp: - * runtime/JSString.h: - (JSC::JSRopeString::RopeBuilder::append): - -2014-04-18 Mark Lam <mark.lam@apple.com> - - REGRESSION(r164205): WebKit crash @StructureIDTable::get. - <https://webkit.org/b/130539> - - Reviewed by Geoffrey Garen. - - prepareOSREntry() prepares for OSR entry by first copying the local var - values from the baseline frame to a scartch buffer, which is then used - to fill in the locals in their new position in the DFG frame. Unfortunately, - prepareOSREntry() was using the DFG frame's frameRegisterCount as the frame - size of the baseline frame. As a result, some values of locals in the - baseline frame were not saved off, and the DFG frame may get initialized - with random content that happened to be in the uninitialized (and possibly - unallocated) portions of the scratch buffer. - - The fix is to use OSREntryData::m_expectedValues.numberOfLocals() as the - number of locals in the baseline frame that we want to copy to the scratch - buffer. - - Note: osrEntryThunkGenerator() is expecting the DFG frameRegisterCount - at offset 0 in the scratch buffer. So, we continue to write that value - there, not the baseline frame size. - - * dfg/DFGOSREntry.cpp: - (JSC::DFG::prepareOSREntry): - -2014-04-18 Timothy Hatcher <timothy@apple.com> - - Web Inspector: Move InspectorProfilerAgent to JavaScriptCore - https://bugs.webkit.org/show_bug.cgi?id=131673 - - Passes existing profiler and inspector tests. - - Reviewed by Joseph Pecoraro. - - * CMakeLists.txt: - * DerivedSources.make: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * inspector/JSConsoleClient.cpp: - (Inspector::JSConsoleClient::JSConsoleClient): - (Inspector::JSConsoleClient::profile): - (Inspector::JSConsoleClient::profileEnd): - (Inspector::JSConsoleClient::count): Deleted. - * inspector/JSConsoleClient.h: - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - * inspector/agents/InspectorProfilerAgent.cpp: Added. - (Inspector::InspectorProfilerAgent::InspectorProfilerAgent): - (Inspector::InspectorProfilerAgent::~InspectorProfilerAgent): - (Inspector::InspectorProfilerAgent::addProfile): - (Inspector::InspectorProfilerAgent::createProfileHeader): - (Inspector::InspectorProfilerAgent::enable): - (Inspector::InspectorProfilerAgent::disable): - (Inspector::InspectorProfilerAgent::getUserInitiatedProfileName): - (Inspector::InspectorProfilerAgent::getProfileHeaders): - (Inspector::buildInspectorObject): - (Inspector::InspectorProfilerAgent::buildProfileInspectorObject): - (Inspector::InspectorProfilerAgent::getCPUProfile): - (Inspector::InspectorProfilerAgent::removeProfile): - (Inspector::InspectorProfilerAgent::reset): - (Inspector::InspectorProfilerAgent::didCreateFrontendAndBackend): - (Inspector::InspectorProfilerAgent::willDestroyFrontendAndBackend): - (Inspector::InspectorProfilerAgent::start): - (Inspector::InspectorProfilerAgent::stop): - (Inspector::InspectorProfilerAgent::setRecordingProfile): - (Inspector::InspectorProfilerAgent::startProfiling): - (Inspector::InspectorProfilerAgent::stopProfiling): - * inspector/agents/InspectorProfilerAgent.h: Added. - * inspector/agents/JSGlobalObjectProfilerAgent.cpp: Copied from Source/WebCore/inspector/ScriptProfile.idl. - (Inspector::JSGlobalObjectProfilerAgent::JSGlobalObjectProfilerAgent): - (Inspector::JSGlobalObjectProfilerAgent::profilingGlobalExecState): - * inspector/agents/JSGlobalObjectProfilerAgent.h: Copied from Source/WebCore/inspector/ScriptProfile.idl. - * inspector/protocol/Profiler.json: Renamed from Source/WebCore/inspector/protocol/Profiler.json. - * profiler/Profile.h: - * runtime/ConsoleClient.h: - -2014-04-18 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r167527. - https://bugs.webkit.org/show_bug.cgi?id=131883 - - Broke 32-bit build (Requested by ap on #webkit). - - Reverted changeset: - - "[Mac] implement WebKitDataCue" - https://bugs.webkit.org/show_bug.cgi?id=131799 - http://trac.webkit.org/changeset/167527 - -2014-04-18 Eric Carlson <eric.carlson@apple.com> - - [Mac] implement WebKitDataCue - https://bugs.webkit.org/show_bug.cgi?id=131799 - - Reviewed by Dean Jackson. - - * Configurations/FeatureDefines.xcconfig: Define ENABLE_DATACUE_VALUE. - -2014-04-18 Filip Pizlo <fpizlo@apple.com> - - Actually address Mark's review feedback. - - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::handleExitCounts): - -2014-04-18 Filip Pizlo <fpizlo@apple.com> - - Options::maximumExecutionCountsBetweenCheckpoints() should be higher for DFG->FTL tier-up but the same for other tier-ups - https://bugs.webkit.org/show_bug.cgi?id=131850 - - Reviewed by Mark Hahnenberg. - - Templatize ExecutionCounter to allow for two different styles of calculating the - checkpoint threshold. - - Appears to be a slight speed-up on DYEBench. - - * bytecode/CodeBlock.h: - (JSC::CodeBlock::llintExecuteCounter): - (JSC::CodeBlock::offsetOfJITExecuteCounter): - (JSC::CodeBlock::offsetOfJITExecutionActiveThreshold): - (JSC::CodeBlock::offsetOfJITExecutionTotalCount): - (JSC::CodeBlock::jitExecuteCounter): - * bytecode/ExecutionCounter.cpp: - (JSC::ExecutionCounter<countingVariant>::ExecutionCounter): - (JSC::ExecutionCounter<countingVariant>::forceSlowPathConcurrently): - (JSC::ExecutionCounter<countingVariant>::checkIfThresholdCrossedAndSet): - (JSC::ExecutionCounter<countingVariant>::setNewThreshold): - (JSC::ExecutionCounter<countingVariant>::deferIndefinitely): - (JSC::applyMemoryUsageHeuristics): - (JSC::applyMemoryUsageHeuristicsAndConvertToInt): - (JSC::ExecutionCounter<countingVariant>::hasCrossedThreshold): - (JSC::ExecutionCounter<countingVariant>::setThreshold): - (JSC::ExecutionCounter<countingVariant>::reset): - (JSC::ExecutionCounter<countingVariant>::dump): - (JSC::ExecutionCounter::ExecutionCounter): Deleted. - (JSC::ExecutionCounter::forceSlowPathConcurrently): Deleted. - (JSC::ExecutionCounter::checkIfThresholdCrossedAndSet): Deleted. - (JSC::ExecutionCounter::setNewThreshold): Deleted. - (JSC::ExecutionCounter::deferIndefinitely): Deleted. - (JSC::ExecutionCounter::applyMemoryUsageHeuristics): Deleted. - (JSC::ExecutionCounter::applyMemoryUsageHeuristicsAndConvertToInt): Deleted. - (JSC::ExecutionCounter::hasCrossedThreshold): Deleted. - (JSC::ExecutionCounter::setThreshold): Deleted. - (JSC::ExecutionCounter::reset): Deleted. - (JSC::ExecutionCounter::dump): Deleted. - * bytecode/ExecutionCounter.h: - (JSC::formattedTotalExecutionCount): - (JSC::ExecutionCounter::maximumExecutionCountsBetweenCheckpoints): - (JSC::ExecutionCounter::clippedThreshold): - (JSC::ExecutionCounter::formattedTotalCount): Deleted. - * dfg/DFGJITCode.h: - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::handleExitCounts): - * llint/LowLevelInterpreter.asm: - * runtime/Options.h: - -2014-04-17 Mark Hahnenberg <mhahnenberg@apple.com> - - Deleting properties poisons objects - https://bugs.webkit.org/show_bug.cgi?id=131551 - - Reviewed by Geoffrey Garen. - - This is ~3% progression on Dromaeo with a ~6% progression on the jslib portion of Dromaeo in particular. - - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::materializePropertyMap): We now re-use deleted properties when materializing the property map. - (JSC::Structure::removePropertyTransition): We allow up to 5 deletes for a particular path through the tree of - Structure transitions. After that, we convert to an uncacheable dictionary like we used to. We don't cache - delete transitions, but we allow transitioning from them. - (JSC::Structure::changePrototypeTransition): - (JSC::Structure::despecifyFunctionTransition): - (JSC::Structure::attributeChangeTransition): - (JSC::Structure::toDictionaryTransition): - (JSC::Structure::preventExtensionsTransition): - (JSC::Structure::addPropertyWithoutTransition): - (JSC::Structure::removePropertyWithoutTransition): - (JSC::Structure::pin): Now does only what it says it does--marks the property table as pinned. - (JSC::Structure::pinAndPreventTransitions): More descriptive version of what the old pin() was doing. - * runtime/Structure.h: - * runtime/StructureInlines.h: - (JSC::Structure::checkOffsetConsistency): Rearranged variables to be more sensible. - -2014-04-17 Filip Pizlo <fpizlo@apple.com> - - InlineCallFrameSet should be refcounted - https://bugs.webkit.org/show_bug.cgi?id=131829 - - Reviewed by Geoffrey Garen. - - And DFG::Plan should hold a ref to it. Previously it was owned by Graph until it - became owned by JITCode. Except that if we're "failing" to compile, JITCode may die. - Even as it dies, the GC may still want to scan the DFG::Plan, which leads to scanning - the DesiredWriteBarriers, which leads to scanning the InlineCallFrameSet. - - So, just make the darn thing refcounted. - - * bytecode/InlineCallFrameSet.h: - * dfg/DFGArgumentsSimplificationPhase.cpp: - (JSC::DFG::ArgumentsSimplificationPhase::run): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): - * dfg/DFGCommonData.h: - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::Graph): - (JSC::DFG::Graph::requiredRegisterCountForExit): - * dfg/DFGGraph.h: - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::link): - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::Plan): - * dfg/DFGPlan.h: - * dfg/DFGStackLayoutPhase.cpp: - (JSC::DFG::StackLayoutPhase::run): - * ftl/FTLFail.cpp: - (JSC::FTL::fail): - * ftl/FTLLink.cpp: - (JSC::FTL::link): - -2014-04-17 Filip Pizlo <fpizlo@apple.com> - - FTL::fail() should manage memory "correctly" - https://bugs.webkit.org/show_bug.cgi?id=131823 - <rdar://problem/16384297> - - Reviewed by Oliver Hunt. - - * ftl/FTLFail.cpp: - (JSC::FTL::fail): - -2014-04-17 Filip Pizlo <fpizlo@apple.com> - - Prediction propagator should correctly model Int52s flowing through arguments - https://bugs.webkit.org/show_bug.cgi?id=131822 - <rdar://problem/16641408> - - Reviewed by Oliver Hunt. - - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * tests/stress/int52-argument.js: Added. - (foo): - * tests/stress/int52-variable.js: Added. - (foo): - -2014-04-17 Filip Pizlo <fpizlo@apple.com> - - REGRESSION: ASSERT(!typeInfo().hasImpureGetOwnPropertySlot() || typeInfo().newImpurePropertyFiresWatchpoints()) on jquery tests - https://bugs.webkit.org/show_bug.cgi?id=131798 - - Reviewed by Alexey Proskuryakov. - - Some day, we will fix https://bugs.webkit.org/show_bug.cgi?id=131810 and some version - of this assertion can return. For now, it's not clear that the assertion is guarding - any truly undesirable behavior - so it should just go away and be replaced with a - FIXME. - - * bytecode/GetByIdStatus.cpp: - (JSC::GetByIdStatus::computeForStubInfo): - * runtime/Structure.h: - (JSC::Structure::takesSlowPathInDFGForImpureProperty): - -2014-04-17 David Kilzer <ddkilzer@apple.com> - - Blind attempt to fix Windows build after r166837 - <http://webkit.org/b/131246> - - Hoping to fix this build error: - - warning MSB8027: Two or more files with the name of GCLogging.cpp will produce outputs to the same location. This can lead to an incorrect build result. The files involved are ..\heap\GCLogging.cpp, ..\heap\GCLogging.cpp. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Fix copy-paste - boo-boo by changing the GCLogging.cpp ClCompile entry to a - GCLogging.h ClInclude entry. - -2014-04-16 Filip Pizlo <fpizlo@apple.com> - - AI for GetLocal should match the DFG backend, and in this case, the best way to do that is to get rid of the "exit if empty prediction" thing since it's a vestige of a time long gone - https://bugs.webkit.org/show_bug.cgi?id=131764 - - Reviewed by Geoffrey Garen. - - The attached test case can be made to not crash by deleting old code. It used to be - the case that the DFG needed empty prediction guards, for shady reasons. We fixed that - long ago. At this point, these guards just make life difficult. So get rid of them. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * tests/stress/bug-131764.js: Added. - (test1): - (test2): - -2014-04-17 Darin Adler <darin@apple.com> - - Add separate flag for IndexedDatabase in workers since the current implementation is not threadsafe - https://bugs.webkit.org/show_bug.cgi?id=131785 - rdar://problem/16003108 - - Reviewed by Brady Eidson. - - * Configurations/FeatureDefines.xcconfig: Added INDEXED_DATABASE_IN_WORKERS. - -2014-04-16 Alexey Proskuryakov <ap@apple.com> - - Build fix after http://trac.webkit.org/changeset/167416 (Sink NaN sanitization) - - * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::speculate): - -2014-04-16 Filip Pizlo <fpizlo@apple.com> - - Extra error reporting for invalid value conversions - https://bugs.webkit.org/show_bug.cgi?id=131786 - - Rubber stamped by Ryosuke Niwa. - - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): - -2014-04-16 Filip Pizlo <fpizlo@apple.com> - - Sink NaN sanitization to uses and remove it when it's unnecessary - https://bugs.webkit.org/show_bug.cgi?id=131419 - - Reviewed by Oliver Hunt. - - This moves NaN purification to stores that could see an impure NaN. - - 5% speed-up on AsmBench, 50% speed-up on AsmBench/n-body. It is a regression on FloatMM - though, because of the other bug that causes that benchmark to box doubles in a loop. - - * bytecode/SpeculatedType.h: - (JSC::isInt32SpeculationForArithmetic): - (JSC::isMachineIntSpeculationForArithmetic): - (JSC::isDoubleSpeculation): - (JSC::isDoubleSpeculationForArithmetic): - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGAbstractValue.cpp: - (JSC::DFG::AbstractValue::fixTypeForRepresentation): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): - * dfg/DFGInPlaceAbstractState.cpp: - (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileValueRep): - (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileValueRep): - (JSC::FTL::LowerDFGToLLVM::compileGetByVal): - * runtime/PureNaN.h: - * tests/stress/float32-array-nan-inlined.js: Added. - (foo): - (test): - * tests/stress/float32-array-nan.js: Added. - (foo): - (test): - * tests/stress/float64-array-nan-inlined.js: Added. - (foo): - (isBigEndian): - (test): - * tests/stress/float64-array-nan.js: Added. - (foo): - (isBigEndian): - (test): - -2014-04-16 Brent Fulgham <bfulgham@apple.com> - - [Win] Unreviewed Windows gardening. Restrict our new 'isinf' check - to 32-bit builds, and revise the comment to explain what we are - doing. - - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::isMachineInt): Provide motivation for the new - 'isinf' check for our 32-bit code path. - -2014-04-16 Juergen Ributzka <juergen@apple.com> - - Allocate the data section on the heap again for FTL on ARM64 - https://bugs.webkit.org/show_bug.cgi?id=130156 - - Reviewed by Geoffrey Garen and Filip Pizlo. - - * ftl/FTLCompile.cpp: - (JSC::FTL::mmAllocateDataSection): - * ftl/FTLDataSection.cpp: - (JSC::FTL::DataSection::DataSection): - (JSC::FTL::DataSection::~DataSection): - * ftl/FTLDataSection.h: - -2014-04-16 Mark Lam <mark.lam@apple.com> - - Crash in CodeBlock::setOptimizationThresholdBasedOnCompilationResult() when the debugger activates. - <https://webkit.org/b/131747> - - Reviewed by Filip Pizlo. - - When the debugger is about to activate (e.g. enter stepping mode), it first - waits for all DFG compilations to complete. However, when the DFG completes, - if compilation is successful, it will install a new DFG codeBlock. The - CodeBlock installation process is required to register codeBlocks with the - debugger. Debugger::registerCodeBlock() will eventually call - CodeBlock::setSteppingMode() which may jettison the DFG codeBlock that we're - trying to install. Thereafter, chaos ensues. - - This jettison'ing only happens because the debugger currently set its - m_steppingMode flag before waiting for compilation to complete. The fix is - simply to set that flag only after compilation is complete. - - * debugger/Debugger.cpp: - (JSC::Debugger::setSteppingMode): - (JSC::Debugger::registerCodeBlock): - -2014-04-16 Filip Pizlo <fpizlo@apple.com> - - Discern between NaNs that would be safe to tag and NaNs that need some purification before tagging - https://bugs.webkit.org/show_bug.cgi?id=131420 - - Reviewed by Oliver Hunt. - - Rationalizes our handling of NaNs. We now have the notion of pureNaN(), or PNaN, which - replaces QNaN and represents a "safe" NaN for our tagging purposes. NaN purification now - goes through the purifyNaN() API. - - SpeculatedType and its clients can now distinguish between a PureNaN and an ImpureNaN. - - Prediction propagator is made slightly more cautious when dealing with NaNs. It doesn't - have to be too cautious since most prediction-based logic only cares about whether or not - a value could be an integer. - - AI is made much more cautious when dealing with NaNs. We don't yet introduce ImpureNaN - anywhere in the compiler, but when we do, we ought to be able to trust AI to propagate it - soundly and precisely. - - No performance change because this just unblocks - https://bugs.webkit.org/show_bug.cgi?id=131419. - - * API/JSValueRef.cpp: - (JSValueMakeNumber): - (JSValueToNumber): - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/SpeculatedType.cpp: - (JSC::dumpSpeculation): - (JSC::speculationFromValue): - (JSC::typeOfDoubleSum): - (JSC::typeOfDoubleDifference): - (JSC::typeOfDoubleProduct): - (JSC::polluteDouble): - (JSC::typeOfDoubleQuotient): - (JSC::typeOfDoubleMinMax): - (JSC::typeOfDoubleNegation): - (JSC::typeOfDoubleAbs): - (JSC::typeOfDoubleFRound): - (JSC::typeOfDoubleBinaryOp): - (JSC::typeOfDoubleUnaryOp): - * bytecode/SpeculatedType.h: - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleInlining): - (JSC::DFG::ByteCodeParser::parseCodeBlock): - * dfg/DFGCriticalEdgeBreakingPhase.cpp: - (JSC::DFG::CriticalEdgeBreakingPhase::breakCriticalEdge): - * dfg/DFGInPlaceAbstractState.cpp: - (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): - * dfg/DFGLoopPreHeaderCreationPhase.cpp: - (JSC::DFG::createPreHeader): - * dfg/DFGNode.h: - (JSC::DFG::BranchTarget::BranchTarget): - * dfg/DFGOSREntrypointCreationPhase.cpp: - (JSC::DFG::OSREntrypointCreationPhase::run): - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::speculatedDoubleTypeForPrediction): - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::emitAllocateJSArray): - (JSC::DFG::SpeculativeJIT::compileValueToInt32): - (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGVariableAccessData.h: - (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileGetByVal): - (JSC::FTL::LowerDFGToLLVM::compilePutByVal): - (JSC::FTL::LowerDFGToLLVM::compileArrayPush): - (JSC::FTL::LowerDFGToLLVM::compileArrayPop): - (JSC::FTL::LowerDFGToLLVM::compileNewArrayWithSize): - (JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32): - (JSC::FTL::LowerDFGToLLVM::allocateJSArray): - * ftl/FTLValueFormat.cpp: - (JSC::FTL::reboxAccordingToFormat): - * jit/AssemblyHelpers.cpp: - (JSC::AssemblyHelpers::purifyNaN): - (JSC::AssemblyHelpers::sanitizeDouble): Deleted. - * jit/AssemblyHelpers.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emitFloatTypedArrayGetByVal): - * runtime/DateConstructor.cpp: - (JSC::constructDate): - * runtime/DateInstanceCache.h: - (JSC::DateInstanceData::DateInstanceData): - (JSC::DateInstanceCache::reset): - * runtime/ExceptionHelpers.cpp: - (JSC::TerminatedExecutionError::defaultValue): - * runtime/JSArray.cpp: - (JSC::JSArray::setLength): - (JSC::JSArray::pop): - (JSC::JSArray::shiftCountWithAnyIndexingType): - (JSC::JSArray::sortVector): - (JSC::JSArray::compactForSorting): - * runtime/JSArray.h: - (JSC::JSArray::create): - (JSC::JSArray::tryCreateUninitialized): - * runtime/JSCJSValue.cpp: - (JSC::JSValue::toNumberSlowCase): - * runtime/JSCJSValue.h: - * runtime/JSCJSValueInlines.h: - (JSC::jsNaN): - (JSC::JSValue::JSValue): - (JSC::JSValue::getPrimitiveNumber): - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::parseInt): - (JSC::jsStrDecimalLiteral): - (JSC::toDouble): - (JSC::jsToNumber): - (JSC::parseFloat): - * runtime/JSObject.cpp: - (JSC::JSObject::createInitialDouble): - (JSC::JSObject::convertUndecidedToDouble): - (JSC::JSObject::convertInt32ToDouble): - (JSC::JSObject::deletePropertyByIndex): - (JSC::JSObject::ensureLengthSlow): - * runtime/MathObject.cpp: - (JSC::mathProtoFuncMax): - (JSC::mathProtoFuncMin): - * runtime/PureNaN.h: Added. - (JSC::pureNaN): - (JSC::isImpureNaN): - (JSC::purifyNaN): - * runtime/TypedArrayAdaptors.h: - (JSC::FloatTypedArrayAdaptor::toJSValue): - -2014-04-16 Juergen Ributzka <juergen@apple.com> - - Enable system library calls in FTL for ARM64 - https://bugs.webkit.org/show_bug.cgi?id=130154 - - Reviewed by Geoffrey Garen and Filip Pizlo. - - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLOutput.h: - (JSC::FTL::Output::doubleRem): - (JSC::FTL::Output::doubleSin): - (JSC::FTL::Output::doubleCos): - -2014-04-16 peavo@outlook.com <peavo@outlook.com> - - Fix JSC Debug Regressions on Windows - https://bugs.webkit.org/show_bug.cgi?id=131182 - - Reviewed by Brent Fulgham. - - The cast static_cast<int64_t>(number) in JSValue::isMachineInt() can generate a floating point error, - and set the st floating point register tags, if the value of the number parameter is infinite. - If the st floating point register tags are not cleared, this can cause strange floating point behavior later on. - This can be avoided by checking for infinity first. - - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::isMachineInt): Avoid floating point error by checking for infinity first. - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): Re-enable jit for Windows. - -2014-04-16 Oliver Hunt <oliver@apple.com> - - Simple ES6 feature:Array.prototype.fill - https://bugs.webkit.org/show_bug.cgi?id=131703 - - Reviewed by David Hyatt. - - Add support for Array.prototype.fill - - * builtins/Array.prototype.js: - (fill): - * runtime/ArrayPrototype.cpp: - -2014-04-16 Mark Hahnenberg <mhahnenberg@apple.com> - - [WebKit] Cleanup the build from uninitialized variable in JavaScriptCore - https://bugs.webkit.org/show_bug.cgi?id=131728 - - Reviewed by Darin Adler. - - * runtime/JSObject.cpp: - (JSC::JSObject::genericConvertDoubleToContiguous): Add a RELEASE_ASSERT on the - path we expect to never take. Also shut up confused compilers about uninitialized things. - -2014-04-16 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, ARMv7 build fix after r167336. - - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::branchAdd32): - -2014-04-16 Gabor Rapcsanyi <rgabor@webkit.org> - - Unreviewed, ARM64 buildfix after r167336. - - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::branchAdd32): Add missing function. - -2014-04-15 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, add the obvious thing that marks MakeRope as exiting since it can exit. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - -2014-04-15 Filip Pizlo <fpizlo@apple.com> - - compileMakeRope does not emit necessary bounds checks - https://bugs.webkit.org/show_bug.cgi?id=130684 - <rdar://problem/16398388> - - Reviewed by Oliver Hunt. - - Add string length bounds checks in a bunch of places. We should never allow a string - to have a length greater than 2^31-1 because it's not clear that the language has - semantics for it and because there is code that assumes that this cannot happen. - - Also add a bunch of tests to that effect to cover the various ways in which this was - previously allowed to happen. - - * dfg/DFGOperations.cpp: - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileMakeRope): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileMakeRope): - * runtime/JSString.cpp: - (JSC::JSRopeString::RopeBuilder::expand): - * runtime/JSString.h: - (JSC::JSString::create): - (JSC::JSRopeString::RopeBuilder::append): - (JSC::JSRopeString::RopeBuilder::release): - (JSC::JSRopeString::append): - * runtime/Operations.h: - (JSC::jsString): - (JSC::jsStringFromRegisterArray): - (JSC::jsStringFromArguments): - * runtime/StringPrototype.cpp: - (JSC::stringProtoFuncIndexOf): - (JSC::stringProtoFuncSlice): - (JSC::stringProtoFuncSubstring): - (JSC::stringProtoFuncToLowerCase): - * tests/stress/make-large-string-jit-strcat.js: Added. - (foo): - * tests/stress/make-large-string-jit.js: Added. - (foo): - * tests/stress/make-large-string-strcat.js: Added. - * tests/stress/make-large-string.js: Added. - -2014-04-15 Julien Brianceau <jbriance@cisco.com> - - Remove invalid sh4 specific code in JITInlines header. - https://bugs.webkit.org/show_bug.cgi?id=131692 - - Reviewed by Geoffrey Garen. - - * jit/JITInlines.h: - (JSC::JIT::callOperation): Prototype is not F_JITOperation_EJJZ - anymore since r160244, so the sh4 specific code is invalid now - and has to be removed. - -2014-04-15 Mark Hahnenberg <mhahnenberg@apple.com> - - Fix precedence issue in JSCell:setRemembered - - Rubber stamped by Filip Pizlo. - - * runtime/JSCell.h: - (JSC::JSCell::setRemembered): - -2014-04-15 Mark Hahnenberg <mhahnenberg@apple.com> - - Objective-C API external object graphs don't handle generational collection properly - https://bugs.webkit.org/show_bug.cgi?id=131634 - - Reviewed by Geoffrey Garen. - - If the set of Objective-C objects transitively reachable through an object changes, we - need to update the set of opaque roots accordingly. If we don't, the next EdenCollection - won't rescan the external object graph, which would lead us to consider a newly allocated - JSManagedValue to be dead. - - * API/JSBase.cpp: - (JSSynchronousEdenCollectForDebugging): - * API/JSVirtualMachine.mm: - (-[JSVirtualMachine initWithContextGroupRef:]): - (-[JSVirtualMachine dealloc]): - (-[JSVirtualMachine isOldExternalObject:]): - (-[JSVirtualMachine addExternalRememberedObject:]): - (-[JSVirtualMachine addManagedReference:withOwner:]): - (-[JSVirtualMachine removeManagedReference:withOwner:]): - (-[JSVirtualMachine externalRememberedSet]): - (scanExternalObjectGraph): - (scanExternalRememberedSet): - * API/JSVirtualMachineInternal.h: - * API/tests/testapi.mm: - * heap/Heap.cpp: - (JSC::Heap::markRoots): - * heap/Heap.h: - (JSC::Heap::slotVisitor): - * heap/SlotVisitor.h: - * heap/SlotVisitorInlines.h: - (JSC::SlotVisitor::containsOpaqueRoot): - (JSC::SlotVisitor::containsOpaqueRootTriState): - -2014-04-15 Filip Pizlo <fpizlo@apple.com> - - DFG IR should keep the data flow of doubles and int52's separate from the data flow of JSValue's - https://bugs.webkit.org/show_bug.cgi?id=131423 - - Reviewed by Geoffrey Garen. - - This introduces more static typing into DFG IR. Previously we just had the notion of - JSValues and Storage. This was weird because doubles weren't always convertible to - JSValues, and Int52s weren't always convertible to either doubles or JSValues. We would - sort of insert explicit conversion nodes just for the places where we knew that an - implicit conversion wouldn't have been possible -- but there was no hard and fast rule so - we'd get bugs from forgetting to do the right conversion. - - This patch introduces a hard and fast rule: doubles can never be implicitly converted to - anything but doubles, and likewise Int52's can never be implicitly converted. Conversion - nodes are used for all of the conversions. Int52Rep, DoubleRep, and ValueRep are the - conversions. They are like Identity but return the same value using a different - representation. Likewise, constants may now be represented using either JSConstant, - Int52Constant, or DoubleConstant. UseKinds have been adjusted accordingly, as well. - Int52RepUse and DoubleRepUse are node uses that mean "the node must be of Int52 (or - Double) type". They don't imply checks. There is also DoubleRepRealUse, which means that - we speculate DoubleReal and expect Double representation. - - In addition to simplifying a bunch of rules in the IR and making the IR more verifiable, - this also makes it easier to introduce optimizations in the future. It's now possible for - AI to model when/how conversion take place. For example if doing a conversion results in - NaN sanitization, then AI can model this and can allow us to sink sanitizations. That's - what https://bugs.webkit.org/show_bug.cgi?id=131419 will be all about. - - This was a big change, so I had to do some interesting things, like finally get rid of - the DFG's weird variadic template macro hacks and use real C++11 variadic templates. Also - the ByteCodeParser no longer emits Identity nodes since that was always pointless. - - No performance change because this mostly just rationalizes preexisting behavior. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * assembler/MacroAssemblerX86.h: - * bytecode/CodeBlock.cpp: - * bytecode/CodeBlock.h: - * dfg/DFGAbstractInterpreter.h: - (JSC::DFG::AbstractInterpreter::setBuiltInConstant): - (JSC::DFG::AbstractInterpreter::setConstant): - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGAbstractValue.cpp: - (JSC::DFG::AbstractValue::set): - (JSC::DFG::AbstractValue::fixTypeForRepresentation): - (JSC::DFG::AbstractValue::checkConsistency): - * dfg/DFGAbstractValue.h: - * dfg/DFGBackwardsPropagationPhase.cpp: - (JSC::DFG::BackwardsPropagationPhase::propagate): - * dfg/DFGBasicBlock.h: - * dfg/DFGBasicBlockInlines.h: - (JSC::DFG::BasicBlock::appendNode): - (JSC::DFG::BasicBlock::appendNonTerminal): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::constantCSE): - (JSC::DFG::CSEPhase::performNodeCSE): - (JSC::DFG::CSEPhase::int32ToDoubleCSE): Deleted. - * dfg/DFGCapabilities.h: - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - * dfg/DFGDCEPhase.cpp: - (JSC::DFG::DCEPhase::fixupBlock): - * dfg/DFGEdge.h: - (JSC::DFG::Edge::willNotHaveCheck): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::run): - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::fixupGetAndSetLocalsInBlock): - (JSC::DFG::FixupPhase::observeUseKindOnNode): - (JSC::DFG::FixupPhase::fixIntEdge): - (JSC::DFG::FixupPhase::attemptToMakeIntegerAdd): - (JSC::DFG::FixupPhase::injectTypeConversionsInBlock): - (JSC::DFG::FixupPhase::tryToRelaxRepresentation): - (JSC::DFG::FixupPhase::fixEdgeRepresentation): - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): - (JSC::DFG::FixupPhase::addRequiredPhantom): - (JSC::DFG::FixupPhase::addPhantomsIfNecessary): - (JSC::DFG::FixupPhase::clearPhantomsAtEnd): - (JSC::DFG::FixupPhase::fixupSetLocalsInBlock): Deleted. - * dfg/DFGFlushFormat.h: - (JSC::DFG::resultFor): - (JSC::DFG::useKindFor): - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::dump): - * dfg/DFGGraph.h: - (JSC::DFG::Graph::addNode): - * dfg/DFGInPlaceAbstractState.cpp: - (JSC::DFG::InPlaceAbstractState::initialize): - * dfg/DFGInsertionSet.h: - (JSC::DFG::InsertionSet::insertNode): - (JSC::DFG::InsertionSet::insertConstant): - (JSC::DFG::InsertionSet::insertConstantForUse): - * dfg/DFGIntegerCheckCombiningPhase.cpp: - (JSC::DFG::IntegerCheckCombiningPhase::insertAdd): - (JSC::DFG::IntegerCheckCombiningPhase::insertMustAdd): - * dfg/DFGNode.cpp: - (JSC::DFG::Node::convertToIdentity): - (WTF::printInternal): - * dfg/DFGNode.h: - (JSC::DFG::Node::Node): - (JSC::DFG::Node::setResult): - (JSC::DFG::Node::result): - (JSC::DFG::Node::isConstant): - (JSC::DFG::Node::hasConstant): - (JSC::DFG::Node::convertToConstant): - (JSC::DFG::Node::valueOfJSConstant): - (JSC::DFG::Node::hasResult): - (JSC::DFG::Node::hasInt32Result): - (JSC::DFG::Node::hasInt52Result): - (JSC::DFG::Node::hasNumberResult): - (JSC::DFG::Node::hasDoubleResult): - (JSC::DFG::Node::hasJSResult): - (JSC::DFG::Node::hasBooleanResult): - (JSC::DFG::Node::hasStorageResult): - (JSC::DFG::Node::defaultUseKind): - (JSC::DFG::Node::defaultEdge): - (JSC::DFG::Node::convertToIdentity): Deleted. - * dfg/DFGNodeFlags.cpp: - (JSC::DFG::dumpNodeFlags): - * dfg/DFGNodeFlags.h: - (JSC::DFG::canonicalResultRepresentation): - * dfg/DFGNodeType.h: - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGResurrectionForValidationPhase.cpp: - (JSC::DFG::ResurrectionForValidationPhase::run): - * dfg/DFGSSAConversionPhase.cpp: - (JSC::DFG::SSAConversionPhase::run): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::SafeToExecuteEdge::operator()): - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): - (JSC::DFG::SpeculativeJIT::silentSavePlanForFPR): - (JSC::DFG::SpeculativeJIT::silentFill): - (JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary): - (JSC::DFG::JSValueRegsTemporary::~JSValueRegsTemporary): - (JSC::DFG::JSValueRegsTemporary::regs): - (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch): - (JSC::DFG::SpeculativeJIT::checkGeneratedTypeForToInt32): - (JSC::DFG::SpeculativeJIT::compileValueToInt32): - (JSC::DFG::SpeculativeJIT::compileDoubleRep): - (JSC::DFG::SpeculativeJIT::compileValueRep): - (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): - (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): - (JSC::DFG::SpeculativeJIT::compileAdd): - (JSC::DFG::SpeculativeJIT::compileArithSub): - (JSC::DFG::SpeculativeJIT::compileArithNegate): - (JSC::DFG::SpeculativeJIT::compileArithMul): - (JSC::DFG::SpeculativeJIT::compileArithDiv): - (JSC::DFG::SpeculativeJIT::compileArithMod): - (JSC::DFG::SpeculativeJIT::compare): - (JSC::DFG::SpeculativeJIT::compileStrictEq): - (JSC::DFG::SpeculativeJIT::speculateNumber): - (JSC::DFG::SpeculativeJIT::speculateDoubleReal): - (JSC::DFG::SpeculativeJIT::speculate): - (JSC::DFG::SpeculativeJIT::compileInt32ToDouble): Deleted. - (JSC::DFG::SpeculativeJIT::speculateMachineInt): Deleted. - (JSC::DFG::SpeculativeJIT::speculateRealNumber): Deleted. - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::allocate): - (JSC::DFG::SpeculativeJIT::use): - (JSC::DFG::SpeculativeJIT::boxDouble): - (JSC::DFG::SpeculativeJIT::spill): - (JSC::DFG::SpeculativeJIT::jsValueResult): - (JSC::DFG::SpeculateInt52Operand::SpeculateInt52Operand): - (JSC::DFG::SpeculateStrictInt52Operand::SpeculateStrictInt52Operand): - (JSC::DFG::SpeculateWhicheverInt52Operand::SpeculateWhicheverInt52Operand): - (JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::fillJSValue): - (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): - (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): - (JSC::DFG::SpeculativeJIT::fillSpeculateCell): - (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): - (JSC::DFG::SpeculativeJIT::compileLogicalNot): - (JSC::DFG::SpeculativeJIT::emitBranch): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::convertToDouble): Deleted. - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::fillJSValue): - (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): - (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): - (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): - (JSC::DFG::SpeculativeJIT::fillSpeculateCell): - (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): - (JSC::DFG::SpeculativeJIT::compileLogicalNot): - (JSC::DFG::SpeculativeJIT::emitBranch): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::convertToDouble): Deleted. - * dfg/DFGStrengthReductionPhase.cpp: - (JSC::DFG::StrengthReductionPhase::handleNode): - * dfg/DFGUseKind.cpp: - (WTF::printInternal): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - (JSC::DFG::shouldNotHaveTypeCheck): - (JSC::DFG::mayHaveTypeCheck): - (JSC::DFG::isNumerical): - (JSC::DFG::isDouble): - (JSC::DFG::isCell): - (JSC::DFG::usesStructure): - (JSC::DFG::useKindForResult): - * dfg/DFGValidate.cpp: - (JSC::DFG::Validate::validate): - * dfg/DFGVariadicFunction.h: Removed. - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::createPhiVariables): - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileUpsilon): - (JSC::FTL::LowerDFGToLLVM::compilePhi): - (JSC::FTL::LowerDFGToLLVM::compileDoubleConstant): - (JSC::FTL::LowerDFGToLLVM::compileInt52Constant): - (JSC::FTL::LowerDFGToLLVM::compileWeakJSConstant): - (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): - (JSC::FTL::LowerDFGToLLVM::compileValueRep): - (JSC::FTL::LowerDFGToLLVM::compileInt52Rep): - (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): - (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): - (JSC::FTL::LowerDFGToLLVM::compileArithMul): - (JSC::FTL::LowerDFGToLLVM::compileArithDiv): - (JSC::FTL::LowerDFGToLLVM::compileArithMod): - (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): - (JSC::FTL::LowerDFGToLLVM::compileArithAbs): - (JSC::FTL::LowerDFGToLLVM::compileArithNegate): - (JSC::FTL::LowerDFGToLLVM::compilePutByVal): - (JSC::FTL::LowerDFGToLLVM::compileCompareEq): - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::compare): - (JSC::FTL::LowerDFGToLLVM::boolify): - (JSC::FTL::LowerDFGToLLVM::lowInt52): - (JSC::FTL::LowerDFGToLLVM::lowStrictInt52): - (JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52): - (JSC::FTL::LowerDFGToLLVM::lowDouble): - (JSC::FTL::LowerDFGToLLVM::lowJSValue): - (JSC::FTL::LowerDFGToLLVM::strictInt52ToDouble): - (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateNumber): - (JSC::FTL::LowerDFGToLLVM::speculateDoubleReal): - (JSC::FTL::LowerDFGToLLVM::compileInt52ToValue): Deleted. - (JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble): Deleted. - (JSC::FTL::LowerDFGToLLVM::setInt52WithStrictValue): Deleted. - (JSC::FTL::LowerDFGToLLVM::speculateRealNumber): Deleted. - (JSC::FTL::LowerDFGToLLVM::speculateMachineInt): Deleted. - * ftl/FTLValueFormat.cpp: - (JSC::FTL::reboxAccordingToFormat): - * jit/AssemblyHelpers.cpp: - (JSC::AssemblyHelpers::sanitizeDouble): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::boxDouble): - -2014-04-15 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r167199 and r167251. - https://bugs.webkit.org/show_bug.cgi?id=131678 - - Caused a DYEBench regression and does not seem to improve perf - on relevant websites (Requested by rniwa on #webkit). - - Reverted changesets: - - "Rewrite Function.bind as a builtin" - https://bugs.webkit.org/show_bug.cgi?id=131083 - http://trac.webkit.org/changeset/167199 - - "Update test result" - http://trac.webkit.org/changeset/167251 - -2014-04-14 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r167272. - https://bugs.webkit.org/show_bug.cgi?id=131666 - - Broke multiple tests (Requested by ap on #webkit). - - Reverted changeset: - - "Function.bind itself is too slow" - https://bugs.webkit.org/show_bug.cgi?id=131636 - http://trac.webkit.org/changeset/167272 - -2014-04-14 Geoffrey Garen <ggaren@apple.com> - - ASSERT when firing low memory warning - https://bugs.webkit.org/show_bug.cgi?id=131659 - - Reviewed by Mark Hahnenberg. - - * heap/Heap.cpp: - (JSC::Heap::deleteAllCompiledCode): Allow deleteAllCompiledCode to be - called when no GC is happening because that is what we do when a low - memory warning fires, and it is harmless. - -2014-04-14 Mark Hahnenberg <mhahnenberg@apple.com> - - emit_op_put_by_id should not emit a write barrier that filters on value - https://bugs.webkit.org/show_bug.cgi?id=131654 - - Reviewed by Filip Pizlo. - - The 32-bit implementation does this, and it can cause crashes if we later repatch the - code to allocate and store new Butterflies. - - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emitWriteBarrier): We also weren't verifying that the base was a cell on - 32-bit if we were passed ShouldFilterBase. I also took the liberty of sinking the tag - load down into the if statement so that we don't do it if we're not filtering on the value. - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emit_op_put_by_id): - -2014-04-14 Oliver Hunt <oliver@apple.com> - - Function.bind itself is too slow - https://bugs.webkit.org/show_bug.cgi?id=131636 - - Reviewed by Geoffrey Garen. - - Rather than forcing creation of an activation, we now store - bound function properties directly on the returned closure. - This is necessary to deal with code that creates many function - bindings, but does not call them very often. - - This is a 60% speed up in the included js/regress test. - - * builtins/BuiltinExecutables.cpp: - (JSC::BuiltinExecutables::createBuiltinExecutable): - * builtins/Function.prototype.js: - (bind.bindingFunction): - (bind.else.switch.case.1.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk): - (bind.else.switch.case.1.bindingFunction): - (bind.else.switch.case.2.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk): - (bind.else.switch.case.2.bindingFunction): - (bind.else.switch.case.3.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk): - (bind.else.switch.case.3.bindingFunction): - (bind.else.switch.bindingFunction): - (bind): - (bind.else.switch.case.1.bindingFunction.oversizedCall): Deleted. - (bind.else.switch.case.2.bindingFunction.oversizedCall): Deleted. - (bind.else.switch.case.3.bindingFunction.oversizedCall): Deleted. - * runtime/CommonIdentifiers.h: - -2014-04-14 Julien Brianceau <jbriance@cisco.com> - - [sh4] Allow use of SubImmediates in LLINT. - https://bugs.webkit.org/show_bug.cgi?id=131608 - - Reviewed by Mark Lam. - - Allow use of SubImmediates with const pool so the sh4 architecture can - share the arm path for setEntryAddress macro. It reduces architecture - specific code and lead to a more optimal generated code for sh4. - - * llint/LowLevelInterpreter.asm: - * offlineasm/sh4.rb: - -2014-04-14 Andreas Kling <akling@apple.com> - - Array.prototype.concat should allocate output storage only once. - <https://webkit.org/b/131609> - - Do a first pass across 'this' and any arguments to compute the - final size of the resulting array from Array.prototype.concat. - This avoids having to grow the output incrementally as we go. - - This also includes two other micro-optimizations: - - - Mark getProperty() with ALWAYS_INLINE. - - - Use JSArray::length() instead of taking the generic property - lookup path when we know an argument is an Array. - - My MBP says ~3% progression on Dromaeo/jslib-traverse-jquery. - - Reviewed by Oliver & Darin. - - * runtime/ArrayPrototype.cpp: - (JSC::getProperty): - (JSC::arrayProtoFuncConcat): - -2014-04-14 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r167249. - https://bugs.webkit.org/show_bug.cgi?id=131621 - - broke 3 tests on cloop (Requested by kling on #webkit). - - Reverted changeset: - - "Array.prototype.concat should allocate output storage only - once." - https://bugs.webkit.org/show_bug.cgi?id=131609 - http://trac.webkit.org/changeset/167249 - -2014-04-14 Alex Christensen <achristensen@webkit.org> - - Fixed potential integer truncation. - https://bugs.webkit.org/show_bug.cgi?id=131615 - - Reviewed by Darin Adler. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::fillNops): - Truncate the size_t to an unsigned after it is limited to 15 instead of before. - -2014-04-14 Andreas Kling <akling@apple.com> - - Array.prototype.concat should allocate output storage only once. - <https://webkit.org/b/131609> - - Do a first pass across 'this' and any arguments to compute the - final size of the resulting array from Array.prototype.concat. - This avoids having to grow the output incrementally as we go. - - This also includes two other micro-optimizations: - - - Mark getProperty() with ALWAYS_INLINE. - - - Use JSArray::length() instead of taking the generic property - lookup path when we know an argument is an Array. - - My MBP says ~3% progression on Dromaeo/jslib-traverse-jquery. - - Reviewed by Darin Adler. - - * runtime/ArrayPrototype.cpp: - (JSC::getProperty): - (JSC::arrayProtoFuncConcat): - -2014-04-14 Benjamin Poulain <benjamin@webkit.org> - - [JSC] Improve the call site of string comparison in some hot path - https://bugs.webkit.org/show_bug.cgi?id=131605 - - Reviewed by Darin Adler. - - When resolved, the String of a JSString is never null. It can be empty but not null. - The null value is reserved for ropes but those would be resolved when getting the value. - - Consequently, we should use the equal() operation that do not handle null values. - Using the StringImpl directly is already common in StringPrototype but it was not used here for some reason. - - * jit/JITOperations.cpp: - * runtime/JSCJSValueInlines.h: - (JSC::JSValue::equalSlowCaseInline): - (JSC::JSValue::strictEqualSlowCaseInline): - (JSC::JSValue::pureStrictEqual): - -2014-04-08 Oliver Hunt <oliver@apple.com> - - Rewrite Function.bind as a builtin - https://bugs.webkit.org/show_bug.cgi?id=131083 - - Reviewed by Geoffrey Garen. - - This change removes the existing function.bind implementation - entirely so JSBoundFunction is no more. - - Instead we just return a regular JS closure with a few - private properties hanging off it that allow us to perform - the necessary bound function fakery. While most of this is - simple, a couple of key changes: - - - The parser and lexer now directly track whether they're - parsing code for call or construct and convert the private - name @IsConstructor into TRUETOK or FALSETOK as appropriate. - This automatically gives us the ability to vary behaviour - from within the builtin. It also leaves a lot of headroom - for trivial future improvements. - - The instanceof operator now uses the prototypeForHasInstance - private name, and we have a helper function to ensure that - all objects that need to can update their magical 'prototype' - property pair correctly. - - * API/JSScriptRef.cpp: - (parseScript): - * JavaScriptCore.xcodeproj/project.pbxproj: - * builtins/BuiltinExecutables.cpp: - (JSC::BuiltinExecutables::createBuiltinExecutable): - * builtins/Function.prototype.js: - (bind.bindingFunction): - (bind.else.bindingFunction): - (bind): - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::generateFunctionCodeBlock): - * bytecompiler/NodesCodegen.cpp: - (JSC::InstanceOfNode::emitBytecode): - * interpreter/Interpreter.cpp: - * parser/Lexer.cpp: - (JSC::Lexer<T>::Lexer): - (JSC::Lexer<LChar>::parseIdentifier): - (JSC::Lexer<UChar>::parseIdentifier): - * parser/Lexer.h: - * parser/Parser.cpp: - (JSC::Parser<LexerType>::Parser): - (JSC::Parser<LexerType>::parseInner): - * parser/Parser.h: - (JSC::parse): - * parser/ParserModes.h: - * runtime/CodeCache.cpp: - (JSC::CodeCache::getGlobalCodeBlock): - (JSC::CodeCache::getFunctionExecutableFromGlobalCode): - * runtime/CommonIdentifiers.h: - * runtime/Completion.cpp: - (JSC::checkSyntax): - * runtime/Executable.cpp: - (JSC::ProgramExecutable::checkSyntax): - * runtime/FunctionPrototype.cpp: - (JSC::FunctionPrototype::addFunctionProperties): - (JSC::functionProtoFuncBind): Deleted. - * runtime/JSBoundFunction.cpp: Removed. - * runtime/JSBoundFunction.h: Removed. - * runtime/JSFunction.cpp: - (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): - (JSC::RetrieveCallerFunctionFunctor::operator()): - (JSC::retrieveCallerFunction): - (JSC::JSFunction::getOwnPropertySlot): - (JSC::JSFunction::defineOwnProperty): - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::reset): - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::globalFuncSetTypeErrorAccessor): - * runtime/JSGlobalObjectFunctions.h: - * runtime/JSObject.h: - (JSC::JSObject::inlineGetOwnPropertySlot): - -2014-04-12 Filip Pizlo <fpizlo@apple.com> - - Math.fround() should be an intrinsic - https://bugs.webkit.org/show_bug.cgi?id=131583 - - Reviewed by Geoffrey Garen. - - Makes programs that use Math.fround() run up to 6x faster. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::performNodeCSE): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileArithFRound): - * runtime/Intrinsic.h: - * runtime/MathObject.cpp: - (JSC::MathObject::finishCreation): - -2014-04-12 Filip Pizlo <fpizlo@apple.com> - - FTL should use stackmap register liveness - https://bugs.webkit.org/show_bug.cgi?id=130791 - - Reviewed by Goeffrey Garen. - - Enable the stackmap register liveness support by fixing the two last bugs: - - - If everything is dead after the patchpoint - a good possibility for a put_by_id - - then we shouldn't crash due to a null scratch buffer. - - - Always consider callee-saves as if they were live. More precisely, we should - consider those callee-saves that are not saved by the enclosing function to be live. - For now we do the much simpler thing and consider callee-saves to be always live - since it has minimal impact on the scratch register allocator. It will know not to - preserve those for calls, anyway. - - I tried writing a test for the null scratch buffer thing, but failed. I will land the - test anyway since it seems useful. - - * ftl/FTLCompile.cpp: - (JSC::FTL::usedRegistersFor): - * jit/ScratchRegisterAllocator.cpp: - (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall): - (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall): - * runtime/Options.h: - * tests/stress/repeated-put-by-id-reallocating-transition.js: Added. - (foo): - -2014-04-11 Filip Pizlo <fpizlo@apple.com> - - DFG::FixupPhase should insert conversion nodes after the rest of fixup so that we know how the types settled - https://bugs.webkit.org/show_bug.cgi?id=131424 - - Reviewed by Geoffrey Garen. - - This defers type conversion injection until we've decided on types. This makes the - process of deciding types a bit more flexible - for example we can naturally fixpoint - and change our minds. Only when things are settled do we actually insert conversions. - - This is a necessary prerequisite for keeping double, int52, and JSValue data flow - separate. A SetLocal/GetLocal will appear to be JSValue until we fixpoint and realize - that there are typed uses. If we were eagerly inserting type conversions then we would - first insert a to/from-JSValue conversion in some cases only to then replace it by - the other conversions. It's probably trivial to remove those redundant conversions later - but I think it's better if we don't insert them to begin with. - - * bytecode/CodeOrigin.h: - (JSC::CodeOrigin::operator!): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::run): - (JSC::DFG::FixupPhase::fixupBlock): - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::fixupSetLocalsInBlock): - (JSC::DFG::FixupPhase::fixEdge): - (JSC::DFG::FixupPhase::fixIntEdge): - (JSC::DFG::FixupPhase::injectTypeConversionsInBlock): - (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): - (JSC::DFG::FixupPhase::addRequiredPhantom): - (JSC::DFG::FixupPhase::addPhantomsIfNecessary): - (JSC::DFG::FixupPhase::clearPhantomsAtEnd): - (JSC::DFG::FixupPhase::observeUntypedEdge): Deleted. - (JSC::DFG::FixupPhase::fixupUntypedSetLocalsInBlock): Deleted. - (JSC::DFG::FixupPhase::injectInt32ToDoubleNode): Deleted. - -2014-04-11 Brian J. Burg <burg@cs.washington.edu> - - Web Replay: code generator should consider enclosing class when computing duplicate type names - https://bugs.webkit.org/show_bug.cgi?id=131554 - - Reviewed by Timothy Hatcher. - - We need to prepend an enum's enclosing class, if any, so that multiple enums with the same name - can coexist without triggering a "duplicate types" error. Now, such enums must be referenced - by the enclosing class and enum name. - - Added tests for the new syntax, and rebaselined one test to reflect a previous patch's change. - - * replay/scripts/CodeGeneratorReplayInputs.py: - (Type.type_name): Prepend the enclosing class name. - (Type.type_name.is): - * replay/scripts/tests/expected/fail-on-duplicate-enum-type.json-error: Added. - * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.cpp: Added. - * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.h: Added. - * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.h: Rebaseline. - * replay/scripts/tests/fail-on-duplicate-enum-type.json: Added. - * replay/scripts/tests/generate-enums-with-same-base-name.json: Added. - -2014-04-11 Gavin Barraclough <baraclough@apple.com> - - Rollout - Rewrite Function.bind as a builtin - https://bugs.webkit.org/show_bug.cgi?id=131083 - - Unreviewed. - - Rolling out r167020 while investigating a performance regression. - - * API/JSObjectRef.cpp: - (JSObjectMakeConstructor): - * API/JSScriptRef.cpp: - (parseScript): - * CMakeLists.txt: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * builtins/BuiltinExecutables.cpp: - (JSC::BuiltinExecutables::createBuiltinExecutable): - * builtins/Function.prototype.js: - (apply): - (bind.bindingFunction): Deleted. - (bind.else.bindingFunction): Deleted. - (bind): Deleted. - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::generateFunctionCodeBlock): - * bytecompiler/NodesCodegen.cpp: - (JSC::InstanceOfNode::emitBytecode): - * interpreter/Interpreter.cpp: - * parser/Lexer.cpp: - (JSC::Lexer<T>::Lexer): - (JSC::Lexer<LChar>::parseIdentifier): - (JSC::Lexer<UChar>::parseIdentifier): - * parser/Lexer.h: - * parser/Parser.cpp: - (JSC::Parser<LexerType>::Parser): - (JSC::Parser<LexerType>::parseInner): - * parser/Parser.h: - (JSC::parse): - * parser/ParserModes.h: - * runtime/ArgumentsIteratorConstructor.cpp: - (JSC::ArgumentsIteratorConstructor::finishCreation): - * runtime/ArrayConstructor.cpp: - (JSC::ArrayConstructor::finishCreation): - * runtime/BooleanConstructor.cpp: - (JSC::BooleanConstructor::finishCreation): - * runtime/CodeCache.cpp: - (JSC::CodeCache::getGlobalCodeBlock): - (JSC::CodeCache::getFunctionExecutableFromGlobalCode): - * runtime/CommonIdentifiers.h: - * runtime/Completion.cpp: - (JSC::checkSyntax): - * runtime/DateConstructor.cpp: - (JSC::DateConstructor::finishCreation): - * runtime/ErrorConstructor.cpp: - (JSC::ErrorConstructor::finishCreation): - * runtime/Executable.cpp: - (JSC::ProgramExecutable::checkSyntax): - * runtime/FunctionConstructor.cpp: - (JSC::FunctionConstructor::finishCreation): - * runtime/FunctionPrototype.cpp: - (JSC::FunctionPrototype::addFunctionProperties): - (JSC::functionProtoFuncBind): - * runtime/JSArrayBufferConstructor.cpp: - (JSC::JSArrayBufferConstructor::finishCreation): - * runtime/JSBoundFunction.cpp: Added. - (JSC::boundFunctionCall): - (JSC::boundFunctionConstruct): - (JSC::JSBoundFunction::create): - (JSC::JSBoundFunction::destroy): - (JSC::JSBoundFunction::customHasInstance): - (JSC::JSBoundFunction::JSBoundFunction): - (JSC::JSBoundFunction::finishCreation): - (JSC::JSBoundFunction::visitChildren): - * runtime/JSBoundFunction.h: Added. - (JSC::JSBoundFunction::targetFunction): - (JSC::JSBoundFunction::boundThis): - (JSC::JSBoundFunction::boundArgs): - (JSC::JSBoundFunction::createStructure): - * runtime/JSFunction.cpp: - (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): - (JSC::RetrieveCallerFunctionFunctor::operator()): - (JSC::retrieveCallerFunction): - (JSC::JSFunction::getOwnPropertySlot): - (JSC::JSFunction::getOwnNonIndexPropertyNames): - (JSC::JSFunction::put): - (JSC::JSFunction::defineOwnProperty): - * runtime/JSGenericTypedArrayViewConstructorInlines.h: - (JSC::JSGenericTypedArrayViewConstructor<ViewClass>::finishCreation): - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::reset): - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::globalFuncSetTypeErrorAccessor): Deleted. - * runtime/JSGlobalObjectFunctions.h: - * runtime/JSObject.cpp: - (JSC::JSObject::putDirectPrototypeProperty): Deleted. - (JSC::JSObject::putDirectPrototypePropertyWithoutTransitions): Deleted. - * runtime/JSObject.h: - * runtime/JSPromiseConstructor.cpp: - (JSC::JSPromiseConstructor::finishCreation): - * runtime/MapConstructor.cpp: - (JSC::MapConstructor::finishCreation): - * runtime/MapIteratorConstructor.cpp: - (JSC::MapIteratorConstructor::finishCreation): - * runtime/NameConstructor.cpp: - (JSC::NameConstructor::finishCreation): - * runtime/NativeErrorConstructor.cpp: - (JSC::NativeErrorConstructor::finishCreation): - * runtime/NumberConstructor.cpp: - (JSC::NumberConstructor::finishCreation): - * runtime/ObjectConstructor.cpp: - (JSC::ObjectConstructor::finishCreation): - * runtime/RegExpConstructor.cpp: - (JSC::RegExpConstructor::finishCreation): - * runtime/SetConstructor.cpp: - (JSC::SetConstructor::finishCreation): - * runtime/SetIteratorConstructor.cpp: - (JSC::SetIteratorConstructor::finishCreation): - * runtime/StringConstructor.cpp: - (JSC::StringConstructor::finishCreation): - * runtime/WeakMapConstructor.cpp: - (JSC::WeakMapConstructor::finishCreation): - -2014-04-11 David Kilzer <ddkilzer@apple.com> - - [ASan] Build broke because libCompileRuntimeToLLVMIR.a links to libclang_rt.asan_osx_dynamic.dylib - <http://webkit.org/b/131556> - <rdar://problem/16591856> - - Reviewed by Brent Fulgham. - - * Configurations/CompileRuntimeToLLVMIR.xcconfig: Clear - OTHER_LDFLAGS so the ASan build does not try to link to - libclang_rt.asan_osx_dynamic.dylib. - -2014-04-11 Mark Lam <mark.lam@apple.com> - - JSMainThreadExecState::call() should clear exceptions before returning. - <https://webkit.org/b/131530> - - Reviewed by Geoffrey Garen. - - Added a version of JSC::call() that return any uncaught exception instead - of leaving it pending in the VM. - - As part of this change, I updated various parts of the code base to use the - new API as needed. - - * bindings/ScriptFunctionCall.cpp: - (Deprecated::ScriptFunctionCall::call): - - ScriptFunctionCall::call() is only used by the inspector to inject scripts. - The injected scripts that will include Inspector scripts that should catch - and handle any exceptions that were thrown. We should not be seeing any - exceptions returned from this call. However, we do have checks for - exceptions in case there are bugs in the Inspector scripts which allowed - the exception to leak through. Hence, it is proper to clear the exception - here, and only record the fact that an exception was seen (if present). - - * bindings/ScriptFunctionCall.h: - * inspector/InspectorEnvironment.h: - * runtime/CallData.cpp: - (JSC::call): - * runtime/CallData.h: - -2014-04-11 Oliver Hunt <oliver@apple.com> - - Add BuiltinLog function to make debugging builtins easier - https://bugs.webkit.org/show_bug.cgi?id=131550 - - Reviewed by Andreas Kling. - - Add a logging function that builtins can use for debugging. - - * runtime/CommonIdentifiers.h: - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::reset): - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::globalFuncBuiltinLog): - * runtime/JSGlobalObjectFunctions.h: - -2014-04-11 Julien Brianceau <jbriance@cisco.com> - - Fix LLInt for sh4 architecture (broken since C stack merge). - https://bugs.webkit.org/show_bug.cgi?id=131532 - - Reviewed by Mark Lam. - - This patch fixes build and also implements sh4 parts for initPCRelative and - setEntryAddress macros introduced in http://trac.webkit.org/changeset/167094. - - * llint/LowLevelInterpreter.asm: - * llint/LowLevelInterpreter32_64.asm: - * offlineasm/instructions.rb: - * offlineasm/sh4.rb: - -2014-04-10 Michael Saboff <msaboff@apple.com> - - Crash beneath DFG JIT code @ video.disney.com - https://bugs.webkit.org/show_bug.cgi?id=131447 - - Reviewed by Geoffrey Garen. - - The 32-bit path of speculateMisc() uses an 'is not int32' check followed by - 'tag not less than Undefined' check. The first check was incorrectly elided if we - knew that the value *was* an int32, when it should have been elided if we already - knew that the value *was not* an int32. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::speculateMisc): - * tests/stress/test-spec-misc.js: Added test. - (getX): - (foo): - (bar): - -2014-04-08 Filip Pizlo <fpizlo@apple.com> - - Make room for additional types in SpeculatedType.h - https://bugs.webkit.org/show_bug.cgi?id=131422 - - Reviewed by Sam Weinig. - - This'll make it easier to add DoubleHeavyNaN and DoubleEmptyNaN. - - * bytecode/SpeculatedType.h: - -2014-04-10 Alex Christensen <achristensen@webkit.org> - - Compile fix for Win64. - https://bugs.webkit.org/show_bug.cgi?id=131508 - - Reviewed by Geoffrey Garen. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::fillNops): - Added unsigned template parameter to distinguish between size_t and unsigned long. - -2014-04-10 Michael Saboff <msaboff@apple.com> - - LLInt interpreter code should be generated as part of one function - https://bugs.webkit.org/show_bug.cgi?id=131205 - - Reviewed by Mark Lam. - - Changed the generation of llint opcodes so that they are all part of the same - global function, llint_entry. That function is used to fill in an entry point - table that includes each of the opcodes and helpers. - - * CMakeLists.txt: - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: - * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.sh: - * JavaScriptCore.xcodeproj/project.pbxproj: - Added appropriate use of new -I option to offline assembler and offset - generator scripts. - - * llint/LowLevelInterpreter.asm: - * llint/LowLevelInterpreter.cpp: - * llint/LowLevelInterpreter.h: - * offlineasm/arm.rb: - * offlineasm/arm64.rb: - * offlineasm/asm.rb: - * offlineasm/ast.rb: - * offlineasm/backends.rb: - * offlineasm/cloop.rb: - * offlineasm/generate_offset_extractor.rb: - * offlineasm/instructions.rb: - * offlineasm/parser.rb: - * offlineasm/registers.rb: - * offlineasm/self_hash.rb: - * offlineasm/settings.rb: - * offlineasm/transform.rb: - * offlineasm/x86.rb: - Added a new "global" keyword to the offline assembler that denotes a label that - should be exported. Added opcode and operand support to get the absolute - address of a local label using position independent calculations. Updated the - offline assembler to handle included files, both when generating the checksum - as well as including files from other than the local directory via a newly - added -I option. The offline assembler now automatically determines external - functions by keeping track of referenced functions that are defined within the - assembly source. This is used both for choosing the correct macro for external - references as well as generating the needed EXTERN directives for masm. - Updated the generation of the masm only .sym file to be written once at the end - of the offline assembler. - - * assembler/MacroAssemblerCodeRef.h: - (JSC::MacroAssemblerCodePtr::createLLIntCodePtr): - (JSC::MacroAssemblerCodeRef::createLLIntCodeRef): - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::dumpBytecode): - (JSC::CodeBlock::CodeBlock): - * bytecode/GetByIdStatus.cpp: - (JSC::GetByIdStatus::computeFromLLInt): - * bytecode/Opcode.h: - (JSC::padOpcodeName): - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeFromLLInt): - * jit/JIT.cpp: - (JSC::JIT::privateCompileMainPass): - * jit/JITStubs.h: - * llint/LLIntCLoop.cpp: - (JSC::LLInt::initialize): - * llint/LLIntData.h: - (JSC::LLInt::getCodeFunctionPtr): - (JSC::LLInt::getOpcode): Deleted. - (JSC::LLInt::getCodePtr): Deleted. - * llint/LLIntOpcode.h: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * llint/LLIntThunks.cpp: - (JSC::LLInt::functionForCallEntryThunkGenerator): - (JSC::LLInt::functionForConstructEntryThunkGenerator): - (JSC::LLInt::functionForCallArityCheckThunkGenerator): - (JSC::LLInt::functionForConstructArityCheckThunkGenerator): - (JSC::LLInt::evalEntryThunkGenerator): - (JSC::LLInt::programEntryThunkGenerator): - * llint/LLIntThunks.h: - Changed references to llint helpers to go through the entry point table populated - by llint_entry. Added helpers to OpcodeID enum for all builds. - - * bytecode/BytecodeList.json: - * generate-bytecode-files: - * llint/LLIntCLoop.cpp: - (JSC::LLInt::CLoop::initialize): - Reordered sections to match the order that the functions are added to the entry point - table. Added new "asmPrefix" property for symbols that have one name but are generated - with a prefix, e.g. op_enter -> llint_op_enter. Eliminated the "emitDefineID" property - as we are using enums for all bytecode references. Changed the C Loop only - llint_c_loop_init to llint_entry. - -2014-04-10 Matthew Mirman <mmirman@apple.com> - - WIP for inlining C++. Added a build target to produce LLVM IR. - https://bugs.webkit.org/show_bug.cgi?id=130523 - - Reviewed by Mark Rowe. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * build-symbol-table-index.py: Added. - * build-symbol-table-index.sh: Added. - * Configurations/CompileRuntimeToLLVMIR.xcconfig: Added. - * copy-llvm-ir-to-derived-sources.sh: Added. - -2014-04-10 Brian J. Burg <burg@cs.washington.edu> - - Web Replay: memoize plugin data for navigator.mimeTypes and navigator.plugins - https://bugs.webkit.org/show_bug.cgi?id=131341 - - Reviewed by Timothy Hatcher. - - Add support for encoding/decoding unsigned long with EncodedValue. - It is a distinct type from uint32_t and uint64_t. - - * replay/EncodedValue.cpp: - (JSC::EncodedValue::convertTo<unsigned long>): - * replay/EncodedValue.h: - -2014-04-10 Mark Lam <mark.lam@apple.com> - - LLINT loadisFromInstruction should handle the big endian case. - <https://webkit.org/b/131495> - - Reviewed by Mark Hahnenberg. - - The LLINT loadisFromInstruction macro aims to load the least significant - 32-bit word from the 64-bit bytecode instruction stream and sign extend - it. For big endian machines, the current implementation would load the - wrong 32-bit word. - - Without this fix, the JSC tests will crash on big endian machines. - Thanks to Tomas Popela for diagnosing this issue. - - * llint/LowLevelInterpreter.asm: - -2014-04-09 Mark Lam <mark.lam@apple.com> - - Temporarily disable the JIT for the Windows port. - <https://webkit.org/b/131470> - - Reviewed by Brent Fulgham. - - This is a temporary stop gap measure to green the Windows bots until - we have a fix for https://webkit.org/b/131182. - - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): - -2014-04-09 Juergen Ributzka <juergen@apple.com> - - [FTL] Emit multibyte NOPs on X86-64 - https://bugs.webkit.org/show_bug.cgi?id=131394 - - Reviewed by Michael Saboff. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::fillNops): - -2014-04-09 Julien Brianceau <jbriance@cisco.com> - - Get rid of JITOperationWrappers.h header file. - https://bugs.webkit.org/show_bug.cgi?id=131450 - - Reviewed by Michael Saboff. - - JITOperationWrappers header file contains architecture specific code that is - not needed anymore, so get rid of it. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGOperations.cpp: - * jit/JITOperationWrappers.h: Removed. - * jit/JITOperations.cpp: - -2014-04-09 Mark Lam <mark.lam@apple.com> - - Ensure that LLINT accessing of the ProtoCallFrame is big endian friendly. - <https://webkit.org/b/131449> - - Reviewed by Mark Hahnenberg. - - Change ProtoCallFrame::paddedArgCount to be of type uint32_t. The argCount - that it pads is of type int anyway. It doesn't need to be 64 bit. This - also makes it work with the LLINT which is loading it with a loadi - instruction. - - We should add the PayLoadOffset to ProtoCallFrame::argCountAndCodeOriginValue - when loading the argCount. - - The paddedArgCount issue was causing failures when running the JSC tests on a - 64-bit big endian machine. In this case, the paddedArgCount in the - ProtoCallFrame has the value 2. However, because the paddedArgCount was stored - as a 64-bit size_t and the LLINT was loading only the low address 32-bits of - that field, the LLINT got a value of 0 instead of the expected 2. With this - patch, we now have a matching store and load of a 32-bit value, and endianness - no longer comes into play. - - As for ProtoCallFrame::argCountAndCodeOriginValue, the argCount is stored in - the payload field of the Register. In the definition of EncodedValueDescriptor, - We already ensure that that the payload is in the least significant 32-bits for - little endian machines, and in the most significant 32-bits for big endian - machines. This means that there is no endianness bug when loading this value - using loadi. However, adding the PayLoadOffset clarifies the intent of the - code to load the payload part of the Register value. - - * interpreter/ProtoCallFrame.h: - (JSC::ProtoCallFrame::setPaddedArgCount): - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: - -2014-04-08 Oliver Hunt <oliver@apple.com> - - Rewrite Function.bind as a builtin - https://bugs.webkit.org/show_bug.cgi?id=131083 - - Reviewed by Geoffrey Garen. - - This change removes the existing function.bind implementation - entirely so JSBoundFunction is no more. - - Instead we just return a regular JS closure with a few - private properties hanging off it that allow us to perform - the necessary bound function fakery. While most of this is - simple, a couple of key changes: - - - The parser and lexer now directly track whether they're - parsing code for call or construct and convert the private - name @IsConstructor into TRUETOK or FALSETOK as appropriate. - This automatically gives us the ability to vary behaviour - from within the builtin. It also leaves a lot of headroom - for trivial future improvements. - - The instanceof operator now uses the prototypeForHasInstance - private name, and we have a helper function to ensure that - all objects that need to can update their magical 'prototype' - property pair correctly. - - * API/JSScriptRef.cpp: - (parseScript): - * JavaScriptCore.xcodeproj/project.pbxproj: - * builtins/BuiltinExecutables.cpp: - (JSC::BuiltinExecutables::createBuiltinExecutable): - * builtins/Function.prototype.js: - (bind.bindingFunction): - (bind.else.bindingFunction): - (bind): - * bytecode/UnlinkedCodeBlock.cpp: - (JSC::generateFunctionCodeBlock): - * bytecompiler/NodesCodegen.cpp: - (JSC::InstanceOfNode::emitBytecode): - * interpreter/Interpreter.cpp: - * parser/Lexer.cpp: - (JSC::Lexer<T>::Lexer): - (JSC::Lexer<LChar>::parseIdentifier): - (JSC::Lexer<UChar>::parseIdentifier): - * parser/Lexer.h: - * parser/Parser.cpp: - (JSC::Parser<LexerType>::Parser): - (JSC::Parser<LexerType>::parseInner): - * parser/Parser.h: - (JSC::parse): - * parser/ParserModes.h: - * runtime/CodeCache.cpp: - (JSC::CodeCache::getGlobalCodeBlock): - (JSC::CodeCache::getFunctionExecutableFromGlobalCode): - * runtime/CommonIdentifiers.h: - * runtime/Completion.cpp: - (JSC::checkSyntax): - * runtime/Executable.cpp: - (JSC::ProgramExecutable::checkSyntax): - * runtime/FunctionPrototype.cpp: - (JSC::FunctionPrototype::addFunctionProperties): - (JSC::functionProtoFuncBind): Deleted. - * runtime/JSBoundFunction.cpp: Removed. - * runtime/JSBoundFunction.h: Removed. - * runtime/JSFunction.cpp: - (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): - (JSC::RetrieveCallerFunctionFunctor::operator()): - (JSC::retrieveCallerFunction): - (JSC::JSFunction::getOwnPropertySlot): - (JSC::JSFunction::defineOwnProperty): - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::reset): - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::globalFuncSetTypeErrorAccessor): - * runtime/JSGlobalObjectFunctions.h: - * runtime/JSObject.h: - (JSC::JSObject::inlineGetOwnPropertySlot): - -2014-04-08 Jon Lee <jonlee@apple.com> - - Turn MSE on by default - https://bugs.webkit.org/show_bug.cgi?id=131313 - <rdar://problem/16525223> - - Reviewed by Jer Noble. - - * Configurations/FeatureDefines.xcconfig: - -2014-04-08 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Prevent deadlocks receiving WIRPermissionDenied message - https://bugs.webkit.org/show_bug.cgi?id=131406 - - Reviewed by Timothy Hatcher. - - * inspector/remote/RemoteInspector.h: - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::stop): - (Inspector::RemoteInspector::stopInternal): - (Inspector::RemoteInspector::xpcConnectionReceivedMessage): - Provide a way to stop externally and a path to stop when in - the middle of handling a message already with the locked mutex. - - * inspector/remote/RemoteInspectorXPCConnection.h: - * inspector/remote/RemoteInspectorXPCConnection.mm: - (Inspector::RemoteInspectorXPCConnection::close): - (Inspector::RemoteInspectorXPCConnection::closeFromMessage): - Provide a way to close externally and a path to close when in - the middle of handling a message already with a mutex. - -2014-04-08 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Address stale FIXMEs concerning console in JSContext inspection - https://bugs.webkit.org/show_bug.cgi?id=131398 - - Reviewed by Timothy Hatcher. - - * inspector/InjectedScriptSource.js: - The console object can be deleted from a page or JSContext, - so keep code that expects that it could have been deleted - to be resilient in those cases. - - * inspector/JSGlobalObjectScriptDebugServer.h: - * inspector/agents/JSGlobalObjectDebuggerAgent.h: - * inspector/agents/JSGlobalObjectRuntimeAgent.h: - Change the FIXMEs to NOTEs that explain why these functions - have empty implementations for JSContext inspection. - -2014-04-08 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix a goofy assertion to fix debug. - - * bytecode/PolymorphicPutByIdList.h: - (JSC::PutByIdAccess::isSetter): - (JSC::PutByIdAccess::oldStructure): - (JSC::PutByIdAccess::chain): - (JSC::PutByIdAccess::stubRoutine): - (JSC::PutByIdAccess::customSetter): - -2014-04-08 Filip Pizlo <fpizlo@apple.com> - - Fail silently if the LLVM dylib isn't found - https://bugs.webkit.org/show_bug.cgi?id=131385 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::compileInThreadImpl): - * llvm/InitializeLLVM.cpp: - (JSC::initializeLLVM): - * llvm/InitializeLLVM.h: - * llvm/InitializeLLVMPOSIX.cpp: - (JSC::initializeLLVMPOSIX): - -2014-04-07 Filip Pizlo <fpizlo@apple.com> - - Repatch should support setters and plant calls to them directly - https://bugs.webkit.org/show_bug.cgi?id=130750 - - Reviewed by Geoffrey Garen. - - All of the infrastructure was in place so this just enables setter optimization. - - This is a 12x speed-up on setter microbenchmarks. This is a 1% speed-up on Octane. - - * bytecode/PolymorphicPutByIdList.cpp: - (JSC::PutByIdAccess::visitWeak): - * bytecode/PolymorphicPutByIdList.h: - (JSC::PutByIdAccess::setter): - (JSC::PutByIdAccess::customSetter): Deleted. - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeForStubInfo): - * jit/Repatch.cpp: - (JSC::toString): - (JSC::kindFor): - (JSC::customFor): - (JSC::generateByIdStub): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - * runtime/JSObject.cpp: - (JSC::JSObject::put): - * runtime/Lookup.h: - (JSC::putEntry): - * runtime/PutPropertySlot.h: - (JSC::PutPropertySlot::setCacheableSetter): - (JSC::PutPropertySlot::isCacheableSetter): - (JSC::PutPropertySlot::isCacheableCustom): - (JSC::PutPropertySlot::setCacheableCustomProperty): Deleted. - (JSC::PutPropertySlot::isCacheableCustomProperty): Deleted. - * tests/stress/setter.js: Added. - (foo): - -2014-04-07 Filip Pizlo <fpizlo@apple.com> - - Setters are just getters that take an extra argument and don't return a value - https://bugs.webkit.org/show_bug.cgi?id=131336 - - Reviewed by Geoffrey Garen. - - Other than that, they're totally the same thing. - - This isn't as dumb as it sounds. - - Most of the work in calling an accessor has to do with emitting the necessary checks for - figuring out whether we're calling the accessor we expected, followed by the boilerplate - needed for setting up a call inside of a stub. It makes sense for the code to be totally - common. - - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::storeValue): - (JSC::AssemblyHelpers::moveTrustedValue): - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupResults): - * jit/Repatch.cpp: - (JSC::kindFor): - (JSC::customFor): - (JSC::generateByIdStub): - (JSC::tryCacheGetByID): - (JSC::tryBuildGetByIDList): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - (JSC::generateGetByIdStub): Deleted. - (JSC::emitCustomSetterStub): Deleted. - * runtime/JSCJSValue.h: - (JSC::JSValue::asValue): - * runtime/PutPropertySlot.h: - (JSC::PutPropertySlot::cachedOffset): - -2014-04-07 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Hang in debuggable application after receiving WIRPermissionDenied - https://bugs.webkit.org/show_bug.cgi?id=131321 - - Reviewed by Mark Rowe. - - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::xpcConnectionReceivedMessage): - Avoid attempting to take the same lock twice. Move the received message - lock grab after the WIRPermissionDenied branch, which takes the lock - inside RemoteInspector::stop. - -2014-04-07 Filip Pizlo <fpizlo@apple.com> - - Make it possible to disable some of the FTL's more interesting features - https://bugs.webkit.org/show_bug.cgi?id=131312 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleGetById): - (JSC::DFG::ByteCodeParser::handlePutById): - (JSC::DFG::ByteCodeParser::parse): - * runtime/Options.h: - -2014-04-04 Mark Lam <mark.lam@apple.com> - - Date object needs to check for ES5 15.9.1.14 TimeClip limit. - <https://webkit.org/b/131248> - - Reviewed by Mark Hahnenberg. - - The current Date object code does not adequately check for the ES5 - 15.9.1.14 TimeClip limit. As a result, some calculations can underflow - / overflow and produce unexpected results. - - For example, we were getting an assertion failure in - WTF::equivalentYearForDST() due int underflows in this function, which - in turn were due to an int overflow in WTF::msToYear(). - - This patch adds the needed checks, and adds some assertions to ensure - that the used values are sane. - - The changes have no noticeable impact on benchmark results. - - * runtime/DateConstructor.cpp: - (JSC::callDate): - * runtime/JSDateMath.cpp: - (JSC::localTimeOffset): - (JSC::gregorianDateTimeToMS): - (JSC::msToGregorianDateTime): - (JSC::parseDateFromNullTerminatedCharacters): - (JSC::parseDate): - * runtime/JSDateMath.h: - - parseDateFromNullTerminatedCharacters() does not need to be public. - Made it a static function. - * runtime/VM.cpp: - (JSC::VM::resetDateCache): - - Changed cachedDateStringValue to use std::numeric_limits<double>::quiet_NaN() - to be consistent with other Date code. - -2014-04-06 Csaba Osztrogonác <ossy@webkit.org> - - Unreviewed speculative 32-bit buildfix after r166837. - - * heap/Heap.cpp: - (JSC::Heap::updateObjectCounts): - -2014-04-06 Dan Bernstein <mitz@apple.com> - - 32-bit build fix. - - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::setInputCursor): - -2014-04-04 Brian J. Burg <burg@cs.washington.edu> - - Enable WEB_REPLAY for PLATFORM(MAC) - https://bugs.webkit.org/show_bug.cgi?id=130700 - - Reviewed by Timothy Hatcher. - - * Configurations/FeatureDefines.xcconfig: - -2014-04-05 Mark Hahnenberg <mhahnenberg@apple.com> - - Add missing files from r166837 - - * heap/GCLogging.cpp: Added. - (JSC::GCLogging::levelAsString): - (JSC::LoggingFunctor::LoggingFunctor): - (JSC::LoggingFunctor::~LoggingFunctor): - (JSC::LoggingFunctor::operator()): - (JSC::LoggingFunctor::log): - (JSC::LoggingFunctor::reviveCells): - (JSC::LoggingFunctor::returnValue): - (JSC::GCLogging::dumpObjectGraph): - * heap/GCLogging.h: Added. - -2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com> - - Enhanced GC logging - https://bugs.webkit.org/show_bug.cgi?id=131246 - - Reviewed by Geoff Garen. - - Getting data on the state of the JSC Heap at runtime is currently in a sad state. - The OBJECT_MARK_LOGGING macro enables some basic GC logging, but it requires a full - recompile to turn it on. It would be nice if we could runtime enable our GC logging - infrastructure while incurring minimal cost when it is disabled. - - It would also be nice to get a complete view of the Heap. Currently OBJECT_MARK_LOGGING - provides us with the discovered roots along with parent-child relationships as objects - are scanned. However, once an object is scanned it will never be declared as the child - of another object during that collection. This gives us a tree-like view of the - Heap (i.e. each scanned node only reports having a single parent), where the actual - Heap can be an arbitrary graph. - - This patch replaces OBJECT_MARK_LOGGING and gives us these nice to haves. First it enhances - our logGC() runtime Option by changing it to be a tri-state value of None, Basic, or Verbose - logging levels. None means no logging is done, Basic is what logGC() = true would have done - prior to this patch, and Verbose logs all object relationships. - - JSCell has new dump/dumpToStream methods, the latter of which is "virtual" to allow - subclasses to override the default string representation that will be dumped. These - methods allow JSCells to be dumped using the standard dataLog() calls similar to much of - the logging infrastructure in our compilers. - - This patch also adds a GCLogging class that handles dumping the relationships between objects. - It does this by using the pre-existing visitChildren virtual methods to obtain the immediate - children of each live cell at the end of garbage collection. - - This change meets our goal of being neutral on the benchmarks we track. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * heap/GCLogging.cpp: Added. - (JSC::GCLogging::levelAsString): - (JSC::LoggingFunctor::LoggingFunctor): - (JSC::LoggingFunctor::operator()): - (JSC::LoggingFunctor::log): - (JSC::LoggingFunctor::reviveCells): - (JSC::LoggingFunctor::returnValue): - (JSC::GCLogging::dumpObjectGraph): - * heap/GCLogging.h: Added. - * heap/GCSegmentedArray.h: - (JSC::GCSegmentedArray::begin): - (JSC::GCSegmentedArray::end): - * heap/Heap.cpp: - (JSC::Heap::markRoots): - (JSC::Heap::visitSmallStrings): - (JSC::Heap::visitConservativeRoots): - (JSC::Heap::visitCompilerWorklists): - (JSC::Heap::visitProtectedObjects): - (JSC::Heap::visitTempSortVectors): - (JSC::Heap::visitArgumentBuffers): - (JSC::Heap::visitException): - (JSC::Heap::visitStrongHandles): - (JSC::Heap::visitHandleStack): - (JSC::Heap::traceCodeBlocksAndJITStubRoutines): - (JSC::Heap::visitWeakHandles): - (JSC::Heap::updateObjectCounts): - (JSC::Heap::collect): - (JSC::Heap::didFinishCollection): - * heap/Heap.h: - * heap/MarkStack.h: - * heap/SlotVisitor.cpp: - (JSC::SlotVisitor::dump): - * heap/SlotVisitor.h: - (JSC::SlotVisitor::markStack): - * heap/SlotVisitorInlines.h: - (JSC::SlotVisitor::internalAppend): - * runtime/ClassInfo.h: - * runtime/JSCell.cpp: - (JSC::JSCell::dump): - (JSC::JSCell::dumpToStream): - (JSC::JSCell::className): - * runtime/JSCell.h: - * runtime/JSCellInlines.h: - (JSC::JSCell::visitChildren): - * runtime/JSString.cpp: - (JSC::JSString::dumpToStream): - (JSC::JSString::visitChildren): - * runtime/JSString.h: - (JSC::JSString::length): - (JSC::JSRopeString::RopeBuilder::length): - * runtime/Options.cpp: - (JSC::parse): - (JSC::Options::setOption): - (JSC::Options::dumpOption): - * runtime/Options.h: - -2014-04-05 Mark Hahnenberg <mhahnenberg@apple.com> - - Remove bogus ASSERT in -JSVirtualMachine scanObjectGraph - https://bugs.webkit.org/show_bug.cgi?id=131251 - - Reviewed by Geoffrey Garen. - - * API/JSVirtualMachine.mm: - (scanExternalObjectGraph): - * API/tests/testapi.mm: - -2014-04-03 Brian J. Burg <burg@cs.washington.edu> - - Web Inspector: hook up probe samples to TimelineAgent's records - https://bugs.webkit.org/show_bug.cgi?id=131127 - - Reviewed by Timothy Hatcher. - - * inspector/ScriptDebugListener.h: Add a proper forward declaration for ScriptBreakpointAction. - -2014-04-04 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r166820. - https://bugs.webkit.org/show_bug.cgi?id=131256 - - Broke builds. (Requested by bdash on #webkit). - - Reverted changeset: - - "WIP for inlining C++. Added a build target to produce llvm - ir." - https://bugs.webkit.org/show_bug.cgi?id=130523 - http://trac.webkit.org/changeset/166820 - -2014-04-04 Matthew Mirman <mmirman@apple.com> - - WIP for inlining C++. Added a build target to produce llvm ir. - https://bugs.webkit.org/show_bug.cgi?id=130523 - - Reviewed by Filip Pizlo. - - The llvm ir gets placed JavaScriptCoreRuntimeToLLVMir.build with the extension .o - - * JavaScriptCore.xcodeproj/project.pbxproj: - * build_index.py: Added. - * Configurations/CompileRuntimeToLLVMir.xcconfig: Added. - -2014-04-04 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Log JS Exceptions to System Console if JavaScriptCoreOutputConsoleMessagesToSystemConsole enabled - https://bugs.webkit.org/show_bug.cgi?id=131241 - - Reviewed by Timothy Hatcher. - - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - Log the exception to the system console if system console output is enabled. - -2014-04-04 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Provide a way for JSContext console to log to system console - https://bugs.webkit.org/show_bug.cgi?id=131050 - - Reviewed by Timothy Hatcher. - - Applications often re-expose some log -> NSLog functionality. - We already have the capability ourselves, which includes extra - information such as sourceURL:line:column, all arguments instead - of just one argument, and backtrace information on console.trace. - Therefore it would be convenient if developers could just use - the built-in console.log and get rich output in both the inspector - and the console, without writing their own logger. - - The logging will be enabled in debug builds by default, and can be enabled - otherwise by setting a user default before creating the first context. - - For example, in the application itself: - - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"JavaScriptCoreOutputConsoleMessagesToSystemConsole"]; - - Or from outside the application: - - shell> defaults write <app-bundle-identifier> JavaScriptCoreOutputConsoleMessagesToSystemConsole -bool YES - - * inspector/JSConsoleClient.h: - * inspector/JSConsoleClient.cpp: - (Inspector::JSConsoleClient::logToSystemConsole): - (Inspector::JSConsoleClient::setLogToSystemConsole): - (Inspector::JSConsoleClient::initializeLogToSystemConsole): - (Inspector::JSConsoleClient::JSConsoleClient): - Global setting for logging to system console. Enabled on - debug builds, and by a user default on supported platforms. - - (Inspector::JSConsoleClient::messageWithTypeAndLevel): - Log to system console when the static setting is enabled. - - * runtime/ConsoleClient.h: - * runtime/ConsoleClient.cpp: - (JSC::appendURLAndPosition): - (JSC::appendMessagePrefix): - (JSC::ConsoleClient::printConsoleMessage): - (JSC::ConsoleClient::printConsoleMessageWithArguments): - Clean up printing. Build strings and use WTFLogAlways instead of printf - for consistant logging. - - * runtime/ConsoleClient.cpp: - (JSC::ConsoleClient::printConsoleMessageWithArguments): - Clean up printing. If there is no source URL, don't print a leading colon. - -2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com> - - Use JSCell::indexingType instead of Structure::indexingType wherever possible - https://bugs.webkit.org/show_bug.cgi?id=131230 - - Reviewed by Mark Lam. - - Avoid the indirection through the Structure. - - * bytecode/ArrayAllocationProfile.cpp: - (JSC::ArrayAllocationProfile::updateIndexingType): - * bytecode/ArrayAllocationProfile.h: - (JSC::ArrayAllocationProfile::selectIndexingType): - * heap/HeapStatistics.cpp: - (JSC::StorageStatistics::operator()): - * runtime/ArrayPrototype.cpp: - (JSC::attemptFastSort): - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::objectPrototypeIsSane): - (JSC::JSGlobalObject::arrayPrototypeChainIsSane): - (JSC::JSGlobalObject::stringPrototypeChainIsSane): - * runtime/JSPropertyNameIterator.cpp: - (JSC::JSPropertyNameIterator::create): - -2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com> - - Use JSCell::type instead of TypeInfo::type wherever possible - https://bugs.webkit.org/show_bug.cgi?id=131229 - - Reviewed by Michael Saboff. - - Avoid going through the Structure and reifying the TypeInfo. - - * runtime/Executable.h: - (JSC::ExecutableBase::isEvalExecutable): - (JSC::ExecutableBase::isProgramExecutable): - -2014-04-03 Andreas Kling <akling@apple.com> - - Fast-path for casting JS wrappers to JSNode. - <https://webkit.org/b/131196> - - Allow code outside of JSC (well, WebCore) to extend the JSType spectrum - a little bit. We do this by exposing a LastJSCObjectType constant so - WebCore can encode its own wrapper types after that. - - Reviewed by Mark Hahnenberg and Geoff Garen. - - * runtime/JSType.h: - - Added LastJSCObjectType for use by WebCore. - - * runtime/JSObject.h: - (JSC::JSObject::isVariableObject): - - Updated since this can no longer assume that types >= VariableObjectType - are all variable objects. - -2014-04-03 Mark Hahnenberg <mhahnenberg@apple.com> - - All Heap::writeBarriers should be inline - https://bugs.webkit.org/show_bug.cgi?id=131197 - - Reviewed by Mark Lam. - - One is in a JSCellInlines.h, another is in Heap.cpp. These are all critical - enough and small enough to belong in HeapInlines.h. Also added the proper - ENABLE(GGC) ifdefs to minimize the cost of C++ barriers for !ENABLE(GGC) builds. - - * heap/Heap.cpp: - (JSC::Heap::writeBarrier): Deleted. - * heap/Heap.h: - * heap/HeapInlines.h: - (JSC::Heap::writeBarrier): - * runtime/JSCellInlines.h: - (JSC::Heap::writeBarrier): Deleted. - -2014-04-03 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: JSContext inspection provide a way to opt-out of including Native Call Stacks in Exception traces reported to Web Inspector - https://bugs.webkit.org/show_bug.cgi?id=131186 - - Reviewed by Geoffrey Garen. - - * API/JSContextPrivate.h: - * API/JSContext.mm: - (-[JSContext _includesNativeCallStackWhenReportingExceptions]): - (-[JSContext _setIncludesNativeCallStackWhenReportingExceptions:]): - JSContext ObjC SPI to opt-out of including native call stacks in exceptions. - - * API/JSContextRefPrivate.h: - * API/JSContextRef.cpp: - (JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions): - (JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions): - JSContext C SPI to opt-out of including native call stacks in exceptions. - - * inspector/JSGlobalObjectInspectorController.h: - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - Only include the native call stack if the setting is enabled. It is enabled by default. - -2014-04-03 Mark Lam <mark.lam@apple.com> - - Fix bit rot in ARMv7 JIT probe mechanism. - <https://webkit.org/b/131167> - - Reviewed by Geoffrey Garen. - - 1. The macro assembler does not support pushing the SP register. Worked - around this by pushing the LR register as a placeholder, and then - writing the original SP value to that slot. - 2. The CPUState field in the ProbeContext needs to be aligned on a 4 - byte boundary, not an 8 byte boundary. - - * assembler/MacroAssemblerARMv7.cpp: - (JSC::MacroAssemblerARMv7::probe): - * jit/JITStubsARMv7.h: - -2014-04-02 Mark Lam <mark.lam@apple.com> - - ARMv7 compare32() should not use TST to do CMP's job. - <https://webkit.org/b/131146> - - Reviewed by Geoffrey Garen. - - The ARMv7 implementation of "compare32(RegisterID left, TrustedImm32 right)" - was using "tst reg, reg" to implement "cmp reg, #0". Unfortunately, the tst - instruction doesn't set the Overflow (V) flag and this results in random - results depending on whether there was a preceeding instruction that did set - the Overflow (V) flag. This issue was causing emscripten-cube2hash to run - with a lot of OSR exits where not expected as well as producing wrong results. - - The fix is to use "cmp reg, #0" to do the job properly. - - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::compare32): - -2014-04-02 Mark Hahnenberg <mhahnenberg@apple.com> - - CodeBlockSet should be generational - https://bugs.webkit.org/show_bug.cgi?id=127152 - - Reviewed by Geoffrey Garen. - - During EdenCollections we now only visit those CodeBlocks that: - a) Are new since the last collection if they were somehow otherwise reachable. - b) Are reachable from an Executable that is part of the remembered set. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::CodeBlock): Initialize uninitialized variables. - (JSC::CodeBlock::visitAggregate): Move the addition of the weak reference harvester after the - shouldImmediatelyAssumeLivenessDuringScan check since it's redundant if we assume liveness. - * bytecode/CodeBlock.h: - (JSC::CodeBlock::forEachRelatedCodeBlock): Executes a functor for each CodeBlock reachable from the current CodeBlock (including this). - We use this to clear marks for the CodeBlocks of remembered Executables (see: CodeBlockSet::clearMarksForEdenCollection). - (JSC::CodeBlockSet::mark): Also check the set of new CodeBlocks for memebership when doing conservative scanning. - (JSC::ScriptExecutable::forEachCodeBlock): Executes a functor for each of this Executable's CodeBlocks. - * heap/CodeBlockSet.cpp: - (JSC::CodeBlockSet::~CodeBlockSet): - (JSC::CodeBlockSet::add): - (JSC::CodeBlockSet::promoteYoungCodeBlocks): Moves all CodeBlocks currently in the set of new CodeBlocks into - the set of old CodeBlocks. - (JSC::CodeBlockSet::clearMarksForFullCollection): Clears the marks for all CodeBlocks. - (JSC::CodeBlockSet::clearMarksForEdenCollection): Clears the marks for CodeBlocks owned by Executables in the - remembered set. When an Executable is added to the remembered set it's typically because we need to do something - with its CodeBlock. - (JSC::CodeBlockSet::clearMarks): - (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): Fixpoints over either just the new CodeBlocks or all CodeBlocks - to determine which CodeBlocks are dead and eagerly finalizes/deletes them. - (JSC::CodeBlockSet::remove): - (JSC::CodeBlockSet::traceMarked): Iterate only the currently executing CodeBlocks instead of all CodeBlocks. - (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): Clear m_mayBeExecuting for all currently executing - CodeBlocks because we no longer always do this at the beginning of EdenCollections. - * heap/CodeBlockSet.h: - (JSC::CodeBlockSet::iterate): - * heap/Heap.cpp: - (JSC::Heap::markRoots): - (JSC::Heap::deleteAllCompiledCode): - (JSC::Heap::deleteUnmarkedCompiledCode): - * runtime/Executable.cpp: - (JSC::ScriptExecutable::installCode): Write barrier code on installation. We do this due to the following situation: - a) A CodeBlock is created and is compiled on a DFG worker thread. - b) No GC happens. - c) The CodeBlock has finished being compiled and is installed in the Executable. - d) The function never executes before the next GC. - e) The next GC needs needs to visit the new CodeBlock but the Executable won't be revisited unless - it's added to the remembered set. - -2014-04-02 Mark Lam <mark.lam@apple.com> - - Added some more dataLog info for OSR exits. - <https://webkit.org/b/131120> - - Reviewed by Michael Saboff. - - Adding info about the OSR exit index, the bytecode index of the bytecode - that is OSR exiting, and the reason for the OSR exit. This change is - for debugging code which only comes into play when we use the - --printEachOSRExit option. - - * dfg/DFGOSRExit.h: - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOperations.cpp: - -2014-04-02 Martin Robinson <mrobinson@igalia.com> - - REGRESSION(r165704): [GTK] Inspector resources not correctly generated - https://bugs.webkit.org/show_bug.cgi?id=130343 - - Reviewed by Gustavo Noronha Silva. - - * CMakeLists.txt: We generate the inspector JavaScript file into a directory like the one - in which it should be distributed. This allows us to more easily package it for GTK+. - -2014-04-01 Timothy Hatcher <timothy@apple.com> - - Remove HeapProfiler from the Web Inspector protocol. - - https://bugs.webkit.org/show_bug.cgi?id=131070 - - Reviewed by Joseph Pecoraro. - - * inspector/agents/InspectorConsoleAgent.h: - * inspector/agents/JSGlobalObjectConsoleAgent.cpp: - (Inspector::JSGlobalObjectConsoleAgent::addInspectedHeapObject): Deleted. - * inspector/agents/JSGlobalObjectConsoleAgent.h: - * inspector/protocol/Console.json: - -2014-03-31 Simon Fraser <simon.fraser@apple.com> - - Enable WEB_TIMING on Mac and iOS - https://bugs.webkit.org/show_bug.cgi?id=128064 - - Reviewed by Sam Weinig, Brent Fulgham. - - Enable WEB_TIMING. - - * Configurations/FeatureDefines.xcconfig: - -2014-03-31 Michael Saboff <msaboff@apple.com> - - REGRESSION(r166415): JSObject{Get,Set}Private() don't work with proxies objects - https://bugs.webkit.org/show_bug.cgi?id=130992 - - Reviewed by Mark Hahnenberg. - - Forward JSObjectGetPrivate() and JSObjectSetPrivate() to the wrapped object. - - * API/JSObjectRef.cpp: - (JSObjectGetPrivate): - (JSObjectSetPrivate): - * API/tests/testapi.c: - (main): Added new test case to validate we are properly foarwarding. - -2014-03-31 Mark Hahnenberg <mhahnenberg@apple.com> - - Improve GC_LOGGING - https://bugs.webkit.org/show_bug.cgi?id=130988 - - Reviewed by Geoffrey Garen. - - GC_LOGGING can be useful for diagnosing where we're spending our time during collection, - but it doesn't distinguish between Eden and Full collections in the data it gathers. This - patch updates it so that it can. It also adds the process ID to the beginning of each line - of input to be able to distinguish between the output of multiple processes exiting at the - same time. - - * heap/Heap.cpp: - (JSC::Heap::collect): - -2014-03-31 Dean Jackson <dino@apple.com> - - Remove WEB_ANIMATIONS - https://bugs.webkit.org/show_bug.cgi?id=130989 - - Reviewed by Simon Fraser. - - Remove this feature flag until we plan to implement. - - * Configurations/FeatureDefines.xcconfig: - -2014-03-31 Filip Pizlo <fpizlo@apple.com> - - More validation for FTL inline caches - https://bugs.webkit.org/show_bug.cgi?id=130948 - - Reviewed by Geoffrey Garen. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleGetById): - (JSC::DFG::ByteCodeParser::handlePutById): - * runtime/Options.h: - -2014-03-31 Filip Pizlo <fpizlo@apple.com> - - LLVM IR for store barriers should be nicely arranged and they don't need exception checks - https://bugs.webkit.org/show_bug.cgi?id=130950 - - Reviewed by Mark Hahnenberg. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): - -2014-03-31 Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> - - [CMake] Stop checking for WTF_USE_ICU_UNICODE. - https://bugs.webkit.org/show_bug.cgi?id=130965 - - Reviewed by Martin Robinson. - - This is somewhat of a follow-up to r162782, which got rid of - WTF_USE_ICU_UNICODE in CMake but did not remove the check in JSC's - CMakeLists.txt. This meant the includes and libraries were not - being properly included since then. - - * CMakeLists.txt: - -2014-03-31 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> - - Remove hostThisRegister() and hostThisValue() - https://bugs.webkit.org/show_bug.cgi?id=130895 - - Reviewed by Geoffrey Garen. - - Removed hostThisRegister() and hostThisValue() and instead use thisArgumentOffset() and thisValue() respectively. - - * API/APICallbackFunction.h: - (JSC::APICallbackFunction::call): - * API/JSCallbackObjectFunctions.h: - (JSC::JSCallbackObject<Parent>::call): - * dfg/DFGOSREntry.cpp: - (JSC::DFG::prepareOSREntry): - * inspector/JSInjectedScriptHostPrototype.cpp: - (Inspector::jsInjectedScriptHostPrototypeAttributeEvaluate): - (Inspector::jsInjectedScriptHostPrototypeFunctionInternalConstructorName): - (Inspector::jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection): - (Inspector::jsInjectedScriptHostPrototypeFunctionType): - (Inspector::jsInjectedScriptHostPrototypeFunctionFunctionDetails): - (Inspector::jsInjectedScriptHostPrototypeFunctionGetInternalProperties): - * inspector/JSJavaScriptCallFramePrototype.cpp: - (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluate): - (Inspector::jsJavaScriptCallFramePrototypeFunctionScopeType): - (Inspector::jsJavaScriptCallFrameAttributeCaller): - (Inspector::jsJavaScriptCallFrameAttributeSourceID): - (Inspector::jsJavaScriptCallFrameAttributeLine): - (Inspector::jsJavaScriptCallFrameAttributeColumn): - (Inspector::jsJavaScriptCallFrameAttributeFunctionName): - (Inspector::jsJavaScriptCallFrameAttributeScopeChain): - (Inspector::jsJavaScriptCallFrameAttributeThisObject): - (Inspector::jsJavaScriptCallFrameAttributeType): - * interpreter/CallFrame.h: - (JSC::ExecState::hostThisRegister): Deleted. - (JSC::ExecState::hostThisValue): Deleted. - * runtime/Arguments.cpp: - (JSC::argumentsFuncIterator): - * runtime/ArrayPrototype.cpp: - (JSC::arrayProtoFuncToString): - (JSC::arrayProtoFuncToLocaleString): - (JSC::arrayProtoFuncJoin): - (JSC::arrayProtoFuncConcat): - (JSC::arrayProtoFuncPop): - (JSC::arrayProtoFuncPush): - (JSC::arrayProtoFuncReverse): - (JSC::arrayProtoFuncShift): - (JSC::arrayProtoFuncSlice): - (JSC::arrayProtoFuncSort): - (JSC::arrayProtoFuncSplice): - (JSC::arrayProtoFuncUnShift): - (JSC::arrayProtoFuncReduce): - (JSC::arrayProtoFuncReduceRight): - (JSC::arrayProtoFuncIndexOf): - (JSC::arrayProtoFuncLastIndexOf): - (JSC::arrayProtoFuncValues): - (JSC::arrayProtoFuncEntries): - (JSC::arrayProtoFuncKeys): - * runtime/BooleanPrototype.cpp: - (JSC::booleanProtoFuncToString): - (JSC::booleanProtoFuncValueOf): - * runtime/ConsolePrototype.cpp: - (JSC::consoleLogWithLevel): - (JSC::consoleProtoFuncClear): - (JSC::consoleProtoFuncDir): - (JSC::consoleProtoFuncDirXML): - (JSC::consoleProtoFuncTable): - (JSC::consoleProtoFuncTrace): - (JSC::consoleProtoFuncAssert): - (JSC::consoleProtoFuncCount): - (JSC::consoleProtoFuncProfile): - (JSC::consoleProtoFuncProfileEnd): - (JSC::consoleProtoFuncTime): - (JSC::consoleProtoFuncTimeEnd): - (JSC::consoleProtoFuncTimeStamp): - (JSC::consoleProtoFuncGroup): - (JSC::consoleProtoFuncGroupCollapsed): - (JSC::consoleProtoFuncGroupEnd): - * runtime/DatePrototype.cpp: - (JSC::formateDateInstance): - (JSC::dateProtoFuncToISOString): - (JSC::dateProtoFuncToLocaleString): - (JSC::dateProtoFuncToLocaleDateString): - (JSC::dateProtoFuncToLocaleTimeString): - (JSC::dateProtoFuncGetTime): - (JSC::dateProtoFuncGetFullYear): - (JSC::dateProtoFuncGetUTCFullYear): - (JSC::dateProtoFuncGetMonth): - (JSC::dateProtoFuncGetUTCMonth): - (JSC::dateProtoFuncGetDate): - (JSC::dateProtoFuncGetUTCDate): - (JSC::dateProtoFuncGetDay): - (JSC::dateProtoFuncGetUTCDay): - (JSC::dateProtoFuncGetHours): - (JSC::dateProtoFuncGetUTCHours): - (JSC::dateProtoFuncGetMinutes): - (JSC::dateProtoFuncGetUTCMinutes): - (JSC::dateProtoFuncGetSeconds): - (JSC::dateProtoFuncGetUTCSeconds): - (JSC::dateProtoFuncGetMilliSeconds): - (JSC::dateProtoFuncGetUTCMilliseconds): - (JSC::dateProtoFuncGetTimezoneOffset): - (JSC::dateProtoFuncSetTime): - (JSC::setNewValueFromTimeArgs): - (JSC::setNewValueFromDateArgs): - (JSC::dateProtoFuncSetYear): - (JSC::dateProtoFuncGetYear): - (JSC::dateProtoFuncToJSON): - * runtime/ErrorPrototype.cpp: - (JSC::errorProtoFuncToString): - * runtime/FunctionPrototype.cpp: - (JSC::functionProtoFuncToString): - (JSC::functionProtoFuncBind): - * runtime/NamePrototype.cpp: - (JSC::privateNameProtoFuncToString): - * runtime/NumberPrototype.cpp: - (JSC::numberProtoFuncToExponential): - (JSC::numberProtoFuncToFixed): - (JSC::numberProtoFuncToPrecision): - (JSC::numberProtoFuncClz): - (JSC::numberProtoFuncToString): - (JSC::numberProtoFuncToLocaleString): - (JSC::numberProtoFuncValueOf): - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncValueOf): - (JSC::objectProtoFuncHasOwnProperty): - (JSC::objectProtoFuncIsPrototypeOf): - (JSC::objectProtoFuncDefineGetter): - (JSC::objectProtoFuncDefineSetter): - (JSC::objectProtoFuncLookupGetter): - (JSC::objectProtoFuncLookupSetter): - (JSC::objectProtoFuncPropertyIsEnumerable): - (JSC::objectProtoFuncToLocaleString): - (JSC::objectProtoFuncToString): - * runtime/RegExpPrototype.cpp: - (JSC::regExpProtoFuncTest): - (JSC::regExpProtoFuncExec): - (JSC::regExpProtoFuncCompile): - (JSC::regExpProtoFuncToString): - * runtime/StringPrototype.cpp: - (JSC::stringProtoFuncReplace): - (JSC::stringProtoFuncToString): - (JSC::stringProtoFuncCharAt): - (JSC::stringProtoFuncCharCodeAt): - (JSC::stringProtoFuncConcat): - (JSC::stringProtoFuncIndexOf): - (JSC::stringProtoFuncLastIndexOf): - (JSC::stringProtoFuncMatch): - (JSC::stringProtoFuncSearch): - (JSC::stringProtoFuncSlice): - (JSC::stringProtoFuncSplit): - (JSC::stringProtoFuncSubstr): - (JSC::stringProtoFuncSubstring): - (JSC::stringProtoFuncToLowerCase): - (JSC::stringProtoFuncToUpperCase): - (JSC::stringProtoFuncLocaleCompare): - (JSC::stringProtoFuncBig): - (JSC::stringProtoFuncSmall): - (JSC::stringProtoFuncBlink): - (JSC::stringProtoFuncBold): - (JSC::stringProtoFuncFixed): - (JSC::stringProtoFuncItalics): - (JSC::stringProtoFuncStrike): - (JSC::stringProtoFuncSub): - (JSC::stringProtoFuncSup): - (JSC::stringProtoFuncFontcolor): - (JSC::stringProtoFuncFontsize): - (JSC::stringProtoFuncAnchor): - (JSC::stringProtoFuncLink): - (JSC::stringProtoFuncTrim): - (JSC::stringProtoFuncTrimLeft): - (JSC::stringProtoFuncTrimRight): - -2014-03-28 Filip Pizlo <fpizlo@apple.com> - - Land the stackmap register liveness glue with the uses of the liveness disabled - https://bugs.webkit.org/show_bug.cgi?id=130924 - - Reviewed by Oliver Hunt. - - Add the liveness and fix other bugs I found. - - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeFor): - * ftl/FTLCompile.cpp: - (JSC::FTL::usedRegistersFor): - (JSC::FTL::fixFunctionBasedOnStackMaps): - * ftl/FTLSlowPathCall.cpp: - * ftl/FTLSlowPathCallKey.cpp: - (JSC::FTL::SlowPathCallKey::dump): - * ftl/FTLSlowPathCallKey.h: - (JSC::FTL::SlowPathCallKey::SlowPathCallKey): - (JSC::FTL::SlowPathCallKey::argumentRegisters): - (JSC::FTL::SlowPathCallKey::withCallTarget): - * ftl/FTLStackMaps.cpp: - (JSC::FTL::StackMaps::Record::locationSet): - (JSC::FTL::StackMaps::Record::liveOutsSet): - (JSC::FTL::StackMaps::Record::usedRegisterSet): - * ftl/FTLStackMaps.h: - * ftl/FTLThunks.cpp: - (JSC::FTL::registerClobberCheck): - (JSC::FTL::slowPathCallThunkGenerator): - * jit/RegisterSet.cpp: - (JSC::RegisterSet::stackRegisters): - (JSC::RegisterSet::reservedHardwareRegisters): - (JSC::RegisterSet::runtimeRegisters): - (JSC::RegisterSet::specialRegisters): - (JSC::RegisterSet::dump): - * jit/RegisterSet.h: - (JSC::RegisterSet::RegisterSet): - (JSC::RegisterSet::setAny): - (JSC::RegisterSet::setMany): - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - (JSC::tryCachePutByID): - (JSC::tryRepatchIn): - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): - * runtime/Options.h: - -2014-03-28 Mark Lam <mark.lam@apple.com> - - mandreel throws a checksum error on 32-bit x86. - <https://webkit.org/b/125706> - - Reviewed by Filip Pizlo. - - The 32-bit DFG can emit code that loads double constants from its - CodeBlock's m_constantRegisters vector. The emitted instruction will - embed the address of the constant from the vector's backing store. - Subsequently, while inserting new constants, the DFG may resize the - vector, thereby reallocating the backing store. This renders the - previously embedded constant addresses stale. - - The fix is to use a dedicated doubles constant pool stored in the DFG - CommonData instead. This constant pool won't be reallocated, and - hence will not manifest this issue. - - * dfg/DFGCommonData.h: - * dfg/DFGGraph.h: - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::link): - (JSC::DFG::JITCompiler::addressOfDoubleConstant): - * dfg/DFGJITCompiler.h: - (JSC::DFG::JITCompiler::addressOfDoubleConstant): Deleted. - -2014-03-28 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: console.warn is showing as error instead of warning - https://bugs.webkit.org/show_bug.cgi?id=130921 - - Reviewed by Timothy Hatcher. - - * runtime/ConsolePrototype.cpp: - (JSC::consoleProtoFuncWarn): - console.warn should be MessageLevel Warning, not Error. - -2014-03-28 Oliver Hunt <oliver@apple.com> - - Fix cloop build. - - * bytecode/BytecodeList.json: - -2014-03-28 Michael Saboff <msaboff@apple.com> - - Unreviewed, rolling r166248 back in. - - Turns out r166070 didn't cause a 2% performance loss in page load times - - Reverted changeset: - - Unreviewed, rolling out r166126. - Rollout r166126 in prepartion to roll out prerequisite r166070 - -2014-03-27 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r166376. - https://bugs.webkit.org/show_bug.cgi?id=130887 - - This was a misguided optimization. (Requested by kling on - #webkit). - - Reverted changeset: - - "Avoid fetching JSObject::structure() repeatedly in - putDirectInternal." - https://bugs.webkit.org/show_bug.cgi?id=130857 - http://trac.webkit.org/changeset/166376 - -2014-03-27 Oliver Hunt <oliver@apple.com> - - Support spread operand in |new| expressions - https://bugs.webkit.org/show_bug.cgi?id=130877 - - Reviewed by Michael Saboff. - - Add support for the spread operator being applied in - |new| expressions. This required adding support for - a new opcode, op_construct_varargs. This is a relatively - simple refactoring of the call_varargs implementation. - - * bytecode/BytecodeList.json: - * bytecode/BytecodeUseDef.h: - (JSC::computeUsesForBytecodeOffset): - (JSC::computeDefsForBytecodeOffset): - * bytecode/CallLinkInfo.cpp: - (JSC::CallLinkInfo::unlink): - * bytecode/CallLinkInfo.h: - (JSC::CallLinkInfo::callTypeFor): - (JSC::CallLinkInfo::specializationKind): - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::dumpBytecode): - (JSC::CodeBlock::CodeBlock): - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::emitCallVarargs): - (JSC::BytecodeGenerator::emitConstructVarargs): - (JSC::BytecodeGenerator::emitConstruct): - * bytecompiler/BytecodeGenerator.h: - * jit/JIT.cpp: - (JSC::JIT::privateCompileMainPass): - (JSC::JIT::privateCompileSlowCases): - * jit/JIT.h: - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - (JSC::JIT::compileOpCallSlowCase): - (JSC::JIT::emit_op_construct_varargs): - (JSC::JIT::emitSlow_op_construct_varargs): - * jit/JITCall32_64.cpp: - (JSC::JIT::emitSlow_op_construct_varargs): - (JSC::JIT::emit_op_construct_varargs): - (JSC::JIT::compileOpCall): - (JSC::JIT::compileOpCallSlowCase): - * jit/JITOperations.cpp: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * llint/LLIntSlowPaths.h: - * llint/LowLevelInterpreter.asm: - * parser/Parser.cpp: - (JSC::Parser<LexerType>::parseMemberExpression): - -2014-03-27 Filip Pizlo <fpizlo@apple.com> - - Revert http://trac.webkit.org/changeset/166386 because it broke builds. - - * Configurations/Base.xcconfig: - * Configurations/LLVMForJSC.xcconfig: - -2014-03-27 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, skip this test for now. - - * tests/stress/recurse-infinitely-on-getter.js: - -2014-03-27 Filip Pizlo <fpizlo@apple.com> - - Switch the LLVMForJSC target to using the LLVM in /usr/local rather than /usr/local/LLVMForJavaScriptCore on iOS - https://bugs.webkit.org/show_bug.cgi?id=130867 - <rdar://problem/16432456> - - Reviewed by Mark Hahnenberg. - - * Configurations/Base.xcconfig: - * Configurations/LLVMForJSC.xcconfig: - -2014-03-27 Andreas Kling <akling@apple.com> - - Avoid fetching JSObject::structure() repeatedly in putDirectInternal. - <https://webkit.org/b/130857> - - Use the cached Structure* instead of re-fetching it over and over since - that's a non-trivial operation these days. - - Reviewed by Mark Hahnenberg. - - * runtime/JSObject.h: - (JSC::JSObject::putDirectInternal): - -2014-03-27 Mark Hahnenberg <mhahnenberg@apple.com> - - Check the remembered set bit faster - https://bugs.webkit.org/show_bug.cgi?id=130860 - - Reviewed by Oliver Hunt. - - Currently we look up the remembered set bit in the MarkedBlock in C++ code, but - that bit is also stored in the object. We should look it up there whenever possible. - - * heap/CopiedBlockInlines.h: - (JSC::CopiedBlock::shouldReportLiveBytes): - * heap/Heap.cpp: - (JSC::Heap::addToRememberedSet): - * heap/Heap.h: - * heap/HeapInlines.h: Removed. - * heap/SlotVisitorInlines.h: - (JSC::SlotVisitor::reportExtraMemoryUsage): - -2014-03-27 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Provide SPI to disallow remote inspection of a JSContext - https://bugs.webkit.org/show_bug.cgi?id=130853 - - Reviewed by Timothy Hatcher. - - * API/JSContextPrivate.h: Added. - * API/JSContext.mm: - (-[JSContext _remoteInspectionEnabled]): - (-[JSContext _setRemoteInspectionEnabled:]): - ObjC SPI to enable/disable remote inspection. - - * API/JSContextRefPrivate.h: - * API/JSContextRef.cpp: - (JSGlobalContextGetRemoteInspectionEnabled): - (JSGlobalContextSetRemoteInspectionEnabled): - C SPI to enable/disable remote inspection. - - * JavaScriptCore.xcodeproj/project.pbxproj: - Add new private header, and export as a private header. - -2014-03-27 Mark Hahnenberg <mhahnenberg@apple.com> - - Clean up questionable style in ScriptExecutable::prepareForExecutionImpl - https://bugs.webkit.org/show_bug.cgi?id=130845 - - Reviewed by Filip Pizlo. - - There was a hack added to make sure C Loop LLInt worked which included overriding the - global Options::useLLInt setting, which makes no sense to do here. We should put the - update of the global setting in Options::recomputeDependentOptions along with the other - execution engine flags. - - * runtime/Executable.cpp: - (JSC::ScriptExecutable::prepareForExecutionImpl): - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): - -2014-03-26 Filip Pizlo <fpizlo@apple.com> - - Enable LLVM stackmap liveOuts computation - https://bugs.webkit.org/show_bug.cgi?id=130821 - - Reviewed by Andy Estes and Sam Weinig. - - * ftl/FTLStackMaps.cpp: - (JSC::FTL::StackMaps::Record::dump): - * llvm/library/LLVMExports.cpp: - (initializeAndGetJSCLLVMAPI): - -2014-03-26 Filip Pizlo <fpizlo@apple.com> - - Parse stackmaps liveOuts - https://bugs.webkit.org/show_bug.cgi?id=130801 - - Reviewed by Geoffrey Garen. - - This just adds the code to parse them but doesn't do anything with them, yet. - - * ftl/FTLLocation.cpp: - (JSC::FTL::Location::forStackmaps): - * ftl/FTLLocation.h: - (JSC::FTL::Location::forRegister): - (JSC::FTL::Location::forIndirect): - * ftl/FTLStackMaps.cpp: - (JSC::FTL::StackMaps::Location::parse): - (JSC::FTL::StackMaps::Location::dump): - (JSC::FTL::StackMaps::LiveOut::parse): - (JSC::FTL::StackMaps::LiveOut::dump): - (JSC::FTL::StackMaps::Record::parse): - (JSC::FTL::StackMaps::Record::dump): - * ftl/FTLStackMaps.h: - -2014-03-26 Mark Lam <mark.lam@apple.com> - - Build fix after r166307. - - Not reviewed. - - * runtime/JSCell.h: - - The inline function isAPIValueWrapper() should not be exported. This - was causing a linkage error when building for 32-bit x86 on Mac. - -2014-03-26 Filip Pizlo <fpizlo@apple.com> - - Reasoning about DWARF register numbers should be moved out of FTL::Location - https://bugs.webkit.org/show_bug.cgi?id=130792 - - Reviewed by Oliver Hunt. - - Moving this code makes it possible for things other than FTL::Location to reason about - DWARF register encoding. This refactoring also appears to reduce some code duplication - and makes FTLLocation.cpp cleaner. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * ftl/FTLCompile.cpp: - (JSC::FTL::fixFunctionBasedOnStackMaps): - * ftl/FTLDWARFRegister.cpp: Added. - (JSC::FTL::DWARFRegister::reg): - (JSC::FTL::DWARFRegister::dump): - * ftl/FTLDWARFRegister.h: Added. - (JSC::FTL::DWARFRegister::DWARFRegister): - (JSC::FTL::DWARFRegister::dwarfRegNum): - * ftl/FTLLocation.cpp: - (JSC::FTL::Location::dump): - (JSC::FTL::Location::isGPR): - (JSC::FTL::Location::gpr): - (JSC::FTL::Location::isFPR): - (JSC::FTL::Location::fpr): - * ftl/FTLLocation.h: - (JSC::FTL::Location::hasDwarfReg): - (JSC::FTL::Location::dwarfReg): - -2014-03-26 Brent Fulgham <bfulgham@apple.com> - - Unreviewed build fix. - - * runtime/JSCell.h: VS2013 confused about argument type. - -2014-03-26 Zoltan Horvath <zoltan@webkit.org> - - [CSS Shapes] Remove shape-inside support - https://bugs.webkit.org/show_bug.cgi?id=130698 - - Reviewed by David Hyatt. - - * Configurations/FeatureDefines.xcconfig: - -2014-03-26 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> - - Rename hasFastArrayStorage to be more appropriate - https://bugs.webkit.org/show_bug.cgi?id=130773 - - Reviewed by Filip Pizlo. - - * dfg/DFGArrayMode.cpp: - (JSC::DFG::ArrayMode::alreadyChecked): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGWatchpointCollectionPhase.cpp: - (JSC::DFG::WatchpointCollectionPhase::handle): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNewArray): - (JSC::FTL::LowerDFGToLLVM::compileNewArrayBuffer): - (JSC::FTL::LowerDFGToLLVM::compileNewArrayWithSize): - * runtime/ButterflyInlines.h: - (JSC::Butterfly::unshift): - (JSC::Butterfly::shift): - * runtime/IndexingHeaderInlines.h: - (JSC::IndexingHeader::preCapacity): - * runtime/IndexingType.h: - (JSC::hasArrayStorage): - (JSC::hasAnyArrayStorage): - (JSC::hasFastArrayStorage): Deleted. - * runtime/JSArray.cpp: - (JSC::JSArray::sortVector): - (JSC::JSArray::compactForSorting): - * runtime/JSArray.h: - (JSC::JSArray::create): - (JSC::JSArray::tryCreateUninitialized): - * runtime/JSGlobalObject.cpp: - * runtime/JSObject.cpp: - (JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage): - * runtime/JSObject.h: - (JSC::JSObject::ensureArrayStorage): - (JSC::JSObject::arrayStorage): - * runtime/StructureTransitionTable.h: - (JSC::newIndexingType): - -2014-03-26 Zan Dobersek <zdobersek@igalia.com> - - Unreviewed. Removing the remaining Automake cruft. - - * GNUmakefile.list.am: Removed. - -2014-03-25 Filip Pizlo <fpizlo@apple.com> - - Arguments simplification phase should be fine with marking the arguments local itself as an arguments alias - https://bugs.webkit.org/show_bug.cgi?id=130764 - <rdar://problem/16304788> - - Reviewed by Sam Weinig. - - Being an arguments alias just means that your OSR exit recovery should attempt arguments - creation. This is true of arguments locals. We had special cases that tried to make it not - true of arguments locals. The only consequence of those special cases was to cause crashes - in case of arguments that are also captured variables (i.e. we have SlowArguments). This - change just removes those special cases. - - This change means that the FTL will now see SetLocals with a FlushedArguments format. - Previously you wouldn't see them because previously only non-captured variable would be - arguments aliases, and non-captured variables get completely SSAified - i.e. no SetLocals - left. Adding handling for FlushedArguments is a benign and simple change since its - behavior is identical to FlushedJSValue for that code's purposes. - - * dfg/DFGArgumentsSimplificationPhase.cpp: - (JSC::DFG::ArgumentsSimplificationPhase::run): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileSetLocal): - * tests/stress/captured-arguments-variable.js: Added. - (foo): - (noInline): - -2014-03-25 Mark Hahnenberg <mhahnenberg@apple.com> - - Add HeapInlines - https://bugs.webkit.org/show_bug.cgi?id=130759 - - Reviewed by Filip Pizlo. - - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * heap/Heap.cpp: - (JSC::MarkedBlockSnapshotFunctor::MarkedBlockSnapshotFunctor): - (JSC::MarkedBlockSnapshotFunctor::operator()): - * heap/Heap.h: Also reindented while we're here. - (JSC::Heap::writeBarrierBuffer): - (JSC::Heap::vm): - (JSC::Heap::objectSpace): - (JSC::Heap::machineThreads): - (JSC::Heap::operationInProgress): - (JSC::Heap::allocatorForObjectWithoutDestructor): - (JSC::Heap::allocatorForObjectWithNormalDestructor): - (JSC::Heap::allocatorForObjectWithImmortalStructureDestructor): - (JSC::Heap::storageAllocator): - (JSC::Heap::notifyIsSafeToCollect): - (JSC::Heap::isSafeToCollect): - (JSC::Heap::handleSet): - (JSC::Heap::handleStack): - (JSC::Heap::lastFullGCLength): - (JSC::Heap::lastEdenGCLength): - (JSC::Heap::increaseLastFullGCLength): - (JSC::Heap::sizeBeforeLastEdenCollection): - (JSC::Heap::sizeAfterLastEdenCollection): - (JSC::Heap::sizeBeforeLastFullCollection): - (JSC::Heap::sizeAfterLastFullCollection): - (JSC::Heap::jitStubRoutines): - (JSC::Heap::isDeferred): - (JSC::Heap::structureIDTable): - (JSC::Heap::removeCodeBlock): - * heap/HeapInlines.h: Added. - (JSC::Heap::shouldCollect): - (JSC::Heap::isBusy): - (JSC::Heap::isCollecting): - (JSC::Heap::heap): - (JSC::Heap::isLive): - (JSC::Heap::isInRememberedSet): - (JSC::Heap::isMarked): - (JSC::Heap::testAndSetMarked): - (JSC::Heap::setMarked): - (JSC::Heap::isWriteBarrierEnabled): - (JSC::Heap::writeBarrier): - (JSC::Heap::reportExtraMemoryCost): - (JSC::Heap::forEachProtectedCell): - (JSC::Heap::forEachCodeBlock): - (JSC::Heap::allocateWithNormalDestructor): - (JSC::Heap::allocateWithImmortalStructureDestructor): - (JSC::Heap::allocateWithoutDestructor): - (JSC::Heap::tryAllocateStorage): - (JSC::Heap::tryReallocateStorage): - (JSC::Heap::ascribeOwner): - (JSC::Heap::blockAllocator): - (JSC::Heap::releaseSoon): - (JSC::Heap::incrementDeferralDepth): - (JSC::Heap::decrementDeferralDepth): - (JSC::Heap::collectIfNecessaryOrDefer): - (JSC::Heap::decrementDeferralDepthAndGCIfNeeded): - (JSC::Heap::markListSet): - * runtime/JSCInlines.h: - -2014-03-25 Filip Pizlo <fpizlo@apple.com> - - DFG::ByteCodeParser::SetMode should distinguish between setting immediately without a flush and setting immediately with a flush - https://bugs.webkit.org/show_bug.cgi?id=130760 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::setLocal): - (JSC::DFG::ByteCodeParser::setArgument): - (JSC::DFG::ByteCodeParser::handleInlining): - (JSC::DFG::ByteCodeParser::parseBlock): - * tests/stress/assign-argument-in-inlined-call.js: Added. - (f1): - (getF2Arguments): - (f2): - (f3): - * tests/stress/assign-captured-argument-in-inlined-call.js: Added. - (f1): - (f2): - (f3): - -2014-03-25 Filip Pizlo <fpizlo@apple.com> - - Fix 32-bit getter call alignment. - - Reviewed by Mark Hahnenberg. - - * jit/Repatch.cpp: - (JSC::generateGetByIdStub): - -2014-03-25 Filip Pizlo <fpizlo@apple.com> - - Repatch should plant calls to getters directly rather than through a C helper - https://bugs.webkit.org/show_bug.cgi?id=129589 - - Reviewed by Mark Hahnenberg. - - As the title says. All of the superstructure for this was already in place, so now it - was just a matter of actually emitting the call. - - 8x speed-up for getter microbenchmarks. - - * CMakeLists.txt: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/PolymorphicGetByIdList.h: - (JSC::GetByIdAccess::doesCalls): - * jit/AccessorCallJITStubRoutine.cpp: Added. - (JSC::AccessorCallJITStubRoutine::AccessorCallJITStubRoutine): - (JSC::AccessorCallJITStubRoutine::~AccessorCallJITStubRoutine): - (JSC::AccessorCallJITStubRoutine::visitWeak): - * jit/AccessorCallJITStubRoutine.h: Added. - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::storeCell): - * jit/GCAwareJITStubRoutine.h: - * jit/Repatch.cpp: - (JSC::generateGetByIdStub): - * runtime/GetterSetter.h: - (JSC::GetterSetter::offsetOfGetter): - (JSC::GetterSetter::offsetOfSetter): - -2014-03-25 Michael Saboff <msaboff@apple.com> - - Unreviewed, rolling out r166126. - - Rollout r166126 in prepartion to roll out prerequisite r166070 - - Reverted changeset: - - "toThis() on a JSWorkerGlobalScope should return a JSProxy and - not undefined" - https://bugs.webkit.org/show_bug.cgi?id=130554 - http://trac.webkit.org/changeset/166126 - -2014-03-25 Oliver Hunt <oliver@apple.com> - - AST incorrectly conflates readable and writable locations - https://bugs.webkit.org/show_bug.cgi?id=130734 - - Reviewed by Filip Pizlo. - - We need to distinguish between "locations" that are valid for reading - and writing, vs those that may only be written. - - * bytecompiler/NodesCodegen.cpp: - (JSC::ForInNode::emitBytecode): - (JSC::ForOfNode::emitBytecode): - * parser/Nodes.h: - (JSC::ExpressionNode::isAssignmentLocation): - -2014-03-24 Oliver Hunt <oliver@apple.com> - - ASSERTION FAILED in Parser: dst != localReg - https://bugs.webkit.org/show_bug.cgi?id=130710 - - Reviewed by Filip Pizlo. - - Just make sure we don't try to write to a captured constant, - following the change to track captured variables separately. - - * bytecompiler/NodesCodegen.cpp: - (JSC::PostfixNode::emitResolve): - (JSC::PrefixNode::emitResolve): - -2014-03-25 Martin Robinson <mrobinson@igalia.com> - - [GTK] Remove the autotools build - https://bugs.webkit.org/show_bug.cgi?id=130717 - - Reviewed by Anders Carlsson. - - * GNUmakefile.am: Removed. - * config.h: Remove references to the autotools configure file. - -2014-03-24 Filip Pizlo <fpizlo@apple.com> - - More scaffolding for a stub routine to have a stub recursively embedded inside it - https://bugs.webkit.org/show_bug.cgi?id=130770 - - Reviewed by Oliver Hunt. - - * bytecode/CallLinkInfo.cpp: - (JSC::CallLinkInfo::unlink): VM& argument is superfluous. - (JSC::CallLinkInfo::visitWeak): Factor this out, it used to be in CodeBlock::finalizeUnconditionally(). - * bytecode/CallLinkInfo.h: - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::finalizeUnconditionally): Factor out some functionality into CallLinkInfo::visitWeak(), and make sure we pass RepatchBuffer& in more places. - (JSC::CodeBlock::unlinkCalls): - (JSC::CodeBlock::unlinkIncomingCalls): - * bytecode/PolymorphicGetByIdList.cpp: Pass RepatchBuffer& through and call JITStubRoutine::visitWeak(). - (JSC::GetByIdAccess::visitWeak): - (JSC::PolymorphicGetByIdList::visitWeak): - * bytecode/PolymorphicGetByIdList.h: - * bytecode/PolymorphicPutByIdList.cpp: Pass RepatchBuffer& through and call JITStubRoutine::visitWeak(). - (JSC::PutByIdAccess::visitWeak): - (JSC::PolymorphicPutByIdList::visitWeak): - * bytecode/PolymorphicPutByIdList.h: - * bytecode/StructureStubInfo.cpp: Pass RepatchBuffer& through. - (JSC::StructureStubInfo::visitWeakReferences): - * bytecode/StructureStubInfo.h: - * jit/ClosureCallStubRoutine.cpp: isClosureCall is unused. - (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine): - * jit/GCAwareJITStubRoutine.cpp: - (JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine): - (JSC::createJITStubRoutine): - * jit/GCAwareJITStubRoutine.h: Make it easier to construct one of these. - (JSC::GCAwareJITStubRoutine::isClosureCall): Deleted. - * jit/JITStubRoutine.cpp: - (JSC::JITStubRoutine::visitWeak): This will allow future JITStubRoutine subclasses to have stubs recursively embedded inside them. - * jit/JITStubRoutine.h: - * jit/Repatch.cpp: - (JSC::generateGetByIdStub): Fix a possible GC bug where we weren't making the stub routine GC aware. - (JSC::emitCustomSetterStub): Clean up some code. - -2014-03-24 Geoffrey Garen <ggaren@apple.com> - - Safari crashes in JavaScriptCore: JSC::JSObject::growOutOfLineStorage - when WebKit is compiled with fcatch-undefined-behavior - https://bugs.webkit.org/show_bug.cgi?id=130652 - - Reviewed by Mark Hahnenberg. - - Use a static member function because the butterfly we pass in might be - NULL, and passing NULL to a member function is undefined behavior. - - Stylistically, I think this new way reads a little more clearly, since it - matches createOrGrowArrayRight, and it helps to convey that m_butterfly - might not exist yet. - - * runtime/Butterfly.h: - * runtime/ButterflyInlines.h: - (JSC::Butterfly::createOrGrowPropertyStorage): Renamed from growPropertyStorage - because we might create. Split out the create path to avoid using NULL - in a member function expression. - - Removed some unused versions of this function. - - * runtime/JSObject.cpp: - (JSC::JSObject::growOutOfLineStorage): Updated for interface change. - -2014-03-24 Oliver Hunt <oliver@apple.com> - - Strict mode destructuring assignment crashes the parser. - https://bugs.webkit.org/show_bug.cgi?id=130538 - - Reviewed by Michael Saboff. - - The SyntaxChecker mode always return 1 for success, except - for a small subset of functions where we needed exact information. - This ends up just being a poor design decision as it means - the parser can get confused between a function return 1, and - the Resolve constant which was also 1. So we now use a unique - type for every creation method. - - * parser/SyntaxChecker.h: - (JSC::SyntaxChecker::createSourceElements): - (JSC::SyntaxChecker::createFunctionBody): - (JSC::SyntaxChecker::createArguments): - (JSC::SyntaxChecker::createSpreadExpression): - (JSC::SyntaxChecker::createArgumentsList): - (JSC::SyntaxChecker::createPropertyList): - (JSC::SyntaxChecker::createElementList): - (JSC::SyntaxChecker::createFormalParameterList): - (JSC::SyntaxChecker::createClause): - (JSC::SyntaxChecker::createClauseList): - (JSC::SyntaxChecker::createFuncDeclStatement): - (JSC::SyntaxChecker::createBlockStatement): - (JSC::SyntaxChecker::createExprStatement): - (JSC::SyntaxChecker::createIfStatement): - (JSC::SyntaxChecker::createForLoop): - (JSC::SyntaxChecker::createForInLoop): - (JSC::SyntaxChecker::createForOfLoop): - (JSC::SyntaxChecker::createEmptyStatement): - (JSC::SyntaxChecker::createVarStatement): - (JSC::SyntaxChecker::createReturnStatement): - (JSC::SyntaxChecker::createBreakStatement): - (JSC::SyntaxChecker::createContinueStatement): - (JSC::SyntaxChecker::createTryStatement): - (JSC::SyntaxChecker::createSwitchStatement): - (JSC::SyntaxChecker::createWhileStatement): - (JSC::SyntaxChecker::createWithStatement): - (JSC::SyntaxChecker::createDoWhileStatement): - (JSC::SyntaxChecker::createLabelStatement): - (JSC::SyntaxChecker::createThrowStatement): - (JSC::SyntaxChecker::createDebugger): - (JSC::SyntaxChecker::createConstStatement): - (JSC::SyntaxChecker::appendConstDecl): - (JSC::SyntaxChecker::combineCommaNodes): - (JSC::SyntaxChecker::operatorStackPop): - -2014-03-24 Brent Fulgham <bfulgham@apple.com> - - Activate WebVTT Tests Once Merging is Complete - https://bugs.webkit.org/show_bug.cgi?id=130420 - - Reviewed by Eric Carlson. - - * Configurations/FeatureDefines.xcconfig: Turn on ENABLE(WEBVTT_REGIONS) - -2014-03-24 Andreas Kling <akling@apple.com> - - Stop pulling in all the macro assemblers from VM.h - <https://webkit.org/b/130691> - - Remove #include of "GPRInfo.h". This breaks WebCore's dependency - on macro assemblers headers and removes 8 includes from every - .cpp file in the JS bindings. - - Reviewed by Geoff Garen. - - * runtime/VM.h: - -2014-03-24 Gavin Barraclough <barraclough@apple.com> - - Add support for thread QoS - https://bugs.webkit.org/show_bug.cgi?id=130688 - - Reviewed by Andreas Kling. - - * heap/BlockAllocator.cpp: - (JSC::BlockAllocator::blockFreeingThreadStartFunc): - - block freeing is a utility activity. - -2014-03-24 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix CLOOP build. - - * bytecode/CallLinkStatus.cpp: - (JSC::CallLinkStatus::computeFor): - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::printCallOp): - (JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): - (JSC::CodeBlock::resetStubDuringGCInternal): Deleted. - * bytecode/CodeBlock.h: - (JSC::CodeBlock::callLinkInfosEnd): Deleted. - -2014-03-24 Gabor Rapcsanyi <rgabor@webkit.org> - - [ARM64] GNU assembler doesn't work with LLInt arm64 backend. - https://bugs.webkit.org/show_bug.cgi?id=130453 - - Reviewed by Filip Pizlo. - - Change fp and lr to x29 and x30. Add both operand kinds to emitARM64() - at sxtw and uxtw instructions. - - * offlineasm/arm64.rb: - -2014-03-23 Hyowon Kim <hw1008.kim@samsung.com> - - Move all EFL typedefs into EflTypedefs.h. - https://bugs.webkit.org/show_bug.cgi?id=130511 - - Reviewed by Gyuyoung Kim - - * heap/HeapTimer.h: Remove EFL typedefs. - -2014-03-23 Filip Pizlo <fpizlo@apple.com> - - Gotta grow the locals vectors if we are about to do SetLocals beyond the bytecode's numCalleeRegisters - https://bugs.webkit.org/show_bug.cgi?id=130650 - <rdar://problem/16122966> - - Reviewed by Michael Saboff. - - Previously, it was only in the case of inlining that we would do SetLocal's beyond the - previously established numLocals limit. But then we added generalized op_call_varargs - handling, which results in us emitting SetLocals that didn't previously exist in the - bytecode. - - This factors out the inliner's ensureLocals loop and calls it from op_call_varargs. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::ensureLocals): - (JSC::DFG::ByteCodeParser::handleInlining): - (JSC::DFG::ByteCodeParser::parseBlock): - (JSC::DFG::ByteCodeParser::parse): - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileStub): Make this do alignment correctly. - * runtime/Options.h: - * tests/stress/call-varargs-from-inlined-code.js: Added. - * tests/stress/call-varargs-from-inlined-code-with-odd-number-of-arguments.js: Added. - -2014-03-22 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, adjust sizes for ARM64. - - * ftl/FTLInlineCacheSize.cpp: - (JSC::FTL::sizeOfCall): - -2014-03-22 Filip Pizlo <fpizlo@apple.com> - - Protect the silent spiller/filler's desire to fill Int32Constants by making sure that we don't mark something as having a Int32 register format if it's a non-Int32 constant - https://bugs.webkit.org/show_bug.cgi?id=130649 - <rdar://problem/16399949> - - Reviewed by Andreas Kling. - - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): - * tests/stress/fuzz-bug-16399949.js: Added. - (tryItOut.f): - (tryItOut): - -2014-03-22 Filip Pizlo <fpizlo@apple.com> - - Call linking slow paths should be passed a CallLinkInfo* directly so that you can create a call IC without adding it to any CodeBlocks - https://bugs.webkit.org/show_bug.cgi?id=130644 - - Reviewed by Andreas Kling. - - This is conceptually a really simple change but it involves the following: - - - The inline part of the call IC stuffs a pointer to the CallLinkInfo into regT2. - - - CodeBlock uses a Bag of CallLinkInfos instead of a Vector. - - - Remove the significance of a CallLinkInfo's index. This means that DFG::JITCode no - longer has a vector of slow path counts that shadows the CallLinkInfo vector. - - - Make CallLinkInfo have its own slowPathCount, which counts actual slow path executions - and not all relinking. - - This makes planting JS->JS calls inside other inline caches or stubs a lot easier, since - the CallLinkInfo and the call IC slow paths no longer rely on the call being associated - with a op_call/op_construct instruction and a machine code return PC within such an - instruction. - - * bytecode/CallLinkInfo.h: - (JSC::getCallLinkInfoCodeOrigin): - * bytecode/CallLinkStatus.cpp: - (JSC::CallLinkStatus::computeFor): - (JSC::CallLinkStatus::computeDFGStatuses): - * bytecode/CallLinkStatus.h: - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::printCallOp): - (JSC::CodeBlock::dumpBytecode): - (JSC::CodeBlock::finalizeUnconditionally): - (JSC::CodeBlock::getCallLinkInfoMap): - (JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): - (JSC::CodeBlock::addCallLinkInfo): - (JSC::CodeBlock::unlinkCalls): - * bytecode/CodeBlock.h: - (JSC::CodeBlock::stubInfoBegin): - (JSC::CodeBlock::stubInfoEnd): - (JSC::CodeBlock::callLinkInfosBegin): - (JSC::CodeBlock::callLinkInfosEnd): - (JSC::CodeBlock::byValInfo): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleCall): - (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): - * dfg/DFGJITCode.h: - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::link): - * dfg/DFGJITCompiler.h: - (JSC::DFG::JITCompiler::addJSCall): - (JSC::DFG::JITCompiler::JSCallRecord::JSCallRecord): - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::reifyInlinedCallFrames): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::emitCall): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::emitCall): - * ftl/FTLCompile.cpp: - (JSC::FTL::fixFunctionBasedOnStackMaps): - * ftl/FTLInlineCacheSize.cpp: - (JSC::FTL::sizeOfCall): - * ftl/FTLJSCall.cpp: - (JSC::FTL::JSCall::JSCall): - (JSC::FTL::JSCall::emit): - (JSC::FTL::JSCall::link): - * ftl/FTLJSCall.h: - * jit/JIT.cpp: - (JSC::JIT::privateCompileMainPass): - (JSC::JIT::privateCompileSlowCases): - (JSC::JIT::privateCompile): - * jit/JIT.h: - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - (JSC::JIT::compileOpCallSlowCase): - * jit/JITCall32_64.cpp: - (JSC::JIT::compileOpCall): - (JSC::JIT::compileOpCallSlowCase): - * jit/JITOperations.cpp: - * jit/JITOperations.h: - (JSC::operationLinkFor): - (JSC::operationVirtualFor): - (JSC::operationLinkClosureCallFor): - * jit/Repatch.cpp: - (JSC::linkClosureCall): - * jit/ThunkGenerators.cpp: - (JSC::slowPathFor): - (JSC::virtualForThunkGenerator): - * tests/stress/eval-that-is-not-eval.js: Added. - -2014-03-22 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix mispelled test name. - - * tests/stress/constand-folding-osr-exit.js: Removed. - * tests/stress/constant-folding-osr-exit.js: Copied from Source/JavaScriptCore/tests/stress/constand-folding-osr-exit.js. - -2014-03-22 Andreas Kling <akling@apple.com> - - CREATE_DOM_WRAPPER doesn't need the ExecState. - <https://webkit.org/b/130648> - - Add a fast path from JSGlobalObject to the VM so we don't have - to dance via the Heap. - - Reviewed by Darin Adler. - - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::JSGlobalObject): - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::vm): - -2014-03-22 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix FTL build. - - * ftl/FTLJITFinalizer.cpp: - -2014-03-22 Michael Saboff <msaboff@apple.com> - - toThis() on a JSWorkerGlobalScope should return a JSProxy and not undefined - https://bugs.webkit.org/show_bug.cgi?id=130554 - - Reviewed by Geoffrey Garen. - - Fixed toThis() on WorkerGlobalScope to return a JSProxy instead of the JSGlobalObject. - Did some cleanup as well. Moved the setting of the thisObject in a JSGlobalObject to - happen in finishCreation() so that it will also happen for other derived classes including - JSWorkerGlobalScopeBase. - - * API/JSContextRef.cpp: - (JSGlobalContextCreateInGroup): - * jsc.cpp: - (GlobalObject::create): - * API/tests/testapi.c: - (globalObject_initialize): Eliminated ASSERT that the global object we are creating matches - the result from JSContextGetGlobalObject() as that will return the proxy. - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::init): Removed thisValue parameter and the call to setGlobalThis() since - we now call setGlobalThis in finishCreation(). - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::finishCreation): - (JSC::JSGlobalObject::setGlobalThis): Made this a private method. - -2014-03-22 Andreas Kling <akling@apple.com> - - Fix debug build. - - * bytecode/CodeBlock.cpp: - * runtime/Executable.cpp: - -2014-03-22 Andreas Kling <akling@apple.com> - - Cut down on JSC profiler includes in WebCore & co. - <https://webkit.org/b/130637> - - Most of WebKit was pulling in JSC's profiler headers via VM.h. - - Reviewed by Darin Adler. - - * dfg/DFGDisassembler.cpp: - * dfg/DFGDisassembler.h: - * dfg/DFGJITFinalizer.cpp: - * jsc.cpp: - * runtime/VM.cpp: - * runtime/VM.h: - -2014-03-22 Landry Breuil <landry@openbsd.org> - - Use pthread_stackseg_np() to find the stack bounds on OpenBSD. - https://bugs.webkit.org/show_bug.cgi?id=129965 - - Reviewed By Anders Carlsson. - -2014-03-21 Mark Lam <mark.lam@apple.com> - - Crash when BytecodeGenerator::emitJump calls Label::bind on null pointer. - <https://webkit.org/b/124508> - - Reviewed by Oliver Hunt. - - The issue is that BreakNode::emitBytecode() is holding onto a LabelScope - pointer from the BytecodeGenerator's m_localScopes vector, and then it - calls emitPopScopes(). emitPopScopes() may do finally clause handling - which will require the m_localScopes to be cloned so that it can change - the local scopes for the finally block, and then restore it after - handling the finally clause. These modifications of the m_localScopes - vector will result in the LabelScope pointer in BreakNode::emitBytecode() - becoming stale, thereby causing the crash. - - The same issue applies to the ContinueNode as well. - - The fix is to use the existing LabelScopePtr abstraction instead of raw - LabelScope pointers. The LabelScopePtr is resilient to the underlying - vector re-allocating its backing store. - - I also changed the LabelScopePtr constructor that takes a LabelScopeStore - to expect a reference to the owner store instead of a pointer because the - owner store should never be a null pointer. - - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::newLabelScope): - (JSC::BytecodeGenerator::breakTarget): - (JSC::BytecodeGenerator::continueTarget): - * bytecompiler/BytecodeGenerator.h: - * bytecompiler/LabelScope.h: - (JSC::LabelScopePtr::LabelScopePtr): - (JSC::LabelScopePtr::operator bool): - (JSC::LabelScopePtr::null): - * bytecompiler/NodesCodegen.cpp: - (JSC::ContinueNode::trivialTarget): - (JSC::ContinueNode::emitBytecode): - (JSC::BreakNode::trivialTarget): - (JSC::BreakNode::emitBytecode): - -2014-03-21 Mark Hahnenberg <mhahnenberg@apple.com> - - 6% SunSpider commandline regression due to r165940 - https://bugs.webkit.org/show_bug.cgi?id=130617 - - Reviewed by Michael Saboff. - - In GCActivityCallback::didAllocate, lastGCLength() returns 0 if we've never collected - before. Some of the benchmarks are never running a single EdenCollection, which causes - them to repeatedly call scheduleTimer with a newDelay of 0. This defeats our timer - slop heuristic, causing us to invoke CFRunLoopTimerSetNextFireDate a couple orders of - magnitude more than we normally would. - - The fix is to seed the last GC lengths in Heap with a non-zero length so that our heuristic works. - - * heap/Heap.cpp: - (JSC::Heap::Heap): - -2014-03-21 Filip Pizlo <fpizlo@apple.com> - - Constants folded by DFG::ByteCodeParser should not be dead. - https://bugs.webkit.org/show_bug.cgi?id=130576 - - Reviewed by Mark Hahnenberg. - - This fixes bugs in the ByteCodeParser's constant folder by removing that constant folder. This - reduces the number of folders in JSC from fourish to just threeish (parser, DFG AI, and one - or more folders in LLVM). Doing so has no performance impact since the other constant folders - already subsume this one. - - Also added a test case for the specific bug that instigated this. - - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::getJSConstantForValue): - (JSC::DFG::ByteCodeParser::getJSConstant): - (JSC::DFG::ByteCodeParser::inferredConstant): - (JSC::DFG::ByteCodeParser::handleIntrinsic): - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGNode.h: - * dfg/DFGNodeFlags.h: - * tests/stress/constand-folding-osr-exit.js: Added. - (foo): - (test): - (.var): - -2014-03-21 Mark Lam <mark.lam@apple.com> - - StackLayoutPhase should find the union'ed calleeVariable before accessing its machineLocal. - <https://webkit.org/b/130566> - - Reviewed by Filip Pizlo. - - * dfg/DFGStackLayoutPhase.cpp: - (JSC::DFG::StackLayoutPhase::run): - -2014-03-20 Filip Pizlo <fpizlo@apple.com> - - FTL should correctly compile GetByVal on Uint32Array that claims to return non-int32 values - https://bugs.webkit.org/show_bug.cgi?id=130562 - <rdar://problem/16382842> - - Reviewed by Geoffrey Garen. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileGetByVal): - * tests/stress/uint32array-unsigned-load.js: Added. - (foo): - -2014-03-20 Brian Burg <bburg@apple.com> - - Web Inspector: add frontend controller and models for replay sessions - https://bugs.webkit.org/show_bug.cgi?id=130145 - - Reviewed by Joseph Pecoraro. - - * inspector/scripts/CodeGeneratorInspector.py: Add the conditional Replay domain. - -2014-03-20 Filip Pizlo <fpizlo@apple.com> - - FTL ValueToInt32 mishandles the constant case, and by the way, there is a constant case that the FTL sees - https://bugs.webkit.org/show_bug.cgi?id=130546 - <rdar://problem/16383308> - - Reviewed by Mark Hahnenberg. - - Make AI do a better job of folding this. - - Also made the FTL backend be more tolerant of data representations. In this case it - didn't know that "constant" was a valid representation. There is a finite set of - possible representations, but broadly, we don't write code that presumes anything - about the representation of an input; that's what methods like lowJSValue() are for. - ValueToInt32 was previously not relying on those methods at all because it had some - hacks. Now, those hacks are just a fast-path optimization but ultimately we fall down - to lowJSValue(). - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): - (JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32): - * tests/stress/value-to-int32-undefined-constant.js: Added. - (foo): - * tests/stress/value-to-int32-undefined.js: Added. - (foo): - -2014-03-20 Mark Hahnenberg <mhahnenberg@apple.com> - - Add some assertions back - https://bugs.webkit.org/show_bug.cgi?id=130531 - - Reviewed by Geoffrey Garen. - - We removed a useful set of assertions for verifying that MarkedBlocks were - in the state that we expected them to be in after clearing marks in the Heap. - We should add these back to catch bugs earlier. - - * heap/MarkedBlock.h: - * heap/MarkedSpace.cpp: - (JSC::VerifyMarkedOrRetired::operator()): - (JSC::MarkedSpace::clearMarks): - -2014-03-20 Filip Pizlo <fpizlo@apple.com> - - Implement stackmap header version check and support new stackmap formats - https://bugs.webkit.org/show_bug.cgi?id=130535 - <rdar://problem/16164284> - - Reviewed by Geoffrey Garen. - - Add the notion of versioning so that LLVMers can happily implement new stackmap formats - without worrying about WebKit getting version-locked to LLVM. In the future, we will have - to implement parsing for a new LLVM stackmap format before it lands in LLVM, or we'll have - to have a "max usable LLVM revision" limit. But, thanks to versioning, we'll always be - happy to move backward in time to older versions of LLVM. - - * ftl/FTLStackMaps.cpp: - (JSC::FTL::readObject): - (JSC::FTL::StackMaps::Constant::parse): - (JSC::FTL::StackMaps::StackSize::parse): - (JSC::FTL::StackMaps::Location::parse): - (JSC::FTL::StackMaps::Record::parse): - (JSC::FTL::StackMaps::parse): - (JSC::FTL::StackMaps::dump): - (JSC::FTL::StackMaps::dumpMultiline): - * ftl/FTLStackMaps.h: - -2014-03-20 Filip Pizlo <fpizlo@apple.com> - - Crash beneath operationTearOffActivation running this JS compression demo - https://bugs.webkit.org/show_bug.cgi?id=130295 - <rdar://problem/16332337> - - Reviewed by Oliver Hunt. - - Make sure that we flush things as if we were at a terminal, if we are at a block with - no forward edges. This fixes infinitely loopy code with captured variables. - - Make sure that the CFG simplifier adds explicit flushes whenever it jettisons a block. - - Make it so that NodeIsFlushed is a thing. Previously only SSA used it and it computed - it by itself. Now it's an artifact of CPS rethreading. - - Add a bunch of tests. All of them previously either crashed or returned bad output due - to memory corruption. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::isCaptured): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::flushForTerminal): - (JSC::DFG::ByteCodeParser::flushForReturn): - (JSC::DFG::ByteCodeParser::flushIfTerminal): - (JSC::DFG::ByteCodeParser::branchData): - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGCFGSimplificationPhase.cpp: - (JSC::DFG::CFGSimplificationPhase::keepOperandAlive): - * dfg/DFGCPSRethreadingPhase.cpp: - (JSC::DFG::CPSRethreadingPhase::run): - (JSC::DFG::CPSRethreadingPhase::computeIsFlushed): - (JSC::DFG::CPSRethreadingPhase::addFlushedLocalOp): - (JSC::DFG::CPSRethreadingPhase::addFlushedLocalEdge): - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::performNodeCSE): - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::clearFlagsOnAllNodes): - * dfg/DFGGraph.h: - * dfg/DFGNode.h: - * dfg/DFGNodeFlags.cpp: - (JSC::DFG::dumpNodeFlags): - * dfg/DFGNodeFlags.h: - * dfg/DFGSSAConversionPhase.cpp: - (JSC::DFG::SSAConversionPhase::run): - * tests/stress/activation-test-loop.js: Added. - (Inner.this.doStuff): - (Inner): - (foo.inner.isDone): - (foo): - * tests/stress/inferred-infinite-loop-that-uses-captured-variables.js: Added. - (bar): - (foo): - (noInline): - * tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js: Added. - (bar): - (foo): - (noInline): - * tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js: Added. - (bar): - (foo): - (noInline): - * tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js: Added. - (bar): - (foo): - (noInline): - * tests/stress/infinite-loop-that-uses-captured-variables.js: Added. - (bar): - (foo): - (noInline): - * tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added. - (bar): - (fuzz): - (foo.f): - (foo): - * tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added. - (bar): - (foo.f): - (foo): - * tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added. - (bar): - (foo.f): - (foo): - * tests/stress/tricky-infinite-loop-that-uses-captured-variables.js: Added. - (bar): - (foo): - (noInline): - -2014-03-20 Oliver Hunt <oliver@apple.com> - - Incorrect behavior when mutating a typed array during set. - https://bugs.webkit.org/show_bug.cgi?id=130428 - - Reviewed by Geoffrey Garen. - - This fixes a null derefence that occurs if a typed array - is mutated during the set() operation. The patch gets rid - of the "Quickly" version of setIndex that is assigning - JSValues of unknown type, as the numeric conversion can trigger - side effects that lead to neutering, and so we deref null. - - * runtime/JSGenericTypedArrayView.h: - (JSC::JSGenericTypedArrayView::setIndex): - * runtime/JSGenericTypedArrayViewInlines.h: - (JSC::JSGenericTypedArrayView<Adaptor>::set): - (JSC::JSGenericTypedArrayView<Adaptor>::putByIndex): - -2014-03-20 Gavin Barraclough <barraclough@apple.com> - - Remove IdentifierTable typedef, isIdentifier() - https://bugs.webkit.org/show_bug.cgi?id=130533 - - Rubber stamped by Geoff Garen. - - Code should use AtomicStringTable, isAtomic() directly. - - * API/JSClassRef.cpp: - (OpaqueJSClass::~OpaqueJSClass): - (OpaqueJSClassContextData::OpaqueJSClassContextData): - (OpaqueJSClass::className): - * API/JSClassRef.h: - * bytecode/SpeculatedType.cpp: - (JSC::speculationFromCell): - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::BytecodeGenerator): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileIn): - (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::speculateStringIdent): - * heap/Heap.cpp: - (JSC::Heap::collect): - * interpreter/CallFrame.h: - (JSC::ExecState::atomicStringTable): - * parser/ASTBuilder.h: - (JSC::ASTBuilder::addVar): - * parser/Parser.cpp: - (JSC::Parser<LexerType>::createBindingPattern): - * runtime/Completion.cpp: - (JSC::checkSyntax): - (JSC::evaluate): - * runtime/Identifier.cpp: - (JSC::Identifier::checkCurrentAtomicStringTable): - * runtime/Identifier.h: - (JSC::Identifier::Identifier): - * runtime/IdentifierInlines.h: - (JSC::Identifier::add): - * runtime/JSCJSValue.cpp: - (JSC::JSValue::dumpInContext): - * runtime/JSLock.cpp: - (JSC::JSLock::didAcquireLock): - (JSC::JSLock::willReleaseLock): - (JSC::JSLock::DropAllLocks::DropAllLocks): - (JSC::JSLock::DropAllLocks::~DropAllLocks): - * runtime/JSLock.h: - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::find): - (JSC::PropertyTable::get): - (JSC::PropertyTable::findWithString): - * runtime/PropertyName.h: - (JSC::PropertyName::PropertyName): - * runtime/PropertyNameArray.cpp: - (JSC::PropertyNameArray::add): - * runtime/VM.cpp: - (JSC::VM::VM): - (JSC::VM::~VM): - * runtime/VM.h: - (JSC::VM::atomicStringTable): - -2014-03-20 Gavin Barraclough <barraclough@apple.com> - - Merge AtomicString, Identifier - https://bugs.webkit.org/show_bug.cgi?id=128624 - - Reviewed by Geoff Garen. - - WTF::StringImpl currently supports two uniquing mechanism - AtomicString and - Identifer - that is one too many. - - Remove Identifier in favour of AtomicString. Identifier had two interesting - mechanisms that we preserve. - - (1) JSC API VMs each get their own string table, switch the string table on - API entry/exit. - (2) JSC caches a pointer to the string table on the VM to avoid a thread - specific access. Adds a new AtomicString::add method to support this. - - * API/JSAPIWrapperObject.mm: - - updated includes. - * JavaScriptCore.xcodeproj/project.pbxproj: - - added IdentifierInlines.h. - * inspector/JSInjectedScriptHostPrototype.cpp: - * inspector/JSJavaScriptCallFramePrototype.cpp: - - updated includes. - * interpreter/CallFrame.h: - (JSC::ExecState::atomicStringTable): - - added, used via AtomicString::add to avoid thread-specific access. - * runtime/ConsolePrototype.cpp: - - updated includes. - * runtime/Identifier.cpp: - (JSC::Identifier::add): - (JSC::Identifier::add8): - - vm->smallStrings.singleCharacterStringRep now returns Atomic strings, use AtomicString::add. - * runtime/Identifier.h: - (JSC::Identifier::Identifier): - - added ASSERTS. - (JSC::Identifier::add): - - vm->smallStrings.singleCharacterStringRep now returns Atomic strings, use AtomicString::add. - * runtime/IdentifierInlines.h: Added. - (JSC::Identifier::add): - - moved from Identifier.h, use AtomicString::add. - * runtime/JSCInlines.h: - - added IdentifierInlines.h. - * runtime/JSLock.h: - - removed IdentifierTable. - * runtime/PropertyNameArray.cpp: - - updated includes. - * runtime/SmallStrings.cpp: - (JSC::SmallStringsStorage::SmallStringsStorage): - - ensure all single character strings are Atomic. - * runtime/VM.cpp: - (JSC::VM::VM): - - instantiate CommonIdentifiers with the correct AtomicStringTable set on thread data. - * runtime/VM.h: - (JSC::VM::atomicStringTable): - - added, used via AtomicString::add to avoid thread-specific access. - -2014-03-20 Gabor Rapcsanyi <rgabor@webkit.org> - - [ARM64] Fix assembler build issues and add cacheFlush support for Linux - https://bugs.webkit.org/show_bug.cgi?id=130502 - - Reviewed by Michael Saboff. - - Add limits.h for INT_MIN in ARM64Assembler(). Delete shouldBlindForSpecificArch(uintptr_t) - because on ARM64 uint64_t and uintptr_t is the same with GCC and Clang as well. - Add cacheFlush support for Linux. - - * assembler/ARM64Assembler.h: - (JSC::ARM64Assembler::linuxPageFlush): - (JSC::ARM64Assembler::cacheFlush): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::shouldBlindForSpecificArch): - -2014-03-19 Gavin Barraclough <barraclough@apple.com> - - https://bugs.webkit.org/show_bug.cgi?id=130494 - EmptyUnique strings are Identifiers/Atomic - - Reviewed by Geoff Garen. - - EmptyUnique strings should set the Identifier/Atomic flag. - - This fixes an unreproducible bug we believe exists in Identifier handling. - Expected behaviour is that while Identifiers may reference EmptyUniques - (StringImpls allocated as UIDs for PrivateNames), these are not created - through the main Identifier constructor, the Identifier flag is not set - on PrivateNames, and we should never lookup EmptyUnique strings in the - IdentifierTable. - - Unfortunately that was happening. Some tables used to implement property - access in the JIT hold StringImpl*s, and turn these back into Identifiers - using the identfiier constructor. Since the code generator will now plant - by-id (cachable) accesses to PrivateNames we can end up passing an - EmptyUnique to Identifier::add, potentially leading to PrivateNames being - uniqued together (though hard to prove, since the hash codes are random). - - * runtime/PropertyName.h: - (JSC::PropertyName::PropertyName): - (JSC::PropertyName::uid): - (JSC::PropertyName::publicName): - (JSC::PropertyName::asIndex): - - PropertyName assumed that PrivateNames are not Identifiers - instead check isEmptyUnique(). - * runtime/Structure.cpp: - (JSC::Structure::getPropertyNamesFromStructure): - - Structure assumed that PrivateNames are not Identifiers - instead check isEmptyUnique(). - -2014-03-19 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, revert the DFGCommon.h change in r165938. It was not intentional. - - * dfg/DFGCommon.h: - -2014-03-19 Mark Hahnenberg <mhahnenberg@apple.com> - - GC timer should intelligently choose between EdenCollections and FullCollections - https://bugs.webkit.org/show_bug.cgi?id=128261 - - Reviewed by Geoffrey Garen. - - Most of the GCs while browsing the web are due to the GC timer. Currently the GC timer - always does FullCollections. To reduce the impact of the GC timer on the system this patch - changes Heap so that it has two timers, one for each type of collection. The FullCollection - timer is notified at the end of EdenCollections how much the Heap has grown since the last - FullCollection and when somebody notifies the Heap of abandoned memory (which usually wouldn't - be detected by an EdenCollection). - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * heap/EdenGCActivityCallback.cpp: Added. - (JSC::EdenGCActivityCallback::EdenGCActivityCallback): - (JSC::EdenGCActivityCallback::doCollection): - (JSC::EdenGCActivityCallback::lastGCLength): - (JSC::EdenGCActivityCallback::deathRate): - (JSC::EdenGCActivityCallback::gcTimeSlice): - * heap/EdenGCActivityCallback.h: Added. - (JSC::GCActivityCallback::createEdenTimer): - * heap/FullGCActivityCallback.cpp: Added. - (JSC::FullGCActivityCallback::FullGCActivityCallback): - (JSC::FullGCActivityCallback::doCollection): - (JSC::FullGCActivityCallback::lastGCLength): - (JSC::FullGCActivityCallback::deathRate): - (JSC::FullGCActivityCallback::gcTimeSlice): - * heap/FullGCActivityCallback.h: Added. - (JSC::GCActivityCallback::createFullTimer): - * heap/GCActivityCallback.cpp: - (JSC::GCActivityCallback::GCActivityCallback): - (JSC::GCActivityCallback::doWork): - (JSC::GCActivityCallback::scheduleTimer): - (JSC::GCActivityCallback::cancelTimer): - (JSC::GCActivityCallback::didAllocate): - (JSC::GCActivityCallback::willCollect): - (JSC::GCActivityCallback::cancel): - * heap/GCActivityCallback.h: - * heap/Heap.cpp: - (JSC::Heap::Heap): - (JSC::Heap::reportAbandonedObjectGraph): - (JSC::Heap::didAbandon): - (JSC::Heap::collectAllGarbage): - (JSC::Heap::collect): - (JSC::Heap::willStartCollection): - (JSC::Heap::updateAllocationLimits): - (JSC::Heap::didFinishCollection): - (JSC::Heap::setFullActivityCallback): - (JSC::Heap::setEdenActivityCallback): - (JSC::Heap::fullActivityCallback): - (JSC::Heap::edenActivityCallback): - (JSC::Heap::setGarbageCollectionTimerEnabled): - (JSC::Heap::didAllocate): - (JSC::Heap::shouldDoFullCollection): - * heap/Heap.h: - (JSC::Heap::lastFullGCLength): - (JSC::Heap::lastEdenGCLength): - (JSC::Heap::increaseLastFullGCLength): - (JSC::Heap::sizeBeforeLastEdenCollection): - (JSC::Heap::sizeAfterLastEdenCollection): - (JSC::Heap::sizeBeforeLastFullCollection): - (JSC::Heap::sizeAfterLastFullCollection): - * heap/HeapOperation.h: - * heap/HeapStatistics.cpp: - (JSC::HeapStatistics::showObjectStatistics): - * heap/HeapTimer.cpp: - (JSC::HeapTimer::timerDidFire): - * jsc.cpp: - (functionFullGC): - (functionEdenGC): - * runtime/Options.h: - -2014-03-19 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r165926. - https://bugs.webkit.org/show_bug.cgi?id=130488 - - broke the iOS build (Requested by estes on #webkit). - - Reverted changeset: - - "GC timer should intelligently choose between EdenCollections - and FullCollections" - https://bugs.webkit.org/show_bug.cgi?id=128261 - http://trac.webkit.org/changeset/165926 - -2014-03-13 Mark Hahnenberg <mhahnenberg@apple.com> - - GC timer should intelligently choose between EdenCollections and FullCollections - https://bugs.webkit.org/show_bug.cgi?id=128261 - - Reviewed by Geoffrey Garen. - - Most of the GCs while browsing the web are due to the GC timer. Currently the GC timer - always does FullCollections. To reduce the impact of the GC timer on the system this patch - changes Heap so that it has two timers, one for each type of collection. The FullCollection - timer is notified at the end of EdenCollections how much the Heap has grown since the last - FullCollection and when somebody notifies the Heap of abandoned memory (which wouldn't be - detected by an EdenCollection). - - * heap/GCActivityCallback.cpp: - (JSC::GCActivityCallback::GCActivityCallback): - (JSC::GCActivityCallback::doWork): - (JSC::FullGCActivityCallback::FullGCActivityCallback): - (JSC::FullGCActivityCallback::doCollection): - (JSC::EdenGCActivityCallback::EdenGCActivityCallback): - (JSC::EdenGCActivityCallback::doCollection): - (JSC::GCActivityCallback::scheduleTimer): - (JSC::GCActivityCallback::cancelTimer): - (JSC::GCActivityCallback::didAllocate): - (JSC::GCActivityCallback::willCollect): - (JSC::GCActivityCallback::cancel): - * heap/GCActivityCallback.h: - (JSC::GCActivityCallback::GCActivityCallback): - (JSC::GCActivityCallback::createFullTimer): - (JSC::GCActivityCallback::createEdenTimer): - * heap/Heap.cpp: - (JSC::Heap::Heap): - (JSC::Heap::didAbandon): - (JSC::Heap::willStartCollection): - (JSC::Heap::updateAllocationLimits): - (JSC::Heap::setFullActivityCallback): - (JSC::Heap::setEdenActivityCallback): - (JSC::Heap::fullActivityCallback): - (JSC::Heap::edenActivityCallback): - (JSC::Heap::setGarbageCollectionTimerEnabled): - (JSC::Heap::didAllocate): - * heap/Heap.h: - * heap/HeapTimer.cpp: - (JSC::HeapTimer::timerDidFire): - -2014-03-19 Filip Pizlo <fpizlo@apple.com> - - REGRESSION(r165459): It broke 109 jsc stress test on ARM Thumb2 and Mac 32 bit - https://bugs.webkit.org/show_bug.cgi?id=130134 - - Reviewed by Mark Hahnenberg. - - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): Can't do some optimizations if you don't have a lot of registers. - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): Move stuff around before going into the IC code to ensure that we give the IC code the invariants it needs. This only happens in case of GetByIdFlush, where we are forced into using weird combinations of registers because the results have to be in t0/t1. - (JSC::DFG::SpeculativeJIT::compile): For a normal GetById, the register allocator should just do the right thing so nobody has to move anything around. - * jit/JITInlineCacheGenerator.cpp: - (JSC::JITGetByIdGenerator::JITGetByIdGenerator): Assert the things we want. - * jit/JITInlineCacheGenerator.h: - * jit/Repatch.cpp: - (JSC::generateGetByIdStub): Remove a previous incomplete hack to try to work around the DFG's problem. - -2014-03-19 Mark Hahnenberg <mhahnenberg@apple.com> - - Normalize some of the older JSC options - https://bugs.webkit.org/show_bug.cgi?id=128753 - - Reviewed by Michael Saboff. - - * runtime/Options.cpp: - (JSC::Options::initialize): - -2014-03-12 Mark Lam <mark.lam@apple.com> - - Update type of local vars to match the type of String length. - <https://webkit.org/b/130077> - - Reviewed by Geoffrey Garen. - - * runtime/JSStringJoiner.cpp: - (JSC::JSStringJoiner::join): - -2014-03-18 Filip Pizlo <fpizlo@apple.com> - - Get rid of Flush in SSA - https://bugs.webkit.org/show_bug.cgi?id=130440 - - Reviewed by Sam Weinig. - - This is basically a red patch. We used to use backwards flow for determining what was - flushed, until it became clear that this doesn't make sense. Now the Flush nodes don't - accomplish anything. Keeping them around in SSA can only make things hard. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGBasicBlock.cpp: - (JSC::DFG::BasicBlock::SSAData::SSAData): - * dfg/DFGBasicBlock.h: - * dfg/DFGFlushLivenessAnalysisPhase.cpp: Removed. - * dfg/DFGFlushLivenessAnalysisPhase.h: Removed. - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::dump): - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::compileInThreadImpl): - * dfg/DFGSSAConversionPhase.cpp: - (JSC::DFG::SSAConversionPhase::run): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - -2014-03-18 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix iOS production build. - - * JavaScriptCore.xcodeproj/project.pbxproj: - -2014-03-18 Michael Saboff <msaboff@apple.com> - - Update RegExp Tracing code - https://bugs.webkit.org/show_bug.cgi?id=130381 - - Reviewed by Andreas Kling. - - Updated the regular expression tracing code for 8/16 bit JIT as - well as match only entry points. Also added average string length - metric. - - * runtime/RegExp.cpp: - (JSC::RegExp::RegExp): - (JSC::RegExp::match): - (JSC::RegExp::printTraceData): - * runtime/RegExp.h: - * runtime/VM.cpp: - (JSC::VM::addRegExpToTrace): - (JSC::VM::dumpRegExpTrace): - * runtime/VM.h: - * yarr/YarrJIT.h: - (JSC::Yarr::YarrCodeBlock::get8BitMatchOnlyAddr): - (JSC::Yarr::YarrCodeBlock::get16BitMatchOnlyAddr): - (JSC::Yarr::YarrCodeBlock::get8BitMatchAddr): - (JSC::Yarr::YarrCodeBlock::get16BitMatchAddr): - -2014-03-17 Filip Pizlo <fpizlo@apple.com> - - Add CompareStrictEq(StringIdent:, NotStringVar:) and CompareStrictEq(String:, Untyped:) - https://bugs.webkit.org/show_bug.cgi?id=130300 - - Reviewed by Mark Hahnenberg. - - We can quickly strictly compare StringIdent's to NotStringVar's and String's to Untyped's. - This makes the DFG aware of this. - - Also adds StringIdent-to-StringIdent and StringIdent-to-NotStringVar strict comparisons to - the FTL. Also adds StringIdent-to-StringIdent non-strict comparisons to the FTL. - - This also gives the DFG some abstractions for checking something is a cell or is other. - This made this patch easier to write and also simplified a bunch of other stuff. - - 1% speed-up on Octane. - - * assembler/AbstractMacroAssembler.h: - (JSC::AbstractMacroAssembler::JumpList::JumpList): - * bytecode/SpeculatedType.h: - (JSC::isNotStringVarSpeculation): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNode.h: - (JSC::DFG::Node::childFor): - (JSC::DFG::Node::shouldSpeculateNotStringVar): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::SafeToExecuteEdge::operator()): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileIn): - (JSC::DFG::SpeculativeJIT::compileValueToInt32): - (JSC::DFG::SpeculativeJIT::compileInstanceOfForObject): - (JSC::DFG::SpeculativeJIT::compileInstanceOf): - (JSC::DFG::SpeculativeJIT::compileStrictEq): - (JSC::DFG::SpeculativeJIT::compileBooleanCompare): - (JSC::DFG::SpeculativeJIT::compileStringEquality): - (JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality): - (JSC::DFG::SpeculativeJIT::compileStringIdentEquality): - (JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality): - (JSC::DFG::SpeculativeJIT::compileStringZeroLength): - (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): - (JSC::DFG::SpeculativeJIT::speculateString): - (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage): - (JSC::DFG::SpeculativeJIT::speculateNotStringVar): - (JSC::DFG::SpeculativeJIT::speculateNotCell): - (JSC::DFG::SpeculativeJIT::speculateOther): - (JSC::DFG::SpeculativeJIT::speculate): - (JSC::DFG::SpeculativeJIT::emitSwitchChar): - (JSC::DFG::SpeculativeJIT::emitSwitchString): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::blessedBooleanResult): - (JSC::DFG::SpeculativeJIT::unblessedBooleanResult): - (JSC::DFG::SpeculativeJIT::booleanResult): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): - (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): - (JSC::DFG::SpeculativeJIT::emitCall): - (JSC::DFG::SpeculativeJIT::fillSpeculateCell): - (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): - (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::branchIsCell): - (JSC::DFG::branchNotCell): - (JSC::DFG::SpeculativeJIT::branchIsOther): - (JSC::DFG::SpeculativeJIT::branchNotOther): - (JSC::DFG::SpeculativeJIT::moveTrueTo): - (JSC::DFG::SpeculativeJIT::moveFalseTo): - (JSC::DFG::SpeculativeJIT::blessBoolean): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): - (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): - (JSC::DFG::SpeculativeJIT::fillSpeculateCell): - (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): - (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::writeBarrier): - (JSC::DFG::SpeculativeJIT::branchIsCell): - (JSC::DFG::SpeculativeJIT::branchNotCell): - (JSC::DFG::SpeculativeJIT::branchIsOther): - (JSC::DFG::SpeculativeJIT::branchNotOther): - (JSC::DFG::SpeculativeJIT::moveTrueTo): - (JSC::DFG::SpeculativeJIT::moveFalseTo): - (JSC::DFG::SpeculativeJIT::blessBoolean): - * dfg/DFGUseKind.cpp: - (WTF::printInternal): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::lowString): - (JSC::FTL::LowerDFGToLLVM::lowStringIdent): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateString): - (JSC::FTL::LowerDFGToLLVM::speculateStringIdent): - (JSC::FTL::LowerDFGToLLVM::speculateNotStringVar): - * runtime/JSCJSValue.h: - * tests/stress/string-ident-to-not-string-var-equality.js: Added. - (foo): - (bar): - (test): - -2014-03-18 Joseph Pecoraro <pecoraro@apple.com> - - Add Copyright to framework.sb - https://bugs.webkit.org/show_bug.cgi?id=130413 - - Reviewed by Timothy Hatcher. - - Other sb files got the copyright. Follow suit. - - * framework.sb: - -2014-03-18 Matthew Mirman <mmirman@apple.com> - - Removed extra parens from if statement in a preprocessor define. - https://bugs.webkit.org/show_bug.cgi?id=130408 - - Reviewed by Filip Pizlo. - - * parser/Parser.cpp: - -2014-03-18 Filip Pizlo <fpizlo@apple.com> - - More FTL enabling. - - Rubber stamped by Dan Bernstein and Mark Hahnenberg. - - * Configurations/FeatureDefines.xcconfig: - * ftl/FTLCompile.cpp: - (JSC::FTL::compile): - -2014-03-17 Michael Saboff <msaboff@apple.com> - - V8 regexp spends most of its time in operationGetById - https://bugs.webkit.org/show_bug.cgi?id=130380 - - Reviewed by Filip Pizlo. - - Added String.length case to tryCacheGetByID that will only help the BaseLine JIT. - When V8 regexp is run from the command line, this nets a 2% performance improvement. - When the test is run for a longer amount of time, there is much less benefit as the - DFG will emit the appropriate code for String.length. This does remove - operationGetById as the hottest function whne run from the command line. - - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - -2014-03-17 Andreas Kling <akling@apple.com> - - Add one-deep cache to opaque roots hashset. - <https://webkit.org/b/130357> - - The vast majority of WebCore JS wrappers will have their Document* - as the root(). This change adds a simple optimization where we cache - the last lookup and avoid going to the hashset for repeated queries. - - Looks like 0.4% progression on DYEB on my MBP. - - Reviewed by Mark Hahnenberg. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * heap/OpaqueRootSet.h: Added. - (JSC::OpaqueRootSet::OpaqueRootSet): - (JSC::OpaqueRootSet::contains): - (JSC::OpaqueRootSet::isEmpty): - (JSC::OpaqueRootSet::clear): - (JSC::OpaqueRootSet::add): - (JSC::OpaqueRootSet::size): - (JSC::OpaqueRootSet::begin): - (JSC::OpaqueRootSet::end): - * heap/SlotVisitor.h: - -2014-03-17 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> - - Implement Math.hypot - https://bugs.webkit.org/show_bug.cgi?id=129486 - - Reviewed by Darin Adler. - - * runtime/MathObject.cpp: - (JSC::MathObject::finishCreation): - (JSC::mathProtoFuncHypot): - -2014-03-17 Zsolt Borbely <borbezs@inf.u-szeged.hu> - - Fix the !ENABLE(PROMISES) build - https://bugs.webkit.org/show_bug.cgi?id=130328 - - Reviewed by Darin Adler. - - Add missing ENABLE(PROMISES) guards. - - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::reset): - (JSC::JSGlobalObject::visitChildren): - * runtime/JSGlobalObject.h: - * runtime/JSPromiseDeferred.cpp: - * runtime/JSPromiseDeferred.h: - * runtime/JSPromiseReaction.cpp: - * runtime/JSPromiseReaction.h: - * runtime/VM.cpp: - (JSC::VM::VM): - * runtime/VM.h: - -2014-03-16 Andreas Kling <akling@apple.com> - - REGRESSION(r165703): JSC tests crashing in StringImpl::destroy(). - <https://webkit.org/b/130304> - - Reviewed by Anders Carlsson. - - Unreviewed, restoring the old behavior of OpaqueJSString::identifier() - that doesn't put a potentially unwanted string into the Identifier table. - - * API/OpaqueJSString.cpp: - (OpaqueJSString::identifier): - -2014-03-16 Brian Burg <bburg@apple.com> - - Web Inspector: generated backend commands should reflect build system ENABLE settings - https://bugs.webkit.org/show_bug.cgi?id=130111 - - Reviewed by Timothy Hatcher. - - * CMakeLists.txt: - - Combine only the Inspector domains listed in INSPECTOR_DOMAINS, - instead of globbing any .json file. - - * DerivedSources.make: - - Force the combined inspector protocol file to be regenerated if - the content or list of domains itself changes. - -2014-03-16 Brian Burg <bburg@apple.com> - - Web Inspector: vended backend commands file should be generated as part of the build - https://bugs.webkit.org/show_bug.cgi?id=130110 - - Reviewed by Timothy Hatcher. - - * JavaScriptCore.xcodeproj/project.pbxproj: Copy InspectorJSBackendCommands.js to the - private headers directory. - -2014-03-16 Darin Adler <darin@apple.com> - - Remove all uses of deprecatedCharacters from JavaScriptCore - https://bugs.webkit.org/show_bug.cgi?id=130304 - - Reviewed by Anders Carlsson. - - * API/JSValueRef.cpp: - (JSValueMakeFromJSONString): Use characters16 in the 16-bit code path. - * API/OpaqueJSString.cpp: - (OpaqueJSString::~OpaqueJSString): Use characters 16 in the 16-bit code path. - (OpaqueJSString::identifier): Get rid of custom Identifier constructor, and - juse use the standard one that takes a String. - (OpaqueJSString::characters): Use getCharactersWithUpconvert instead of a - hand-written alternative. - - * bindings/ScriptValue.cpp: - (Deprecated::jsToInspectorValue): Create InspectorString from String directly - instead of involving a character pointer. Use the String from Identifier - directly instead of making a new String. - - * inspector/ContentSearchUtilities.cpp: - (Inspector::ContentSearchUtilities::createSearchRegexSource): Use StringBuilder - instead of building a String a character at a time. This is still a very slow - way to do this. Also use strchr to search for a character instead of building - a String every time just to use find on it. - - * inspector/InspectorValues.cpp: - (Inspector::doubleQuoteString): Remove unnecessary trip through a - character pointer. This is still a really slow way to do this. - (Inspector::InspectorValue::parseJSON): Use StringView::upconvertedCharacters - instead of String::deprecatedCharacters. Still slow to always upconvert. - - * runtime/DateConstructor.cpp: Removed unneeded include. - * runtime/DatePrototype.cpp: Ditto. - - * runtime/Identifier.h: Removed deprecatedCharacters function. - - * runtime/JSGlobalObjectFunctions.cpp: - (JSC::encode): Added a type cast to avoid ambiguity with the two character- - appending functions from JSStringBuilder. Removed unneeded code duplicating - what JSStringBuilder already does in its character append function. - (JSC::decode): Deleted code that creates a JSStringBuilder that is never used. - (JSC::parseIntOverflow): Changed lengths to unsigned. Made only the overload that - is used outside this file have external linkage. Added a new overload that takes - a StringView. - (JSC::parseInt): Use StringView::substring to call parseIntOverflow. - (JSC::globalFuncEscape): Use JSBuilder::append in a more efficient way for a - single character. - - * runtime/JSGlobalObjectFunctions.h: Removed unused overloads of parseIntOverflow. - - * runtime/JSStringBuilder.h: Marked this "lightly deprecated". - (JSC::JSStringBuilder::append): Overloaded for better speed with 8-bit characters. - Made one overload private. Fixed a performance bug where we would reserve capacity - in the 8-bit buffer but then append to the 16-bit buffer. - - * runtime/ObjectPrototype.cpp: Removed unneeded include. - - * runtime/StringPrototype.cpp: - (JSC::stringProtoFuncFontsize): Use StringView::getCharactersWithUpconvert. - (JSC::stringProtoFuncLink): Ditto. - -2014-03-15 Filip Pizlo <fpizlo@apple.com> - - FTL ArrayifyToStructure shouldn't fail every time that it actually arrayifies - https://bugs.webkit.org/show_bug.cgi?id=130296 - - Reviewed by Andreas Kling. - - During the 32-bit structure ID work, the second load of the structure was removed. - That's wrong. The whole point of loading the structure ID again is that the structure - ID would have been changed by the arrayification call, and we're verifying that the - arrayification succeeded in changing the structure. If we check the old structure - as - the code was doing after the 32-bit structure ID work - then this check is guaranteed - to fail, causing a significant performance regression. - - It's actually amazing that the regression wasn't bigger. The reason is that if FTL - code pathologically exits but the equivalent DFG code doesn't, then the exponential - backoff almost perfectly guarantees that we just end up in the DFG. For this code, at - the time at least, the DFG wasn't much slower so this didn't cause too much pain. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): - -2014-03-15 Filip Pizlo <fpizlo@apple.com> - - FTL should support CheckHasInstance/InstanceOf - https://bugs.webkit.org/show_bug.cgi?id=130285 - - Reviewed by Sam Weinig. - - Fairly straightforward; I also discovered an inaccurate FIXME in the process. - - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * ftl/FTLAbstractHeapRepository.h: - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileCheckHasInstance): - (JSC::FTL::LowerDFGToLLVM::compileInstanceOf): - * ftl/FTLOutput.h: - (JSC::FTL::Output::phi): - * tests/stress/instanceof.js: Added. - * tests/stress/instanceof-not-cell.js: Added. - -2014-03-15 Michael Saboff <msaboff@apple.com> - - It should be possible to adjust DFG and FTL compiler thread priorities - https://bugs.webkit.org/show_bug.cgi?id=130288 - - Reviewed by Filip Pizlo. - - Added ability to change thread priorities relative to its current priority. - Created options to adjust the priority of the DFG and FTL compilation work thread - pools. For two core systems, there might be three runnable threads, the main thread, - the DFG compilation thread and the FTL compilation thread. With the same priority, - the scheduler is free to schedule whatever thread it wants. By lowering the - compilation threads, the main thread can run. Further tests may suggest better values - for the new options, priorityDeltaOfDFGCompilerThreads and priorityDeltaOfFTLCompilerThreads. - - For a two-core device, this change has a net positive improvement of 1-3% across - SunSpider, Octane, Kraken and AsmBench. - - * dfg/DFGWorklist.cpp: - (JSC::DFG::Worklist::finishCreation): - (JSC::DFG::Worklist::create): - (JSC::DFG::ensureGlobalDFGWorklist): - (JSC::DFG::ensureGlobalFTLWorklist): - * dfg/DFGWorklist.h: - * runtime/Options.cpp: - (JSC::computePriorityDeltaOfWorkerThreads): - * runtime/Options.h: - -2014-03-15 David Kilzer <ddkilzer@apple.com> - - [iOS] Define SYSTEM_VERSION_PREFIX consistently - <http://webkit.org/b/130293> - <rdar://problem/15926359> - - Reviewed by Dan Bernstein. - - * Configurations/Version.xcconfig: - (SYSTEM_VERSION_PREFIX_iphoneos): Sync with - Source/WebKit/mac/Version.xcconfig. - -2014-03-15 David Kilzer <ddkilzer@apple.com> - - Fix build: using integer absolute value function 'abs' when argument is of floating point type - <http://webkit.org/b/130286> - - Reviewed by Filip Pizlo. - - Fixes the following build failure using trunk clang: - - JavaScriptCore/assembler/MacroAssembler.h:992:17: error: using integer absolute value function 'abs' when argument is of floating point type [-Werror,-Wabsolute-value] - value = abs(value); - ^ - JavaScriptCore/assembler/MacroAssembler.h:992:17: note: use function 'fabs' instead - value = abs(value); - ^~~ - fabs - - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::shouldBlindDouble): Switch from abs() to - fabs(). - -2014-03-14 Oliver Hunt <oliver@apple.com> - - Reinstate intialiser syntax in for-in loops - https://bugs.webkit.org/show_bug.cgi?id=130269 - - Reviewed by Michael Saboff. - - Disallowing the initialiser broke some sites so this patch re-allows - the syntax. We still disallow the syntax in 'of' and pattern based - enumeration. - - * parser/ASTBuilder.h: - (JSC::ASTBuilder::isBindingNode): - * parser/Parser.cpp: - (JSC::Parser<LexerType>::parseVarDeclarationList): - (JSC::Parser<LexerType>::parseForStatement): - * parser/SyntaxChecker.h: - (JSC::SyntaxChecker::operatorStackPop): - -2014-03-14 Mark Lam <mark.lam@apple.com> - - Accessing __lookupGetter__ and __lookupSetter__ should not crash the VM when undefined. - <https://webkit.org/b/130279> - - Reviewed by Filip Pizlo. - - If neither the getter nor setter are defined, accessing __lookupGetter__ - and __lookupSetter__ will return undefined as expected. However, if the - getter is defined but the setter is not, accessing __lookupSetter__ will - crash the VM. Similarly, accessing __lookupGetter__ when only the setter - is defined will crash the VM. - - The reason is because objectProtoFuncLookupGetter() and - objectProtoFuncLookupSetter() did not check if the getter and setter - value is non-null before returning it as an EncodedJSValue. The fix is - to add the appropriate null checks. - - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncLookupGetter): - (JSC::objectProtoFuncLookupSetter): - -2014-03-14 Mark Rowe <mrowe@apple.com> - - Fix the production build. - - Don't rely on USE_INTERNAL_SDK being set for the Production configuration since UseInternalSDK.xcconfig won't - be at the expected relative path when working from installed source. - - * Configurations/Base.xcconfig: - -2014-03-14 Maciej Stachowiak <mjs@apple.com> - - Replace "Apple Computer, Inc." with "Apple Inc." in copyright headers - https://bugs.webkit.org/show_bug.cgi?id=130276 - <rdar://problem/16266927> - - Reviewed by Simon Fraser. - - * API/APICast.h: - * API/JSBase.cpp: - * API/JSBase.h: - * API/JSBasePrivate.h: - * API/JSCallbackConstructor.cpp: - * API/JSCallbackConstructor.h: - * API/JSCallbackFunction.cpp: - * API/JSCallbackFunction.h: - * API/JSCallbackObject.cpp: - * API/JSCallbackObject.h: - * API/JSCallbackObjectFunctions.h: - * API/JSClassRef.cpp: - * API/JSClassRef.h: - * API/JSContextRef.cpp: - * API/JSContextRef.h: - * API/JSContextRefPrivate.h: - * API/JSObjectRef.cpp: - * API/JSObjectRef.h: - * API/JSProfilerPrivate.cpp: - * API/JSProfilerPrivate.h: - * API/JSRetainPtr.h: - * API/JSStringRef.cpp: - * API/JSStringRef.h: - * API/JSStringRefBSTR.cpp: - * API/JSStringRefBSTR.h: - * API/JSStringRefCF.cpp: - * API/JSStringRefCF.h: - * API/JSValueRef.cpp: - * API/JSValueRef.h: - * API/JavaScript.h: - * API/JavaScriptCore.h: - * API/OpaqueJSString.cpp: - * API/OpaqueJSString.h: - * API/tests/JSNode.c: - * API/tests/JSNode.h: - * API/tests/JSNodeList.c: - * API/tests/JSNodeList.h: - * API/tests/Node.c: - * API/tests/Node.h: - * API/tests/NodeList.c: - * API/tests/NodeList.h: - * API/tests/minidom.c: - * API/tests/minidom.js: - * API/tests/testapi.c: - * API/tests/testapi.js: - * DerivedSources.make: - * bindings/ScriptValue.cpp: - * bytecode/CodeBlock.cpp: - * bytecode/CodeBlock.h: - * bytecode/EvalCodeCache.h: - * bytecode/Instruction.h: - * bytecode/JumpTable.cpp: - * bytecode/JumpTable.h: - * bytecode/Opcode.cpp: - * bytecode/Opcode.h: - * bytecode/SamplingTool.cpp: - * bytecode/SamplingTool.h: - * bytecode/SpeculatedType.cpp: - * bytecode/SpeculatedType.h: - * bytecode/ValueProfile.h: - * bytecompiler/BytecodeGenerator.cpp: - * bytecompiler/BytecodeGenerator.h: - * bytecompiler/Label.h: - * bytecompiler/LabelScope.h: - * bytecompiler/RegisterID.h: - * debugger/DebuggerCallFrame.cpp: - * debugger/DebuggerCallFrame.h: - * dfg/DFGDesiredStructureChains.cpp: - * dfg/DFGDesiredStructureChains.h: - * heap/GCActivityCallback.cpp: - * heap/GCActivityCallback.h: - * inspector/ConsoleMessage.cpp: - * inspector/ConsoleMessage.h: - * inspector/IdentifiersFactory.cpp: - * inspector/IdentifiersFactory.h: - * inspector/InjectedScriptManager.cpp: - * inspector/InjectedScriptManager.h: - * inspector/InjectedScriptSource.js: - * inspector/ScriptBreakpoint.h: - * inspector/ScriptDebugListener.h: - * inspector/ScriptDebugServer.cpp: - * inspector/ScriptDebugServer.h: - * inspector/agents/InspectorAgent.cpp: - * inspector/agents/InspectorAgent.h: - * inspector/agents/InspectorDebuggerAgent.cpp: - * inspector/agents/InspectorDebuggerAgent.h: - * interpreter/Interpreter.cpp: - * interpreter/Interpreter.h: - * interpreter/JSStack.cpp: - * interpreter/JSStack.h: - * interpreter/Register.h: - * jit/CompactJITCodeMap.h: - * jit/JITStubs.cpp: - * jit/JITStubs.h: - * jit/JITStubsARM.h: - * jit/JITStubsARMv7.h: - * jit/JITStubsX86.h: - * jit/JITStubsX86_64.h: - * os-win32/stdbool.h: - * parser/SourceCode.h: - * parser/SourceProvider.h: - * profiler/LegacyProfiler.cpp: - * profiler/LegacyProfiler.h: - * profiler/ProfileNode.cpp: - * profiler/ProfileNode.h: - * runtime/ArrayBufferView.cpp: - * runtime/ArrayBufferView.h: - * runtime/BatchedTransitionOptimizer.h: - * runtime/CallData.h: - * runtime/ConstructData.h: - * runtime/DumpContext.cpp: - * runtime/DumpContext.h: - * runtime/ExceptionHelpers.cpp: - * runtime/ExceptionHelpers.h: - * runtime/InitializeThreading.cpp: - * runtime/InitializeThreading.h: - * runtime/IntegralTypedArrayBase.h: - * runtime/IntendedStructureChain.cpp: - * runtime/IntendedStructureChain.h: - * runtime/JSActivation.cpp: - * runtime/JSActivation.h: - * runtime/JSExportMacros.h: - * runtime/JSGlobalObject.cpp: - * runtime/JSNotAnObject.cpp: - * runtime/JSNotAnObject.h: - * runtime/JSPropertyNameIterator.cpp: - * runtime/JSPropertyNameIterator.h: - * runtime/JSSegmentedVariableObject.cpp: - * runtime/JSSegmentedVariableObject.h: - * runtime/JSSymbolTableObject.cpp: - * runtime/JSSymbolTableObject.h: - * runtime/JSTypeInfo.h: - * runtime/JSVariableObject.cpp: - * runtime/JSVariableObject.h: - * runtime/PropertyTable.cpp: - * runtime/PutPropertySlot.h: - * runtime/SamplingCounter.cpp: - * runtime/SamplingCounter.h: - * runtime/Structure.cpp: - * runtime/Structure.h: - * runtime/StructureChain.cpp: - * runtime/StructureChain.h: - * runtime/StructureInlines.h: - * runtime/StructureTransitionTable.h: - * runtime/SymbolTable.cpp: - * runtime/SymbolTable.h: - * runtime/TypedArrayBase.h: - * runtime/TypedArrayType.cpp: - * runtime/TypedArrayType.h: - * runtime/VM.cpp: - * runtime/VM.h: - * yarr/RegularExpression.cpp: - * yarr/RegularExpression.h: - -2014-03-14 Filip Pizlo <fpizlo@apple.com> - - Final FTL iOS build magic - https://bugs.webkit.org/show_bug.cgi?id=130281 - - Reviewed by Michael Saboff. - - * Configurations/Base.xcconfig: For now our LLVM headers are in /usr/local/LLVMForJavaScriptCore/include, which is the same as OS X. - * Configurations/LLVMForJSC.xcconfig: We need to be more careful about how we specify library paths if we want to get the prioritzation right. Also we need protobuf because things. :-/ - -2014-03-14 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Gracefully handle nil name -[JSContext setName:] - https://bugs.webkit.org/show_bug.cgi?id=130262 - - Reviewed by Mark Hahnenberg. - - * API/JSContext.mm: - (-[JSContext setName:]): - Gracefully handle nil input. - - * API/tests/testapi.c: - (globalContextNameTest): - * API/tests/testapi.mm: - Test for nil / NULL names in the ObjC and C APIs. - -2014-03-11 Oliver Hunt <oliver@apple.com> - - Improve dom error messages - https://bugs.webkit.org/show_bug.cgi?id=130103 - - Reviewed by Andreas Kling. - - Add new helper function. - - * runtime/Error.h: - (JSC::throwVMTypeError): - -2014-03-14 László Langó <llango.u-szeged@partner.samsung.com> - - Remove unused method declaration. - https://bugs.webkit.org/show_bug.cgi?id=130238 - - Reviewed by Filip Pizlo. - - The implementation of CallFrame::dumpCaller was removed in - http://trac.webkit.org/changeset/153183, but the declaration of it was not. - - * interpreter/CallFrame.h: - Remove CallFrame::dumpCaller() method declaration. - -2014-03-12 Sergio Villar Senin <svillar@igalia.com> - - Rename DEFINE_STATIC_LOCAL to DEPRECATED_DEFINE_STATIC_LOCAL - https://bugs.webkit.org/show_bug.cgi?id=129612 - - Reviewed by Darin Adler. - - For new code use static NeverDestroyed<T> instead. - - * API/JSAPIWrapperObject.mm: - (jsAPIWrapperObjectHandleOwner): - * API/JSManagedValue.mm: - (managedValueHandleOwner): - * inspector/agents/InspectorDebuggerAgent.cpp: - (Inspector::objectGroupForBreakpointAction): - * inspector/scripts/CodeGeneratorInspectorStrings.py: - * interpreter/JSStack.cpp: - (JSC::stackStatisticsMutex): - * jit/ExecutableAllocator.cpp: - (JSC::DemandExecutableAllocator::allocators): - -2014-03-12 Gavin Barraclough <barraclough@apple.com> - - Reduce memory use for static property maps - https://bugs.webkit.org/show_bug.cgi?id=129986 - - Reviewed by Andreas Kling. - - Static property tables are currently duplicated on first use from read-only memory into dirty memory - in every process, and since the entries are large (48 bytes) and the tables can be unusually sparse - (we use a custom hash table without a rehash) a lot of memory may be wasted. - - First, reduce the size of the hashtable. Instead of storing values in the table the hashtable maps - from string hashes to indicies into a densely packed array of values. Compute the index table at - compile time as a part of the derived sources step, such that this may be read-only data. - - Second, don't copy all data from the HashTableValue array into a HashEntry objects. Instead refer - directly to the HashTableValue entries. The only data that needs to be allocated at runtime are the - keys, which are Identifiers. - - * create_hash_table: - - emit the hash table index into the derived source (we were calculating this already to ensure chaining does not get too deep). - * parser/Lexer.cpp: - (JSC::Lexer<LChar>::parseIdentifier): - (JSC::Lexer<UChar>::parseIdentifier): - (JSC::Lexer<T>::parseIdentifierSlowCase): - - HashEntry -> HashTableValue. - * parser/Lexer.h: - (JSC::Keywords::getKeyword): - - HashEntry -> HashTableValue. - * runtime/ClassInfo.h: - - removed HashEntry. - * runtime/JSObject.cpp: - (JSC::getClassPropertyNames): - - use HashTable::ConstIterator. - (JSC::JSObject::put): - (JSC::JSObject::deleteProperty): - (JSC::JSObject::findPropertyHashEntry): - - HashEntry -> HashTableValue. - (JSC::JSObject::reifyStaticFunctionsForDelete): - - changed HashTable::ConstIterator interface. - * runtime/JSObject.h: - - HashEntry -> HashTableValue. - * runtime/Lookup.cpp: - (JSC::HashTable::createTable): - - table -> keys, keys array is now densely packed. - (JSC::HashTable::deleteTable): - - table -> keys. - (JSC::setUpStaticFunctionSlot): - - HashEntry -> HashTableValue. - * runtime/Lookup.h: - (JSC::HashTableValue::builtinGenerator): - (JSC::HashTableValue::function): - (JSC::HashTableValue::functionLength): - (JSC::HashTableValue::propertyGetter): - (JSC::HashTableValue::propertyPutter): - (JSC::HashTableValue::lexerValue): - - added accessor methods from HashEntry. - (JSC::HashTable::copy): - - fields changed. - (JSC::HashTable::initializeIfNeeded): - - table -> keys. - (JSC::HashTable::entry): - - HashEntry -> HashTableValue. - (JSC::HashTable::ConstIterator::ConstIterator): - - iterate packed value array, so no need to skipInvalidKeys(). - (JSC::HashTable::ConstIterator::value): - (JSC::HashTable::ConstIterator::key): - (JSC::HashTable::ConstIterator::operator->): - - accessors now get HashTableValue/StringImpl* separately. - (JSC::HashTable::ConstIterator::operator++): - - iterate packed value array, so no need to skipInvalidKeys(). - (JSC::HashTable::end): - - end is now size of dense not sparse array. - (JSC::getStaticPropertySlot): - (JSC::getStaticFunctionSlot): - (JSC::getStaticValueSlot): - (JSC::putEntry): - (JSC::lookupPut): - - HashEntry -> HashTableValue. - -2014-03-13 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix Mac no-FTL build. - - * llvm/library/LLVMExports.cpp: - (initializeAndGetJSCLLVMAPI): - -2014-03-13 Juergen Ributzka <juergen@apple.com> - - Only export initializeAndGetJSCLLVMAPI from libllvmForJSC.dylib - https://bugs.webkit.org/show_bug.cgi?id=130224 - - Reviewed by Filip Pizlo. - - This limits the exported symbols to only initializeAndGetJSCLLVMAPI from - the LLVM dylib. This allows the dylib to be safely used with other LLVM - dylibs on the same system. It also reduces the dynamic linking overhead - and also reduces the size by 6MB, because the linker can now dead strip - many unused functions. - - * Configurations/LLVMForJSC.xcconfig: - -2014-03-13 Andreas Kling <akling@apple.com> - - VM::discardAllCode() should clear the RegExp cache. - <https://webkit.org/b/130144> - - Reviewed by Michael Saboff. - - * runtime/VM.cpp: - (JSC::VM::discardAllCode): - -2014-03-13 Andreas Kling <akling@apple.com> - - Revert "Short-circuit JSGlobalObjectInspectorController when not inspecting." - <https://webkit.org/b/129995> - - This code path is not taken anymore on DYEB, and I can't explain why - it was showing up in my profiles. Backing it out per JoePeck's suggestion. - - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - -2014-03-13 Filip Pizlo <fpizlo@apple.com> - - FTL should support IsBlah - https://bugs.webkit.org/show_bug.cgi?id=130202 - - Reviewed by Geoffrey Garen. - - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileIsUndefined): - (JSC::FTL::LowerDFGToLLVM::compileIsBoolean): - (JSC::FTL::LowerDFGToLLVM::compileIsNumber): - (JSC::FTL::LowerDFGToLLVM::compileIsString): - (JSC::FTL::LowerDFGToLLVM::compileIsObject): - (JSC::FTL::LowerDFGToLLVM::compileIsFunction): - (JSC::FTL::LowerDFGToLLVM::compileStoreBarrier): - (JSC::FTL::LowerDFGToLLVM::compileStoreBarrierWithNullCheck): - (JSC::FTL::LowerDFGToLLVM::isNotCellOrMisc): - (JSC::FTL::LowerDFGToLLVM::isNumber): - (JSC::FTL::LowerDFGToLLVM::isNotNumber): - (JSC::FTL::LowerDFGToLLVM::isBoolean): - * ftl/FTLOSRExitCompiler.cpp: - * tests/stress/is-undefined-exit-on-masquerader.js: Added. - (bar): - (foo): - (test): - * tests/stress/is-undefined-jettison-on-masquerader.js: Added. - (foo): - (test): - * tests/stress/is-undefined-masquerader.js: Added. - (foo): - (test): - -2014-03-13 Mark Lam <mark.lam@apple.com> - - JS benchmarks crash with a bus error on 32-bit x86. - <https://webkit.org/b/130203> - - Reviewed by Geoffrey Garen. - - The issue is that generateGetByIdStub() can potentially use the same register - for the JSValue base register and the target tag register. After loading the - tag value into the target tag register, the JSValue base address is lost. - The code then proceeds to load the payload value using the base register, and - this results in a crash. - - The fix is to check if the base register is the same as the target tag register. - If so, we should make a copy the base register first before loading the tag - value, and use the copy to load the payload value instead. - - * jit/Repatch.cpp: - (JSC::generateGetByIdStub): - -2014-03-12 Filip Pizlo <fpizlo@apple.com> - - WebKit shouldn't crash on uniprocessor machines - https://bugs.webkit.org/show_bug.cgi?id=130176 - - Reviewed by Michael Saboff. - - Previously the math for computing the number of JIT compiler threads would come up with - zero threads on uniprocessor machines, and then the Worklist code would assert. - - * runtime/Options.cpp: - (JSC::computeNumberOfWorkerThreads): - * runtime/Options.h: - -2014-03-13 Radu Stavila <stavila@adobe.com> - - Webkit not building on XCode 5.1 due to garbage collection no longer being supported - https://bugs.webkit.org/show_bug.cgi?id=130087 - - Reviewed by Mark Rowe. - - Disable garbage collection on macosx when not using internal SDK. - - * Configurations/Base.xcconfig: - -2014-03-10 Darin Adler <darin@apple.com> - - Avoid copy-prone idiom "for (auto item : collection)" - https://bugs.webkit.org/show_bug.cgi?id=129990 - - Reviewed by Geoffrey Garen. - - * heap/CodeBlockSet.h: - (JSC::CodeBlockSet::iterate): Use auto& to be sure we don't copy by accident. - * inspector/ScriptDebugServer.cpp: - (Inspector::ScriptDebugServer::dispatchBreakpointActionLog): Use auto* to - make explicit that we are iterating through pointers. - (Inspector::ScriptDebugServer::dispatchBreakpointActionSound): Ditto. - (Inspector::ScriptDebugServer::dispatchBreakpointActionProbe): Ditto. - * inspector/agents/InspectorDebuggerAgent.cpp: - (Inspector::InspectorDebuggerAgent::removeBreakpoint): Use auto&, and also - get rid of an unneeded local variable. - -2014-03-13 Brian Burg <bburg@apple.com> - - Web Inspector: Remove unused callId parameter from evaluateInWebInspector - https://bugs.webkit.org/show_bug.cgi?id=129744 - - Reviewed by Timothy Hatcher. - - * inspector/agents/InspectorAgent.cpp: - (Inspector::InspectorAgent::enable): - (Inspector::InspectorAgent::evaluateForTestInFrontend): - * inspector/agents/InspectorAgent.h: - * inspector/protocol/InspectorDomain.json: - -2014-03-11 Filip Pizlo <fpizlo@apple.com> - - ASSERTION FAILED: node->op() == Phi || node->op() == SetArgument - https://bugs.webkit.org/show_bug.cgi?id=130069 - - Reviewed by Geoffrey Garen. - - This was a great assertion, and it represents our strictest interpretation of the rules of - our intermediate representation. However, fixing DCE to actually preserve the relevant - property would be hard, and it wouldn't have an observable effect right now because nobody - actually uses the propery of CPS that this assertion is checking for. - - In particular, we do always require, and rely on, the fact that non-captured variables - have variablesAtTail refer to the last interesting use of the variable: a SetLocal if the - block assigns to the variable, a GetLocal if it only reads from it, and a Flush, - PhantomLocal, or Phi otherwise. We do preserve this property successfully and DCE was not - broken in this regard. But, in the strictest sense, CPS also means that for captured - variables, variablesAtTail also continues to point to the last relevant use of the - variable. In particular, if there are multiple GetLocals, then it should point to the last - one. This is hard for DCE to preserve. Also, nobody relies on variablesAtTail for captured - variables, except to check the VariableAccessData; but in that case, we don't really need - the *last* relevant use of the variable - any node that mentions the same variable will do - just fine. - - So, this change loosens the assertion and adds a detailed FIXME describing what we would - have to do if we wanted to preserve the more strict property. - - This also makes changes to various debug printing paths so that validation doesn't crash - during graph dump. This also adds tests for the interesting cases of DCE failing to - preserve CPS in the strictest sense. This also attempts to win the record for longest test - name. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::hashAsStringIfPossible): - (JSC::CodeBlock::dumpAssumingJITType): - * bytecode/CodeBlock.h: - * bytecode/CodeOrigin.cpp: - (JSC::InlineCallFrame::hashAsStringIfPossible): - (JSC::InlineCallFrame::dumpBriefFunctionInformation): - * bytecode/CodeOrigin.h: - * dfg/DFGCPSRethreadingPhase.cpp: - (JSC::DFG::CPSRethreadingPhase::run): - * dfg/DFGDCEPhase.cpp: - (JSC::DFG::DCEPhase::cleanVariables): - * dfg/DFGInPlaceAbstractState.cpp: - (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): - * runtime/FunctionExecutableDump.cpp: - (JSC::FunctionExecutableDump::dump): - * tests/stress/dead-access-to-captured-variable-preceded-by-a-live-store-in-function-with-multiple-basic-blocks.js: Added. - (foo): - * tests/stress/dead-access-to-captured-variable-preceded-by-a-live-store.js: Added. - (foo): - -2014-03-12 Brian Burg <bburg@apple.com> - - Web Replay: add infrastructure for memoizing nondeterministic DOM APIs - https://bugs.webkit.org/show_bug.cgi?id=129445 - - Reviewed by Timothy Hatcher. - - There was a bug in the replay inputs code generator that would include - headers for definitions of enum classes, even though they can be safely - forward-declared. - - * replay/scripts/CodeGeneratorReplayInputs.py: - (Generator.generate_includes): Only include for copy constructor if the - type is a heavy scalar (i.e., String, URL), not a normal scalar - (i.e., int, double, enum classes). - - (Generator.generate_type_forward_declarations): Forward-declare scalars - that are enums or enum classes. - -2014-03-12 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Disable REMOTE_INSPECTOR in earlier OS X releases - https://bugs.webkit.org/show_bug.cgi?id=130118 - - Reviewed by Timothy Hatcher. - - * Configurations/FeatureDefines.xcconfig: - -2014-03-12 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Hang in Remote Inspection triggering breakpoint from console - https://bugs.webkit.org/show_bug.cgi?id=130032 - - Reviewed by Timothy Hatcher. - - * inspector/EventLoop.h: - * inspector/EventLoop.cpp: - (Inspector::EventLoop::remoteInspectorRunLoopMode): - (Inspector::EventLoop::cycle): - Expose the run loop mode name so it can be used if needed by others. - - * inspector/remote/RemoteInspectorDebuggableConnection.h: - * inspector/remote/RemoteInspectorDebuggableConnection.mm: - (Inspector::RemoteInspectorBlock::RemoteInspectorBlock): - (Inspector::RemoteInspectorBlock::~RemoteInspectorBlock): - (Inspector::RemoteInspectorBlock::operator=): - (Inspector::RemoteInspectorBlock::operator()): - (Inspector::RemoteInspectorQueueTask): - Instead of a dispatch_queue, have our own static Vector of debugger tasks. - - (Inspector::RemoteInspectorHandleRunSource): - (Inspector::RemoteInspectorInitializeQueue): - Initialize the static queue and run loop source. When the run loop source - fires, it will exhaust the queue of debugger messages. - - (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): - (Inspector::RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection): - When we get a debuggable connection add a run loop source for inspector commands. - - (Inspector::RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable): - (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): - Enqueue blocks on our Vector instead of our dispatch_queue. - -2014-03-12 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r165482. - https://bugs.webkit.org/show_bug.cgi?id=130157 - - Broke the windows build; "error C2466: cannot allocate an - array of constant size 0" (Requested by jernoble on #webkit). - - Reverted changeset: - - "Reduce memory use for static property maps" - https://bugs.webkit.org/show_bug.cgi?id=129986 - http://trac.webkit.org/changeset/165482 - -2014-03-12 Mark Hahnenberg <mhahnenberg@apple.com> - - Remove HandleSet::m_nextToFinalize - https://bugs.webkit.org/show_bug.cgi?id=130109 - - Reviewed by Mark Lam. - - This is a remnant of when HandleSet contained things that needed to be finalized. - - * heap/HandleSet.cpp: - (JSC::HandleSet::HandleSet): - (JSC::HandleSet::writeBarrier): - * heap/HandleSet.h: - (JSC::HandleSet::allocate): - (JSC::HandleSet::deallocate): - -2014-03-12 Mark Hahnenberg <mhahnenberg@apple.com> - - Layout Test fast/workers/worker-gc.html is failing - https://bugs.webkit.org/show_bug.cgi?id=130135 - - Reviewed by Geoffrey Garen. - - When removing MarkedBlocks, we always expect them to be in the MarkedAllocator's - main list of blocks, i.e. not in the retired list. When shutting down the VM this - wasn't always the case which was causing ASSERTs to fire. We should rearrange things - so that allocators are notified with lastChanceToFinalize. This will give them - the chance to move their retired blocks back into the main list before removing them all. - - * heap/MarkedAllocator.cpp: - (JSC::LastChanceToFinalize::operator()): - (JSC::MarkedAllocator::lastChanceToFinalize): - * heap/MarkedAllocator.h: - * heap/MarkedSpace.cpp: - (JSC::LastChanceToFinalize::operator()): - (JSC::MarkedSpace::lastChanceToFinalize): - -2014-03-12 Gavin Barraclough <barraclough@apple.com> - - Reduce memory use for static property maps - https://bugs.webkit.org/show_bug.cgi?id=129986 - - Reviewed by Andreas Kling. - - Static property tables are currently duplicated on first use from read-only memory into dirty memory - in every process, and since the entries are large (48 bytes) and the tables can be unusually sparse - (we use a custom hash table without a rehash) a lot of memory may be wasted. - - First, reduce the size of the hashtable. Instead of storing values in the table the hashtable maps - from string hashes to indicies into a densely packed array of values. Compute the index table at - compile time as a part of the derived sources step, such that this may be read-only data. - - Second, don't copy all data from the HashTableValue array into a HashEntry objects. Instead refer - directly to the HashTableValue entries. The only data that needs to be allocated at runtime are the - keys, which are Identifiers. - - * create_hash_table: - - emit the hash table index into the derived source (we were calculating this already to ensure chaining does not get too deep). - * parser/Lexer.cpp: - (JSC::Lexer<LChar>::parseIdentifier): - (JSC::Lexer<UChar>::parseIdentifier): - (JSC::Lexer<T>::parseIdentifierSlowCase): - - HashEntry -> HashTableValue. - * parser/Lexer.h: - (JSC::Keywords::getKeyword): - - HashEntry -> HashTableValue. - * runtime/ClassInfo.h: - - removed HashEntry. - * runtime/JSObject.cpp: - (JSC::getClassPropertyNames): - - use HashTable::ConstIterator. - (JSC::JSObject::put): - (JSC::JSObject::deleteProperty): - (JSC::JSObject::findPropertyHashEntry): - - HashEntry -> HashTableValue. - (JSC::JSObject::reifyStaticFunctionsForDelete): - - changed HashTable::ConstIterator interface. - * runtime/JSObject.h: - - HashEntry -> HashTableValue. - * runtime/Lookup.cpp: - (JSC::HashTable::createTable): - - table -> keys, keys array is now densely packed. - (JSC::HashTable::deleteTable): - - table -> keys. - (JSC::setUpStaticFunctionSlot): - - HashEntry -> HashTableValue. - * runtime/Lookup.h: - (JSC::HashTableValue::builtinGenerator): - (JSC::HashTableValue::function): - (JSC::HashTableValue::functionLength): - (JSC::HashTableValue::propertyGetter): - (JSC::HashTableValue::propertyPutter): - (JSC::HashTableValue::lexerValue): - - added accessor methods from HashEntry. - (JSC::HashTable::copy): - - fields changed. - (JSC::HashTable::initializeIfNeeded): - - table -> keys. - (JSC::HashTable::entry): - - HashEntry -> HashTableValue. - (JSC::HashTable::ConstIterator::ConstIterator): - - iterate packed value array, so no need to skipInvalidKeys(). - (JSC::HashTable::ConstIterator::value): - (JSC::HashTable::ConstIterator::key): - (JSC::HashTable::ConstIterator::operator->): - - accessors now get HashTableValue/StringImpl* separately. - (JSC::HashTable::ConstIterator::operator++): - - iterate packed value array, so no need to skipInvalidKeys(). - (JSC::HashTable::end): - - end is now size of dense not sparse array. - (JSC::getStaticPropertySlot): - (JSC::getStaticFunctionSlot): - (JSC::getStaticValueSlot): - (JSC::putEntry): - (JSC::lookupPut): - - HashEntry -> HashTableValue. - -2014-03-11 Filip Pizlo <fpizlo@apple.com> - - It should be possible to build WebKit with FTL on iOS - https://bugs.webkit.org/show_bug.cgi?id=130116 - - Reviewed by Dan Bernstein. - - * Configurations/Base.xcconfig: - -2014-03-10 Filip Pizlo <fpizlo@apple.com> - - GetById list caching should use something object-oriented rather than PolymorphicAccessStructureList - https://bugs.webkit.org/show_bug.cgi?id=129778 - - Reviewed by Geoffrey Garen. - - Also deduplicate the GetById getter call caching. Also add some small tests for - get stubs. - - This change reduces the amount of code involved in GetById access caching and it - creates data structures that can serve as an elegant scaffold for introducing other - kinds of caches or improving current caching styles. It will definitely make getter - performance improvements easier to implement. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::printGetByIdCacheStatus): - * bytecode/GetByIdStatus.cpp: - (JSC::GetByIdStatus::computeForStubInfo): - * bytecode/PolymorphicGetByIdList.cpp: Added. - (JSC::GetByIdAccess::GetByIdAccess): - (JSC::GetByIdAccess::~GetByIdAccess): - (JSC::GetByIdAccess::fromStructureStubInfo): - (JSC::GetByIdAccess::visitWeak): - (JSC::PolymorphicGetByIdList::PolymorphicGetByIdList): - (JSC::PolymorphicGetByIdList::from): - (JSC::PolymorphicGetByIdList::~PolymorphicGetByIdList): - (JSC::PolymorphicGetByIdList::currentSlowPathTarget): - (JSC::PolymorphicGetByIdList::addAccess): - (JSC::PolymorphicGetByIdList::isFull): - (JSC::PolymorphicGetByIdList::isAlmostFull): - (JSC::PolymorphicGetByIdList::didSelfPatching): - (JSC::PolymorphicGetByIdList::visitWeak): - * bytecode/PolymorphicGetByIdList.h: Added. - (JSC::GetByIdAccess::GetByIdAccess): - (JSC::GetByIdAccess::isSet): - (JSC::GetByIdAccess::operator!): - (JSC::GetByIdAccess::type): - (JSC::GetByIdAccess::structure): - (JSC::GetByIdAccess::chain): - (JSC::GetByIdAccess::chainCount): - (JSC::GetByIdAccess::stubRoutine): - (JSC::GetByIdAccess::doesCalls): - (JSC::PolymorphicGetByIdList::isEmpty): - (JSC::PolymorphicGetByIdList::size): - (JSC::PolymorphicGetByIdList::at): - (JSC::PolymorphicGetByIdList::operator[]): - * bytecode/StructureStubInfo.cpp: - (JSC::StructureStubInfo::deref): - (JSC::StructureStubInfo::visitWeakReferences): - * bytecode/StructureStubInfo.h: - (JSC::isGetByIdAccess): - (JSC::StructureStubInfo::initGetByIdList): - * jit/Repatch.cpp: - (JSC::generateGetByIdStub): - (JSC::tryCacheGetByID): - (JSC::patchJumpToGetByIdStub): - (JSC::tryBuildGetByIDList): - (JSC::tryBuildPutByIdList): - * tests/stress/getter.js: Added. - (foo): - (.o): - * tests/stress/polymorphic-prototype-accesses.js: Added. - (Foo): - (Bar): - (foo): - * tests/stress/prototype-getter.js: Added. - (Foo): - (foo): - * tests/stress/simple-prototype-accesses.js: Added. - (Foo): - (foo): - -2014-03-11 Mark Hahnenberg <mhahnenberg@apple.com> - - MarkedBlocks that are "full enough" shouldn't be swept after EdenCollections - https://bugs.webkit.org/show_bug.cgi?id=129920 - - Reviewed by Geoffrey Garen. - - This patch introduces the notion of "retiring" MarkedBlocks. We retire a MarkedBlock - when the amount of free space in a MarkedBlock drops below a certain threshold. - Retired blocks are not considered for sweeping. - - This is profitable because it reduces churn during sweeping. To build a free list, - we have to scan through each cell in a block. After a collection, all objects that - are live in the block will remain live until the next FullCollection, at which time - we un-retire all previously retired blocks. Thus, a small number of objects in a block - that die during each EdenCollection could cause us to do a disproportiante amount of - sweeping for how much free memory we get back. - - This patch looks like a consistent ~2% progression on boyer and is neutral everywhere else. - - * heap/Heap.h: - (JSC::Heap::didRetireBlockWithFreeListSize): - * heap/MarkedAllocator.cpp: - (JSC::MarkedAllocator::tryAllocateHelper): - (JSC::MarkedAllocator::removeBlock): - (JSC::MarkedAllocator::reset): - * heap/MarkedAllocator.h: - (JSC::MarkedAllocator::MarkedAllocator): - (JSC::MarkedAllocator::forEachBlock): - * heap/MarkedBlock.cpp: - (JSC::MarkedBlock::sweepHelper): - (JSC::MarkedBlock::clearMarksWithCollectionType): - (JSC::MarkedBlock::didRetireBlock): - * heap/MarkedBlock.h: - (JSC::MarkedBlock::willRemoveBlock): - (JSC::MarkedBlock::isLive): - * heap/MarkedSpace.cpp: - (JSC::MarkedSpace::clearNewlyAllocated): - (JSC::MarkedSpace::clearMarks): - * runtime/Options.h: - -2014-03-11 Andreas Kling <akling@apple.com> - - Streamline PropertyTable for lookup-only access. - <https://webkit.org/b/130060> - - The PropertyTable lookup algorithm was written to support both read - and write access. This wasn't actually needed in most places. - - This change adds a PropertyTable::get() that just returns the value - type (instead of an insertion iterator.) It also adds an early return - for empty tables. - - Finally, up the minimum table capacity from 8 to 16. It was lowered - to 8 in order to save memory, but that was before PropertyTables were - GC allocated. Nowadays we don't have nearly as many tables, since all - the unpinned transitions die off. - - Reviewed by Darin Adler. - - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::get): - * runtime/Structure.cpp: - (JSC::Structure::despecifyDictionaryFunction): - (JSC::Structure::attributeChangeTransition): - (JSC::Structure::get): - (JSC::Structure::despecifyFunction): - * runtime/StructureInlines.h: - (JSC::Structure::get): - -2014-03-10 Mark Hahnenberg <mhahnenberg@apple.com> - - REGRESSION(r165407): DoYouEvenBench crashes in DRT - https://bugs.webkit.org/show_bug.cgi?id=130066 - - Reviewed by Geoffrey Garen. - - The baseline JIT does a conditional store barrier for the put_by_id, but we need - an unconditional store barrier so that we cover the butterfly case as well in emitPutTransitionStub. - - * jit/JIT.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emit_op_put_by_id): - (JSC::JIT::emitWriteBarrier): - -2014-03-10 Mark Lam <mark.lam@apple.com> - - Resurrect bit-rotted JIT::probe() mechanism. - <https://webkit.org/b/130067> - - Reviewed by Geoffrey Garen. - - * jit/JITStubs.cpp: - - Added the needed #include <wtf/InlineASM.h>. - -2014-03-10 Joseph Pecoraro <pecoraro@apple.com> - - Fix typo in EXCLUDED_SOURCE_FILE_NAMES_iphoneos. - - Rubber-stamped by Dan Bernstein. - - * Configurations/JavaScriptCore.xcconfig: - -2014-03-10 Mark Lam <mark.lam@apple.com> - - r165414 broke the 32-bit x86 tests: ASSERTION FAILED: result != InvalidIndex @ GPRInfo.h:330. - <https://webkit.org/b/130065> - - Reviewed by Michael Saboff. - - There is code in ScratchRegisterAllocator.cpp that is relying on GPRInfo::toIndex() - being able to return InvalidIndex. Hence, the assertion is invalid. Ditto for - FPRInfo::toIndex(). - - The fix is to remove the "result != InvalidIndex" assertions. - - * jit/FPRInfo.h: - (JSC::FPRInfo::toIndex): - * jit/GPRInfo.h: - (JSC::GPRInfo::toIndex): - -2014-03-10 Mark Lam <mark.lam@apple.com> - - Crash on a stack overflow on 32-bit x86 in http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html. - <https://webkit.org/b/129955> - - Reviewed by Geoffrey Garen. - - The 32-bit x86 version of getHostCallReturnValue() was leaking 16 bytes - stack memory every time it was called. This is now fixed. - - * jit/JITOperations.cpp: - -2014-03-10 Joseph Pecoraro <pecoraro@apple.com> - - Better JSContext API for named evaluations (other than //# sourceURL) - https://bugs.webkit.org/show_bug.cgi?id=129911 - - Reviewed by Geoffrey Garen. - - * API/JSBase.h: - * API/JSContext.h: - * API/JSContext.mm: - (-[JSContext evaluateScript:]): - (-[JSContext evaluateScript:withSourceURL:]): - Add new evaluateScript:withSourceURL:. - - * API/tests/testapi.c: - (main): - * API/tests/testapi.mm: - (testObjectiveCAPI): - Add tests for sourceURL in evaluate APIs. It should - affect the exception objects. - -2014-03-10 Filip Pizlo <fpizlo@apple.com> - - Repatch should save and restore all used registers - not just temp ones - when making a call - https://bugs.webkit.org/show_bug.cgi?id=130041 - - Reviewed by Geoffrey Garen and Mark Hahnenberg. - - The save/restore code was written back when the only client was the DFG, which only uses a - subset of hardware registers: the "temp" registers in our lingo. But the FTL may use many - other registers, especially on ARM64. The fact that Repatch doesn't know to save those can - lead to data corruption on ARM64. - - * jit/RegisterSet.cpp: - (JSC::RegisterSet::calleeSaveRegisters): - (JSC::RegisterSet::numberOfSetGPRs): - (JSC::RegisterSet::numberOfSetFPRs): - * jit/RegisterSet.h: - * jit/Repatch.cpp: - (JSC::storeToWriteBarrierBuffer): - (JSC::emitPutTransitionStub): - * jit/ScratchRegisterAllocator.cpp: - (JSC::ScratchRegisterAllocator::ScratchRegisterAllocator): - (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing): - (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping): - (JSC::ScratchRegisterAllocator::usedRegistersForCall): - (JSC::ScratchRegisterAllocator::desiredScratchBufferSizeForCall): - (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall): - (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall): - * jit/ScratchRegisterAllocator.h: - -2014-03-10 Mark Hahnenberg <mhahnenberg@apple.com> - - Remove ConditionalStore barrier - https://bugs.webkit.org/show_bug.cgi?id=130040 - - Reviewed by Geoffrey Garen. - - ConditionalStoreBarrier was created when barriers were much more expensive. Now that - they're cheap(er), we can get rid of them. This also allows us to get rid of the write - barrier logic in emitPutTransitionStub because we always will have executed a write barrier - on the base object in the case where we are allocating and storing a new Butterfly into it. - Previously, a ConditionalStoreBarrier might or might not have barrier-ed the base object, - so we'd have to emit a write barrier in the transition case. - - This is performance neutral on the benchmarks we track. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::insertStoreBarrier): - * dfg/DFGNode.h: - (JSC::DFG::Node::isStoreBarrier): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileStoreBarrier): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - * jit/Repatch.cpp: - (JSC::emitPutTransitionStub): - -2014-03-10 Filip Pizlo <fpizlo@apple.com> - - DFG and FTL should know that comparing anything to Misc is cheap and easy - https://bugs.webkit.org/show_bug.cgi?id=130001 - - Reviewed by Geoffrey Garen. - - - Expand CompareStrictEq(Misc:, Misc:) to work for cases where either side of the - comparison is just Untyped:. - - - This obviates the need for CompareStrictEqConstant, so remove it. - - - FTL had a thing called "Nully" which is really "Other". Rename it and add - OtherUse. - - 9% speed-up on box2d. - - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNode.h: - (JSC::DFG::Node::isBinaryUseKind): - (JSC::DFG::Node::shouldSpeculateOther): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch): - (JSC::DFG::SpeculativeJIT::compare): - (JSC::DFG::SpeculativeJIT::compileStrictEq): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): - (JSC::DFG::SpeculativeJIT::compile): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileCompareEq): - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): - (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): - (JSC::FTL::LowerDFGToLLVM::isNotOther): - (JSC::FTL::LowerDFGToLLVM::isOther): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): - (JSC::FTL::LowerDFGToLLVM::speculateNotCell): - (JSC::FTL::LowerDFGToLLVM::speculateOther): - (JSC::FTL::LowerDFGToLLVM::speculateMisc): - * tests/stress/compare-strict-eq-integer-to-misc.js: Added. - -2014-03-10 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, remove unintended change. - - * dfg/DFGDriver.cpp: - (JSC::DFG::compileImpl): - -2014-03-10 Filip Pizlo <fpizlo@apple.com> - - jsc commandline shouldn't have a "console" because that confuses some tests into thinking - that they're running in the browser. - - Rubber stamped by Mark Hahnenberg. - - * jsc.cpp: - (GlobalObject::finishCreation): - -2014-03-10 Filip Pizlo <fpizlo@apple.com> - - Out-line ScratchRegisterAllocator - - Rubber stamped by Mark Hahnenberg. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGDriver.cpp: - (JSC::DFG::compileImpl): - * jit/ScratchRegisterAllocator.cpp: Added. - (JSC::ScratchRegisterAllocator::ScratchRegisterAllocator): - (JSC::ScratchRegisterAllocator::~ScratchRegisterAllocator): - (JSC::ScratchRegisterAllocator::lock): - (JSC::ScratchRegisterAllocator::allocateScratch): - (JSC::ScratchRegisterAllocator::allocateScratchGPR): - (JSC::ScratchRegisterAllocator::allocateScratchFPR): - (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing): - (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping): - (JSC::ScratchRegisterAllocator::desiredScratchBufferSize): - (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBuffer): - (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBuffer): - * jit/ScratchRegisterAllocator.h: - -2014-03-10 Brent Fulgham <bfulgham@apple.com> - - [Win] Pass environment to Pre-Build, Pre-link, and Post-Build Stages. - https://bugs.webkit.org/show_bug.cgi?id=130023 - - Reviewed by Dean Jackson. - - * JavaScriptCore.vcxproj/JavaScriptCore.proj: Avoid trailing backslashes in - path names to avoid accidental escaping of later string substitutions. - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for testb_i8r when register is accumulator. - <https://webkit.org/b/130026> - - Generate the shorthand version of "test al, imm" when possible. - - Reviewed by Michael Saboff. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::testb_i8r): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for sub_ir when register is accumulator. - <https://webkit.org/b/130025> - - Generate the shorthand version of "sub eax, imm" when possible. - - Reviewed by Michael Saboff. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::subl_ir): - (JSC::X86Assembler::subq_ir): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for add_ir when register is accumulator. - <https://webkit.org/b/130024> - - Generate the shorthand version of "add eax, imm" when possible. - - Reviewed by Michael Saboff. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::addl_ir): - (JSC::X86Assembler::addq_ir): - -2014-03-10 Mark Hahnenberg <mhahnenberg@apple.com> - - writeBarrier in emitPutReplaceStub is unnecessary - https://bugs.webkit.org/show_bug.cgi?id=130030 - - Reviewed by Filip Pizlo. - - We already emit write barriers for each put-by-id when they're first compiled, so it's - redundant to emit a write barrier as part of the repatched code. - - * jit/Repatch.cpp: - (JSC::emitPutReplaceStub): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for xor_ir when register is accumulator. - <https://webkit.org/b/130008> - - Generate the shorthand version of "xor eax, imm" when possible. - - Reviewed by Benjamin Poulain. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::xorl_ir): - (JSC::X86Assembler::xorq_ir): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for or_ir when register is accumulator. - <https://webkit.org/b/130007> - - Generate the shorthand version of "or eax, imm" when possible. - - Reviewed by Benjamin Poulain. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::orl_ir): - (JSC::X86Assembler::orq_ir): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for test_ir when register is accumulator. - <https://webkit.org/b/130006> - - Generate the shorthand version of "test eax, imm" when possible. - - Reviewed by Benjamin Poulain. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::testl_i32r): - (JSC::X86Assembler::testq_i32r): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for cmp_ir when register is accumulator. - <https://webkit.org/b/130005> - - Generate the shorthand version of "cmp eax, imm" when possible. - - Reviewed by Benjamin Poulain. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::cmpl_ir): - (JSC::X86Assembler::cmpq_ir): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for store64(imm, address) when imm fits in 32 bits. - <https://webkit.org/b/130002> - - Generate this: - - mov [address], imm32 - - Instead of this: - - mov scratchRegister, imm32 - mov [address], scratchRegister - - For store64(imm, address) where the 64-bit immediate can be passed as - a sign-extended 32-bit value. - - Reviewed by Benjamin Poulain. - - * assembler/MacroAssemblerX86_64.h: - (CAN_SIGN_EXTEND_32_64): - (JSC::MacroAssemblerX86_64::store64): - -2014-03-10 Andreas Kling <akling@apple.com> - - [X86_64] Smaller code for xchg_rr when one register is accumulator. - <https://webkit.org/b/130004> - - Generate the 1-byte version of "xchg eax, reg" when possible. - - Reviewed by Benjamin Poulain. - - * assembler/X86Assembler.h: - (JSC::X86Assembler::xchgl_rr): - (JSC::X86Assembler::xchgq_rr): - -2014-03-09 Filip Pizlo <fpizlo@apple.com> - - GPRInfo::toIndex should return InvalidIndex for non-temp registers on ARM64 - https://bugs.webkit.org/show_bug.cgi?id=129998 - - Reviewed by Geoffrey Garen. - - Not only is that the established contract, but this is used to signal to - ScratchRegisterAllocator that the register doesn't need locking since it isn't a register - that this allocator would use. In the FTL, we may have an inline cache where LLVM had used - some non-temp register (i.e. a register that JSC itself wouldn't have used). This is totally - fine but previously it would have led to either an assertion failure, or data corruption, in - the ScratchRegisterAllocator. - - * jit/GPRInfo.h: - (JSC::GPRInfo::toIndex): - -2014-03-09 Filip Pizlo <fpizlo@apple.com> - - FTL fails the new equals-masquerader strictEqualConstant test - https://bugs.webkit.org/show_bug.cgi?id=129996 - - Reviewed by Mark Lam. - - It turns out that the FTL was trying to do the masquerading stuff for ===null. But - that's wrong since none of the other engines do it. The DFG even had an ancient - FIXME about doing it - but that doesn't make sense since the LLInt and baseline JIT - don't do it and JSValue::strictEqual() doesn't do it. - - Remove the FIXME and remove the extra checks in the FTL. - - This is a glorious patch: nothing but red and it fixes a test failure. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileStrictEqForConstant): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEqConstant): - -2014-03-09 Andreas Kling <akling@apple.com> - - Short-circuit JSGlobalObjectInspectorController when not inspecting. - <https://webkit.org/b/129995> - - Add an early return in reportAPIException() when the console agent - is disabled. This avoids expensive symbolication during exceptions - if there's nobody expecting the fancy backtrace anyway. - - ~2% progression on DYEB on my MBP. - - Reviewed by Geoff Garen. - - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - -2014-03-09 Andreas Kling <akling@apple.com> - - Inline the trivial parts of GC deferral. - <https://webkit.org/b/129984> - - Made most of the functions called by the DeferGC RAII object inline - to avoid function call overhead. - - Looks like ~1% progression on DYEB. - - Reviewed by Geoffrey Garen. - - * heap/Heap.cpp: - * heap/Heap.h: - (JSC::Heap::incrementDeferralDepth): - (JSC::Heap::decrementDeferralDepth): - (JSC::Heap::collectIfNecessaryOrDefer): - (JSC::Heap::decrementDeferralDepthAndGCIfNeeded): - -2014-03-08 Mark Lam <mark.lam@apple.com> - - 32-bit x86 handleUncaughtException returns to wrong location after a stack overflow. - <https://webkit.org/b/129969> - - Reviewed by Geoffrey Garen. - - The 32-bit version of handleUncaughtException was missing the handling of an - edge case for stack overflows where the current frame may already be the - sentinel frame. This edge case was handled in the 64-bit version. The fix - is to bring the 32-bit version up to parity. - - * jit/JIT.cpp: - (JSC::JIT::privateCompile): - * llint/LowLevelInterpreter32_64.asm: - -2014-03-07 Mark Lam <mark.lam@apple.com> - - Fix bugs in 32-bit Structure implementation. - <https://webkit.org/b/129947> - - Reviewed by Mark Hahnenberg. - - Added the loading of the Structure (from the JSCell) before use that was - missing in a few places. Also added more test cases to equals-masquerader.js. - - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * llint/LowLevelInterpreter32_64.asm: - * tests/stress/equals-masquerader.js: - (equalsNull): - (notEqualsNull): - (strictEqualsNull): - (strictNotEqualsNull): - (equalsUndefined): - (notEqualsUndefined): - (strictEqualsUndefined): - (strictNotEqualsUndefined): - (isFalsey): - (test): - -2014-03-07 Andrew Trick <atrick@apple.com> - - Temporarily disable repeat-out-of-bounds stress tests pending fix for 129953. - https://bugs.webkit.org/show_bug.cgi?id=129954 - - Reviewed by Filip Pizlo. - - * tests/stress/float32-repeat-out-of-bounds.js: - * tests/stress/int8-repeat-out-of-bounds.js: - -2014-03-07 Michael Saboff <msaboff@apple.com> - - .cfi directives in LowLevelInterpreter.cpp are providing no benefit - https://bugs.webkit.org/show_bug.cgi?id=129945 - - Reviewed by Mark Lam. - - Removed .cfi directive. Verified that stack traces didn't regress in crash reporter - or in lldb. - - * llint/LowLevelInterpreter.cpp: - -2014-03-07 Oliver Hunt <oliver@apple.com> - - Continue hangs when performing for-of over arguments - https://bugs.webkit.org/show_bug.cgi?id=129915 - - Reviewed by Geoffrey Garen. - - Put the continue label in the right place - - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::emitEnumeration): - -2014-03-07 peavo@outlook.com <peavo@outlook.com> - - [Win64] Compile error after r165128. - https://bugs.webkit.org/show_bug.cgi?id=129807 - - Reviewed by Mark Lam. - - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: - Check platform environment variable to determine if an assembler file should be generated. - -2014-03-07 Michael Saboff <msaboff@apple.com> - - Clarify how we deal with "special" registers - https://bugs.webkit.org/show_bug.cgi?id=129806 - - Already reviewed change being relanded. - - Relanding change set r165196 as it wasn't responsible for the breakage reported in - https://bugs.webkit.org/show_bug.cgi?id=129822. That appears to be a build or - - Reviewed by Michael Saboff. - configuration issue. - - * assembler/ARM64Assembler.h: - (JSC::ARM64Assembler::lastRegister): - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::nextRegister): - * ftl/FTLLocation.cpp: - (JSC::FTL::Location::restoreInto): - * ftl/FTLSaveRestore.cpp: - (JSC::FTL::saveAllRegisters): - (JSC::FTL::restoreAllRegisters): - * ftl/FTLSlowPathCall.cpp: - * jit/RegisterSet.cpp: - (JSC::RegisterSet::reservedHardwareRegisters): - (JSC::RegisterSet::runtimeRegisters): - (JSC::RegisterSet::specialRegisters): - (JSC::RegisterSet::calleeSaveRegisters): - * jit/RegisterSet.h: - -2014-03-07 Mark Hahnenberg <mhahnenberg@apple.com> - - Move GCActivityCallback to heap - https://bugs.webkit.org/show_bug.cgi?id=129457 - - Reviewed by Geoffrey Garen. - - All the other GC timer related stuff is there already. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * heap/GCActivityCallback.cpp: Copied from Source/JavaScriptCore/runtime/GCActivityCallback.cpp. - * heap/GCActivityCallback.h: Copied from Source/JavaScriptCore/runtime/GCActivityCallback.h. - * runtime/GCActivityCallback.cpp: Removed. - * runtime/GCActivityCallback.h: Removed. - -2014-03-07 Andrew Trick <atrick@apple.com> - - Correct a comment typo from: - FLT should call fmod directly on platforms where LLVM cannot relocate the libcall - https://bugs.webkit.org/show_bug.cgi?id=129865 - - Reviewed by Mark Lam. - - * ftl/FTLOutput.h: - (JSC::FTL::Output::doubleRem): - -2014-03-07 Mark Hahnenberg <mhahnenberg@apple.com> - - Use OwnPtr in StructureIDTable - https://bugs.webkit.org/show_bug.cgi?id=129828 - - Reviewed by Geoffrey Garen. - - This reduces the amount of boilerplate and fixes a memory leak. - - * runtime/StructureIDTable.cpp: - (JSC::StructureIDTable::StructureIDTable): - (JSC::StructureIDTable::resize): - (JSC::StructureIDTable::flushOldTables): - (JSC::StructureIDTable::allocateID): - (JSC::StructureIDTable::deallocateID): - * runtime/StructureIDTable.h: - (JSC::StructureIDTable::table): - (JSC::StructureIDTable::get): - -2014-03-07 Andrew Trick <atrick@apple.com> - - FLT should call fmod directly on platforms where LLVM cannot relocate the libcall - https://bugs.webkit.org/show_bug.cgi?id=129865 - - Reviewed by Filip Pizlo. - - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLOutput.h: - (JSC::FTL::Output::doubleRem): - -2014-03-06 Filip Pizlo <fpizlo@apple.com> - - If the FTL is build-time enabled then it should be run-time enabled. - - Rubber stamped by Geoffrey Garen. - - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): - * runtime/Options.h: - -2014-03-06 Joseph Pecoraro <pecoraro@apple.com> - - [OS X] Web Inspector: Allow Apps using JavaScriptCore to access "com.apple.webinspector" mach port - https://bugs.webkit.org/show_bug.cgi?id=129852 - - Reviewed by Geoffrey Garen. - - * framework.sb: Added. - Sandbox extension to allow access to "com.apple.webinspector". - - * JavaScriptCore.xcodeproj/project.pbxproj: - Add a Copy Resources build phase and include framework.sb. - - * Configurations/JavaScriptCore.xcconfig: - Do not copy framework.sb on iOS. - -2014-03-06 Mark Hahnenberg <mhahnenberg@apple.com> - - JSGlobalContextRelease incorrectly handles saving/restoring IdentifierTable - https://bugs.webkit.org/show_bug.cgi?id=129858 - - Reviewed by Mark Lam. - - It was correct (but really ugly) prior to the combining of APIEntryShim and JSLock, - but now it ends up overwriting the IdentifierTable that JSLock just restored. - - * API/JSContextRef.cpp: - (JSGlobalContextRelease): - -2014-03-06 Oliver Hunt <oliver@apple.com> - - Fix FTL build. - - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - -2014-03-06 Brent Fulgham <bfulgham@apple.com> - - Unreviewed build fix after r165128. - - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: The SEH flag was not getting set when - performing 'Production' and 'DebugSuffix' type builds. - -2014-03-06 Julien Brianceau <jbriance@cisco.com> - - Unreviewed, fix style in my previous commit. - https://bugs.webkit.org/show_bug.cgi?id=129833 - - * runtime/JSConsole.cpp: - -2014-03-06 Julien Brianceau <jbriance@cisco.com> - - Build fix: add missing include in JSConole.cpp. - https://bugs.webkit.org/show_bug.cgi?id=129833 - - Reviewed by Oliver Hunt. - - * runtime/JSConsole.cpp: - -2014-03-06 Oliver Hunt <oliver@apple.com> - - Fix ARMv7 - - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): - -2014-03-06 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r165196. - http://trac.webkit.org/changeset/165196 - https://bugs.webkit.org/show_bug.cgi?id=129822 - - broke arm64 on hardware (Requested by bfulgham on #webkit). - - * assembler/ARM64Assembler.h: - (JSC::ARM64Assembler::lastRegister): - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::isStackRelated): - (JSC::MacroAssembler::firstRealRegister): - (JSC::MacroAssembler::nextRegister): - (JSC::MacroAssembler::secondRealRegister): - * ftl/FTLLocation.cpp: - (JSC::FTL::Location::restoreInto): - * ftl/FTLSaveRestore.cpp: - (JSC::FTL::saveAllRegisters): - (JSC::FTL::restoreAllRegisters): - * ftl/FTLSlowPathCall.cpp: - * jit/RegisterSet.cpp: - (JSC::RegisterSet::specialRegisters): - (JSC::RegisterSet::calleeSaveRegisters): - * jit/RegisterSet.h: - -2014-03-06 Mark Lam <mark.lam@apple.com> - - REGRESSION(r165205): broke the CLOOP build (Requested by smfr on #webkit). - <https://webkit.org/b/129813> - - Reviewed by Michael Saboff. - - Fixed broken C loop LLINT build. - - * llint/LowLevelInterpreter.cpp: - (JSC::CLoop::execute): - * offlineasm/cloop.rb: - -2014-03-03 Oliver Hunt <oliver@apple.com> - - Support caching of custom setters - https://bugs.webkit.org/show_bug.cgi?id=129519 - - Reviewed by Filip Pizlo. - - This patch adds caching of assignment to properties that - are backed by C functions. This provides most of the leg - work required to start supporting setters, and resolves - the remaining regressions from moving DOM properties up - the prototype chain. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/PolymorphicPutByIdList.cpp: - (JSC::PutByIdAccess::visitWeak): - (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): - (JSC::PolymorphicPutByIdList::from): - * bytecode/PolymorphicPutByIdList.h: - (JSC::PutByIdAccess::transition): - (JSC::PutByIdAccess::replace): - (JSC::PutByIdAccess::customSetter): - (JSC::PutByIdAccess::isCustom): - (JSC::PutByIdAccess::oldStructure): - (JSC::PutByIdAccess::chain): - (JSC::PutByIdAccess::stubRoutine): - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeForStubInfo): - (JSC::PutByIdStatus::computeFor): - (JSC::PutByIdStatus::dump): - * bytecode/PutByIdStatus.h: - (JSC::PutByIdStatus::PutByIdStatus): - (JSC::PutByIdStatus::takesSlowPath): - (JSC::PutByIdStatus::makesCalls): - * bytecode/StructureStubInfo.h: - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::emitPutById): - (JSC::DFG::ByteCodeParser::handlePutById): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGCommon.h: - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNode.h: - (JSC::DFG::Node::hasIdentifier): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileIn): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - (JSC::DFG::SpeculativeJIT::compile): - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): - * jit/JITInlineCacheGenerator.cpp: - (JSC::JITByIdGenerator::JITByIdGenerator): - (JSC::JITPutByIdGenerator::JITPutByIdGenerator): - * jit/JITInlineCacheGenerator.h: - (JSC::JITGetByIdGenerator::JITGetByIdGenerator): - * jit/JITOperations.cpp: - * jit/JITOperations.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_put_by_id): - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_put_by_id): - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - (JSC::tryBuildGetByIDList): - (JSC::emitCustomSetterStub): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - * jit/SpillRegistersMode.h: Added. - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * runtime/Lookup.h: - (JSC::putEntry): - * runtime/PutPropertySlot.h: - (JSC::PutPropertySlot::setCacheableCustomProperty): - (JSC::PutPropertySlot::customSetter): - (JSC::PutPropertySlot::isCacheablePut): - (JSC::PutPropertySlot::isCacheableCustomProperty): - (JSC::PutPropertySlot::cachedOffset): - -2014-03-06 Filip Pizlo <fpizlo@apple.com> - - FTL arity fixup should work on ARM64 - https://bugs.webkit.org/show_bug.cgi?id=129810 - - Reviewed by Michael Saboff. - - - Using regT5 to pass the thunk return address to arityFixup is shady since that's a - callee-save. - - - The FTL path was assuming X86 conventions for where SP points at the top of the prologue. - - This makes some more tests pass. - - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::compileFunction): - * ftl/FTLLink.cpp: - (JSC::FTL::link): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::prologueStackPointerDelta): - * jit/JIT.cpp: - (JSC::JIT::privateCompile): - * jit/ThunkGenerators.cpp: - (JSC::arityFixup): - * llint/LowLevelInterpreter64.asm: - * offlineasm/arm64.rb: - * offlineasm/x86.rb: In addition to the t7 change, make t6 agree with GPRInfo.h. - -2014-03-06 Mark Hahnenberg <mhahnenberg@apple.com> - - Fix write barriers in Repatch.cpp for !ENABLE(DFG_JIT) platforms after r165128 - https://bugs.webkit.org/show_bug.cgi?id=129760 - - Reviewed by Geoffrey Garen. - - r165128 disabled the write barrier fast path for inline caches on !ENABLE(DFG_JIT) platforms. - The fix is to refactor the write barrier code into AssemblyHelpers and use that everywhere. - - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::writeBarrier): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::checkMarkByte): - * jit/JIT.h: - * jit/JITPropertyAccess.cpp: - * jit/Repatch.cpp: - (JSC::writeBarrier): - -2014-03-06 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Expose the console object in JSContexts to interact with Web Inspector - https://bugs.webkit.org/show_bug.cgi?id=127944 - - Reviewed by Geoffrey Garen. - - Always expose the Console object in JSContexts, just like we - do for web pages. The default behavior will route to an - attached JSContext inspector. This can be overriden by - setting the ConsoleClient on the JSGlobalObject, which WebCore - does to get slightly different behavior. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - Update build systems. - - * API/tests/testapi.js: - * API/tests/testapi.mm: - Test that "console" exists in C and ObjC contexts. - - * runtime/ConsoleClient.cpp: Added. - (JSC::ConsoleClient::printURLAndPosition): - (JSC::ConsoleClient::printMessagePrefix): - (JSC::ConsoleClient::printConsoleMessage): - (JSC::ConsoleClient::printConsoleMessageWithArguments): - (JSC::ConsoleClient::internalMessageWithTypeAndLevel): - (JSC::ConsoleClient::logWithLevel): - (JSC::ConsoleClient::clear): - (JSC::ConsoleClient::dir): - (JSC::ConsoleClient::dirXML): - (JSC::ConsoleClient::table): - (JSC::ConsoleClient::trace): - (JSC::ConsoleClient::assertCondition): - (JSC::ConsoleClient::group): - (JSC::ConsoleClient::groupCollapsed): - (JSC::ConsoleClient::groupEnd): - * runtime/ConsoleClient.h: Added. - (JSC::ConsoleClient::~ConsoleClient): - New private interface for handling the console object's methods. - A lot of the methods funnel through messageWithTypeAndLevel. - - * runtime/ConsoleTypes.h: Renamed from Source/JavaScriptCore/inspector/ConsoleTypes.h. - Moved to JSC namespace. - - * runtime/JSGlobalObject.cpp: - (JSC::JSGlobalObject::JSGlobalObject): - (JSC::JSGlobalObject::init): - (JSC::JSGlobalObject::reset): - (JSC::JSGlobalObject::visitChildren): - Create the "console" object when initializing the environment. - Also set the default console client to be the JS context inspector. - - * runtime/JSGlobalObject.h: - (JSC::JSGlobalObject::setConsoleClient): - (JSC::JSGlobalObject::consoleClient): - Ability to change the console client, so WebCore can set a custom client. - - * runtime/ConsolePrototype.cpp: Added. - (JSC::ConsolePrototype::finishCreation): - (JSC::valueToStringWithUndefinedOrNullCheck): - (JSC::consoleLogWithLevel): - (JSC::consoleProtoFuncDebug): - (JSC::consoleProtoFuncError): - (JSC::consoleProtoFuncLog): - (JSC::consoleProtoFuncWarn): - (JSC::consoleProtoFuncClear): - (JSC::consoleProtoFuncDir): - (JSC::consoleProtoFuncDirXML): - (JSC::consoleProtoFuncTable): - (JSC::consoleProtoFuncTrace): - (JSC::consoleProtoFuncAssert): - (JSC::consoleProtoFuncCount): - (JSC::consoleProtoFuncProfile): - (JSC::consoleProtoFuncProfileEnd): - (JSC::consoleProtoFuncTime): - (JSC::consoleProtoFuncTimeEnd): - (JSC::consoleProtoFuncTimeStamp): - (JSC::consoleProtoFuncGroup): - (JSC::consoleProtoFuncGroupCollapsed): - (JSC::consoleProtoFuncGroupEnd): - * runtime/ConsolePrototype.h: Added. - (JSC::ConsolePrototype::create): - (JSC::ConsolePrototype::createStructure): - (JSC::ConsolePrototype::ConsolePrototype): - Define the console object interface. Parse out required / expected - arguments and throw expcetions when methods are misused. - - * runtime/JSConsole.cpp: Added. - * runtime/JSConsole.h: Added. - (JSC::JSConsole::createStructure): - (JSC::JSConsole::create): - (JSC::JSConsole::JSConsole): - Empty "console" object. Everything is in the prototype. - - * inspector/JSConsoleClient.cpp: Added. - (Inspector::JSConsoleClient::JSGlobalObjectConsole): - (Inspector::JSConsoleClient::count): - (Inspector::JSConsoleClient::profile): - (Inspector::JSConsoleClient::profileEnd): - (Inspector::JSConsoleClient::time): - (Inspector::JSConsoleClient::timeEnd): - (Inspector::JSConsoleClient::timeStamp): - (Inspector::JSConsoleClient::warnUnimplemented): - (Inspector::JSConsoleClient::internalAddMessage): - * inspector/JSConsoleClient.h: Added. - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - (Inspector::JSGlobalObjectInspectorController::consoleClient): - * inspector/JSGlobalObjectInspectorController.h: - Default JSContext ConsoleClient implementation. Handle nearly - everything exception profile/profileEnd and timeStamp. - -2014-03-06 Andreas Kling <akling@apple.com> - - Drop unlinked function code on memory pressure. - <https://webkit.org/b/129789> - - Make VM::discardAllCode() also drop UnlinkedFunctionCodeBlocks that - are not currently being compiled. - - 4.5 MB progression on Membuster. - - Reviewed by Geoffrey Garen. - - * heap/Heap.cpp: - (JSC::Heap::deleteAllUnlinkedFunctionCode): - * heap/Heap.h: - * runtime/VM.cpp: - (JSC::VM::discardAllCode): - -2014-03-06 Filip Pizlo <fpizlo@apple.com> - - Clarify how we deal with "special" registers - https://bugs.webkit.org/show_bug.cgi?id=129806 - - Reviewed by Michael Saboff. - - Previously we had two different places that defined what "stack" registers are, a thing - called "specialRegisters" that had unclear meaning, and a really weird "firstRealRegister"/ - "secondRealRegister"/"nextRegister" idiom in MacroAssembler that appeared to only be used by - one place and had a baked-in notion of what it meant for a register to be "real" or not. - - It's not cool to use words like "real" and "special" to describe registers, especially if you - fail to qualify what that means. This originally made sense on X86 - "real" registers were - the ones that weren't "stack related" (so "real" was the opposite of "stack"). But on ARM64, - you also have to worry about the LR register, which we'd want to say is "not real" but it's - also not a "stack" register. This got super confusing. - - So, this patch removes any mention of "real" registers, consolidates the knowledge of what is - a "stack" register, and uses the word special only in places where it's clearly defined and - where no better word comes to mind. - - This cleans up the code and fixes what seems like it was probably a harmless ARM64 bug: the - Reg and RegisterSet data structures would sometimes think that FP was Q0. Somehow this - magically didn't break anything because you never need to save/restore either FP or Q0, but - it was still super weird. - - * assembler/ARM64Assembler.h: - (JSC::ARM64Assembler::lastRegister): - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::nextRegister): - * ftl/FTLLocation.cpp: - (JSC::FTL::Location::restoreInto): - * ftl/FTLSaveRestore.cpp: - (JSC::FTL::saveAllRegisters): - (JSC::FTL::restoreAllRegisters): - * ftl/FTLSlowPathCall.cpp: - * jit/RegisterSet.cpp: - (JSC::RegisterSet::reservedHardwareRegisters): - (JSC::RegisterSet::runtimeRegisters): - (JSC::RegisterSet::specialRegisters): - (JSC::RegisterSet::calleeSaveRegisters): - * jit/RegisterSet.h: - -2014-03-06 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, fix build. - - * disassembler/ARM64Disassembler.cpp: - -2014-03-06 Filip Pizlo <fpizlo@apple.com> - - Use the LLVM disassembler on ARM64 if we are enabling the FTL - https://bugs.webkit.org/show_bug.cgi?id=129785 - - Reviewed by Geoffrey Garen. - - Our disassembler can't handle some of the code sequences that LLVM emits. LLVM's disassembler - is strictly more capable at this point. Use it if it's available. - - * disassembler/ARM64Disassembler.cpp: - (JSC::tryToDisassemble): - -2014-03-05 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Reduce RWI message frequency - https://bugs.webkit.org/show_bug.cgi?id=129767 - - Reviewed by Timothy Hatcher. - - This used to be 0.2s and changed by accident to 0.02s. - - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::pushListingSoon): - -2014-03-05 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r165141, r165157, and r165158. - http://trac.webkit.org/changeset/165141 - http://trac.webkit.org/changeset/165157 - http://trac.webkit.org/changeset/165158 - https://bugs.webkit.org/show_bug.cgi?id=129772 - - "broke ftl" (Requested by olliej_ on #webkit). - - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/PolymorphicPutByIdList.cpp: - (JSC::PutByIdAccess::visitWeak): - (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): - (JSC::PolymorphicPutByIdList::from): - * bytecode/PolymorphicPutByIdList.h: - (JSC::PutByIdAccess::transition): - (JSC::PutByIdAccess::replace): - (JSC::PutByIdAccess::oldStructure): - (JSC::PutByIdAccess::chain): - (JSC::PutByIdAccess::stubRoutine): - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeForStubInfo): - (JSC::PutByIdStatus::computeFor): - (JSC::PutByIdStatus::dump): - * bytecode/PutByIdStatus.h: - (JSC::PutByIdStatus::PutByIdStatus): - (JSC::PutByIdStatus::takesSlowPath): - * bytecode/StructureStubInfo.h: - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::emitPutById): - (JSC::DFG::ByteCodeParser::handlePutById): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGCommon.h: - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNode.h: - (JSC::DFG::Node::hasIdentifier): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileIn): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - (JSC::DFG::SpeculativeJIT::compile): - * ftl/FTLCompile.cpp: - (JSC::FTL::fixFunctionBasedOnStackMaps): - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): - * jit/JITInlineCacheGenerator.cpp: - (JSC::JITByIdGenerator::JITByIdGenerator): - (JSC::JITPutByIdGenerator::JITPutByIdGenerator): - * jit/JITInlineCacheGenerator.h: - (JSC::JITGetByIdGenerator::JITGetByIdGenerator): - * jit/JITOperations.cpp: - * jit/JITOperations.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_put_by_id): - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_put_by_id): - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - (JSC::tryBuildGetByIDList): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - * jit/SpillRegistersMode.h: Removed. - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * runtime/Lookup.h: - (JSC::putEntry): - * runtime/PutPropertySlot.h: - (JSC::PutPropertySlot::isCacheable): - (JSC::PutPropertySlot::cachedOffset): - -2014-03-05 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Prevent possible deadlock in view indication - https://bugs.webkit.org/show_bug.cgi?id=129766 - - Reviewed by Geoffrey Garen. - - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::receivedIndicateMessage): - -2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> - - JSObject::fastGetOwnPropertySlot does a slow check for OverridesGetOwnPropertySlot - https://bugs.webkit.org/show_bug.cgi?id=129754 - - Reviewed by Geoffrey Garen. - - InlineTypeFlags are stored in JSCell, so we can just load those instead of going through the TypeInfo. - - * runtime/JSCell.h: - (JSC::JSCell::inlineTypeFlags): - * runtime/JSObject.h: - (JSC::JSObject::fastGetOwnPropertySlot): - * runtime/JSTypeInfo.h: - (JSC::TypeInfo::TypeInfo): - (JSC::TypeInfo::overridesGetOwnPropertySlot): - -2014-03-05 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: ASSERTION FAILED: m_javaScriptBreakpoints.isEmpty() - https://bugs.webkit.org/show_bug.cgi?id=129763 - - Reviewed by Geoffrey Garen. - - Clear the list of all breakpoints, including unresolved breakpoints. - - * inspector/agents/InspectorDebuggerAgent.cpp: - (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): - -2014-03-05 Mark Lam <mark.lam@apple.com> - - llint_slow_path_check_has_instance() should not adjust PC before accessing operands. - <https://webkit.org/b/129768> - - Reviewed by Mark Hahnenberg. - - When evaluating "a instanceof b" where b is an object that ImplementsHasInstance - and OverridesHasInstance (e.g. a bound function), the LLINT will take the slow - path llint_slow_path_check_has_instance(), and execute a code path that does the - following: - 1. Adjusts the byte code PC to the jump target PC. - 2. For the purpose of storing the result, get the result registerIndex from the - 1st operand using the PC as if the PC is still pointing to op_check_has_instance - bytecode. - - The result is that whatever value resides after where the jump target PC is will - be used as a result register value. Depending on what that value is, the result - can be: - 1. the code coincidently works correctly - 2. memory corruption - 3. crashes - - The fix is to only adjust the byte code PC after we have stored the result. - - * llint/LLIntSlowPaths.cpp: - (llint_slow_path_check_has_instance): - -2014-03-05 Ryosuke Niwa <rniwa@webkit.org> - - Another build fix attempt after r165141. - - * ftl/FTLCompile.cpp: - (JSC::FTL::fixFunctionBasedOnStackMaps): - -2014-03-05 Ryosuke Niwa <rniwa@webkit.org> - - FTL build fix attempt after r165141. - - * ftl/FTLCompile.cpp: - (JSC::FTL::fixFunctionBasedOnStackMaps): - -2014-03-05 Gavin Barraclough <barraclough@apple.com> - - https://bugs.webkit.org/show_bug.cgi?id=128625 - Add fast mapping from StringImpl to JSString - - Unreviewed roll-out. - - Reverting r164347, r165054, r165066 - not clear the performance tradeoff was right. - - * runtime/JSString.cpp: - * runtime/JSString.h: - * runtime/VM.cpp: - (JSC::VM::createLeaked): - * runtime/VM.h: - -2014-03-03 Oliver Hunt <oliver@apple.com> - - Support caching of custom setters - https://bugs.webkit.org/show_bug.cgi?id=129519 - - Reviewed by Filip Pizlo. - - This patch adds caching of assignment to properties that - are backed by C functions. This provides most of the leg - work required to start supporting setters, and resolves - the remaining regressions from moving DOM properties up - the prototype chain. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/PolymorphicPutByIdList.cpp: - (JSC::PutByIdAccess::visitWeak): - (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): - (JSC::PolymorphicPutByIdList::from): - * bytecode/PolymorphicPutByIdList.h: - (JSC::PutByIdAccess::transition): - (JSC::PutByIdAccess::replace): - (JSC::PutByIdAccess::customSetter): - (JSC::PutByIdAccess::isCustom): - (JSC::PutByIdAccess::oldStructure): - (JSC::PutByIdAccess::chain): - (JSC::PutByIdAccess::stubRoutine): - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeForStubInfo): - (JSC::PutByIdStatus::computeFor): - (JSC::PutByIdStatus::dump): - * bytecode/PutByIdStatus.h: - (JSC::PutByIdStatus::PutByIdStatus): - (JSC::PutByIdStatus::takesSlowPath): - (JSC::PutByIdStatus::makesCalls): - * bytecode/StructureStubInfo.h: - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::emitPutById): - (JSC::DFG::ByteCodeParser::handlePutById): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGCommon.h: - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNode.h: - (JSC::DFG::Node::hasIdentifier): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileIn): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::cachedGetById): - (JSC::DFG::SpeculativeJIT::cachedPutById): - (JSC::DFG::SpeculativeJIT::compile): - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): - * jit/JITInlineCacheGenerator.cpp: - (JSC::JITByIdGenerator::JITByIdGenerator): - (JSC::JITPutByIdGenerator::JITPutByIdGenerator): - * jit/JITInlineCacheGenerator.h: - (JSC::JITGetByIdGenerator::JITGetByIdGenerator): - * jit/JITOperations.cpp: - * jit/JITOperations.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_put_by_id): - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_put_by_id): - * jit/Repatch.cpp: - (JSC::tryCacheGetByID): - (JSC::tryBuildGetByIDList): - (JSC::emitCustomSetterStub): - (JSC::tryCachePutByID): - (JSC::tryBuildPutByIdList): - * jit/SpillRegistersMode.h: Added. - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * runtime/Lookup.h: - (JSC::putEntry): - * runtime/PutPropertySlot.h: - (JSC::PutPropertySlot::setCacheableCustomProperty): - (JSC::PutPropertySlot::customSetter): - (JSC::PutPropertySlot::isCacheablePut): - (JSC::PutPropertySlot::isCacheableCustomProperty): - (JSC::PutPropertySlot::cachedOffset): - -2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> - - JSCell::m_gcData should encode its information differently - https://bugs.webkit.org/show_bug.cgi?id=129741 - - Reviewed by Geoffrey Garen. - - We want to keep track of three GC states for an object: - - 1. Not marked (which implies not in the remembered set) - 2. Marked but not in the remembered set - 3. Marked and in the remembered set - - Currently we only indicate marked vs. not marked in JSCell::m_gcData. During a write - barrier, we only want to take the slow path if the object being stored to is in state #2. - We'd like to make the test for state #2 as fast as possible, which means making it a - compare against 0. - - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::osrWriteBarrier): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::checkMarkByte): - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::writeBarrier): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::allocateCell): - (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): - * heap/Heap.cpp: - (JSC::Heap::clearRememberedSet): - (JSC::Heap::addToRememberedSet): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::checkMarkByte): - * jit/JIT.h: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::checkMarkByte): - (JSC::JIT::emitWriteBarrier): - * jit/Repatch.cpp: - (JSC::writeBarrier): - * llint/LowLevelInterpreter.asm: - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: - * runtime/JSCell.h: - (JSC::JSCell::mark): - (JSC::JSCell::remember): - (JSC::JSCell::forget): - (JSC::JSCell::isMarked): - (JSC::JSCell::isRemembered): - * runtime/JSCellInlines.h: - (JSC::JSCell::JSCell): - * runtime/StructureIDBlob.h: - (JSC::StructureIDBlob::StructureIDBlob): - -2014-03-05 Filip Pizlo <fpizlo@apple.com> - - More FTL ARM fixes - https://bugs.webkit.org/show_bug.cgi?id=129755 - - Reviewed by Geoffrey Garen. - - - Be more defensive about inline caches that have degenerate chains. - - - Temporarily switch to allocating all MCJIT memory in the executable pool on non-x86 - platforms. The bug tracking the real fix is: https://bugs.webkit.org/show_bug.cgi?id=129756 - - - Don't even emit intrinsic declarations on non-x86 platforms. - - - More debug printing support. - - - Don't use vmCall() in the prologue. This should have crashed on all platforms all the time - but somehow it gets lucky on x86. - - * bytecode/GetByIdStatus.cpp: - (JSC::GetByIdStatus::appendVariant): - (JSC::GetByIdStatus::computeForChain): - (JSC::GetByIdStatus::computeForStubInfo): - * bytecode/GetByIdStatus.h: - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::appendVariant): - (JSC::PutByIdStatus::computeForStubInfo): - * bytecode/PutByIdStatus.h: - * bytecode/StructureSet.h: - (JSC::StructureSet::overlaps): - * ftl/FTLCompile.cpp: - (JSC::FTL::mmAllocateDataSection): - * ftl/FTLDataSection.cpp: - (JSC::FTL::DataSection::DataSection): - (JSC::FTL::DataSection::~DataSection): - * ftl/FTLDataSection.h: - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::lower): - * ftl/FTLOutput.h: - (JSC::FTL::Output::doubleSin): - (JSC::FTL::Output::doubleCos): - * runtime/JSCJSValue.cpp: - (JSC::JSValue::dumpInContext): - * runtime/JSCell.h: - (JSC::JSCell::structureID): - -2014-03-05 peavo@outlook.com <peavo@outlook.com> - - [Win32][LLINT] Crash when running JSC stress tests. - https://bugs.webkit.org/show_bug.cgi?id=129429 - - On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory, - where the guard page is a barrier between committed and uncommitted memory. - When data from the guard page is read or written, the guard page is moved, and memory is committed. - This is how the system grows the stack. - When using the C stack on Windows we need to precommit the needed stack space. - Otherwise we might crash later if we access uncommitted stack memory. - This can happen if we allocate stack space larger than the page guard size (4K). - The system does not get the chance to move the guard page, and commit more memory, - and we crash if uncommitted memory is accessed. - The MSVC compiler fixes this by inserting a call to the _chkstk() function, - when needed, see http://support.microsoft.com/kb/100775. - - Reviewed by Geoffrey Garen. - - * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: Enable LLINT. - * jit/Repatch.cpp: - (JSC::writeBarrier): Compile fix when DFG_JIT is not enabled. - * offlineasm/x86.rb: Compile fix, and small simplification. - * runtime/VM.cpp: - (JSC::preCommitStackMemory): Added function to precommit stack memory. - (JSC::VM::updateStackLimit): Call function to precommit stack memory when stack limit is updated. - -2014-03-05 Michael Saboff <msaboff@apple.com> - - JSDataViewPrototype::getData() and setData() crash on platforms that don't allow unaligned accesses - https://bugs.webkit.org/show_bug.cgi?id=129746 - - Reviewed by Filip Pizlo. - - Changed to use a union to manually assemble or disassemble the various types - from / to the corresponding bytes. All memory access is now done using - byte accesses. - - * runtime/JSDataViewPrototype.cpp: - (JSC::getData): - (JSC::setData): - -2014-03-05 Filip Pizlo <fpizlo@apple.com> - - FTL loadStructure always generates invalid IR - https://bugs.webkit.org/show_bug.cgi?id=129747 - - Reviewed by Mark Hahnenberg. - - As the comment at the top of FTL::Output states, the FTL doesn't use LLVM's notion - of pointers. LLVM's notion of pointers tries to model C, in the sense that you have - to have a pointer to a type, and you can only load things of that type from that - pointer. Pointer arithmetic is basically not possible except through the bizarre - getelementptr operator. This doesn't fit with how the JS object model works since - the JS object model doesn't consist of nice and tidy C types placed in C arrays. - Also, it would be impossible to use getelementptr and LLVM pointers for accessing - any of JSC's C or C++ objects unless we went through the exercise of redeclaring - all of our fundamental data structures in LLVM IR as LLVM types. Clang could do - this for us, but that would require that to use the FTL, JSC itself would have to - be compiled with clang. Worse, it would have to be compiled with a clang that uses - a version of LLVM that is compatible with the one against which the FTL is linked. - Yuck! - - The solution is to NEVER use LLVM pointers. This has always been the case in the - FTL. But it causes some confusion. - - Not using LLVM pointers means that if the FTL has a "pointer", it's actually a - pointer-wide integer (m_out.intPtr in FTL-speak). The act of "loading" and - "storing" from or to a pointer involves first bitcasting the intPtr to a real LLVM - pointer that has the type that we want. The load and store operations over pointers - are called Output::load* and Output::store*, where * is one of "8", "16", "32", - "64", "Ptr", "Float", or "Double. - - There is unavoidable confusion here. It would be bizarre for the FTL to call its - "pointer-wide integers" anything other than "pointers", since they are, in all - respects that we care about, simply pointers. But they are *not* LLVM pointers and - they never will be that. - - There is one exception to this "no pointers" rule. The FTL does use actual LLVM - pointers for refering to LLVM alloca's - i.e. local variables. To try to reduce - confusion, we call these "references". So an "FTL reference" is actually an "LLVM - pointer", while an "FTL pointer" is actually an "LLVM integer". FTL references have - methods for access called Output::get and Output::set. These lower to LLVM load - and store, since FTL references are just LLVM pointers. - - This confusion appears to have led to incorrect code in loadStructure(). - loadStructure() was using get() and set() to access FTL pointers. But those methods - don't work on FTL pointers and never will, since they are for FTL references. - - The worst part of this is that it was previously impossible to have test coverage - for the relevant path (MasqueradesAsUndefined) without writing a DRT test. This - patch fixes this by introducing a Masquerader object to jsc.cpp. - - * ftl/FTLAbstractHeapRepository.h: Add an abstract heap for the structure table. - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::loadStructure): This was wrong. - * ftl/FTLOutput.h: Add a comment to disuade people from using get() and set(). - * jsc.cpp: Give us the power to test for MasqueradesAsUndefined. - (WTF::Masquerader::Masquerader): - (WTF::Masquerader::create): - (WTF::Masquerader::createStructure): - (GlobalObject::finishCreation): - (functionMakeMasquerader): - * tests/stress/equals-masquerader.js: Added. - (foo): - (test): - -2014-03-05 Anders Carlsson <andersca@apple.com> - - Tweak after r165109 to avoid extra copies - https://bugs.webkit.org/show_bug.cgi?id=129745 - - Reviewed by Geoffrey Garen. - - * heap/Heap.cpp: - (JSC::Heap::visitProtectedObjects): - (JSC::Heap::visitTempSortVectors): - (JSC::Heap::clearRememberedSet): - * heap/Heap.h: - (JSC::Heap::forEachProtectedCell): - -2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> - - DFGStoreBarrierElisionPhase should should GCState directly instead of m_gcClobberSet when calling writesOverlap() - https://bugs.webkit.org/show_bug.cgi?id=129717 - - Reviewed by Filip Pizlo. - - * dfg/DFGStoreBarrierElisionPhase.cpp: - (JSC::DFG::StoreBarrierElisionPhase::StoreBarrierElisionPhase): - (JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): - -2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> - - Use range-based loops where possible in Heap methods - https://bugs.webkit.org/show_bug.cgi?id=129513 - - Reviewed by Mark Lam. - - Replace old school iterator based loops with the new range-based loop hotness - for a better tomorrow. - - * heap/CodeBlockSet.cpp: - (JSC::CodeBlockSet::~CodeBlockSet): - (JSC::CodeBlockSet::clearMarks): - (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): - (JSC::CodeBlockSet::traceMarked): - * heap/Heap.cpp: - (JSC::Heap::visitProtectedObjects): - (JSC::Heap::visitTempSortVectors): - (JSC::Heap::clearRememberedSet): - * heap/Heap.h: - (JSC::Heap::forEachProtectedCell): - -2014-03-04 Filip Pizlo <fpizlo@apple.com> - - DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null) - https://bugs.webkit.org/show_bug.cgi?id=129563 - - Reviewed by Geoffrey Garen. - - Rolling this back in after fixing an assertion failure. speculateMisc() should have - said DFG_TYPE_CHECK instead of typeCheck. - - This adds a specialization of CompareStrictEq over Misc. I noticed the need for this - when I saw that we didn't support CompareStrictEq(Untyped) in FTL but that the main - user of this was EarleyBoyer, and in that benchmark what it was really doing was - comparing undefined, null, and booleans to each other. - - This also adds support for miscellaneous things that I needed to make my various test - cases work. This includes comparison over booleans and the various Throw-related node - types. - - This also improves constant folding of CompareStrictEq and CompareEq. - - Also found a bug where we were claiming that GetByVals on typed arrays are OutOfBounds - based on profiling, which caused some downstream badness. We don't actually support - compiling OutOfBounds GetByVals on typed arrays. The DFG would ignore the flag and just - emit a bounds check, but in the FTL path, the SSA lowering phase would assume that it - shouldn't factor out the bounds check since the access is not InBounds but then the - backend would ignore the flag and assume that the bounds check was already emitted. - This showed up on an existing test but I added a test for this explicitly to have more - certain coverage. The fix is to not mark something as OutOfBounds if the semantics are - that we'll have a bounds check anyway. - - This is a 1% speed-up on Octane mostly because of raytrace, but also because of just - general progressions across the board. No speed-up yet on EarleyBoyer, since there is - still a lot more coverage work to be done there. - - * bytecode/SpeculatedType.cpp: - (JSC::speculationToAbbreviatedString): - (JSC::leastUpperBoundOfStrictlyEquivalentSpeculations): - (JSC::valuesCouldBeEqual): - * bytecode/SpeculatedType.h: - (JSC::isMiscSpeculation): - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGArrayMode.cpp: - (JSC::DFG::ArrayMode::refine): - * dfg/DFGArrayMode.h: - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength): - * dfg/DFGNode.h: - (JSC::DFG::Node::shouldSpeculateMisc): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::SafeToExecuteEdge::operator()): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileStrictEq): - (JSC::DFG::SpeculativeJIT::speculateMisc): - (JSC::DFG::SpeculativeJIT::speculate): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): - * dfg/DFGUseKind.cpp: - (WTF::printInternal): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileCompareEq): - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::compileThrow): - (JSC::FTL::LowerDFGToLLVM::isNotMisc): - (JSC::FTL::LowerDFGToLLVM::isMisc): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateMisc): - * tests/stress/float32-array-out-of-bounds.js: Added. - * tests/stress/weird-equality-folding-cases.js: Added. - -2014-03-04 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r165085. - http://trac.webkit.org/changeset/165085 - https://bugs.webkit.org/show_bug.cgi?id=129729 - - Broke imported/w3c/html-templates/template-element/template- - content.html (Requested by ap on #webkit). - - * bytecode/SpeculatedType.cpp: - (JSC::speculationToAbbreviatedString): - * bytecode/SpeculatedType.h: - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGArrayMode.cpp: - (JSC::DFG::ArrayMode::refine): - * dfg/DFGArrayMode.h: - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength): - * dfg/DFGNode.h: - (JSC::DFG::Node::shouldSpeculateBoolean): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::SafeToExecuteEdge::operator()): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileStrictEq): - (JSC::DFG::SpeculativeJIT::speculate): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - * dfg/DFGSpeculativeJIT64.cpp: - * dfg/DFGUseKind.cpp: - (WTF::printInternal): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileCompareEq): - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::speculate): - * tests/stress/float32-array-out-of-bounds.js: Removed. - * tests/stress/weird-equality-folding-cases.js: Removed. - -2014-03-04 Brian Burg <bburg@apple.com> - - Inspector does not restore breakpoints after a page reload - https://bugs.webkit.org/show_bug.cgi?id=129655 - - Reviewed by Joseph Pecoraro. - - Fix a regression introduced by r162096 that erroneously removed - the inspector backend's mapping of files to breakpoints whenever the - global object was cleared. - - The inspector's breakpoint mappings should only be cleared when the - debugger agent is disabled or destroyed. We should only clear the - debugger's breakpoint state when the global object is cleared. - - To make it clearer what state is being cleared, the two cases have - been split into separate methods. - - * inspector/agents/InspectorDebuggerAgent.cpp: - (Inspector::InspectorDebuggerAgent::disable): - (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): - (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState): - (Inspector::InspectorDebuggerAgent::didClearGlobalObject): - * inspector/agents/InspectorDebuggerAgent.h: - -2014-03-04 Andreas Kling <akling@apple.com> - - Streamline JSValue::get(). - <https://webkit.org/b/129720> - - Fetch each Structure and VM only once when walking the prototype chain - in JSObject::getPropertySlot(), then pass it along to the functions - we call from there, so they don't have to re-fetch it. - - Reviewed by Geoff Garen. - - * runtime/JSObject.h: - (JSC::JSObject::inlineGetOwnPropertySlot): - (JSC::JSObject::fastGetOwnPropertySlot): - (JSC::JSObject::getPropertySlot): - -2014-03-01 Filip Pizlo <fpizlo@apple.com> - - DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null) - https://bugs.webkit.org/show_bug.cgi?id=129563 - - Reviewed by Geoffrey Garen. - - This adds a specialization of CompareStrictEq over Misc. I noticed the need for this - when I saw that we didn't support CompareStrictEq(Untyped) in FTL but that the main - user of this was EarleyBoyer, and in that benchmark what it was really doing was - comparing undefined, null, and booleans to each other. - - This also adds support for miscellaneous things that I needed to make my various test - cases work. This includes comparison over booleans and the various Throw-related node - types. - - This also improves constant folding of CompareStrictEq and CompareEq. - - Also found a bug where we were claiming that GetByVals on typed arrays are OutOfBounds - based on profiling, which caused some downstream badness. We don't actually support - compiling OutOfBounds GetByVals on typed arrays. The DFG would ignore the flag and just - emit a bounds check, but in the FTL path, the SSA lowering phase would assume that it - shouldn't factor out the bounds check since the access is not InBounds but then the - backend would ignore the flag and assume that the bounds check was already emitted. - This showed up on an existing test but I added a test for this explicitly to have more - certain coverage. The fix is to not mark something as OutOfBounds if the semantics are - that we'll have a bounds check anyway. - - This is a 1% speed-up on Octane mostly because of raytrace, but also because of just - general progressions across the board. No speed-up yet on EarleyBoyer, since there is - still a lot more coverage work to be done there. - - * bytecode/SpeculatedType.cpp: - (JSC::speculationToAbbreviatedString): - (JSC::leastUpperBoundOfStrictlyEquivalentSpeculations): - (JSC::valuesCouldBeEqual): - * bytecode/SpeculatedType.h: - (JSC::isMiscSpeculation): - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGNode.h: - (JSC::DFG::Node::shouldSpeculateMisc): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::SafeToExecuteEdge::operator()): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::compileStrictEq): - (JSC::DFG::SpeculativeJIT::speculateMisc): - (JSC::DFG::SpeculativeJIT::speculate): - * dfg/DFGSpeculativeJIT.h: - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): - * dfg/DFGUseKind.cpp: - (WTF::printInternal): - * dfg/DFGUseKind.h: - (JSC::DFG::typeFilterFor): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileCompareEq): - (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): - (JSC::FTL::LowerDFGToLLVM::compileThrow): - (JSC::FTL::LowerDFGToLLVM::isNotMisc): - (JSC::FTL::LowerDFGToLLVM::isMisc): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateMisc): - * tests/stress/float32-array-out-of-bounds.js: Added. - * tests/stress/weird-equality-folding-cases.js: Added. - -2014-03-04 Andreas Kling <akling@apple.com> - - Spam static branch prediction hints on JS bindings. - <https://webkit.org/b/129703> - - Add LIKELY hint to jsDynamicCast since it's always used in a context - where we expect it to succeed and takes an error path when it doesn't. - - Reviewed by Geoff Garen. - - * runtime/JSCell.h: - (JSC::jsDynamicCast): - -2014-03-04 Andreas Kling <akling@apple.com> - - Get to Structures more efficiently in JSCell::methodTable(). - <https://webkit.org/b/129702> - - In JSCell::methodTable(), get the VM once and pass that along to - structure(VM&) instead of using the heavier structure(). - - In JSCell::methodTable(VM&), replace calls to structure() with - calls to structure(VM&). - - Reviewed by Mark Hahnenberg. - - * runtime/JSCellInlines.h: - (JSC::JSCell::methodTable): - -2014-03-04 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Listen for the XPC_ERROR_CONNECTION_INVALID event to deref - https://bugs.webkit.org/show_bug.cgi?id=129697 - - Reviewed by Timothy Hatcher. - - * inspector/remote/RemoteInspectorXPCConnection.mm: - (Inspector::RemoteInspectorXPCConnection::RemoteInspectorXPCConnection): - (Inspector::RemoteInspectorXPCConnection::handleEvent): - -2014-03-04 Mark Hahnenberg <mhahnenberg@apple.com> - - Merge API shims and JSLock - https://bugs.webkit.org/show_bug.cgi?id=129650 - - Reviewed by Mark Lam. - - JSLock is now taking on all of APIEntryShim's responsibilities since there is never a reason - to take just the JSLock. Ditto for DropAllLocks and APICallbackShim. - - * API/APICallbackFunction.h: - (JSC::APICallbackFunction::call): - (JSC::APICallbackFunction::construct): - * API/APIShims.h: Removed. - * API/JSBase.cpp: - (JSEvaluateScript): - (JSCheckScriptSyntax): - (JSGarbageCollect): - (JSReportExtraMemoryCost): - (JSSynchronousGarbageCollectForDebugging): - * API/JSCallbackConstructor.cpp: - * API/JSCallbackFunction.cpp: - * API/JSCallbackObjectFunctions.h: - (JSC::JSCallbackObject<Parent>::init): - (JSC::JSCallbackObject<Parent>::getOwnPropertySlot): - (JSC::JSCallbackObject<Parent>::put): - (JSC::JSCallbackObject<Parent>::putByIndex): - (JSC::JSCallbackObject<Parent>::deleteProperty): - (JSC::JSCallbackObject<Parent>::construct): - (JSC::JSCallbackObject<Parent>::customHasInstance): - (JSC::JSCallbackObject<Parent>::call): - (JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames): - (JSC::JSCallbackObject<Parent>::getStaticValue): - (JSC::JSCallbackObject<Parent>::callbackGetter): - * API/JSContext.mm: - (-[JSContext setException:]): - (-[JSContext wrapperForObjCObject:]): - (-[JSContext wrapperForJSObject:]): - * API/JSContextRef.cpp: - (JSContextGroupRelease): - (JSContextGroupSetExecutionTimeLimit): - (JSContextGroupClearExecutionTimeLimit): - (JSGlobalContextCreateInGroup): - (JSGlobalContextRetain): - (JSGlobalContextRelease): - (JSContextGetGlobalObject): - (JSContextGetGlobalContext): - (JSGlobalContextCopyName): - (JSGlobalContextSetName): - * API/JSManagedValue.mm: - (-[JSManagedValue value]): - * API/JSObjectRef.cpp: - (JSObjectMake): - (JSObjectMakeFunctionWithCallback): - (JSObjectMakeConstructor): - (JSObjectMakeFunction): - (JSObjectMakeArray): - (JSObjectMakeDate): - (JSObjectMakeError): - (JSObjectMakeRegExp): - (JSObjectGetPrototype): - (JSObjectSetPrototype): - (JSObjectHasProperty): - (JSObjectGetProperty): - (JSObjectSetProperty): - (JSObjectGetPropertyAtIndex): - (JSObjectSetPropertyAtIndex): - (JSObjectDeleteProperty): - (JSObjectGetPrivateProperty): - (JSObjectSetPrivateProperty): - (JSObjectDeletePrivateProperty): - (JSObjectIsFunction): - (JSObjectCallAsFunction): - (JSObjectCallAsConstructor): - (JSObjectCopyPropertyNames): - (JSPropertyNameArrayRelease): - (JSPropertyNameAccumulatorAddName): - * API/JSScriptRef.cpp: - * API/JSValue.mm: - (isDate): - (isArray): - (containerValueToObject): - (valueToArray): - (valueToDictionary): - (objectToValue): - * API/JSValueRef.cpp: - (JSValueGetType): - (JSValueIsUndefined): - (JSValueIsNull): - (JSValueIsBoolean): - (JSValueIsNumber): - (JSValueIsString): - (JSValueIsObject): - (JSValueIsObjectOfClass): - (JSValueIsEqual): - (JSValueIsStrictEqual): - (JSValueIsInstanceOfConstructor): - (JSValueMakeUndefined): - (JSValueMakeNull): - (JSValueMakeBoolean): - (JSValueMakeNumber): - (JSValueMakeString): - (JSValueMakeFromJSONString): - (JSValueCreateJSONString): - (JSValueToBoolean): - (JSValueToNumber): - (JSValueToStringCopy): - (JSValueToObject): - (JSValueProtect): - (JSValueUnprotect): - * API/JSVirtualMachine.mm: - (-[JSVirtualMachine addManagedReference:withOwner:]): - (-[JSVirtualMachine removeManagedReference:withOwner:]): - * API/JSWeakObjectMapRefPrivate.cpp: - * API/JSWrapperMap.mm: - (constructorHasInstance): - (makeWrapper): - (tryUnwrapObjcObject): - * API/ObjCCallbackFunction.mm: - (JSC::objCCallbackFunctionCallAsFunction): - (JSC::objCCallbackFunctionCallAsConstructor): - (objCCallbackFunctionForInvocation): - * CMakeLists.txt: - * ForwardingHeaders/JavaScriptCore/APIShims.h: Removed. - * GNUmakefile.list.am: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGWorklist.cpp: - * heap/DelayedReleaseScope.h: - (JSC::DelayedReleaseScope::~DelayedReleaseScope): - * heap/HeapTimer.cpp: - (JSC::HeapTimer::timerDidFire): - (JSC::HeapTimer::timerEvent): - * heap/IncrementalSweeper.cpp: - * inspector/InjectedScriptModule.cpp: - (Inspector::InjectedScriptModule::ensureInjected): - * jsc.cpp: - (jscmain): - * runtime/GCActivityCallback.cpp: - (JSC::DefaultGCActivityCallback::doWork): - * runtime/JSGlobalObjectDebuggable.cpp: - (JSC::JSGlobalObjectDebuggable::connect): - (JSC::JSGlobalObjectDebuggable::disconnect): - (JSC::JSGlobalObjectDebuggable::dispatchMessageFromRemoteFrontend): - * runtime/JSLock.cpp: - (JSC::JSLock::lock): - (JSC::JSLock::didAcquireLock): - (JSC::JSLock::unlock): - (JSC::JSLock::willReleaseLock): - (JSC::JSLock::DropAllLocks::DropAllLocks): - (JSC::JSLock::DropAllLocks::~DropAllLocks): - * runtime/JSLock.h: - * testRegExp.cpp: - (realMain): - -2014-03-04 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r164812. - http://trac.webkit.org/changeset/164812 - https://bugs.webkit.org/show_bug.cgi?id=129699 - - it made things run slower (Requested by pizlo on #webkit). - - * interpreter/Interpreter.cpp: - (JSC::Interpreter::execute): - * jsc.cpp: - (GlobalObject::finishCreation): - * runtime/BatchedTransitionOptimizer.h: - (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): - (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer): - -2014-03-02 Filip Pizlo <fpizlo@apple.com> - - GetMyArgumentByVal in FTL - https://bugs.webkit.org/show_bug.cgi?id=128850 - - Reviewed by Oliver Hunt. - - This would have been easy if the OSR exit compiler's arity checks hadn't been wrong. - They checked arity by doing "exec->argumentCount == codeBlock->numParameters", which - caused it to think that the arity check had failed if the caller had passed more - arguments than needed. This would cause the call frame copying to sort of go into - reverse (because the amount-by-which-we-failed-arity would have opposite sign, - throwing off a bunch of math) and the stack would end up being corrupted. - - The bug was revealed by two existing tests although as far as I could tell, neither - test was intending to cover this case directly. So, I added a new test. - - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): - (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): - (JSC::FTL::LowerDFGToLLVM::compileCheckArgumentsNotCreated): - (JSC::FTL::LowerDFGToLLVM::checkArgumentsNotCreated): - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileStub): - * ftl/FTLState.h: - * tests/stress/exit-from-ftl-when-caller-passed-extra-args-then-use-function-dot-arguments.js: Added. - * tests/stress/ftl-get-my-argument-by-val-inlined-and-not-inlined.js: Added. - * tests/stress/ftl-get-my-argument-by-val-inlined.js: Added. - * tests/stress/ftl-get-my-argument-by-val.js: Added. - -2014-03-04 Zan Dobersek <zdobersek@igalia.com> - - [GTK] Build the Udis86 disassembler - https://bugs.webkit.org/show_bug.cgi?id=129679 - - Reviewed by Michael Saboff. - - * GNUmakefile.am: Generate the Udis86-related derived sources. Distribute the required files. - * GNUmakefile.list.am: Add the Udis86 disassembler files to the build. - -2014-03-04 Andreas Kling <akling@apple.com> - - Fix too-narrow assertion I added in r165054. - - It's okay for a 1-character string to come in here. This will happen - if the VM small string optimization doesn't apply (ch > 0xFF) - - * runtime/JSString.h: - (JSC::jsStringWithWeakOwner): - -2014-03-04 Andreas Kling <akling@apple.com> - - Micro-optimize Strings in JS bindings. - <https://webkit.org/b/129673> - - Make jsStringWithWeakOwner() take a StringImpl& instead of a String. - This avoids branches in length() and operator[]. - - Also call JSString::create() directly instead of jsString() and just - assert that the string length is >1. This way we don't duplicate the - optimizations for empty and single-character strings. - - Reviewed by Ryosuke Niwa. - - * runtime/JSString.h: - (JSC::jsStringWithWeakOwner): - -2014-03-04 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> - - Implement Number.prototype.clz() - https://bugs.webkit.org/show_bug.cgi?id=129479 - - Reviewed by Oliver Hunt. - - Implemented Number.prototype.clz() as specified in the ES6 standard. - - * runtime/NumberPrototype.cpp: - (JSC::numberProtoFuncClz): - -2014-03-03 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Avoid too early deref caused by RemoteInspectorXPCConnection::close - https://bugs.webkit.org/show_bug.cgi?id=129631 - - Reviewed by Timothy Hatcher. - - Avoid deref() too early if a client calls close(). The xpc_connection_close - will cause another XPC_ERROR event to come in from the queue, deref then. - Likewise, protect multithreaded access to m_client. If a client calls - close() we want to immediately clear the pointer to prevent calls to it. - - Overall the multi-threading aspects of RemoteInspectorXPCConnection are - growing too complicated for probably little benefit. We may want to - clean this up later. - - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::xpcConnectionFailed): - * inspector/remote/RemoteInspectorXPCConnection.h: - * inspector/remote/RemoteInspectorXPCConnection.mm: - (Inspector::RemoteInspectorXPCConnection::RemoteInspectorXPCConnection): - (Inspector::RemoteInspectorXPCConnection::close): - (Inspector::RemoteInspectorXPCConnection::closeOnQueue): - (Inspector::RemoteInspectorXPCConnection::deserializeMessage): - (Inspector::RemoteInspectorXPCConnection::handleEvent): - (Inspector::RemoteInspectorXPCConnection::sendMessage): - -2014-03-03 Michael Saboff <msaboff@apple.com> - - AbstractMacroAssembler::CachedTempRegister should start out invalid - https://bugs.webkit.org/show_bug.cgi?id=129657 - - Reviewed by Filip Pizlo. - - * assembler/AbstractMacroAssembler.h: - (JSC::AbstractMacroAssembler::AbstractMacroAssembler): - - Invalidate all cached registers in constructor as we don't know the - contents of any register at the entry to the code we are going to - generate. - -2014-03-03 Andreas Kling <akling@apple.com> - - StructureOrOffset should be fastmalloced. - <https://webkit.org/b/129640> - - Reviewed by Geoffrey Garen. - - * runtime/StructureIDTable.h: - -2014-03-03 Michael Saboff <msaboff@apple.com> - - Crash in JIT code while watching a video @ storyboard.tumblr.com - https://bugs.webkit.org/show_bug.cgi?id=129635 - - Reviewed by Filip Pizlo. - - Clear m_set before we set bits in the TempRegisterSet(const RegisterSet& other) - construtor. - - * jit/TempRegisterSet.cpp: - (JSC::TempRegisterSet::TempRegisterSet): Clear map before setting it. - * jit/TempRegisterSet.h: - (JSC::TempRegisterSet::TempRegisterSet): Use new clearAll() helper. - (JSC::TempRegisterSet::clearAll): New private helper. - -2014-03-03 Benjamin Poulain <benjamin@webkit.org> - - [x86] Improve code generation of byte test - https://bugs.webkit.org/show_bug.cgi?id=129597 - - Reviewed by Geoffrey Garen. - - When possible, test the 8 bit register to itself instead of comparing it - to a literal. - - * assembler/MacroAssemblerX86Common.h: - (JSC::MacroAssemblerX86Common::test32): - -2014-03-03 Mark Lam <mark.lam@apple.com> - - Web Inspector: debugger statements do not break. - <https://webkit.org/b/129524> - - Reviewed by Geoff Garen. - - Since we no longer call op_debug hooks unless there is a debugger request - made on the CodeBlock, the op_debug for the debugger statement never gets - serviced. - - With this fix, we check in the CodeBlock constructor if any debugger - statements are present. If so, we set a m_hasDebuggerStatement flag that - causes the CodeBlock to show as having debugger requests. Hence, - breaking at debugger statements is now restored. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::CodeBlock): - * bytecode/CodeBlock.h: - (JSC::CodeBlock::hasDebuggerRequests): - (JSC::CodeBlock::clearDebuggerRequests): - -2014-03-03 Mark Lam <mark.lam@apple.com> - - ASSERTION FAILED: m_numBreakpoints >= numBreakpoints when deleting breakpoints. - <https://webkit.org/b/129393> - - Reviewed by Geoffrey Garen. - - The issue manifests because the debugger will iterate all CodeBlocks in - the heap when setting / clearing breakpoints, but it is possible for a - CodeBlock to have been instantiate but is not yet registered with the - debugger. This can happen because of the following: - - 1. DFG worklist compilation is still in progress, and the target - codeBlock is not ready for installation in its executable yet. - - 2. DFG compilation failed and we have a codeBlock that will never be - installed in its executable, and the codeBlock has not been cleaned - up by the GC yet. - - The code for installing the codeBlock in its executable is the same code - that registers it with the debugger. Hence, these codeBlocks are not - registered with the debugger, and any pending breakpoints that would map - to that CodeBlock is as yet unset or will never be set. As such, an - attempt to remove a breakpoint in that CodeBlock will fail that assertion. - - To fix this, we do the following: - - 1. We'll eagerly clean up any zombie CodeBlocks due to failed DFG / FTL - compilation. This is achieved by providing a - DeferredCompilationCallback::compilationDidComplete() that does this - clean up, and have all sub classes call it at the end of their - compilationDidComplete() methods. - - 2. Before the debugger or profiler iterates CodeBlocks in the heap, they - will wait for all compilations to complete before proceeding. This - ensures that: - 1. any zombie CodeBlocks would have been cleaned up, and won't be - seen by the debugger or profiler. - 2. all CodeBlocks that the debugger and profiler needs to operate on - will be "ready" for whatever needs to be done to them e.g. - jettison'ing of DFG codeBlocks. - - * bytecode/DeferredCompilationCallback.cpp: - (JSC::DeferredCompilationCallback::compilationDidComplete): - * bytecode/DeferredCompilationCallback.h: - - Provide default implementation method to clean up zombie CodeBlocks. - - * debugger/Debugger.cpp: - (JSC::Debugger::forEachCodeBlock): - - Utility function to iterate CodeBlocks. It ensures that all compilations - are complete before proceeding. - (JSC::Debugger::setSteppingMode): - (JSC::Debugger::toggleBreakpoint): - (JSC::Debugger::recompileAllJSFunctions): - (JSC::Debugger::clearBreakpoints): - (JSC::Debugger::clearDebuggerRequests): - - Use the utility iterator function. - - * debugger/Debugger.h: - * dfg/DFGOperations.cpp: - - Added an assert to ensure that zombie CodeBlocks will be imminently cleaned up. - - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::finalizeWithoutNotifyingCallback): - - Remove unneeded code (that was not the best solution anyway) for ensuring - that we don't generate new DFG codeBlocks after enabling the debugger or - profiler. Now that we wait for compilations to complete before proceeding - with debugger and profiler work, this scenario will never happen. - - * dfg/DFGToFTLDeferredCompilationCallback.cpp: - (JSC::DFG::ToFTLDeferredCompilationCallback::compilationDidComplete): - - Call the super class method to clean up zombie codeBlocks. - - * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp: - (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidComplete): - - Call the super class method to clean up zombie codeBlocks. - - * heap/CodeBlockSet.cpp: - (JSC::CodeBlockSet::remove): - * heap/CodeBlockSet.h: - * heap/Heap.h: - (JSC::Heap::removeCodeBlock): - - New method to remove a codeBlock from the codeBlock set. - - * jit/JITOperations.cpp: - - Added an assert to ensure that zombie CodeBlocks will be imminently cleaned up. - - * jit/JITToDFGDeferredCompilationCallback.cpp: - (JSC::JITToDFGDeferredCompilationCallback::compilationDidComplete): - - Call the super class method to clean up zombie codeBlocks. - - * runtime/VM.cpp: - (JSC::VM::waitForCompilationsToComplete): - - Renamed from prepareToDiscardCode() to be clearer about what it does. - - (JSC::VM::discardAllCode): - (JSC::VM::releaseExecutableMemory): - (JSC::VM::setEnabledProfiler): - - Wait for compilation to complete before enabling the profiler. - - * runtime/VM.h: - -2014-03-03 Brian Burg <bburg@apple.com> - - Another unreviewed build fix attempt for Windows after r164986. - - We never told Visual Studio to copy over the web replay code generator scripts - and the generated headers for JavaScriptCore replay inputs as if they were - private headers. - - * JavaScriptCore.vcxproj/copy-files.cmd: - -2014-03-03 Brian Burg <bburg@apple.com> - - Web Replay: upstream input storage, capture/replay machinery, and inspector domain - https://bugs.webkit.org/show_bug.cgi?id=128782 - - Reviewed by Timothy Hatcher. - - Alter the replay inputs code generator so that it knows when it is necessary to - to include headers for HEAVY_SCALAR types such as WTF::String and WebCore::URL. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * replay/scripts/CodeGeneratorReplayInputs.py: - (Framework.fromString): - (Frameworks): Add WTF as an allowed framework for code generation. - (Generator.generate_includes): Include headers for HEAVY_SCALAR types in the header file. - (Generator.generate_includes.declaration): - (Generator.generate_includes.or): - (Generator.generate_type_forward_declarations): Skip HEAVY_SCALAR types. - -2014-03-02 Filip Pizlo <fpizlo@apple.com> - - PolymorphicPutByIdList should have a simpler construction API with basically a single entrypoint - https://bugs.webkit.org/show_bug.cgi?id=129591 - - Reviewed by Michael Saboff. - - * bytecode/PolymorphicPutByIdList.cpp: - (JSC::PutByIdAccess::fromStructureStubInfo): This function can figure out the slow path target for itself. - (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): This constuctor should be private, only from() should call it. - (JSC::PolymorphicPutByIdList::from): - * bytecode/PolymorphicPutByIdList.h: - (JSC::PutByIdAccess::stubRoutine): - * jit/Repatch.cpp: - (JSC::tryBuildPutByIdList): Don't pass the slow path target since it can be derived from the stubInfo. - -2014-03-02 Filip Pizlo <fpizlo@apple.com> - - Debugging improvements from my gbemu investigation session - https://bugs.webkit.org/show_bug.cgi?id=129599 - - Reviewed by Mark Lam. - - Various improvements from when I was investigating bug 129411. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::optimizationThresholdScalingFactor): Make the dataLog() statement print the actual multiplier. - * jsc.cpp: - (GlobalObject::finishCreation): - (functionDescribe): Make describe() return a string rather than printing the string. - (functionDescribeArray): Like describe(), but prints details about arrays. - -2014-02-25 Andreas Kling <akling@apple.com> - - JSDOMWindow::commonVM() should return a reference. - <https://webkit.org/b/129293> - - Added a DropAllLocks constructor that takes VM& without null checks. - - Reviewed by Geoff Garen. - -2014-03-02 Mark Lam <mark.lam@apple.com> - - CodeBlock::hasDebuggerRequests() should returning a bool instead of an int. - <https://webkit.org/b/129584> - - Reviewed by Darin Adler. - - * bytecode/CodeBlock.h: - (JSC::CodeBlock::hasDebuggerRequests): - -2014-03-02 Mark Lam <mark.lam@apple.com> - - Clean up use of Options::enableConcurrentJIT(). - <https://webkit.org/b/129582> - - Reviewed by Filip Pizlo. - - DFG Driver was conditionally checking Options::enableConcurrentJIT() - only if ENABLE(CONCURRENT_JIT). Otherwise, it bypasses it with a local - enableConcurrentJIT set to false. - - Instead we should configure Options::enableConcurrentJIT() to be false - in Options.cpp if !ENABLE(CONCURRENT_JIT), and DFG Driver should always - check Options::enableConcurrentJIT(). This makes the code read a little - cleaner. - - * dfg/DFGDriver.cpp: - (JSC::DFG::compileImpl): - * runtime/Options.cpp: - (JSC::recomputeDependentOptions): - -2014-03-01 Filip Pizlo <fpizlo@apple.com> - - This shouldn't have been a layout test since it runs only under jsc. Moving it to JSC - stress tests. - - * tests/stress/generational-opaque-roots.js: Copied from LayoutTests/js/script-tests/generational-opaque-roots.js. - -2014-03-01 Andreas Kling <akling@apple.com> - - JSCell::fastGetOwnProperty() should get the Structure more efficiently. - <https://webkit.org/b/129560> - - Now that structure() is nontrivial and we have a faster structure(VM&), - make use of that in fastGetOwnProperty() since we already have VM. - - Reviewed by Sam Weinig. - - * runtime/JSCellInlines.h: - (JSC::JSCell::fastGetOwnProperty): - -2014-03-01 Andreas Kling <akling@apple.com> - - Avoid going through ExecState for VM when we already have it (in some places.) - <https://webkit.org/b/129554> - - Tweak some places that jump through unnecessary hoops to get the VM. - There are many more like this. - - Reviewed by Sam Weinig. - - * runtime/JSObject.cpp: - (JSC::JSObject::putByIndexBeyondVectorLength): - (JSC::JSObject::putDirectIndexBeyondVectorLength): - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncToString): - -2014-02-28 Filip Pizlo <fpizlo@apple.com> - - FTL should support PhantomArguments - https://bugs.webkit.org/show_bug.cgi?id=113986 - - Reviewed by Oliver Hunt. - - Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments - object into the FTL's OSR exit compiler. - - This isn't a speed-up yet, since there is still more to be done to fully support - all of the arguments craziness that our varargs benchmarks do. - - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): move the recovery code to DFGOSRExitCompilerCommon.cpp - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): move the recovery code to DFGOSRExitCompilerCommon.cpp - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::ArgumentsRecoveryGenerator::ArgumentsRecoveryGenerator): - (JSC::DFG::ArgumentsRecoveryGenerator::~ArgumentsRecoveryGenerator): - (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): this is the common place for the recovery code - * dfg/DFGOSRExitCompilerCommon.h: - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLExitValue.cpp: - (JSC::FTL::ExitValue::dumpInContext): - * ftl/FTLExitValue.h: - (JSC::FTL::ExitValue::argumentsObjectThatWasNotCreated): - (JSC::FTL::ExitValue::isArgumentsObjectThatWasNotCreated): - (JSC::FTL::ExitValue::valueFormat): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compilePhantomArguments): - (JSC::FTL::LowerDFGToLLVM::buildExitArguments): - (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument): - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileStub): Call into the ArgumentsRecoveryGenerator - * tests/stress/slightly-more-difficult-to-fold-reflective-arguments-access.js: Added. - * tests/stress/trivially-foldable-reflective-arguments-access.js: Added. - -2014-02-28 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, uncomment some code. It wasn't meant to be commented in the first place. - - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination): - -2014-02-28 Andreas Kling <akling@apple.com> - - JSObject::findPropertyHashEntry() should take VM instead of ExecState. - <https://webkit.org/b/129529> - - Callers already have VM in a local, and findPropertyHashEntry() only - uses the VM, no need to go all the way through ExecState. - - Reviewed by Geoffrey Garen. - - * runtime/JSObject.cpp: - (JSC::JSObject::put): - (JSC::JSObject::deleteProperty): - (JSC::JSObject::findPropertyHashEntry): - * runtime/JSObject.h: - -2014-02-28 Joseph Pecoraro <pecoraro@apple.com> - - Deadlock remotely inspecting iOS Simulator - https://bugs.webkit.org/show_bug.cgi?id=129511 - - Reviewed by Timothy Hatcher. - - Avoid synchronous setup. Do it asynchronously, and let - the RemoteInspector singleton know later if it failed. - - * inspector/remote/RemoteInspector.h: - * inspector/remote/RemoteInspector.mm: - (Inspector::RemoteInspector::setupFailed): - * inspector/remote/RemoteInspectorDebuggableConnection.h: - * inspector/remote/RemoteInspectorDebuggableConnection.mm: - (Inspector::RemoteInspectorDebuggableConnection::setup): - -2014-02-28 Oliver Hunt <oliver@apple.com> - - REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms - https://bugs.webkit.org/show_bug.cgi?id=129488 - - Reviewed by Mark Lam. - - Whoops, modify the right register. - - * jit/JITCall32_64.cpp: - (JSC::JIT::compileLoadVarargs): - -2014-02-28 Filip Pizlo <fpizlo@apple.com> - - FTL should be able to call sin/cos directly on platforms where the intrinsic is busted - https://bugs.webkit.org/show_bug.cgi?id=129503 - - Reviewed by Mark Lam. - - * ftl/FTLIntrinsicRepository.h: - * ftl/FTLOutput.h: - (JSC::FTL::Output::doubleSin): - (JSC::FTL::Output::doubleCos): - (JSC::FTL::Output::intrinsicOrOperation): - -2014-02-28 Mark Hahnenberg <mhahnenberg@apple.com> - - Fix !ENABLE(GGC) builds - - * heap/Heap.cpp: - (JSC::Heap::markRoots): - (JSC::Heap::gatherJSStackRoots): Also fix one of the names of the GC phases. - -2014-02-27 Mark Hahnenberg <mhahnenberg@apple.com> - - Clean up Heap::collect and Heap::markRoots - https://bugs.webkit.org/show_bug.cgi?id=129464 - - Reviewed by Geoffrey Garen. - - These functions have built up a lot of cruft recently. - We should do a bit of cleanup to make them easier to grok. - - * heap/Heap.cpp: - (JSC::Heap::finalizeUnconditionalFinalizers): - (JSC::Heap::gatherStackRoots): - (JSC::Heap::gatherJSStackRoots): - (JSC::Heap::gatherScratchBufferRoots): - (JSC::Heap::clearLivenessData): - (JSC::Heap::visitSmallStrings): - (JSC::Heap::visitConservativeRoots): - (JSC::Heap::visitCompilerWorklists): - (JSC::Heap::markProtectedObjects): - (JSC::Heap::markTempSortVectors): - (JSC::Heap::markArgumentBuffers): - (JSC::Heap::visitException): - (JSC::Heap::visitStrongHandles): - (JSC::Heap::visitHandleStack): - (JSC::Heap::traceCodeBlocksAndJITStubRoutines): - (JSC::Heap::converge): - (JSC::Heap::visitWeakHandles): - (JSC::Heap::clearRememberedSet): - (JSC::Heap::updateObjectCounts): - (JSC::Heap::resetVisitors): - (JSC::Heap::markRoots): - (JSC::Heap::copyBackingStores): - (JSC::Heap::deleteUnmarkedCompiledCode): - (JSC::Heap::collect): - (JSC::Heap::collectIfNecessaryOrDefer): - (JSC::Heap::suspendCompilerThreads): - (JSC::Heap::willStartCollection): - (JSC::Heap::deleteOldCode): - (JSC::Heap::flushOldStructureIDTables): - (JSC::Heap::flushWriteBarrierBuffer): - (JSC::Heap::stopAllocation): - (JSC::Heap::reapWeakHandles): - (JSC::Heap::sweepArrayBuffers): - (JSC::Heap::snapshotMarkedSpace): - (JSC::Heap::deleteSourceProviderCaches): - (JSC::Heap::notifyIncrementalSweeper): - (JSC::Heap::rememberCurrentlyExecutingCodeBlocks): - (JSC::Heap::resetAllocators): - (JSC::Heap::updateAllocationLimits): - (JSC::Heap::didFinishCollection): - (JSC::Heap::resumeCompilerThreads): - * heap/Heap.h: - -2014-02-27 Ryosuke Niwa <rniwa@webkit.org> - - indexOf and lastIndexOf shouldn't resolve ropes when needle is longer than haystack - https://bugs.webkit.org/show_bug.cgi?id=129466 - - Reviewed by Michael Saboff. - - Refactored the code to avoid calling JSString::value when needle is longer than haystack. - - * runtime/StringPrototype.cpp: - (JSC::stringProtoFuncIndexOf): - (JSC::stringProtoFuncLastIndexOf): - -2014-02-27 Timothy Hatcher <timothy@apple.com> - - Improve how ContentSearchUtilities::lineEndings works by supporting the three common line endings. - - https://bugs.webkit.org/show_bug.cgi?id=129458 - - Reviewed by Joseph Pecoraro. - - * inspector/ContentSearchUtilities.cpp: - (Inspector::ContentSearchUtilities::textPositionFromOffset): Remove assumption about line ending length. - (Inspector::ContentSearchUtilities::getRegularExpressionMatchesByLines): Remove assumption about - line ending type and don't try to strip the line ending. Use size_t - (Inspector::ContentSearchUtilities::lineEndings): Use findNextLineStart to find the lines. - This will include the line ending in the lines, but that is okay. - (Inspector::ContentSearchUtilities::buildObjectForSearchMatch): Use size_t. - (Inspector::ContentSearchUtilities::searchInTextByLines): Modernize. - -2014-02-27 Joseph Pecoraro <pecoraro@apple.com> - - [Mac] Warning: Multiple build commands for output file GCSegmentedArray and InspectorAgent - https://bugs.webkit.org/show_bug.cgi?id=129446 - - Reviewed by Timothy Hatcher. - - Remove duplicate header entries in Copy Header build phase. - - * JavaScriptCore.xcodeproj/project.pbxproj: - -2014-02-27 Oliver Hunt <oliver@apple.com> - - Whoops, include all of last patch. - - * jit/JITCall32_64.cpp: - (JSC::JIT::compileLoadVarargs): - -2014-02-27 Oliver Hunt <oliver@apple.com> - - Slow cases for function.apply and function.call should not require vm re-entry - https://bugs.webkit.org/show_bug.cgi?id=129454 - - Reviewed by Geoffrey Garen. - - Implement call and apply using builtins. Happily the use - of @call and @apply don't perform function equality checks - and just plant direct var_args calls. This did expose a few - codegen issues, but they're all covered by existing tests - once call and apply are implemented in JS. - - * JavaScriptCore.xcodeproj/project.pbxproj: - * builtins/Function.prototype.js: Added. - (call): - (apply): - * bytecompiler/NodesCodegen.cpp: - (JSC::CallFunctionCallDotNode::emitBytecode): - (JSC::ApplyFunctionCallDotNode::emitBytecode): - * dfg/DFGCapabilities.cpp: - (JSC::DFG::capabilityLevel): - * interpreter/Interpreter.cpp: - (JSC::sizeFrameForVarargs): - (JSC::loadVarargs): - * interpreter/Interpreter.h: - * jit/JITCall.cpp: - (JSC::JIT::compileLoadVarargs): - * parser/ASTBuilder.h: - (JSC::ASTBuilder::makeFunctionCallNode): - * parser/Lexer.cpp: - (JSC::isSafeBuiltinIdentifier): - * runtime/CommonIdentifiers.h: - * runtime/FunctionPrototype.cpp: - (JSC::FunctionPrototype::addFunctionProperties): - * runtime/JSObject.cpp: - (JSC::JSObject::putDirectBuiltinFunction): - (JSC::JSObject::putDirectBuiltinFunctionWithoutTransition): - * runtime/JSObject.h: - -2014-02-27 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: Better name for RemoteInspectorDebuggableConnection dispatch queue - https://bugs.webkit.org/show_bug.cgi?id=129443 - - Reviewed by Timothy Hatcher. - - This queue is specific to the JSContext debuggable connections, - there is no XPC involved. Give it a better name. - - * inspector/remote/RemoteInspectorDebuggableConnection.mm: - (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): - -2014-02-27 David Kilzer <ddkilzer@apple.com> - - Remove jsc symlink if it already exists - - This is a follow-up fix for: - - Create symlink to /usr/local/bin/jsc during installation - <http://webkit.org/b/129399> - <rdar://problem/16168734> - - * JavaScriptCore.xcodeproj/project.pbxproj: - (Create /usr/local/bin/jsc symlink): If a jsc symlink already - exists where we're about to create the symlink, remove the old - one first. - -2014-02-27 Michael Saboff <msaboff@apple.com> - - Unreviewed build fix for Mac tools after r164814 - - * Configurations/ToolExecutable.xcconfig: - - Added JavaScriptCore.framework/PrivateHeaders to ToolExecutable include path. - * JavaScriptCore.xcodeproj/project.pbxproj: - - Changed productName to testRegExp for testRegExp target. - -2014-02-27 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: JSContext inspection should report exceptions in the console - https://bugs.webkit.org/show_bug.cgi?id=128776 - - Reviewed by Timothy Hatcher. - - When JavaScript API functions have an exception, let the inspector - know so it can log the JavaScript and Native backtrace that caused - the exception. - - Include some clean up of ConsoleMessage and ScriptCallStack construction. - - * API/JSBase.cpp: - (JSEvaluateScript): - (JSCheckScriptSyntax): - * API/JSObjectRef.cpp: - (JSObjectMakeFunction): - (JSObjectMakeArray): - (JSObjectMakeDate): - (JSObjectMakeError): - (JSObjectMakeRegExp): - (JSObjectGetProperty): - (JSObjectSetProperty): - (JSObjectGetPropertyAtIndex): - (JSObjectSetPropertyAtIndex): - (JSObjectDeleteProperty): - (JSObjectCallAsFunction): - (JSObjectCallAsConstructor): - * API/JSValue.mm: - (reportExceptionToInspector): - (valueToArray): - (valueToDictionary): - * API/JSValueRef.cpp: - (JSValueIsEqual): - (JSValueIsInstanceOfConstructor): - (JSValueCreateJSONString): - (JSValueToNumber): - (JSValueToStringCopy): - (JSValueToObject): - When seeing an exception, let the inspector know there was an exception. - - * inspector/JSGlobalObjectInspectorController.h: - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - Log API exceptions by also grabbing the native backtrace. - - * inspector/ScriptCallStack.h: - * inspector/ScriptCallStack.cpp: - (Inspector::ScriptCallStack::firstNonNativeCallFrame): - (Inspector::ScriptCallStack::append): - Minor extensions to ScriptCallStack to make it easier to work with. - - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - Provide better default information if the first call frame was native. - - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::extractSourceInformationFromException): - (Inspector::createScriptCallStackFromException): - Perform the handling here of inserting a fake call frame for exceptions - if there was no call stack (e.g. a SyntaxError) or if the first call - frame had no information. - - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - * inspector/ConsoleMessage.h: - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::createScriptCallStackForConsole): - * inspector/ScriptCallStackFactory.h: - * inspector/agents/InspectorConsoleAgent.cpp: - (Inspector::InspectorConsoleAgent::enable): - (Inspector::InspectorConsoleAgent::addMessageToConsole): - (Inspector::InspectorConsoleAgent::count): - * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: - (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): - ConsoleMessage cleanup. - -2014-02-27 David Kilzer <ddkilzer@apple.com> - - Create symlink to /usr/local/bin/jsc during installation - <http://webkit.org/b/129399> - <rdar://problem/16168734> - - Reviewed by Dan Bernstein. - - * JavaScriptCore.xcodeproj/project.pbxproj: - - Add "Create /usr/local/bin/jsc symlink" build phase script to - create the symlink during installation. - -2014-02-27 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> - - Math.{max, min}() must not return after first NaN value - https://bugs.webkit.org/show_bug.cgi?id=104147 - - Reviewed by Oliver Hunt. - - According to the spec, ToNumber going to be called on each argument - even if a `NaN` value was already found - - * runtime/MathObject.cpp: - (JSC::mathProtoFuncMax): - (JSC::mathProtoFuncMin): - -2014-02-27 Gergo Balogh <gbalogh.u-szeged@partner.samsung.com> - - JSType upper limit (0xff) assertion can be removed. - https://bugs.webkit.org/show_bug.cgi?id=129424 - - Reviewed by Geoffrey Garen. - - * runtime/JSTypeInfo.h: - (JSC::TypeInfo::TypeInfo): - -2014-02-26 Michael Saboff <msaboff@apple.com> - - Auto generate bytecode information for bytecode parser and LLInt - https://bugs.webkit.org/show_bug.cgi?id=129181 - - Reviewed by Mark Lam. - - Added new bytecode/BytecodeList.json that contains a list of bytecodes and related - helpers. It also includes bytecode length and other information used to generate files. - Added a new generator, generate-bytecode-files that generates Bytecodes.h and InitBytecodes.asm - in DerivedSources/JavaScriptCore/. - - Added the generation of these files to the "DerivedSource" build step. - Slighty changed the build order, since the Bytecodes.h file is needed by - JSCLLIntOffsetsExtractor. Moved the offline assembly to a separate step since it needs - to be run after JSCLLIntOffsetsExtractor. - - Made related changes to OPCODE macros and their use. - - Added JavaScriptCore.framework/PrivateHeaders to header file search path for building - jsc to resolve Mac build issue. - - * CMakeLists.txt: - * Configurations/JSC.xcconfig: - * DerivedSources.make: - * GNUmakefile.am: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.vcxproj/copy-files.cmd: - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/Opcode.h: - (JSC::padOpcodeName): - * llint/LLIntCLoop.cpp: - (JSC::LLInt::CLoop::initialize): - * llint/LLIntCLoop.h: - * llint/LLIntData.cpp: - (JSC::LLInt::initialize): - * llint/LLIntOpcode.h: - * llint/LowLevelInterpreter.asm: - -2014-02-27 Julien Brianceau <jbriance@cisco.com> - - Fix 32-bit V_JITOperation_EJ callOperation introduced in r162652. - https://bugs.webkit.org/show_bug.cgi?id=129420 - - Reviewed by Geoffrey Garen. - - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::callOperation): Payload and tag are swapped. - Also, EABI_32BIT_DUMMY_ARG is missing for arm EABI and mips. - -2014-02-27 Filip Pizlo <fpizlo@apple.com> - - Octane/closure thrashes between flattening dictionaries during global object initialization in a global eval - https://bugs.webkit.org/show_bug.cgi?id=129435 - - Reviewed by Oliver Hunt. - - This is a 5-10% speed-up on Octane/closure. - - * interpreter/Interpreter.cpp: - (JSC::Interpreter::execute): - * jsc.cpp: - (GlobalObject::finishCreation): - (functionClearCodeCache): - * runtime/BatchedTransitionOptimizer.h: - (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): - (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer): - -2014-02-27 Alexey Proskuryakov <ap@apple.com> - - Added svn:ignore to two directories, so that .pyc files don't show up as unversioned. - - * inspector/scripts: Added property svn:ignore. - * replay/scripts: Added property svn:ignore. - -2014-02-27 Gabor Rapcsanyi <rgabor@webkit.org> - - r164764 broke the ARM build - https://bugs.webkit.org/show_bug.cgi?id=129415 - - Reviewed by Zoltan Herczeg. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::moveWithPatch): Change reinterpret_cast to static_cast. - (JSC::MacroAssemblerARM::canJumpReplacePatchableBranch32WithPatch): Add missing function. - (JSC::MacroAssemblerARM::startOfPatchableBranch32WithPatchOnAddress): Add missing function. - (JSC::MacroAssemblerARM::revertJumpReplacementToPatchableBranch32WithPatch): Add missing function. - -2014-02-27 Mark Hahnenberg <mhahnenberg@apple.com> - - r164764 broke the ARM build - https://bugs.webkit.org/show_bug.cgi?id=129415 - - Reviewed by Geoffrey Garen. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::moveWithPatch): - -2014-02-26 Mark Hahnenberg <mhahnenberg@apple.com> - - r164764 broke the ARM build - https://bugs.webkit.org/show_bug.cgi?id=129415 - - Reviewed by Geoffrey Garen. - - * assembler/MacroAssemblerARM.h: - (JSC::MacroAssemblerARM::branch32WithPatch): Missing this function. - -2014-02-26 Mark Hahnenberg <mhahnenberg@apple.com> - - EFL build fix - - * dfg/DFGSpeculativeJIT32_64.cpp: Remove unused variables. - (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): - -2014-02-25 Mark Hahnenberg <mhahnenberg@apple.com> - - Make JSCells have 32-bit Structure pointers - https://bugs.webkit.org/show_bug.cgi?id=123195 - - Reviewed by Filip Pizlo. - - This patch changes JSCells such that they no longer have a full 64-bit Structure - pointer in their header. Instead they now have a 32-bit index into - a per-VM table of Structure pointers. 32-bit platforms still use normal Structure - pointers. - - This change frees up an additional 32 bits of information in our object headers. - We then use this extra space to store the indexing type of the object, the JSType - of the object, some various type flags, and garbage collection data (e.g. mark bit). - Because this inline type information is now faster to read, it pays for the slowdown - incurred by having to perform an extra indirection through the StructureIDTable. - - This patch also threads a reference to the current VM through more of the C++ runtime - to offset the cost of having to look up the VM to get the actual Structure pointer. - - * API/JSContext.mm: - (-[JSContext setException:]): - (-[JSContext wrapperForObjCObject:]): - (-[JSContext wrapperForJSObject:]): - * API/JSContextRef.cpp: - (JSContextGroupRelease): - (JSGlobalContextRelease): - * API/JSObjectRef.cpp: - (JSObjectIsFunction): - (JSObjectCopyPropertyNames): - * API/JSValue.mm: - (containerValueToObject): - * API/JSWrapperMap.mm: - (tryUnwrapObjcObject): - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: - * JavaScriptCore.xcodeproj/project.pbxproj: - * assembler/AbstractMacroAssembler.h: - * assembler/MacroAssembler.h: - (JSC::MacroAssembler::patchableBranch32WithPatch): - (JSC::MacroAssembler::patchableBranch32): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::branchPtrWithPatch): - (JSC::MacroAssemblerARM64::patchableBranch32WithPatch): - (JSC::MacroAssemblerARM64::canJumpReplacePatchableBranch32WithPatch): - (JSC::MacroAssemblerARM64::startOfPatchableBranch32WithPatchOnAddress): - (JSC::MacroAssemblerARM64::revertJumpReplacementToPatchableBranch32WithPatch): - * assembler/MacroAssemblerARMv7.h: - (JSC::MacroAssemblerARMv7::store8): - (JSC::MacroAssemblerARMv7::branch32WithPatch): - (JSC::MacroAssemblerARMv7::patchableBranch32WithPatch): - (JSC::MacroAssemblerARMv7::canJumpReplacePatchableBranch32WithPatch): - (JSC::MacroAssemblerARMv7::startOfPatchableBranch32WithPatchOnAddress): - (JSC::MacroAssemblerARMv7::revertJumpReplacementToPatchableBranch32WithPatch): - * assembler/MacroAssemblerX86.h: - (JSC::MacroAssemblerX86::branch32WithPatch): - (JSC::MacroAssemblerX86::canJumpReplacePatchableBranch32WithPatch): - (JSC::MacroAssemblerX86::startOfPatchableBranch32WithPatchOnAddress): - (JSC::MacroAssemblerX86::revertJumpReplacementToPatchableBranch32WithPatch): - * assembler/MacroAssemblerX86_64.h: - (JSC::MacroAssemblerX86_64::store32): - (JSC::MacroAssemblerX86_64::moveWithPatch): - (JSC::MacroAssemblerX86_64::branch32WithPatch): - (JSC::MacroAssemblerX86_64::canJumpReplacePatchableBranch32WithPatch): - (JSC::MacroAssemblerX86_64::startOfBranch32WithPatchOnRegister): - (JSC::MacroAssemblerX86_64::startOfPatchableBranch32WithPatchOnAddress): - (JSC::MacroAssemblerX86_64::revertJumpReplacementToPatchableBranch32WithPatch): - * assembler/RepatchBuffer.h: - (JSC::RepatchBuffer::startOfPatchableBranch32WithPatchOnAddress): - (JSC::RepatchBuffer::revertJumpReplacementToPatchableBranch32WithPatch): - * assembler/X86Assembler.h: - (JSC::X86Assembler::revertJumpTo_movq_i64r): - (JSC::X86Assembler::revertJumpTo_movl_i32r): - * bytecode/ArrayProfile.cpp: - (JSC::ArrayProfile::computeUpdatedPrediction): - * bytecode/ArrayProfile.h: - (JSC::ArrayProfile::ArrayProfile): - (JSC::ArrayProfile::addressOfLastSeenStructureID): - (JSC::ArrayProfile::observeStructure): - * bytecode/CodeBlock.h: - (JSC::CodeBlock::heap): - * bytecode/UnlinkedCodeBlock.h: - * debugger/Debugger.h: - * dfg/DFGAbstractHeap.h: - * dfg/DFGArrayifySlowPathGenerator.h: - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGJITCompiler.h: - (JSC::DFG::JITCompiler::branchWeakStructure): - (JSC::DFG::JITCompiler::branchStructurePtr): - * dfg/DFGOSRExitCompiler32_64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompiler64.cpp: - (JSC::DFG::OSRExitCompiler::compileExit): - * dfg/DFGOSRExitCompilerCommon.cpp: - (JSC::DFG::osrWriteBarrier): - (JSC::DFG::adjustAndJumpToTarget): - * dfg/DFGOperations.cpp: - (JSC::DFG::putByVal): - * dfg/DFGSpeculativeJIT.cpp: - (JSC::DFG::SpeculativeJIT::checkArray): - (JSC::DFG::SpeculativeJIT::arrayify): - (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): - (JSC::DFG::SpeculativeJIT::compileInstanceOfForObject): - (JSC::DFG::SpeculativeJIT::compileInstanceOf): - (JSC::DFG::SpeculativeJIT::compileToStringOnCell): - (JSC::DFG::SpeculativeJIT::speculateObject): - (JSC::DFG::SpeculativeJIT::speculateFinalObject): - (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): - (JSC::DFG::SpeculativeJIT::speculateString): - (JSC::DFG::SpeculativeJIT::speculateStringObject): - (JSC::DFG::SpeculativeJIT::speculateStringOrStringObject): - (JSC::DFG::SpeculativeJIT::emitSwitchChar): - (JSC::DFG::SpeculativeJIT::emitSwitchString): - (JSC::DFG::SpeculativeJIT::genericWriteBarrier): - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGSpeculativeJIT.h: - (JSC::DFG::SpeculativeJIT::emitAllocateJSCell): - (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): - (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): - (JSC::DFG::SpeculativeJIT::compileObjectEquality): - (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): - (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): - (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): - (JSC::DFG::SpeculativeJIT::compileObjectEquality): - (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): - (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): - (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): - (JSC::DFG::SpeculativeJIT::compile): - (JSC::DFG::SpeculativeJIT::writeBarrier): - * dfg/DFGWorklist.cpp: - * ftl/FTLAbstractHeapRepository.cpp: - (JSC::FTL::AbstractHeapRepository::AbstractHeapRepository): - * ftl/FTLAbstractHeapRepository.h: - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileCheckStructure): - (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): - (JSC::FTL::LowerDFGToLLVM::compilePutStructure): - (JSC::FTL::LowerDFGToLLVM::compileToString): - (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): - (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): - (JSC::FTL::LowerDFGToLLVM::speculateTruthyObject): - (JSC::FTL::LowerDFGToLLVM::allocateCell): - (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): - (JSC::FTL::LowerDFGToLLVM::isObject): - (JSC::FTL::LowerDFGToLLVM::isString): - (JSC::FTL::LowerDFGToLLVM::isArrayType): - (JSC::FTL::LowerDFGToLLVM::hasClassInfo): - (JSC::FTL::LowerDFGToLLVM::isType): - (JSC::FTL::LowerDFGToLLVM::speculateStringOrStringObject): - (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForCell): - (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID): - (JSC::FTL::LowerDFGToLLVM::speculateNonNullObject): - (JSC::FTL::LowerDFGToLLVM::loadMarkByte): - (JSC::FTL::LowerDFGToLLVM::loadStructure): - (JSC::FTL::LowerDFGToLLVM::weakStructure): - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileStub): - * ftl/FTLOutput.h: - (JSC::FTL::Output::store8): - * heap/GCAssertions.h: - * heap/Heap.cpp: - (JSC::Heap::getConservativeRegisterRoots): - (JSC::Heap::collect): - (JSC::Heap::writeBarrier): - * heap/Heap.h: - (JSC::Heap::structureIDTable): - * heap/MarkedSpace.h: - (JSC::MarkedSpace::forEachBlock): - * heap/SlotVisitorInlines.h: - (JSC::SlotVisitor::internalAppend): - * jit/AssemblyHelpers.h: - (JSC::AssemblyHelpers::branchIfCellNotObject): - (JSC::AssemblyHelpers::genericWriteBarrier): - (JSC::AssemblyHelpers::emitLoadStructure): - (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): - * jit/JIT.h: - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - (JSC::JIT::privateCompileClosureCall): - * jit/JITCall32_64.cpp: - (JSC::JIT::emit_op_ret_object_or_this): - (JSC::JIT::compileOpCall): - (JSC::JIT::privateCompileClosureCall): - * jit/JITInlineCacheGenerator.cpp: - (JSC::JITByIdGenerator::generateFastPathChecks): - * jit/JITInlineCacheGenerator.h: - * jit/JITInlines.h: - (JSC::JIT::emitLoadCharacterString): - (JSC::JIT::checkStructure): - (JSC::JIT::emitJumpIfCellNotObject): - (JSC::JIT::emitAllocateJSObject): - (JSC::JIT::emitArrayProfilingSiteWithCell): - (JSC::JIT::emitArrayProfilingSiteForBytecodeIndexWithCell): - (JSC::JIT::branchStructure): - (JSC::branchStructure): - * jit/JITOpcodes.cpp: - (JSC::JIT::emit_op_check_has_instance): - (JSC::JIT::emit_op_instanceof): - (JSC::JIT::emit_op_is_undefined): - (JSC::JIT::emit_op_is_string): - (JSC::JIT::emit_op_ret_object_or_this): - (JSC::JIT::emit_op_to_primitive): - (JSC::JIT::emit_op_jeq_null): - (JSC::JIT::emit_op_jneq_null): - (JSC::JIT::emit_op_get_pnames): - (JSC::JIT::emit_op_next_pname): - (JSC::JIT::emit_op_eq_null): - (JSC::JIT::emit_op_neq_null): - (JSC::JIT::emit_op_to_this): - (JSC::JIT::emitSlow_op_to_this): - * jit/JITOpcodes32_64.cpp: - (JSC::JIT::emit_op_check_has_instance): - (JSC::JIT::emit_op_instanceof): - (JSC::JIT::emit_op_is_undefined): - (JSC::JIT::emit_op_is_string): - (JSC::JIT::emit_op_to_primitive): - (JSC::JIT::emit_op_jeq_null): - (JSC::JIT::emit_op_jneq_null): - (JSC::JIT::emitSlow_op_eq): - (JSC::JIT::emitSlow_op_neq): - (JSC::JIT::compileOpStrictEq): - (JSC::JIT::emit_op_eq_null): - (JSC::JIT::emit_op_neq_null): - (JSC::JIT::emit_op_get_pnames): - (JSC::JIT::emit_op_next_pname): - (JSC::JIT::emit_op_to_this): - * jit/JITOperations.cpp: - * jit/JITPropertyAccess.cpp: - (JSC::JIT::stringGetByValStubGenerator): - (JSC::JIT::emit_op_get_by_val): - (JSC::JIT::emitSlow_op_get_by_val): - (JSC::JIT::emit_op_get_by_pname): - (JSC::JIT::emit_op_put_by_val): - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emitLoadWithStructureCheck): - (JSC::JIT::emitSlow_op_get_from_scope): - (JSC::JIT::emitSlow_op_put_to_scope): - (JSC::JIT::checkMarkWord): - (JSC::JIT::emitWriteBarrier): - (JSC::JIT::addStructureTransitionCheck): - (JSC::JIT::emitIntTypedArrayGetByVal): - (JSC::JIT::emitFloatTypedArrayGetByVal): - (JSC::JIT::emitIntTypedArrayPutByVal): - (JSC::JIT::emitFloatTypedArrayPutByVal): - * jit/JITPropertyAccess32_64.cpp: - (JSC::JIT::stringGetByValStubGenerator): - (JSC::JIT::emit_op_get_by_val): - (JSC::JIT::emitSlow_op_get_by_val): - (JSC::JIT::emit_op_put_by_val): - (JSC::JIT::emit_op_get_by_id): - (JSC::JIT::emit_op_get_by_pname): - (JSC::JIT::emitLoadWithStructureCheck): - * jit/JSInterfaceJIT.h: - (JSC::JSInterfaceJIT::emitJumpIfNotType): - * jit/Repatch.cpp: - (JSC::repatchByIdSelfAccess): - (JSC::addStructureTransitionCheck): - (JSC::replaceWithJump): - (JSC::generateProtoChainAccessStub): - (JSC::tryCacheGetByID): - (JSC::tryBuildGetByIDList): - (JSC::writeBarrier): - (JSC::emitPutReplaceStub): - (JSC::emitPutTransitionStub): - (JSC::tryBuildPutByIdList): - (JSC::tryRepatchIn): - (JSC::linkClosureCall): - (JSC::resetGetByID): - (JSC::resetPutByID): - * jit/SpecializedThunkJIT.h: - (JSC::SpecializedThunkJIT::loadJSStringArgument): - (JSC::SpecializedThunkJIT::loadArgumentWithSpecificClass): - * jit/ThunkGenerators.cpp: - (JSC::virtualForThunkGenerator): - (JSC::arrayIteratorNextThunkGenerator): - * jit/UnusedPointer.h: - * llint/LowLevelInterpreter.asm: - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: - * runtime/Arguments.cpp: - (JSC::Arguments::createStrictModeCallerIfNecessary): - (JSC::Arguments::createStrictModeCalleeIfNecessary): - * runtime/Arguments.h: - (JSC::Arguments::createStructure): - * runtime/ArrayPrototype.cpp: - (JSC::shift): - (JSC::unshift): - (JSC::arrayProtoFuncToString): - (JSC::arrayProtoFuncPop): - (JSC::arrayProtoFuncReverse): - (JSC::performSlowSort): - (JSC::arrayProtoFuncSort): - (JSC::arrayProtoFuncSplice): - (JSC::arrayProtoFuncUnShift): - * runtime/CommonSlowPaths.cpp: - (JSC::SLOW_PATH_DECL): - * runtime/Executable.h: - (JSC::ExecutableBase::isFunctionExecutable): - (JSC::ExecutableBase::clearCodeVirtual): - (JSC::ScriptExecutable::unlinkCalls): - * runtime/GetterSetter.cpp: - (JSC::callGetter): - (JSC::callSetter): - * runtime/InitializeThreading.cpp: - * runtime/JSArray.cpp: - (JSC::JSArray::unshiftCountSlowCase): - (JSC::JSArray::setLength): - (JSC::JSArray::pop): - (JSC::JSArray::push): - (JSC::JSArray::shiftCountWithArrayStorage): - (JSC::JSArray::shiftCountWithAnyIndexingType): - (JSC::JSArray::unshiftCountWithArrayStorage): - (JSC::JSArray::unshiftCountWithAnyIndexingType): - (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/JSCJSValueInlines.h: - (JSC::JSValue::toThis): - (JSC::JSValue::put): - (JSC::JSValue::putByIndex): - (JSC::JSValue::equalSlowCaseInline): - * runtime/JSCell.cpp: - (JSC::JSCell::put): - (JSC::JSCell::putByIndex): - (JSC::JSCell::deleteProperty): - (JSC::JSCell::deletePropertyByIndex): - * runtime/JSCell.h: - (JSC::JSCell::clearStructure): - (JSC::JSCell::mark): - (JSC::JSCell::isMarked): - (JSC::JSCell::structureIDOffset): - (JSC::JSCell::typeInfoFlagsOffset): - (JSC::JSCell::typeInfoTypeOffset): - (JSC::JSCell::indexingTypeOffset): - (JSC::JSCell::gcDataOffset): - * runtime/JSCellInlines.h: - (JSC::JSCell::JSCell): - (JSC::JSCell::finishCreation): - (JSC::JSCell::type): - (JSC::JSCell::indexingType): - (JSC::JSCell::structure): - (JSC::JSCell::visitChildren): - (JSC::JSCell::isObject): - (JSC::JSCell::isString): - (JSC::JSCell::isGetterSetter): - (JSC::JSCell::isProxy): - (JSC::JSCell::isAPIValueWrapper): - (JSC::JSCell::setStructure): - (JSC::JSCell::methodTable): - (JSC::Heap::writeBarrier): - * runtime/JSDataView.cpp: - (JSC::JSDataView::createStructure): - * runtime/JSDestructibleObject.h: - (JSC::JSCell::classInfo): - * runtime/JSFunction.cpp: - (JSC::JSFunction::getOwnNonIndexPropertyNames): - (JSC::JSFunction::put): - (JSC::JSFunction::defineOwnProperty): - * runtime/JSGenericTypedArrayView.h: - (JSC::JSGenericTypedArrayView::createStructure): - * runtime/JSObject.cpp: - (JSC::getCallableObjectSlow): - (JSC::JSObject::copyButterfly): - (JSC::JSObject::visitButterfly): - (JSC::JSFinalObject::visitChildren): - (JSC::JSObject::getOwnPropertySlotByIndex): - (JSC::JSObject::put): - (JSC::JSObject::putByIndex): - (JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists): - (JSC::JSObject::enterDictionaryIndexingMode): - (JSC::JSObject::notifyPresenceOfIndexedAccessors): - (JSC::JSObject::createInitialIndexedStorage): - (JSC::JSObject::createInitialUndecided): - (JSC::JSObject::createInitialInt32): - (JSC::JSObject::createInitialDouble): - (JSC::JSObject::createInitialContiguous): - (JSC::JSObject::createArrayStorage): - (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::genericConvertDoubleToContiguous): - (JSC::JSObject::convertDoubleToArrayStorage): - (JSC::JSObject::convertContiguousToArrayStorage): - (JSC::JSObject::ensureInt32Slow): - (JSC::JSObject::ensureDoubleSlow): - (JSC::JSObject::ensureContiguousSlow): - (JSC::JSObject::ensureArrayStorageSlow): - (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode): - (JSC::JSObject::switchToSlowPutArrayStorage): - (JSC::JSObject::setPrototype): - (JSC::JSObject::setPrototypeWithCycleCheck): - (JSC::JSObject::putDirectNonIndexAccessor): - (JSC::JSObject::deleteProperty): - (JSC::JSObject::hasOwnProperty): - (JSC::JSObject::deletePropertyByIndex): - (JSC::JSObject::getPrimitiveNumber): - (JSC::JSObject::hasInstance): - (JSC::JSObject::getPropertySpecificValue): - (JSC::JSObject::getPropertyNames): - (JSC::JSObject::getOwnPropertyNames): - (JSC::JSObject::getOwnNonIndexPropertyNames): - (JSC::JSObject::seal): - (JSC::JSObject::freeze): - (JSC::JSObject::preventExtensions): - (JSC::JSObject::reifyStaticFunctionsForDelete): - (JSC::JSObject::removeDirect): - (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes): - (JSC::JSObject::putByIndexBeyondVectorLength): - (JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage): - (JSC::JSObject::putDirectIndexBeyondVectorLength): - (JSC::JSObject::getNewVectorLength): - (JSC::JSObject::countElements): - (JSC::JSObject::increaseVectorLength): - (JSC::JSObject::ensureLengthSlow): - (JSC::JSObject::growOutOfLineStorage): - (JSC::JSObject::getOwnPropertyDescriptor): - (JSC::putDescriptor): - (JSC::JSObject::defineOwnNonIndexProperty): - * runtime/JSObject.h: - (JSC::getJSFunction): - (JSC::JSObject::getArrayLength): - (JSC::JSObject::getVectorLength): - (JSC::JSObject::putByIndexInline): - (JSC::JSObject::canGetIndexQuickly): - (JSC::JSObject::getIndexQuickly): - (JSC::JSObject::tryGetIndexQuickly): - (JSC::JSObject::getDirectIndex): - (JSC::JSObject::canSetIndexQuickly): - (JSC::JSObject::canSetIndexQuicklyForPutDirect): - (JSC::JSObject::setIndexQuickly): - (JSC::JSObject::initializeIndex): - (JSC::JSObject::hasSparseMap): - (JSC::JSObject::inSparseIndexingMode): - (JSC::JSObject::getDirect): - (JSC::JSObject::getDirectOffset): - (JSC::JSObject::isSealed): - (JSC::JSObject::isFrozen): - (JSC::JSObject::flattenDictionaryObject): - (JSC::JSObject::ensureInt32): - (JSC::JSObject::ensureDouble): - (JSC::JSObject::ensureContiguous): - (JSC::JSObject::rageEnsureContiguous): - (JSC::JSObject::ensureArrayStorage): - (JSC::JSObject::arrayStorage): - (JSC::JSObject::arrayStorageOrNull): - (JSC::JSObject::ensureLength): - (JSC::JSObject::currentIndexingData): - (JSC::JSObject::getHolyIndexQuickly): - (JSC::JSObject::currentRelevantLength): - (JSC::JSObject::isGlobalObject): - (JSC::JSObject::isVariableObject): - (JSC::JSObject::isStaticScopeObject): - (JSC::JSObject::isNameScopeObject): - (JSC::JSObject::isActivationObject): - (JSC::JSObject::isErrorInstance): - (JSC::JSObject::inlineGetOwnPropertySlot): - (JSC::JSObject::fastGetOwnPropertySlot): - (JSC::JSObject::getPropertySlot): - (JSC::JSObject::putDirectInternal): - (JSC::JSObject::setStructureAndReallocateStorageIfNecessary): - * runtime/JSPropertyNameIterator.h: - (JSC::JSPropertyNameIterator::createStructure): - * runtime/JSProxy.cpp: - (JSC::JSProxy::getOwnPropertySlot): - (JSC::JSProxy::getOwnPropertySlotByIndex): - (JSC::JSProxy::put): - (JSC::JSProxy::putByIndex): - (JSC::JSProxy::defineOwnProperty): - (JSC::JSProxy::deleteProperty): - (JSC::JSProxy::deletePropertyByIndex): - (JSC::JSProxy::getPropertyNames): - (JSC::JSProxy::getOwnPropertyNames): - * runtime/JSScope.cpp: - (JSC::JSScope::objectAtScope): - * runtime/JSString.h: - (JSC::JSString::createStructure): - (JSC::isJSString): - * runtime/JSType.h: - * runtime/JSTypeInfo.h: - (JSC::TypeInfo::TypeInfo): - (JSC::TypeInfo::isObject): - (JSC::TypeInfo::structureIsImmortal): - (JSC::TypeInfo::zeroedGCDataOffset): - (JSC::TypeInfo::inlineTypeFlags): - * runtime/MapData.h: - * runtime/ObjectConstructor.cpp: - (JSC::objectConstructorGetOwnPropertyNames): - (JSC::objectConstructorKeys): - (JSC::objectConstructorDefineProperty): - (JSC::defineProperties): - (JSC::objectConstructorSeal): - (JSC::objectConstructorFreeze): - (JSC::objectConstructorIsSealed): - (JSC::objectConstructorIsFrozen): - * runtime/ObjectPrototype.cpp: - (JSC::objectProtoFuncDefineGetter): - (JSC::objectProtoFuncDefineSetter): - (JSC::objectProtoFuncToString): - * runtime/Operations.cpp: - (JSC::jsTypeStringForValue): - (JSC::jsIsObjectType): - * runtime/Operations.h: - (JSC::normalizePrototypeChainForChainAccess): - (JSC::normalizePrototypeChain): - * runtime/PropertyMapHashTable.h: - (JSC::PropertyTable::createStructure): - * runtime/RegExp.h: - (JSC::RegExp::createStructure): - * runtime/SparseArrayValueMap.h: - * runtime/Structure.cpp: - (JSC::Structure::Structure): - (JSC::Structure::~Structure): - (JSC::Structure::prototypeChainMayInterceptStoreTo): - * runtime/Structure.h: - (JSC::Structure::id): - (JSC::Structure::idBlob): - (JSC::Structure::objectInitializationFields): - (JSC::Structure::structureIDOffset): - * runtime/StructureChain.h: - (JSC::StructureChain::createStructure): - * runtime/StructureIDTable.cpp: Added. - (JSC::StructureIDTable::StructureIDTable): - (JSC::StructureIDTable::~StructureIDTable): - (JSC::StructureIDTable::resize): - (JSC::StructureIDTable::flushOldTables): - (JSC::StructureIDTable::allocateID): - (JSC::StructureIDTable::deallocateID): - * runtime/StructureIDTable.h: Added. - (JSC::StructureIDTable::base): - (JSC::StructureIDTable::get): - * runtime/SymbolTable.h: - * runtime/TypedArrayType.cpp: - (JSC::typeForTypedArrayType): - * runtime/TypedArrayType.h: - * runtime/WeakMapData.h: - -2014-02-26 Mark Hahnenberg <mhahnenberg@apple.com> - - Unconditional logging in compileFTLOSRExit - https://bugs.webkit.org/show_bug.cgi?id=129407 - - Reviewed by Michael Saboff. - - This was causing tests to fail with the FTL enabled. - - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileFTLOSRExit): - -2014-02-26 Oliver Hunt <oliver@apple.com> - - Remove unused access types - https://bugs.webkit.org/show_bug.cgi?id=129385 - - Reviewed by Filip Pizlo. - - Remove unused cruft. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::printGetByIdCacheStatus): - * bytecode/StructureStubInfo.cpp: - (JSC::StructureStubInfo::deref): - * bytecode/StructureStubInfo.h: - (JSC::isGetByIdAccess): - (JSC::isPutByIdAccess): - -2014-02-26 Oliver Hunt <oliver@apple.com> - - Function.prototype.apply has a bad time with the spread operator - https://bugs.webkit.org/show_bug.cgi?id=129381 - - Reviewed by Mark Hahnenberg. - - Make sure our apply logic handle the spread operator correctly. - To do this we simply emit the enumeration logic that we'd normally - use for other enumerations, but only store the first two results - to registers. Then perform a varargs call. - - * bytecompiler/NodesCodegen.cpp: - (JSC::ApplyFunctionCallDotNode::emitBytecode): - -2014-02-26 Mark Lam <mark.lam@apple.com> - - Compilation policy management belongs in operationOptimize(), not the DFG Driver. - <https://webkit.org/b/129355> - - Reviewed by Filip Pizlo. - - By compilation policy, I mean the rules for determining whether to - compile, when to compile, when to attempt compilation again, etc. The - few of these policy decisions that were previously being made in the - DFG driver are now moved to operationOptimize() where we keep the rest - of the policy logic. Decisions that are based on the capabilities - supported by the DFG are moved to DFG capabiliityLevel(). - - I've run the following benchmarks: - 1. the collection of jsc benchmarks on the jsc executable vs. its - baseline. - 2. Octane 2.0 in browser without the WebInspector. - 3. Octane 2.0 in browser with the WebInspector open and a breakpoint - set somewhere where it won't break. - - In all of these, the results came out to be a wash as expected. - - * dfg/DFGCapabilities.cpp: - (JSC::DFG::isSupported): - (JSC::DFG::mightCompileEval): - (JSC::DFG::mightCompileProgram): - (JSC::DFG::mightCompileFunctionForCall): - (JSC::DFG::mightCompileFunctionForConstruct): - (JSC::DFG::mightInlineFunctionForCall): - (JSC::DFG::mightInlineFunctionForClosureCall): - (JSC::DFG::mightInlineFunctionForConstruct): - * dfg/DFGCapabilities.h: - * dfg/DFGDriver.cpp: - (JSC::DFG::compileImpl): - * jit/JITOperations.cpp: - -2014-02-26 Mark Lam <mark.lam@apple.com> - - ASSERTION FAILED: m_heap->vm()->currentThreadIsHoldingAPILock() in inspector-protocol/*. - <https://webkit.org/b/129364> - - Reviewed by Alexey Proskuryakov. - - InjectedScriptModule::ensureInjected() needs an APIEntryShim. - - * inspector/InjectedScriptModule.cpp: - (Inspector::InjectedScriptModule::ensureInjected): - - Added the needed but missing APIEntryShim. - -2014-02-25 Mark Lam <mark.lam@apple.com> - - Web Inspector: CRASH when evaluating in console of JSContext RWI with disabled breakpoints. - <https://webkit.org/b/128766> - - Reviewed by Geoffrey Garen. - - Make the JSLock::grabAllLocks() work the same way as for the C loop LLINT. - The reasoning is that we don't know of any clients that need unordered - re-entry into the VM from different threads. So, we're enforcing ordered - re-entry i.e. we must re-grab locks in the reverse order of dropping locks. - - The crash in this bug happened because we were allowing unordered re-entry, - and the following type of scenario occurred: - - 1. Thread T1 locks the VM, and enters the VM to execute some JS code. - 2. On entry, T1 detects that VM::m_entryScope is null i.e. this is the - first time it entered the VM. - T1 sets VM::m_entryScope to T1's entryScope. - 3. T1 drops all locks. - - 4. Thread T2 locks the VM, and enters the VM to execute some JS code. - On entry, T2 sees that VM::m_entryScope is NOT null, and therefore - does not set the entryScope. - 5. T2 drops all locks. - - 6. T1 re-grabs locks. - 7. T1 returns all the way out of JS code. On exit from the outer most - JS function, T1 clears VM::m_entryScope (because T1 was the one who - set it). - 8. T1 unlocks the VM. - - 9. T2 re-grabs locks. - 10. T2 proceeds to execute some code and expects VM::m_entryScope to be - NOT null, but it turns out to be null. Assertion failures and - crashes ensue. - - With ordered re-entry, at step 6, T1 will loop and yield until T2 exits - the VM. Hence, the issue will no longer manifest. - - * runtime/JSLock.cpp: - (JSC::JSLock::dropAllLocks): - (JSC::JSLock::grabAllLocks): - * runtime/JSLock.h: - (JSC::JSLock::DropAllLocks::dropDepth): - -2014-02-25 Mark Lam <mark.lam@apple.com> - - Need to initialize VM stack data even when the VM is on an exclusive thread. - <https://webkit.org/b/129265> - - Not reviewed. - - Relanding r164627 now that <https://webkit.org/b/129341> is fixed. - - * API/APIShims.h: - (JSC::APIEntryShim::APIEntryShim): - (JSC::APICallbackShim::shouldDropAllLocks): - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::addCurrentThread): - * runtime/JSLock.cpp: - (JSC::JSLockHolder::JSLockHolder): - (JSC::JSLockHolder::init): - (JSC::JSLockHolder::~JSLockHolder): - (JSC::JSLock::JSLock): - (JSC::JSLock::setExclusiveThread): - (JSC::JSLock::lock): - (JSC::JSLock::unlock): - (JSC::JSLock::currentThreadIsHoldingLock): - (JSC::JSLock::dropAllLocks): - (JSC::JSLock::grabAllLocks): - * runtime/JSLock.h: - (JSC::JSLock::hasExclusiveThread): - (JSC::JSLock::exclusiveThread): - * runtime/VM.cpp: - (JSC::VM::VM): - * runtime/VM.h: - (JSC::VM::hasExclusiveThread): - (JSC::VM::exclusiveThread): - (JSC::VM::setExclusiveThread): - (JSC::VM::currentThreadIsHoldingAPILock): - -2014-02-25 Filip Pizlo <fpizlo@apple.com> - - Inline caching in the FTL on ARM64 should "work" - https://bugs.webkit.org/show_bug.cgi?id=129334 - - Reviewed by Mark Hahnenberg. - - Gets us to the point where simple tests that use inline caching are passing. - - * assembler/LinkBuffer.cpp: - (JSC::LinkBuffer::copyCompactAndLinkCode): - (JSC::LinkBuffer::shrink): - * ftl/FTLInlineCacheSize.cpp: - (JSC::FTL::sizeOfGetById): - (JSC::FTL::sizeOfPutById): - (JSC::FTL::sizeOfCall): - * ftl/FTLOSRExitCompiler.cpp: - (JSC::FTL::compileFTLOSRExit): - * ftl/FTLThunks.cpp: - (JSC::FTL::osrExitGenerationThunkGenerator): - * jit/GPRInfo.h: - * offlineasm/arm64.rb: - -2014-02-25 Commit Queue <commit-queue@webkit.org> - - Unreviewed, rolling out r164627. - http://trac.webkit.org/changeset/164627 - https://bugs.webkit.org/show_bug.cgi?id=129325 - - Broke SubtleCrypto tests (Requested by ap on #webkit). - - * API/APIShims.h: - (JSC::APIEntryShim::APIEntryShim): - (JSC::APICallbackShim::shouldDropAllLocks): - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::addCurrentThread): - * runtime/JSLock.cpp: - (JSC::JSLockHolder::JSLockHolder): - (JSC::JSLockHolder::init): - (JSC::JSLockHolder::~JSLockHolder): - (JSC::JSLock::JSLock): - (JSC::JSLock::lock): - (JSC::JSLock::unlock): - (JSC::JSLock::currentThreadIsHoldingLock): - (JSC::JSLock::dropAllLocks): - (JSC::JSLock::grabAllLocks): - * runtime/JSLock.h: - * runtime/VM.cpp: - (JSC::VM::VM): - * runtime/VM.h: - (JSC::VM::currentThreadIsHoldingAPILock): - -2014-02-25 Filip Pizlo <fpizlo@apple.com> - - ARM64 rshift64 should be an arithmetic shift - https://bugs.webkit.org/show_bug.cgi?id=129323 - - Reviewed by Mark Hahnenberg. - - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::rshift64): - -2014-02-25 Sergio Villar Senin <svillar@igalia.com> - - [CSS Grid Layout] Add ENABLE flag - https://bugs.webkit.org/show_bug.cgi?id=129153 - - Reviewed by Simon Fraser. - - * Configurations/FeatureDefines.xcconfig: added ENABLE_CSS_GRID_LAYOUT feature flag. - -2014-02-25 Michael Saboff <msaboff@apple.com> - - JIT Engines use the wrong stack limit for stack checks - https://bugs.webkit.org/show_bug.cgi?id=129314 - - Reviewed by Filip Pizlo. - - Change the Baseline and DFG code to use VM::m_stackLimit for stack limit checks. - - * dfg/DFGJITCompiler.cpp: - (JSC::DFG::JITCompiler::compileFunction): - * jit/JIT.cpp: - (JSC::JIT::privateCompile): - * jit/JITCall.cpp: - (JSC::JIT::compileLoadVarargs): - * jit/JITCall32_64.cpp: - (JSC::JIT::compileLoadVarargs): - * runtime/VM.h: - (JSC::VM::addressOfStackLimit): - -2014-02-25 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, roll out http://trac.webkit.org/changeset/164493. - - It causes crashes, apparently because it's removing too many barriers. I will investigate - later. - - * bytecode/SpeculatedType.cpp: - (JSC::speculationToAbbreviatedString): - * bytecode/SpeculatedType.h: - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::insertStoreBarrier): - * dfg/DFGNode.h: - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): - (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): - (JSC::FTL::LowerDFGToLLVM::isNotNully): - (JSC::FTL::LowerDFGToLLVM::isNully): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): - (JSC::FTL::LowerDFGToLLVM::speculateNotCell): - -2014-02-24 Oliver Hunt <oliver@apple.com> - - Fix build. - - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): - -2014-02-24 Oliver Hunt <oliver@apple.com> - - Spread operator has a bad time when applied to call function - https://bugs.webkit.org/show_bug.cgi?id=128853 - - Reviewed by Geoffrey Garen. - - Follow on from the previous patch the added an extra slot to - op_call_varargs (and _call, _call_eval, _construct). We now - use the slot as an offset to in effect act as a 'slice' on - the spread subject. This allows us to automatically retain - all our existing argument and array optimisatons. Most of - this patch is simply threading the offset around. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::dumpBytecode): - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::emitCall): - (JSC::BytecodeGenerator::emitCallVarargs): - * bytecompiler/BytecodeGenerator.h: - * bytecompiler/NodesCodegen.cpp: - (JSC::getArgumentByVal): - (JSC::CallFunctionCallDotNode::emitBytecode): - (JSC::ApplyFunctionCallDotNode::emitBytecode): - * interpreter/Interpreter.cpp: - (JSC::sizeFrameForVarargs): - (JSC::loadVarargs): - * interpreter/Interpreter.h: - * jit/CCallHelpers.h: - (JSC::CCallHelpers::setupArgumentsWithExecState): - * jit/JIT.h: - * jit/JITCall.cpp: - (JSC::JIT::compileLoadVarargs): - * jit/JITInlines.h: - (JSC::JIT::callOperation): - * jit/JITOperations.cpp: - * jit/JITOperations.h: - * llint/LLIntSlowPaths.cpp: - (JSC::LLInt::LLINT_SLOW_PATH_DECL): - * runtime/Arguments.cpp: - (JSC::Arguments::copyToArguments): - * runtime/Arguments.h: - * runtime/JSArray.cpp: - (JSC::JSArray::copyToArguments): - * runtime/JSArray.h: - -2014-02-24 Mark Lam <mark.lam@apple.com> - - Need to initialize VM stack data even when the VM is on an exclusive thread. - <https://webkit.org/b/129265> - - Reviewed by Geoffrey Garen. - - We check VM::exclusiveThread as an optimization to forego the need to do - JSLock locking. However, we recently started piggy backing on JSLock's - lock() and unlock() to initialize VM stack data (stackPointerAtVMEntry - and lastStackTop) to appropriate values for the current thread. This is - needed because we may be acquiring the lock to enter the VM on a different - thread. - - As a result, we ended up not initializing the VM stack data when - VM::exclusiveThread causes us to bypass the locking activity. Even though - the VM::exclusiveThread will not have to deal with the VM being entered - on a different thread, it still needs to initialize the VM stack data. - The VM relies on that data being initialized properly once it has been - entered. - - With this fix, we push the check for exclusiveThread down into the JSLock, - and handle the bypassing of unneeded locking activity there while still - executing the necessary the VM stack data initialization. - - * API/APIShims.h: - (JSC::APIEntryShim::APIEntryShim): - (JSC::APICallbackShim::shouldDropAllLocks): - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::addCurrentThread): - * runtime/JSLock.cpp: - (JSC::JSLockHolder::JSLockHolder): - (JSC::JSLockHolder::init): - (JSC::JSLockHolder::~JSLockHolder): - (JSC::JSLock::JSLock): - (JSC::JSLock::setExclusiveThread): - (JSC::JSLock::lock): - (JSLock::unlock): - (JSLock::currentThreadIsHoldingLock): - (JSLock::dropAllLocks): - (JSLock::grabAllLocks): - * runtime/JSLock.h: - (JSC::JSLock::exclusiveThread): - * runtime/VM.cpp: - (JSC::VM::VM): - * runtime/VM.h: - (JSC::VM::exclusiveThread): - (JSC::VM::setExclusiveThread): - (JSC::VM::currentThreadIsHoldingAPILock): - -2014-02-24 Filip Pizlo <fpizlo@apple.com> - - FTL should do polymorphic PutById inlining - https://bugs.webkit.org/show_bug.cgi?id=129210 - - Reviewed by Mark Hahnenberg and Oliver Hunt. - - This makes PutByIdStatus inform us about polymorphic cases by returning an array of - PutByIdVariants. The DFG now has a node called MultiPutByOffset that indicates a - selection of multiple inlined PutByIdVariants. - - MultiPutByOffset is almost identical to MultiGetByOffset, which we added in - http://trac.webkit.org/changeset/164207. - - This also does some FTL refactoring to make MultiPutByOffset share code with some nodes - that generate similar code. - - 1% speed-up on V8v7 due to splay improving by 6.8%. Splay does the thing where it - sometimes swaps field insertion order, creating fake polymorphism. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * bytecode/PutByIdStatus.cpp: - (JSC::PutByIdStatus::computeFromLLInt): - (JSC::PutByIdStatus::computeFor): - (JSC::PutByIdStatus::computeForStubInfo): - (JSC::PutByIdStatus::dump): - * bytecode/PutByIdStatus.h: - (JSC::PutByIdStatus::PutByIdStatus): - (JSC::PutByIdStatus::isSimple): - (JSC::PutByIdStatus::numVariants): - (JSC::PutByIdStatus::variants): - (JSC::PutByIdStatus::at): - (JSC::PutByIdStatus::operator[]): - * bytecode/PutByIdVariant.cpp: Added. - (JSC::PutByIdVariant::dump): - (JSC::PutByIdVariant::dumpInContext): - * bytecode/PutByIdVariant.h: Added. - (JSC::PutByIdVariant::PutByIdVariant): - (JSC::PutByIdVariant::replace): - (JSC::PutByIdVariant::transition): - (JSC::PutByIdVariant::kind): - (JSC::PutByIdVariant::isSet): - (JSC::PutByIdVariant::operator!): - (JSC::PutByIdVariant::structure): - (JSC::PutByIdVariant::oldStructure): - (JSC::PutByIdVariant::newStructure): - (JSC::PutByIdVariant::structureChain): - (JSC::PutByIdVariant::offset): - * dfg/DFGAbstractInterpreterInlines.h: - (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::emitPrototypeChecks): - (JSC::DFG::ByteCodeParser::handleGetById): - (JSC::DFG::ByteCodeParser::emitPutById): - (JSC::DFG::ByteCodeParser::handlePutById): - (JSC::DFG::ByteCodeParser::parseBlock): - * dfg/DFGCSEPhase.cpp: - (JSC::DFG::CSEPhase::checkStructureElimination): - (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): - (JSC::DFG::CSEPhase::putStructureStoreElimination): - (JSC::DFG::CSEPhase::getByOffsetLoadElimination): - (JSC::DFG::CSEPhase::putByOffsetStoreElimination): - * dfg/DFGClobberize.h: - (JSC::DFG::clobberize): - * dfg/DFGConstantFoldingPhase.cpp: - (JSC::DFG::ConstantFoldingPhase::foldConstants): - (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - * dfg/DFGGraph.cpp: - (JSC::DFG::Graph::dump): - * dfg/DFGGraph.h: - * dfg/DFGNode.cpp: - (JSC::DFG::MultiPutByOffsetData::writesStructures): - (JSC::DFG::MultiPutByOffsetData::reallocatesStorage): - * dfg/DFGNode.h: - (JSC::DFG::Node::convertToPutByOffset): - (JSC::DFG::Node::hasMultiPutByOffsetData): - (JSC::DFG::Node::multiPutByOffsetData): - * dfg/DFGNodeType.h: - * dfg/DFGPredictionPropagationPhase.cpp: - (JSC::DFG::PredictionPropagationPhase::propagate): - * dfg/DFGSafeToExecute.h: - (JSC::DFG::safeToExecute): - * dfg/DFGSpeculativeJIT32_64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGSpeculativeJIT64.cpp: - (JSC::DFG::SpeculativeJIT::compile): - * dfg/DFGTypeCheckHoistingPhase.cpp: - (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): - (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileNode): - (JSC::FTL::LowerDFGToLLVM::compilePutStructure): - (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage): - (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage): - (JSC::FTL::LowerDFGToLLVM::compileGetByOffset): - (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): - (JSC::FTL::LowerDFGToLLVM::compilePutByOffset): - (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): - (JSC::FTL::LowerDFGToLLVM::loadProperty): - (JSC::FTL::LowerDFGToLLVM::storeProperty): - (JSC::FTL::LowerDFGToLLVM::addressOfProperty): - (JSC::FTL::LowerDFGToLLVM::storageForTransition): - (JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage): - (JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage): - (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): - * tests/stress/fold-multi-put-by-offset-to-put-by-offset.js: Added. - * tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js: Added. - * tests/stress/multi-put-by-offset-reallocation-cases.js: Added. - -2014-02-24 peavo@outlook.com <peavo@outlook.com> - - JSC regressions after r164494 - https://bugs.webkit.org/show_bug.cgi?id=129272 - - Reviewed by Mark Lam. - - * offlineasm/x86.rb: Only avoid reverse opcode (fdivr) for Windows. - -2014-02-24 Tamas Gergely <tgergely.u-szeged@partner.samsung.com> - - Code cleanup: remove leftover ENABLE(WORKERS) macros and support. - https://bugs.webkit.org/show_bug.cgi?id=129255 - - Reviewed by Csaba Osztrogonác. - - ENABLE_WORKERS macro was removed in r159679. - Support is now also removed from xcconfig files. - - * Configurations/FeatureDefines.xcconfig: - -2014-02-24 David Kilzer <ddkilzer@apple.com> - - Remove redundant setting in FeatureDefines.xcconfig - - * Configurations/FeatureDefines.xcconfig: - -2014-02-23 Sam Weinig <sam@webkit.org> - - Update FeatureDefines.xcconfig - - Rubber-stamped by Anders Carlsson. - - * Configurations/FeatureDefines.xcconfig: - -2014-02-23 Dean Jackson <dino@apple.com> - - Sort the project file with sort-Xcode-project-file. - - Rubber-stamped by Sam Weinig. - - * JavaScriptCore.xcodeproj/project.pbxproj: - -2014-02-23 Sam Weinig <sam@webkit.org> - - Move telephone number detection behind its own ENABLE macro - https://bugs.webkit.org/show_bug.cgi?id=129236 - - Reviewed by Dean Jackson. - - * Configurations/FeatureDefines.xcconfig: - Add ENABLE_TELEPHONE_NUMBER_DETECTION. - -2014-02-22 Filip Pizlo <fpizlo@apple.com> - - Refine DFG+FTL inlining and compilation limits - https://bugs.webkit.org/show_bug.cgi?id=129212 - - Reviewed by Mark Hahnenberg. - - Allow larger functions to be DFG-compiled. Institute a limit on FTL compilation, - and set that limit quite high. Institute a limit on inlining-into. The idea here is - that large functions tend to be autogenerated, and code generators like emscripten - appear to leave few inlining opportunities anyway. Also, we don't want the code - size explosion that we would risk if we allowed compilation of a large function and - then inlined a ton of stuff into it. - - This is a 0.5% speed-up on Octane v2 and almost eliminates the typescript - regression. This is a 9% speed-up on AsmBench. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::noticeIncomingCall): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleInlining): - * dfg/DFGCapabilities.h: - (JSC::DFG::isSmallEnoughToInlineCodeInto): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLState.h: - (JSC::FTL::shouldShowDisassembly): - * runtime/Options.h: - -2014-02-22 Dan Bernstein <mitz@apple.com> - - REGRESSION (r164507): Crash beneath JSGlobalObjectInspectorController::reportAPIException at facebook.com, twitter.com, youtube.com - https://bugs.webkit.org/show_bug.cgi?id=129227 - - Reviewed by Eric Carlson. - - Reverted r164507. - - * API/JSBase.cpp: - (JSEvaluateScript): - (JSCheckScriptSyntax): - * API/JSObjectRef.cpp: - (JSObjectMakeFunction): - (JSObjectMakeArray): - (JSObjectMakeDate): - (JSObjectMakeError): - (JSObjectMakeRegExp): - (JSObjectGetProperty): - (JSObjectSetProperty): - (JSObjectGetPropertyAtIndex): - (JSObjectSetPropertyAtIndex): - (JSObjectDeleteProperty): - (JSObjectCallAsFunction): - (JSObjectCallAsConstructor): - * API/JSValue.mm: - (valueToArray): - (valueToDictionary): - * API/JSValueRef.cpp: - (JSValueIsEqual): - (JSValueIsInstanceOfConstructor): - (JSValueCreateJSONString): - (JSValueToNumber): - (JSValueToStringCopy): - (JSValueToObject): - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - * inspector/ConsoleMessage.h: - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - * inspector/JSGlobalObjectInspectorController.h: - * inspector/ScriptCallStack.cpp: - * inspector/ScriptCallStack.h: - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::createScriptCallStackForConsole): - (Inspector::createScriptCallStackFromException): - * inspector/ScriptCallStackFactory.h: - * inspector/agents/InspectorConsoleAgent.cpp: - (Inspector::InspectorConsoleAgent::enable): - (Inspector::InspectorConsoleAgent::addMessageToConsole): - (Inspector::InspectorConsoleAgent::count): - * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: - (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): - -2014-02-22 Joseph Pecoraro <pecoraro@apple.com> - - Remove some unreachable code (-Wunreachable-code) - https://bugs.webkit.org/show_bug.cgi?id=129220 - - Reviewed by Eric Carlson. - - * API/tests/testapi.c: - (EvilExceptionObject_convertToType): - * disassembler/udis86/udis86_decode.c: - (decode_operand): - -2014-02-22 Filip Pizlo <fpizlo@apple.com> - - Unreviewed, ARMv7 build fix. - - * assembler/ARMv7Assembler.h: - -2014-02-21 Filip Pizlo <fpizlo@apple.com> - - It should be possible for a LinkBuffer to outlive the MacroAssembler and still be useful - https://bugs.webkit.org/show_bug.cgi?id=124733 - - Reviewed by Oliver Hunt. - - This also takes the opportunity to de-duplicate some branch compaction code. - - * assembler/ARM64Assembler.h: - * assembler/ARMv7Assembler.h: - (JSC::ARMv7Assembler::buffer): - * assembler/AssemblerBuffer.h: - (JSC::AssemblerData::AssemblerData): - (JSC::AssemblerBuffer::AssemblerBuffer): - (JSC::AssemblerBuffer::storage): - (JSC::AssemblerBuffer::grow): - * assembler/LinkBuffer.h: - (JSC::LinkBuffer::LinkBuffer): - (JSC::LinkBuffer::executableOffsetFor): - (JSC::LinkBuffer::applyOffset): - * assembler/MacroAssemblerARM64.h: - (JSC::MacroAssemblerARM64::link): - * assembler/MacroAssemblerARMv7.h: - -2014-02-21 Brent Fulgham <bfulgham@apple.com> - - Extend media support for WebVTT sources - https://bugs.webkit.org/show_bug.cgi?id=129156 - - Reviewed by Eric Carlson. - - * Configurations/FeatureDefines.xcconfig: Add new feature define for AVF_CAPTIONS - -2014-02-21 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: JSContext inspection should report exceptions in the console - https://bugs.webkit.org/show_bug.cgi?id=128776 - - Reviewed by Timothy Hatcher. - - When JavaScript API functions have an exception, let the inspector - know so it can log the JavaScript and Native backtrace that caused - the exception. - - Include some clean up of ConsoleMessage and ScriptCallStack construction. - - * API/JSBase.cpp: - (JSEvaluateScript): - (JSCheckScriptSyntax): - * API/JSObjectRef.cpp: - (JSObjectMakeFunction): - (JSObjectMakeArray): - (JSObjectMakeDate): - (JSObjectMakeError): - (JSObjectMakeRegExp): - (JSObjectGetProperty): - (JSObjectSetProperty): - (JSObjectGetPropertyAtIndex): - (JSObjectSetPropertyAtIndex): - (JSObjectDeleteProperty): - (JSObjectCallAsFunction): - (JSObjectCallAsConstructor): - * API/JSValue.mm: - (reportExceptionToInspector): - (valueToArray): - (valueToDictionary): - * API/JSValueRef.cpp: - (JSValueIsEqual): - (JSValueIsInstanceOfConstructor): - (JSValueCreateJSONString): - (JSValueToNumber): - (JSValueToStringCopy): - (JSValueToObject): - When seeing an exception, let the inspector know there was an exception. - - * inspector/JSGlobalObjectInspectorController.h: - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - Log API exceptions by also grabbing the native backtrace. - - * inspector/ScriptCallStack.h: - * inspector/ScriptCallStack.cpp: - (Inspector::ScriptCallStack::firstNonNativeCallFrame): - (Inspector::ScriptCallStack::append): - Minor extensions to ScriptCallStack to make it easier to work with. - - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - Provide better default information if the first call frame was native. - - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::extractSourceInformationFromException): - (Inspector::createScriptCallStackFromException): - Perform the handling here of inserting a fake call frame for exceptions - if there was no call stack (e.g. a SyntaxError) or if the first call - frame had no information. - - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - * inspector/ConsoleMessage.h: - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::createScriptCallStackForConsole): - * inspector/ScriptCallStackFactory.h: - * inspector/agents/InspectorConsoleAgent.cpp: - (Inspector::InspectorConsoleAgent::enable): - (Inspector::InspectorConsoleAgent::addMessageToConsole): - (Inspector::InspectorConsoleAgent::count): - * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: - (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): - ConsoleMessage cleanup. - -2014-02-21 Oliver Hunt <oliver@apple.com> - - Add extra space to op_call and related opcodes - https://bugs.webkit.org/show_bug.cgi?id=129170 - - Reviewed by Mark Lam. - - No change in behaviour, just some refactoring to add an extra - slot to the op_call instructions, and refactoring to make similar - changes easier in future. - - * bytecode/CodeBlock.cpp: - (JSC::CodeBlock::printCallOp): - * bytecode/Opcode.h: - (JSC::padOpcodeName): - * bytecompiler/BytecodeGenerator.cpp: - (JSC::BytecodeGenerator::emitCall): - (JSC::BytecodeGenerator::emitCallVarargs): - (JSC::BytecodeGenerator::emitConstruct): - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleIntrinsic): - * jit/JITCall.cpp: - (JSC::JIT::compileOpCall): - * jit/JITCall32_64.cpp: - (JSC::JIT::compileOpCall): - * llint/LowLevelInterpreter.asm: - * llint/LowLevelInterpreter32_64.asm: - * llint/LowLevelInterpreter64.asm: - -2014-02-21 Mark Lam <mark.lam@apple.com> - - gatherFromOtherThread() needs to align the sp before gathering roots. - <https://webkit.org/b/129169> - - Reviewed by Geoffrey Garen. - - The GC scans the stacks of other threads using MachineThreads::gatherFromOtherThread(). - gatherFromOtherThread() defines the range of the other thread's stack as - being bounded by the other thread's stack pointer and stack base. While - the stack base will always be aligned to sizeof(void*), the stack pointer - may not be. This is because the other thread may have just pushed a 32-bit - value on its stack before we suspended it for scanning. - - The fix is to round the stack pointer up to the next aligned address of - sizeof(void*) and start scanning from there. On 64-bit systems, we will - effectively ignore the 32-bit word at the bottom of the stack (top of the - stack for stacks growing up) because it cannot be a 64-bit pointer anyway. - 64-bit pointers should always be stored on 64-bit aligned boundaries (our - conservative scan algorithm already depends on this assumption). - - On 32-bit systems, the rounding is effectively a no-op. - - * heap/ConservativeRoots.cpp: - (JSC::ConservativeRoots::genericAddSpan): - - Hardened somne assertions so that we can catch misalignment issues on - release builds as well. - * heap/MachineStackMarker.cpp: - (JSC::MachineThreads::gatherFromOtherThread): - -2014-02-21 Matthew Mirman <mmirman@apple.com> - - Added a GetMyArgumentsLengthSafe and added a speculation check. - https://bugs.webkit.org/show_bug.cgi?id=129051 - - Reviewed by Filip Pizlo. - - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): - -2014-02-21 peavo@outlook.com <peavo@outlook.com> - - [Win][LLINT] Many JSC stress test failures. - https://bugs.webkit.org/show_bug.cgi?id=129155 - - Reviewed by Michael Saboff. - - Intel syntax has reversed operand order compared to AT&T syntax, so we need to swap the operand order, in this case on floating point operations. - Also avoid using the reverse opcode (e.g. fdivr), as this puts the result at the wrong position in the floating point stack. - E.g. "divd ft0, ft1" would translate to fdivr st, st(1) (Intel syntax) on Windows, but this puts the result in st, when it should be in st(1). - - * offlineasm/x86.rb: Swap operand order on Windows. - -2014-02-21 Filip Pizlo <fpizlo@apple.com> - - DFG write barriers should do more speculations - https://bugs.webkit.org/show_bug.cgi?id=129160 - - Reviewed by Mark Hahnenberg. - - Replace ConditionalStoreBarrier with the cheapest speculation that you could do - instead. - - Miniscule speed-up on some things. It's a decent difference in code size, though. - - * bytecode/SpeculatedType.cpp: - (JSC::speculationToAbbreviatedString): - * bytecode/SpeculatedType.h: - (JSC::isNotCellSpeculation): - * dfg/DFGFixupPhase.cpp: - (JSC::DFG::FixupPhase::fixupNode): - (JSC::DFG::FixupPhase::insertStoreBarrier): - (JSC::DFG::FixupPhase::insertPhantomCheck): - * dfg/DFGNode.h: - (JSC::DFG::Node::shouldSpeculateOther): - (JSC::DFG::Node::shouldSpeculateNotCell): - * ftl/FTLCapabilities.cpp: - (JSC::FTL::canCompile): - * ftl/FTLLowerDFGToLLVM.cpp: - (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): - (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): - (JSC::FTL::LowerDFGToLLVM::isNotOther): - (JSC::FTL::LowerDFGToLLVM::isOther): - (JSC::FTL::LowerDFGToLLVM::speculate): - (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): - (JSC::FTL::LowerDFGToLLVM::speculateOther): - (JSC::FTL::LowerDFGToLLVM::speculateNotCell): - -2014-02-21 Joseph Pecoraro <pecoraro@apple.com> - - Revert r164486, causing a number of test failures. - - Unreviewed rollout. - -2014-02-21 Filip Pizlo <fpizlo@apple.com> - - Revive SABI (aka shouldAlwaysBeInlined) - https://bugs.webkit.org/show_bug.cgi?id=129159 - - Reviewed by Mark Hahnenberg. - - This is a small Octane speed-up. - - * jit/Repatch.cpp: - (JSC::linkFor): This code was assuming that if it's invoked then the caller is a DFG code block. That's wrong, since it's now used by all of the JITs. - -2014-02-21 Joseph Pecoraro <pecoraro@apple.com> - - Web Inspector: JSContext inspection should report exceptions in the console - https://bugs.webkit.org/show_bug.cgi?id=128776 - - Reviewed by Timothy Hatcher. - - When JavaScript API functions have an exception, let the inspector - know so it can log the JavaScript and Native backtrace that caused - the exception. - - Include some clean up of ConsoleMessage and ScriptCallStack construction. - - * API/JSBase.cpp: - (JSEvaluateScript): - (JSCheckScriptSyntax): - * API/JSObjectRef.cpp: - (JSObjectMakeFunction): - (JSObjectMakeArray): - (JSObjectMakeDate): - (JSObjectMakeError): - (JSObjectMakeRegExp): - (JSObjectGetProperty): - (JSObjectSetProperty): - (JSObjectGetPropertyAtIndex): - (JSObjectSetPropertyAtIndex): - (JSObjectDeleteProperty): - (JSObjectCallAsFunction): - (JSObjectCallAsConstructor): - * API/JSValue.mm: - (reportExceptionToInspector): - (valueToArray): - (valueToDictionary): - * API/JSValueRef.cpp: - (JSValueIsEqual): - (JSValueIsInstanceOfConstructor): - (JSValueCreateJSONString): - (JSValueToNumber): - (JSValueToStringCopy): - (JSValueToObject): - When seeing an exception, let the inspector know there was an exception. - - * inspector/JSGlobalObjectInspectorController.h: - * inspector/JSGlobalObjectInspectorController.cpp: - (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): - (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): - (Inspector::JSGlobalObjectInspectorController::reportAPIException): - Log API exceptions by also grabbing the native backtrace. - - * inspector/ScriptCallStack.h: - * inspector/ScriptCallStack.cpp: - (Inspector::ScriptCallStack::firstNonNativeCallFrame): - (Inspector::ScriptCallStack::append): - Minor extensions to ScriptCallStack to make it easier to work with. - - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - Provide better default information if the first call frame was native. - - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::extractSourceInformationFromException): - (Inspector::createScriptCallStackFromException): - Perform the handling here of inserting a fake call frame for exceptions - if there was no call stack (e.g. a SyntaxError) or if the first call - frame had no information. - - * inspector/ConsoleMessage.cpp: - (Inspector::ConsoleMessage::ConsoleMessage): - (Inspector::ConsoleMessage::autogenerateMetadata): - * inspector/ConsoleMessage.h: - * inspector/ScriptCallStackFactory.cpp: - (Inspector::createScriptCallStack): - (Inspector::createScriptCallStackForConsole): - * inspector/ScriptCallStackFactory.h: - * inspector/agents/InspectorConsoleAgent.cpp: - (Inspector::InspectorConsoleAgent::enable): - (Inspector::InspectorConsoleAgent::addMessageToConsole): - (Inspector::InspectorConsoleAgent::count): - * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: - (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): - ConsoleMessage cleanup. - -2014-02-20 Anders Carlsson <andersca@apple.com> - - Modernize JSGlobalLock and JSLockHolder - https://bugs.webkit.org/show_bug.cgi?id=129105 - - Reviewed by Michael Saboff. - - Use std::mutex and std::thread::id where possible. - - * runtime/JSLock.cpp: - (JSC::GlobalJSLock::GlobalJSLock): - (JSC::GlobalJSLock::~GlobalJSLock): - (JSC::GlobalJSLock::initialize): - (JSC::JSLock::JSLock): - (JSC::JSLock::lock): - (JSC::JSLock::unlock): - (JSC::JSLock::currentThreadIsHoldingLock): - * runtime/JSLock.h: - -2014-02-20 Mark Lam <mark.lam@apple.com> - - virtualForWithFunction() should not throw an exception with a partially initialized frame. - <https://webkit.org/b/129134> - - Reviewed by Michael Saboff. - - Currently, when JITOperations.cpp's virtualForWithFunction() fails to - prepare the callee function for execution, it proceeds to throw the - exception using the callee frame which is only partially initialized - thus far. Instead, it should be throwing the exception using the caller - frame because: - 1. the error happened "in" the caller while preparing the callee for - execution i.e. the caller frame is the top fully initialized frame - on the stack. - 2. the callee frame is not fully initialized yet, and the unwind - mechanism cannot depend on the data in it. - - * jit/JITOperations.cpp: - -2014-02-20 Mark Lam <mark.lam@apple.com> - - DefaultGCActivityCallback::doWork() should reschedule if GC is deferred. - <https://webkit.org/b/129131> - - Reviewed by Mark Hahnenberg. - - Currently, DefaultGCActivityCallback::doWork() does not check if the GC - needs to be deferred before commencing. As a result, the GC may crash - and/or corrupt data because the VM is not in the consistent state needed - for the GC to run. With this fix, doWork() now checks if the GC is - supposed to be deferred and re-schedules if needed. It only commences - with GC'ing when it's safe to do so. - - * runtime/GCActivityCallback.cpp: - (JSC::DefaultGCActivityCallback::doWork): - -2014-02-20 Geoffrey Garen <ggaren@apple.com> - - Math.imul gives wrong results - https://bugs.webkit.org/show_bug.cgi?id=126345 - - Reviewed by Mark Hahnenberg. - - Don't truncate non-int doubles to 0 -- that's just not how ToInt32 works. - Instead, take a slow path that will do the right thing. - - * jit/ThunkGenerators.cpp: - (JSC::imulThunkGenerator): - -2014-02-20 Filip Pizlo <fpizlo@apple.com> - - DFG should do its own static estimates of execution frequency before it starts creating OSR entrypoints - https://bugs.webkit.org/show_bug.cgi?id=129129 - - Reviewed by Geoffrey Garen. - - We estimate execution counts based on loop depth, and then use those to estimate branch - weights. These weights then get carried all the way down to LLVM prof branch_weights - meta-data. - - This is better than letting LLVM do its own static estimates, since by the time we - generate LLVM IR, we may have messed up the CFG due to OSR entrypoint creation. Of - course, it would be even better if we just slurped in some kind of execution counts - from profiling, but we don't do that, yet. - - * CMakeLists.txt: - * GNUmakefile.list.am: - * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: - * JavaScriptCore.xcodeproj/project.pbxproj: - * dfg/DFGBasicBlock.cpp: - (JSC::DFG::BasicBlock::BasicBlock): - * dfg/DFGBasicBlock.h: - * dfg/DFGBlockInsertionSet.cpp: - (JSC::DFG::BlockInsertionSet::insert): - (JSC::DFG::BlockInsertionSet::insertBefore): - * dfg/DFGBlockInsertionSet.h: - * dfg/DFGByteCodeParser.cpp: - (JSC::DFG::ByteCodeParser::handleInlining): - (JSC::DFG::ByteCodeParser::parseCodeBlock): - * dfg/DFGCriticalEdgeBreakingPhase.cpp: - (JSC::DFG::CriticalEdgeBreakingPhase::breakCriticalEdge): - * dfg/DFGLoopPreHeaderCreationPhase.cpp: - (JSC::DFG::createPreHeader): - * dfg/DFGNaturalLoops.h: - (JSC::DFG::NaturalLoops::loopDepth): - * dfg/DFGOSREntrypointCreationPhase.cpp: - (JSC::DFG::OSREntrypointCreationPhase::run): - * dfg/DFGPlan.cpp: - (JSC::DFG::Plan::compileInThreadImpl): - * dfg/DFGStaticExecutionCountEstimationPhase.cpp: Added. - (JSC::DFG::StaticExecutionCountEstimationPhase::StaticExecutionCountEstimationPhase): - (JSC::DFG::StaticExecutionCountEstimationPhase::run): - (JSC::DFG::StaticExecutionCountEstimationPhase::applyCounts): - (JSC::DFG::performStaticExecutionCountEstimation): - * dfg/DFGStaticExecutionCountEstimationPhase.h: Added. - -2014-02-20 Filip Pizlo <fpizlo@apple.com> - - FTL may not see a compact_unwind section if there weren't any stackmaps - https://bugs.webkit.org/show_bug.cgi?id=129125 - - Reviewed by Geoffrey Garen. - - It's OK to not have an unwind section, so long as the function also doesn't have any - OSR exits. - - * ftl/FTLCompile.cpp: - (JSC::FTL::fixFunctionBasedOnStackMaps): - (JSC::FTL::compile): - * ftl/FTLUnwindInfo.cpp: - (JSC::FTL::UnwindInfo::parse): - * ftl/FTLUnwindInfo.h: -== Rolled over to ChangeLog-2014-02-20 == +== Rolled over to ChangeLog-2015-07-23 == diff --git a/ChangeLog-2014-10-07 b/ChangeLog-2014-10-07 new file mode 100644 index 0000000..55c897c --- /dev/null +++ b/ChangeLog-2014-10-07 @@ -0,0 +1,30352 @@ +2014-10-07 Oliver Hunt <oliver@apple.com> + + Remove op_new_captured_func + https://bugs.webkit.org/show_bug.cgi?id=137491 + + Reviewed by Mark Lam. + + Removes the op_captured_new_func opcode as part of the work + towards having any magical opcodes that write directly to + named "registers" and then have a follow on op to ensure that + the environment record correctly represents the stack state. + + For this we add a non-captured scratch register so we don't + have to have any kind of magic opcode, and instead simply + have sensible creation and move semantics for capturing new + functions. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitLazyNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + * bytecompiler/BytecodeGenerator.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_new_captured_func): Deleted. + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): Deleted. + * runtime/CommonSlowPaths.h: + +2014-10-06 Andy Estes <aestes@apple.com> + + Objective-C objects must be fully defined when used in a WTF::Vector + https://bugs.webkit.org/show_bug.cgi?id=137479 + + Reviewed by Mark Rowe. + + When compiling an Objective-C++ file under ARC, @class types are considered non-trivially destructable, so + Vector needs to see their definition in order to call their destructor. + + See <http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership-qualified-fields-of-structs-and-unions> for details. + + * API/ObjcRuntimeExtras.h: Imported <objc/Protocol.h>. + +2014-10-06 Brent Fulgham <bfulgham@apple.com> + + [Win] Use of 1-bit Enum type behaves improperly + https://bugs.webkit.org/show_bug.cgi?id=137471 + <rdar://problem/18559172> + + Reviewed by Mark Lam. + + Represent 1-bit enum element as 'unsigned', as we have done elsewhere + in WebKit to avoid problems when building with MSVC. + + * debugger/Debugger.h: + +2014-10-06 Mark Lam <mark.lam@apple.com> + + Fixed compiler warnings on Windows build. + <https://webkit.org/b/135205> + + Reviewed by Geoffrey Garen. + + Benchmarking with jsc shows that perf is neutral with this change. + + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::call): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * dfg/DFGArgumentPosition.h: + (JSC::DFG::ArgumentPosition::mergeShouldNeverUnbox): + (JSC::DFG::ArgumentPosition::mergeArgumentUnboxingAwareness): + * dfg/DFGEdge.h: + (JSC::DFG::Edge::makeWord): + * dfg/DFGNodeFlags.h: + (JSC::DFG::nodeMayOverflow): + (JSC::DFG::nodeMayNegZero): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + * dfg/DFGVariableAccessData.cpp: + (JSC::DFG::VariableAccessData::mergeIsCaptured): + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::mergeIsProfitableToUnbox): + (JSC::DFG::VariableAccessData::mergeStructureCheckHoistingFailed): + (JSC::DFG::VariableAccessData::mergeCheckArrayHoistingFailed): + (JSC::DFG::VariableAccessData::mergeIsArgumentsAlias): + (JSC::DFG::VariableAccessData::mergeIsLoadedFrom): + * runtime/JSDataViewPrototype.cpp: + (JSC::getData): + +2014-10-06 Oliver Hunt <oliver@apple.com> + + Remove incorrect assertion. + + * runtime/Arguments.cpp: + (JSC::Arguments::tearOff): + +2014-10-06 Oliver Hunt <oliver@apple.com> + + Fix cloop build + + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + +2014-10-06 Mark Lam <mark.lam@apple.com> + + Unreviewed build fix. + <https://webkit.org/b/137279> + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2014-10-06 Oliver Hunt <oliver@apple.com> + + REGRESSION(r174226): [JSC] Crash when running the perf test Speedometer/Full.html + https://bugs.webkit.org/show_bug.cgi?id=137404 + + Reviewed by Michael Saboff. + + Update the Arguments object to recognise that it must always have an + environment record if the referenced callee has one, and if such is not + present it should not try to extract one from the callframe, as that + path leads to madness. + + Happily this makes some of the other code more sensible, and removes a + bunch of unnecessary and icky logic. + + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::tearOff): + (JSC::Arguments::didTearOffActivation): Deleted. + * runtime/Arguments.h: + (JSC::Arguments::argument): + (JSC::Arguments::finishCreation): + +2014-10-04 Brian J. Burg <burg@cs.washington.edu> + + Unreviewed, rolling out r174319. + + Causes assertions in fast/profiler tests. Needs nontrivial + investigation, will take offline. + + Reverted changeset: + + "Web Inspector: timelines should not count time elapsed while + paused in the debugger" + https://bugs.webkit.org/show_bug.cgi?id=136351 + http://trac.webkit.org/changeset/174319 + +2014-10-04 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: timelines should not count time elapsed while paused in the debugger + https://bugs.webkit.org/show_bug.cgi?id=136351 + + Reviewed by Timothy Hatcher. + + Now that we have a stopwatch to provide pause-aware timing data, we can remove the + profiler's handling of debugger pause/continue callbacks. The timeline agent accounts + for debugger pauses by pausing and resuming the stopwatch. + + * API/JSProfilerPrivate.cpp: + (JSStartProfiling): Use a fresh stopwatch when profiling from the JSC API. + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::handlePause): + * profiler/LegacyProfiler.cpp: + (JSC::LegacyProfiler::profiler): Use nullptr. + (JSC::LegacyProfiler::startProfiling): Hand off a stopwatch to the profile generator. + (JSC::LegacyProfiler::stopProfiling): Use nullptr. + (JSC::LegacyProfiler::didPause): Deleted. + (JSC::LegacyProfiler::didContinue): Deleted. + * profiler/LegacyProfiler.h: + * profiler/ProfileGenerator.cpp: Remove debugger pause/continue callbacks and the + timestamp member that was used to track time elapsed by the debugger. Just use the + stopwatch's elapsed times to generate start/elapsed times for function calls. + (JSC::ProfileGenerator::create): + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::ProfileGenerator::beginCallEntry): + (JSC::ProfileGenerator::endCallEntry): + (JSC::ProfileGenerator::didPause): Deleted. + (JSC::ProfileGenerator::didContinue): Deleted. + * profiler/ProfileGenerator.h: + +2014-10-04 Filip Pizlo <fpizlo@apple.com> + + FTL should sink PutLocals + https://bugs.webkit.org/show_bug.cgi?id=137168 + + Reviewed by Oliver Hunt. + + We've known for a while that our PutLocal situation was sub-optimal. We emit them anytime we + "pass" arguments to an inlined function call, because we need to enable the runtime to grab + those arguments when doing foo.arguments where foo is inlined: our engine doesn't deoptimize + in that case but rather just relies on the arguments being flushed (i.e. a copy of their + values is spilled) at a well-known place in a well-known format. + + The PutLocals incur two costs: (1) they are store instructions and stores ain't free, and (2) + they look like escaping sites and so they inhibit object allocation sinking. + + But in most cases, the PutLocals are unnecessary because the inlined code never performs any + side effect that could transitively lead to function.arguments. Even if the inlined code + could do such a side effect, it may be on a rare path so there is no need to penalize the + entire function. + + This patch implements one solution to the PutLocal problem: it aggressively sinks PutLocals + to the latest possible point. This is even more aggressive than the object allocation + sinking. That sinking algorithm avoids creating situations where an object could be + materialized more than one along any path. PutLocal sinking, on the other hand, doesn't avoid + this at all - both to make the phase cheaper and simpler and to make it more aggressive. + Every PutLocal is sunk no matter what. + + The upside of this patch is that it eliminates many PutLocals: many of them are sunk "past + their death", thus eliminating them completely. Others are sunk to rare paths. This enables a + lot of object allocation sinking and it removes a lot of pointless store instructions. + + It also has downsites. Sinking PutLocals increases register pressure because it increases the + live ranges of things like inlined arguments. + + This patch is a net performance win in its current form: 1% SunSpider regression, 2% OctaneV2 + progression, 0.6% Kraken regression, 1% AsmBench progression, and 0.5% CompressionBench + regression. The biggest win is on Octane/raytrace, which improves by 27%. + + Relanding after fixing internal builds. We have to be careful about implicit casts from int64 + to int32. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.h: + * bytecode/Operands.h: + (JSC::Operands::dump): Deleted. + * bytecode/OperandsInlines.h: + (JSC::Traits>::dump): + * bytecode/VirtualRegister.h: + (JSC::VirtualRegister::isHeader): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGClobberSet.h: + (JSC::DFG::ClobberSetAdd::operator()): + (JSC::DFG::ClobberSetOverlaps::operator()): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + (JSC::DFG::NoOpClobberize::operator()): + (JSC::DFG::CheckClobberize::operator()): + (JSC::DFG::AbstractHeapOverlaps::operator()): + (JSC::DFG::ReadMethodClobberize::operator()): + (JSC::DFG::WriteMethodClobberize::operator()): + (JSC::DFG::DefMethodClobberize::operator()): + * dfg/DFGFlushFormat.h: + (JSC::DFG::merge): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::capturedVarsFor): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPreciseLocalClobberize.h: Added. + (JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor): + (JSC::DFG::PreciseLocalClobberizeAdaptor::read): + (JSC::DFG::PreciseLocalClobberizeAdaptor::write): + (JSC::DFG::PreciseLocalClobberizeAdaptor::def): + (JSC::DFG::PreciseLocalClobberizeAdaptor::callIfAppropriate): + (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): + (JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop): + (JSC::DFG::forEachLocalReadByUnwind): + (JSC::DFG::preciseLocalClobberize): + * dfg/DFGPutLocalSinkingPhase.cpp: Added. + (JSC::DFG::performPutLocalSinking): + * dfg/DFGPutLocalSinkingPhase.h: Added. + * dfg/DFGSSACalculator.h: + (JSC::DFG::SSACalculator::computePhis): + * dfg/DFGValidate.cpp: + +2014-10-03 Michael Saboff <msaboff@apple.com> + + REGRESSION(r174216): CodeBlock::dumpByteCodes crashes on op_push_name_scope + https://bugs.webkit.org/show_bug.cgi?id=137412 + + Reviewed by Mark Lam. + + Added support for the JSNameScope::type opcode parameter in dumpBytecode(). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + +2014-10-03 Saam Barati <saambarati1@gmail.com> + + Implement op_profile_type in the 32-bit baseline JIT + https://bugs.webkit.org/show_bug.cgi?id=137181 + + Reviewed by Michael Saboff. + + Generate inline code to write to the TypeProfilerLog inside the 32-bit + baseline JIT instead of unconditionally bailing out to the slow path + for op_profile_type. + + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_type): + +2014-10-03 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r174275. + https://bugs.webkit.org/show_bug.cgi?id=137408 + + Build failures on the internal bots. (Requested by dethbakin + on #webkit). + + Reverted changeset: + + "FTL should sink PutLocals" + https://bugs.webkit.org/show_bug.cgi?id=137168 + http://trac.webkit.org/changeset/174275 + +2014-10-03 Oliver Hunt <oliver@apple.com> + + tearoff_arguments should always refer to the unmodified arguments register + https://bugs.webkit.org/show_bug.cgi?id=137406 + + Reviewed by Michael Saboff. + + To simplify subsequent work, and remove unnecessary work from + actual execution this patch simply ensures that tear_off_arguments + refers to the actual unmodified arguments register. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitReturn): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_tear_off_arguments): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_tear_off_arguments): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-10-03 Saam Barati <saambarati1@gmail.com> + + Web Inspector: Move the computation that results in UI strings from JSC to the Web Inspector + https://bugs.webkit.org/show_bug.cgi?id=137295 + + Reviewed by Timothy Hatcher. + + Remove unnecessary functions and properties from JSC that are + now being computed inside the Web Inspector. + + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/protocol/Runtime.json: + * runtime/TypeSet.cpp: + (JSC::TypeSet::allPrimitiveTypeNames): Deleted. + * runtime/TypeSet.h: + +2014-10-02 Filip Pizlo <fpizlo@apple.com> + + FTL should sink PutLocals + https://bugs.webkit.org/show_bug.cgi?id=137168 + + Reviewed by Oliver Hunt. + + We've known for a while that our PutLocal situation was sub-optimal. We emit them anytime we + "pass" arguments to an inlined function call, because we need to enable the runtime to grab + those arguments when doing foo.arguments where foo is inlined: our engine doesn't deoptimize + in that case but rather just relies on the arguments being flushed (i.e. a copy of their + values is spilled) at a well-known place in a well-known format. + + The PutLocals incur two costs: (1) they are store instructions and stores ain't free, and (2) + they look like escaping sites and so they inhibit object allocation sinking. + + But in most cases, the PutLocals are unnecessary because the inlined code never performs any + side effect that could transitively lead to function.arguments. Even if the inlined code + could do such a side effect, it may be on a rare path so there is no need to penalize the + entire function. + + This patch implements one solution to the PutLocal problem: it aggressively sinks PutLocals + to the latest possible point. This is even more aggressive than the object allocation + sinking. That sinking algorithm avoids creating situations where an object could be + materialized more than one along any path. PutLocal sinking, on the other hand, doesn't avoid + this at all - both to make the phase cheaper and simpler and to make it more aggressive. + Every PutLocal is sunk no matter what. + + The upside of this patch is that it eliminates many PutLocals: many of them are sunk "past + their death", thus eliminating them completely. Others are sunk to rare paths. This enables a + lot of object allocation sinking and it removes a lot of pointless store instructions. + + It also has downsites. Sinking PutLocals increases register pressure because it increases the + live ranges of things like inlined arguments. + + This patch is a net performance win in its current form: 1% SunSpider regression, 2% OctaneV2 + progression, 0.6% Kraken regression, 1% AsmBench progression, and 0.5% CompressionBench + regression. The biggest win is on Octane/raytrace, which improves by 27%. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.h: + * bytecode/Operands.h: + (JSC::Operands::dump): Deleted. + * bytecode/OperandsInlines.h: + (JSC::Traits>::dump): + * bytecode/VirtualRegister.h: + (JSC::VirtualRegister::isHeader): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGClobberSet.h: + (JSC::DFG::ClobberSetAdd::operator()): + (JSC::DFG::ClobberSetOverlaps::operator()): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + (JSC::DFG::NoOpClobberize::operator()): + (JSC::DFG::CheckClobberize::operator()): + (JSC::DFG::AbstractHeapOverlaps::operator()): + (JSC::DFG::ReadMethodClobberize::operator()): + (JSC::DFG::WriteMethodClobberize::operator()): + (JSC::DFG::DefMethodClobberize::operator()): + * dfg/DFGFlushFormat.h: + (JSC::DFG::merge): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::capturedVarsFor): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPreciseLocalClobberize.h: Added. + (JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor): + (JSC::DFG::PreciseLocalClobberizeAdaptor::read): + (JSC::DFG::PreciseLocalClobberizeAdaptor::write): + (JSC::DFG::PreciseLocalClobberizeAdaptor::def): + (JSC::DFG::PreciseLocalClobberizeAdaptor::callIfAppropriate): + (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): + (JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop): + (JSC::DFG::forEachLocalReadByUnwind): + (JSC::DFG::preciseLocalClobberize): + * dfg/DFGPutLocalSinkingPhase.cpp: Added. + (JSC::DFG::performPutLocalSinking): + * dfg/DFGPutLocalSinkingPhase.h: Added. + * dfg/DFGSSACalculator.h: + (JSC::DFG::SSACalculator::computePhis): + * dfg/DFGValidate.cpp: + +2014-10-03 Saam Barati <saambarati1@gmail.com> + + Change how 32-bit JSValues check if they are a Boolean + + Rubber stamped by Filip Pizlo. + + 32-bit JSValue::isBoolean can simply check if its tag corresponds + to the boolean tag instead of checking if it's either true or false. + + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::isBoolean): + +2014-10-01 Oliver Hunt <oliver@apple.com> + + Do all closed variable access through the local lexical object + https://bugs.webkit.org/show_bug.cgi?id=136869 + + Reviewed by Filip Pizlo. + + This patch makes all reads and writes from captured registers + go through the lexical record, and by doing so removes the + need for record tearoff. + + To keep the patch simple we still number variables as though + they are local stack allocated registers, but ::local() will + fail. When local fails we perform a generic resolve, and in + that resolve we now use a ResolveScopeInfo struct to pass + around information about whether a lookup is a statically + known captured variable, and its location in the activation. + To ensure correct behaviour during codeblock linking we also + add a LocalClosureVariable resolution type. + + To ensure correct semantics for the Arguments object, we now + have to eagerly create the Arguments object for any function + that uses both the Arguments object and requires a lexical + record. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::initializeCapturedVariable): + During the entry to a function we are not yet in a position + to allocate temporaries so we directly use the lexical + environment register. + (JSC::BytecodeGenerator::resolveCallee): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::local): + (JSC::BytecodeGenerator::constLocal): + (JSC::BytecodeGenerator::emitResolveScope): + (JSC::BytecodeGenerator::emitResolveConstantLocal): + The two resolve scope operations could technically skip + the op_resolve_scope, and simply perform + op_mov dst, recordRegister + but for now it seemed best to maintain the same basic + behaviour. + (JSC::BytecodeGenerator::emitGetFromScope): + (JSC::BytecodeGenerator::emitPutToScope): + (JSC::BytecodeGenerator::createArgumentsIfNecessary): + If we have an environment we've already created Arguments + so no need to check again. + (JSC::BytecodeGenerator::emitReturn): + Don't need to emit tearoff_environment + * bytecompiler/BytecodeGenerator.h: + (JSC::Local::Local): + (JSC::Local::operator bool): + (JSC::Local::get): + (JSC::Local::isReadOnly): + (JSC::Local::isSpecial): + (JSC::ResolveScopeInfo::ResolveScopeInfo): + (JSC::ResolveScopeInfo::isLocal): + (JSC::ResolveScopeInfo::localIndex): + (JSC::BytecodeGenerator::shouldCreateArgumentsEagerly): + (JSC::Local::isCaptured): Deleted. + (JSC::Local::captureMode): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ResolveNode::emitBytecode): + (JSC::EvalFunctionCallNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::DeleteResolveNode::emitBytecode): + (JSC::TypeOfResolveNode::emitBytecode): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::EmptyVarExpression::emitBytecode): + (JSC::ForInNode::tryGetBoundLocal): + (JSC::ForInNode::emitLoopHeader): + (JSC::ForOfNode::emitBytecode): + (JSC::BindingNode::bindValue): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetRegisters): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_captured_mov): Deleted. + (JSC::JIT::emit_op_tear_off_lexical_environment): Deleted. + (JSC::JIT::emitSlow_op_captured_mov): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_captured_mov): Deleted. + (JSC::JIT::emit_op_tear_off_lexical_environment): Deleted. + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_resolve_scope): + (JSC::JIT::emit_op_get_from_scope): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emit_op_put_to_scope): + (JSC::JIT::emitSlow_op_put_to_scope): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_resolve_scope): + (JSC::JIT::emit_op_get_from_scope): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emit_op_put_to_scope): + (JSC::JIT::emitSlow_op_put_to_scope): + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/Arguments.cpp: + (JSC::Arguments::tearOff): + * runtime/Arguments.h: + (JSC::Arguments::argument): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): Deleted. + * runtime/CommonSlowPaths.h: + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::visitChildren): + (JSC::JSLexicalEnvironment::symbolTableGet): + (JSC::JSLexicalEnvironment::symbolTablePut): + (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames): + (JSC::JSLexicalEnvironment::getOwnPropertySlot): + (JSC::JSLexicalEnvironment::argumentsGetter): + * runtime/JSLexicalEnvironment.h: + (JSC::JSLexicalEnvironment::create): + (JSC::JSLexicalEnvironment::JSLexicalEnvironment): + (JSC::JSLexicalEnvironment::tearOff): Deleted. + (JSC::JSLexicalEnvironment::isTornOff): Deleted. + * runtime/JSScope.cpp: + (JSC::resolveTypeName): + * runtime/JSScope.h: + (JSC::makeType): + (JSC::needsVarInjectionChecks): + * runtime/WriteBarrier.h: + (JSC::WriteBarrier<Unknown>::WriteBarrier): + +2014-10-02 Filip Pizlo <fpizlo@apple.com> + + Object allocation sinking should have a sound story for picking materialization points + https://bugs.webkit.org/show_bug.cgi?id=137315 + + Reviewed by Oliver Hunt. + + The only missing piece was having the object allocation sinking phase locate materialization + points that were at CFG edges. + + The logic for how and why this "just works" relies on some properties of critical edge + breaking, so I was fairly careful in how I did this. Also, this requires inserting things at + the "first origin node" of a block - that is the first node in a block that has a NodeOrigin + and therefore is allowed to exit. We basically had support for such a notion before, but + didn't close the loop on it; this patch does that. + + Also I added the ability to provide a BasicBlock* as context for a DFG_ASSERT(). + + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::firstOriginNode): + (JSC::DFG::BasicBlock::firstOrigin): + * dfg/DFGBasicBlock.h: + * dfg/DFGCriticalEdgeBreakingPhase.cpp: + (JSC::DFG::CriticalEdgeBreakingPhase::breakCriticalEdge): + * dfg/DFGGraph.cpp: + (JSC::DFG::crash): + (JSC::DFG::Graph::handleAssertionFailure): + * dfg/DFGGraph.h: + * dfg/DFGLoopPreHeaderCreationPhase.cpp: + (JSC::DFG::createPreHeader): + * dfg/DFGNodeOrigin.h: + (JSC::DFG::NodeOrigin::isSet): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * runtime/Options.h: + +2014-10-02 Daniel Bates <dabates@apple.com> + + Clean up: Move XPC forward declarations in JavaScriptCore to WTF SPI wrapper header + https://bugs.webkit.org/show_bug.cgi?id=137277 + + Reviewed by Alexey Proskuryakov. + + Use wtf/spi/darwin/XPCSPI.h instead of including the corresponding XPC headers/ + forward declaring XPC functions. + + * inspector/remote/RemoteInspector.mm: + * inspector/remote/RemoteInspectorXPCConnection.h: + * inspector/remote/RemoteInspectorXPCConnection.mm: + +2014-10-01 Anders Carlsson <andersca@apple.com> + + Use variadic templates for jsMakeNontrivialString + https://bugs.webkit.org/show_bug.cgi?id=137325 + + Reviewed by Sam Weinig. + + * runtime/JSString.h: + (JSC::jsNontrivialString): + Add an overload that takes an rvalue reference to a String so we can transfer ownership easily. + + * runtime/JSStringBuilder.h: + (JSC::jsMakeNontrivialString): + Make this a variadic function template, with a single-parameter version that can steal the string if it's OK to do so. + +2014-10-02 Mark Lam <mark.lam@apple.com> + + Fixed the Inspector to be able to properly distinguish between scope types. + <https://webkit.org/b/137279> + + Reviewed by Geoffrey Garen. + + The pre-existing code incorrectly labels Catch Scopes and Function Name Scopes + as With Scopes. This patch will fix this. + + * bytecode/BytecodeList.json: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitPushFunctionNameScope): + (JSC::BytecodeGenerator::emitPushCatchScope): + - These now passes stores the desired JSNameScope::Type in a bytecode operand. + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::isCatchScope): + (JSC::DebuggerScope::isFunctionNameScope): + - Added queries to be able to explicitly test if the scope is a CatchScope + or FunctionNameScope. The FunctionNameScope is the case where the + NameScope is used to capture the function name of a function expression. + * debugger/DebuggerScope.h: + * inspector/InjectedScriptSource.js: + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::scopeType): + * inspector/JSJavaScriptCallFrame.h: + * inspector/JSJavaScriptCallFramePrototype.cpp: + (Inspector::JSJavaScriptCallFramePrototype::finishCreation): + (Inspector::jsJavaScriptCallFrameConstantFUNCTION_NAME_SCOPE): + * inspector/protocol/Debugger.json: + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * runtime/JSFunction.cpp: + (JSC::JSFunction::addNameScopeIfNeeded): + * runtime/JSNameScope.h: + (JSC::JSNameScope::create): + (JSC::JSNameScope::isFunctionNameScope): + (JSC::JSNameScope::isCatchScope): + (JSC::JSNameScope::JSNameScope): + - Now stores the JSNameScope::Type in a field. + +2014-10-01 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r174180, r174183, and r174186. + https://bugs.webkit.org/show_bug.cgi?id=137320 + + Broke the Mac MountainLion build. Will investigate offline. + (Requested by dydz on #webkit). + + Reverted changesets: + + "Clean up: Move XPC forward declarations in JavaScriptCore to + WTF SPI wrapper header" + https://bugs.webkit.org/show_bug.cgi?id=137277 + http://trac.webkit.org/changeset/174180 + + "Attempt to fix the build after + <https://trac.webkit.org/changeset/174180>" + https://bugs.webkit.org/show_bug.cgi?id=137277 + http://trac.webkit.org/changeset/174183 + + "Another attempt to fix the Mac build after + <https://trac.webkit.org/changeset/174180>" + https://bugs.webkit.org/show_bug.cgi?id=137277 + http://trac.webkit.org/changeset/174186 + +2014-10-01 Daniel Bates <dabates@apple.com> + + Clean up: Move XPC forward declarations in JavaScriptCore to WTF SPI wrapper header + https://bugs.webkit.org/show_bug.cgi?id=137277 + + Reviewed by Alexey Proskuryakov. + + Use wtf/spi/darwin/XPCSPI.h instead of including the corresponding XPC headers/ + forward declaring XPC functions. + + * inspector/remote/RemoteInspector.mm: + * inspector/remote/RemoteInspectorXPCConnection.h: + * inspector/remote/RemoteInspectorXPCConnection.mm: + +2014-10-01 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed build gardening. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Show files in the appropriate + folders in Visual Studio. + +2014-10-01 Filip Pizlo <fpizlo@apple.com> + + Object allocation sinking is broken for escaping sites in loops + https://bugs.webkit.org/show_bug.cgi?id=137310 + + Reviewed by Michael Saboff. + + I tried to do this clever forward-flow based materialization point placement, and I messed up loops. Disabling + the phase for now and landing a test to demonstrate what it going on. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * runtime/Options.h: + * tests/stress/object-escapes-in-loop.js: Added. + (foo): + (bar): + +2014-10-01 Saam Barati <saambarati1@gmail.com> + + Support the type profiler in the DFG + https://bugs.webkit.org/show_bug.cgi?id=136712 + + Reviewed by Filip Pizlo. + + This patch implements op_profile_type inside the DFG as the node: ProfileType. + The DFG will convert the ProfileType node into a Check node in the cases where + passing a type check is equivalent to writing to the TypeProfilerLog. This + gives the DFG the potential to optimize out multiple ProfileType nodes into + a single Check node. + + When the DFG doesn't convert ProfileType into a Check node, it will generate + the same inline code as the baseline JIT does for writing an entry to the + TypeProfilerLog. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::typeLocation): + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::logTypesForTypeLocation): + * runtime/TypeSet.cpp: + (JSC::TypeSet::dumpTypes): + (JSC::TypeSet::doesTypeConformTo): + Make this method public so others can reason about the types a TypeSet has seen. + (JSC::TypeSet::seenTypes): Deleted. + (JSC::TypeSet::dumpSeenTypes): Deleted. + Renamed to dumpTypes so the method seenTypes can be used as a public getter. + * runtime/TypeSet.h: + (JSC::TypeSet::seenTypes): + * tests/typeProfiler/dfg-jit-optimizations.js: Added. + (tierUpToDFG): + (funcs): + (.return): + +2014-10-01 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix 32-bit. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-09-30 Filip Pizlo <fpizlo@apple.com> + + DFG SSA should use PutLocal/KillLocal instead of SetLocal to communicate what is flushed to the stack and when + https://bugs.webkit.org/show_bug.cgi?id=137242 + + Reviewed by Geoffrey Garen. + + OSR availability has to do with telling you the various ways that you could go about getting + the value of a bytecode variable. It can give you two options: node availability means that + there is a node in the DFG IR that has the right value, and flush availability tells you + that the value was already stored to the stack. The clients of OSR availability would + typically prefer flush over node availability. + + Previously OSR availability was affected thusly by the various local-related nodes: SetLocal + set both the node and flush availability, MovHint set node availability and cleared flush + availability, GetArgument set both, and ZombieHint cleared both. + + A MovHint could be turned into a ZombieHint if its source value was DCEd. + + The fact that each node affected both node and flush availability caused weirdness. For + example it meant that we could not insert MovHints in areas of the CFG where a SetLocal's + variable was still live, because then those parts of the code would forget that they had an + availability flush. This meant that if a flush was available, we wouldn't insert MovHints, + and so we would forget that a node was in fact available. This kind of "either-or" picking + was not only hackish but it led to interesting problems for IR transformation: for example + if you tried to do any kind of code motion on SetLocals, you had to be super careful because + you might violate the rule that "MovHints must exist for a live local if a flush is + unavailable". + + The right thing to do is to have independent nodes for flushing and making nodes available. + They shouldn't interact with each other. This patch accomplishes this: + + - PutLocal means that that a value is to be stored to the stack. It makes a flush available. + - KillLocal means that the value stored to the stack is no longer available for the purposes + of OSR (i.e. it no longer accurately corresponds to what that actual bytecode variable + would have been, so you have to fall back on node availability). + - MovHint means that a node is available. It has no effect on flush availability. + - ZombieHint means that a node is not available. It has no effect on flush availability. + + This means that we will see a lot of KillLocals and MovHints right next to each other. It's + a bit verbose, but at least it's precise. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAvailability.h: + (JSC::DFG::Availability::setFlush): + (JSC::DFG::Availability::setNode): + (JSC::DFG::Availability::setNodeUnavailable): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::hasVariableAccessData): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasUnlinkedLocal): + (JSC::DFG::Node::willHaveCodeGenOrOSR): + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePutLocal): + (JSC::FTL::LowerDFGToLLVM::compileSetLocal): Deleted. + +2014-10-01 Brent Fulgham <bfulgham@apple.com> + + [Win] 32-bit JavaScriptCore should limit itself to the C loop + https://bugs.webkit.org/show_bug.cgi?id=137304 + <rdar://problem/18375370> + + Reviewed by Michael Saboff. + + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl: + Use the C loop for 32-bit builds. + +2014-09-30 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: ErrorString should be passed by reference + https://bugs.webkit.org/show_bug.cgi?id=137257 + + Reviewed by Joseph Pecoraro. + + Pass the leading ErrorString argument by reference, since it is always an out parameter. + Clean up callsites where the error message is written. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::evaluate): + (Inspector::InjectedScript::callFunctionOn): + (Inspector::InjectedScript::evaluateOnCallFrame): + (Inspector::InjectedScript::getFunctionDetails): + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getInternalProperties): + * inspector/InjectedScript.h: + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::makeEvalCall): + * inspector/InjectedScriptBase.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::willDestroyFrontendAndBackend): + (Inspector::InspectorAgent::enable): + (Inspector::InspectorAgent::disable): + (Inspector::InspectorAgent::initialized): + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::willDestroyFrontendAndBackend): + (Inspector::InspectorConsoleAgent::enable): + (Inspector::InspectorConsoleAgent::disable): + (Inspector::InspectorConsoleAgent::clearMessages): + (Inspector::InspectorConsoleAgent::reset): + (Inspector::InspectorConsoleAgent::addMessageToConsole): + * inspector/agents/InspectorConsoleAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::enable): + (Inspector::InspectorDebuggerAgent::disable): + (Inspector::InspectorDebuggerAgent::setBreakpointsActive): + (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::parseLocation): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::removeBreakpoint): + (Inspector::InspectorDebuggerAgent::continueToLocation): + (Inspector::InspectorDebuggerAgent::searchInContent): + (Inspector::InspectorDebuggerAgent::getScriptSource): + (Inspector::InspectorDebuggerAgent::getFunctionDetails): + (Inspector::InspectorDebuggerAgent::pause): + (Inspector::InspectorDebuggerAgent::resume): + (Inspector::InspectorDebuggerAgent::stepOver): + (Inspector::InspectorDebuggerAgent::stepInto): + (Inspector::InspectorDebuggerAgent::stepOut): + (Inspector::InspectorDebuggerAgent::setPauseOnExceptions): + (Inspector::InspectorDebuggerAgent::evaluateOnCallFrame): + (Inspector::InspectorDebuggerAgent::setOverlayMessage): + (Inspector::InspectorDebuggerAgent::didParseSource): + (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): + (Inspector::InspectorDebuggerAgent::assertPaused): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::parse): + (Inspector::InspectorRuntimeAgent::evaluate): + (Inspector::InspectorRuntimeAgent::callFunctionOn): + (Inspector::InspectorRuntimeAgent::getProperties): + (Inspector::InspectorRuntimeAgent::releaseObject): + (Inspector::InspectorRuntimeAgent::releaseObjectGroup): + (Inspector::InspectorRuntimeAgent::run): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::InspectorRuntimeAgent::enableTypeProfiler): + (Inspector::InspectorRuntimeAgent::disableTypeProfiler): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/agents/JSGlobalObjectConsoleAgent.cpp: + (Inspector::JSGlobalObjectConsoleAgent::setMonitoringXHREnabled): + (Inspector::JSGlobalObjectConsoleAgent::addInspectedNode): + * inspector/agents/JSGlobalObjectConsoleAgent.h: + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + (Inspector::JSGlobalObjectDebuggerAgent::injectedScriptForEval): + * inspector/agents/JSGlobalObjectDebuggerAgent.h: + * inspector/agents/JSGlobalObjectRuntimeAgent.cpp: + (Inspector::JSGlobalObjectRuntimeAgent::injectedScriptForEval): + * inspector/agents/JSGlobalObjectRuntimeAgent.h: + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator._generate_handler_declaration_for_command): + (BackendDispatcherHeaderGenerator._generate_async_handler_declaration_for_command): + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + +2014-09-30 Mark Lam <mark.lam@apple.com> + + Label some asserts as having security implications. + <https://webkit.org/b/137260> + + Reviewed by Filip Pizlo. + + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::handleAssertionFailure): + * runtime/JSCell.h: + (JSC::jsCast): + * runtime/StructureIDTable.h: + (JSC::StructureIDTable::get): + +2014-09-30 Filip Pizlo <fpizlo@apple.com> + + REGRESSION (r174025): Invalid cast in JSC::asString + https://bugs.webkit.org/show_bug.cgi?id=137224 + + Reviewed by Geoffrey Garen. + + Store barrier elision in fixup depends on checking the type of the value being stored. It's very important that + when we speak of "the value being stored" we are really referring to the right value. + + The bug here was that the PutClosureVar case was assuming that child2 is the value being stored. It's actually + child3. So we were incorrectly removing all barriers from PutClosureVar. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + +2014-09-30 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: use static Strings instead of AtomicStrings for replay input type tags + https://bugs.webkit.org/show_bug.cgi?id=137086 + + Reviewed by Joseph Pecoraro. + + This pattern doesn't work when we want to define some inputs in WebKit2. + The ReplayInputTypes class was generated from WebCore inputs only. This + patch moves all input traits to use static local Strings as type tags. + + * replay/scripts/CodeGeneratorReplayInputs.py: Remove configuration of how + type tags are generated, since all framework targets now generate the same code. + + * replay/NondeterministicInput.h: + * replay/scripts/CodeGeneratorReplayInputs.py: Simplify and rebase test results. + (Generator.generate_input_trait_implementation): + * replay/scripts/CodeGeneratorReplayInputsTemplates.py: Simplify templates. + + * replay/scripts/tests/expected/generate-enum-encoding-helpers-with-guarded-values.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::SavedMouseButton>::type): + * replay/scripts/tests/expected/generate-enum-encoding-helpers-with-guarded-values.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::SavedMouseButton>::type): + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::HandleWheelEvent>::type): + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::FormCombo>::type): + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-input-with-guard.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::GetCurrentTime>::type): + (JSC::InputTraits<Test::SetRandomSeed>::type): + * replay/scripts/tests/expected/generate-input-with-guard.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::ArrayOfThings>::type): + (JSC::InputTraits<Test::SavedHistory>::type): + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-inputs-with-flags.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::ScalarInput1>::type): + (JSC::InputTraits<Test::ScalarInput2>::type): + * replay/scripts/tests/expected/generate-inputs-with-flags.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-memoized-type-modes.json-TestReplayInputs.cpp: + (JSC::InputTraits<Test::ScalarInput>::type): + (JSC::InputTraits<Test::MapInput>::type): + * replay/scripts/tests/expected/generate-memoized-type-modes.json-TestReplayInputs.h: + +2014-09-30 Daniel Bates <dabates@apple.com> + + REGRESSION (r172532): JSBase.h declares NSMapTable functions that are SPI + https://bugs.webkit.org/show_bug.cgi?id=137170 + <rdar://problem/18477384> + + Reviewed by Geoffrey Garen. + + Move conditional include of header Foundation/NSMapTablePriv.h and forward declarations + of NSMapTable SPI from file JavaScriptCore/API/JSBase.h to WTF/wtf/spi/cocoa/NSMapTableSPI.h. + + * API/JSBase.h: + * API/JSManagedValue.mm: Include header WTF/wtf/spi/cocoa/NSMapTableSPI.h. + * API/JSVirtualMachine.mm: Ditto. + * API/JSVirtualMachineInternal.h: Forward declare class NSMapTable. + * API/JSWrapperMap.mm: Include header WTF/wtf/spi/cocoa/NSMapTableSPI.h. Also, order + #include directives such that they are sorted in alphabetical order. + +2014-09-30 Oliver Hunt <oliver@apple.com> + + Fix C API header + https://bugs.webkit.org/show_bug.cgi?id=137254 + <rdar://problem/18487528> + + Build fix + + Guard extern "C" behind __cplusplus ifdef + + * API/JSBase.h: + +2014-09-29 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: InjectedScripts should not be profiled or displayed in Timeline + https://bugs.webkit.org/show_bug.cgi?id=136806 + + Reviewed by Timothy Hatcher. + + It doesn't make sense to show profile nodes for injected scripts when profiling user content. + For now, omit nodes by suspending profiling before and after executing injected scripts. + + * profiler/LegacyProfiler.cpp: + (JSC::LegacyProfiler::suspendProfiling): Added. + (JSC::LegacyProfiler::unsuspendProfiling): Added. + * profiler/LegacyProfiler.h: + * profiler/ProfileGenerator.cpp: Add isSuspended() flag, remove unused typedef. + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::ProfileGenerator::willExecute): + (JSC::ProfileGenerator::didExecute): + * profiler/ProfileGenerator.h: + (JSC::ProfileGenerator::setIsSuspended): Added. + +2014-09-29 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: InspectorValues should use references for out parameters + https://bugs.webkit.org/show_bug.cgi?id=137190 + + Reviewed by Joseph Pecoraro. + + Use references for out parameters in asType() and getType() methods. + Also convert to references in some miscellaneous code where we don't + expect or handle null values. + + Remove variants of asObject() and asArray() that return a nullable RefPtr. + Now, client code is forced to use out parameters and check for cast failure. + + Iron out control flow in some functions and fix some style issues. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getFunctionDetails): + (Inspector::InjectedScript::wrapObject): + (Inspector::InjectedScript::wrapTable): + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::makeEvalCall): + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::injectedScriptForObjectId): Simplify control flow. + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::InspectorBackendDispatcher::dispatch): + (Inspector::getPropertyValue): + (Inspector::AsMethodBridges::asInteger): + (Inspector::AsMethodBridges::asDouble): + (Inspector::AsMethodBridges::asString): + (Inspector::AsMethodBridges::asBoolean): + (Inspector::AsMethodBridges::asObject): + (Inspector::AsMethodBridges::asArray): + * inspector/InspectorProtocolTypes.h: + (Inspector::Protocol::BindingTraits<Protocol::Array<T>>::runtimeCast): + (Inspector::Protocol::BindingTraits<Protocol::Array<T>>::assertValueHasExpectedType): + * inspector/InspectorValues.cpp: Use more by-reference out parameters. Add more spacing. + (Inspector::InspectorValue::asBoolean): + (Inspector::InspectorValue::asDouble): + (Inspector::InspectorValue::asInteger): + (Inspector::InspectorValue::asString): + (Inspector::InspectorValue::asValue): + (Inspector::InspectorValue::asObject): + (Inspector::InspectorValue::asArray): + (Inspector::InspectorValue::parseJSON): + (Inspector::InspectorValue::toJSONString): + (Inspector::InspectorValue::writeJSON): + (Inspector::InspectorBasicValue::asBoolean): + (Inspector::InspectorBasicValue::asDouble): + (Inspector::InspectorBasicValue::asInteger): + (Inspector::InspectorBasicValue::writeJSON): + (Inspector::InspectorString::asString): + (Inspector::InspectorString::writeJSON): + (Inspector::InspectorObjectBase::asObject): + (Inspector::InspectorObjectBase::openAccessors): + (Inspector::InspectorObjectBase::getBoolean): + (Inspector::InspectorObjectBase::getString): + (Inspector::InspectorObjectBase::getObject): + (Inspector::InspectorObjectBase::getArray): + (Inspector::InspectorObjectBase::writeJSON): + (Inspector::InspectorArrayBase::asArray): + (Inspector::InspectorArrayBase::writeJSON): + * inspector/InspectorValues.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::parseLocation): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::continueToLocation): + (Inspector::InspectorDebuggerAgent::didParseSource): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/scripts/codegen/generate_protocol_types_implementation.py: + (ProtocolTypesImplementationGenerator): + (ProtocolTypesImplementationGenerator._generate_assertion_for_enum): + * inspector/scripts/codegen/generator_templates.py: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * replay/EncodedValue.cpp: + (JSC::EncodedValue::asObject): + (JSC::EncodedValue::asArray): + (JSC::EncodedValue::convertTo<bool>): + (JSC::EncodedValue::convertTo<double>): + (JSC::EncodedValue::convertTo<float>): + (JSC::EncodedValue::convertTo<int32_t>): + (JSC::EncodedValue::convertTo<int64_t>): + (JSC::EncodedValue::convertTo<uint32_t>): + (JSC::EncodedValue::convertTo<uint64_t>): + (JSC::EncodedValue::convertTo<String>): + +2014-09-29 Filip Pizlo <fpizlo@apple.com> + + DFG HasStructureProperty codegen should use one fewer registers + https://bugs.webkit.org/show_bug.cgi?id=137235 + + Reviewed by Andreas Kling. + + This was an obvious source of inefficiency and it was causing us to run out of registers on + x86-32. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-09-29 Filip Pizlo <fpizlo@apple.com> + + Don't use GPRResult unless you're flushing registers and making a runtime function call + https://bugs.webkit.org/show_bug.cgi?id=137234 + + Rubber stamped by Andreas Kling. + + Rename GPRResult to GPRFlushedCallResult, in an attempt to dissuade people from using it for results in the + general case. + + Replace GPRResult with GPRTemporary in those places where it was causing bugs: particularly in GetDirectPname it + would cause us to spill the register that has the base, and the code was assuming (rightly) that the base and the + result were in different registers. That's a valid assumption when using GPRTemporary but not with GPRResult. + Also this code wasn't getting any benefit from using GPRResult because it wasn't doing flushRegisters(). + + I don't know how to test this. A test would require setting up a particularly awkward register allocation state. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + (JSC::DFG::SpeculativeJIT::compileNewFunctionNoCheck): + (JSC::DFG::SpeculativeJIT::compileNewFunctionExpression): + (JSC::DFG::SpeculativeJIT::compileRegExpExec): + (JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage): + (JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage): + (JSC::DFG::SpeculativeJIT::compileToStringOnCell): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::GPRFlushedCallResult::GPRFlushedCallResult): + (JSC::DFG::GPRFlushedCallResult2::GPRFlushedCallResult2): + (JSC::DFG::GPRResult::GPRResult): Deleted. + (JSC::DFG::GPRResult2::GPRResult2): Deleted. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranch): + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranch): + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::speculateDoubleRepMachineInt): + +2014-09-29 Diego Pino Garcia <dpino@igalia.com> + + Missing changes from r174049 + https://bugs.webkit.org/show_bug.cgi?id=137206 + + Reviewed by Darin Adler. + + * runtime/CommonIdentifiers.h: + +2014-09-28 Diego Pino Garcia <dpino@igalia.com> + + Simple ES6 feature: Number constructor extras + https://bugs.webkit.org/show_bug.cgi?id=131707 + + Reviewed by Darin Adler. + + * runtime/CommonIdentifiers.h: + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::finishCreation): Setup constants and + functions. + (JSC::numberConstructorFuncIsFinite): Added. + (JSC::numberConstructorFuncIsInteger): Added. + (JSC::numberConstructorFuncIsNaN): Added. + (JSC::numberConstructorFuncIsSafeInteger): Added. + (JSC::NumberConstructor::getOwnPropertySlot): Deleted. + (JSC::numberConstructorNaNValue): Deleted. + (JSC::numberConstructorNegInfinity): Deleted. + (JSC::numberConstructorPosInfinity): Deleted. + (JSC::numberConstructorMaxValue): Deleted. + (JSC::numberConstructorMinValue): Deleted. + * runtime/NumberConstructor.h: + +2014-09-26 Filip Pizlo <fpizlo@apple.com> + + Disable function.arguments + https://bugs.webkit.org/show_bug.cgi?id=137167 + + Rubber stamped by Geoffrey Garen. + + Add an option to disable function.arguments. Add a test for disabling it. + + Disabling function.arguments means that it returns an Arguments object that claims that + there were zero arguments. All other Arguments functionality still works, so any code + that tries to inspect this object will still think that it is looking at a perfectly + valid Arguments object. + + This also makes function.arguments disabled by default. Note that the RJST harness will + enable them by default, to continue to get test coverage for the code that implements + the feature. + + We will rip out that code once we're confident that it's really safe to remove this + feature. Only once we rip out that support will we be able to do optimizations to + leverage the lack of this feature. It's important to keep the support code, and the test + infrastructure, in place before we are confident. The logic to keep this working touches + the entire compiler and a large chunk of the runtime, so reimplementing it - or even + merging it back in - would be a nightmare. That's also basically the reason why we want + to rip it out if at all possible. It's a lot of terrible code. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::createArguments): + * runtime/Arguments.h: + (JSC::Arguments::create): + (JSC::Arguments::finishCreation): + * runtime/Options.h: + * tests/stress/disable-function-dot-arguments.js: Added. + (foo): + (bar): + +2014-09-26 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Automatic Inspection should continue once all breakpoints are loaded + https://bugs.webkit.org/show_bug.cgi?id=137038 + + Reviewed by Timothy Hatcher. + + Add a new protocol command "Inspector.initialized" that signifies to the backend + when the frontend has sent all its initialization messages to the backend. This + can include information like breakpoints, which we would want to have loaded + before any JavaScript evaluates in the context. + + * inspector/protocol/InspectorDomain.json: + New protocol command, Inspector.initialized. + + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::InspectorAgent): + (Inspector::InspectorAgent::initialized): + Tell the InspectorEnvironment (the Controller) the frontend has initialized. + + * inspector/InspectorEnvironment.h: + Abstract virtual method to handle frontend initialization. To be + implemented by all of the InspectorControllers. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + (Inspector::JSGlobalObjectInspectorController::disconnectFrontend): + (Inspector::JSGlobalObjectInspectorController::frontendInitialized): + When a frontend is initialized, if it was automatic inspection unpause the debuggable. + + * inspector/remote/RemoteInspectorDebuggable.cpp: + (Inspector::RemoteInspectorDebuggable::unpauseForInitializedInspector): + Complete setup for this debuggable. + + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + Move the setup complete to later, when the frontend sends an "initialized" message. + + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::updateDebuggableAutomaticInspectCandidate): + Provide a longer timeout now that the frontend must send messages after the connection + has established. The longest I have seen in 600ms, but the average tends to be 200ms. + So bump the timeout to 800ms for a buffer. + + (Inspector::RemoteInspector::setupSucceeded): Deleted. + (Inspector::RemoteInspector::setupCompleted): + Rename, as this happens at a slightly different time. + +2014-09-26 Filip Pizlo <fpizlo@apple.com> + + DFG shouldn't insert store barriers when it has it on good authority that we're not storing a cell + https://bugs.webkit.org/show_bug.cgi?id=137161 + + Reviewed by Mark Hahnenberg. + + This looks like a 1% Octane speed-up. + + * bytecode/SpeculatedType.h: + (JSC::isNotCellSpeculation): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::insertStoreBarrier): + (JSC::DFG::FixupPhase::insertCheck): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateNotCell): + +2014-09-26 Peter Varga <pvarga@webkit.org> + + Fix typo in YARR at BOL check + https://bugs.webkit.org/show_bug.cgi?id=137144 + + Reviewed by Darin Adler. + + * yarr/YarrPattern.cpp: replace bitwise and operator by logical and + (JSC::Yarr::YarrPatternConstructor::assertionBOL): + +2014-09-25 Saam Barati <saambarati1@gmail.com> + + Web Inspector: console.assert(bitString) TypeSet:50 + https://bugs.webkit.org/show_bug.cgi?id=137051 + + Reviewed by Joseph Pecoraro. + + This patch creates stricter requirements on a TypeDescription + being valid. To be valid, a TypeDescription now ensures that + the TypeSet it describes has non null type information. + + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * runtime/TypeSet.h: + (JSC::TypeSet::isEmpty): + +2014-09-25 Filip Pizlo <fpizlo@apple.com> + + FTL should sink object allocations + https://bugs.webkit.org/show_bug.cgi?id=136330 + + Reviewed by Oliver Hunt. + + This adds a comprehensive infrastructure for sinking object allocations in DFG SSA form. The + ultimate goal of sinking is to sink an allocation "past the points of its death" - i.e. to + eliminate it completely. The way sinking reasons about the CFG means that it resembles a + partial escape analysis: we create paths through a function where some allocation(s) don't + have to be done at all even if there are other paths along which those allocations still have + to happen. But it also produces other side benefits. Even if an allocation isn't eliminated + along any path, the act of sinking reduces the number of barriers that have to execute. + + Because this was a fairly ambituous SSA analysis and transformation, I added a bunch of C++11 + sugar to the DFG's internal APIs to allow for easier iteration over blocks, nodes, and + successors; and to add more functor goodness to allow for more lambdas. + + This is just the beginning. The bug has a bunch of other bugs that depend on it. So far this + is a spectacular speed-up on microbenchmarks but it's still too limited to affect big + benchmarks. For example, doing o == p makes the sinking phase think that o and p escape. + That's just an omission and there are likely others; we can easily fix them. I think it's + best to land it in its current form and then to worry about the big benchmarks in subsequent + work (see bug 137126). + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/StructureSet.h: + (JSC::StructureSet::iterator::iterator): + (JSC::StructureSet::iterator::operator*): + (JSC::StructureSet::iterator::operator++): + (JSC::StructureSet::iterator::operator==): + (JSC::StructureSet::iterator::operator!=): + (JSC::StructureSet::begin): + (JSC::StructureSet::end): + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::phiChildren): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::AbstractInterpreter): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::startExecuting): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::execute): + * dfg/DFGAvailability.h: + (JSC::DFG::Availability::shouldUseNode): + (JSC::DFG::Availability::isFlushUseful): + (JSC::DFG::Availability::isDead): + (JSC::DFG::Availability::operator!=): + * dfg/DFGAvailabilityMap.cpp: Added. + (JSC::DFG::AvailabilityMap::prune): + (JSC::DFG::AvailabilityMap::clear): + (JSC::DFG::AvailabilityMap::dump): + (JSC::DFG::AvailabilityMap::operator==): + (JSC::DFG::AvailabilityMap::merge): + * dfg/DFGAvailabilityMap.h: Added. + (JSC::DFG::AvailabilityMap::forEachAvailability): + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::SSAData::SSAData): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::begin): + (JSC::DFG::BasicBlock::end): + (JSC::DFG::BasicBlock::SuccessorsIterable::SuccessorsIterable): + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::iterator): + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator*): + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator++): + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator==): + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator!=): + (JSC::DFG::BasicBlock::SuccessorsIterable::begin): + (JSC::DFG::BasicBlock::SuccessorsIterable::end): + (JSC::DFG::BasicBlock::successors): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGFlushedAt.cpp: + (JSC::DFG::FlushedAt::dump): + * dfg/DFGFlushedAt.h: + (JSC::DFG::FlushedAt::FlushedAt): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::dumpBlockHeader): + (JSC::DFG::Graph::mergeRelevantToOSR): + (JSC::DFG::Graph::invalidateCFG): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::NaturalBlockIterable::NaturalBlockIterable): + (JSC::DFG::Graph::NaturalBlockIterable::iterator::iterator): + (JSC::DFG::Graph::NaturalBlockIterable::iterator::operator*): + (JSC::DFG::Graph::NaturalBlockIterable::iterator::operator++): + (JSC::DFG::Graph::NaturalBlockIterable::iterator::operator==): + (JSC::DFG::Graph::NaturalBlockIterable::iterator::operator!=): + (JSC::DFG::Graph::NaturalBlockIterable::iterator::findNext): + (JSC::DFG::Graph::NaturalBlockIterable::begin): + (JSC::DFG::Graph::NaturalBlockIterable::end): + (JSC::DFG::Graph::blocksInNaturalOrder): + (JSC::DFG::Graph::doToChildrenWithNode): + (JSC::DFG::Graph::doToChildren): + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGInsertOSRHintsForUpdate.cpp: Added. + (JSC::DFG::insertOSRHintsForUpdate): + * dfg/DFGInsertOSRHintsForUpdate.h: Added. + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::graph): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPutByOffsetHint): + (JSC::DFG::Node::convertToPutStructureHint): + (JSC::DFG::Node::convertToPhantomNewObject): + (JSC::DFG::Node::isCellConstant): + (JSC::DFG::Node::castConstant): + (JSC::DFG::Node::hasIdentifier): + (JSC::DFG::Node::hasStorageAccessData): + (JSC::DFG::Node::hasObjectMaterializationData): + (JSC::DFG::Node::objectMaterializationData): + (JSC::DFG::Node::isPhantomObjectAllocation): + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::OSRAvailabilityAnalysisPhase::run): + (JSC::DFG::LocalOSRAvailabilityCalculator::endBlock): + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGOSRAvailabilityAnalysisPhase.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: Added. + (JSC::DFG::ObjectAllocationSinkingPhase::ObjectAllocationSinkingPhase): + (JSC::DFG::ObjectAllocationSinkingPhase::run): + (JSC::DFG::ObjectAllocationSinkingPhase::performSinking): + (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + (JSC::DFG::ObjectAllocationSinkingPhase::resolve): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize): + (JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize): + (JSC::DFG::performObjectAllocationSinking): + * dfg/DFGObjectAllocationSinkingPhase.h: Added. + * dfg/DFGObjectMaterializationData.cpp: Added. + (JSC::DFG::PhantomPropertyValue::dump): + (JSC::DFG::ObjectMaterializationData::dump): + (JSC::DFG::ObjectMaterializationData::oneWaySimilarityScore): + (JSC::DFG::ObjectMaterializationData::similarityScore): + * dfg/DFGObjectMaterializationData.h: Added. + (JSC::DFG::PhantomPropertyValue::PhantomPropertyValue): + (JSC::DFG::PhantomPropertyValue::operator==): + * dfg/DFGPhantomCanonicalizationPhase.cpp: + (JSC::DFG::PhantomCanonicalizationPhase::run): + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPhiChildren.cpp: Added. + (JSC::DFG::PhiChildren::PhiChildren): + (JSC::DFG::PhiChildren::~PhiChildren): + (JSC::DFG::PhiChildren::upsilonsOf): + * dfg/DFGPhiChildren.h: Added. + (JSC::DFG::PhiChildren::forAllIncomingValues): + (JSC::DFG::PhiChildren::forAllTransitiveIncomingValues): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPrePostNumbering.cpp: Added. + (JSC::DFG::PrePostNumbering::PrePostNumbering): + (JSC::DFG::PrePostNumbering::~PrePostNumbering): + (JSC::DFG::PrePostNumbering::compute): + (WTF::printInternal): + * dfg/DFGPrePostNumbering.h: Added. + (JSC::DFG::PrePostNumbering::preNumber): + (JSC::DFG::PrePostNumbering::postNumber): + (JSC::DFG::PrePostNumbering::isStrictAncestorOf): + (JSC::DFG::PrePostNumbering::isAncestorOf): + (JSC::DFG::PrePostNumbering::isStrictDescendantOf): + (JSC::DFG::PrePostNumbering::isDescendantOf): + (JSC::DFG::PrePostNumbering::edgeKind): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGPromoteHeapAccess.h: Added. + (JSC::DFG::promoteHeapAccess): + * dfg/DFGPromotedHeapLocation.cpp: Added. + (JSC::DFG::PromotedLocationDescriptor::dump): + (JSC::DFG::PromotedHeapLocation::createHint): + (JSC::DFG::PromotedHeapLocation::dump): + (WTF::printInternal): + * dfg/DFGPromotedHeapLocation.h: Added. + (JSC::DFG::PromotedLocationDescriptor::PromotedLocationDescriptor): + (JSC::DFG::PromotedLocationDescriptor::operator!): + (JSC::DFG::PromotedLocationDescriptor::kind): + (JSC::DFG::PromotedLocationDescriptor::info): + (JSC::DFG::PromotedLocationDescriptor::hash): + (JSC::DFG::PromotedLocationDescriptor::operator==): + (JSC::DFG::PromotedLocationDescriptor::operator!=): + (JSC::DFG::PromotedLocationDescriptor::isHashTableDeletedValue): + (JSC::DFG::PromotedHeapLocation::PromotedHeapLocation): + (JSC::DFG::PromotedHeapLocation::operator!): + (JSC::DFG::PromotedHeapLocation::kind): + (JSC::DFG::PromotedHeapLocation::base): + (JSC::DFG::PromotedHeapLocation::info): + (JSC::DFG::PromotedHeapLocation::descriptor): + (JSC::DFG::PromotedHeapLocation::hash): + (JSC::DFG::PromotedHeapLocation::operator==): + (JSC::DFG::PromotedHeapLocation::isHashTableDeletedValue): + (JSC::DFG::PromotedHeapLocationHash::hash): + (JSC::DFG::PromotedHeapLocationHash::equal): + * dfg/DFGSSACalculator.cpp: + (JSC::DFG::SSACalculator::reset): + * dfg/DFGSSACalculator.h: + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureRegistrationPhase.cpp: + (JSC::DFG::StructureRegistrationPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLExitPropertyValue.cpp: Added. + (JSC::FTL::ExitPropertyValue::dump): + * ftl/FTLExitPropertyValue.h: Added. + (JSC::FTL::ExitPropertyValue::ExitPropertyValue): + (JSC::FTL::ExitPropertyValue::operator!): + (JSC::FTL::ExitPropertyValue::location): + (JSC::FTL::ExitPropertyValue::value): + * ftl/FTLExitTimeObjectMaterialization.cpp: Added. + (JSC::FTL::ExitTimeObjectMaterialization::ExitTimeObjectMaterialization): + (JSC::FTL::ExitTimeObjectMaterialization::~ExitTimeObjectMaterialization): + (JSC::FTL::ExitTimeObjectMaterialization::add): + (JSC::FTL::ExitTimeObjectMaterialization::get): + (JSC::FTL::ExitTimeObjectMaterialization::dump): + * ftl/FTLExitTimeObjectMaterialization.h: Added. + (JSC::FTL::ExitTimeObjectMaterialization::type): + (JSC::FTL::ExitTimeObjectMaterialization::properties): + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::materializeNewObject): + (JSC::FTL::ExitValue::dumpInContext): + * ftl/FTLExitValue.h: + (JSC::FTL::ExitValue::isObjectMaterialization): + (JSC::FTL::ExitValue::objectMaterialization): + (JSC::FTL::ExitValue::withVirtualRegister): + (JSC::FTL::ExitValue::valueFormat): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCheckStructure): + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + (JSC::FTL::LowerDFGToLLVM::compilePutStructure): + (JSC::FTL::LowerDFGToLLVM::compileNewObject): + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint): + (JSC::FTL::LowerDFGToLLVM::compileCheckStructureImmediate): + (JSC::FTL::LowerDFGToLLVM::compileMaterializeNewObject): + (JSC::FTL::LowerDFGToLLVM::checkStructure): + (JSC::FTL::LowerDFGToLLVM::allocateCell): + (JSC::FTL::LowerDFGToLLVM::storeStructure): + (JSC::FTL::LowerDFGToLLVM::allocateObject): + (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID): + (JSC::FTL::LowerDFGToLLVM::appendOSRExit): + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability): + (JSC::FTL::LowerDFGToLLVM::exitValueForNode): + (JSC::FTL::LowerDFGToLLVM::weakStructureID): + (JSC::FTL::LowerDFGToLLVM::weakStructure): + (JSC::FTL::LowerDFGToLLVM::availabilityMap): + (JSC::FTL::LowerDFGToLLVM::availability): Deleted. + * ftl/FTLOSRExit.h: + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileRecovery): + (JSC::FTL::compileStub): + * ftl/FTLOperations.cpp: Added. + (JSC::FTL::operationNewObjectWithButterfly): + (JSC::FTL::operationMaterializeObjectInOSR): + * ftl/FTLOperations.h: Added. + * ftl/FTLSwitchCase.h: + (JSC::FTL::SwitchCase::SwitchCase): + * runtime/JSObject.h: + (JSC::JSObject::finishCreation): + (JSC::JSFinalObject::JSFinalObject): + (JSC::JSFinalObject::create): + * runtime/Structure.cpp: + (JSC::Structure::canUseForAllocationsOf): + * runtime/Structure.h: + * tests/stress/elidable-new-object-roflcopter-then-exit.js: Added. + (sumOfArithSeries): + (foo): + * tests/stress/elide-new-object-dag-then-exit.js: Added. + (sumOfArithSeries): + (bar): + (verify): + (foo): + * tests/stress/obviously-elidable-new-object-then-exit.js: Added. + (sumOfArithSeries): + (foo): + +2014-09-25 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: Check event loop input extents during replaying too + https://bugs.webkit.org/show_bug.cgi?id=136316 + + Reviewed by Timothy Hatcher. + + Sometimes we see different nondeterminism during capture and replay + executions, so we should add determinism checks during replay too. + + Move the withinEventLoopInputExtent flag to the base class, and tighten + the assertion to address <http://webkit.org/b/133019>. + + * replay/InputCursor.h: + (JSC::InputCursor::InputCursor): + (JSC::InputCursor::setWithinEventLoopInputExtent): Added. + This assertion is slightly wrong because it does not account for nested run loops. + We can be within two input extents when a nested run loop processes additional + user inputs while the debugger is paused. + + This should only be the case when execution is being neither captured or + replayed. The debugger should not pause when capturing, and we should not replay + event loop inputs while in a nested run loop. + + (JSC::InputCursor::withinEventLoopInputExtent): Added. + +2014-09-25 Csaba Osztrogonác <ossy@webkit.org> + + Remove WinCE port from trunk + https://bugs.webkit.org/show_bug.cgi?id=136951 + + Reviewed by Alex Christensen. + + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::cacheFlush): + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::cacheFlush): + * config.h: + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::gatherFromCurrentThread): + (JSC::MachineThreads::gatherFromOtherThread): + (JSC::swapIfBackwards): Deleted. + * jit/ExecutableAllocator.h: + * jsc.cpp: + (main): + * runtime/DateConstructor.cpp: + * runtime/Options.cpp: + (JSC::overrideOptionWithHeuristic): + * runtime/VM.cpp: + (JSC::VM::VM): + * testRegExp.cpp: + (main): + * tools/CodeProfiling.cpp: + (JSC::CodeProfiling::notifyAllocator): + +2014-09-24 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: subtract elapsed time while debugger is paused from profile nodes + https://bugs.webkit.org/show_bug.cgi?id=136796 + + Reviewed by Timothy Hatcher. + + Rather than accruing no time to any profile node created while the debugger is paused, + we can instead count a node's elapsed time and exclude time elapsed while paused. + + Time for a node may elapse in a non-contiguous fashion depending on the interleaving of + didPause, didContinue, willExecute, and didExecute. A node's start time is set to the + start of the last such interval that accrues elapsed time. + + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::ProfileGenerator::beginCallEntry): + (JSC::ProfileGenerator::endCallEntry): + (JSC::ProfileGenerator::didPause): Added. + (JSC::ProfileGenerator::didContinue): Added. + * profiler/ProfileGenerator.h: + (JSC::ProfileGenerator::didPause): Deleted. + (JSC::ProfileGenerator::didContinue): Deleted. + * profiler/ProfileNode.h: Rename totalTime to elapsedTime. + (JSC::ProfileNode::Call::Call): + (JSC::ProfileNode::Call::elapsedTime): Added. + (JSC::ProfileNode::Call::setElapsedTime): Added. + (JSC::CalculateProfileSubtreeDataFunctor::operator()): + (JSC::ProfileNode::Call::totalTime): Deleted. + (JSC::ProfileNode::Call::setTotalTime): Deleted. + +2014-09-24 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r173839. + https://bugs.webkit.org/show_bug.cgi?id=137062 + + NumberConstruct should no longer use static tables (Requested + by dpino on #webkit). + + Reverted changeset: + + "Simple ES6 feature: Number constructor extras" + https://bugs.webkit.org/show_bug.cgi?id=131707 + http://trac.webkit.org/changeset/173839 + +2014-09-23 Mark Lam <mark.lam@apple.com> + + DebuggerCallFrame::invalidate() should invalidate all DebuggerScope chains. + <https://webkit.org/b/137045> + + Reviewed by Geoffrey Garen. + + DebuggerCallFrame::invalidate() currently invalidates all DebuggerCallFrames + in the debugger stack, but only invalidates the DebuggerScope chain of the + top most frame. We should also invalidate all the DebuggerScope chains of + the other frames in the debugger stack. + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::invalidate): + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::invalidateChain): + +2014-09-23 Mark Lam <mark.lam@apple.com> + + Renamed DebuggerCallFrameScope to DebuggerPausedScope. + <https://webkit.org/b/137042> + + Reviewed by Michael Saboff. + + DebuggerPausedScope is a better name for this data structure because it + is meant for tracking the period within which the debugger is paused, + and doing clean ups after the pause ends. + + * debugger/Debugger.cpp: + (JSC::DebuggerPausedScope::DebuggerPausedScope): + (JSC::DebuggerPausedScope::~DebuggerPausedScope): + (JSC::Debugger::pauseIfNeeded): + (JSC::DebuggerCallFrameScope::DebuggerCallFrameScope): Deleted. + (JSC::DebuggerCallFrameScope::~DebuggerCallFrameScope): Deleted. + * debugger/Debugger.h: + * debugger/DebuggerCallFrame.h: + +2014-09-23 Tomas Popela <tpopela@redhat.com> + + [CLoop] - Fix CLoop on the 32-bit Big-Endians + https://bugs.webkit.org/show_bug.cgi?id=137020 + + Reviewed by Mark Lam. + + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + +2014-09-23 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Should be able to attach a debugger to a JSContext before anything is executed + https://bugs.webkit.org/show_bug.cgi?id=136893 + + Reviewed by Timothy Hatcher. + + Adds new remote inspector protocol handling for automatic inspection. + Debuggers can signal they have enabled automatic inspection, and + when debuggables are created the current application will pause to + see if the debugger will inspect or decline to inspect the debuggable. + + * inspector/remote/RemoteInspectorConstants.h: + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::globalAutomaticInspectionState): + (Inspector::RemoteInspector::RemoteInspector): + (Inspector::RemoteInspector::start): + When first starting, check the global "is there an auto-inspect" debugger state. + This is necessary so that the current application knows if it should pause or + not when a debuggable is created, even without having connected to webinspectord yet. + + (Inspector::RemoteInspector::updateDebuggableAutomaticInspectCandidate): + When a debuggable has enabled remote inspection, take this path to propose + it as an automatic inspection candidate if there is an auto-inspect debugger. + + (Inspector::RemoteInspector::sendAutomaticInspectionCandidateMessage): + Send the automatic inspection candidate message. + + (Inspector::RemoteInspector::receivedSetupMessage): + (Inspector::RemoteInspector::setupFailed): + (Inspector::RemoteInspector::setupSucceeded): + After attempting to open an inspector, unpause if it was for the + automatic inspection candidate. + + (Inspector::RemoteInspector::waitingForAutomaticInspection): + When running a nested runloop, check if we should remain paused. + + (Inspector::RemoteInspector::setupXPCConnectionIfNeeded): + If by the time we connect to webinspectord we have a candidate, then + immediately send the candidate message. + + (Inspector::RemoteInspector::stopInternal): + (Inspector::RemoteInspector::xpcConnectionFailed): + In error cases, clear our state. + + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + (Inspector::RemoteInspector::receivedAutomaticInspectionConfigurationMessage): + (Inspector::RemoteInspector::receivedAutomaticInspectionRejectMessage): + Update state when receiving new messages. + + + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggable.cpp: + (Inspector::RemoteInspectorDebuggable::setRemoteDebuggingAllowed): + Special case when a debuggable is newly allowed to be debuggable. + + (Inspector::RemoteInspectorDebuggable::pauseWaitingForAutomaticInspection): + Run a nested run loop while this is an automatic inspection candidate. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + When the inspector starts via automatic inspection automatically pause. + We plan on removing this condition by having the frontend signal to the + backend when it is completely initialized. + + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + Pass on the flag of whether or not this was automatic inspection. + + * runtime/JSGlobalObjectDebuggable.h: + * runtime/JSGlobalObjectDebuggable.cpp: + (JSC::JSGlobalObjectDebuggable::connect): + (JSC::JSGlobalObjectDebuggable::pauseWaitingForAutomaticInspection): + When pausing in a JSGlobalObject we need to release the API lock. + +2014-09-22 Filip Pizlo <fpizlo@apple.com> + + FTL allocatePropertyStorage code should involve less copy-paste + https://bugs.webkit.org/show_bug.cgi?id=137006 + + Reviewed by Michael Saboff. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::allocatePropertyStorageWithSizeImpl): + +2014-09-22 Diego Pino Garcia <dpino@igalia.com> + + Simple ES6 feature: Number constructor extras + https://bugs.webkit.org/show_bug.cgi?id=131707 + + Reviewed by Darin Adler. + + * runtime/CommonIdentifiers.h: Added new identifiers. + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::getOwnPropertySlot): + (JSC::NumberConstructor::isFunction): Added. + (JSC::numberConstructorEpsilonValue): Added. + (JSC::numberConstructorNegInfinity): Added. + (JSC::numberConstructorPosInfinity): Added. + (JSC::numberConstructorMaxValue): Added. + (JSC::numberConstructorMinValue): Added. + (JSC::numberConstructorMaxSafeInteger): Added. + (JSC::numberConstructorMinSafeInteger): Added. + (JSC::numberConstructorFuncIsFinite): Added. + (JSC::numberConstructorFuncIsInteger): Added. + (JSC::numberConstructorFuncIsNaN): Added. + (JSC::numberConstructorFuncIsSafeInteger): Added. + * runtime/NumberConstructor.h: + +2014-09-21 Filip Pizlo <fpizlo@apple.com> + + FTL should store the four bytes of the cell header using a 32-bit store rather than four 8-bit stores + https://bugs.webkit.org/show_bug.cgi?id=136992 + + Reviewed by Sam Weinig. + + LLVM ought to be able to do this optimization for us given how the code was written, but + any such lower-level attempts to optimize this would get into trouble with the weird + object materialization logic I'll be introducing in bug 136330. So, this brings the + merging of the byte stores into the FTL lowering so that we can control it explicitly. + + * ftl/FTLAbstractHeap.h: + (JSC::FTL::AbstractHeap::changeParent): + * ftl/FTLAbstractHeapRepository.cpp: + (JSC::FTL::AbstractHeapRepository::AbstractHeapRepository): + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::allocateCell): + +2014-09-21 Saam Barati <saambarati1@gmail.com> + + Web Inspector: fix TypeSet hierarchy in TypeTokenView + https://bugs.webkit.org/show_bug.cgi?id=136982 + + Reviewed by Joseph Pecoraro. + + TypeSet was computing the set of type booleans in the Inspector::Protocol::Runtime::TypeSet + object incorrectly because it was calling TypeSet::doesTypeConformTo(T) which checks if the + type set has only been of type T. It now checks '(m_seenTypes & T) != TypeNothing' to see + if type T is in the set of seen types, but not the entire set itself. + + * runtime/TypeSet.cpp: + (JSC::TypeSet::inspectorTypeSet): + +2014-09-21 Filip Pizlo <fpizlo@apple.com> + + Structure should have a method for concurrently getting all of the property map entries, and this method shouldn't involve copy-paste + https://bugs.webkit.org/show_bug.cgi?id=136983 + + Reviewed by Mark Hahnenberg. + + * runtime/PropertyMapHashTable.h: + (JSC::PropertyMapEntry::PropertyMapEntry): Moved PropertyMapEntry struct to Structure.h so that Structure can refer to it. + * runtime/Structure.cpp: + (JSC::Structure::getConcurrently): Switch to using the new forEachPropertyConcurrently() method. + (JSC::Structure::getPropertiesConcurrently): The subject of this patch. It will be useful for object allocation sinking (bug 136330). + (JSC::Structure::dump): Switch to using the new forEachPropertyConcurrently() method. + * runtime/Structure.h: + (JSC::PropertyMapEntry::PropertyMapEntry): Moved from PropertyMapHashTable.h. + * runtime/StructureInlines.h: + (JSC::Structure::forEachPropertyConcurrently): Capture this very common concurrent structure iteration pattern into a template method. + +2014-09-21 Filip Pizlo <fpizlo@apple.com> + + Structure::getConcurrently() doesn't need to take a VM& argument. + + Rubber stamped by Dan Bernstein. + + Removed the extra argument, and then removed similar arguments from other methods until + I could build successfully again. It turned out that many methods took a VM& argument + just for calling getConcurrently(). + + * bytecode/CodeBlock.cpp: + (JSC::dumpStructure): + (JSC::dumpChain): + (JSC::CodeBlock::printGetByIdCacheStatus): + (JSC::CodeBlock::printPutByIdCacheStatus): + * bytecode/ComplexGetStatus.cpp: + (JSC::ComplexGetStatus::computeFor): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + (JSC::GetByIdStatus::computeForStubInfo): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdStatus.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::isStringPrototypeMethodSane): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::mayInterceptStoreTo): + * runtime/IntendedStructureChain.h: + * runtime/Structure.cpp: + (JSC::Structure::getConcurrently): + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::getConcurrently): + +2014-09-20 Filip Pizlo <fpizlo@apple.com> + + FTL OSRExit construction should be based on methods that return ExitValues rather than methods that add ExitValues to OSRExit + https://bugs.webkit.org/show_bug.cgi?id=136978 + + Reviewed by Dean Jackson. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + (JSC::FTL::LowerDFGToLLVM::exitValueForNode): + (JSC::FTL::LowerDFGToLLVM::exitArgument): + (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode): Deleted. + (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument): Deleted. + (JSC::FTL::LowerDFGToLLVM::addExitArgument): Deleted. + +2014-09-20 Filip Pizlo <fpizlo@apple.com> + + FTL OSR exit should do reboxing and value recovery in the same pass + https://bugs.webkit.org/show_bug.cgi?id=136977 + + Reviewed by Oliver Hunt. + + It's conceptually simpler to have all of the logic in one place. After the + recover-and-rebox loop is done, all of the exit values are in the form that the baseline + JIT would want them to be in; the only remaining task is to move them into the right + place on the stack after we do all of the necessary stack adjustments. + + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + +2014-09-19 Filip Pizlo <fpizlo@apple.com> + + StorageAccessData should be referenced in a sensible way + https://bugs.webkit.org/show_bug.cgi?id=136963 + + Reviewed and rubber stamped by Michael Saboff. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetByOffset): + (JSC::DFG::ByteCodeParser::handlePutByOffset): + (JSC::DFG::ByteCodeParser::handlePutById): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToGetByOffset): + (JSC::DFG::Node::convertToPutByOffset): + (JSC::DFG::Node::storageAccessData): + (JSC::DFG::Node::storageAccessDataIndex): Deleted. + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compilePutByOffset): + +2014-09-19 Ryosuke Niwa <rniwa@webkit.org> + + Leak of mallocs under StructureSet::OutOfLineList::create + https://bugs.webkit.org/show_bug.cgi?id=136970 + + Reviewed by Filip Pizlo. + + addOutOfLine should free the old list when expanding the capacity. + + * bytecode/StructureSet.cpp: + (JSC::StructureSet::addOutOfLine): + +2014-09-19 Daniel Bates <dabates@apple.com> + + Always assume internal SDK when building configuration Production + https://bugs.webkit.org/show_bug.cgi?id=136925 + <rdar://problem/18362399> + + Reviewed by Dan Bernstein. + + As a side effect of this change we will always enable ENABLE_TOUCH_EVENTS, ENABLE_IOS_{GESTURE, TOUCH}_EVENTS, + and ENABLE_XSLT when either building configuration Production or building with the Internal SDK. + + * Configurations/Base.xcconfig: + +2014-09-19 Diego Pino Garcia <dpino@igalia.com> + + Simple ES6 feature:String prototype additions + https://bugs.webkit.org/show_bug.cgi?id=131704 + + Reviewed by Darin Adler. + + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + (JSC::stringProtoFuncStartsWith): Added. + (JSC::stringProtoFuncEndsWith): Added. + (JSC::stringProtoFuncContains): Added. + +2014-09-18 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed rollout r173731. Broke multiple builds. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::RemoteInspector): + (Inspector::RemoteInspector::setupFailed): + (Inspector::RemoteInspector::start): + (Inspector::RemoteInspector::stopInternal): + (Inspector::RemoteInspector::setupXPCConnectionIfNeeded): + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + (Inspector::RemoteInspector::xpcConnectionFailed): + (Inspector::RemoteInspector::receivedSetupMessage): + (Inspector::globalAutomaticInspectionState): Deleted. + (Inspector::RemoteInspector::updateDebuggableAutomaticInspectCandidate): Deleted. + (Inspector::RemoteInspector::sendAutomaticInspectionCandidateMessage): Deleted. + (Inspector::RemoteInspector::setupSucceeded): Deleted. + (Inspector::RemoteInspector::waitingForAutomaticInspection): Deleted. + (Inspector::RemoteInspector::receivedAutomaticInspectionConfigurationMessage): Deleted. + (Inspector::RemoteInspector::receivedAutomaticInspectionRejectMessage): Deleted. + * inspector/remote/RemoteInspectorConstants.h: + * inspector/remote/RemoteInspectorDebuggable.cpp: + (Inspector::RemoteInspectorDebuggable::setRemoteDebuggingAllowed): + (Inspector::RemoteInspectorDebuggable::pauseWaitingForAutomaticInspection): Deleted. + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + * runtime/JSGlobalObjectDebuggable.cpp: + (JSC::JSGlobalObjectDebuggable::connect): + (JSC::JSGlobalObjectDebuggable::pauseWaitingForAutomaticInspection): Deleted. + * runtime/JSGlobalObjectDebuggable.h: + +2014-09-18 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Should be able to attach a debugger to a JSContext before anything is executed + https://bugs.webkit.org/show_bug.cgi?id=136893 + + Reviewed by Timothy Hatcher. + + Adds new remote inspector protocol handling for automatic inspection. + Debuggers can signal they have enabled automatic inspection, and + when debuggables are created the current application will pause to + see if the debugger will inspect or decline to inspect the debuggable. + + * inspector/remote/RemoteInspectorConstants.h: + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::globalAutomaticInspectionState): + (Inspector::RemoteInspector::RemoteInspector): + (Inspector::RemoteInspector::start): + When first starting, check the global "is there an auto-inspect" debugger state. + This is necessary so that the current application knows if it should pause or + not when a debuggable is created, even without having connected to webinspectord yet. + + (Inspector::RemoteInspector::updateDebuggableAutomaticInspectCandidate): + When a debuggable has enabled remote inspection, take this path to propose + it as an automatic inspection candidate if there is an auto-inspect debugger. + + (Inspector::RemoteInspector::sendAutomaticInspectionCandidateMessage): + Send the automatic inspection candidate message. + + (Inspector::RemoteInspector::receivedSetupMessage): + (Inspector::RemoteInspector::setupFailed): + (Inspector::RemoteInspector::setupSucceeded): + After attempting to open an inspector, unpause if it was for the + automatic inspection candidate. + + (Inspector::RemoteInspector::waitingForAutomaticInspection): + When running a nested runloop, check if we should remain paused. + + (Inspector::RemoteInspector::setupXPCConnectionIfNeeded): + If by the time we connect to webinspectord we have a candidate, then + immediately send the candidate message. + + (Inspector::RemoteInspector::stopInternal): + (Inspector::RemoteInspector::xpcConnectionFailed): + In error cases, clear our state. + + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + (Inspector::RemoteInspector::receivedAutomaticInspectionConfigurationMessage): + (Inspector::RemoteInspector::receivedAutomaticInspectionRejectMessage): + Update state when receiving new messages. + + + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggable.cpp: + (Inspector::RemoteInspectorDebuggable::setRemoteDebuggingAllowed): + Special case when a debuggable is newly allowed to be debuggable. + + (Inspector::RemoteInspectorDebuggable::pauseWaitingForAutomaticInspection): + Run a nested run loop while this is an automatic inspection candidate. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + When the inspector starts via automatic inspection automatically pause. + We plan on removing this condition by having the frontend signal to the + backend when it is completely initialized. + + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + Pass on the flag of whether or not this was automatic inspection. + + * runtime/JSGlobalObjectDebuggable.h: + * runtime/JSGlobalObjectDebuggable.cpp: + (JSC::JSGlobalObjectDebuggable::connect): + (JSC::JSGlobalObjectDebuggable::pauseWaitingForAutomaticInspection): + When pausing in a JSGlobalObject we need to release the API lock. + +2014-09-18 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + Fix "Tools/Scripts/build-webkit --efl --no-inspector" build + https://bugs.webkit.org/show_bug.cgi?id=136912 + + Reviewed by Darin Adler. + + * runtime/TypeSet.cpp: + (JSC::TypeSet::leastCommonAncestor): + +2014-09-17 Michael Saboff <msaboff@apple.com> + + Change CallFrame to use Callee instead of JSScope to implement vm() + https://bugs.webkit.org/show_bug.cgi?id=136894 + + Reviewed by Geoffrey Garen. + + Added JSCell::vm() method that can be used on any JSObject. Changed CallFrame::vm() to + use JSCell::vm with the Callee. Made similar changes in the LLInt. + In support of this, changed JSGlobalObject::init() to take a VM& parameter, as there is + a chicken/egg problem with trying to use the Callee in the global exec before the Callee + has been create. Besides, the vm is readily available in finishCreation(), the caller of + init(). + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Changed the calculation of CallFrame::VM to use the Callee instead of JSScope. + + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::vm): New method for getting VM from the pointer. + (JSC::ExecState::vm): Moved this method from JSScope.h to here since this file + contains the implementation of JSCell::vm(), this file is included by all users + of CallFrame::vm, and lastly putting it in CallFrameInlines.h required changing + many other .h files and possible the WebCore generator generate-bindings.pl. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::finishCreation): + Changed init() to take a VM parameter. + + * runtime/JSScope.h: + (JSC::ExecState::vm): Deleted. + +2014-09-16 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, disable native inlining because it causes build failures. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-09-16 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Reduce a bit of churn setting initial remote inspection state + https://bugs.webkit.org/show_bug.cgi?id=136875 + + Reviewed by Timothy Hatcher. + + * API/JSContextRef.cpp: + (JSGlobalContextCreateInGroup): + Set the defaultl remote debuggable state at the API boundary. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + Do not set remote debuggable state here. Let clients set it. + +2014-09-16 Yusuke Suzuki <utatane.tea@gmail.com> + + Promise: Drop Promise.cast + https://bugs.webkit.org/show_bug.cgi?id=136222 + + Reviewed by Sam Weinig. + + Promise.cast is dropped and Promise.resolve is replaced with old Promise.cast. + + * runtime/CommonIdentifiers.h: + * runtime/JSPromiseConstructor.cpp: + (JSC::JSPromiseConstructorFuncResolve): + (JSC::JSPromiseConstructorFuncRace): + (JSC::JSPromiseConstructorFuncAll): + (JSC::JSPromiseConstructorFuncCast): Deleted. + +2014-09-16 Filip Pizlo <fpizlo@apple.com> + + Local OSR availability calculation should be reusable + https://bugs.webkit.org/show_bug.cgi?id=136860 + + Reviewed by Oliver Hunt. + + Previously, the FTL lowering repeated some of the logic of the OSR availability analysis + phase. Humorously, it actually did this logic a bit differently; for example the phase + would claim that a SetLocal makes both the flush and the node available while the FTL + only claimed that the flush was available. This different was benign, but still: yuck! + + Also, previously if you wanted to use availability information then you'd have to repeat + some of the logic that both the phase itself and the FTL lowering already had. + Presumably, you could get epic style points for finding other benign ways in which to + make your copy of the logic different from the other two! + + This reduces the amount of style points one could conceivably get in the future when + hacking JSC, by creating a single reusable thingy for computing local OSR availability. + + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::OSRAvailabilityAnalysisPhase::run): + (JSC::DFG::LocalOSRAvailabilityCalculator::LocalOSRAvailabilityCalculator): + (JSC::DFG::LocalOSRAvailabilityCalculator::~LocalOSRAvailabilityCalculator): + (JSC::DFG::LocalOSRAvailabilityCalculator::beginBlock): + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGOSRAvailabilityAnalysisPhase.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM): + (JSC::FTL::LowerDFGToLLVM::compileBlock): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileSetLocal): + (JSC::FTL::LowerDFGToLLVM::compileInvalidationPoint): + (JSC::FTL::LowerDFGToLLVM::appendOSRExit): + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + (JSC::FTL::LowerDFGToLLVM::availability): + (JSC::FTL::LowerDFGToLLVM::compileMovHint): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileZombieHint): Deleted. + (JSC::FTL::LowerDFGToLLVM::initializeOSRExitStateForBlock): Deleted. + +2014-09-16 Csaba Osztrogonác <ossy@webkit.org> + + JSC test gardening + https://bugs.webkit.org/show_bug.cgi?id=136823 + + Reviewed by Geoffrey Garen. + + * tests/mozilla/mozilla-tests.yaml: Unskip passing tests. + +2014-09-15 Michael Saboff <msaboff@apple.com> + + Create a JSCallee for GlobalExec object + https://bugs.webkit.org/show_bug.cgi?id=136840 + + Reviewed by Geoffrey Garen. + + Added m_globalCallee, initialized it and then used it to set the globalExec's callee. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + +2014-09-14 Filip Pizlo <fpizlo@apple.com> + + DFG ref count calculation should be reusable + https://bugs.webkit.org/show_bug.cgi?id=136811 + + Reviewed by Oliver Hunt. + + Henceforth if you call Graph::computeRefCounts(), a nifty O(n) operation, every Node + will be able to tell you how many places it is used from. Currently only DCE uses this, + but it will be useful for https://bugs.webkit.org/show_bug.cgi?id=136330. + + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + (JSC::DFG::DCEPhase::findTypeCheckRoot): Deleted. + (JSC::DFG::DCEPhase::countNode): Deleted. + (JSC::DFG::DCEPhase::countEdge): Deleted. + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::computeRefCounts): + * dfg/DFGGraph.h: + +2014-09-12 Michael Saboff <msaboff@apple.com> + + Merge JSGlobalObject::reset() into ::init() + https://bugs.webkit.org/show_bug.cgi?id=136800 + + Reviewed by Oliver Hunt. + + Moved the contents of reset() into init(). + Note that the diff shows more changes. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): Moved body of reset() into init. + (JSC::JSGlobalObject::put): + (JSC::JSGlobalObject::defineOwnProperty): + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + (JSC::lastInPrototypeChain): + (JSC::JSGlobalObject::reset): Deleted. + * runtime/JSGlobalObject.h: + +2014-09-12 Michael Saboff <msaboff@apple.com> + + Add JSCallee to program and eval CallFrames + https://bugs.webkit.org/show_bug.cgi?id=136785 + + Reviewed by Mark Lam. + + Populated Callee slot for program and call eval CallFrames with a JSCallee objects. + Made supporting changes including adding a JSCallee structure to global object and adding + JSCallee::create() method. Added code so that the newly added callee object won't be + returned by Function.caller. Changed null pointer checks of callee to check the if + the type is JSFunction* or JSCallee*. + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::functionName): + (JSC::DebuggerCallFrame::type): + * profiler/LegacyProfiler.cpp: + (JSC::LegacyProfiler::createCallIdentifier): + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + Changed checks of callee is a JSFunction* or JSCallee* instead of just checking + if it is null or not. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): Create and use JSCallee objects for execute(EvalExecutable, ...) + and execute(ProgramExecutable, ...) + + * jit/JITCode.cpp: + (JSC::JITCode::execute): Use jsDynamicCast to cast only JSFunctions. + + * runtime/JSCallee.cpp: + (JSC::JSCallee::create): Not used, therefore deleted. + + * runtime/JSCallee.h: + (JSC::JSCallee::create): Added. + + * runtime/JSFunction.cpp: + (JSC::JSFunction::callerGetter): Added test to return null for JSCallee's that aren't + JSFunction's. This can only be the case when the JSCallee comes from a program or + call eval CallFrame. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::calleeStructure): + Added new JSCallee structure. + +2014-09-10 Jon Honeycutt <jhoneycutt@apple.com> + + Re-add the request autocomplete feature + + <https://bugs.webkit.org/show_bug.cgi?id=136730> + + This feature was rolled out in r148731 because it was only used by + Chromium. As we consider supporting this feature, roll it back in, but + leave it disabled. + + This rolls out r148731 (which removed the feature) with small changes + needed to make the code build in ToT, to match modern style, to make + the tests run, and to remove unused code. + + Reviewed by Andy Estes. + + * Configurations/FeatureDefines.xcconfig: + +2014-09-12 Julien Brianceau <jbriance@cisco.com> + + [x86] moveDoubleToInts() does not clobber its source register anymore + https://bugs.webkit.org/show_bug.cgi?id=131690 + + Reviewed by Oliver Hunt. + + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::moveDoubleToInts): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileValueRep): + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::returnDouble): + +2014-09-12 Mark Lam <mark.lam@apple.com> + + Unreviewed build fix for CLOOP build. + + * runtime/JSCallee.h: + +2014-09-12 Michael Saboff <msaboff@apple.com> + + Remove unneeded declarations from JSCallee.h + https://bugs.webkit.org/show_bug.cgi?id=136783 + + Reviewed by Mark Lam. + + * runtime/JSCallee.h: + (JSCallee::name): Deleted. + (JSCallee::displayName): Deleted. + (JSCallee::calculatedDisplayName): Deleted. + +2014-09-11 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: disambiguate double and integer primitive types in the protocol + https://bugs.webkit.org/show_bug.cgi?id=136606 + + Reviewed by Timothy Hatcher. + + Right now it's really easy to mix up doubles and integers when serializing or deserializing + values for the inspector protocol. This patch disambiguates setting/getting doubles and integers + so that it is clearer as to which type is intended. + + A new InspectorValue::Type is added for Integer types, and the Number type is renamed to Double. + The existing callsites for asNumber/getNumber/setNumber have been fixed. + + Address various integration points to make sure the right type tag is assigned to InspectorValues. + + * bindings/ScriptValue.cpp: + (Deprecated::jsToInspectorValue): Make an Integer if the JSValue is Int52 or smaller. + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::injectedScriptForObjectId): + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::InspectorBackendDispatcher::dispatch): + (Inspector::InspectorBackendDispatcher::sendResponse): + (Inspector::InspectorBackendDispatcher::reportProtocolError): + (Inspector::AsMethodBridges::asInteger): + (Inspector::AsMethodBridges::asDouble): + (Inspector::InspectorBackendDispatcher::getInteger): + (Inspector::InspectorBackendDispatcher::getDouble): + (Inspector::AsMethodBridges::asInt): Deleted. + (Inspector::InspectorBackendDispatcher::getInt): Deleted. + * inspector/InspectorBackendDispatcher.h: + * inspector/InspectorProtocolTypes.h: Remove the special case for checking int type tags. + (Inspector::Protocol::ArrayItemHelper<int>::Traits::pushRaw): + (Inspector::Protocol::ArrayItemHelper<double>::Traits::pushRaw): + (Inspector::Protocol::BindingTraits<int>::assertValueHasExpectedType): Deleted. + * inspector/InspectorValues.cpp: Allow integers and doubles to be convertible using asInteger/asDouble. + (Inspector::InspectorValue::asDouble): + (Inspector::InspectorValue::asInteger): + (Inspector::InspectorBasicValue::asDouble): + (Inspector::InspectorBasicValue::asInteger): + (Inspector::InspectorBasicValue::writeJSON): + (Inspector::InspectorValue::asNumber): Deleted. + (Inspector::InspectorBasicValue::asNumber): Deleted. + * inspector/InspectorValues.h: + (Inspector::InspectorObjectBase::setInteger): + (Inspector::InspectorObjectBase::setDouble): + (Inspector::InspectorArrayBase::pushInteger): + (Inspector::InspectorArrayBase::pushDouble): + (Inspector::InspectorObjectBase::setNumber): Deleted. + (Inspector::InspectorArrayBase::pushInt): Deleted. + (Inspector::InspectorArrayBase::pushNumber): Deleted. + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::buildObjectForBreakpointCookie): + (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): + (Inspector::parseLocation): + (Inspector::InspectorDebuggerAgent::didParseSource): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/scripts/codegen/generator.py: Update emitted code and rebaseline test results. + (Generator.keyed_get_method_for_type): + (Generator.keyed_set_method_for_type): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * replay/EncodedValue.cpp: + (JSC::EncodedValue::convertTo<double>): + (JSC::EncodedValue::convertTo<float>): + (JSC::EncodedValue::convertTo<int32_t>): + (JSC::EncodedValue::convertTo<int64_t>): + (JSC::EncodedValue::convertTo<uint32_t>): + (JSC::EncodedValue::convertTo<uint64_t>): + +2014-09-11 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Occasional ASSERT closing web inspector + https://bugs.webkit.org/show_bug.cgi?id=136762 + + Reviewed by Timothy Hatcher. + + It is harmless, and indeed possible to have an empty set of listeners + now that each Page gets its own PageDebugServer instead of a shared + global. So we should replace the null checks with isEmpty checks. + Since nobody was ever returning null, convert to references as well. + + * inspector/JSGlobalObjectScriptDebugServer.h: + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::dispatchBreakpointActionLog): + (Inspector::ScriptDebugServer::dispatchBreakpointActionSound): + (Inspector::ScriptDebugServer::dispatchBreakpointActionProbe): + (Inspector::ScriptDebugServer::sourceParsed): + (Inspector::ScriptDebugServer::dispatchFunctionToListeners): + (Inspector::ScriptDebugServer::notifyDoneProcessingDebuggerEvents): + (Inspector::ScriptDebugServer::handlePause): + (Inspector::ScriptDebugServer::needPauseHandling): Deleted. + * inspector/ScriptDebugServer.h: + +2014-09-10 Michael Saboff <msaboff@apple.com> + + Move JSScope out of JSFunction into separate JSCallee class + https://bugs.webkit.org/show_bug.cgi?id=136725 + + Reviewed by Oliver Hunt. + + Created new JSCallee class that contains a JSScope*. Changed JSFunction to inherit from + JSCallee. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + Build changes. Added JSCallee.cpp and JSCallee.h. + + * runtime/JSCallee.cpp: Added. + (JSC::JSCallee::create): + (JSC::JSCallee::destroy): + (JSC::JSCallee::JSCallee): + (JSC::JSCallee::finishCreation): + (JSC::JSCallee::visitChildren): + (JSC::JSCallee::getOwnPropertySlot): Pass through wrapper function. + (JSC::JSCallee::getOwnNonIndexPropertyNames): Pass through wrapper function. + (JSC::JSCallee::put): Pass through wrapper function. + (JSC::JSCallee::deleteProperty): Pass through wrapper function. + (JSC::JSCallee::defineOwnProperty): Pass through wrapper function. + + * runtime/JSCallee.h: Added. + (JSC::JSCallee::scope): + (JSC::JSCallee::scopeUnchecked): + (JSC::JSCallee::setScope): + (JSC::JSCallee::createStructure): + (JSC::JSCallee::offsetOfScopeChain): + + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + (JSC::JSFunction::addNameScopeIfNeeded): + (JSC::JSFunction::visitChildren): + * runtime/JSFunction.h: + (JSC::JSFunction::scope): Deleted. + (JSC::JSFunction::scopeUnchecked): Deleted. + (JSC::JSFunction::setScope): Deleted. + (JSC::JSFunction::offsetOfScopeChain): Deleted. + * runtime/JSFunctionInlines.h: + (JSC::JSFunction::JSFunction): + Changed to reference JSCallee and its methods. + + * runtime/JSType.h: Added JSCallee as a TypeEnum. + +2014-09-11 Filip Pizlo <fpizlo@apple.com> + + REGRESSION (r172129): Vine pages load as blank + https://bugs.webkit.org/show_bug.cgi?id=136655 + rdar://problem/18281215 + + Reviewed by Michael Saboff. + + If lastNode is something that is subject to DCE, then removing the Phantom's reference to something + that lastNode references means that the thing being referenced may no longer be kept alive for OSR. + Teach PhantomRemovalPhase that it's only safe to do this if lastNode is a Phantom. That's probably too + conservative, but that's fine since this is mainly just an optimization to make the IR sane to read and + reasonably compact; it's OK if we miss cases here. + + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * tests/stress/remove-phantom-after-setlocal.js: Added. + +2014-09-11 Bear Travis <betravis@adobe.com> + + [CSS Font Loading] Enable CSS Font Loading on Mac + https://bugs.webkit.org/show_bug.cgi?id=135473 + + Reviewed by Antti Koivisto. + + Enable CSS Font Loading in FeatureDefines. + + * Configurations/FeatureDefines.xcconfig: + +2014-09-11 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed rebaseline of inspector generator test results after r173120. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + +2014-09-11 Oliver Hunt <oliver@apple.com> + + Rename activation to be more in line with spec language + https://bugs.webkit.org/show_bug.cgi?id=136721 + + Reviewed by Michael Saboff. + + Somewhat bigger than the last one, but still just a rename. + + * CMakeLists.txt: + * JavaScriptCore.order: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CallVariant.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::isCaptured): + (JSC::CodeBlock::nameForRegister): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::setActivationRegister): + (JSC::CodeBlock::activationRegister): + (JSC::CodeBlock::uncheckedActivationRegister): + (JSC::CodeBlock::needsActivation): + * bytecode/Instruction.h: + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::setActivationRegister): + (JSC::UnlinkedCodeBlock::activationRegister): + (JSC::UnlinkedCodeBlock::hasActivationRegister): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitReturn): + * bytecompiler/BytecodeGenerator.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::scope): + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::isFunctionOrEvalScope): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetActivation): + (JSC::DFG::Graph::tryGetRegisters): + * dfg/DFGGraph.h: + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * interpreter/CallFrame.cpp: + (JSC::CallFrame::lexicalEnvironment): + (JSC::CallFrame::setActivation): + (JSC::CallFrame::activation): Deleted. + * interpreter/CallFrame.h: + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + * interpreter/Register.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_tear_off_lexical_environment): + (JSC::JIT::emit_op_tear_off_arguments): + (JSC::JIT::emit_op_create_lexical_environment): + (JSC::JIT::emit_op_tear_off_activation): Deleted. + (JSC::JIT::emit_op_create_activation): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_tear_off_lexical_environment): + (JSC::JIT::emit_op_tear_off_arguments): + (JSC::JIT::emit_op_create_lexical_environment): + (JSC::JIT::emit_op_tear_off_activation): Deleted. + (JSC::JIT::emit_op_create_activation): Deleted. + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/Arguments.cpp: + (JSC::Arguments::visitChildren): + (JSC::Arguments::tearOff): + (JSC::Arguments::didTearOffActivation): + * runtime/Arguments.h: + (JSC::Arguments::offsetOfActivation): + (JSC::Arguments::argument): + (JSC::Arguments::finishCreation): + * runtime/CommonSlowPaths.cpp: + * runtime/JSFunction.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::activationStructure): + * runtime/JSLexicalEnvironment.cpp: Renamed from Source/JavaScriptCore/runtime/JSActivation.cpp. + (JSC::JSLexicalEnvironment::visitChildren): + (JSC::JSLexicalEnvironment::symbolTableGet): + (JSC::JSLexicalEnvironment::symbolTablePut): + (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames): + (JSC::JSLexicalEnvironment::symbolTablePutWithAttributes): + (JSC::JSLexicalEnvironment::getOwnPropertySlot): + (JSC::JSLexicalEnvironment::put): + (JSC::JSLexicalEnvironment::deleteProperty): + (JSC::JSLexicalEnvironment::toThis): + (JSC::JSLexicalEnvironment::argumentsGetter): + * runtime/JSLexicalEnvironment.h: Renamed from Source/JavaScriptCore/runtime/JSActivation.h. + (JSC::JSLexicalEnvironment::create): + (JSC::JSLexicalEnvironment::createStructure): + (JSC::JSLexicalEnvironment::JSLexicalEnvironment): + (JSC::asActivation): + (JSC::Register::lexicalEnvironment): + (JSC::JSLexicalEnvironment::registersOffset): + (JSC::JSLexicalEnvironment::tearOff): + (JSC::JSLexicalEnvironment::isTornOff): + (JSC::JSLexicalEnvironment::storageOffset): + (JSC::JSLexicalEnvironment::storage): + (JSC::JSLexicalEnvironment::allocationSize): + (JSC::JSLexicalEnvironment::isValidIndex): + (JSC::JSLexicalEnvironment::isValid): + (JSC::JSLexicalEnvironment::registerAt): + * runtime/JSObject.h: + * runtime/JSScope.cpp: + (JSC::abstractAccess): + * runtime/JSScope.h: + (JSC::ResolveOp::ResolveOp): + * runtime/JSSymbolTableObject.cpp: + * runtime/StrictEvalActivation.h: + (JSC::StrictEvalActivation::create): + * runtime/VM.cpp: + +2014-09-11 László Langó <llango.u-szeged@partner.samsung.com> + + [JavaScriptCore] Fix FTL on platform EFL. + https://bugs.webkit.org/show_bug.cgi?id=133571 + + Reviewed by Filip Pizlo. + + There are no compact_unwind sections on Linux systems so FTL crashes. + We have to parse eh_frame in FTLUnwindInfo instead of compact_unwind + and get the information for stack unwinding from there. + + * CMakeLists.txt: Revert r169181. + * ftl/FTLCompile.cpp: + Change section name literals to use SECTION_NAME macro, because of architecture differencies. + (JSC::FTL::mmAllocateCodeSection): + (JSC::FTL::mmAllocateDataSection): + (JSC::FTL::compile): + * ftl/FTLJITCode.h: + We need the SECTION_NAME macro in FTLCompile and FTLLink, so we define it here. + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLState.h: + * ftl/FTLState.cpp: + (JSC::FTL::State::State): + * ftl/FTLUnwindInfo.h: + * ftl/FTLUnwindInfo.cpp: + Lift the eh_frame parsing method from LLVM/libcxxabi project and modify it for our purposes. + Parse eh_frame on Linux instead of compact_unwind. + (JSC::FTL::UnwindInfo::parse): + +2014-09-10 Saam Barati <saambarati1@gmail.com> + + Web Inspector: Modify the type profiler runtime protocol to transfer some computation into the WebInspector + https://bugs.webkit.org/show_bug.cgi?id=136500 + + Reviewed by Joseph Pecoraro. + + This patch changes the type profiler protocol to the Web Inspector + by moving the work of calculating computed properties that effect the UI + into the Web Inspector. This makes the Web Inspector have control over the + strings it displays as UI elements representing type information to the user + instead of JavaScriptCore deciding on a convention for these strings. + JavaScriptCore now sends enough information to the Web Inspector so that + it can compute the properties JavaScriptCore used to compute. + + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/protocol/Runtime.json: + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::getTypesForVariableAtOffsetForInspector): Deleted. + * runtime/TypeProfiler.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::inspectorTypeSet): + (JSC::StructureShape::leastCommonAncestor): + (JSC::StructureShape::inspectorRepresentation): + * runtime/TypeSet.h: + +2014-09-10 Akos Kiss <akiss@inf.u-szeged.hu> + + Apply ARM64-specific lowering to load/store instructions in offlineasm + https://bugs.webkit.org/show_bug.cgi?id=136569 + + Reviewed by Michael Saboff. + + The standard risc lowering of load/store instructions with base + + immediate offset addresses is to move the offset to a temporary, add the + base to the temporary, and then change the load/store to use the + temporary + 0 immediate offset address. However, on ARM64, base + + register offset addressing mode is available, so it is unnecessary to + perform explicit register additions but it is enough to change load/store + to use base + temporary as the address. + + * offlineasm/arm64.rb: Added arm64LowerMalformedLoadStoreAddresses + +2014-09-10 Oliver Hunt <oliver@apple.com> + + Rename JSVariableObject to JSEnvironmentRecord to align naming with ES spec + https://bugs.webkit.org/show_bug.cgi?id=136710 + + Reviewed by Anders Carlsson. + + This is a trivial rename. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractHeap.h: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLAbstractHeapRepository.cpp: + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetClosureRegisters): + * jit/JITOpcodes32_64.cpp: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitGetClosureVar): + (JSC::JIT::emitPutClosureVar): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitGetClosureVar): + (JSC::JIT::emitPutClosureVar): + * llint/LLIntOffsetsExtractor.cpp: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSActivation.cpp: + (JSC::JSActivation::getOwnNonIndexPropertyNames): + * runtime/JSActivation.h: + * runtime/JSEnvironmentRecord.cpp: Renamed from Source/JavaScriptCore/runtime/JSVariableObject.cpp. + * runtime/JSEnvironmentRecord.h: Renamed from Source/JavaScriptCore/runtime/JSVariableObject.h. + (JSC::JSEnvironmentRecord::registers): + (JSC::JSEnvironmentRecord::registerAt): + (JSC::JSEnvironmentRecord::addressOfRegisters): + (JSC::JSEnvironmentRecord::offsetOfRegisters): + (JSC::JSEnvironmentRecord::JSEnvironmentRecord): + * runtime/JSNameScope.h: + * runtime/JSSegmentedVariableObject.h: + +2014-09-10 Julien Brianceau <jbriance@cisco.com> + + [mips] Add missing parts and fix LLINT mips backend + https://bugs.webkit.org/show_bug.cgi?id=136706 + + Reviewed by Michael Saboff. + + * llint/LowLevelInterpreter.asm: Fix invalid CalleeSave register number. + Implement initPCRelative and setEntryAddress macros. + * llint/LowLevelInterpreter32_64.asm: Fix register distribution in + doVMEntry macro. + +2014-09-10 Saam Barati <saambarati1@gmail.com> + + TypeSet needs a mode where it no longer profiles structure shapes + https://bugs.webkit.org/show_bug.cgi?id=136263 + + Reviewed by Filip Pizlo. + + The TypeSet data structure used to gather as many StructureShape + objects as it encountered during type profiling. But, this meant + that there was no upper limit on how many objects it could allocate. + This patch places a fixed upper bound on the number of StructureShapes + allocated per TypeSet to prevent using too much memory for little gain + in type profiling usefulness. + + StructureShape objects are now also aware of when they are created + from Structures which are dictionaries. + + In total, this patch lays the final groundwork needed in refactoring + the inspector protocol for the type profiler. + + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::typeInformationForExpressionAtOffset): + * runtime/TypeSet.cpp: + (JSC::TypeSet::TypeSet): + (JSC::TypeSet::addTypeInformation): + (JSC::StructureShape::StructureShape): + (JSC::StructureShape::toJSONString): + (JSC::StructureShape::enterDictionaryMode): + * runtime/TypeSet.h: + (JSC::TypeSet::isOverflown): + * tests/typeProfiler/dictionary-mode.js: Added. + (wrapper): + * tests/typeProfiler/driver/driver.js: + * tests/typeProfiler/overflow.js: Added. + (wrapper.Proto): + (wrapper): + +2014-09-10 Peter Gal <galpeter@inf.u-szeged.hu> + + [MIPS] branch32WithPatch missing + https://bugs.webkit.org/show_bug.cgi?id=136696 + + Reviewed by Michael Saboff. + + Added the missing branch32WithPatch. The implementation + is currently the same as the branchPtrithPatch because + the macro assembler supports only 32 bit MIPS. + + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::branch32WithPatch): + +2014-09-10 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Fix !ENABLE(DFG_JIT) build + https://bugs.webkit.org/show_bug.cgi?id=136702 + + Reviewed by Michael Saboff. + + * bytecode/CallEdgeProfile.h: + +2014-09-09 Benjamin Poulain <bpoulain@apple.com> + + Disable the "unreachable-code" warning + https://bugs.webkit.org/show_bug.cgi?id=136677 + + Reviewed by Darin Adler. + + * Configurations/Base.xcconfig: + +2014-09-08 Filip Pizlo <fpizlo@apple.com> + + DFG should have a reusable SSA builder + https://bugs.webkit.org/show_bug.cgi?id=136331 + + Reviewed by Oliver Hunt. + + We want to implement sophisticated SSA transformations like object allocation sinking + (https://bugs.webkit.org/show_bug.cgi?id=136330), but to do that, we need to be able to do + updates to SSA that require inserting new Phi's. This requires calculating where Phis go. + Previously, our Phi calculation was based on Aycock and Horspool's algorithm, and our + implementation of this algorithm only worked when doing CPS->SSA conversion. The code + could not be reused for cases where some phase happens to know that it introduced a few + defs in some blocks and it wants to figure out where the Phis should go. Moreover, even + the general algorithm of Aycock and Horspool is not well suited to such targetted SSA + updates, since it requires first inserting maximal Phis. That scales well when the Phis + were already there (like in our CPS form) but otherwise it's quite unnatural and may be + difficult to make efficient. + + The usual way of handling both SSA conversion and SSA update is to use Cytron et al's + algorithm based on dominance frontiers. For a while now, I've been working on creating a + Cytron-based SSA calculator that can be used both as a replacement for our current SSA + converter and as a reusable tool for any phase that needs to do SSA update. I previously + optimized our dominator calculation and representation to use dominator trees computed + using Lengauer and Tarjan's algorithm - mainly to make it more scalable to enumerate over + the set of blocks that dominate you or vice-versa, and then I implemented a dominance + frontier calculator. This patch implements the final step towards making SSA update + available to all SSA phases: it implements an SSACalculator that can tell you where Phis + go when given an arbitrary set of Defs. To keep things simple, and to ensure that we have + good test coverage for this SSACalculator, this patch replaces the old Aycock-Horspool + SSA converter with one based on the SSACalculator. + + This has no observable impact. It does reduce the amount of code in SSAConversionPhase. + But even better, it makes SSAConversionPhase have significantly less tricky logic. It + mostly just relies on SSACalculator to do the tricky stuff, and SSAConversionPhase mostly + just reasons about the weirdnesses unique to the ThreadedCPS form that it sees as input. + In fact, using the Cytron et al approach means that there isn't really any "smoke and + mirrors" trickyness related to SSA. SSACalculator's only "tricks" are using the pruned + iterated dominance frontier to place Phi's and using the dom tree to find reaching defs. + The complexity is mostly confined to Dominators, which computes various dominator-related + properties over the control flow graph. That class can be difficult to understand, but at + least it follows well-known graph theory wisdom. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAnalysis.h: + * dfg/DFGCSEPhase.cpp: + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + * dfg/DFGDominators.h: + (JSC::DFG::Dominators::immediateDominatorOf): + (JSC::DFG::Dominators::forAllBlocksInIteratedDominanceFrontierOf): + (JSC::DFG::Dominators::forAllBlocksInPrunedIteratedDominanceFrontierOf): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::blocksInPreOrder): + (JSC::DFG::Graph::blocksInPostOrder): + (JSC::DFG::Graph::getBlocksInPreOrder): Deleted. + (JSC::DFG::Graph::getBlocksInPostOrder): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::run): + * dfg/DFGNodeFlags.h: + * dfg/DFGPhase.cpp: + (JSC::DFG::Phase::beginPhase): + (JSC::DFG::Phase::endPhase): + * dfg/DFGPhase.h: + * dfg/DFGSSACalculator.cpp: Added. + (JSC::DFG::SSACalculator::Variable::dump): + (JSC::DFG::SSACalculator::Variable::dumpVerbose): + (JSC::DFG::SSACalculator::Def::dump): + (JSC::DFG::SSACalculator::SSACalculator): + (JSC::DFG::SSACalculator::~SSACalculator): + (JSC::DFG::SSACalculator::newVariable): + (JSC::DFG::SSACalculator::newDef): + (JSC::DFG::SSACalculator::nonLocalReachingDef): + (JSC::DFG::SSACalculator::reachingDefAtTail): + (JSC::DFG::SSACalculator::dump): + * dfg/DFGSSACalculator.h: Added. + (JSC::DFG::SSACalculator::Variable::index): + (JSC::DFG::SSACalculator::Variable::Variable): + (JSC::DFG::SSACalculator::Def::variable): + (JSC::DFG::SSACalculator::Def::block): + (JSC::DFG::SSACalculator::Def::value): + (JSC::DFG::SSACalculator::Def::Def): + (JSC::DFG::SSACalculator::variable): + (JSC::DFG::SSACalculator::computePhis): + (JSC::DFG::SSACalculator::phisForBlock): + (JSC::DFG::SSACalculator::reachingDefAtHead): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::SSAConversionPhase): + (JSC::DFG::SSAConversionPhase::run): + (JSC::DFG::SSAConversionPhase::forwardPhiChildren): Deleted. + (JSC::DFG::SSAConversionPhase::forwardPhi): Deleted. + (JSC::DFG::SSAConversionPhase::forwardPhiEdge): Deleted. + (JSC::DFG::SSAConversionPhase::deduplicateChildren): Deleted. + * dfg/DFGSSAConversionPhase.h: + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::Validate): + (JSC::DFG::Validate::dumpGraphIfAppropriate): + (JSC::DFG::validate): + * dfg/DFGValidate.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + * runtime/Options.h: + +2014-09-08 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r173402. + https://bugs.webkit.org/show_bug.cgi?id=136649 + + Breaking buildw with error "unable to restore file position to + 0x00000c60 for section __DWARF.__debug_info (errno = 9)" + (Requested by mlam_ on #webkit). + + Reverted changeset: + + "Move CallFrame and Register inlines functions out of + JSScope.h." + https://bugs.webkit.org/show_bug.cgi?id=136579 + http://trac.webkit.org/changeset/173402 + +2014-09-08 Mark Lam <mark.lam@apple.com> + + Move CallFrame and Register inlines functions out of JSScope.h. + <https://webkit.org/b/136579> + + Reviewed by Geoffrey Garen. + + This include fixing up some files to #include JSCInlines.h to pick up + these inline functions. I also added JSCellInlines.h to JSCInlines.h + since it is included from many of the affected .cpp files. + + * API/ObjCCallbackFunction.mm: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bindings/ScriptValue.cpp: + * inspector/InjectedScriptHost.cpp: + * inspector/InjectedScriptManager.cpp: + * inspector/JSGlobalObjectInspectorController.cpp: + * inspector/JSJavaScriptCallFrame.cpp: + * inspector/ScriptDebugServer.cpp: + * interpreter/CallFrameInlines.h: + (JSC::CallFrame::vm): + (JSC::CallFrame::lexicalGlobalObject): + (JSC::CallFrame::globalThisValue): + * interpreter/RegisterInlines.h: Added. + (JSC::Register::operator=): + (JSC::Register::scope): + * runtime/ArgumentsIteratorConstructor.cpp: + * runtime/JSArrayIterator.cpp: + * runtime/JSCInlines.h: + * runtime/JSCJSValue.cpp: + * runtime/JSMapIterator.cpp: + * runtime/JSPromiseConstructor.cpp: + * runtime/JSPromiseDeferred.cpp: + * runtime/JSPromiseFunctions.cpp: + * runtime/JSPromisePrototype.cpp: + * runtime/JSPromiseReaction.cpp: + * runtime/JSScope.h: + (JSC::Register::operator=): Deleted. + (JSC::Register::scope): Deleted. + (JSC::ExecState::vm): Deleted. + (JSC::ExecState::lexicalGlobalObject): Deleted. + (JSC::ExecState::globalThisValue): Deleted. + * runtime/JSSetIterator.cpp: + * runtime/MapConstructor.cpp: + * runtime/MapData.cpp: + * runtime/MapIteratorPrototype.cpp: + * runtime/MapPrototype.cpp: + * runtime/SetConstructor.cpp: + * runtime/SetIteratorPrototype.cpp: + * runtime/SetPrototype.cpp: + * runtime/WeakMapConstructor.cpp: + * runtime/WeakMapPrototype.cpp: + +2014-09-08 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + Remove FILTERS flag + https://bugs.webkit.org/show_bug.cgi?id=136571 + + Reviewed by Darin Adler. + + * Configurations/FeatureDefines.xcconfig: + +2014-09-08 Saam Barati <saambarati1@gmail.com> + + Merge StructureShapes that share the same prototype chain + https://bugs.webkit.org/show_bug.cgi?id=136549 + + Reviewed by Filip Pizlo. + + Instead of keeping track of many discrete StructureShapes that share + the same prototype chain, TypeSet should merge StructureShapes that + have the same prototype chain and provide a new member variable for + optional structure fields. This provides a cleaner and more concise + interface for dealing with StructureShapes within TypeSet. Instead + of having many discrete shapes that are almost identical, almost + identical shapes will be merged together with an interface for + understanding what fields the shapes being merged together differ in. + + * runtime/TypeSet.cpp: + (JSC::TypeSet::addTypeInformation): + (JSC::StructureShape::addProperty): + (JSC::StructureShape::toJSONString): + (JSC::StructureShape::inspectorRepresentation): + (JSC::StructureShape::hasSamePrototypeChain): + (JSC::StructureShape::merge): + * runtime/TypeSet.h: + * tests/typeProfiler/optional-fields.js: Added. + (wrapper.func): + (wrapper): + +2014-09-08 Jessie Berlin <jberlin@apple.com> + + More 32-bit Release build fixes after r173364. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-09-07 Maciej Stachowiak <mjs@apple.com> + + Fix typos in last patch to fix build. + + Unreviewed build fix. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode): + +2014-09-07 Maciej Stachowiak <mjs@apple.com> + + Introduce COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) and use it + https://bugs.webkit.org/show_bug.cgi?id=136616 + + Reviewed by Darin Adler. + + Many compilers will analyze unrechable code paths (e.g. after an + unreachable code path), so sometimes they need dead code initializations. + But clang with suitable warnings will complain about unreachable code. So + use the quirk to include it conditionally. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printGetByIdOp): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::handleExitCounts): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThread): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + * jsc.cpp: + * runtime/JSArray.cpp: + (JSC::JSArray::fillArgList): + (JSC::JSArray::copyToArguments): + * runtime/RegExp.cpp: + (JSC::RegExp::compile): + (JSC::RegExp::compileMatchOnly): + +2014-09-06 Darin Adler <darin@apple.com> + + Make updates suggested by new version of Xcode + https://bugs.webkit.org/show_bug.cgi?id=136603 + + Reviewed by Mark Rowe. + + * Configurations/Base.xcconfig: Added CLANG_WARN_UNREACHABLE_CODE, COMBINE_HIDPI_IMAGES, + and ENABLE_STRICT_OBJC_MSGSEND as suggested by Xcode upgrade check. + + * JavaScriptCore.xcodeproj/project.pbxproj: Update LastUpgradeCheck. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode): Compile out unreachable code + for clang, since it understands the code is unreachable. + * runtime/JSArray.cpp: + (JSC::JSArray::fillArgList): Ditto. + (JSC::JSArray::copyToArguments): Ditto. + +2014-09-05 Matt Baker <mattbaker@apple.com> + + Web Inspector: breakpoint actions should work regardless of Content Security Policy + https://bugs.webkit.org/show_bug.cgi?id=136542 + + Reviewed by Mark Lam. + + Added JSC::DebuggerEvalEnabler, an RAII object which enables eval on a + JSGlobalObject for the duration of a scope, returning the eval enabled state to its + original value when the scope exits. Used by JSC::DebuggerCallFrame::evaluate + to allow breakpoint actions to execute JS in pages with a Content Security Policy + that would normally prohibit this (such as Inspector's Main.html). + + Refactored Inspector::InjectedScriptBase to use the RAII object instead of manually + setting eval enabled and then resetting the original eval enabled state. + + NOTE: The JS::DebuggerEvalEnabler constructor checks the passed in ExecState pointer + for null to be equivalent with the original code in Inspector::InjectedScriptBase. + InjectedScriptBase is getting the ExecState from ScriptObject::scriptState(), which + can currently be null. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + * debugger/DebuggerEvalEnabler.h: Added. + (JSC::DebuggerEvalEnabler::DebuggerEvalEnabler): + (JSC::DebuggerEvalEnabler::~DebuggerEvalEnabler): + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::callFunctionWithEvalEnabled): + +2014-09-05 peavo@outlook.com <peavo@outlook.com> + + [WinCairo] jsc.exe won't run. + https://bugs.webkit.org/show_bug.cgi?id=136481 + + Reviewed by Alex Christensen. + + We need to define WIN_CAIRO to avoid looking for the AAS folder. + + * JavaScriptCore.vcxproj/jsc/DLLLauncherWinCairo.props: Added. + * JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj: + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props: + * JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj: + +2014-09-05 David Kilzer <ddkilzer@apple.com> + + JavaScriptCore should build with newer clang + <http://webkit.org/b/136002> + <rdar://problem/18020616> + + Reviewed by Geoffrey Garen. + + Other than the JSC::SourceProvider::asID() change (which simply + removes code that the optimizing compiler would have discarded + in Release builds), we move the |this| checks in OpaqueJSString + to NULL checks in to JSBase, JSObjectRef, JSScriptRef, + JSStringRef{CF} and JSValueRef. + + Note that the following function arguments are _not_ NULL-checked + since doing so would just cover up bugs (and were not needed to + prevent any tests from failing): + - |script| in JSEvaluateScript(), JSCheckScriptSyntax(); + - |body| in JSObjectMakeFunction(); + - |source| in JSScriptCreateReferencingImmortalASCIIText() + (which is a const char* anyway); + - |source| in JSScriptCreateFromString(). + + * API/JSBase.cpp: + (JSEvaluateScript): Add NULL check for |sourceURL|. + (JSCheckScriptSyntax): Ditto. + * API/JSObjectRef.cpp: + (JSObjectMakeFunction): Ditto. + * API/JSScriptRef.cpp: + (JSScriptCreateReferencingImmortalASCIIText): Ditto. + (JSScriptCreateFromString): Add NULL check for |url|. + * API/JSStringRef.cpp: + (JSStringGetLength): Return early if NULL pointer is passed in. + (JSStringGetCharactersPtr): Ditto. + (JSStringGetUTF8CString): Ditto. Also check |buffer| parameter. + * API/JSStringRefCF.cpp: + (JSStringCopyCFString): Ditto. + * API/JSValueRef.cpp: + (JSValueMakeString): Add NULL check for |string|. + + * API/OpaqueJSString.cpp: + (OpaqueJSString::string): Remove code that checks |this|. + (OpaqueJSString::identifier): Ditto. + (OpaqueJSString::characters): Ditto. + * API/OpaqueJSString.h: + (OpaqueJSString::is8Bit): Remove code that checks |this|. + (OpaqueJSString::characters8): Ditto. + (OpaqueJSString::characters16): Ditto. + (OpaqueJSString::length): Ditto. + + * parser/SourceProvider.h: + (JSC::SourceProvider::asID): Remove code that checks |this|. + +2014-06-06 Jer Noble <jer.noble@apple.com> + + Refactoring: make MediaTime the primary time type for audiovisual times. + https://bugs.webkit.org/show_bug.cgi?id=133579 + + Reviewed by Eric Carlson. + + Add a utility function which converts a MediaTime to a JSNumber. + + * runtime/JSCJSValue.h: + (JSC::jsNumber): + +2014-09-04 Michael Saboff <msaboff@apple.com> + + ARM: Add more coverage to ARMv7 disassembler + https://bugs.webkit.org/show_bug.cgi?id=136565 + + Reviewed by Mark Lam. + + Added ARMV7 disassembler support for Push/Pop multiple and floating point instructions + VCMP, VCVT[R] between floating point and integer, and VLDR. + + * disassembler/ARMv7/ARMv7DOpcode.cpp: + (JSC::ARMv7Disassembler::ARMv7DOpcodeDataPushPopMultiple::appendRegisterList): + (JSC::ARMv7Disassembler::ARMv7DOpcodeDataPopMultiple::format): + (JSC::ARMv7Disassembler::ARMv7DOpcodeDataPushMultiple::format): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::format): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::format): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::format): + * disassembler/ARMv7/ARMv7DOpcode.h: + (JSC::ARMv7Disassembler::ARMv7DOpcodeDataPushPopMultiple::registerList): + (JSC::ARMv7Disassembler::ARMv7DOpcodeDataPushPopMultiple::condition): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::condition): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::dBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::vd): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::szBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::eBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::mBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCMP::vm): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::condition): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::dBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::op2): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::vd): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::szBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::op): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::mBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVCVTBetweenFPAndInt::vm): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::condition): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::uBit): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::rn): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::vd): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::doubleReg): + (JSC::ARMv7Disassembler::ARMv7DOpcodeVLDR::immediate8): + +2014-09-04 Mark Lam <mark.lam@apple.com> + + Move PropertySlot's inline functions back to PropertySlot.h. + <https://webkit.org/b/136547> + + Reviewed by Filip Pizlo. + + * runtime/JSObject.h: + (JSC::PropertySlot::getValue): Deleted. + * runtime/PropertySlot.h: + (JSC::PropertySlot::getValue): + +2014-09-04 Filip Pizlo <fpizlo@apple.com> + + Make sure that deleting all code first processes the call edge log, and reenable call edge profiling. + + Rubber stamped by Sam Weinig. + + * debugger/Debugger.cpp: + (JSC::Debugger::forEachCodeBlock): + (JSC::Debugger::setSteppingMode): + (JSC::Debugger::recompileAllJSFunctions): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::recompileAllJSFunctionsForTypeProfiling): + * runtime/Options.h: Reenable call edge profiling. + * runtime/VM.cpp: + (JSC::VM::prepareToDiscardCode): Make sure this also processes the call edge log, in case any call edge profiles are about to be destroyed. + (JSC::VM::discardAllCode): + (JSC::VM::releaseExecutableMemory): + (JSC::VM::setEnabledProfiler): + (JSC::VM::waitForCompilationsToComplete): Deleted. + * runtime/VM.h: Rename waitForCompilationsToComplete() back to prepareToDiscardCode() because the purpose of the method - now as ever - is to do all of the things that need to be done to ensure that code may be safely deleted. + +2014-09-04 Akos Kiss <akiss@inf.u-szeged.hu> + + Ensure that the call frame set up by vmEntryToNative does not overlap with the stack of the callee + https://bugs.webkit.org/show_bug.cgi?id=136485 + + Reviewed by Michael Saboff. + + Changed makeHostFunctionCall to keep the stack pointer above the call + frame set up by doVMEntry. Thus the callee will/can not override the top + of the call frame. + + Refactored the two (32_64 and 64) versions of makeHostFunctionCall to be + more alike to help future maintenance. + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-09-04 Michael Saboff <msaboff@apple.com> + + REGRESSION(r173031): crashes during run-layout-jsc on x86/Linux + https://bugs.webkit.org/show_bug.cgi?id=136436 + + Reviewed by Geoffrey Garen. + + Instead of trying to calculate a stack pointer that allows for possible + stacked argument space, just use the "home" stack pointer location. + That stack pointer provides space for the worst case number of stacked + arguments on architectures that use stacked arguments. It also provides + stack space so that the return PC and caller frame pointer that are stored + as part of making the call to operationCallEval will not override any part + of the callee frame created on the stack. + + Changed compileCallEval() to use the stackPointer value of the calling + function. That stack pointer is calculated to have enough space for + outgoing stacked arguments. By moving the stack pointer to its "home" + position, the caller frame and return PC are not set as part of making + the call to operationCallEval(). Moved the explicit setting of the + callerFrame field of the callee CallFrame from operationCallEval() to + compileCallEval() since it has been the artifact of making a call for + most architectures. Simplified the exception logic in compileCallEval() + as a result of the change. To be compliant with the stack state + expected by virtualCallThunkGenerator(), moved the stack pointer to + point above the CallerFrameAndPC of the callee CallFrame. + + * jit/JIT.h: Changed callOperationNoExceptionCheck(J_JITOperation_EE, ...) + to callOperation(J_JITOperation_EE, ...) as it now can do a typical exception + check. + * jit/JITCall.cpp & jit/JITCall32_64.cpp: + (JSC::JIT::compileCallEval): Use the home stack pointer when making the call + to operationCallEval. Since the stack pointer adjustment no longer needs + to be done after making the call to operationCallEval(), the exception check + logic can be simplified. + (JSC::JIT::compileCallEvalSlowCase): Restored the stack pointer to point + to above the calleeFrame as this is what the generated thunk expects. + * jit/JITInlines.h: + (JSC::JIT::callOperation): Refactor of callOperationNoExceptionCheck + with the addition of a standard exception check. + (JSC::JIT::callOperationNoExceptionCheck): Deleted. + * jit/JITOperations.cpp: + (JSC::operationCallEval): Eliminated the explicit setting of caller frame + as that is now done in the code generated by compileCallEval(). + +2014-09-03 Filip Pizlo <fpizlo@apple.com> + + Beef up the DFG's CFG analyses to include iterated dominance frontiers and more user-friendly BlockSets + https://bugs.webkit.org/show_bug.cgi?id=136520 + + Reviewed by Geoffrey Garen. + + Add code to compute iterated dominance frontiers. This involves using BlockSet a lot, so + this patch also makes BlockSet a lot more user-friendly. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBasicBlock.h: + * dfg/DFGBlockSet.cpp: Added. + (JSC::DFG::BlockSet::dump): + * dfg/DFGBlockSet.h: + (JSC::DFG::BlockSet::iterator::iterator): + (JSC::DFG::BlockSet::iterator::operator++): + (JSC::DFG::BlockSet::iterator::operator==): + (JSC::DFG::BlockSet::iterator::operator!=): + (JSC::DFG::BlockSet::Iterable::Iterable): + (JSC::DFG::BlockSet::Iterable::begin): + (JSC::DFG::BlockSet::Iterable::end): + (JSC::DFG::BlockSet::iterable): + (JSC::DFG::BlockAdder::BlockAdder): + (JSC::DFG::BlockAdder::operator()): + * dfg/DFGBlockSetInlines.h: Added. + (JSC::DFG::BlockSet::iterator::operator*): + * dfg/DFGDominators.cpp: + (JSC::DFG::Dominators::strictDominatorsOf): + (JSC::DFG::Dominators::dominatorsOf): + (JSC::DFG::Dominators::blocksStrictlyDominatedBy): + (JSC::DFG::Dominators::blocksDominatedBy): + (JSC::DFG::Dominators::dominanceFrontierOf): + (JSC::DFG::Dominators::iteratedDominanceFrontierOf): + * dfg/DFGDominators.h: + (JSC::DFG::Dominators::forAllStrictDominatorsOf): + (JSC::DFG::Dominators::forAllDominatorsOf): + (JSC::DFG::Dominators::forAllBlocksStrictlyDominatedBy): + (JSC::DFG::Dominators::forAllBlocksDominatedBy): + (JSC::DFG::Dominators::forAllBlocksInDominanceFrontierOf): + (JSC::DFG::Dominators::forAllBlocksInIteratedDominanceFrontierOf): + (JSC::DFG::Dominators::forAllBlocksInDominanceFrontierOfImpl): + (JSC::DFG::Dominators::forAllBlocksInIteratedDominanceFrontierOfImpl): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dumpBlockHeader): + * dfg/DFGInvalidationPointInjectionPhase.cpp: + (JSC::DFG::InvalidationPointInjectionPhase::run): + +2014-09-04 Mark Lam <mark.lam@apple.com> + + Fixed indentations and some style warnings in JavaScriptCore/runtime. + <https://webkit.org/b/136518> + + Reviewed by Michael Saboff. + + Also removed some superflous spaces. There are no semantic changes. + + * runtime/Completion.h: + * runtime/ConstructData.h: + * runtime/DateConstructor.h: + * runtime/DateInstance.h: + * runtime/DateInstanceCache.h: + * runtime/DatePrototype.h: + * runtime/Error.h: + * runtime/ErrorConstructor.h: + * runtime/ErrorInstance.h: + * runtime/ErrorPrototype.h: + * runtime/FunctionConstructor.h: + * runtime/FunctionPrototype.h: + * runtime/GetterSetter.h: + * runtime/Identifier.h: + * runtime/InitializeThreading.h: + * runtime/InternalFunction.h: + * runtime/JSAPIValueWrapper.h: + * runtime/JSFunction.h: + * runtime/JSLock.h: + * runtime/JSNotAnObject.h: + * runtime/JSONObject.h: + * runtime/JSString.h: + * runtime/JSTypeInfo.h: + * runtime/JSWrapperObject.h: + * runtime/Lookup.h: + * runtime/MathObject.h: + * runtime/NativeErrorConstructor.h: + * runtime/NativeErrorPrototype.h: + * runtime/NumberConstructor.h: + * runtime/NumberObject.h: + * runtime/NumberPrototype.h: + * runtime/NumericStrings.h: + * runtime/ObjectConstructor.h: + * runtime/ObjectPrototype.h: + * runtime/PropertyDescriptor.h: + * runtime/Protect.h: + * runtime/PutPropertySlot.h: + * runtime/RegExp.h: + * runtime/RegExpCachedResult.h: + * runtime/RegExpConstructor.h: + * runtime/RegExpMatchesArray.h: + * runtime/RegExpObject.h: + * runtime/RegExpPrototype.h: + * runtime/SmallStrings.h: + * runtime/StringConstructor.h: + * runtime/StringObject.h: + * runtime/StringPrototype.h: + * runtime/StructureChain.h: + * runtime/VM.h: + +2014-09-04 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + Remove CSS_FILTERS flag + https://bugs.webkit.org/show_bug.cgi?id=136529 + + Reviewed by Dirk Schulze. + + * Configurations/FeatureDefines.xcconfig: + +2014-09-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r173248. + https://bugs.webkit.org/show_bug.cgi?id=136536 + + call edge profiling and polymorphic call inlining are still + causing crashes (Requested by eric_carlson on #webkit). + + Reverted changeset: + + "Reenable call edge profiling and polymorphic call inlining, + now that a bunch of the bugs" + http://trac.webkit.org/changeset/173248 + +2014-09-04 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: the profiler should not accrue time to nodes while the debugger is paused + https://bugs.webkit.org/show_bug.cgi?id=136352 + + Reviewed by Timothy Hatcher. + + Hook up pause/continue events to the LegacyProfiler and any active + ProfilerGenerators. If the debugger is paused, all intervening call + entries will be created with totalTime as 0.0. + + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::handlePause): + * profiler/LegacyProfiler.cpp: Move from typedef'd callbacks to using + std::function. This allows callbacks to take different argument types. + + (JSC::callFunctionForProfilesWithGroup): + (JSC::LegacyProfiler::willExecute): + (JSC::LegacyProfiler::didExecute): + (JSC::LegacyProfiler::exceptionUnwind): + (JSC::LegacyProfiler::didPause): + (JSC::LegacyProfiler::didContinue): + (JSC::dispatchFunctionToProfiles): Deleted. + * profiler/LegacyProfiler.h: + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::ProfileGenerator::endCallEntry): + (JSC::ProfileGenerator::didExecute): Deleted. + * profiler/ProfileGenerator.h: + (JSC::ProfileGenerator::didPause): + (JSC::ProfileGenerator::didContinue): + +2014-09-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r173245. + https://bugs.webkit.org/show_bug.cgi?id=136533 + + Broke JSC tests. (Requested by ddkilzer on #webkit). + + Reverted changeset: + + "JavaScriptCore should build with newer clang" + https://bugs.webkit.org/show_bug.cgi?id=136002 + http://trac.webkit.org/changeset/173245 + +2014-09-04 Brian J. Burg <burg@cs.washington.edu> + + LegacyProfiler: ProfileNodes should be used more like structs + https://bugs.webkit.org/show_bug.cgi?id=136381 + + Reviewed by Timothy Hatcher. + + Previously, both the profile generator and individual profile nodes + were collectively responsible for creating new Call entries and + maintaining data structure invariants. This complexity is unnecessary. + + This patch centralizes profile data creation inside the profile generator. + The profile nodes manage nextSibling and parent pointers, but do not + collect the current time or create new Call entries themselves. + + Since ProfileNode::nextSibling and its callers are only used within + debug printing code, it should be compiled out for release builds. + + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::AddParentForConsoleStartFunctor::operator()): + (JSC::ProfileGenerator::beginCallEntry): create a new Call entry. + (JSC::ProfileGenerator::endCallEntry): finish the last Call entry. + (JSC::ProfileGenerator::willExecute): inline ProfileNode::willExecute() + (JSC::ProfileGenerator::didExecute): inline ProfileNode::didExecute() + (JSC::ProfileGenerator::stopProfiling): Only walk up the spine. + (JSC::ProfileGenerator::removeProfileStart): + (JSC::ProfileGenerator::removeProfileEnd): + * profiler/ProfileGenerator.h: + * profiler/ProfileNode.cpp: + (JSC::ProfileNode::ProfileNode): + (JSC::ProfileNode::addChild): + (JSC::ProfileNode::removeChild): + (JSC::ProfileNode::spliceNode): Renamed from insertNode. + (JSC::ProfileNode::debugPrintRecursively): + (JSC::ProfileNode::willExecute): Deleted. + (JSC::ProfileNode::insertNode): Deleted. + (JSC::ProfileNode::stopProfiling): Deleted. + (JSC::ProfileNode::traverseNextNodePostOrder): + (JSC::ProfileNode::endAndRecordCall): Deleted. + (JSC::ProfileNode::debugPrintDataSampleStyle): + * profiler/ProfileNode.h: + (JSC::ProfileNode::Call::setStartTime): + (JSC::ProfileNode::Call::setTotalTime): + (JSC::ProfileNode::appendCall): + (JSC::ProfileNode::firstChild): + (JSC::ProfileNode::lastChild): + (JSC::ProfileNode::nextSibling): + (JSC::ProfileNode::setNextSibling): + +2014-09-02 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: fix prefixes for subclasses of JSC::ConsoleClient + https://bugs.webkit.org/show_bug.cgi?id=136476 + + Reviewed by Timothy Hatcher. + + * CMakeLists.txt: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/JSGlobalObjectConsoleClient.cpp: Renamed from Source/JavaScriptCore/inspector/JSConsoleClient.cpp. + * inspector/JSGlobalObjectConsoleClient.h: Renamed from Source/JavaScriptCore/inspector/JSConsoleClient.h. + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + * inspector/JSGlobalObjectInspectorController.h: + +2014-09-03 Filip Pizlo <fpizlo@apple.com> + + Reenable call edge profiling and polymorphic call inlining, now that a bunch of the bugs + are fixed. + + * runtime/Options.h: + +2014-09-03 David Kilzer <ddkilzer@apple.com> + + JavaScriptCore should build with newer clang + <http://webkit.org/b/136002> + <rdar://problem/18020616> + + Reviewed by Geoffrey Garen. + + Other than the JSC::SourceProvider::asID() change (which simply + removes code that the optimizing compiler would have discarded + in Release builds), we move the |this| checks in OpaqueJSString + to NULL checks in to JSBase, JSScriptRef, JSStringRef{CF} and + JSValueRef. + + * API/JSBase.cpp: + (JSEvaluateScript): Use String() in case |script| or |sourceURL| + are NULL. + * API/JSScriptRef.cpp: + (JSScriptCreateReferencingImmortalASCIIText): Use String() in + case |url| is NULL. + * API/JSStringRef.cpp: + (JSStringGetLength): Return early if NULL pointer is passed in. + (JSStringGetCharactersPtr): Ditto. + (JSStringGetUTF8CString): Ditto. Also check |buffer| parameter. + * API/JSStringRefCF.cpp: + (JSStringCopyCFString): Ditto. + * API/JSValueRef.cpp: + (JSValueMakeString): Use String() in case |string| is NULL. + + * API/OpaqueJSString.cpp: + (OpaqueJSString::string): Remove code that checks |this|. + (OpaqueJSString::identifier): Ditto. + (OpaqueJSString::characters): Ditto. + * API/OpaqueJSString.h: + (OpaqueJSString::is8Bit): Remove code that checks |this|. + (OpaqueJSString::characters8): Ditto. + (OpaqueJSString::characters16): Ditto. + (OpaqueJSString::length): Ditto. + + * parser/SourceProvider.h: + (JSC::SourceProvider::asID): Remove code that checks |this|. + +2014-09-03 Filip Pizlo <fpizlo@apple.com> + + CallEdgeProfile::visitWeak() shouldn't attempt to despecify empty profiles + https://bugs.webkit.org/show_bug.cgi?id=136511 + + Reviewed by Geoffrey Garen. + + * bytecode/CallEdgeProfile.cpp: + (JSC::CallEdgeProfile::worthDespecifying): + (JSC::CallEdgeProfile::visitWeak): + (JSC::CallEdgeProfile::mergeBack): + +2014-09-03 David Kilzer <ddkilzer@apple.com> + + REGRESSION (r167325): (null) entry added to Xcode project file when JSBoundFunction.h was removed + <http://webkit.org/b/136509> + + Reviewed by Daniel Bates. + + * JavaScriptCore.xcodeproj/project.pbxproj: Remove the (null) + entry left behind when JSBoundFunction.h was removed. + +2014-09-03 Joseph Pecoraro <pecoraro@apple.com> + + Avoid warning if a process does not have access to com.apple.webinspector + https://bugs.webkit.org/show_bug.cgi?id=136473 + + Reviewed by Alexey Proskuryakov. + + Pre-check for access to the mach port to avoid emitting warnings + in syslog for processes that do not have access. + + * inspector/remote/RemoteInspector.mm: + (Inspector::canAccessWebInspectorMachPort): + (Inspector::RemoteInspector::shared): + +2014-09-03 Filip Pizlo <fpizlo@apple.com> + + Temporarily disable call edge profiling. It is causing crashes and I'm still investigating + them. + + * runtime/Options.h: + +2014-09-03 Balazs Kilvady <kilvadyb@homejinni.com> + + [MIPS] Wrong register usage in LLInt op_catch. + https://bugs.webkit.org/show_bug.cgi?id=125168 + + Reviewed by Geoffrey Garen. + + Fix register usage and add PIC header to all the ops in LLInt. + + * offlineasm/instructions.rb: + * offlineasm/mips.rb: + +2014-09-03 Saam Barati <saambarati1@gmail.com> + + Create tests for type profiling + https://bugs.webkit.org/show_bug.cgi?id=136161 + + Reviewed by Geoffrey Garen. + + The type profiler is now being tested. These are basic tests that don't + check every edge case, but will catch any major failures in the type profiler. + These tests cover: + - The basic, inheritance-based type system in TypeSet. + - Function return types. + - Correct merging of types for multiple assignments to one variable. + + This patch also provides an API for writing new tests for + the type profiler. The API works by passing in a function and a + unique substring of an expression contained in that function, and + returns an object representing type information for that expression. + + * jsc.cpp: + (GlobalObject::finishCreation): + (functionFindTypeForExpression): + (functionReturnTypeFor): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::typeInformationForExpressionAtOffset): + * runtime/TypeProfiler.h: + * runtime/TypeProfilerLog.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::toJSONString): + (JSC::StructureShape::toJSONString): + * runtime/TypeSet.h: + * tests/typeProfiler: Added. + * tests/typeProfiler.yaml: Added. + * tests/typeProfiler/basic.js: Added. + (wrapper.foo): + (wrapper): + * tests/typeProfiler/captured.js: Added. + (wrapper.changeFoo): + (wrapper): + * tests/typeProfiler/driver: Added. + * tests/typeProfiler/driver/driver.js: Added. + (assert): + * tests/typeProfiler/inheritance.js: Added. + (wrapper.A): + (wrapper.B): + (wrapper.C): + (wrapper): + * tests/typeProfiler/return.js: Added. + (foo): + (Ctor): + +2014-09-03 Julien Brianceau <jbriance@cisco.com> + + Add missing implementations to fix build for sh4 architecture + https://bugs.webkit.org/show_bug.cgi?id=136455 + + Reviewed by Geoffrey Garen. + + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::store8): + (JSC::MacroAssemblerSH4::moveWithPatch): + (JSC::MacroAssemblerSH4::branchAdd32): + (JSC::MacroAssemblerSH4::branch32WithPatch): + (JSC::MacroAssemblerSH4::abortWithReason): + (JSC::MacroAssemblerSH4::canJumpReplacePatchableBranch32WithPatch): + (JSC::MacroAssemblerSH4::startOfPatchableBranch32WithPatchOnAddress): + (JSC::MacroAssemblerSH4::revertJumpReplacementToPatchableBranch32WithPatch): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::emitFunctionPrologue): + (JSC::AssemblyHelpers::emitFunctionEpilogue): + +2014-09-03 Dan Bernstein <mitz@apple.com> + + Get rid of HIGH_DPI_CANVAS leftovers + https://bugs.webkit.org/show_bug.cgi?id=136491 + + Reviewed by Benjamin Poulain. + + * Configurations/FeatureDefines.xcconfig: Removed definition of ENABLE_HIGH_DPI_CANVAS + and removed it from FEATURE_DEFINES. + +2014-09-03 Filip Pizlo <fpizlo@apple.com> + + CallEdgeProfile::visitWeak() should gracefully handle the case where primaryCallee duplicates an entry in otherCallees + https://bugs.webkit.org/show_bug.cgi?id=136490 + + Reviewed by Geoffrey Garen. + + * bytecode/CallEdgeProfile.cpp: + (JSC::CallEdgeProfile::visitWeak): + +2014-09-03 Filip Pizlo <fpizlo@apple.com> + + FTL In implementation sets callReturnLocation incorrectly leading to crashes beneath repatchCall() + https://bugs.webkit.org/show_bug.cgi?id=136488 + + Reviewed by Mark Hahnenberg. + + * ftl/FTLCompile.cpp: + (JSC::FTL::generateCheckInICFastPath): The call is in the slow path. + * tests/stress/ftl-in-overflow.js: Added. This used to crash with 100% with FTL enabled. + (foo): + +2014-09-03 Akos Kiss <akiss@inf.u-szeged.hu> + + Don't generate superfluous mov instructions for move immediate on ARM64. + https://bugs.webkit.org/show_bug.cgi?id=136435 + + Reviewed by Michael Saboff. + + On ARM64, the size of an immediate operand for a mov instruction is 16 + bits. Thus, a move immediate offlineasm instruction may potentially be + split up to several machine level instructions. The current + implementation always emits a mov for the least significant 16 bits of + the value. However, if any of the bits 63:16 are significant then the + first emitted mov already filled bits 15:0 with zeroes (or ones, for + negative values). So, if bits 15:0 of the value are all zeroes (or ones) + then the last mov does not need to be emitted. + + * offlineasm/arm64.rb: + +2014-09-02 Brian J. Burg <burg@cs.washington.edu> + + LegacyProfiler: remove redundant ProfileNode members and other cleanup + https://bugs.webkit.org/show_bug.cgi?id=136380 + + Reviewed by Timothy Hatcher. + + ProfileNode's selfTime and totalTime members are redundant and only used + for dumping profile data from debug-only code. Remove the members and compute + the same data on-demand when necessary using a postorder traversal functor. + + Remove ProfileNode.head since it is only used to calculate percentages for + dumped profile data. This can be explicitly passed around when needed. + + Rename Profile.head to Profile.rootNode, and other various renamings. + + Rearrange some header includes so that touching LegacyProfiler-related headers + will no longer cause a full rebuild. + + * inspector/JSConsoleClient.cpp: Add header include. + * inspector/agents/InspectorProfilerAgent.cpp: + (Inspector::InspectorProfilerAgent::buildProfileInspectorObject): + * inspector/protocol/Profiler.json: Remove unused Profile.idleTime member. + * jit/JIT.h: Remove header include. + * jit/JITCode.h: Remove header include. + * jit/JITOperations.cpp: Sort and add header include. + * llint/LLIntSlowPaths.cpp: Sort and add header include. + * profiler/Profile.cpp: Rename the debug dumping functions. Move the node + postorder traversal code to ProfileNode so we can traverse any subtree. + (JSC::Profile::Profile): + (JSC::Profile::debugPrint): + (JSC::Profile::debugPrintSampleStyle): + (JSC::Profile::forEach): Deleted. + (JSC::Profile::debugPrintData): Deleted. + (JSC::Profile::debugPrintDataSampleStyle): Deleted. + * profiler/Profile.h: + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::AddParentForConsoleStartFunctor::AddParentForConsoleStartFunctor): + (JSC::AddParentForConsoleStartFunctor::operator()): + (JSC::ProfileGenerator::addParentForConsoleStart): + (JSC::ProfileGenerator::didExecute): + (JSC::StopProfilingFunctor::operator()): + (JSC::ProfileGenerator::stopProfiling): + (JSC::ProfileGenerator::removeProfileStart): + (JSC::ProfileGenerator::removeProfileEnd): + * profiler/ProfileGenerator.h: + * profiler/ProfileNode.cpp: + (JSC::ProfileNode::ProfileNode): + (JSC::ProfileNode::willExecute): + (JSC::ProfileNode::removeChild): + (JSC::ProfileNode::stopProfiling): + (JSC::ProfileNode::endAndRecordCall): + (JSC::ProfileNode::debugPrint): + (JSC::ProfileNode::debugPrintSampleStyle): + (JSC::ProfileNode::debugPrintRecursively): + (JSC::ProfileNode::debugPrintSampleStyleRecursively): + (JSC::ProfileNode::debugPrintData): Deleted. + (JSC::ProfileNode::debugPrintDataSampleStyle): Deleted. + * profiler/ProfileNode.h: Calculate per-node self and total times using a postorder traversal. + The forEachNodePostorder functor traverses the subtree rooted at |this|. + (JSC::ProfileNode::create): + (JSC::ProfileNode::calls): + (JSC::ProfileNode::forEachNodePostorder): + (JSC::CalculateProfileSubtreeDataFunctor::returnValue): + (JSC::CalculateProfileSubtreeDataFunctor::operator()): + (JSC::ProfileNode::head): Deleted. + (JSC::ProfileNode::setHead): Deleted. + (JSC::ProfileNode::totalTime): Deleted. + (JSC::ProfileNode::setTotalTime): Deleted. + (JSC::ProfileNode::selfTime): Deleted. + (JSC::ProfileNode::setSelfTime): Deleted. + (JSC::ProfileNode::totalPercent): Deleted. + (JSC::ProfileNode::selfPercent): Deleted. + * runtime/ConsoleClient.h: Remove header include. + +2014-09-02 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: remove ProfilerAgent and legacy profiler files in the frontend + https://bugs.webkit.org/show_bug.cgi?id=136462 + + Reviewed by Timothy Hatcher. + + It's not used by the frontend anymore. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + + * inspector/JSConsoleClient.cpp: + (Inspector::JSConsoleClient::JSConsoleClient): Stub out console.profile/profileEnd + methods since they didn't work for JSContexts anyway. + (Inspector::JSConsoleClient::profile): + (Inspector::JSConsoleClient::profileEnd): + * inspector/JSConsoleClient.h: + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + * inspector/agents/InspectorProfilerAgent.cpp: Removed. + * inspector/agents/InspectorProfilerAgent.h: Removed. + * inspector/agents/JSGlobalObjectProfilerAgent.cpp: Removed. + * inspector/agents/JSGlobalObjectProfilerAgent.h: Removed. + * inspector/protocol/Profiler.json: Removed. + +2014-09-02 Andreas Kling <akling@apple.com> + + Optimize own property GetByVals with rope string subscripts. + <https://webkit.org/b/136458> + + For simple JSObjects that don't override getOwnPropertySlot to implement + custom properties, we have a fast path that grabs directly at the object + property storage. + + Make this fast path even faster when the property name is an unresolved + rope string by using JSString::toExistingAtomicString(). This is faster + because it avoids allocating a new StringImpl if the string is already + a known Identifier, which is guaranteed to be the case if it's present + as an own property on the object.) + + ~10% speed-up on Dromaeo/dom-attr.html + + Reviewed by Geoffrey Garen. + + * dfg/DFGOperations.cpp: + * jit/JITOperations.cpp: + (JSC::getByVal): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getByVal): + + When using the fastGetOwnProperty() optimization, get the String + out of JSString by using toExistingAtomicString(). This avoids + StringImpl allocation and lets us bypass the PropertyTable lookup + entirely if no AtomicString is found. + + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::fastGetOwnProperty): + + Make fastGetOwnProperty() take a PropertyName instead of a String. + This avoids churning the ref count, since we don't need to create + a temporary wrapper around the AtomicStringImpl* found in GetByVal. + + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + + Add constructor: PropertyName(AtomicStringImpl*) + + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::get): + (JSC::PropertyTable::findWithString): Deleted. + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::get): + + Remove code for querying a PropertyTable with an unhashed string key + since the only client is now gone. + +2014-09-02 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + [ARM] MacroAssembler generating incorrect code on ARM32 Traditional + https://bugs.webkit.org/show_bug.cgi?id=136429 + + Reviewed by Csaba Osztrogonác. + + Changed test32 to use tst to check if reg is zero, instead of cmp. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::test32): + +2014-09-02 Michael Saboff <msaboff@apple.com> + + Out of bounds write in vmEntryToJavaScript / JSC::JITCode::execute + https://bugs.webkit.org/show_bug.cgi?id=136305 + + Reviewed by Filip Pizlo. + + While preparing the callee's CallFrame, ProtoCallFrame fixes any arity mismatch + and then JITCode::execute() calls the normal entrypoint. This is incompatible + with the expectation of FTL generated functions. Changed ProtoCallFrame to not + perform the arity fix, but just flag an arity mismatch. now JITCode::execute() + uses that arity mismatch condition to select the normal or arity check + entrypoint. The entrypoint selection is only done for functions, programs + and eval always have one parameter. + + * interpreter/ProtoCallFrame.cpp: + (JSC::ProtoCallFrame::init): Changed to flag arity mismatch instead of fixing it. + * interpreter/ProtoCallFrame.h: + (JSC::ProtoCallFrame::needArityCheck): New boolean to signify what entrypoint + should be called. + * jit/JITCode.cpp: + (JSC::JITCode::execute): Select normal or arity check entrypoint as appropriate. + +2014-09-02 peavo@outlook.com <peavo@outlook.com> + + [WinCairo] testapi.exe is not built. + https://bugs.webkit.org/show_bug.cgi?id=136369 + + Reviewed by Alex Christensen. + + The testapi project should be of type Application. + + * JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj: Change project type to Application. + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj: Ditto. + * JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props: Compile and link fix. + * JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj: Change project type to Application. + +2014-09-01 Akos Kiss <akiss@inf.u-szeged.hu> + + [CMAKE] Add missing offlineasm dependencies + https://bugs.webkit.org/show_bug.cgi?id=136437 + + Reviewed by Csaba Osztrogonác. + + Add the ARM64, MIPS and SH4 backends to the dependencies. + + * CMakeLists.txt: + +2014-09-01 Brian J. Burg <burg@cs.washington.edu> + + Provide column numbers to DTrace willExecute/didExecute probes + https://bugs.webkit.org/show_bug.cgi?id=136434 + + Reviewed by Antti Koivisto. + + Provide the columnNumber and update stubs for !HAVE(DTRACE). + + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::willExecute): + (JSC::ProfileGenerator::didExecute): + * runtime/Tracing.d: + * runtime/Tracing.h: + +2014-09-01 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + [CMAKE] Build warning by INTERFACE_LINK_LIBRARIES + https://bugs.webkit.org/show_bug.cgi?id=136194 + + Reviewed by Csaba Osztrogonác. + + Set the LINK_INTERFACE_LIBRARIES target property on the top level CMakeLists.txt. + + * CMakeLists.txt: + +2014-08-26 Maciej Stachowiak <mjs@apple.com> + + Use RetainPtr::autorelease in some places where it seems appropriate + https://bugs.webkit.org/show_bug.cgi?id=136280 + + Reviewed by Darin Adler. + + * API/JSContext.mm: + (-[JSContext name]): Use RetainPtr::autorelease() in place of ObjC autorelease. + * API/JSValue.mm: + (valueToString): Make appropriate use of RetainPtr + +2014-08-29 Akos Kiss <akiss@inf.u-szeged.hu> + + Ensure that the call frame passed from doVMEntry to the called function always contains the valid scope chain. + https://bugs.webkit.org/show_bug.cgi?id=136391 + + Reviewed by Michael Saboff. + + Do not rely on calling conventions to fill in the CallerFrame component + of the ExecState* parameter of the called function. + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-08-29 Saam Barati <sbarati@apple.com> + + emit op_profile_type for deconstruction assignments + https://bugs.webkit.org/show_bug.cgi?id=136274 + + Reviewed by Filip Pizlo. + + Enable type profiling for ES6 deconstruction expressions. + + * bytecompiler/NodesCodegen.cpp: + (JSC::BindingNode::bindValue): + +2014-08-29 Joseph Pecoraro <pecoraro@apple.com> + + JavaScriptCore: Use ASCIILiteral where possible + https://bugs.webkit.org/show_bug.cgi?id=136179 + + Reviewed by Michael Saboff. + + General string / character related changes. Use ASCIILiteral where + possible, jsNontrivialString where possible, and replace string + literals with character literals in some places. + + No new tests, no changes to functionality. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::nameForRegister): + * bytecompiler/NodesCodegen.cpp: + (JSC::PostfixNode::emitBytecode): + (JSC::PrefixNode::emitBytecode): + (JSC::AssignErrorNode::emitBytecode): + (JSC::ForInNode::emitMultiLoopBytecode): + (JSC::ForOfNode::emitBytecode): + (JSC::ObjectPatternNode::toString): + * dfg/DFGFunctionWhitelist.cpp: + (JSC::DFG::FunctionWhitelist::contains): + * dfg/DFGOperations.cpp: + (JSC::DFG::newTypedArrayWithSize): + (JSC::DFG::newTypedArrayWithOneArgument): + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::addToFrontend): + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::InspectorBackendDispatcher::dispatch): + * inspector/ScriptCallStackFactory.cpp: + (Inspector::extractSourceInformationFromException): + * inspector/scripts/codegen/generator_templates.py: + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::functionName): + (JSC::StackVisitor::Frame::sourceURL): + * jit/JITOperations.cpp: + * jsc.cpp: + (functionDescribeArray): + (functionRun): + (functionLoad): + (functionReadFile): + (functionCheckSyntax): + (functionTransferArrayBuffer): + (runWithScripts): + (runInteractive): + * parser/Lexer.cpp: + (JSC::Lexer<T>::invalidCharacterMessage): + (JSC::Lexer<T>::parseString): + (JSC::Lexer<T>::parseStringSlowCase): + (JSC::Lexer<T>::lex): + * profiler/Profile.cpp: + (JSC::Profile::Profile): + * runtime/Arguments.cpp: + (JSC::argumentsFuncIterator): + * runtime/ArrayPrototype.cpp: + (JSC::performSlowSort): + (JSC::arrayProtoFuncSort): + * runtime/ExceptionHelpers.cpp: + (JSC::createError): + (JSC::createInvalidParameterError): + (JSC::createNotAConstructorError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + (JSC::createErrorForInvalidGlobalAssignment): + * runtime/FunctionPrototype.cpp: + (JSC::insertSemicolonIfNeeded): + * runtime/JSArray.cpp: + (JSC::JSArray::defineOwnProperty): + (JSC::JSArray::pop): + (JSC::JSArray::push): + * runtime/JSArrayBufferConstructor.cpp: + (JSC::JSArrayBufferConstructor::finishCreation): + * runtime/JSArrayBufferPrototype.cpp: + (JSC::arrayBufferProtoFuncSlice): + * runtime/JSDataView.cpp: + (JSC::JSDataView::create): + * runtime/JSDataViewPrototype.cpp: + (JSC::getData): + (JSC::setData): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncProtoSetter): + * runtime/JSPromiseConstructor.cpp: + (JSC::JSPromiseConstructor::finishCreation): + * runtime/LiteralParser.cpp: + (JSC::LiteralParser<CharType>::Lexer::lex): + (JSC::LiteralParser<CharType>::Lexer::lexString): + (JSC::LiteralParser<CharType>::parse): + * runtime/LiteralParser.h: + (JSC::LiteralParser::getErrorMessage): + * runtime/TypeSet.cpp: + (JSC::TypeSet::seenTypes): + (JSC::TypeSet::displayName): + (JSC::TypeSet::allPrimitiveTypeNames): + (JSC::StructureShape::propertyHash): + (JSC::StructureShape::stringRepresentation): + +2014-08-29 Csaba Osztrogonác <ossy@webkit.org> + + Unreviwed, remove empty directories. + + * qt: Removed. + +2014-08-28 Mark Lam <mark.lam@apple.com> + + DebuggerCallFrame::scope() should return a DebuggerScope. + <https://webkit.org/b/134420> + + Reviewed by Geoffrey Garen. + + Rolling back in r170680 with the fix for <https://webkit.org/b/135656>. + + Previously, DebuggerCallFrame::scope() returns a JSActivation (and relevant + peers) which the WebInspector will use to introspect CallFrame variables. + Instead, we should be returning a DebuggerScope as an abstraction layer that + provides the introspection functionality that the WebInspector needs. This + is the first step towards not forcing every frame to have a JSActivation + object just because the debugger is enabled. + + 1. Instantiate the debuggerScopeStructure as a member of the JSGlobalObject + instead of the VM. This allows JSObject::globalObject() to be able to + return the global object for the DebuggerScope. + + 2. On the DebuggerScope's life-cycle management: + + The DebuggerCallFrame is designed to be "valid" only during a debugging session + (while the debugger is broken) through the use of a DebuggerCallFrameScope in + Debugger::pauseIfNeeded(). Once the debugger resumes from the break, the + DebuggerCallFrameScope destructs, and the DebuggerCallFrame will be invalidated. + We can't guarantee (from this code alone) that the Inspector code isn't still + holding a ref to the DebuggerCallFrame (though they shouldn't), but by contract, + the frame will be invalidated, and any attempt to query it will return null values. + This is pre-existing behavior. + + Now, we're adding the DebuggerScope into the picture. While a single debugger + pause session is in progress, the Inspector may request the scope from the + DebuggerCallFrame. While the DebuggerCallFrame is still valid, we want + DebuggerCallFrame::scope() to always return the same DebuggerScope object. + This is why we hold on to the DebuggerScope with a strong ref. + + If we use a weak ref instead, the following cooky behavior can manifest: + 1. The Inspector calls Debugger::scope() to get the top scope. + 2. The Inspector iterates down the scope chain and is now only holding a + reference to a parent scope. It is no longer referencing the top scope. + 3. A GC occurs, and the DebuggerCallFrame's weak m_scope ref to the top scope + gets cleared. + 4. The Inspector calls DebuggerCallFrame::scope() to get the top scope again but gets + a different DebuggerScope instance. + 5. The Inspector iterates down the scope chain but never sees the parent scope + instance that retained a ref to in step 2 above. This is because when iterating + this new DebuggerScope instance (which has no knowledge of the previous parent + DebuggerScope instance), a new DebuggerScope instance will get created for the + same parent scope. + + Since the DebuggerScope is a JSObject, its liveness is determined by its reachability. + However, its "validity" is determined by the life-cycle of its owner DebuggerCallFrame. + When the owner DebuggerCallFrame gets invalidated, its debugger scope chain (if + instantiated) will also get invalidated. This is why we need the + DebuggerScope::invalidateChain() method. The Inspector should not be using the + DebuggerScope instance after its owner DebuggerCallFrame is invalidated. If it does, + those methods will do nothing or returned a failed status. + + Fix for <https://webkit.org/b/135656>: + 3. DebuggerScope::getOwnPropertySlot() and DebuggerScope::put() need to set + m_thisValue in the returned slot to the wrapped scope object. Previously, + it was pointing to the DebuggerScope though the rest of the fields in the + returned slot will be set to data pertaining the wrapped scope object. + + 4. DebuggerScope::getOwnPropertySlot() will invoke getPropertySlot() on its + wrapped scope. This is because JSObject::getPropertySlot() cannot be + overridden, and when called on a DebuggerScope, will not know to look in + the ptototype chain of the DebuggerScope's wrapped scope. Hence, we'll + treat all properties in the wrapped scope as own properties in the + DebuggerScope. This is fine because the WebInspector does not presently + care about where in the prototype chain the scope property comes from. + + Note that the DebuggerScope and the JSActivation objects that it wraps do + not have prototypes. They are always jsNull(). This works perfectly with + the above change to use getPropertySlot() instead of getOwnPropertySlot(). + To make this an explicit invariant, I also changed DebuggerScope::createStructure() + and JSActivation::createStructure() to not take a prototype argument, and + to always use jsNull() for their prototype value. + + * debugger/Debugger.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::scope): + (JSC::DebuggerCallFrame::evaluate): + (JSC::DebuggerCallFrame::invalidate): + * debugger/DebuggerCallFrame.h: + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::DebuggerScope): + (JSC::DebuggerScope::finishCreation): + (JSC::DebuggerScope::visitChildren): + (JSC::DebuggerScope::className): + (JSC::DebuggerScope::getOwnPropertySlot): + (JSC::DebuggerScope::put): + (JSC::DebuggerScope::deleteProperty): + (JSC::DebuggerScope::getOwnPropertyNames): + (JSC::DebuggerScope::defineOwnProperty): + (JSC::DebuggerScope::next): + (JSC::DebuggerScope::invalidateChain): + (JSC::DebuggerScope::isWithScope): + (JSC::DebuggerScope::isGlobalScope): + (JSC::DebuggerScope::isFunctionOrEvalScope): + * debugger/DebuggerScope.h: + (JSC::DebuggerScope::create): + (JSC::DebuggerScope::createStructure): + (JSC::DebuggerScope::iterator::iterator): + (JSC::DebuggerScope::iterator::get): + (JSC::DebuggerScope::iterator::operator++): + (JSC::DebuggerScope::iterator::operator==): + (JSC::DebuggerScope::iterator::operator!=): + (JSC::DebuggerScope::isValid): + (JSC::DebuggerScope::jsScope): + (JSC::DebuggerScope::begin): + (JSC::DebuggerScope::end): + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::scopeType): + (Inspector::JSJavaScriptCallFrame::scopeChain): + * inspector/JavaScriptCallFrame.h: + (Inspector::JavaScriptCallFrame::scopeChain): + * inspector/ScriptDebugServer.cpp: + * runtime/JSActivation.h: + (JSC::JSActivation::createStructure): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::debuggerScopeStructure): + * runtime/JSObject.cpp: + * runtime/JSObject.h: + (JSC::JSObject::isWithScope): + * runtime/JSScope.h: + * runtime/PropertySlot.h: + (JSC::PropertySlot::setThisValue): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::setThisValue): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2014-08-28 Andreas Kling <akling@apple.com> + + Use JSString::toIdentifier() in more places. + <https://webkit.org/b/136348> + + Call sites that grab the WTF::String from a JSString using value() can + use the more efficient toIdentifier() if the string is going to be used + to construct an Identifier. + + If the JSString is a rope that resolves to something that is already + present in the VM's Identifier table, using toIdentifier() can avoid + allocating a new StringImpl. + + Reviewed by Geoffrey Garen. + + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::opIn): + * runtime/JSONObject.cpp: + (JSC::Stringifier::Stringifier): + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyDescriptor): + (JSC::objectConstructorDefineProperty): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncPropertyIsEnumerable): + +2014-08-27 Filip Pizlo <fpizlo@apple.com> + + DFG should compute immediate dominators using the O(n log n) form of Lengauer and Tarjan's "A Fast Algorithm for Finding Dominators in a Flowgraph" + https://bugs.webkit.org/show_bug.cgi?id=93361 + + Reviewed by Mark Hahnenberg. + + This patch also adds some new utilities for reasoning about block-keyed maps, block sets, + and block worklists. It changes preexisting code to use these abstractions. + + The main effect of this code is that all current clients of dominators end up using the + results of the new idom calculation. We convert the dom tree to a dominance test using + Dietz's pre/post number range check trick. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAnalysis.h: + (JSC::DFG::Analysis::computeIfNecessary): + (JSC::DFG::Analysis::computeDependencies): + * dfg/DFGBlockMap.h: Added. + (JSC::DFG::BlockMap::BlockMap): + (JSC::DFG::BlockMap::size): + (JSC::DFG::BlockMap::atIndex): + (JSC::DFG::BlockMap::operator[]): + * dfg/DFGBlockMapInlines.h: Added. + (JSC::DFG::BlockMap<T>::BlockMap): + * dfg/DFGBlockSet.h: Added. + (JSC::DFG::BlockSet::BlockSet): + (JSC::DFG::BlockSet::add): + (JSC::DFG::BlockSet::contains): + * dfg/DFGBlockWorklist.cpp: Added. + (JSC::DFG::BlockWorklist::BlockWorklist): + (JSC::DFG::BlockWorklist::~BlockWorklist): + (JSC::DFG::BlockWorklist::push): + (JSC::DFG::BlockWorklist::pop): + (JSC::DFG::PostOrderBlockWorklist::PostOrderBlockWorklist): + (JSC::DFG::PostOrderBlockWorklist::~PostOrderBlockWorklist): + (JSC::DFG::PostOrderBlockWorklist::pushPre): + (JSC::DFG::PostOrderBlockWorklist::pushPost): + (JSC::DFG::PostOrderBlockWorklist::pop): + * dfg/DFGBlockWorklist.h: Added. + (JSC::DFG::BlockWorklist::notEmpty): + (JSC::DFG::BlockWith::BlockWith): + (JSC::DFG::BlockWith::operator UnspecifiedBoolType*): + (JSC::DFG::ExtendedBlockWorklist::ExtendedBlockWorklist): + (JSC::DFG::ExtendedBlockWorklist::forcePush): + (JSC::DFG::ExtendedBlockWorklist::push): + (JSC::DFG::ExtendedBlockWorklist::notEmpty): + (JSC::DFG::ExtendedBlockWorklist::pop): + (JSC::DFG::BlockWithOrder::BlockWithOrder): + (JSC::DFG::BlockWithOrder::operator UnspecifiedBoolType*): + (JSC::DFG::PostOrderBlockWorklist::push): + (JSC::DFG::PostOrderBlockWorklist::notEmpty): + * dfg/DFGCSEPhase.cpp: + * dfg/DFGDominators.cpp: + (JSC::DFG::Dominators::compute): + (JSC::DFG::Dominators::naiveDominates): + (JSC::DFG::Dominators::dump): + (JSC::DFG::Dominators::pruneDominators): Deleted. + * dfg/DFGDominators.h: + (JSC::DFG::Dominators::strictlyDominates): + (JSC::DFG::Dominators::dominates): + (JSC::DFG::Dominators::BlockData::BlockData): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dumpBlockHeader): + (JSC::DFG::Graph::getBlocksInPreOrder): + (JSC::DFG::Graph::getBlocksInPostOrder): + * dfg/DFGInvalidationPointInjectionPhase.cpp: + (JSC::DFG::InvalidationPointInjectionPhase::run): + * dfg/DFGNaiveDominators.cpp: Added. + (JSC::DFG::NaiveDominators::NaiveDominators): + (JSC::DFG::NaiveDominators::~NaiveDominators): + (JSC::DFG::NaiveDominators::compute): + (JSC::DFG::NaiveDominators::pruneDominators): + (JSC::DFG::NaiveDominators::dump): + * dfg/DFGNaiveDominators.h: Added. + (JSC::DFG::NaiveDominators::dominates): + * dfg/DFGNaturalLoops.cpp: + (JSC::DFG::NaturalLoops::computeDependencies): + (JSC::DFG::NaturalLoops::compute): + * dfg/DFGNaturalLoops.h: + +2014-08-27 Filip Pizlo <fpizlo@apple.com> + + FTL should be able to do polymorphic call inlining + https://bugs.webkit.org/show_bug.cgi?id=135145 + + Reviewed by Geoffrey Garen. + + Added a log-based high-fidelity call edge profiler that runs in DFG JIT (and optionally + baseline JIT) code. Used it to do precise polymorphic inlining in the FTL. Potential + inlining sites use the call edge profile if it is available, but they will still fall back + on the call inline cache and rare case counts if it's not. Polymorphic inlining means that + multiple possible callees can be inlined with a switch to guard them. The slow path may + either be an OSR exit or a virtual call. + + The call edge profiling added in this patch is very precise - it will tell you about every + call that has ever happened. It took some effort to reduce the overhead of this profiling. + This mostly involved ensuring that we don't do it unnecessarily. For example, we avoid it + in the baseline JIT (you can conditionally enable it but it's off by default) and we only do + it in the DFG JIT if we know that the regular inline cache profiling wasn't precise enough. + I also experimented with reducing the precision of the profiling. This led to a significant + reduction in the speed-up, so I avoided this approach. I also explored making log processing + concurrent, but that didn't help. Also, I tested the overhead of the log processing and + found that most of the overhead of this profiling is actually in putting things into the log + rather than in processing the log - that part appears to be surprisingly cheap. + + Polymorphic inlining could be enabled in the DFG if we enabled baseline call edge profiling, + and if we guarded such inlining sites with some profiling mechanism to detect + polyvariant monomorphisation opportunities (where the callsite being inlined reveals that + it's actually monomorphic). + + This is a ~28% speed-up on deltablue and a ~7% speed-up on richards, with small speed-ups on + other programs as well. It's about a 2% speed-up on Octane version 2, and never a regression + on anything we care about. Some aggregates, like V8Spider, see a regression. This is + highlighting the increase in profiling overhead. But since this doesn't show up on any major + score (code-load or SunSpider), it's probably not relevant. + + Relanding after fixing debug assertions in fast/storage/serialized-script-value.html. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CallEdge.cpp: Added. + (JSC::CallEdge::dump): + * bytecode/CallEdge.h: Added. + (JSC::CallEdge::operator!): + (JSC::CallEdge::callee): + (JSC::CallEdge::count): + (JSC::CallEdge::despecifiedClosure): + (JSC::CallEdge::CallEdge): + * bytecode/CallEdgeProfile.cpp: Added. + (JSC::CallEdgeProfile::callEdges): + (JSC::CallEdgeProfile::numCallsToKnownCells): + (JSC::worthDespecifying): + (JSC::CallEdgeProfile::worthDespecifying): + (JSC::CallEdgeProfile::visitWeak): + (JSC::CallEdgeProfile::addSlow): + (JSC::CallEdgeProfile::mergeBack): + (JSC::CallEdgeProfile::fadeByHalf): + (JSC::CallEdgeLog::CallEdgeLog): + (JSC::CallEdgeLog::~CallEdgeLog): + (JSC::CallEdgeLog::isEnabled): + (JSC::operationProcessCallEdgeLog): + (JSC::CallEdgeLog::emitLogCode): + (JSC::CallEdgeLog::processLog): + * bytecode/CallEdgeProfile.h: Added. + (JSC::CallEdgeProfile::numCallsToNotCell): + (JSC::CallEdgeProfile::numCallsToUnknownCell): + (JSC::CallEdgeProfile::totalCalls): + * bytecode/CallEdgeProfileInlines.h: Added. + (JSC::CallEdgeProfile::CallEdgeProfile): + (JSC::CallEdgeProfile::add): + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::visitWeak): + * bytecode/CallLinkInfo.h: + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::computeFromLLInt): + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeExitSiteData): + (JSC::CallLinkStatus::computeFromCallLinkInfo): + (JSC::CallLinkStatus::computeFromCallEdgeProfile): + (JSC::CallLinkStatus::computeDFGStatuses): + (JSC::CallLinkStatus::isClosureCall): + (JSC::CallLinkStatus::makeClosureCall): + (JSC::CallLinkStatus::dump): + (JSC::CallLinkStatus::function): Deleted. + (JSC::CallLinkStatus::internalFunction): Deleted. + (JSC::CallLinkStatus::intrinsicFor): Deleted. + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::isSet): + (JSC::CallLinkStatus::couldTakeSlowPath): + (JSC::CallLinkStatus::edges): + (JSC::CallLinkStatus::size): + (JSC::CallLinkStatus::at): + (JSC::CallLinkStatus::operator[]): + (JSC::CallLinkStatus::canOptimize): + (JSC::CallLinkStatus::canTrustCounts): + (JSC::CallLinkStatus::isClosureCall): Deleted. + (JSC::CallLinkStatus::callTarget): Deleted. + (JSC::CallLinkStatus::executable): Deleted. + (JSC::CallLinkStatus::makeClosureCall): Deleted. + * bytecode/CallVariant.cpp: Added. + (JSC::CallVariant::dump): + * bytecode/CallVariant.h: Added. + (JSC::CallVariant::CallVariant): + (JSC::CallVariant::operator!): + (JSC::CallVariant::despecifiedClosure): + (JSC::CallVariant::rawCalleeCell): + (JSC::CallVariant::internalFunction): + (JSC::CallVariant::function): + (JSC::CallVariant::isClosureCall): + (JSC::CallVariant::executable): + (JSC::CallVariant::nonExecutableCallee): + (JSC::CallVariant::intrinsicFor): + (JSC::CallVariant::functionExecutable): + (JSC::CallVariant::isHashTableDeletedValue): + (JSC::CallVariant::operator==): + (JSC::CallVariant::operator!=): + (JSC::CallVariant::operator<): + (JSC::CallVariant::operator>): + (JSC::CallVariant::operator<=): + (JSC::CallVariant::operator>=): + (JSC::CallVariant::hash): + (JSC::CallVariant::deletedToken): + (JSC::CallVariantHash::hash): + (JSC::CallVariantHash::equal): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::isNormalCall): + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): + * bytecode/ExitKind.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::~BasicBlock): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::takeLast): + (JSC::DFG::BasicBlock::didLink): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::processSetLocalQueue): + (JSC::DFG::ByteCodeParser::removeLastNodeFromGraph): + (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::emitFunctionChecks): + (JSC::DFG::ByteCodeParser::undoFunctionChecks): + (JSC::DFG::ByteCodeParser::inliningCost): + (JSC::DFG::ByteCodeParser::inlineCall): + (JSC::DFG::ByteCodeParser::cancelLinkingForBlock): + (JSC::DFG::ByteCodeParser::attemptToInlineCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + (JSC::DFG::ByteCodeParser::prepareToParseBlock): + (JSC::DFG::ByteCodeParser::clearCaches): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::linkBlock): + (JSC::DFG::ByteCodeParser::linkBlocks): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::freeUnnecessaryNodes): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::getBlocksInPreOrder): + (JSC::DFG::Graph::visitChildren): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGLazyJSValue.cpp: + (JSC::DFG::LazyJSValue::switchLookupValue): + * dfg/DFGLazyJSValue.h: + (JSC::DFG::LazyJSValue::switchLookupValue): Deleted. + * dfg/DFGNode.cpp: + (WTF::printInternal): + * dfg/DFGNode.h: + (JSC::DFG::OpInfo::OpInfo): + (JSC::DFG::Node::hasHeapPrediction): + (JSC::DFG::Node::hasCellOperand): + (JSC::DFG::Node::cellOperand): + (JSC::DFG::Node::setCellOperand): + (JSC::DFG::Node::canBeKnownFunction): Deleted. + (JSC::DFG::Node::hasKnownFunction): Deleted. + (JSC::DFG::Node::knownFunction): Deleted. + (JSC::DFG::Node::giveKnownFunction): Deleted. + (JSC::DFG::Node::hasFunction): Deleted. + (JSC::DFG::Node::function): Deleted. + (JSC::DFG::Node::hasExecutable): Deleted. + (JSC::DFG::Node::executable): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGPhantomCanonicalizationPhase.cpp: + (JSC::DFG::PhantomCanonicalizationPhase::run): + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitSwitch): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureRegistrationPhase.cpp: + (JSC::DFG::StructureRegistrationPhase::run): + * dfg/DFGTierUpCheckInjectionPhase.cpp: + (JSC::DFG::TierUpCheckInjectionPhase::run): + (JSC::DFG::TierUpCheckInjectionPhase::removeFTLProfiling): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::ftlUnreachable): + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCheckCell): + (JSC::FTL::LowerDFGToLLVM::compileCheckBadCell): + (JSC::FTL::LowerDFGToLLVM::compileGetExecutable): + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::buildSwitch): + (JSC::FTL::LowerDFGToLLVM::compileCheckFunction): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileCheckExecutable): Deleted. + * heap/Heap.cpp: + (JSC::Heap::collect): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::storeValue): + (JSC::AssemblyHelpers::loadValue): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArguments): + * jit/GPRInfo.h: + (JSC::JSValueRegs::uses): + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + * runtime/Options.h: + * runtime/VM.cpp: + (JSC::VM::ensureCallEdgeLog): + * runtime/VM.h: + * tests/stress/fold-profiled-call-to-call.js: Added. This test pinpoints the problem we saw in fast/storage/serialized-script-value.html. + * tests/stress/new-array-then-exit.js: Added. + * tests/stress/poly-call-exit-this.js: Added. + * tests/stress/poly-call-exit.js: Added. + +2014-08-28 Julien Brianceau <jbriance@cisco.com> + + Correct GC length unit and prevent division by 0 in showObjectStatistics. + https://bugs.webkit.org/show_bug.cgi?id=136340 + + Reviewed by Mark Hahnenberg. + + * heap/HeapStatistics.cpp: + (JSC::HeapStatistics::showObjectStatistics): + +2014-08-27 Akos Kiss <akiss@inf.u-szeged.hu> + + Ensure that the call frame passed from JIT code via JSC::operationCallEval to JSC::eval always contains the valid scope chain. + https://bugs.webkit.org/show_bug.cgi?id=136313 + + Reviewed by Michael Saboff. + + Do not rely on calling conventions to fill in the CallerFrame component + of the execCallee parameter of JSC::operationCallEval. + + * jit/JITOperations.cpp: + +2014-08-27 Saam Barati <sbarati@apple.com> + + Deconstruction object pattern node emits the wrong start/end text positions + https://bugs.webkit.org/show_bug.cgi?id=136304 + + Reviewed by Geoffrey Garen. + + Object pattern nodes that used the syntactic sugar binding: + 'var {foo} = {foo:20}' instead of 'var {foo:foo} = {foo:20}' + would get the wrong text position for variable 'foo'. The position + would be placed on the comma(s)/closing brace instead of the identifier. + This patch fixes this bug by caching the identifier's JSToken before + trying to parse an optional colon. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclarationList): + (JSC::Parser<LexerType>::createBindingPattern): + (JSC::Parser<LexerType>::parseDeconstructionPattern): + * parser/Parser.h: + +2014-08-27 Brent Fulgham <bfulgham@apple.com> + + [Win] Build fix after last commit. + + Check in new DLLLauncherMain.cpp file. + + * JavaScriptCore.vcxproj/jsc/DLLLauncherMain.cpp: Added. + (enableTerminationOnHeapCorruption): + (getStringValue): + (applePathFromRegistry): + (appleApplicationSupportDirectory): + (copyEnvironmentVariable): + (prependPath): + (fatalError): + (directoryExists): + (modifyPath): + (getLastErrorString): + (wWinMain): + +2014-08-27 Brent Fulgham <bfulgham@apple.com> + + [Win] testapi and testRegExp need to find support libraries. + https://bugs.webkit.org/show_bug.cgi?id=136008. + + Reviewed by Dean Jackson. + + Revise the Windows build of jsc, testapi, and testRegExp so that they + find and use the proper runtime support libraries. + + These locations vary between the Apple Windows build and WinCairo, and + are generally not in the system PATH environment setting. Consequently, + these applications fail on launch unless the user modifies their + PATH. + + This patch revises these tools to work like WinLauncher and DumpRenderTree + so that they run reliably. + + * API/tests/testapi.c: + (dllLauncherEntryPoint): Added. + * JavaScriptCore.vcxproj/JavaScriptCore.sln: Add new build projects and + provide proper dependencies with existing projects. + * JavaScriptCore.vcxproj/JavaScriptCore.submit.sln: Ditto. + * JavaScriptCore.vcxproj/jsc/jsc.vcxproj: Switch to build + a DLL, rather than an executable. + * JavaScriptCore.vcxproj/jsc/jscCommon.props: Add shlwapi.lib + to the list of libraries needed at link-time, and to use + the DLL/Console combination entry point. + * JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj: Added. + * JavaScriptCore.vcxproj/jsc/jscLauncherPostBuild.cmd: Copied from JavaScriptCore.vcxproj/jsc/jscPostBuild.cmd. + * JavaScriptCore.vcxproj/jsc/jscLauncherPreBuild.cmd: Copied from JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd. + * JavaScriptCore.vcxproj/jsc/jscLauncherPreLink.cmd: Copied from JavaScriptCore.vcxproj/jsc/jscPreLink.cmd. + * JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj: Switch to build + a DLL, rather than an executable. + * JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props: Add shlwapi.lib + to the list of libraries needed at link-time, and to use + the DLL/Console combination entry point. + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj: Added. + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPostBuild.cmd: Copied from JavaScriptCore.vcxproj/testRegExp/testRegExpPostBuild.cmd. + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreBuild.cmd: Copied from JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd. + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreLink.cmd: Copied from JavaScriptCore.vcxproj/testRegExp/testRegExpPreLink.cmd. + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: Switch to build + a DLL, rather than an executable. + * JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj: Added. + * JavaScriptCore.vcxproj/testapi/testapiCommon.props: Add shlwapi.lib + to the list of libraries needed at link-time, and to use + the DLL/Console combination entry point. + * JavaScriptCore.vcxproj/testapi/testapiLauncherPostBuild.cmd: Copied from JavaScriptCore.vcxproj/testRegExp/testRegExpPostBuild.cmd. + * JavaScriptCore.vcxproj/testapi/testapiLauncherPreBuild.cmd: Copied from JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd. + * JavaScriptCore.vcxproj/testapi/testapiLauncherPreLink.cmd: Copied from JavaScriptCore.vcxproj/testRegExp/testRegExpPreLink.cmd. + * jsc.cpp: + (dllLauncherEntryPoint): Added. + * testRegExp.cpp: + (dllLauncherEntryPoint): Added. + +2014-08-27 Julien Brianceau <jbriance@cisco.com> + + Take advantage of 3 parameters or32() calls + https://bugs.webkit.org/show_bug.cgi?id=136287 + + Reviewed by Michael Saboff. + + For specific architectures (arm and mips for instance), or32() calls + with 3 parameters are likely to produce a single instruction. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::branchIsOther): + (JSC::DFG::SpeculativeJIT::branchNotOther): + +2014-08-26 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: put feature flags for Inspector domains in the protocol specification + https://bugs.webkit.org/show_bug.cgi?id=136027 + + Reviewed by Timothy Hatcher. + + Remove the hardcoded map of domains to feature guards, and instead parse it from the specification. + + Test: inspector/scripts/tests/generate-domains-with-feature-guards.json + + * inspector/scripts/codegen/generator.py: + (Generator.wrap_with_guard_for_domain): + * inspector/scripts/codegen/models.py: + (Protocol.parse_domain): + (Domain.__init__): + (Domains): + * inspector/scripts/tests/generate-domains-with-feature-guards.json: Added. + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + +2014-08-26 Andy Estes <aestes@apple.com> + + [Cocoa] Some projects are incorrectly installed to $BUILT_PRODUCTS_DIR + https://bugs.webkit.org/show_bug.cgi?id=136267 + + Reviewed by Dan Bernstein. + + INSTALL_PATH was set to $BUILT_PRODUCTS_DIR for engineering configurations in r20225 as part of a build fix. + Not only is this no longer necessary to build, but it causes built products to be incorrectly installed in + engineering configurations. + + Remove the setting of INSTALL_PATH from the pbxproj file so that the value specified in the xcconfig files is + used instead. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-08-26 Michael Saboff <msaboff@apple.com> + + [Win] 64-bit JavaScriptCore crashes on launch + https://bugs.webkit.org/show_bug.cgi?id=136241 + + Reviewed by Mark Lam. + + * llint/LowLevelInterpreter.asm: + (vmEntryRecord): X86_64_WIN doesn't use "a0" (rax) for the first argument, it uses + "t2" (rcx). Changed to get the input parameter using the correct register. + +2014-08-26 Saam Barati <sbarati@apple.com> + + TypeSet caches structureIDs even after the corresponding Structure could be GCed + https://bugs.webkit.org/show_bug.cgi?id=136178 + + Reviewed by Geoffrey Garen. + + Currently, TypeSet will never remove StructureIDs from its cache, + even after the corresponding Structures could be garbage collected. + Now, when the Garbage Collector collects, and type profiling is + enabled, the Garbage Collector will invalidate all TypeSet caches. + + * heap/Heap.cpp: + (JSC::Heap::collect): + * runtime/TypeSet.cpp: + (JSC::TypeSet::addTypeInformation): + (JSC::TypeSet::invalidateCache): + * runtime/TypeSet.h: + * runtime/VM.cpp: + (JSC::VM::invalidateTypeSetCache): + * runtime/VM.h: + +2014-08-26 Michael Saboff <msaboff@apple.com> + + REGRESSION(r172794) + 32Bit build: for-in-base-reassigned-later-and-change-structure.js fail with NaN result + https://bugs.webkit.org/show_bug.cgi?id=136187 + + Reviewed by Mark Hahnenberg. + + Added two arg version for 32 bit builds of callOperation(J_JITOperation_ECJ, ...) that + doesn't require a tag for the second argument, instead it fills in a CellTag. This is + used for the slow case of the GetDirectPname case in SpeculativeJIT::compile since we + haven't set up a register with a tag and we know that argument 2 is a cell. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): New version with implicit CellTag. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): Eliminated extraneous filling of the scratchGPR + with CellTag as it wasn't in the control flow for the slow path that needed the tag. + Instead changed to calling new version of callOperation with an implicit CellTag. + +2014-08-26 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r172940. + https://bugs.webkit.org/show_bug.cgi?id=136256 + + Caused assertions on fast/storage/serialized-script- + value.html, and possibly flakiness on more tests (Requested by + ap on #webkit). + + Reverted changeset: + + "FTL should be able to do polymorphic call inlining" + https://bugs.webkit.org/show_bug.cgi?id=135145 + http://trac.webkit.org/changeset/172940 + +2014-08-26 Michael Saboff <msaboff@apple.com> + + REGRESSION(r172794) + 32Bit build: ASSERT failures in for-in-tests.js tests. + https://bugs.webkit.org/show_bug.cgi?id=136165 + + Reviewed by Mark Hahnenberg. + + Changed switch case GetDirectPname: to always use the slow path for X86 since it only has + 6 registers available, but the code requires 7. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-08-25 Saam Barati <sbarati@apple.com> + + TypeProfiler search breaks on return statements + https://bugs.webkit.org/show_bug.cgi?id=136201 + + Reviewed by Filip Pizlo. + + Searching for return statements in the TypeProfiler currently + breaks down because it expected to see the search descriptor + TypeProfilerSearchDescriptorFunctionReturn when looking for + return statements in the actual source code of the program. + But, TypeProfilerSearchDescriptorFunctionReturn search descriptor + is reserved for looking for return statements that aren't in the + actual source code of the program, but when asking for the + aggregate return type of a function. Now, searching for + return statements in the actual source code of the program will + work when passing in the search descriptor TypeProfilerSearchDescriptorNormal. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::findLocation): + (JSC::descriptorMatchesTypeLocation): Deleted. + +2014-08-25 Saam Barati <sbarati@apple.com> + + Return statement TypeSet's might be duplicated + https://bugs.webkit.org/show_bug.cgi?id=136200 + + Reviewed by Filip Pizlo. + + Currently, the globalTypeSet that converges the types of all + return statements in a function lives off of CodeBlock. It lives + off CodeBlock because of a faulty assumption that CodeBlock + will have a one to one mapping with a function in the source + text of the program. (Currently, there isn't an actual bug + with this design because TypeLocationCache will hash cons to + the same TypeLocation, but this is still an incorrect design). + In this patch, the globalTypeSet for function return statements + is moved to the FunctionExecutable object which does have a one + to one mapping with functions in the source text of a program. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::returnStatementTypeSet): Deleted. + * runtime/Executable.h: + (JSC::FunctionExecutable::returnStatementTypeSet): + +2014-08-24 Filip Pizlo <fpizlo@apple.com> + + FTL should be able to do polymorphic call inlining + https://bugs.webkit.org/show_bug.cgi?id=135145 + + Reviewed by Geoffrey Garen. + + Added a log-based high-fidelity call edge profiler that runs in DFG JIT (and optionally + baseline JIT) code. Used it to do precise polymorphic inlining in the FTL. Potential + inlining sites use the call edge profile if it is available, but they will still fall back + on the call inline cache and rare case counts if it's not. Polymorphic inlining means that + multiple possible callees can be inlined with a switch to guard them. The slow path may + either be an OSR exit or a virtual call. + + The call edge profiling added in this patch is very precise - it will tell you about every + call that has ever happened. It took some effort to reduce the overhead of this profiling. + This mostly involved ensuring that we don't do it unnecessarily. For example, we avoid it + in the baseline JIT (you can conditionally enable it but it's off by default) and we only do + it in the DFG JIT if we know that the regular inline cache profiling wasn't precise enough. + I also experimented with reducing the precision of the profiling. This led to a significant + reduction in the speed-up, so I avoided this approach. I also explored making log processing + concurrent, but that didn't help. Also, I tested the overhead of the log processing and + found that most of the overhead of this profiling is actually in putting things into the log + rather than in processing the log - that part appears to be surprisingly cheap. + + Polymorphic inlining could be enabled in the DFG if we enabled baseline call edge profiling, + and if we guarded such inlining sites with some profiling mechanism to detect + polyvariant monomorphisation opportunities (where the callsite being inlined reveals that + it's actually monomorphic). + + This is a ~28% speed-up on deltablue and a ~7% speed-up on richards, with small speed-ups on + other programs as well. It's about a 2% speed-up on Octane version 2, and never a regression + on anything we care about. Some aggregates, like V8Spider, see a regression. This is + highlighting the increase in profiling overhead. But since this doesn't show up on any major + score (code-load or SunSpider), it's probably not relevant. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CallEdge.cpp: Added. + (JSC::CallEdge::dump): + * bytecode/CallEdge.h: Added. + (JSC::CallEdge::operator!): + (JSC::CallEdge::callee): + (JSC::CallEdge::count): + (JSC::CallEdge::despecifiedClosure): + (JSC::CallEdge::CallEdge): + * bytecode/CallEdgeProfile.cpp: Added. + (JSC::CallEdgeProfile::callEdges): + (JSC::CallEdgeProfile::numCallsToKnownCells): + (JSC::worthDespecifying): + (JSC::CallEdgeProfile::worthDespecifying): + (JSC::CallEdgeProfile::visitWeak): + (JSC::CallEdgeProfile::addSlow): + (JSC::CallEdgeProfile::mergeBack): + (JSC::CallEdgeProfile::fadeByHalf): + (JSC::CallEdgeLog::CallEdgeLog): + (JSC::CallEdgeLog::~CallEdgeLog): + (JSC::CallEdgeLog::isEnabled): + (JSC::operationProcessCallEdgeLog): + (JSC::CallEdgeLog::emitLogCode): + (JSC::CallEdgeLog::processLog): + * bytecode/CallEdgeProfile.h: Added. + (JSC::CallEdgeProfile::numCallsToNotCell): + (JSC::CallEdgeProfile::numCallsToUnknownCell): + (JSC::CallEdgeProfile::totalCalls): + * bytecode/CallEdgeProfileInlines.h: Added. + (JSC::CallEdgeProfile::CallEdgeProfile): + (JSC::CallEdgeProfile::add): + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::visitWeak): + * bytecode/CallLinkInfo.h: + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::computeFromLLInt): + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeExitSiteData): + (JSC::CallLinkStatus::computeFromCallLinkInfo): + (JSC::CallLinkStatus::computeFromCallEdgeProfile): + (JSC::CallLinkStatus::computeDFGStatuses): + (JSC::CallLinkStatus::isClosureCall): + (JSC::CallLinkStatus::makeClosureCall): + (JSC::CallLinkStatus::dump): + (JSC::CallLinkStatus::function): Deleted. + (JSC::CallLinkStatus::internalFunction): Deleted. + (JSC::CallLinkStatus::intrinsicFor): Deleted. + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::isSet): + (JSC::CallLinkStatus::couldTakeSlowPath): + (JSC::CallLinkStatus::edges): + (JSC::CallLinkStatus::size): + (JSC::CallLinkStatus::at): + (JSC::CallLinkStatus::operator[]): + (JSC::CallLinkStatus::canOptimize): + (JSC::CallLinkStatus::canTrustCounts): + (JSC::CallLinkStatus::isClosureCall): Deleted. + (JSC::CallLinkStatus::callTarget): Deleted. + (JSC::CallLinkStatus::executable): Deleted. + (JSC::CallLinkStatus::makeClosureCall): Deleted. + * bytecode/CallVariant.cpp: Added. + (JSC::CallVariant::dump): + * bytecode/CallVariant.h: Added. + (JSC::CallVariant::CallVariant): + (JSC::CallVariant::operator!): + (JSC::CallVariant::despecifiedClosure): + (JSC::CallVariant::rawCalleeCell): + (JSC::CallVariant::internalFunction): + (JSC::CallVariant::function): + (JSC::CallVariant::isClosureCall): + (JSC::CallVariant::executable): + (JSC::CallVariant::nonExecutableCallee): + (JSC::CallVariant::intrinsicFor): + (JSC::CallVariant::functionExecutable): + (JSC::CallVariant::isHashTableDeletedValue): + (JSC::CallVariant::operator==): + (JSC::CallVariant::operator!=): + (JSC::CallVariant::operator<): + (JSC::CallVariant::operator>): + (JSC::CallVariant::operator<=): + (JSC::CallVariant::operator>=): + (JSC::CallVariant::hash): + (JSC::CallVariant::deletedToken): + (JSC::CallVariantHash::hash): + (JSC::CallVariantHash::equal): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::isNormalCall): + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): + * bytecode/ExitKind.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::~BasicBlock): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::takeLast): + (JSC::DFG::BasicBlock::didLink): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::processSetLocalQueue): + (JSC::DFG::ByteCodeParser::removeLastNodeFromGraph): + (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::emitFunctionChecks): + (JSC::DFG::ByteCodeParser::undoFunctionChecks): + (JSC::DFG::ByteCodeParser::inliningCost): + (JSC::DFG::ByteCodeParser::inlineCall): + (JSC::DFG::ByteCodeParser::cancelLinkingForBlock): + (JSC::DFG::ByteCodeParser::attemptToInlineCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + (JSC::DFG::ByteCodeParser::prepareToParseBlock): + (JSC::DFG::ByteCodeParser::clearCaches): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::linkBlock): + (JSC::DFG::ByteCodeParser::linkBlocks): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::freeUnnecessaryNodes): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::visitChildren): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGLazyJSValue.cpp: + (JSC::DFG::LazyJSValue::switchLookupValue): + * dfg/DFGLazyJSValue.h: + (JSC::DFG::LazyJSValue::switchLookupValue): Deleted. + * dfg/DFGNode.cpp: + (WTF::printInternal): + * dfg/DFGNode.h: + (JSC::DFG::OpInfo::OpInfo): + (JSC::DFG::Node::hasHeapPrediction): + (JSC::DFG::Node::hasCellOperand): + (JSC::DFG::Node::cellOperand): + (JSC::DFG::Node::setCellOperand): + (JSC::DFG::Node::canBeKnownFunction): Deleted. + (JSC::DFG::Node::hasKnownFunction): Deleted. + (JSC::DFG::Node::knownFunction): Deleted. + (JSC::DFG::Node::giveKnownFunction): Deleted. + (JSC::DFG::Node::hasFunction): Deleted. + (JSC::DFG::Node::function): Deleted. + (JSC::DFG::Node::hasExecutable): Deleted. + (JSC::DFG::Node::executable): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGPhantomCanonicalizationPhase.cpp: + (JSC::DFG::PhantomCanonicalizationPhase::run): + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitSwitch): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureRegistrationPhase.cpp: + (JSC::DFG::StructureRegistrationPhase::run): + * dfg/DFGTierUpCheckInjectionPhase.cpp: + (JSC::DFG::TierUpCheckInjectionPhase::run): + (JSC::DFG::TierUpCheckInjectionPhase::removeFTLProfiling): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::ftlUnreachable): + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCheckCell): + (JSC::FTL::LowerDFGToLLVM::compileCheckBadCell): + (JSC::FTL::LowerDFGToLLVM::compileGetExecutable): + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::buildSwitch): + (JSC::FTL::LowerDFGToLLVM::compileCheckFunction): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileCheckExecutable): Deleted. + * heap/Heap.cpp: + (JSC::Heap::collect): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::storeValue): + (JSC::AssemblyHelpers::loadValue): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArguments): + * jit/GPRInfo.h: + (JSC::JSValueRegs::uses): + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + * runtime/Options.h: + * runtime/VM.cpp: + (JSC::VM::ensureCallEdgeLog): + * runtime/VM.h: + * tests/stress/new-array-then-exit.js: Added. + (foo): + * tests/stress/poly-call-exit-this.js: Added. + * tests/stress/poly-call-exit.js: Added. + +2014-08-22 Michael Saboff <msaboff@apple.com> + + After r172867 another crash in in js/dom/line-column-numbers.html + https://bugs.webkit.org/show_bug.cgi?id=136192 + + Reviewed by Geoffrey Garen. + + In lookupExceptionHandlerFromCallerFrame(), We need to use the caller's CallFrame + and VMEntryFrame when calling genericUnwind(). NativeCallFrameTracerWithRestore() + does that for us. + + In general, NativeCallFrameTracerWithRestore(), restores the values because we may + do more processing that requires the current callFrame and vmEntryFrame before we + get to the catch handler where we change these to the catch values. In this + particular case, that restoration isn't currently needed, but we add complexity + and possible future confusion if we create another NativeCallFrameTracerXXX() + version that doesn't restore the values. + + * jit/JITOperations.cpp: + (JSC::lookupExceptionHandlerFromCallerFrame): Changed NativeCallFrameTracer() to + NativeCallFrameTracerWithRestore() so that VM::topVMEntryFrame will be updated + before calling genericUnwind(). + +2014-08-24 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: rename Inspector::TypeBuilder to Inspector::Protocol + https://bugs.webkit.org/show_bug.cgi?id=136031 + + Reviewed by Timothy Hatcher. + + Rename TypeBuilder namespace to Protocol. Disambiguate where + necessary. Also rename InspectorTypeBuilder to ProtocolTypes. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/ConsoleMessage.cpp: + (Inspector::messageSourceValue): + (Inspector::messageTypeValue): + (Inspector::messageLevelValue): + (Inspector::ConsoleMessage::addToFrontend): + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::buildObjectForSearchMatch): + (Inspector::ContentSearchUtilities::searchInTextByLines): + * inspector/ContentSearchUtilities.h: + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::evaluate): + (Inspector::InjectedScript::callFunctionOn): + (Inspector::InjectedScript::evaluateOnCallFrame): + (Inspector::InjectedScript::getFunctionDetails): + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getInternalProperties): + (Inspector::InjectedScript::wrapCallFrames): + (Inspector::InjectedScript::wrapObject): + (Inspector::InjectedScript::wrapTable): + * inspector/InjectedScript.h: + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::makeEvalCall): + * inspector/InjectedScriptBase.h: + * inspector/InspectorTypeBuilder.h: Removed. + * inspector/ScriptCallFrame.cpp: + (Inspector::ScriptCallFrame::buildInspectorObject): + * inspector/ScriptCallFrame.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::buildInspectorArray): + * inspector/ScriptCallStack.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::inspect): + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::breakpointActionTypeForString): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::resolveBreakpoint): + (Inspector::InspectorDebuggerAgent::searchInContent): + (Inspector::InspectorDebuggerAgent::getFunctionDetails): + (Inspector::InspectorDebuggerAgent::evaluateOnCallFrame): + (Inspector::InspectorDebuggerAgent::currentCallFrames): + (Inspector::InspectorDebuggerAgent::didParseSource): + (Inspector::InspectorDebuggerAgent::breakpointActionProbe): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorProfilerAgent.cpp: + (Inspector::InspectorProfilerAgent::createProfileHeader): + (Inspector::InspectorProfilerAgent::getProfileHeaders): + (Inspector::buildInspectorObject): + (Inspector::InspectorProfilerAgent::buildProfileInspectorObject): + (Inspector::InspectorProfilerAgent::getCPUProfile): + * inspector/agents/InspectorProfilerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::buildErrorRangeObject): + (Inspector::InspectorRuntimeAgent::parse): + (Inspector::InspectorRuntimeAgent::evaluate): + (Inspector::InspectorRuntimeAgent::callFunctionOn): + (Inspector::InspectorRuntimeAgent::getProperties): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/scripts/codegen/__init__.py: + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: + (BackendDispatcherImplementationGenerator._generate_async_dispatcher_class_for_domain): + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/codegen/generate_frontend_dispatcher_header.py: + (FrontendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_frontend_dispatcher_implementation.py: + (FrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + * inspector/scripts/codegen/generate_type_builder_header.py: Removed. + * inspector/scripts/codegen/generate_type_builder_implementation.py: Removed. + * inspector/scripts/codegen/generator.py: + (Generator.protocol_type_string_for_type): + (Generator.protocol_type_string_for_type_member): + (Generator.type_string_for_type_with_name): + (Generator.type_string_for_formal_out_parameter): + (Generator.type_string_for_formal_async_parameter): + (Generator.type_string_for_stack_in_parameter): + (Generator.type_string_for_stack_out_parameter): + (Generator.assertion_method_for_type_member.assertion_method_for_type): + (Generator.assertion_method_for_type_member): + (Generator.type_builder_string_for_type): Deleted. + (Generator.type_builder_string_for_type_member): Deleted. + * inspector/scripts/codegen/generator_templates.py: + (Inspector): + * inspector/scripts/generate-inspector-protocol-bindings.py: + (generate_from_specification): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * runtime/HighFidelityTypeProfiler.cpp: + (JSC::HighFidelityTypeProfiler::getTypesForVariableAtOffsetForInspector): + * runtime/HighFidelityTypeProfiler.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::allPrimitiveTypeNames): + (JSC::TypeSet::allStructureRepresentations): + (JSC::StructureShape::inspectorRepresentation): + * runtime/TypeSet.h: + +2014-08-24 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: Rename DOM.RGBA and remove workarounds in the bindings generator + https://bugs.webkit.org/show_bug.cgi?id=136025 + + Reviewed by Joseph Pecoraro. + + This workaround can be removed since it is no longer necessary. + + * inspector/scripts/codegen/models.py: + (TypeReference.__init__): + (Type.raw_name): + (TypeDeclaration.__init__): + * inspector/scripts/tests/type-declaration-object-type.json: Remove related test input. + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: Rebaseline. + +2014-08-23 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Do not copy large module source strings + https://bugs.webkit.org/show_bug.cgi?id=136191 + + Reviewed by Benjamin Poulain. + + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::injectedScriptSource): + +2014-08-21 Michael Saboff <msaboff@apple.com> + + REGRESSION(r163179): Sporadic crash in js/dom/line-column-numbers.html test + https://bugs.webkit.org/show_bug.cgi?id=136111 + + Reviewed by Filip Pizlo. + + The problem was that we weren't properly handling VM::topVMEntryFrame in two ways. + + First in the case where we get an exception of a stack overflow during setup of the direct + callee frame of a VM entry frame, we need to throw the exception in the caller's frame. + This requires unrolling topVMEntryFrame while creating the exception object. This is + accomplished with the renamed NativeCallFrameTracerWithRestore object. As part of this, + split the JIT rollback exception handling to call a new helper, + callLookupExceptionHandlerFromCallerFrame, which will unroll the callFrame and VMEntryFrame. + + Second, when we unwind to find a handler, we also need to unwind topVMCallFrame for the + case where we end up (re)throwing another exception after entering the catch block, but + before another vmEntry call. Added VM::vmEntryFrameForThrow as a way similar to + VM::callFrameForThrow to pass the appropriate VMENtryFrame to the catch block. + + + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compileExceptionHandlers): + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + * jit/JIT.cpp: + (JSC::JIT::privateCompileExceptionHandlers): + Split out the unroll cases to use the new helper callLookupExceptionHandlerFromCallerFrame() + to unwind both the callFrame and topVMEntryFrame. + + * interpreter/Interpreter.cpp: + (JSC::UnwindFunctor::UnwindFunctor): + (JSC::UnwindFunctor::operator()): + (JSC::Interpreter::unwind): + * jit/JITExceptions.cpp: + (JSC::genericUnwind): + Added VMEntryFrame as another component to unwind. + + * interpreter/Interpreter.h: + (JSC::NativeCallFrameTracer::NativeCallFrameTracer): + (JSC::NativeCallFrameTracerWithRestore::NativeCallFrameTracerWithRestore): + (JSC::NativeCallFrameTracerWithRestore::~NativeCallFrameTracerWithRestore): + Renamed and changed to save and restore topCallFrame and topVMEntryFrame around the setting of + both values. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::gotoNextFrame): + (JSC::StackVisitor::readNonInlinedFrame): + * interpreter/StackVisitor.h: + (JSC::StackVisitor::Frame::vmEntryFrame): + Added code to unwind the VMEntryFrame. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::jumpToExceptionHandler): Updated comment to indicate that the value + the handler should use for VM::topEntryFrame is in VM::vmEntryFrameForThrow. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_catch): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_catch): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Added code to update VM::topVMEntryFrame from VM::vmEntryFrameForThrowOffset. + + * jit/JITOperations.cpp: + * jit/JITOperations.h: + (JSC::operationThrowStackOverflowError): + (JSC::operationCallArityCheck): + (JSC::operationConstructArityCheck): + + * runtime/VM.h: + (JSC::VM::vmEntryFrameForThrowOffset): + (JSC::VM::topVMEntryFrameOffset): + Added as the side channel to return the topVMEntryFrame that the handler should use. + +2014-08-22 Daniel Bates <dabates@apple.com> + + [iOS] Disable ENABLE_IOS_{GESTURE, TOUCH}_EVENTS, and temporarily disable ENABLE_TOUCH_EVENTS + and ENABLE_XSLT when building with the iOS public SDK + https://bugs.webkit.org/show_bug.cgi?id=135945 + + Reviewed by Andy Estes. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-22 Jon Lee <jonlee@apple.com> + + Fix iOS build due to r172832 and move RUBBER_BANDING out of FeatureDefines.h + https://bugs.webkit.org/show_bug.cgi?id=136157 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: Add ENABLE(RUBBER_BANDING). + +2014-08-21 Mark Lam <mark.lam@apple.com> + + r171362 accidentally increased the size of InlineCallFrame. + <https://webkit.org/b/136141> + + Reviewed by Filip Pizlo. + + r171362 increased the size of InlineCallFrame::kind to 2 bits. This increased + the size of InlineCallFrame from 72 to 80 though not intentionally. The fix + is to reduce the size of InlineCallFrame::stackOffset to 29 bits. + + Also added an assert to ensure that we never set a value that exceeds the size + of InlineCallFrame::stackOffset. + + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::setStackOffset): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + +2014-08-21 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: RetainPtr misuse, CFRunLoopSource leak + https://bugs.webkit.org/show_bug.cgi?id=136143 + + Reviewed by Timothy Hatcher. + + Adopt a Create into the RetainPtr to avoid leaking. + + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setupRunLoop): + +2014-08-21 Mark Lam <mark.lam@apple.com> + + REGRESSION(r172808): It made 6 different tests fail on 32 bit platforms. + <https://webkit.org/b/136123> + + Reviewed by Filip Pizlo. + + The original patch in r172808 removed the code to skip the top scope in + the 64-bit port of JIT::emitResolveClosure() but not in the 32-bit port. + This patch fixes that and achieves parity. + + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitResolveClosure): + +2014-08-21 Zalan Bujtas <zalan@apple.com> + + Enable SATURATED_LAYOUT_ARITHMETIC. + https://bugs.webkit.org/show_bug.cgi?id=136106 + + Reviewed by Simon Fraser. + + SATURATED_LAYOUT_ARITHMETIC protects LayoutUnit against arithmetic overflow. + (No measurable performance regression on Mac.) + + * Configurations/FeatureDefines.xcconfig: + +2014-08-20 Saam Barati <sbarati@apple.com> + + Fix how CodeBlock dumps the opcode op_profile_type + https://bugs.webkit.org/show_bug.cgi?id=136088 + + Reviewed by Filip Pizlo. + + op_profile_type was modified to receive two extra arguments, + but its dump in CodeBlock::dumpBytecode wasn't changed to + account for this, so it broke CodeBlock::dumpBytecode when + op_profile_type was in the stream of bytecode instructions. + CodeBlock::dumpBytecode now accounts for the change in + op_profile_type's arity. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + +2014-08-20 Saam Barati <sbarati@apple.com> + + Rename HighFidelityTypeProfiling variables for more clarity + https://bugs.webkit.org/show_bug.cgi?id=135899 + + Reviewed by Geoffrey Garen. + + Many names that are used in the type profiling infrastructure + prefix themselves with "HighFidelity" or include the words "high" + and/or "fidelity" in some way. But the words "high" and "fidelity" don't + add anything descriptive to the names surrounding type profiling. + So this patch removes all uses of "HighFidelity" and its variants. + + Most renamings change "HighFidelity*" to "TypeProfiler*" or simply + drop the prefix "HighFidelity" all together. Now, almost all names + in relation to type profiling contain in them "TypeProfiler" or + "TypeProfiling" or some combination of the words "type" and "profile". + + This patch also changes how we check if type profiling is enabled: + We no longer call vm::isProfilingTypesWithHighFidelity. We now just + check that vm::typeProfiler is not null. + + This patch also changes all calls to TypeProfilerLog::processLogEntries + to use ASCIILiteral to form WTFStrings instead of vanilla C string literals. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecode/TypeLocation.h: + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + (JSC::UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset): + (JSC::UnlinkedCodeBlock::addTypeProfilerExpressionInfo): + (JSC::UnlinkedCodeBlock::highFidelityTypeProfileExpressionInfoForBytecodeOffset): Deleted. + (JSC::UnlinkedCodeBlock::addHighFidelityTypeProfileExpressionInfo): Deleted. + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::typeProfilingStartOffset): + (JSC::UnlinkedFunctionExecutable::typeProfilingEndOffset): + (JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingStartOffset): Deleted. + (JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingEndOffset): Deleted. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitTypeProfilerExpressionInfo): + (JSC::BytecodeGenerator::emitProfileType): + (JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo): Deleted. + (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): Deleted. + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ThisNode::emitBytecode): + (JSC::ResolveNode::emitBytecode): + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::FunctionCallValueNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::FunctionCallBracketNode::emitBytecode): + (JSC::FunctionCallDotNode::emitBytecode): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::PostfixNode::emitBracket): + (JSC::PostfixNode::emitDot): + (JSC::PrefixNode::emitResolve): + (JSC::PrefixNode::emitBracket): + (JSC::PrefixNode::emitDot): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::AssignDotNode::emitBytecode): + (JSC::ReadModifyDotNode::emitBytecode): + (JSC::AssignBracketNode::emitBytecode): + (JSC::ReadModifyBracketNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::EmptyVarExpression::emitBytecode): + (JSC::ReturnNode::emitBytecode): + (JSC::FunctionBodyNode::emitBytecode): + * heap/Heap.cpp: + (JSC::Heap::collect): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::recompileAllJSFunctionsForTypeProfiling): + (Inspector::InspectorRuntimeAgent::willDestroyFrontendAndBackend): + (Inspector::InspectorRuntimeAgent::enableTypeProfiler): + (Inspector::InspectorRuntimeAgent::disableTypeProfiler): + (Inspector::InspectorRuntimeAgent::setTypeProfilerEnabledState): + (Inspector::InspectorRuntimeAgent::enableHighFidelityTypeProfiling): Deleted. + (Inspector::InspectorRuntimeAgent::disableHighFidelityTypeProfiling): Deleted. + (Inspector::InspectorRuntimeAgent::setHighFidelityTypeProfilingEnabledState): Deleted. + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_profile_type): + (JSC::JIT::emit_op_profile_types_with_high_fidelity): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_type): + (JSC::JIT::emit_op_profile_types_with_high_fidelity): Deleted. + * jit/JITOperations.cpp: + * jsc.cpp: + (functionDumpTypesForAllVariables): + * llint/LLIntSlowPaths.cpp: + * llint/LowLevelInterpreter.asm: + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/Executable.cpp: + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::ProgramExecutable::ProgramExecutable): + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::ProgramExecutable::initializeGlobalProperties): + * runtime/Executable.h: + (JSC::ScriptExecutable::typeProfilingStartOffset): + (JSC::ScriptExecutable::typeProfilingEndOffset): + (JSC::ScriptExecutable::highFidelityTypeProfilingStartOffset): Deleted. + (JSC::ScriptExecutable::highFidelityTypeProfilingEndOffset): Deleted. + * runtime/HighFidelityLog.cpp: Removed. + * runtime/HighFidelityLog.h: Removed. + * runtime/HighFidelityTypeProfiler.cpp: Removed. + * runtime/HighFidelityTypeProfiler.h: Removed. + * runtime/Options.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::prepareForTypeProfiling): + (JSC::SymbolTable::uniqueIDForVariable): + (JSC::SymbolTable::uniqueIDForRegister): + (JSC::SymbolTable::prepareForHighFidelityTypeProfiling): Deleted. + * runtime/SymbolTable.h: + * runtime/TypeProfiler.cpp: Added. + (JSC::TypeProfiler::logTypesForTypeLocation): + (JSC::TypeProfiler::insertNewLocation): + (JSC::TypeProfiler::getTypesForVariableAtOffsetForInspector): + (JSC::descriptorMatchesTypeLocation): + (JSC::TypeProfiler::findLocation): + * runtime/TypeProfiler.h: Added. + (JSC::QueryKey::QueryKey): + (JSC::QueryKey::isHashTableDeletedValue): + (JSC::QueryKey::operator==): + (JSC::QueryKey::hash): + (JSC::QueryKeyHash::hash): + (JSC::QueryKeyHash::equal): + (JSC::TypeProfiler::functionHasExecutedCache): + (JSC::TypeProfiler::typeLocationCache): + * runtime/TypeProfilerLog.cpp: Added. + (JSC::TypeProfilerLog::initializeLog): + (JSC::TypeProfilerLog::~TypeProfilerLog): + (JSC::TypeProfilerLog::processLogEntries): + * runtime/TypeProfilerLog.h: Added. + (JSC::TypeProfilerLog::LogEntry::structureIDOffset): + (JSC::TypeProfilerLog::LogEntry::valueOffset): + (JSC::TypeProfilerLog::LogEntry::locationOffset): + (JSC::TypeProfilerLog::TypeProfilerLog): + (JSC::TypeProfilerLog::recordTypeInformationForLocation): + (JSC::TypeProfilerLog::logEndPtr): + (JSC::TypeProfilerLog::logStartOffset): + (JSC::TypeProfilerLog::currentLogEntryOffset): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::enableTypeProfiler): + (JSC::VM::disableTypeProfiler): + (JSC::VM::dumpTypeProfilerData): + (JSC::VM::enableHighFidelityTypeProfiling): Deleted. + (JSC::VM::disableHighFidelityTypeProfiling): Deleted. + (JSC::VM::dumpHighFidelityProfilingTypes): Deleted. + * runtime/VM.h: + (JSC::VM::typeProfilerLog): + (JSC::VM::typeProfiler): + (JSC::VM::isProfilingTypesWithHighFidelity): Deleted. + (JSC::VM::highFidelityLog): Deleted. + (JSC::VM::highFidelityTypeProfiler): Deleted. + +2014-08-20 Csaba Osztrogonác <ossy@webkit.org> + + URTBF after r172799. + + * disassembler/ARM64/A64DOpcode.cpp: + * disassembler/ARM64Disassembler.cpp: + +2014-08-20 Oliver Hunt <oliver@apple.com> + + Stop implicitly skipping a function's own activation when walking the scope chain + https://bugs.webkit.org/show_bug.cgi?id=136118 + + Reviewed by Geoffrey Garen. + + Remove the current logic that implicitly skips a function's + own activation when walking the scope chain. This is ground + work for ensuring that all closed variable access is made + through the function's activation. This leads to a further + 10% regression on earley, but we're already tracking the + overall performance regression. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getScope): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitResolveClosure): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSScope.cpp: + (JSC::JSScope::abstractResolve): + * runtime/JSScope.h: + +2014-08-20 Michael Saboff <msaboff@apple.com> + + REGRESSION: Web Inspector crashes when reloading apple.com with Timeline recording active + https://bugs.webkit.org/show_bug.cgi?id=136034 + + Reviewed by Mark Lam. + + DebuggerCallFrame::positionForCallFrame is trying to unwind starting somewhere in the middle + of the stack. Hardened StackVisitor to skip over the frames between the current top frame + and the requested start frame. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::StackVisitor): + +2014-08-20 Brent Fulgham <bfulgham@apple.com> + + [Win] JavaScriptCore.dll is missing version information. + https://bugs.webkit.org/show_bug.cgi?id=136105 + <rdar://problem/18075852> + + Reviewed by Dean Jackson. + + * JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd: Add missing step to generate + version information for intermediary build path. + +2014-08-20 Saam Barati <sbarati@apple.com> + + Fix a memory leak in TypeSet + https://bugs.webkit.org/show_bug.cgi?id=135913 + + Reviewed by Filip Pizlo. + + Currently, TypeSet unconditionally allocates memory for its member + variable m_structureHistory, but never deallocates it. Change this + from being a pointer that is unconditionally allocated to a member + variable that will be deallocated when TypeSet itself is deallocated. + + * runtime/TypeSet.cpp: + (JSC::TypeSet::TypeSet): + (JSC::TypeSet::addTypeInformation): + (JSC::TypeSet::seenTypes): + (JSC::TypeSet::displayName): + (JSC::TypeSet::allStructureRepresentations): + (JSC::StructureShape::leastCommonAncestor): + * runtime/TypeSet.h: + +2014-08-20 peavo@outlook.com <peavo@outlook.com> + + [Win] Assertion fails when running JSC stress tests. + https://bugs.webkit.org/show_bug.cgi?id=136103 + + Reviewed by Darin Adler. + + Use unsigned bitfield member instead of enum bitfield member to avoid negative values. + + * bytecode/CodeOrigin.h: Use unsigned bitfield member. + (JSC::InlineCallFrame::specializationKind): Compile fix. + +2014-08-20 Akos Kiss <akiss@inf.u-szeged.hu> + + Enable ARM64 disassembler on EFL + https://bugs.webkit.org/show_bug.cgi?id=136089 + + Reviewed by Filip Pizlo. + + * CMakeLists.txt: + Added disassembler/ARM64Disassembler.cpp and + disassembler/ARM64/A64DOpcode.cpp to JavaScriptCore_SOURCES. + + * disassembler/ARM64/A64DOpcode.cpp: + Added USE(ARM64_DISASSEMBLER) guard around implementation. + + * disassembler/ARM64/A64DOpcode.h: + (JSC::ARM64Disassembler::A64DOpcode::appendUnsignedImmediate64): + (JSC::ARM64Disassembler::A64DOpcode::appendPCRelativeOffset): + Made format strings portable by changing "%llx" to "%" PRIx64 for + uint64_t arguments. + +2014-08-19 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(r172401): for-in optimization no longer works at all + https://bugs.webkit.org/show_bug.cgi?id=136056 + + Reviewed by Geoffrey Garen. + + Roll this back in, along with a fix to make proxies work. Previously, for-in over proxies + would instacrash every time. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::pushIndexedForInScope): + (JSC::BytecodeGenerator::pushStructureForInScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::ForInContext::ForInContext): + (JSC::StructureForInContext::StructureForInContext): + (JSC::IndexedForInContext::IndexedForInContext): + (JSC::ForInContext::base): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitMultiLoopBytecode): + * runtime/JSProxy.cpp: + (JSC::JSProxy::getStructurePropertyNames): + (JSC::JSProxy::getGenericPropertyNames): + * tests/stress/for-in-base-reassigned-later-and-change-structure.js: Added. + (foo): + * tests/stress/for-in-base-reassigned-later.js: Added. + (foo): + * tests/stress/for-in-base-reassigned.js: Added. + (foo): + * tests/stress/for-in-proxy-target-changed-structure.js: Added. + (deleteAll): + (foo): + * tests/stress/for-in-proxy.js: Added. + (foo): + +2014-08-19 Jaehun Lim <ljaehun.lim@samsung.com> + + Unreviewed, fix EFL build after r17275 + + Fix error: ignoring #pragma clang diagnostic [-Werror=unknown-pragmas] + + * runtime/JSDataViewPrototype.cpp: + Add #if COMPILER(CLANG) and #endif. + +2014-08-19 Michael Saboff <msaboff@apple.com> + + Crash in jsc-layout-tests.yaml/js/script-tests/reentrant-caching.js + https://bugs.webkit.org/show_bug.cgi?id=136080 + + Reviewed by Mark Lam. + + Update VM::topVMEntryFrame via NativeCallFrameTracer() when we pass the caller's frame + to NativeCallFrameTracer() as the callee's frame may be the first callee from an entry + frame. In that case, the caller will have the prior VM entry frame. + + The new NativeCallFrameTracer with a VMEntryFrame parameter should be used when throwing + an exception from a caller frame. The value to use for the VMEntryFrame should be a + value possibly modified by CallFrame::callerFrame(&*VMEntryFrame) used to find the caller. + + * interpreter/Interpreter.h: + (JSC::NativeCallFrameTracer::NativeCallFrameTracer): Added a new constructor that takes a + VMEntryFrame. Added an ASSERT to both constructors to check that the updated topCallFrame + is below the current vmEntryFrame. + + * jit/JITOperations.cpp: + (JSC::operationThrowStackOverflowError): + (JSC::operationCallArityCheck): + (JSC::operationConstructArityCheck): + Set VM::topVMEntryFrame to the possibly updated VMEntryFrame after getting the caller's frame. + +2014-08-19 Andy Estes <aestes@apple.com> + + [Cocoa] Offline Assembler build phase fails when $BUILT_PRODUCTS_DIR contains spaces + https://bugs.webkit.org/show_bug.cgi?id=136086 + + Reviewed by Filip Pizlo. + + Enclosed arguments to asm.rb containing $BUILT_PRODUCTS_DIR in double quotes so that they don't get split on + whitespace. Also let Xcode have its way with an unrelated part of the project file. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-08-19 Filip Pizlo <fpizlo@apple.com> + + LLInt build should be way faster + https://bugs.webkit.org/show_bug.cgi?id=136085 + + Reviewed by Geoffrey Garen. + + This does three things to improve the LLInt build performance. One of them is only for + Xcode for now while the others should benefit all platforms: + + - Don't exponentially build settings combinations that correspond to being on two backends + simultaneously. This is by far the biggest win. + + - Don't generate offset extraction code for backends that aren't supported by the current + port. This currently only works on Xcode-based ports. This is a relatively small win. + + - Remove the ALWAYS_ALLOCATE_SLOW option. Each option increases build time, and we haven't + used this one in a long time. Anyway, setting this option could be emulated by just + directly hacking the code. + + This is an enormous speed-up in the LLInt build. + + * JavaScriptCore.xcodeproj/project.pbxproj: Prune the set of backends that we should consider on Xcode-based platforms. + * llint/LLIntOfflineAsmConfig.h: Remove ALWAYS_ALLOCATE_SLOW + * llint/LowLevelInterpreter.asm: Remove ALWAYS_ALLOCATE_SLOW + * offlineasm/backends.rb: Add infrastructure for reasoning about valid backends. + * offlineasm/generate_offset_extractor.rb: Allow the client to specify a filtered set of valid backends. + * offlineasm/settings.rb: Improve the construction of settings combinations so that it doesn't traverse the enourmous set of obviously invalid multi-backend combinations. Also glue into support for valid backends. + +2014-08-19 Filip Pizlo <fpizlo@apple.com> + + Fix indentation and style in LowLevelInterpreter.asm + https://bugs.webkit.org/show_bug.cgi?id=136083 + + Reviewed by Mark Lam. + + * llint/LowLevelInterpreter.asm: + +2014-08-19 Magnus Granberg <zorry@gentoo.org> + + TEXTREL in libjavascriptcoregtk-1.0.so.0.11.0 on x86 (or i586) + https://bugs.webkit.org/show_bug.cgi?id=70610 + + Reviewed by Darin Adler. + + Setup %ebx so we can use the plt. + + * jit/ThunkGenerators.cpp: + +2014-08-19 Zalan Bujtas <zalan@apple.com> + + Remove ENABLE(SUBPIXEL_LAYOUT). + https://bugs.webkit.org/show_bug.cgi?id=136077 + + Reviewed by Simon Fraser. + + Remove compile time flag SUBPIXEL_LAYOUT. All ports have it enabled for a while now. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-19 Alex Christensen <achristensen@webkit.org> + + [CMake] Generate LLInt assembly correctly on Windows. + https://bugs.webkit.org/show_bug.cgi?id=135888 + + Reviewed by Oliver Hunt. + + * CMakeLists.txt: + Generate LowLevelInterpreterWin.asm instead of LLIntAssembly.h on Windows like the existing build system. + * PlatformWin.cmake: + Don't build JSGlobalObjectInspectorController.cpp on Windows. + * offlineasm/x86.rb: + Detect non-cygwin ruby installations correctly. + +2014-08-19 Michael Saboff <msaboff@apple.com> + + REGRESSION(r163179): It broke the build on ARM Thumb2 with GCC + https://bugs.webkit.org/show_bug.cgi?id=136028 + + Reviewed by Oliver Hunt. + + Added back ARMv7 conditionals around three op addp and subp since ARM Thumb2 spec says that + the behavior for those ops are undefined. This was originally done in changeset 163179. + + * llint/LowLevelInterpreter32_64.asm: + +2014-08-18 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r172741. + https://bugs.webkit.org/show_bug.cgi?id=136058 + + This change is breaking PLT. (Requested by mlam on #webkit). + + Reverted changeset: + + "REGRESSION(r172401): for-in optimization no longer works at + all" + https://bugs.webkit.org/show_bug.cgi?id=136056 + http://trac.webkit.org/changeset/172741 + +2014-08-18 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(r172401): for-in optimization no longer works at all + https://bugs.webkit.org/show_bug.cgi?id=136056 + + Reviewed by Mark Hahnenberg. + + This is a partial roll-out of r172401. It turns out that the fix wasn't actually fixing a + real bug (since it's fine to use op_get_direct_pname on the wrong base because it has a + structure check) and it was actually breaking the entire for-in optimization (since there is + no way that we can statically prove that the base matches, because the base we see is a + newly created temporary, and anyway doing it right would be really hard in our bytecode + because it's 3AC form). + + But, I added a new test for the problem, and kept the original test. Both the old test and + the new test prove that r172401 wasn't fixing what it thought it was fixing. To the extent + that it resolved crashes it was because it just disabled the for-in optimization entirely. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::pushIndexedForInScope): + (JSC::BytecodeGenerator::pushStructureForInScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::ForInContext::ForInContext): + (JSC::StructureForInContext::StructureForInContext): + (JSC::IndexedForInContext::IndexedForInContext): + (JSC::ForInContext::base): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitMultiLoopBytecode): + * tests/stress/for-in-base-reassigned.js: Added. + * tests/stress/for-in-base-reassigned-later.js: Added. + * tests/stress/for-in-base-reassigned-later-and-change-structure.js: Added. + +2014-08-18 Mark Lam <mark.lam@apple.com> + + Gardening: build fix for non-Mac builds after r172737. + https://bugs.webkit.org/show_bug.cgi?id=135750 + + Not reviewed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-08-18 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(r172129): ftlopt branch merge made performance tests flakey crash + https://bugs.webkit.org/show_bug.cgi?id=135750 + + Reviewed by Mark Lam. + + This was caused by a rather embarrassing oversight in how the DFG tracks structures: we + could sometimes perform an optimization that requires a structure to be alive but forget to + ensure that the structure is actually kept alive. In particular, any watchpoint-based + optimizations involve setting watchpoints even if the code that got optimized is eventually + deleted because it is unreachable. All such optimizations would leave behind something in + the IR to tell us that we are interested in the structure and that therefore it should be + kept alive. But, IR can be deleted if it is unreachable. + + The solution is to ensure that as soon as the DFG is made aware of a structure, it adds it + to the set of weak references. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::setOSREntryValue): + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::normalizeClarity): + (JSC::DFG::AbstractValue::assertIsRegistered): + (JSC::DFG::AbstractValue::assertIsWatched): Deleted. + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::assertIsRegistered): + (JSC::DFG::AbstractValue::assertIsWatched): Deleted. + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck): + * dfg/DFGDesiredWeakReferences.cpp: + (JSC::DFG::DesiredWeakReferences::addLazily): + (JSC::DFG::DesiredWeakReferences::contains): + (JSC::DFG::DesiredWeakReferences::reallyAdd): + (JSC::DFG::DesiredWeakReferences::visitChildren): + * dfg/DFGDesiredWeakReferences.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + (JSC::DFG::Graph::registerFrozenValues): + (JSC::DFG::Graph::convertToConstant): + (JSC::DFG::Graph::registerStructure): + (JSC::DFG::Graph::assertIsRegistered): + (JSC::DFG::Graph::assertIsWatched): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGStructureAbstractValue.cpp: + (JSC::DFG::StructureAbstractValue::assertIsRegistered): + (JSC::DFG::StructureAbstractValue::assertIsWatched): Deleted. + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::assertIsRegistered): + (JSC::DFG::StructureAbstractValue::assertIsWatched): Deleted. + * dfg/DFGStructureRegistrationPhase.cpp: Copied from Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp. + (JSC::DFG::StructureRegistrationPhase::StructureRegistrationPhase): + (JSC::DFG::StructureRegistrationPhase::run): + (JSC::DFG::StructureRegistrationPhase::registerStructures): + (JSC::DFG::StructureRegistrationPhase::registerStructure): + (JSC::DFG::performStructureRegistration): + (JSC::DFG::WatchableStructureWatchingPhase::WatchableStructureWatchingPhase): Deleted. + (JSC::DFG::WatchableStructureWatchingPhase::run): Deleted. + (JSC::DFG::WatchableStructureWatchingPhase::tryWatch): Deleted. + (JSC::DFG::performWatchableStructureWatching): Deleted. + * dfg/DFGStructureRegistrationPhase.h: Copied from Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.h. + * dfg/DFGWatchableStructureWatchingPhase.cpp: Removed. + * dfg/DFGWatchableStructureWatchingPhase.h: Removed. + +2014-08-18 Akos Kiss <akiss@inf.u-szeged.hu> + + Fix ASSERT in ARM64's JSC::GPRInfo::debugName + https://bugs.webkit.org/show_bug.cgi?id=136050 + + Reviewed by Darin Adler. + + Remove cast of GPRReg to unsigned to prevent signed/unsigned comparison + error. + + * jit/GPRInfo.h: + (JSC::GPRInfo::debugName): + +2014-08-18 Andreas Kling <akling@apple.com> + + REGRESSION(r168256): JSString can get 8-bit flag wrong when re-using AtomicStrings. + <https://webkit.org/b/133574> + <rdar://problem/18051847> + + The optimization that resolves JSRopeStrings into an existing + AtomicString (to save time and memory by avoiding StringImpl allocation) + had a bug that it wasn't copying the 8-bit flag from the AtomicString. + + This could lead to a situation where a 16-bit StringImpl containing + only 8-bit characters is sitting in the AtomicString table, is found + by the rope resolution optimization, and gives you a rope that thinks + it's all 8-bit, but has a fiber with 16-bit characters. + + Resolving that rope will then yield incorrect results. + + This was all caught by an assertion, but very hard to reproduce. + + Test: js/dopey-rope-with-16-bit-propertyname.html + + Reviewed by Darin Adler. + + * runtime/JSString.cpp: + (JSC::JSRopeString::resolveRopeToAtomicString): + (JSC::JSRopeString::resolveRopeToExistingAtomicString): + * runtime/JSString.h: + (JSC::JSString::setIs8Bit): + (JSC::JSString::toExistingAtomicString): + +2014-08-18 Matthew Mirman <mmirman@apple.com> + + Merges the two native inlining passes from the build. + Also adds the AvailableExternallyLinkage assertion to linked + functions to allow unused and duplicate ones to be removed. + https://bugs.webkit.org/show_bug.cgi?id=135526 + + Reviewed by Filip Pizlo. + + * JavaScriptCore.xcodeproj/project.pbxproj: + Removed second generation of llvm binary files. + Fixed the flags on the first pass. + * build-symbol-table-index.py: Modified some paths. + * build-symbol-table-index.sh: Removed. + * copy-llvm-ir-to-derived-sources.sh: Now calls build-symbol-table-index directly. + * ftl/FTLLowerDFGToLLVM.cpp: Added LLVMAvailableExternallyLinkage assertion. + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): + * runtime/ArrayPrototype.cpp: Removed static declarations. + * runtime/DateConstructor.cpp: ditto. + (JSC::dateParse): + (JSC::dateNow): + (JSC::dateUTC): + * runtime/DatePrototype.cpp: ditto. + * runtime/JSDataViewPrototype.cpp: ditto on both. + (JSC::dataViewProtoFuncGetInt8): + (JSC::dataViewProtoFuncGetInt16): + (JSC::dataViewProtoFuncGetInt32): + (JSC::dataViewProtoFuncGetUint8): + (JSC::dataViewProtoFuncGetUint16): + (JSC::dataViewProtoFuncGetUint32): + (JSC::dataViewProtoFuncGetFloat32): + (JSC::dataViewProtoFuncGetFloat64): + (JSC::dataViewProtoFuncSetInt8): + (JSC::dataViewProtoFuncSetInt16): + (JSC::dataViewProtoFuncSetInt32): + (JSC::dataViewProtoFuncSetUint8): + (JSC::dataViewProtoFuncSetUint16): + (JSC::dataViewProtoFuncSetUint32): + (JSC::dataViewProtoFuncSetFloat32): + (JSC::dataViewProtoFuncSetFloat64): + * runtime/JSONObject.cpp: ditto. + * runtime/ObjectConstructor.cpp: ditto. + * runtime/StringPrototype.cpp: ditto. + +2014-08-18 Saam Barati <sbarati@apple.com> + + The parser should generate AST nodes the var declarations with no initializers + https://bugs.webkit.org/show_bug.cgi?id=135545 + + Reviewed by Geoffrey Garen. + + Currently, JSC's parser ignores variable declarations + that have no assignment initializer value because all + variables are implicitly assigned to undefined. But, + type profiling needs an AST node to be generated for these + empty variable declarations because it needs to be able to + profile their text locations and to see that their type + is undefined. + + * bytecompiler/NodesCodegen.cpp: + (JSC::EmptyVarExpression::emitBytecode): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createVarStatement): + (JSC::ASTBuilder::createEmptyVarExpression): + * parser/NodeConstructors.h: + (JSC::EmptyVarExpression::EmptyVarExpression): + * parser/Nodes.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclarationList): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createEmptyVarExpression): + +2014-08-18 Diego Pino Garcia <dpino@igalia.com> + + Completed iterator can be revived by adding more than one new entry to the target object + https://bugs.webkit.org/show_bug.cgi?id=129993 + + Reviewed by Oliver Hunt. + + When iterator reaches end, finish iterator. + + * runtime/JSMapIterator.h: + (JSC::JSMapIterator::finish): + * runtime/JSSetIterator.h: + (JSC::JSSetIterator::finish): + * runtime/MapData.h: + (JSC::MapData::const_iterator::finish): set index of iterator to max + Int32. + * runtime/MapIteratorPrototype.cpp: + (JSC::MapIteratorPrototypeFuncNext): + * runtime/SetIteratorPrototype.cpp: + (JSC::SetIteratorPrototypeFuncNext): + +2014-08-15 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: rewrite CodeGeneratorInspector to be modular and testable + https://bugs.webkit.org/show_bug.cgi?id=131596 + + Unreviewed gardening to rebaseline inspector generator tests after addressing review comments. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + +2014-08-15 Brian J. Burg <burg@cs.washington.edu> + + Unreviewed build fix for some GTK bots after r172655. + + Some bots use Python 2.6, which lacks the 'flags' named parameter for re.sub. + + * inspector/scripts/codegen/generator.py: + (Generator.stylized_name_for_enum_value): Do things the old-school way. + +2014-08-15 Michael Saboff <msaboff@apple.com> + + Change callToJavaScript and callToNativeFunction so their callFrames match the native calling conventions + https://bugs.webkit.org/show_bug.cgi?id=131578 + + Reviewed by Geoffrey Garen. + + Renamed callToJavaScript and callToNativeFunction to vmEntryToJavaScript and vmEntryToNative, + respectively. Eliminated the sentinel frame and replaced it with the structure VMEntryRecord + that appears in the "locals" area of a VM entry stack frame. Changed the order that + vmEntryToJavaScript and vmEntryToNative creates their stack frames to be native calling + convention compliant. That is to save prior frame pointer, save callee save registers, then + allocate and populate the VMEntryRecord, and finally allocate a CallFrame for the JS function + that vmEntryToJavaScript will invoke. The top most vm entry frame pointer is saved in + VM::topVMEntryFrame. The vmEntry functions save prior contents of VM::topVMEntryFrame + along with the VM and VM::topCallFrame in the VMEntryRecord it places on the stack. Starting + at VM::topCallFrame, the stack can be walked using these VMEntryRecords. + + Arbitrary stack unwinding is now handled either iteratively by loading VM::topVMEntryFrame + into a local variable and using CallFrame::callerFrame(VMEntryFrame*&) or by using StackVisitor. + Given that the stack is effectively a singly linked list, general stack unwinding needs to use + one of these two methods. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + Addition of VMEntryRecord.h + + * bytecode/BytecodeList.json: + Renaming of llint helper opcodes due to renaming callToJavaScript and callToNativeFunction. + + * debugger/Debugger.cpp: + (JSC::Debugger::stepOutOfFunction): + (JSC::Debugger::returnEvent): + (JSC::Debugger::didExecuteProgram): + * jsc.cpp: + (functionDumpCallFrame): + * jit/JITOperations.cpp: + Changed unwinding to use CallFrame::callerFrame(VMEntryFrame*&). + + * bytecode/CodeBlock.cpp: + (JSC::RecursionCheckFunctor::RecursionCheckFunctor): + (JSC::RecursionCheckFunctor::operator()): + (JSC::RecursionCheckFunctor::didRecurse): + (JSC::CodeBlock::noticeIncomingCall): + * debugger/DebuggerCallFrame.cpp: + (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): + (JSC::FindCallerMidStackFunctor::operator()): + (JSC::FindCallerMidStackFunctor::getCallerFrame): + (JSC::DebuggerCallFrame::callerFrame): + * interpreter/VMInspector.cpp: + (JSC::CountFramesFunctor::CountFramesFunctor): + (JSC::CountFramesFunctor::operator()): + (JSC::CountFramesFunctor::count): + (JSC::VMInspector::countFrames): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::index): + (JSC::VM::throwException): + Changed unwinding to use StackVisitor including added functor classes. + + * interpreter/CallFrame.cpp: + (JSC::CallFrame::callerFrame): + Added new flavor of callerFrame() that can iteratively unwind the stack. + + * interpreter/CallFrame.h: + (JSC::ExecState::callerFrame): Changed callerFrame() to use private common helper. + (JSC::ExecState::callerFrameOrVMEntryFrame): Deleted. + (JSC::ExecState::isVMEntrySentinel): Deleted. + (JSC::ExecState::vmEntrySentinelCallerFrame): Deleted. + (JSC::ExecState::initializeVMEntrySentinelFrame): Deleted. + (JSC::ExecState::callerFrameSkippingVMEntrySentinel): Deleted. + (JSC::ExecState::vmEntrySentinelCodeBlock): Deleted. + + * interpreter/CallFrame.h: + (JSC::ExecState::init): + (JSC::ExecState::topOfFrame): + (JSC::ExecState::currentVPC): + (JSC::ExecState::setCurrentVPC): + Eliminated unneded checking of sentinel frame. + + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + (JSC::Interpreter::getStackTrace): Updated for unwidning changes. + (JSC::Interpreter::unwind): Eliminated unneeded sentinel frame check. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + * jit/JITStubs.h: + * llint/LLIntThunks.cpp: + (JSC::callToJavaScript): Deleted. + (JSC::callToNativetion): Deleted. + (JSC::vmEntryToJavaScript): + (JSC::vmEntryToNative): + * llint/LLIntThunks.h: + Updated for vmEntryToJavaScript and vmEntryToNative name changes. + + * interpreter/Interpreter.h: + (JSC::TopCallFrameSetter::TopCallFrameSetter): + (JSC::TopCallFrameSetter::~TopCallFrameSetter): + Eliminated unneeded sentinel frame check. + + * interpreter/Interpreter.h: + (JSC::NativeCallFrameTracer::NativeCallFrameTracer): + Removed sentinel specific constructor. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::StackVisitor): + (JSC::StackVisitor::readFrame): + (JSC::StackVisitor::readNonInlinedFrame): + (JSC::StackVisitor::readInlinedFrame): + (JSC::StackVisitor::Frame::print): + * interpreter/StackVisitor.h: + (JSC::StackVisitor::Frame::callerIsVMEntry): + Changes for unwinding using CallFrame::callerFrame(VMEntryFrame*&). Also added field that + indicates when about to step over a VM entry frame. + + * interpreter/VMEntryRecord.h: Added. + (JSC::VMEntryRecord::prevTopCallFrame): + (JSC::VMEntryRecord::prevTopVMEntryFrame): + New struct to record prior state of VM's notion of VM entry and top call frames. + + * jit/JITCode.cpp: + (JSC::JITCode::execute): + Use new vmEntryToJavaScript and vmEntryToNative name. + + * llint/LLIntOffsetsExtractor.cpp: Added include for VMEntryRecord.h. + + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Offline assembly implementation of creating stack frame with VMEntryRecord and well as restoring + relevent VM fields when exiting the VM. Added a helper that returns a VMEntryRecord given + a pointer to the VM entry frame. + + * llint/LLIntThunks.cpp: + (JSC::vmEntryRecord): + * llint/LowLevelInterpreter.cpp: + (JSC::CLoop::execute): + C Loop changes to mirror the assembly changes. + + * runtime/VM.h: + Added topVMEntryFrame field. + +2014-08-15 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: rewrite CodeGeneratorInspector to be modular and testable + https://bugs.webkit.org/show_bug.cgi?id=131596 + + Reviewed by Joseph Pecoraro. + + Replace CodeGeneratorInspector.py with generate-inspector-protocol-bindings.py. + The new generator decouples parsing and typechecking a model of the protocol from + code generation. Each generated file is created by a different subclass of Generator. + Helper methods to compute various type signatures are shared among generators. + + This patch introduces a test harness and a test suite that covers all functionality. + + Aside from hooking up the new inspector bindings generator to the build system, + there are a few comingled changes that would be painful to split from the main + patch: + + Convert protocol enumeration types from struct-namespaced enums to C++ scoped enums. + + Move all runtimeCast(), assertValueHasExpectedType(), and RuntimeCastHelper methods to static + methods of BindingTraits specializations. + + Together, these changes reduce duplication and make it possible to forward-declare + all protocol enum and object types, reducing weird ordering dependencies between domains. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Add inspector scripts to solution filters. + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/ConsoleMessage.cpp: Convert to scoped enums. + (Inspector::messageSourceValue): + (Inspector::messageTypeValue): + (Inspector::messageLevelValue): + * inspector/InjectedScript.cpp: Convert to scoped enums and BindingTraits. + (Inspector::InjectedScript::getFunctionDetails): + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getInternalProperties): + (Inspector::InjectedScript::wrapCallFrames): + (Inspector::InjectedScript::wrapObject): + (Inspector::InjectedScript::wrapTable): + * inspector/InjectedScriptBase.cpp: Convert InspectorValue::Type to a scoped enum. + (Inspector::InjectedScriptBase::makeEvalCall): + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::injectedScriptForObjectId): + * inspector/InspectorTypeBuilder.h: + (Inspector::TypeBuilder::Array::create): + (Inspector::TypeBuilder::StructItemTraits::pushRefPtr): + (Inspector::TypeBuilder::ArrayItemHelper<String>::Traits::pushRaw): + (Inspector::TypeBuilder::ArrayItemHelper<int>::Traits::pushRaw): + (Inspector::TypeBuilder::ArrayItemHelper<double>::Traits::pushRaw): + (Inspector::TypeBuilder::ArrayItemHelper<bool>::Traits::pushRaw): + (Inspector::TypeBuilder::ArrayItemHelper<InspectorValue>::Traits::pushRefPtr): + (Inspector::TypeBuilder::ArrayItemHelper<InspectorObject>::Traits::pushRefPtr): + (Inspector::TypeBuilder::ArrayItemHelper<InspectorArray>::Traits::pushRefPtr): + (Inspector::TypeBuilder::PrimitiveBindingTraits::assertValueHasExpectedType): + (Inspector::TypeBuilder::BindingTraits<TypeBuilder::Array<T>>::runtimeCast): + (Inspector::TypeBuilder::BindingTraits<TypeBuilder::Array<T>>::assertValueHasExpectedType): + (Inspector::TypeBuilder::BindingTraits<InspectorValue>::assertValueHasExpectedType): + (Inspector::TypeBuilder::BindingTraits<int>::assertValueHasExpectedType): + (Inspector::TypeBuilder::ExactlyInt::ExactlyInt): Deleted. It was not used. + (Inspector::TypeBuilder::ExactlyInt::operator int): Deleted. + (Inspector::TypeBuilder::ExactlyInt::cast_to_int): Deleted. + (Inspector::TypeBuilder::ExactlyInt::cast_to_int<int>): Deleted. + (Inspector::TypeBuilder::int>): Deleted. + (Inspector::TypeBuilder::RuntimeCastHelper::assertType): Deleted. + (Inspector::TypeBuilder::RuntimeCastHelper::assertAny): Deleted. + (Inspector::TypeBuilder::RuntimeCastHelper::assertInt): Deleted. + (Inspector::TypeBuilder::Array::runtimeCast): Deleted. + (Inspector::TypeBuilder::Array::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::StructItemTraits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<String>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<int>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<double>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<bool>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<InspectorValue>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<InspectorObject>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<InspectorArray>::Traits::assertCorrectValue): Deleted. + (Inspector::TypeBuilder::ArrayItemHelper<TypeBuilder::Array<T>>::Traits::assertCorrectValue): Deleted. + + * inspector/InspectorValues.cpp: Convert InspectorValue::Type to a scoped enum. + (Inspector::InspectorValue::writeJSON): + (Inspector::InspectorBasicValue::asBoolean): + (Inspector::InspectorBasicValue::asNumber): + (Inspector::InspectorBasicValue::writeJSON): + (Inspector::InspectorString::writeJSON): + (Inspector::InspectorObjectBase::InspectorObjectBase): + (Inspector::InspectorObjectBase::setArray): Take InspectorArrayBase. + (Inspector::InspectorObjectBase::setObject): Take InspectorObjectBase. + (Inspector::InspectorArrayBase::InspectorArrayBase): + * inspector/InspectorValues.h: + + * inspector/agents/InspectorDebuggerAgent.cpp: Convert to scoped enums. + (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): + (Inspector::InspectorDebuggerAgent::breakProgram): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::parse): + * inspector/agents/InspectorRuntimeAgent.h: + + * inspector/scripts/CodeGeneratorInspector.py: Removed. + * inspector/scripts/codegen/__init__.py: Added. + * inspector/scripts/codegen/generate_backend_commands.py: Added. + (BackendCommandsGenerator): + (BackendCommandsGenerator.__init__): + (BackendCommandsGenerator.model): + (BackendCommandsGenerator.output_filename): + (BackendCommandsGenerator.generate_license): + (BackendCommandsGenerator.generate_output): + (BackendCommandsGenerator.generate_domain): + (BackendCommandsGenerator.generate_domain.is_anonymous_enum_member): + (BackendCommandsGenerator.generate_domain.generate_parameter_object): + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: Added. + (BackendDispatcherHeaderGenerator): + (BackendDispatcherHeaderGenerator.__init__): + (BackendDispatcherHeaderGenerator.model): + (BackendDispatcherHeaderGenerator.output_filename): + (BackendDispatcherHeaderGenerator.generate_license): + (BackendDispatcherHeaderGenerator.generate_output): + (BackendDispatcherHeaderGenerator.generate_output.for): + (BackendDispatcherHeaderGenerator._generate_handler_declarations_for_domain): + (BackendDispatcherHeaderGenerator._generate_anonymous_enum_for_parameter): + (BackendDispatcherHeaderGenerator._generate_handler_declaration_for_command): + (BackendDispatcherHeaderGenerator._generate_async_handler_declaration_for_command): + (BackendDispatcherHeaderGenerator._generate_dispatcher_declarations_for_domain): + (BackendDispatcherHeaderGenerator._generate_dispatcher_declaration_for_command): + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: Added. + (BackendDispatcherImplementationGenerator): + (BackendDispatcherImplementationGenerator.__init__): + (BackendDispatcherImplementationGenerator.model): + (BackendDispatcherImplementationGenerator.output_filename): + (BackendDispatcherImplementationGenerator.generate_license): + (BackendDispatcherImplementationGenerator.generate_output): + (BackendDispatcherImplementationGenerator._generate_handler_class_destructor_for_domain): + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementations_for_domain): + (BackendDispatcherImplementationGenerator._generate_small_dispatcher_switch_implementation_for_domain): + (BackendDispatcherImplementationGenerator._generate_large_dispatcher_switch_implementation_for_domain): + (BackendDispatcherImplementationGenerator._generate_async_dispatcher_class_for_domain): + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/codegen/generate_frontend_dispatcher_header.py: Added. + (FrontendDispatcherHeaderGenerator): + (FrontendDispatcherHeaderGenerator.__init__): + (FrontendDispatcherHeaderGenerator.model): + (FrontendDispatcherHeaderGenerator.output_filename): + (FrontendDispatcherHeaderGenerator.generate_license): + (FrontendDispatcherHeaderGenerator.generate_output): + (FrontendDispatcherHeaderGenerator._generate_anonymous_enum_for_parameter): + (FrontendDispatcherHeaderGenerator._generate_dispatcher_declarations_for_domain): + (FrontendDispatcherHeaderGenerator._generate_dispatcher_declaration_for_event): + * inspector/scripts/codegen/generate_frontend_dispatcher_implementation.py: Added. + (FrontendDispatcherImplementationGenerator): + (FrontendDispatcherImplementationGenerator.__init__): + (FrontendDispatcherImplementationGenerator.model): + (FrontendDispatcherImplementationGenerator.output_filename): + (FrontendDispatcherImplementationGenerator.generate_license): + (FrontendDispatcherImplementationGenerator.generate_output): + (FrontendDispatcherImplementationGenerator._generate_dispatcher_implementations_for_domain): + (FrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + * inspector/scripts/codegen/generate_type_builder_header.py: Added. + (TypeBuilderHeaderGenerator): + (TypeBuilderHeaderGenerator.__init__): + (TypeBuilderHeaderGenerator.model): + (TypeBuilderHeaderGenerator.output_filename): + (TypeBuilderHeaderGenerator.generate_license): + (TypeBuilderHeaderGenerator.generate_output): + (TypeBuilderHeaderGenerator._generate_forward_declarations): + (_generate_typedefs): + (_generate_typedefs_for_domain): + (_generate_builders_for_domain): + (_generate_class_for_object_declaration): + (_generate_struct_for_enum_declaration): + (_generate_struct_for_anonymous_enum_member): + (_generate_struct_for_anonymous_enum_member.apply_indentation): + (_generate_struct_for_enum_type): + (_generate_builder_state_enum): + (_generate_builder_setter_for_member): + (_generate_unchecked_setter_for_member): + (_generate_forward_declarations_for_binding_traits): + * inspector/scripts/codegen/generate_type_builder_implementation.py: Added. + (TypeBuilderImplementationGenerator): + (TypeBuilderImplementationGenerator.__init__): + (TypeBuilderImplementationGenerator.model): + (TypeBuilderImplementationGenerator.output_filename): + (TypeBuilderImplementationGenerator.generate_license): + (TypeBuilderImplementationGenerator.generate_output): + (TypeBuilderImplementationGenerator._generate_enum_mapping): + (TypeBuilderImplementationGenerator._generate_open_field_names): + (TypeBuilderImplementationGenerator._generate_builders_for_domain): + (TypeBuilderImplementationGenerator._generate_runtime_cast_for_object_declaration): + (TypeBuilderImplementationGenerator._generate_assertion_for_object_declaration): + (TypeBuilderImplementationGenerator._generate_assertion_for_enum): + * inspector/scripts/codegen/generator.py: Added. + (ucfirst): + (Generator): + (Generator.__init__): + (Generator.model): + (Generator.generate_license): + (Generator.domains_to_generate): + (Generator.generate_output): + (Generator.output_filename): + (Generator.encoding_for_enum_value): + (Generator.assigned_enum_values): + (Generator.type_needs_runtime_casts): + (Generator.type_has_open_fields): + (Generator.type_needs_shape_assertions): + (Generator.calculate_types_requiring_shape_assertions): + (Generator.calculate_types_requiring_shape_assertions.gather_transitively_referenced_types): + (Generator._traverse_and_assign_enum_values): + (Generator._assign_encoding_for_enum_value): + (Generator.wrap_with_guard_for_domain): + (Generator.stylized_name_for_enum_value): + (Generator.stylized_name_for_enum_value.replaceCallback): + (Generator.keyed_get_method_for_type): + (Generator.keyed_set_method_for_type): + (Generator.type_builder_string_for_type): + (Generator.type_builder_string_for_type_member): + (Generator.type_string_for_unchecked_formal_in_parameter): + (Generator.type_string_for_checked_formal_event_parameter): + (Generator.type_string_for_type_member): + (Generator.type_string_for_type_with_name): + (Generator.type_string_for_formal_out_parameter): + (Generator.type_string_for_formal_async_parameter): + (Generator.type_string_for_stack_in_parameter): + (Generator.type_string_for_stack_out_parameter): + (Generator.assertion_method_for_type_member): + (Generator.assertion_method_for_type_member.assertion_method_for_type): + (Generator.cpp_name_for_primitive_type): + (Generator.js_name_for_parameter_type): + (Generator.should_use_wrapper_for_return_type): + (Generator.should_pass_by_copy_for_return_type): + * inspector/scripts/codegen/generator_templates.py: Added. + (GeneratorTemplates): + (void): + (HashMap): + (Builder): + (Inspector): + * inspector/scripts/codegen/models.py: Added. + (ucfirst): + (ParseException): + (TypecheckException): + (Framework): + (Framework.__init__): + (Framework.setting): + (Framework.fromString): + (Frameworks): + (TypeReference): + (TypeReference.__init__): + (TypeReference.referenced_name): + (Type): + (Type.__init__): + (Type.__eq__): + (Type.__hash__): + (Type.raw_name): + (Type.is_enum): + (Type.type_domain): + (Type.qualified_name): + (Type.resolve_type_references): + (PrimitiveType): + (PrimitiveType.__init__): + (PrimitiveType.__repr__): + (PrimitiveType.type_domain): + (PrimitiveType.qualified_name): + (AliasedType): + (AliasedType.__init__): + (AliasedType.__repr__): + (AliasedType.is_enum): + (AliasedType.type_domain): + (AliasedType.qualified_name): + (AliasedType.resolve_type_references): + (EnumType): + (EnumType.__init__): + (EnumType.__repr__): + (EnumType.is_enum): + (EnumType.type_domain): + (EnumType.enum_values): + (EnumType.qualified_name): + (EnumType.resolve_type_references): + (ArrayType): + (ArrayType.__init__): + (ArrayType.__repr__): + (ArrayType.type_domain): + (ArrayType.qualified_name): + (ArrayType.resolve_type_references): + (ObjectType): + (ObjectType.__init__): + (ObjectType.__repr__): + (ObjectType.type_domain): + (ObjectType.qualified_name): + (check_for_required_properties): + (Protocol): + (Protocol.__init__): + (Protocol.parse_specification): + (Protocol.parse_domain): + (Protocol.parse_type_declaration): + (Protocol.parse_type_member): + (Protocol.parse_command): + (Protocol.parse_event): + (Protocol.parse_call_or_return_parameter): + (Protocol.resolve_types): + (Protocol.lookup_type_for_declaration): + (Protocol.lookup_type_reference): + (Domain): + (Domain.__init__): + (Domain.resolve_type_references): + (Domains): + (TypeDeclaration): + (TypeDeclaration.__init__): + (TypeDeclaration.resolve_type_references): + (TypeMember): + (TypeMember.__init__): + (TypeMember.resolve_type_references): + (Parameter): + (Parameter.__init__): + (Parameter.resolve_type_references): + (Command): + (Command.__init__): + (Command.resolve_type_references): + (Event): + (Event.__init__): + (Event.resolve_type_references): + * inspector/scripts/generate-inspector-protocol-bindings.py: Added. + (IncrementalFileWriter): + (IncrementalFileWriter.__init__): + (IncrementalFileWriter.write): + (IncrementalFileWriter.close): + (generate_from_specification): + (generate_from_specification.load_specification): + * inspector/scripts/tests/commands-with-async-attribute.json: Added. + * inspector/scripts/tests/commands-with-optional-call-return-parameters.json: Added. + * inspector/scripts/tests/domains-with-varying-command-sizes.json: Added. + * inspector/scripts/tests/events-with-optional-parameters.json: Added. + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: Added. + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: Added. + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: Added. + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: Added. + * inspector/scripts/tests/fail-on-duplicate-type-declarations.json-error: Added. + * inspector/scripts/tests/fail-on-enum-with-no-values.json-error: Added. + * inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json-error: Added. + * inspector/scripts/tests/fail-on-type-with-lowercase-name.json-error: Added. + * inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json-error: Added. + * inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json-error: Added. + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: Added. + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: Added. + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: Added. + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: Added. + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: Added. + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: Added. + * inspector/scripts/tests/fail-on-duplicate-type-declarations.json: Added. + * inspector/scripts/tests/fail-on-enum-with-no-values.json: Added. + * inspector/scripts/tests/fail-on-type-declaration-using-type-reference.json: Added. + * inspector/scripts/tests/fail-on-type-with-lowercase-name.json: Added. + * inspector/scripts/tests/fail-on-unknown-type-reference-in-type-declaration.json: Added. + * inspector/scripts/tests/fail-on-unknown-type-reference-in-type-member.json: Added. + * inspector/scripts/tests/same-type-id-different-domain.json: Added. + * inspector/scripts/tests/type-declaration-aliased-primitive-type.json: Added. + * inspector/scripts/tests/type-declaration-array-type.json: Added. + * inspector/scripts/tests/type-declaration-enum-type.json: Added. + * inspector/scripts/tests/type-declaration-object-type.json: Added. + * inspector/scripts/tests/type-requiring-runtime-casts.json: Added. + +2014-08-15 Matthew Mirman <mmirman@apple.com> + + Made native inlining errors not segfault. + https://bugs.webkit.org/show_bug.cgi?id=135988 + + Reviewed by Geoffrey Garen. + + * ftl/FTLAbbreviations.h: + (JSC::FTL::disposeMessage): Added. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compilePutById): + abstracted out Options::verboseCompilation as was the case in the rest of the file. + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): + added output error messages for llvm module loading. + +2014-08-14 Andreas Kling <akling@apple.com> + + Allocate the whole RegExpMatchesArray backing store up front. + <https://webkit.org/b/135217> + + We were using the generic array backing store allocation path for + RegExpMatchesArray which meant starting with 4 slots and then growing + it dynamically as we append. Since we always know the final number of + entries up front, allocate a perfectly-sized backing store right away. + + ~2% progression on Octane/regexp. + + Reviewed by Geoffrey Garen. + + * runtime/JSArray.h: + (JSC::createArrayButterflyWithExactLength): + * runtime/RegExpMatchesArray.cpp: + (JSC::RegExpMatchesArray::create): + +2014-08-14 Saam Barati <sbarati@apple.com> + + Allow high fidelity type profiling to be enabled and disabled. + https://bugs.webkit.org/show_bug.cgi?id=135423 + + Reviewed by Geoffrey Garen. + + - Merged op_put_to_scope_with_profile and op_get_from_scope_with_profile into + op_profile_types_with_high_fidelity by adding extra arguments to the opcode. + - Altered SymbolTable to use less memory by adding a rare data structure for + type profiling. + - Created an interface to turn on and off type profiling from the Web + Inspector. + - Refactored how entries are written to HighFidelityLog to make it + easier to inline when generating machine code. + - Implemented op_profile_types_with_high_fidelity in the baseline JIT + by inlining the process of writing to the log and doing a small amount + of type inference optimizations. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::scopeDependentProfile): Deleted. + * bytecode/CodeBlock.h: + * bytecode/TypeLocation.h: + (JSC::TypeLocation::TypeLocation): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): + (JSC::BytecodeGenerator::emitGetFromScopeWithProfile): Deleted. + (JSC::BytecodeGenerator::emitPutToScopeWithProfile): Deleted. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ThisNode::emitBytecode): + (JSC::ResolveNode::emitBytecode): + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::FunctionCallValueNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::FunctionCallBracketNode::emitBytecode): + (JSC::FunctionCallDotNode::emitBytecode): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::PostfixNode::emitBracket): + (JSC::PostfixNode::emitDot): + (JSC::PrefixNode::emitResolve): + (JSC::PrefixNode::emitBracket): + (JSC::PrefixNode::emitDot): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::AssignDotNode::emitBytecode): + (JSC::ReadModifyDotNode::emitBytecode): + (JSC::AssignBracketNode::emitBytecode): + (JSC::ReadModifyBracketNode::emitBytecode): + (JSC::ReturnNode::emitBytecode): + (JSC::FunctionBodyNode::emitBytecode): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::InspectorRuntimeAgent): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::TypeRecompiler::operator()): + (Inspector::recompileAllJSFunctionsForTypeProfiling): + (Inspector::InspectorRuntimeAgent::willDestroyFrontendAndBackend): + (Inspector::InspectorRuntimeAgent::enableHighFidelityTypeProfiling): + (Inspector::InspectorRuntimeAgent::disableHighFidelityTypeProfiling): + (Inspector::InspectorRuntimeAgent::setHighFidelityTypeProfilingEnabledState): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/agents/JSGlobalObjectRuntimeAgent.cpp: + (Inspector::JSGlobalObjectRuntimeAgent::willDestroyFrontendAndBackend): + * inspector/protocol/Runtime.json: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_profile_types_with_high_fidelity): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_types_with_high_fidelity): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (JSC::LLInt::getFromScopeCommon): Deleted. + (JSC::LLInt::putToScopeCommon): Deleted. + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/HighFidelityLog.cpp: + (JSC::HighFidelityLog::initializeHighFidelityLog): + (JSC::HighFidelityLog::~HighFidelityLog): + (JSC::HighFidelityLog::processHighFidelityLog): + * runtime/HighFidelityLog.h: + (JSC::HighFidelityLog::LogEntry::structureIDOffset): + (JSC::HighFidelityLog::LogEntry::valueOffset): + (JSC::HighFidelityLog::LogEntry::locationOffset): + (JSC::HighFidelityLog::recordTypeInformationForLocation): + (JSC::HighFidelityLog::logEndPtr): + (JSC::HighFidelityLog::logStartOffset): + (JSC::HighFidelityLog::currentLogEntryOffset): + * runtime/HighFidelityTypeProfiler.cpp: + (JSC::HighFidelityTypeProfiler::logTypesForTypeLocation): + (JSC::descriptorMatchesTypeLocation): + * runtime/HighFidelityTypeProfiler.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::SymbolTable): + (JSC::SymbolTable::cloneCapturedNames): + (JSC::SymbolTable::prepareForHighFidelityTypeProfiling): + (JSC::SymbolTable::uniqueIDForVariable): + (JSC::SymbolTable::uniqueIDForRegister): + (JSC::SymbolTable::globalTypeSetForRegister): + (JSC::SymbolTable::globalTypeSetForVariable): + * runtime/SymbolTable.h: + (JSC::SymbolTable::add): + (JSC::SymbolTable::set): + * runtime/TypeLocationCache.cpp: + (JSC::TypeLocationCache::getTypeLocation): + * runtime/TypeSet.cpp: + (JSC::TypeSet::getRuntimeTypeForValue): + (JSC::TypeSet::addTypeInformation): + (JSC::TypeSet::allPrimitiveTypeNames): + (JSC::TypeSet::addTypeForValue): Deleted. + * runtime/TypeSet.h: + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::nextTypeLocation): + (JSC::VM::enableHighFidelityTypeProfiling): + (JSC::VM::disableHighFidelityTypeProfiling): + (JSC::VM::dumpHighFidelityProfilingTypes): + * runtime/VM.h: + (JSC::VM::nextLocation): Deleted. + +2014-08-14 Oliver Hunt <oliver@apple.com> + + Update scope resolution to assume that the parent activation is always there + https://bugs.webkit.org/show_bug.cgi?id=135947 + + Reviewed by Andreas Kling. + + Another incremental step in removing the idea of lazily created + activations. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitResolveClosure): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitResolveClosure): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-08-14 Oliver Hunt <oliver@apple.com> + + Create activations eagerly + https://bugs.webkit.org/show_bug.cgi?id=135942 + + Reviewed by Geoffrey Garen. + + Prepare to rewrite activation objects into a more + sane implementation. Step 1 is reverting to eager + creation of the activation object. This results in + a 1.35x regression in earley, but otherwise has a + minimal performance impact. + + The earley regression is being tracked by bug #135943 + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + (JSC::BytecodeGenerator::emitCallEval): + (JSC::BytecodeGenerator::emitPushWithScope): + (JSC::BytecodeGenerator::emitPushCatchScope): + (JSC::BytecodeGenerator::createActivationIfNecessary): Deleted. + * bytecompiler/BytecodeGenerator.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_activation): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_activation): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-08-14 Oliver Hunt <oliver@apple.com> + + Create activations eagerly + https://bugs.webkit.org/show_bug.cgi?id=135942 + + Reviewed by Geoffrey Garen. + + Prepare to rewrite activation objects into a more + sane implementation. Step 1 is reverting to eager + creation of the activation object. This results in + a 1.35x regression in earley, but otherwise has a + minimal performance impact. + + The earley regression is being tracked by + http://webkit.org/b/135943 + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + (JSC::BytecodeGenerator::emitCallEval): + (JSC::BytecodeGenerator::emitPushWithScope): + (JSC::BytecodeGenerator::emitPushCatchScope): + (JSC::BytecodeGenerator::createActivationIfNecessary): Deleted. + * bytecompiler/BytecodeGenerator.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_activation): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_activation): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-08-14 Tomas Popela <tpopela@redhat.com> + + Add support for ppc, ppc64, ppc64le, s390, s390x into the CMake build + https://bugs.webkit.org/show_bug.cgi?id=135937 + + Reviewed by Carlos Garcia Campos. + + * CMakeLists.txt: + +2014-08-14 Akos Kiss <akiss@inf.u-szeged.hu> + + Fix JSC::ARM64Assembler::LinkRecord::RealTypes + https://bugs.webkit.org/show_bug.cgi?id=135906 + + Reviewed by Michael Saboff. + + JSC::ARM64Assembler::LinkRecord::RealTypes::m_compareRegister is defined + to occupy 5 bits but JSC::ARM64Assembler::RegisterID needs 6 bits. So, + increase the size of the bit field and also reorganize the struct to + better align with word boundaries. + + * assembler/ARM64Assembler.h: + +2014-08-13 Akos Kiss <akiss@inf.u-szeged.hu> + + Add ARM64 support to CMake-based builds + https://bugs.webkit.org/show_bug.cgi?id=135912 + + Reviewed by Gyuyoung Kim. + + This patch ensures that CMake does not fail with Unknown CPU error when + building for ARM64. + + * CMakeLists.txt: + +2014-08-13 Wenson Hsieh <wenson_hsieh@apple.com> + + Enable CSS_SCROLL_SNAP for iOS + https://bugs.webkit.org/show_bug.cgi?id=135915 + + Turn on CSS_SCROLL_SNAP for iOS and the iOS simulator. + + Reviewed by Tim Horton. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-13 Alex Christensen <achristensen@webkit.org> + + Progress towards CMake on Mac. + https://bugs.webkit.org/show_bug.cgi?id=135819 + + Reviewed by Laszlo Gombos. + + * CMakeLists.txt: + Add the remote inspector headers to the forwarding headers list. + +2014-08-13 Daniel Bates <dabates@apple.com> + + [iOS] Make JavaScriptCore and bmalloc build with the public SDK + https://bugs.webkit.org/show_bug.cgi?id=135848 + + Reviewed by Geoffrey Garen. + + * API/JSBase.h: Declare NSMap functions with external linkage when building for iOS without the + header <Foundation/NSMapTablePriv.h>. + * inspector/remote/RemoteInspector.mm: Define XPC functions with external linkage when building + without the system header <xpc/xpc.h>. + * inspector/remote/RemoteInspectorXPCConnection.h: Define xpc_connection_t and xpc_object_t when building + without the system header <xpc/xpc.h>. + * inspector/remote/RemoteInspectorXPCConnection.mm: Declare XPC functions with external linkage when + building without without the system header <xpc/xpc.h>. + (Inspector::RemoteInspectorXPCConnection::closeOnQueue): Fix code style; use nullptr instead of NULL. + (Inspector::RemoteInspectorXPCConnection::sendMessage): Ditto. + +2014-08-12 Peyton Randolph <prandolph@apple.com> + + Runtime switch for long mouse press gesture. Part of 135257 - Add long mouse press gesture. + https://bugs.webkit.org/show_bug.cgi?id=135682 + + Reviewed by Tim Horton. + + * Configurations/FeatureDefines.xcconfig: + Remove ENABLE_LONG_MOUSE_PRESS feature flag. + +2014-08-12 Alex Christensen <achristensen@webkit.org> + + Generate header detection headers for CMake on Windows. + https://bugs.webkit.org/show_bug.cgi?id=135807 + + Reviewed by Brent Fulgham. + + * CMakeLists.txt: + Include the derived sources directory to find WTF/WTFHeaderDetection.h. + +2014-08-11 Andy Estes <aestes@apple.com> + + [iOS] Get rid of iOS.xcconfig + https://bugs.webkit.org/show_bug.cgi?id=135809 + + Reviewed by Joseph Pecoraro. + + All iOS.xcconfig did was include AspenFamily.xcconfig, so there's no need for the indirection. + + * Configurations/Base.xcconfig: + * Configurations/iOS.xcconfig: Removed. + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-08-11 Michael Saboff <msaboff@apple.com> + + Eliminate {push,pop}CalleeSaves in favor of individual pushes & pops + https://bugs.webkit.org/show_bug.cgi?id=127155 + + Reviewed by Geoffrey Garen. + + Eliminated the offline assembler instructions {push,pop}CalleeSaves as well as the + ARM64 specific {push,pop}LRAndFP and replaced them with individual push and pop + instructions. Where the registers referenced by the added push and pop instructions + are not part of the offline assembler register aliases, used a newly added "emit" + offline assembler instruction which takes a string literal and outputs that + string as a native instruction. + + * llint/LowLevelInterpreter.asm: + * offlineasm/arm.rb: + * offlineasm/arm64.rb: + * offlineasm/ast.rb: + * offlineasm/cloop.rb: + * offlineasm/instructions.rb: + * offlineasm/mips.rb: + * offlineasm/parser.rb: + * offlineasm/sh4.rb: + * offlineasm/transform.rb: + * offlineasm/x86.rb: + +2014-08-11 Mark Lam <mark.lam@apple.com> + + Re-landing r172401 with fixed test. + <https://webkit.org/b/135782> + + Not reviewed. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::pushIndexedForInScope): + (JSC::BytecodeGenerator::pushStructureForInScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::ForInContext::ForInContext): + (JSC::ForInContext::base): + (JSC::StructureForInContext::StructureForInContext): + (JSC::IndexedForInContext::IndexedForInContext): + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitMultiLoopBytecode): + * tests/stress/for-in-tests.js: + +2014-08-11 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r172401. + https://bugs.webkit.org/show_bug.cgi?id=135812 + + Failing stress/for-in-tests.js + http://build.webkit.org/builders/Apple%20Mavericks%20Release%20WK1%20%28Tests%29/builds/7945/steps + /jscore-test/logs/stdio (Requested by mlam on #webkit). + + Reverted changeset: + + "for-in optimization should also make sure the base matches + the object being iterated" + https://bugs.webkit.org/show_bug.cgi?id=135782 + http://trac.webkit.org/changeset/172401 + +2014-08-11 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: use type builders to construct high fidelity type information payloads + https://bugs.webkit.org/show_bug.cgi?id=135803 + + Reviewed by Timothy Hatcher. + + Due to some typos in the protocol file, the code had worked with raw objects + rather than with type builders. Convert to using builders. + + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: Fix 'item' for 'items'; true for 'true'. + * runtime/HighFidelityTypeProfiler.cpp: + (JSC::HighFidelityTypeProfiler::getTypesForVariableAtOffsetForInspector): + * runtime/HighFidelityTypeProfiler.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::allStructureRepresentations): + (JSC::StructureShape::stringRepresentation): + (JSC::StructureShape::inspectorRepresentation): + * runtime/TypeSet.h: + +2014-08-11 Mark Hahnenberg <mhahnenberg@apple.com> + + for-in optimization should also make sure the base matches the object being iterated + https://bugs.webkit.org/show_bug.cgi?id=135782 + + Reviewed by Geoffrey Garen. + + If we access a different base object with the same index, we shouldn't try to randomly + load from that object's backing store. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::pushIndexedForInScope): + (JSC::BytecodeGenerator::pushStructureForInScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::ForInContext::ForInContext): + (JSC::ForInContext::base): + (JSC::StructureForInContext::StructureForInContext): + (JSC::IndexedForInContext::IndexedForInContext): + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitMultiLoopBytecode): + * tests/stress/for-in-tests.js: + +2014-08-11 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed gardening. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Display files in + proper folder categories.. + +2014-08-11 Mark Hahnenberg <mhahnenberg@apple.com> + + JIT should use full 64-bit stores for jsBoolean and jsNull + https://bugs.webkit.org/show_bug.cgi?id=135784 + + Reviewed by Michael Saboff. + + This guarantees that we set the high bits of the register with the correct tag. + + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_has_structure_property): + (JSC::JIT::emit_op_next_enumerator_pname): + +2014-08-11 Brent Fulgham <bfulgham@apple.com> + + [Win] Adjust build script for Windows production build. + https://bugs.webkit.org/show_bug.cgi?id=135806 + <rdar://problem/17978299> + + Reviewed by Timothy Hatcher. + + * JavaScriptCore.vcxproj/copy-files.cmd: Copy file for later use + in WebInspectorUI build. + +2014-08-10 Oliver Hunt <oliver@apple.com> + + Destructuring assignment in a var declaration list incorrectly consumes subsequent variable initialisers + https://bugs.webkit.org/show_bug.cgi?id=135773 + + Reviewed by Michael Saboff. + + We should be using parseAssignment expression in order to get the correct + precedence. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclarationList): + +2014-08-10 Diego Pino Garcia <dpino@igalia.com> + + JSC Lexer is allowing octals 08 and 09 in strict mode functions + https://bugs.webkit.org/show_bug.cgi?id=135704 + + Reviewed by Oliver Hunt. + + Return syntax error ("Decimal integer literals with a leading zero are + forbidden in strict mode") if a number starts with 0 and is followed + by a digit. + + * parser/Lexer.cpp: + (JSC::Lexer<T>::lex): + +2014-08-08 Mark Lam <mark.lam@apple.com> + + REGRESSION: Inspector crashes when debugger is paused and injected scripts access window.screen(). + <https://webkit.org/b/135656> + + Not reviewed. + + Rolling out r170680 which was merged to ToT in r172129. + + * debugger/Debugger.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::scope): + (JSC::DebuggerCallFrame::evaluate): + (JSC::DebuggerCallFrame::invalidate): + * debugger/DebuggerCallFrame.h: + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::DebuggerScope): + (JSC::DebuggerScope::finishCreation): + (JSC::DebuggerScope::visitChildren): + (JSC::DebuggerScope::className): + (JSC::DebuggerScope::getOwnPropertySlot): + (JSC::DebuggerScope::put): + (JSC::DebuggerScope::deleteProperty): + (JSC::DebuggerScope::getOwnPropertyNames): + (JSC::DebuggerScope::defineOwnProperty): + (JSC::DebuggerScope::next): Deleted. + (JSC::DebuggerScope::invalidateChain): Deleted. + (JSC::DebuggerScope::isWithScope): Deleted. + (JSC::DebuggerScope::isGlobalScope): Deleted. + (JSC::DebuggerScope::isFunctionScope): Deleted. + * debugger/DebuggerScope.h: + (JSC::DebuggerScope::create): + (JSC::DebuggerScope::Iterator::Iterator): Deleted. + (JSC::DebuggerScope::Iterator::get): Deleted. + (JSC::DebuggerScope::Iterator::operator++): Deleted. + (JSC::DebuggerScope::Iterator::operator==): Deleted. + (JSC::DebuggerScope::Iterator::operator!=): Deleted. + (JSC::DebuggerScope::isValid): Deleted. + (JSC::DebuggerScope::jsScope): Deleted. + (JSC::DebuggerScope::begin): Deleted. + (JSC::DebuggerScope::end): Deleted. + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::scopeType): + (Inspector::JSJavaScriptCallFrame::scopeChain): + * inspector/JavaScriptCallFrame.h: + (Inspector::JavaScriptCallFrame::scopeChain): + * inspector/ScriptDebugServer.cpp: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::debuggerScopeStructure): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::isWithScope): Deleted. + * runtime/JSScope.h: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2014-08-07 Saam Barati <sbarati@apple.com> + + Create a more generic way for VMEntryScope to notify those interested that it will be destroyed + https://bugs.webkit.org/show_bug.cgi?id=135358 + + Reviewed by Geoffrey Garen. + + When VMEntryScope is destroyed, and it has a flag set indicating that the + Debugger needs to recompile all functions, it calls Debugger::recompileAllJSFunctions. + This flag is only used by Debugger to have VMEntryScope notify it when the + Debugger is safe to recompile all functions. This patch will substitute this + Debugger-specific recompilation flag with a list of callbacks that are notified + when the outermost VMEntryScope dies. This creates a general purpose interface + for being notified when the VM stops executing code via the event of the outermost + VMEntryScope dying. + + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): + * runtime/VMEntryScope.cpp: + (JSC::VMEntryScope::VMEntryScope): + (JSC::VMEntryScope::setEntryScopeDidPopListener): + (JSC::VMEntryScope::~VMEntryScope): + * runtime/VMEntryScope.h: + (JSC::VMEntryScope::setRecompilationNeeded): Deleted. + +2014-08-07 Benjamin Poulain <bpoulain@apple.com> + + Get rid of SCRIPTED_SPEECH + https://bugs.webkit.org/show_bug.cgi?id=135729 + + Reviewed by Brent Fulgham. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-07 Mark Hahnenberg <mhahnenberg@apple.com> + + SpeculateInt32Operand is sometimes used in a 64-bit context, which has undefined behavior + https://bugs.webkit.org/show_bug.cgi?id=135722 + + Reviewed by Filip Pizlo. + + We should be using SpeculateStrictInt32Operand instead. + + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-08-07 Benjamin Poulain <bpoulain@apple.com> + + Get rid of INPUT_SPEECH + https://bugs.webkit.org/show_bug.cgi?id=135672 + + Reviewed by Andreas Kling. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-07 Mark Hahnenberg <mhahnenberg@apple.com> + + for-in is failing fast/dom/dataset-xhtml.xhtml and dataset.html tests + https://bugs.webkit.org/show_bug.cgi?id=135681 + + Reviewed by Filip Pizlo. + + * runtime/Structure.cpp: + (JSC::Structure::canCacheGenericPropertyNameEnumerator): We were checking the entire + prototype chain for overridesGetPropertyNames, but we were neglecting to check the + base object's Structure. D'oh! + +2014-08-06 Mark Lam <mark.lam@apple.com> + + Gardening: fix for build failure on EFL bots. + + Not reviewed. + + * runtime/EnumerationMode.h: + (JSC::shouldIncludeJSObjectPropertyNames): + (JSC::modeThatSkipsJSObject): + * runtime/JSCell.cpp: + (JSC::JSCell::getEnumerableLength): + * runtime/JSCell.h: + +2014-08-06 Dean Jackson <dino@apple.com> + + ENABLE_CSS_TRANSFORMS_ANIMATIONS_UNPREFIXED is not used anywhere. Remove it. + https://bugs.webkit.org/show_bug.cgi?id=135675 + + Reviewed by Sam Weinig. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-06 Wenson Hsieh <wenson_hsieh@apple.com> + + Implement parsing for CSS scroll snap points + https://bugs.webkit.org/show_bug.cgi?id=134301 + + Reviewed by Dean Jackson. + + * Configurations/FeatureDefines.xcconfig: Added ENABLE_CSS_SCROLL_SNAP + +2014-08-06 Mark Lam <mark.lam@apple.com> + + Gardening: fix for build failure on GTK bots. + + Not reviewed. + + * runtime/FunctionHasExecutedCache.cpp: + - #include <limits.h> for UINT_MAX's definition. + +2014-08-06 Mark Lam <mark.lam@apple.com> + + Gardening: fix for build failure on EFL bots. + + Not reviewed. + + * jit/JITInlines.h: + (JSC::JIT::emitLoadForArrayMode): + +2014-08-06 Mark Lam <mark.lam@apple.com> + + Gardening: adding missing build file changes from the FTLOPT merge at r172176. + + Not reviewed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-08-06 Ryuan Choi <ryuan.choi@samsung.com> + + Unreviewed build fix attempt since r172184 + + * CMakeLists.txt: Removed TypeLocation.cpp + +2014-08-06 Mark Lam <mark.lam@apple.com> + + Gardening: adding missing build file changes from r171510. + <https://webkit.org/b/134860> + + Not reviewed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-08-06 Mark Lam <mark.lam@apple.com> + + Gardening: adding missing build file changes from r170490. + <https://webkit.org/b/133395> + + Not reviewed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-08-06 Filip Pizlo <fpizlo@apple.com> + + Silence a debug assertion. + + Reviewed by Mark Hahnenberg. + + * runtime/JSPropertyNameEnumerator.h: + (JSC::JSPropertyNameEnumerator::cachedStructure): + +2014-08-06 Filip Pizlo <fpizlo@apple.com> + + Fix 32-bit build. + + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileHasIndexedProperty): + +2014-08-06 Filip Pizlo <fpizlo@apple.com> + + Merge r171389, r171495, r171508, r171510, r171605, r171606, r171611, r171614, r171763 from ftlopt. + + 2014-07-28 Mark Hahnenberg <mhahnenberg@apple.com> + + Support for-in in the FTL + https://bugs.webkit.org/show_bug.cgi?id=134140 + + Reviewed by Filip Pizlo. + + * dfg/DFGSSALoweringPhase.cpp: + (JSC::DFG::SSALoweringPhase::handleNode): + * ftl/FTLAbstractHeapRepository.cpp: + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileHasIndexedProperty): + (JSC::FTL::LowerDFGToLLVM::compileHasGenericProperty): + (JSC::FTL::LowerDFGToLLVM::compileHasStructureProperty): + (JSC::FTL::LowerDFGToLLVM::compileGetDirectPname): + (JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength): + (JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator): + (JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator): + (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname): + (JSC::FTL::LowerDFGToLLVM::compileToIndexString): + + 2014-07-25 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove JSPropertyNameIterator + https://bugs.webkit.org/show_bug.cgi?id=135066 + + Reviewed by Geoffrey Garen. + + It has been replaced by JSPropertyNameEnumerator. + + * JavaScriptCore.order: + * bytecode/BytecodeBasicBlock.cpp: + (JSC::isBranch): + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecode/PreciseJumpTargets.cpp: + (JSC::getJumpTargetsForBytecodeOffset): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetPropertyNames): Deleted. + (JSC::BytecodeGenerator::emitNextPropertyName): Deleted. + * bytecompiler/BytecodeGenerator.h: + * interpreter/Interpreter.cpp: + * interpreter/Register.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_pnames): Deleted. + (JSC::JIT::emit_op_next_pname): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_pnames): Deleted. + (JSC::JIT::emit_op_next_pname): Deleted. + * jit/JITOperations.cpp: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_pname): Deleted. + (JSC::JIT::emitSlow_op_get_by_pname): Deleted. + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_pname): Deleted. + (JSC::JIT::emitSlow_op_get_by_pname): Deleted. + * llint/LLIntOffsetsExtractor.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): Deleted. + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::JSPropertyNameIterator): Deleted. + (JSC::JSPropertyNameIterator::create): Deleted. + (JSC::JSPropertyNameIterator::destroy): Deleted. + (JSC::JSPropertyNameIterator::get): Deleted. + (JSC::JSPropertyNameIterator::visitChildren): Deleted. + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::createStructure): Deleted. + (JSC::JSPropertyNameIterator::size): Deleted. + (JSC::JSPropertyNameIterator::setCachedStructure): Deleted. + (JSC::JSPropertyNameIterator::cachedStructure): Deleted. + (JSC::JSPropertyNameIterator::setCachedPrototypeChain): Deleted. + (JSC::JSPropertyNameIterator::cachedPrototypeChain): Deleted. + (JSC::JSPropertyNameIterator::finishCreation): Deleted. + (JSC::Register::propertyNameIterator): Deleted. + (JSC::StructureRareData::enumerationCache): Deleted. + (JSC::StructureRareData::setEnumerationCache): Deleted. + * runtime/Structure.cpp: + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::removePropertyWithoutTransition): + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): Deleted. + (JSC::Structure::enumerationCache): Deleted. + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::visitChildren): + * runtime/StructureRareData.h: + * runtime/VM.cpp: + (JSC::VM::VM): + + 2014-07-25 Saam Barati <sbarati@apple.com> + + Fix 32-bit build breakage for type profiling + https://bugs.webkit.org/process_bug.cgi + + Reviewed by Mark Hahnenberg. + + 32-bit builds currently break because global variable IDs for high + fidelity type profiling are int64_t. Change this to intptr_t so that + it's 32 bits on 32-bit platforms and 64 bits on 64-bit platforms. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::scopeDependentProfile): + * bytecode/TypeLocation.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::uniqueIDForVariable): + (JSC::SymbolTable::uniqueIDForRegister): + * runtime/SymbolTable.h: + * runtime/TypeLocationCache.cpp: + (JSC::TypeLocationCache::getTypeLocation): + * runtime/TypeLocationCache.h: + * runtime/VM.h: + (JSC::VM::getNextUniqueVariableID): + + 2014-07-25 Mark Hahnenberg <mhahnenberg@apple.com> + + Reindent PropertyNameArray.h + https://bugs.webkit.org/show_bug.cgi?id=135067 + + Reviewed by Geoffrey Garen. + + * runtime/PropertyNameArray.h: + (JSC::RefCountedIdentifierSet::contains): + (JSC::RefCountedIdentifierSet::size): + (JSC::RefCountedIdentifierSet::add): + (JSC::PropertyNameArrayData::create): + (JSC::PropertyNameArrayData::propertyNameVector): + (JSC::PropertyNameArrayData::PropertyNameArrayData): + (JSC::PropertyNameArray::PropertyNameArray): + (JSC::PropertyNameArray::vm): + (JSC::PropertyNameArray::add): + (JSC::PropertyNameArray::addKnownUnique): + (JSC::PropertyNameArray::operator[]): + (JSC::PropertyNameArray::setData): + (JSC::PropertyNameArray::data): + (JSC::PropertyNameArray::releaseData): + (JSC::PropertyNameArray::identifierSet): + (JSC::PropertyNameArray::canAddKnownUniqueForStructure): + (JSC::PropertyNameArray::size): + (JSC::PropertyNameArray::begin): + (JSC::PropertyNameArray::end): + (JSC::PropertyNameArray::numCacheableSlots): + (JSC::PropertyNameArray::setNumCacheableSlotsForObject): + (JSC::PropertyNameArray::setBaseObject): + (JSC::PropertyNameArray::setPreviouslyEnumeratedLength): + + 2014-07-23 Mark Hahnenberg <mhahnenberg@apple.com> + + Refactor our current implementation of for-in + https://bugs.webkit.org/show_bug.cgi?id=134142 + + Reviewed by Filip Pizlo. + + This patch splits for-in loops into three distinct parts: + + - Iterating over the indexed properties in the base object. + - Iterating over the Structure properties in the base object. + - Iterating over any other enumerable properties for that object and any objects in the prototype chain. + + It does this by emitting these explicit loops in bytecode, using a new set of bytecodes to + support the various operations required for each loop. + + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames): + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetByVal): + (JSC::BytecodeGenerator::emitComplexPopScopes): + (JSC::BytecodeGenerator::emitGetEnumerableLength): + (JSC::BytecodeGenerator::emitHasGenericProperty): + (JSC::BytecodeGenerator::emitHasIndexedProperty): + (JSC::BytecodeGenerator::emitHasStructureProperty): + (JSC::BytecodeGenerator::emitGetStructurePropertyEnumerator): + (JSC::BytecodeGenerator::emitGetGenericPropertyEnumerator): + (JSC::BytecodeGenerator::emitNextEnumeratorPropertyName): + (JSC::BytecodeGenerator::emitToIndexString): + (JSC::BytecodeGenerator::pushIndexedForInScope): + (JSC::BytecodeGenerator::popIndexedForInScope): + (JSC::BytecodeGenerator::pushStructureForInScope): + (JSC::BytecodeGenerator::popStructureForInScope): + (JSC::BytecodeGenerator::invalidateForInContextForLocal): + * bytecompiler/BytecodeGenerator.h: + (JSC::ForInContext::ForInContext): + (JSC::ForInContext::~ForInContext): + (JSC::ForInContext::isValid): + (JSC::ForInContext::invalidate): + (JSC::ForInContext::local): + (JSC::StructureForInContext::StructureForInContext): + (JSC::StructureForInContext::type): + (JSC::StructureForInContext::index): + (JSC::StructureForInContext::property): + (JSC::StructureForInContext::enumerator): + (JSC::IndexedForInContext::IndexedForInContext): + (JSC::IndexedForInContext::type): + (JSC::IndexedForInContext::index): + (JSC::BytecodeGenerator::pushOptimisedForIn): Deleted. + (JSC::BytecodeGenerator::popOptimisedForIn): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ForInNode::tryGetBoundLocal): + (JSC::ForInNode::emitLoopHeader): + (JSC::ForInNode::emitMultiLoopBytecode): + (JSC::ForInNode::emitBytecode): + * debugger/DebuggerScope.h: + * dfg/DFGAbstractHeap.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::hasHeapPrediction): + (JSC::DFG::Node::hasArrayMode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + (JSC::JIT::compileHasIndexedProperty): + (JSC::JIT::emitInt32Load): + * jit/JITInlines.h: + (JSC::JIT::emitDoubleGetByVal): + (JSC::JIT::emitLoadForArrayMode): + (JSC::JIT::emitContiguousGetByVal): + (JSC::JIT::emitArrayStorageGetByVal): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_enumerable_length): + (JSC::JIT::emit_op_has_structure_property): + (JSC::JIT::emitSlow_op_has_structure_property): + (JSC::JIT::emit_op_has_generic_property): + (JSC::JIT::privateCompileHasIndexedProperty): + (JSC::JIT::emit_op_has_indexed_property): + (JSC::JIT::emitSlow_op_has_indexed_property): + (JSC::JIT::emit_op_get_direct_pname): + (JSC::JIT::emitSlow_op_get_direct_pname): + (JSC::JIT::emit_op_get_structure_property_enumerator): + (JSC::JIT::emit_op_get_generic_property_enumerator): + (JSC::JIT::emit_op_next_enumerator_pname): + (JSC::JIT::emit_op_to_index_string): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_enumerable_length): + (JSC::JIT::emit_op_has_structure_property): + (JSC::JIT::emitSlow_op_has_structure_property): + (JSC::JIT::emit_op_has_generic_property): + (JSC::JIT::privateCompileHasIndexedProperty): + (JSC::JIT::emit_op_has_indexed_property): + (JSC::JIT::emitSlow_op_has_indexed_property): + (JSC::JIT::emit_op_get_direct_pname): + (JSC::JIT::emitSlow_op_get_direct_pname): + (JSC::JIT::emit_op_get_structure_property_enumerator): + (JSC::JIT::emit_op_get_generic_property_enumerator): + (JSC::JIT::emit_op_next_enumerator_pname): + (JSC::JIT::emit_op_to_index_string): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitDoubleLoad): + (JSC::JIT::emitContiguousLoad): + (JSC::JIT::emitArrayStorageLoad): + (JSC::JIT::emitDoubleGetByVal): Deleted. + (JSC::JIT::emitContiguousGetByVal): Deleted. + (JSC::JIT::emitArrayStorageGetByVal): Deleted. + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitContiguousLoad): + (JSC::JIT::emitDoubleLoad): + (JSC::JIT::emitArrayStorageLoad): + (JSC::JIT::emitContiguousGetByVal): Deleted. + (JSC::JIT::emitDoubleGetByVal): Deleted. + (JSC::JIT::emitArrayStorageGetByVal): Deleted. + * llint/LowLevelInterpreter.asm: + * parser/Nodes.h: + * runtime/Arguments.cpp: + (JSC::Arguments::getOwnPropertyNames): + * runtime/ClassInfo.h: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/EnumerationMode.h: Added. + (JSC::shouldIncludeDontEnumProperties): + (JSC::shouldExcludeDontEnumProperties): + (JSC::shouldIncludeJSObjectPropertyNames): + (JSC::modeThatSkipsJSObject): + * runtime/JSActivation.cpp: + (JSC::JSActivation::getOwnNonIndexPropertyNames): + * runtime/JSArray.cpp: + (JSC::JSArray::getOwnNonIndexPropertyNames): + * runtime/JSArrayBuffer.cpp: + (JSC::JSArrayBuffer::getOwnNonIndexPropertyNames): + * runtime/JSArrayBufferView.cpp: + (JSC::JSArrayBufferView::getOwnNonIndexPropertyNames): + * runtime/JSCell.cpp: + (JSC::JSCell::getEnumerableLength): + (JSC::JSCell::getStructurePropertyNames): + (JSC::JSCell::getGenericPropertyNames): + * runtime/JSCell.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnNonIndexPropertyNames): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames): + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + (JSC::JSObject::hasOwnProperty): + (JSC::JSObject::getOwnPropertyNames): + (JSC::JSObject::getOwnNonIndexPropertyNames): + (JSC::JSObject::getEnumerableLength): + (JSC::JSObject::getStructurePropertyNames): + (JSC::JSObject::getGenericPropertyNames): + * runtime/JSObject.h: + * runtime/JSPropertyNameEnumerator.cpp: Added. + (JSC::JSPropertyNameEnumerator::create): + (JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator): + (JSC::JSPropertyNameEnumerator::finishCreation): + (JSC::JSPropertyNameEnumerator::destroy): + (JSC::JSPropertyNameEnumerator::visitChildren): + * runtime/JSPropertyNameEnumerator.h: Added. + (JSC::JSPropertyNameEnumerator::createStructure): + (JSC::JSPropertyNameEnumerator::propertyNameAtIndex): + (JSC::JSPropertyNameEnumerator::identifierSet): + (JSC::JSPropertyNameEnumerator::cachedPrototypeChain): + (JSC::JSPropertyNameEnumerator::setCachedPrototypeChain): + (JSC::JSPropertyNameEnumerator::cachedStructure): + (JSC::JSPropertyNameEnumerator::cachedStructureID): + (JSC::JSPropertyNameEnumerator::cachedInlineCapacity): + (JSC::JSPropertyNameEnumerator::cachedStructureIDOffset): + (JSC::JSPropertyNameEnumerator::cachedInlineCapacityOffset): + (JSC::JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset): + (JSC::JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset): + (JSC::structurePropertyNameEnumerator): + (JSC::genericPropertyNameEnumerator): + * runtime/JSProxy.cpp: + (JSC::JSProxy::getEnumerableLength): + (JSC::JSProxy::getStructurePropertyNames): + (JSC::JSProxy::getGenericPropertyNames): + * runtime/JSProxy.h: + * runtime/JSSymbolTableObject.cpp: + (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames): + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + (JSC::PropertyNameArray::setPreviouslyEnumeratedProperties): + * runtime/PropertyNameArray.h: + (JSC::RefCountedIdentifierSet::contains): + (JSC::RefCountedIdentifierSet::size): + (JSC::RefCountedIdentifierSet::add): + (JSC::PropertyNameArray::PropertyNameArray): + (JSC::PropertyNameArray::add): + (JSC::PropertyNameArray::addKnownUnique): + (JSC::PropertyNameArray::identifierSet): + (JSC::PropertyNameArray::canAddKnownUniqueForStructure): + (JSC::PropertyNameArray::setPreviouslyEnumeratedLength): + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::getOwnNonIndexPropertyNames): + (JSC::RegExpObject::getPropertyNames): + (JSC::RegExpObject::getGenericPropertyNames): + * runtime/RegExpObject.h: + * runtime/StringObject.cpp: + (JSC::StringObject::getOwnPropertyNames): + * runtime/Structure.cpp: + (JSC::Structure::getPropertyNamesFromStructure): + (JSC::Structure::setCachedStructurePropertyNameEnumerator): + (JSC::Structure::cachedStructurePropertyNameEnumerator): + (JSC::Structure::setCachedGenericPropertyNameEnumerator): + (JSC::Structure::cachedGenericPropertyNameEnumerator): + (JSC::Structure::canCacheStructurePropertyNameEnumerator): + (JSC::Structure::canCacheGenericPropertyNameEnumerator): + (JSC::Structure::canAccessPropertiesQuickly): + * runtime/Structure.h: + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::visitChildren): + (JSC::StructureRareData::cachedStructurePropertyNameEnumerator): + (JSC::StructureRareData::setCachedStructurePropertyNameEnumerator): + (JSC::StructureRareData::cachedGenericPropertyNameEnumerator): + (JSC::StructureRareData::setCachedGenericPropertyNameEnumerator): + * runtime/StructureRareData.h: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + + 2014-07-23 Saam Barati <sbarati@apple.com> + + Make improvements to Type Profiling + https://bugs.webkit.org/show_bug.cgi?id=134860 + + Reviewed by Filip Pizlo. + + I improved the API between the inspector and JSC. We no longer send one huge + string to the inspector. We now send structured data that represents the type + information that JSC has collected. I've also created a beginning implementation + of a type lattice that allows us to resolve a display name for a type that + consists of a single word. + + I created a data structure that knows which functions have executed. This + solves the bug where types inside an un-executed function will resolve + to the type of the enclosing expression of that function. This data + structure may also be useful later if the inspector chooses to create a UI + around showing which functions have executed. + + Better type information is gathered for objects. StructureShape now + represents an object's prototype chain. StructureShape also collects + the constructor name for an object. + + Expression ranges are now zero indexed. + + Removed some extraneous methods. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::scopeDependentProfile): + * bytecode/CodeBlock.h: + * bytecode/TypeLocation.h: + (JSC::TypeLocation::TypeLocation): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingStartOffset): + (JSC::UnlinkedFunctionExecutable::highFidelityTypeProfilingEndOffset): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo): Deleted. + * heap/Heap.cpp: + (JSC::Heap::collect): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableAtOffset): Deleted. + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + * runtime/Executable.cpp: + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::ProgramExecutable::ProgramExecutable): + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::ProgramExecutable::initializeGlobalProperties): + * runtime/Executable.h: + (JSC::ScriptExecutable::highFidelityTypeProfilingStartOffset): + (JSC::ScriptExecutable::highFidelityTypeProfilingEndOffset): + * runtime/FunctionHasExecutedCache.cpp: Added. + (JSC::FunctionHasExecutedCache::hasExecutedAtOffset): + (JSC::FunctionHasExecutedCache::insertUnexecutedRange): + (JSC::FunctionHasExecutedCache::removeUnexecutedRange): + * runtime/FunctionHasExecutedCache.h: Added. + (JSC::FunctionHasExecutedCache::FunctionRange::FunctionRange): + (JSC::FunctionHasExecutedCache::FunctionRange::operator==): + (JSC::FunctionHasExecutedCache::FunctionRange::hash): + * runtime/HighFidelityLog.cpp: + (JSC::HighFidelityLog::processHighFidelityLog): + (JSC::HighFidelityLog::actuallyProcessLogThreadFunction): Deleted. + * runtime/HighFidelityLog.h: + (JSC::HighFidelityLog::recordTypeInformationForLocation): + * runtime/HighFidelityTypeProfiler.cpp: + (JSC::HighFidelityTypeProfiler::logTypesForTypeLocation): + (JSC::HighFidelityTypeProfiler::insertNewLocation): + (JSC::HighFidelityTypeProfiler::getTypesForVariableAtOffsetForInspector): + (JSC::descriptorMatchesTypeLocation): + (JSC::HighFidelityTypeProfiler::findLocation): + (JSC::HighFidelityTypeProfiler::getTypesForVariableInAtOffset): Deleted. + (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableAtOffset): Deleted. + (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableAtOffset): Deleted. + * runtime/HighFidelityTypeProfiler.h: + (JSC::QueryKey::QueryKey): + (JSC::QueryKey::isHashTableDeletedValue): + (JSC::QueryKey::operator==): + (JSC::QueryKey::hash): + (JSC::QueryKeyHash::hash): + (JSC::QueryKeyHash::equal): + (JSC::HighFidelityTypeProfiler::functionHasExecutedCache): + (JSC::HighFidelityTypeProfiler::typeLocationCache): + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + * runtime/Structure.h: + * runtime/TypeLocationCache.cpp: Added. + (JSC::TypeLocationCache::getTypeLocation): + * runtime/TypeLocationCache.h: Added. + (JSC::TypeLocationCache::LocationKey::LocationKey): + (JSC::TypeLocationCache::LocationKey::operator==): + (JSC::TypeLocationCache::LocationKey::hash): + * runtime/TypeSet.cpp: + (JSC::TypeSet::getRuntimeTypeForValue): + (JSC::TypeSet::addTypeForValue): + (JSC::TypeSet::seenTypes): + (JSC::TypeSet::doesTypeConformTo): + (JSC::TypeSet::displayName): + (JSC::TypeSet::allPrimitiveTypeNames): + (JSC::TypeSet::allStructureRepresentations): + (JSC::TypeSet::leastCommonAncestor): + (JSC::StructureShape::StructureShape): + (JSC::StructureShape::addProperty): + (JSC::StructureShape::propertyHash): + (JSC::StructureShape::leastCommonAncestor): + (JSC::StructureShape::stringRepresentation): + (JSC::StructureShape::inspectorRepresentation): + (JSC::StructureShape::leastUpperBound): Deleted. + * runtime/TypeSet.h: + (JSC::StructureShape::setConstructorName): + (JSC::StructureShape::constructorName): + (JSC::StructureShape::setProto): + * runtime/VM.cpp: + (JSC::VM::dumpHighFidelityProfilingTypes): + (JSC::VM::getTypesForVariableAtOffset): Deleted. + (JSC::VM::updateHighFidelityTypeProfileState): Deleted. + * runtime/VM.h: + (JSC::VM::isProfilingTypesWithHighFidelity): + (JSC::VM::highFidelityTypeProfiler): + + 2014-07-23 Filip Pizlo <fpizlo@apple.com> + + Fix debug build. + + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + + 2014-07-20 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Phantoms in SSA form should be aggressively hoisted + https://bugs.webkit.org/show_bug.cgi?id=135111 + + Reviewed by Oliver Hunt. + + In CPS form, Phantom means three things: (1) that the children should be kept alive so long + as they are relevant to OSR (due to a MovHint), (2) that the children are live-in-bytecode + at the point of the Phantom, and (3) that some checks should be performed. In SSA, the + second meaning is not used but the other two stay. + + The fact that a Phantom that is used to keep a node alive could be anywhere in the graph, + even in a totally different basic block, complicates some SSA transformations. It's not + possible to just jettison some successor, since tha successor could have a Phantom that we + care about. + + This change rationalizes how Phantoms work so that: + + 1) Phantoms keep children alive so long as those children are relevant to OSR. This is true + in both CPS and SSA. This was true before and it's true now. + + 2) Phantoms are used for live-in-bytecode only in CPS. This was true before and it's true + now, except that now we also don't bother preserving the live-in-bytecode information + that Phantoms convey, when we are in SSA. + + 3) Phantoms may incidentally have checks, but in cases where we only want checks, we now + use Check instead of Phantom. Notably, DCE phase has dead nodes decay to Check, not + Phantom. + + The biggest part of this change is that in SSA, we canonicalize Phantoms: + + - All Phantoms are replaced with Check nodes that include only those edges that have + checks. + + - Nodes that were the children of any Phantoms have a Phantom right after them. + + For example, the following code: + + 5: ArithAdd(@1, @2) + 6: ArithSub(@5, @3) + 7: Phantom(Int32:@5) + + would be turned into the following: + + 5: ArithAdd(@1, @2) + 8: Phantom(@5) // @5 was the child of a Phantom, so we create a new Phantom right after + // @5. This is the only Phantom we will have for @5. + 6: ArithSub(@5, @3) + 7: Check(Int32:@5) // We replace the Phantom with a Check; in this case since Int32: is + // a checking edge, we leave it. + + This is a slight speed-up across the board, presumably because we now do a better job of + reducing the size of the graph during compilation. It could also be a fluke, though. The + main purpose of this is to unlock some other work (like CFG simplification in SSA). It will + become a requirement to run phantom canonicalization prior to some SSA phases. None of the + current phases need it, but future phases probably will. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + (JSC::DFG::DCEPhase::findTypeCheckRoot): + (JSC::DFG::DCEPhase::countEdge): + (JSC::DFG::DCEPhase::fixupBlock): + (JSC::DFG::DCEPhase::eliminateIrrelevantPhantomChildren): + * dfg/DFGEdge.cpp: + (JSC::DFG::Edge::dump): + * dfg/DFGEdge.h: + (JSC::DFG::Edge::isProved): + (JSC::DFG::Edge::needsCheck): Deleted. + * dfg/DFGNodeFlags.h: + * dfg/DFGPhantomCanonicalizationPhase.cpp: Added. + (JSC::DFG::PhantomCanonicalizationPhase::PhantomCanonicalizationPhase): + (JSC::DFG::PhantomCanonicalizationPhase::run): + (JSC::DFG::performPhantomCanonicalization): + * dfg/DFGPhantomCanonicalizationPhase.h: Added. + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPhantomRemovalPhase.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lowJSValue): + (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): + + 2014-07-22 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Get rid of structure checks as a way of checking if a function is in fact a function + https://bugs.webkit.org/show_bug.cgi?id=135146 + + Reviewed by Oliver Hunt. + + This greatly simplifies our closure call optimizations by taking advantage of the type + bits available in the cell header. + + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::visitWeak): + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::dump): + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::executable): + (JSC::CallLinkStatus::structure): Deleted. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitFunctionChecks): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::observeUseKindOnNode): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::checkArray): + (JSC::DFG::SpeculativeJIT::speculateCellTypeWithoutTypeFiltering): + (JSC::DFG::SpeculativeJIT::speculateCellType): + (JSC::DFG::SpeculativeJIT::speculateFunction): + (JSC::DFG::SpeculativeJIT::speculateFinalObject): + (JSC::DFG::SpeculativeJIT::speculate): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + (JSC::DFG::isCell): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCheckExecutable): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::isFunction): + (JSC::FTL::LowerDFGToLLVM::isNotFunction): + (JSC::FTL::LowerDFGToLLVM::speculateFunction): + * jit/ClosureCallStubRoutine.cpp: + (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine): + (JSC::ClosureCallStubRoutine::markRequiredObjectsInternal): + * jit/ClosureCallStubRoutine.h: + (JSC::ClosureCallStubRoutine::structure): Deleted. + * jit/JIT.h: + (JSC::JIT::compileClosureCall): Deleted. + * jit/JITCall.cpp: + (JSC::JIT::privateCompileClosureCall): Deleted. + * jit/JITCall32_64.cpp: + (JSC::JIT::privateCompileClosureCall): Deleted. + * jit/JITOperations.cpp: + * jit/Repatch.cpp: + (JSC::linkClosureCall): + * jit/Repatch.h: + +2014-08-06 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + [ARM] Incorrect handling of Unicode characters + https://bugs.webkit.org/show_bug.cgi?id=135380 + + Reviewed by Darin Adler. + + Removed erroneous fast case from stringFromUTF(), since it assumed that + char is always implemented as signed. + + * jsc.cpp: + (stringFromUTF): + +2014-08-06 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + [JSC] Build fix for FTL on EFL after ftlopt merge + https://bugs.webkit.org/show_bug.cgi?id=135565 + + Reviewed by Mark Lam. + + Adding an enable guard for native inlining, since it now requires the bitcode + emitted from Clang, and we don't have a good way of creating it from other compilers. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * ftl/FTLState.cpp: + (JSC::FTL::State::State): + * ftl/FTLState.h: + +2014-08-05 Csaba Osztrogonác <ossy@webkit.org> + + URTBF after r172129. (ftlopt branch merge) + + Remove the duplicated friend declaration to fix this build failure: + "error: âJSC::Structureâ is already a friend of âJSC::StructureRareDataâ [-Werror]" + + * runtime/StructureRareData.h: + +2014-08-05 Filip Pizlo <fpizlo@apple.com> + + Attempt to fix CMake-based builds, part 3. + + * CMakeLists.txt: + +2014-08-05 Filip Pizlo <fpizlo@apple.com> + + Attempt to fix CMake-based builds, part 2. + + * CMakeLists.txt: + +2014-08-05 Filip Pizlo <fpizlo@apple.com> + + Attempt to fix Windows build, part 2. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + +2014-08-05 Filip Pizlo <fpizlo@apple.com> + + Attempt to fix CMake-based builds. + + * CMakeLists.txt: + +2014-08-05 Filip Pizlo <fpizlo@apple.com> + + Attempt to fix Windows build. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + +2014-08-05 Filip Pizlo <fpizlo@apple.com> + + Fix cloop build. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::jettison): + +2014-07-29 Filip Pizlo <fpizlo@apple.com> + + Merge r170564, r170571, r170604, r170628, r170672, r170680, r170724, r170728, r170729, r170819, r170821, r170836, r170855, r170860, r170890, r170907, r170929, r171052, r171106, r171152, r171153, r171214 from ftlopt. + + This part of the merge delivers roughly a 2% across-the-board performance + improvement, mostly due to immutable property inference and DFG-side GCSE. It also + almost completely resolves accessor performance issues; in the common case the DFG + will compile a getter/setter access into code that is just as efficient as a normal + property access. + + Another major highlight of this part of the merge is the work to add a type profiler + to the inspector. This work is still on-going but this greatly increases coverage. + + Note that this merge fixes a minor bug in the GetterSetter refactoring from + http://trac.webkit.org/changeset/170729 (https://bugs.webkit.org/show_bug.cgi?id=134518). + It also adds a new tests to tests/stress to cover that bug. That bug was previously only + covered by layout tests. + + 2014-07-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG Flush(SetLocal) store elimination is overzealous for captured variables in the presence of nodes that have no effects but may throw (merge trunk r171190) + https://bugs.webkit.org/show_bug.cgi?id=135019 + + Reviewed by Oliver Hunt. + + Behaviorally, this is just a merge of trunk r171190, except that the relevant functionality + has moved to StrengthReductionPhase and is written in a different style. Same algorithm, + different code. + + * dfg/DFGNodeType.h: + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * tests/stress/capture-escape-and-throw.js: Added. + (foo.f): + (foo): + * tests/stress/new-array-with-size-throw-exception-and-tear-off-arguments.js: Added. + (foo): + (bar): + + 2014-07-15 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Constant fold GetGetter and GetSetter if the GetterSetter is a constant + https://bugs.webkit.org/show_bug.cgi?id=134962 + + Reviewed by Oliver Hunt. + + This removes yet another steady-state-throughput implication of using getters and setters: + if your accessor call is monomorphic then you'll just get a structure check, nothing more. + No more loads to get to the GetterSetter object or the accessor function object. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * runtime/GetterSetter.h: + (JSC::GetterSetter::getterConcurrently): + (JSC::GetterSetter::setGetter): + (JSC::GetterSetter::setterConcurrently): + (JSC::GetterSetter::setSetter): + + 2014-07-15 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Identity replacement in CSE shouldn't create a Phantom over the Identity's children + https://bugs.webkit.org/show_bug.cgi?id=134893 + + Reviewed by Oliver Hunt. + + Replace Identity with Check instead of Phantom. Phantom means that the child of the + Identity should be unconditionally live. The liveness semantics of Identity are such that + if the parents of Identity are live then the child is live. Removing the Identity entirely + preserves such liveness semantics. So, the only thing that should be left behind is the + type check on the child, which is what Check means: do the check but don't keep the child + alive if the check isn't needed. + + * dfg/DFGCSEPhase.cpp: + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToCheck): + + 2014-07-13 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG should be able to do GCSE in SSA and this should be unified with the CSE in CPS, and both of these things should use abstract heaps for reasoning about effects + https://bugs.webkit.org/show_bug.cgi?id=134677 + + Reviewed by Sam Weinig. + + This removes the old local CSE phase, which was based on manually written backward-search + rules for all of the different kinds of things we cared about, and adds a new local/global + CSE (local for CPS and global for SSA) that leaves the node semantics almost entirely up to + clobberize(). Thus, the CSE phase itself just worries about the algorithms and data + structures used for storing sets of available values. This results in a large reduction in + code size in CSEPhase.cpp while greatly increasing the phase's power (since it now does + global CSE) and reducing compile time (since local CSE is now rewritten to use smarter data + structures). Even though LLVM was already running GVN, the extra GCSE at DFG IR level means + that this is a significant (~0.7%) throughput improvement. + + This work is based on the concept of "def" to clobberize(). If clobberize() calls def(), it + means that the node being analyzed makes available some value in some DFG node, and that + future attempts to compute that value can simply use that node. In other words, it + establishes an available value mapping of the form value=>node. There are two kinds of + values that can be passed to def(): + + PureValue. This captures everything needed to determine whether two pure nodes - nodes that + neither read nor write, and produce a value that is a CSE candidate - are identical. It + carries the NodeType, an AdjacencyList, and one word of meta-data. The meta-data is + usually used for things like the arithmetic mode or constant pointer. Passing a + PureValue to def() means that the node produces a value that is valid anywhere that the + node dominates. + + HeapLocation. This describes a location in the heap that could be written to or read from. + Both stores and loads can def() a HeapLocation. HeapLocation carries around an abstract + heap that both serves as part of the "name" of the heap location (together with the + other fields of HeapLocation) and also tells us what write()'s to watch for. If someone + write()'s to an abstract heap that overlaps the heap associated with the HeapLocation, + then it means that the values for that location are no longer available. + + This approach is sufficiently clever that the CSEPhase itself can focus on the mechanism of + tracking the PureValue=>node and HeapLocation=>node maps, without having to worry about + interpreting the semantics of different DFG node types - that is now almost entirely in + clobberize(). The only things we special-case inside CSEPhase are the Identity node, which + CSE is traditionally responsible for eliminating even though it has nothing to do with CSE, + and the LocalCSE rule for turning PutByVal into PutByValAlias. + + This is a slight Octane, SunSpider, and Kraken speed-up - all somewhere arond 0.7% . It's + not a bigger win because LLVM was already giving us most of what we needed in its GVN. + Also, the SunSpider speed-up isn't from GCSE as much as it's a clean-up of local CSE - that + is no longer O(n^2). Basically this is purely good: it reduces the amount of LLVM IR we + generate, it removes the old CSE's heap modeling (which was a constant source of bugs), and + it improves both the quality of the code we generate and the speed with which we generate + it. Also, any future optimizations that depend on GCSE will now be easier to implement. + + During the development of this patch I also rationalized some other stuff, like Graph's + ordered traversals - we now have preorder and postorder rather than just "depth first". + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractHeap.h: + * dfg/DFGAdjacencyList.h: + (JSC::DFG::AdjacencyList::hash): + (JSC::DFG::AdjacencyList::operator==): + * dfg/DFGBasicBlock.h: + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::performLocalCSE): + (JSC::DFG::performGlobalCSE): + (JSC::DFG::CSEPhase::CSEPhase): Deleted. + (JSC::DFG::CSEPhase::run): Deleted. + (JSC::DFG::CSEPhase::endIndexForPureCSE): Deleted. + (JSC::DFG::CSEPhase::pureCSE): Deleted. + (JSC::DFG::CSEPhase::constantCSE): Deleted. + (JSC::DFG::CSEPhase::constantStoragePointerCSE): Deleted. + (JSC::DFG::CSEPhase::getCalleeLoadElimination): Deleted. + (JSC::DFG::CSEPhase::getArrayLengthElimination): Deleted. + (JSC::DFG::CSEPhase::globalVarLoadElimination): Deleted. + (JSC::DFG::CSEPhase::scopedVarLoadElimination): Deleted. + (JSC::DFG::CSEPhase::varInjectionWatchpointElimination): Deleted. + (JSC::DFG::CSEPhase::getByValLoadElimination): Deleted. + (JSC::DFG::CSEPhase::checkFunctionElimination): Deleted. + (JSC::DFG::CSEPhase::checkExecutableElimination): Deleted. + (JSC::DFG::CSEPhase::checkStructureElimination): Deleted. + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): Deleted. + (JSC::DFG::CSEPhase::getByOffsetLoadElimination): Deleted. + (JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination): Deleted. + (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination): Deleted. + (JSC::DFG::CSEPhase::checkArrayElimination): Deleted. + (JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination): Deleted. + (JSC::DFG::CSEPhase::getInternalFieldLoadElimination): Deleted. + (JSC::DFG::CSEPhase::getMyScopeLoadElimination): Deleted. + (JSC::DFG::CSEPhase::getLocalLoadElimination): Deleted. + (JSC::DFG::CSEPhase::invalidationPointElimination): Deleted. + (JSC::DFG::CSEPhase::setReplacement): Deleted. + (JSC::DFG::CSEPhase::eliminate): Deleted. + (JSC::DFG::CSEPhase::performNodeCSE): Deleted. + (JSC::DFG::CSEPhase::performBlockCSE): Deleted. + (JSC::DFG::performCSE): Deleted. + * dfg/DFGCSEPhase.h: + * dfg/DFGClobberSet.cpp: + (JSC::DFG::addReads): + (JSC::DFG::addWrites): + (JSC::DFG::addReadsAndWrites): + (JSC::DFG::readsOverlap): + (JSC::DFG::writesOverlap): + * dfg/DFGClobberize.cpp: + (JSC::DFG::doesWrites): + (JSC::DFG::accessesOverlap): + (JSC::DFG::writesOverlap): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + (JSC::DFG::NoOpClobberize::operator()): + (JSC::DFG::CheckClobberize::operator()): + (JSC::DFG::ReadMethodClobberize::ReadMethodClobberize): + (JSC::DFG::ReadMethodClobberize::operator()): + (JSC::DFG::WriteMethodClobberize::WriteMethodClobberize): + (JSC::DFG::WriteMethodClobberize::operator()): + (JSC::DFG::DefMethodClobberize::DefMethodClobberize): + (JSC::DFG::DefMethodClobberize::operator()): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + (JSC::DFG::DCEPhase::fixupBlock): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::getBlocksInPreOrder): + (JSC::DFG::Graph::getBlocksInPostOrder): + (JSC::DFG::Graph::addForDepthFirstSort): Deleted. + (JSC::DFG::Graph::getBlocksInDepthFirstOrder): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGHeapLocation.cpp: Added. + (JSC::DFG::HeapLocation::dump): + (WTF::printInternal): + * dfg/DFGHeapLocation.h: Added. + (JSC::DFG::HeapLocation::HeapLocation): + (JSC::DFG::HeapLocation::operator!): + (JSC::DFG::HeapLocation::kind): + (JSC::DFG::HeapLocation::heap): + (JSC::DFG::HeapLocation::base): + (JSC::DFG::HeapLocation::index): + (JSC::DFG::HeapLocation::hash): + (JSC::DFG::HeapLocation::operator==): + (JSC::DFG::HeapLocation::isHashTableDeletedValue): + (JSC::DFG::HeapLocationHash::hash): + (JSC::DFG::HeapLocationHash::equal): + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::run): + * dfg/DFGNode.h: + (JSC::DFG::Node::replaceWith): + (JSC::DFG::Node::convertToPhantomUnchecked): Deleted. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPureValue.cpp: Added. + (JSC::DFG::PureValue::dump): + * dfg/DFGPureValue.h: Added. + (JSC::DFG::PureValue::PureValue): + (JSC::DFG::PureValue::operator!): + (JSC::DFG::PureValue::op): + (JSC::DFG::PureValue::children): + (JSC::DFG::PureValue::info): + (JSC::DFG::PureValue::hash): + (JSC::DFG::PureValue::operator==): + (JSC::DFG::PureValue::isHashTableDeletedValue): + (JSC::DFG::PureValueHash::hash): + (JSC::DFG::PureValueHash::equal): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + + 2014-07-13 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, revert unintended change in r171051. + + * dfg/DFGCSEPhase.cpp: + + 2014-07-08 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Move Flush(SetLocal) store elimination to StrengthReductionPhase + https://bugs.webkit.org/show_bug.cgi?id=134739 + + Reviewed by Mark Hahnenberg. + + I'm going to streamline CSE around clobberize() as part of + https://bugs.webkit.org/show_bug.cgi?id=134677, and so Flush(SetLocal) store + elimination wouldn't belong in CSE anymore. It doesn't quite belong anywhere, which + means that it belongs in StrengthReductionPhase, since that's intended to be our + dumping ground. + + To do this I had to add some missing smarts to clobberize(). Previously clobberize() + could play a bit loose with reads of Variables because it wasn't used for store + elimination. The main client of read() was LICM, but it would only use it to + determine hoistability and anything that did a write() was not hoistable - so, we had + benign (but still wrong) missing read() calls in places that did write()s. This fixes + a bunch of those cases. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::setLocalStoreElimination): Deleted. + * dfg/DFGClobberize.cpp: + (JSC::DFG::accessesOverlap): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): Make clobberize() smart enough for detecting when this store elimination would be sound. + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): Implement the store elimination in terms of clobberize(). + + 2014-07-08 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Phantom simplification should be in its own phase + https://bugs.webkit.org/show_bug.cgi?id=134742 + + Reviewed by Geoffrey Garen. + + This moves Phantom simplification out of CSE, which greatly simplifies CSE and gives it + more focus. Also this finally adds a phase that removes empty Phantoms. We sort of had + this in CPSRethreading, but that phase runs too infrequently and doesn't run at all for + SSA. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAdjacencyList.h: + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::run): + (JSC::DFG::CSEPhase::setReplacement): + (JSC::DFG::CSEPhase::eliminate): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::eliminateIrrelevantPhantomChildren): Deleted. + * dfg/DFGPhantomRemovalPhase.cpp: Added. + (JSC::DFG::PhantomRemovalPhase::PhantomRemovalPhase): + (JSC::DFG::PhantomRemovalPhase::run): + (JSC::DFG::performCleanUp): + * dfg/DFGPhantomRemovalPhase.h: Added. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + + 2014-07-08 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Get rid of Node::misc by moving the fields out of the union so that you can use replacement and owner simultaneously + https://bugs.webkit.org/show_bug.cgi?id=134730 + + Reviewed by Mark Lam. + + This will allow for a better GCSE implementation. + + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::canonicalizeGetLocalFor): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::setReplacement): + * dfg/DFGEdgeDominates.h: + (JSC::DFG::EdgeDominates::operator()): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::clearReplacements): + (JSC::DFG::Graph::initializeNodeOwners): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::performSubstitutionForEdge): + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGNode.h: + (JSC::DFG::Node::Node): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + + 2014-07-04 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Infer immutable object properties + https://bugs.webkit.org/show_bug.cgi?id=134567 + + Reviewed by Mark Hahnenberg. + + This introduces a new way of inferring immutable object properties. A property is said to + be immutable if after its creation (i.e. the transition that creates it), we never + overwrite it (i.e. replace it) or delete it. Immutability is a property of an "own + property" - so if we say that "f" is immutable at "o" then we are implying that "o" has "f" + directly and not on a prototype. More specifically, the immutability inference will prove + that a property on some structure is immutable. This means that, for example, we may have a + structure S1 with property "f" where we claim that "f" at S1 is immutable, but S1 has a + transition to S2 that adds a new property "g" and we may claim that "f" at S2 is actually + mutable. This is mainly for convenience; it allows us to decouple immutability logic from + transition logic. Immutability can be used to constant-fold accesses to objects at + DFG-time. The DFG needs to prove the following to constant-fold the access: + + - The base of the access must be a constant object pointer. We prove that a property at a + structure is immutable, but that says nothing of its value; each actual instance of that + property may have a different value. So, a constant object pointer is needed to get an + actual constant instance of the immutable value. + + - A check (or watchpoint) must have been emitted proving that the object has a structure + that allows loading the property in question. + + - The replacement watchpoint set of the property in the structure that we've proven the + object to have is still valid and we add a watchpoint to it lazily. The replacement + watchpoint set is the key new mechanism that this change adds. It's possible that we have + proven that the object has one of many structures, in which case each of those structures + needs a valid replacement watchpoint set. + + The replacement watchpoint set is created the first time that any access to the property is + cached. A put replace cache will create, and immediately invalidate, the watchpoint set. A + get cache will create the watchpoint set and make it start watching. Any non-cached put + access will invalidate the watchpoint set if one had been created; the underlying algorithm + ensures that checking for the existence of a replacement watchpoint set is very fast in the + common case. This algorithm ensures that no cached access needs to ever do any work to + invalidate, or check the validity of, any replacement watchpoint sets. It also has some + other nice properties: + + - It's very robust in its definition of immutability. The strictest that it will ever be is + that for any instance of the object, the property must be written to only once, + specifically at the time that the property is created. But it's looser than this in + practice. For example, the property may be written to any number of times before we add + the final property that the object will have before anyone reads the property; this works + since for optimization purposes we only care if we detect immutability on the structure + that the object will have when it is most frequently read from, not any previous + structure that the object had. Also, we may write to the property any number of times + before anyone caches accesses to it. + + - It is mostly orthogonal to structure transitions. No new structures need to be created to + track the immutability of a property. Hence, there is no risk from this feature causing + more polymorphism. This is different from the previous "specificValue" constant + inference, which did cause additional structures to be created and sometimes those + structures led to fake polymorphism. This feature does leverage existing transitions to + do some of the watchpointing: property deletions don't fire the replacement watchpoint + set because that would cause a new structure and so the mandatory structure check would + fail. Also, this feature is guaranteed to never kick in for uncacheable dictionaries + because those wouldn't allow for cacheable accesses - and it takes a cacheable access for + this feature to be enabled. + + - No memory overhead is incurred except when accesses to the property are cached. + Dictionary properties will typically have no meta-data for immutability. The number of + replacement watchpoint sets we allocate is proportional to the number of inline caches in + the program, which is typically must smaller than the number of structures or even the + number of objects. + + This inference is far more powerful than the previous "specificValue" inference, so this + change also removes all of that code. It's interesting that the amount of code that is + changed to remove that feature is almost as big as the amount of code added to support the + new inference - and that's if you include the new tests in the tally. Without new tests, + it appears that the new feature actually touches less code! + + There is one corner case where the previous "specificValue" inference was more powerful. + You can imagine someone creating objects with functions as self properties on those + objects, such that each object instance had the same function pointers - essentially, + someone might be trying to create a vtable but failing at the whole "one vtable for many + instances" concept. The "specificValue" inference would do very well for such programs, + because a structure check would be sufficient to prove a constant value for all of the + function properties. This new inference will fail because it doesn't track the constant + values of constant properties; instead it detects the immutability of otherwise variable + properties (in the sense that each instance of the property may have a different value). + So, the new inference requires having a particular object instance to actually get the + constant value. I think it's OK to lose this antifeature. It took a lot of code to support + and was a constant source of grief in our transition logic, and there doesn't appear to be + any real evidence that programs benefited from that particular kind of inference since + usually it's the singleton prototype instance that has all of the functions. + + This change is a speed-up on everything. date-format-xparb and both SunSpider/raytrace and + V8/raytrace seem to be the biggest winners among the macrobenchmarks; they see >5% + speed-ups. Many of our microbenchmarks see very large performance improvements, even 80% in + one case. + + * bytecode/ComplexGetStatus.cpp: + (JSC::ComplexGetStatus::computeFor): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + (JSC::GetByIdStatus::computeForStubInfo): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::GetByIdVariant): + (JSC::GetByIdVariant::operator=): + (JSC::GetByIdVariant::attemptToMerge): + (JSC::GetByIdVariant::dumpInContext): + * bytecode/GetByIdVariant.h: + (JSC::GetByIdVariant::alternateBase): + (JSC::GetByIdVariant::specificValue): Deleted. + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::operator=): + (JSC::PutByIdVariant::setter): + (JSC::PutByIdVariant::dumpInContext): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::specificValue): Deleted. + * bytecode/Watchpoint.cpp: + (JSC::WatchpointSet::fireAllSlow): + (JSC::WatchpointSet::fireAll): Deleted. + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::fireAll): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetByOffset): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::isStringPrototypeMethodSane): + (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetConstantProperty): + (JSC::DFG::Graph::visitChildren): + * dfg/DFGGraph.h: + * dfg/DFGWatchableStructureWatchingPhase.cpp: + (JSC::DFG::WatchableStructureWatchingPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + * jit/JITOperations.cpp: + * jit/Repatch.cpp: + (JSC::repatchByIdSelfAccess): + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (JSC::LLInt::putToScopeCommon): + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::tryCachePutToScopeGlobal): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::mayInterceptStoreTo): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitive): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::defaultValue): + (JSC::getCallableObjectSlow): Deleted. + (JSC::JSObject::getPropertySpecificValue): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::getDirect): + (JSC::JSObject::getDirectOffset): + (JSC::JSObject::inlineGetOwnPropertySlot): + (JSC::JSObject::putDirectInternal): + (JSC::JSObject::putOwnDataProperty): + (JSC::JSObject::putDirect): + (JSC::JSObject::putDirectWithoutTransition): + (JSC::getCallableObject): Deleted. + * runtime/JSScope.cpp: + (JSC::abstractAccess): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyMapEntry::PropertyMapEntry): + (JSC::PropertyTable::copy): + * runtime/PropertyTable.cpp: + (JSC::PropertyTable::clone): + (JSC::PropertyTable::PropertyTable): + (JSC::PropertyTable::visitChildren): Deleted. + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::addPropertyTransitionToExistingStructureImpl): + (JSC::Structure::addPropertyTransitionToExistingStructure): + (JSC::Structure::addPropertyTransitionToExistingStructureConcurrently): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::changePrototypeTransition): + (JSC::Structure::attributeChangeTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::takePropertyTableOrCloneIfPinned): + (JSC::Structure::nonPropertyTransition): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::allocateRareData): + (JSC::Structure::ensurePropertyReplacementWatchpointSet): + (JSC::Structure::startWatchingPropertyForReplacements): + (JSC::Structure::didCachePropertyReplacement): + (JSC::Structure::startWatchingInternalProperties): + (JSC::Structure::copyPropertyTable): + (JSC::Structure::copyPropertyTableForPinning): + (JSC::Structure::getConcurrently): + (JSC::Structure::get): + (JSC::Structure::add): + (JSC::Structure::visitChildren): + (JSC::Structure::prototypeChainMayInterceptStoreTo): + (JSC::Structure::dump): + (JSC::Structure::despecifyDictionaryFunction): Deleted. + (JSC::Structure::despecifyFunctionTransition): Deleted. + (JSC::Structure::despecifyFunction): Deleted. + (JSC::Structure::despecifyAllFunctions): Deleted. + (JSC::Structure::putSpecificValue): Deleted. + * runtime/Structure.h: + (JSC::Structure::startWatchingPropertyForReplacements): + (JSC::Structure::startWatchingInternalPropertiesIfNecessary): + (JSC::Structure::startWatchingInternalPropertiesIfNecessaryForEntireChain): + (JSC::Structure::transitionDidInvolveSpecificValue): Deleted. + (JSC::Structure::disableSpecificFunctionTracking): Deleted. + * runtime/StructureInlines.h: + (JSC::Structure::getConcurrently): + (JSC::Structure::didReplaceProperty): + (JSC::Structure::propertyReplacementWatchpointSet): + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::destroy): + * runtime/StructureRareData.h: + * tests/stress/infer-constant-global-property.js: Added. + (foo.Math.sin): + (foo): + * tests/stress/infer-constant-property.js: Added. + (foo): + * tests/stress/jit-cache-poly-replace-then-cache-get-and-fold-then-invalidate.js: Added. + (foo): + (bar): + * tests/stress/jit-cache-replace-then-cache-get-and-fold-then-invalidate.js: Added. + (foo): + (bar): + * tests/stress/jit-put-to-scope-global-cache-watchpoint-invalidate.js: Added. + (foo): + (bar): + * tests/stress/llint-cache-replace-then-cache-get-and-fold-then-invalidate.js: Added. + (foo): + (bar): + * tests/stress/llint-put-to-scope-global-cache-watchpoint-invalidate.js: Added. + (foo): + (bar): + * tests/stress/repeat-put-to-scope-global-with-same-value-watchpoint-invalidate.js: Added. + (foo): + (bar): + + 2014-07-03 Saam Barati <sbarati@apple.com> + + Add more coverage for the profile_types_with_high_fidelity op code. + https://bugs.webkit.org/show_bug.cgi?id=134616 + + Reviewed by Filip Pizlo. + + More operations are now being recorded by the profile_types_with_high_fidelity + opcode. Specifically: function parameters, function return values, + function 'this' value, get_by_id, get_by_value, resolve nodes, function return + values at the call site. Added more flags to the profile_types_with_high_fidelity + opcode so more focused tasks can take place when the instruction is + being linked in CodeBlock. Re-worked the type profiler to search + through character offset ranges when asked for the type of an expression + at a given offset. Removed redundant calls to Structure::toStructureShape + in HighFidelityLog and TypeSet by caching calls based on StructureID. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::scopeDependentProfile): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::returnStatementTypeSet): + * bytecode/TypeLocation.h: + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::highFidelityTypeProfileExpressionInfoForBytecodeOffset): + (JSC::UnlinkedCodeBlock::addHighFidelityTypeProfileExpressionInfo): + * bytecode/UnlinkedCodeBlock.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): + (JSC::BytecodeGenerator::emitGetFromScopeWithProfile): + (JSC::BytecodeGenerator::emitPutToScope): + (JSC::BytecodeGenerator::emitPutToScopeWithProfile): + (JSC::BytecodeGenerator::emitPutById): + (JSC::BytecodeGenerator::emitPutByVal): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitHighFidelityTypeProfilingExpressionInfo): + * bytecompiler/NodesCodegen.cpp: + (JSC::ResolveNode::emitBytecode): + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::FunctionCallValueNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::FunctionCallBracketNode::emitBytecode): + (JSC::FunctionCallDotNode::emitBytecode): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::PostfixNode::emitBracket): + (JSC::PostfixNode::emitDot): + (JSC::PrefixNode::emitResolve): + (JSC::PrefixNode::emitBracket): + (JSC::PrefixNode::emitDot): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::AssignDotNode::emitBytecode): + (JSC::ReadModifyDotNode::emitBytecode): + (JSC::AssignBracketNode::emitBytecode): + (JSC::ReadModifyBracketNode::emitBytecode): + (JSC::ReturnNode::emitBytecode): + (JSC::FunctionBodyNode::emitBytecode): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableAtOffset): + (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange): Deleted. + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getFromScopeCommon): + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * runtime/HighFidelityLog.cpp: + (JSC::HighFidelityLog::processHighFidelityLog): + (JSC::HighFidelityLog::actuallyProcessLogThreadFunction): + (JSC::HighFidelityLog::recordTypeInformationForLocation): Deleted. + * runtime/HighFidelityLog.h: + (JSC::HighFidelityLog::recordTypeInformationForLocation): + * runtime/HighFidelityTypeProfiler.cpp: + (JSC::HighFidelityTypeProfiler::getTypesForVariableInAtOffset): + (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableAtOffset): + (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableAtOffset): + (JSC::HighFidelityTypeProfiler::insertNewLocation): + (JSC::HighFidelityTypeProfiler::findLocation): + (JSC::HighFidelityTypeProfiler::getTypesForVariableInRange): Deleted. + (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableInRange): Deleted. + (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableInRange): Deleted. + (JSC::HighFidelityTypeProfiler::getLocationBasedHash): Deleted. + * runtime/HighFidelityTypeProfiler.h: + (JSC::LocationKey::LocationKey): Deleted. + (JSC::LocationKey::hash): Deleted. + (JSC::LocationKey::operator==): Deleted. + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + * runtime/Structure.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::TypeSet): + (JSC::TypeSet::addTypeForValue): + (JSC::TypeSet::seenTypes): + (JSC::TypeSet::removeDuplicatesInStructureHistory): Deleted. + * runtime/TypeSet.h: + (JSC::StructureShape::setConstructorName): + * runtime/VM.cpp: + (JSC::VM::getTypesForVariableAtOffset): + (JSC::VM::dumpHighFidelityProfilingTypes): + (JSC::VM::getTypesForVariableInRange): Deleted. + * runtime/VM.h: + + 2014-07-04 Filip Pizlo <fpizlo@apple.com> + + [ftlopt][REGRESSION] debug tests fail because PutByIdDirect is now implemented in terms of In + https://bugs.webkit.org/show_bug.cgi?id=134642 + + Rubber stamped by Andreas Kling. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + + 2014-07-01 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Allocate a new GetterSetter if we change the value of any of its entries other than when they were previously null, so that if we constant-infer an accessor slot then we immediately get the function constant for free + https://bugs.webkit.org/show_bug.cgi?id=134518 + + Reviewed by Mark Hahnenberg. + + This has no real effect right now, particularly since almost all uses of + setSetter/setGetter were already allocating a branch new GetterSetter. But once we start + doing more aggressive constant property inference, this change will allow us to remove + all runtime checks from getter/setter calls. + + * runtime/GetterSetter.cpp: + (JSC::GetterSetter::withGetter): + (JSC::GetterSetter::withSetter): + * runtime/GetterSetter.h: + (JSC::GetterSetter::setGetter): + (JSC::GetterSetter::setSetter): + * runtime/JSObject.cpp: + (JSC::JSObject::defineOwnNonIndexProperty): + + 2014-07-02 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Rename notifyTransitionFromThisStructure to didTransitionFromThisStructure + + Rubber stamped by Mark Hahnenberg. + + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::nonPropertyTransition): + (JSC::Structure::didTransitionFromThisStructure): + (JSC::Structure::notifyTransitionFromThisStructure): Deleted. + * runtime/Structure.h: + + 2014-07-02 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Remove the functionality for cloning StructureRareData since we never do that anymore. + + Rubber stamped by Mark Hahnenberg. + + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::cloneRareDataFrom): Deleted. + * runtime/Structure.h: + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::clone): Deleted. + (JSC::StructureRareData::StructureRareData): Deleted. + * runtime/StructureRareData.h: + (JSC::StructureRareData::needsCloning): Deleted. + + 2014-07-01 Mark Lam <mark.lam@apple.com> + + [ftlopt] DebuggerCallFrame::scope() should return a DebuggerScope. + <https://webkit.org/b/134420> + + Reviewed by Geoffrey Garen. + + Previously, DebuggerCallFrame::scope() returns a JSActivation (and relevant + peers) which the WebInspector will use to introspect CallFrame variables. + Instead, we should be returning a DebuggerScope as an abstraction layer that + provides the introspection functionality that the WebInspector needs. This + is the first step towards not forcing every frame to have a JSActivation + object just because the debugger is enabled. + + 1. Instantiate the debuggerScopeStructure as a member of the JSGlobalObject + instead of the VM. This allows JSObject::globalObject() to be able to + return the global object for the DebuggerScope. + + 2. On the DebuggerScope's life-cycle management: + + The DebuggerCallFrame is designed to be "valid" only during a debugging session + (while the debugger is broken) through the use of a DebuggerCallFrameScope in + Debugger::pauseIfNeeded(). Once the debugger resumes from the break, the + DebuggerCallFrameScope destructs, and the DebuggerCallFrame will be invalidated. + We can't guarantee (from this code alone) that the Inspector code isn't still + holding a ref to the DebuggerCallFrame (though they shouldn't), but by contract, + the frame will be invalidated, and any attempt to query it will return null values. + This is pre-existing behavior. + + Now, we're adding the DebuggerScope into the picture. While a single debugger + pause session is in progress, the Inspector may request the scope from the + DebuggerCallFrame. While the DebuggerCallFrame is still valid, we want + DebuggerCallFrame::scope() to always return the same DebuggerScope object. + This is why we hold on to the DebuggerScope with a strong ref. + + If we use a weak ref instead, the following cooky behavior can manifest: + 1. The Inspector calls Debugger::scope() to get the top scope. + 2. The Inspector iterates down the scope chain and is now only holding a + reference to a parent scope. It is no longer referencing the top scope. + 3. A GC occurs, and the DebuggerCallFrame's weak m_scope ref to the top scope + gets cleared. + 4. The Inspector calls DebuggerCallFrame::scope() to get the top scope again but gets + a different DebuggerScope instance. + 5. The Inspector iterates down the scope chain but never sees the parent scope + instance that retained a ref to in step 2 above. This is because when iterating + this new DebuggerScope instance (which has no knowledge of the previous parent + DebuggerScope instance), a new DebuggerScope instance will get created for the + same parent scope. + + Since the DebuggerScope is a JSObject, it's liveness is determined by its reachability. + However, it's "validity" is determined by the life-cycle of its owner DebuggerCallFrame. + When the owner DebuggerCallFrame gets invalidated, its debugger scope chain (if + instantiated) will also get invalidated. This is why we need the + DebuggerScope::invalidateChain() method. The Inspector should not be using the + DebuggerScope instance after its owner DebuggerCallFrame is invalidated. If it does, + those methods will do nothing or returned a failed status. + + * debugger/Debugger.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::scope): + (JSC::DebuggerCallFrame::evaluate): + (JSC::DebuggerCallFrame::invalidate): + (JSC::DebuggerCallFrame::vm): + (JSC::DebuggerCallFrame::lexicalGlobalObject): + * debugger/DebuggerCallFrame.h: + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::DebuggerScope): + (JSC::DebuggerScope::finishCreation): + (JSC::DebuggerScope::visitChildren): + (JSC::DebuggerScope::className): + (JSC::DebuggerScope::getOwnPropertySlot): + (JSC::DebuggerScope::put): + (JSC::DebuggerScope::deleteProperty): + (JSC::DebuggerScope::getOwnPropertyNames): + (JSC::DebuggerScope::defineOwnProperty): + (JSC::DebuggerScope::next): + (JSC::DebuggerScope::invalidateChain): + (JSC::DebuggerScope::isWithScope): + (JSC::DebuggerScope::isGlobalScope): + (JSC::DebuggerScope::isFunctionScope): + * debugger/DebuggerScope.h: + (JSC::DebuggerScope::create): + (JSC::DebuggerScope::Iterator::Iterator): + (JSC::DebuggerScope::Iterator::get): + (JSC::DebuggerScope::Iterator::operator++): + (JSC::DebuggerScope::Iterator::operator==): + (JSC::DebuggerScope::Iterator::operator!=): + (JSC::DebuggerScope::isValid): + (JSC::DebuggerScope::jsScope): + (JSC::DebuggerScope::begin): + (JSC::DebuggerScope::end): + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::scopeType): + (Inspector::JSJavaScriptCallFrame::scopeChain): + * inspector/JavaScriptCallFrame.h: + (Inspector::JavaScriptCallFrame::scopeChain): + * inspector/ScriptDebugServer.cpp: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::debuggerScopeStructure): + * runtime/JSObject.h: + (JSC::JSObject::isWithScope): + * runtime/JSScope.h: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + + 2014-07-01 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG bytecode parser should turn PutById with nothing but a Setter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to + https://bugs.webkit.org/show_bug.cgi?id=130756 + + Reviewed by Oliver Hunt. + + The enables exposing the call to setters in the DFG, and then inlining it. Previously we + already supproted inlined-cached calls to setters from within put_by_id inline caches, + and the DFG could certainly emit such IC's. Now, if an IC had a setter call, then the DFG + will either emit the GetGetterSetterByOffset/GetSetter/Call combo, or it will do one + better and inline the call. + + A lot of the core functionality was already available from the previous work to inline + getters. So, there are some refactorings in this patch that move preexisting + functionality around. For example, the work to figure out how the DFG should go about + getting to what we call the "loaded value" - i.e. the GetterSetter object reference in + the case of accessors - is now shared in ComplexGetStatus, and both GetByIdStatus and + PutByIdStatus use it. This means that we can keep the safety checks common. This patch + also does additional refactorings in DFG::ByteCodeParser so that we can continue to reuse + handleCall() for all of the various kinds of calls we can now emit. + + 83% speed-up on getter-richards, 2% speed-up on box2d. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/ComplexGetStatus.cpp: Added. + (JSC::ComplexGetStatus::computeFor): + * bytecode/ComplexGetStatus.h: Added. + (JSC::ComplexGetStatus::ComplexGetStatus): + (JSC::ComplexGetStatus::skip): + (JSC::ComplexGetStatus::takesSlowPath): + (JSC::ComplexGetStatus::kind): + (JSC::ComplexGetStatus::attributes): + (JSC::ComplexGetStatus::specificValue): + (JSC::ComplexGetStatus::offset): + (JSC::ComplexGetStatus::chain): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::GetByIdVariant): + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::PutByIdAccess): + (JSC::PutByIdAccess::setter): + (JSC::PutByIdAccess::structure): + (JSC::PutByIdAccess::chainCount): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::makesCalls): + * bytecode/PutByIdStatus.h: + (JSC::PutByIdStatus::makesCalls): Deleted. + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::PutByIdVariant): + (JSC::PutByIdVariant::operator=): + (JSC::PutByIdVariant::replace): + (JSC::PutByIdVariant::transition): + (JSC::PutByIdVariant::setter): + (JSC::PutByIdVariant::writesStructures): + (JSC::PutByIdVariant::reallocatesStorage): + (JSC::PutByIdVariant::makesCalls): + (JSC::PutByIdVariant::dumpInContext): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::PutByIdVariant): + (JSC::PutByIdVariant::structure): + (JSC::PutByIdVariant::oldStructure): + (JSC::PutByIdVariant::alternateBase): + (JSC::PutByIdVariant::specificValue): + (JSC::PutByIdVariant::callLinkStatus): + (JSC::PutByIdVariant::replace): Deleted. + (JSC::PutByIdVariant::transition): Deleted. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parseBlock): + * jit/Repatch.cpp: + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::takesSlowPathInDFGForImpureProperty): + * runtime/IntendedStructureChain.h: + * tests/stress/exit-from-setter.js: Added. + * tests/stress/poly-chain-setter.js: Added. + (Cons): + (foo): + (test): + * tests/stress/poly-chain-then-setter.js: Added. + (Cons1): + (Cons2): + (foo): + (test): + * tests/stress/poly-setter-combo.js: Added. + (Cons1): + (Cons2): + (foo): + (test): + (.test): + * tests/stress/poly-setter-then-self.js: Added. + (foo): + (test): + (.test): + * tests/stress/weird-setter-counter.js: Added. + (foo): + (test): + * tests/stress/weird-setter-counter-syntactic.js: Added. + (foo): + (test): + + 2014-07-01 Matthew Mirman <mmirman@apple.com> + + Added an implementation of the "in" check to FTL. + https://bugs.webkit.org/show_bug.cgi?id=134508 + + Reviewed by Filip Pizlo. + + * ftl/FTLCapabilities.cpp: enabled compilation for "in" + (JSC::FTL::canCompile): ditto + * ftl/FTLCompile.cpp: + (JSC::FTL::generateCheckInICFastPath): added. + (JSC::FTL::fixFunctionBasedOnStackMaps): added case for CheckIn descriptors. + * ftl/FTLInlineCacheDescriptor.h: + (JSC::FTL::CheckInGenerator::CheckInGenerator): added. + (JSC::FTL::CheckInDescriptor::CheckInDescriptor): added. + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCheckIn): added. Currently larger than necessary. + * ftl/FTLInlineCacheSize.h: ditto + * ftl/FTLIntrinsicRepository.h: Added function type for operationInGeneric + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): added case for In. + (JSC::FTL::LowerDFGToLLVM::compileIn): added. + * ftl/FTLSlowPathCall.cpp: Added a callOperation for operationIn + (JSC::FTL::callOperation): ditto + * ftl/FTLSlowPathCall.h: ditto + * ftl/FTLState.h: Added a vector to hold CheckIn descriptors. + * jit/JITOperations.h: made operationIns internal. + * tests/stress/ftl-checkin.js: Added. + * tests/stress/ftl-checkin-variable.js: Added. + + 2014-06-30 Mark Hahnenberg <mhahnenberg@apple.com> + + CodeBlock::stronglyVisitWeakReferences should mark DFG::CommonData::weakStructureReferences + https://bugs.webkit.org/show_bug.cgi?id=134455 + + Reviewed by Geoffrey Garen. + + Otherwise we get hanging pointers which can cause us to die later. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::stronglyVisitWeakReferences): + + 2014-06-27 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Reduce the GC's influence on optimization decisions + https://bugs.webkit.org/show_bug.cgi?id=134427 + + Reviewed by Oliver Hunt. + + This is a slight speed-up on some platforms, that arises from a bunch of fixes that I made + while trying to make the GC keep more structures alive + (https://bugs.webkit.org/show_bug.cgi?id=128072). + + The fixes are, roughly: + + - If the GC clears an inline cache, then this no longer causes the IC to be forever + polymorphic. + + - If we exit in inlined code into a function that tries to OSR enter, then we jettison + sooner. + + - Some variables being uninitialized led to rage-recompilations. + + This is a pretty strong step in the direction of keeping more Structures alive and not + blowing away code just because a Structure died. But, it seems like there is still a slight + speed-up to be had from blowing away code that references dead Structures. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpAssumingJITType): + (JSC::shouldMarkTransition): + (JSC::CodeBlock::propagateTransitions): + (JSC::CodeBlock::determineLiveness): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::isSupportedForInlining): + (JSC::DFG::mightInlineFunctionForCall): + (JSC::DFG::mightInlineFunctionForClosureCall): + (JSC::DFG::mightInlineFunctionForConstruct): + * dfg/DFGCapabilities.h: + * dfg/DFGCommonData.h: + * dfg/DFGDesiredWeakReferences.cpp: + (JSC::DFG::DesiredWeakReferences::reallyAdd): + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::handleExitCounts): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * ftl/FTLForOSREntryJITCode.cpp: + (JSC::FTL::ForOSREntryJITCode::ForOSREntryJITCode): These variables being uninitialized is benign in terms of correctness but can sometimes cause rage-recompilations. For some reason it took this patch to reveal this. + * ftl/FTLOSREntry.cpp: + (JSC::FTL::prepareOSREntry): + * runtime/Executable.cpp: + (JSC::ExecutableBase::destroy): + (JSC::NativeExecutable::destroy): + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::ScriptExecutable::destroy): + (JSC::ScriptExecutable::installCode): + (JSC::EvalExecutable::EvalExecutable): + (JSC::ProgramExecutable::ProgramExecutable): + * runtime/Executable.h: + (JSC::ScriptExecutable::setDidTryToEnterInLoop): + (JSC::ScriptExecutable::didTryToEnterInLoop): + (JSC::ScriptExecutable::addressOfDidTryToEnterInLoop): + (JSC::ScriptExecutable::ScriptExecutable): Deleted. + * runtime/StructureInlines.h: + (JSC::Structure::storedPrototypeObject): + (JSC::Structure::storedPrototypeStructure): + + 2014-06-25 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] If a CodeBlock is jettisoned due to a watchpoint then it should be possible to figure out something about that watchpoint + https://bugs.webkit.org/show_bug.cgi?id=134333 + + Reviewed by Geoffrey Garen. + + This is engineered to provide loads of information to the profiler without incurring any + costs when the profiler is disabled. It's the oldest trick in the book: the thing that + fires the watchpoint doesn't actually create anything to describe the reason why it was + fired; instead it creates a stack-allocated FireDetail subclass instance. Only if the + FireDetail::dump() virtual method is called does anything happen. + + Currently we use this to produce very fine-grained data for Structure watchpoints and + some cases of variable watchpoints. For all other situations, the given reason is just a + string constant, by using StringFireDetail. If we find a situation where that string + constant is insufficient to diagnose an issue then we can change it to provide more + fine-grained information. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::jettison): + * bytecode/CodeBlock.h: + * bytecode/CodeBlockJettisoningWatchpoint.cpp: + (JSC::CodeBlockJettisoningWatchpoint::fireInternal): + * bytecode/CodeBlockJettisoningWatchpoint.h: + * bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp: Removed. + * bytecode/ProfiledCodeBlockJettisoningWatchpoint.h: Removed. + * bytecode/StructureStubClearingWatchpoint.cpp: + (JSC::StructureStubClearingWatchpoint::fireInternal): + * bytecode/StructureStubClearingWatchpoint.h: + * bytecode/VariableWatchpointSet.h: + (JSC::VariableWatchpointSet::invalidate): + (JSC::VariableWatchpointSet::finalizeUnconditionally): + * bytecode/VariableWatchpointSetInlines.h: + (JSC::VariableWatchpointSet::notifyWrite): + * bytecode/Watchpoint.cpp: + (JSC::StringFireDetail::dump): + (JSC::WatchpointSet::fireAll): + (JSC::WatchpointSet::fireAllSlow): + (JSC::WatchpointSet::fireAllWatchpoints): + (JSC::InlineWatchpointSet::fireAll): + * bytecode/Watchpoint.h: + (JSC::FireDetail::FireDetail): + (JSC::FireDetail::~FireDetail): + (JSC::StringFireDetail::StringFireDetail): + (JSC::Watchpoint::fire): + (JSC::WatchpointSet::fireAll): + (JSC::WatchpointSet::touch): + (JSC::WatchpointSet::invalidate): + (JSC::InlineWatchpointSet::fireAll): + (JSC::InlineWatchpointSet::touch): + * dfg/DFGCommonData.h: + * dfg/DFGOperations.cpp: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * jsc.cpp: + (WTF::Masquerader::create): + * profiler/ProfilerCompilation.cpp: + (JSC::Profiler::Compilation::setJettisonReason): + (JSC::Profiler::Compilation::toJS): + * profiler/ProfilerCompilation.h: + (JSC::Profiler::Compilation::setJettisonReason): Deleted. + * runtime/ArrayBuffer.cpp: + (JSC::ArrayBuffer::transfer): + * runtime/ArrayBufferNeuteringWatchpoint.cpp: + (JSC::ArrayBufferNeuteringWatchpoint::fireAll): + * runtime/ArrayBufferNeuteringWatchpoint.h: + * runtime/CommonIdentifiers.h: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/Identifier.cpp: + (JSC::Identifier::dump): + * runtime/Identifier.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::put): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addFunction): + (JSC::JSGlobalObject::haveABadTime): + * runtime/JSSymbolTableObject.cpp: + (JSC::VariableWriteFireDetail::dump): + * runtime/JSSymbolTableObject.h: + (JSC::VariableWriteFireDetail::VariableWriteFireDetail): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/PropertyName.h: + (JSC::PropertyName::dump): + * runtime/Structure.cpp: + (JSC::Structure::notifyTransitionFromThisStructure): + * runtime/Structure.h: + (JSC::Structure::notifyTransitionFromThisStructure): Deleted. + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::notifyWriteSlow): + (JSC::SymbolTable::WatchpointCleanup::finalizeUnconditionally): + * runtime/SymbolTable.h: + (JSC::SymbolTableEntry::notifyWrite): + * runtime/VM.cpp: + (JSC::VM::addImpureProperty): + +2014-08-05 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r172099. + https://bugs.webkit.org/show_bug.cgi?id=135635 + + Needs a do-over. (Requested by kling on #webkit). + + Reverted changeset: + + "The JIT should cache property lookup misses." + https://bugs.webkit.org/show_bug.cgi?id=135578 + http://trac.webkit.org/changeset/172099 + +2014-08-05 Przemyslaw Kuczynski <p.kuczynski@samsung.com> + + Fix resource leak of unclosed file descriptor. + https://bugs.webkit.org/show_bug.cgi?id=135417 + + Reviewed by Darin Adler. + + When open returns zero, fd handle leaks. Checking (fd > 0) needs to be replaced + with (fd != -1). + + * assembler/MacroAssemblerARM.cpp: + (JSC::isVFPPresent): + +2014-08-05 Andreas Kling <akling@apple.com> + + The JIT should cache property lookup misses. + <https://webkit.org/b/135578> + + Add support for inline caching of object properties that don't exist. + Previously we'd fall back to the C++ slow-path whenever a property was missing. + + It's implemented as a simple GetById-style stub that returns jsUndefined() as + long as the Structure chain check passes. + + 10x speedup on the included microbenchmark. + + Reviewed by Geoffrey Garen. + + * jit/Repatch.cpp: + (JSC::toString): + (JSC::kindFor): + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::patchJumpToGetByIdStub): + * runtime/PropertySlot.h: + (JSC::PropertySlot::isUnset): + +2014-08-05 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r172009. + https://bugs.webkit.org/show_bug.cgi?id=135627 + + "Commit landed on trunk instead of ftlopt branch." (Requested + by saamyjoon on #webkit). + + Reverted changeset: + + "Create a more generic way for VMEntryScope to notify those + interested that it will be destroyed" + https://bugs.webkit.org/show_bug.cgi?id=135358 + http://trac.webkit.org/changeset/172009 + +2014-08-05 Alex Christensen <achristensen@webkit.org> + + More work on CMake. + https://bugs.webkit.org/show_bug.cgi?id=135620 + + Reviewed by Laszlo Gombos. + + * CMakeLists.txt: + Added missing source files. + * PlatformEfl.cmake: + * PlatformGTK.cmake: + Include glib directories and libraries to find glib.h in EventLoop.cpp. + * PlatformMac.cmake: + Moved STATICALLY_LINKED_WITH_WTF definition away from the common CMakeLists + because it should not be defined on Windows. + Added remote inspector source files. + +2014-08-05 Peyton Randolph <prandolph@apple.com> + + Rename MAC_LONG_PRESS feature flag to LONG_MOUSE_PRESS. + https://bugs.webkit.org/show_bug.cgi?id=135276 + + Reviewed by Beth Dakin. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-04 Benjamin Poulain <benjamin@webkit.org> + + Add a flag for the CSS Selectors level 4 implementation + https://bugs.webkit.org/show_bug.cgi?id=135535 + + Reviewed by Andreas Kling. + + * Configurations/FeatureDefines.xcconfig: + +2014-08-04 Alex Christensen <achristensen@webkit.org> + + Progress towards CMake on Mac. + https://bugs.webkit.org/show_bug.cgi?id=135528 + + Reviewed by Gyuyoung Kim. + + * CMakeLists.txt: + Include necessary directories and copy all necessary forwarding headers. + Only compile UDis86Disassembler.cpp if we're using UDIS86. + * PlatformMac.cmake: Added. + * tools/CodeProfiling.cpp: + Compile fix. Include sys/time.h on darwin, too. + +2014-08-04 Saam Barati <sbarati@apple.com> + + Create a more generic way for VMEntryScope to notify those interested that it will be destroyed + https://bugs.webkit.org/show_bug.cgi?id=135358 + + Reviewed by Geoffrey Garen. + + When VMEntryScope is destroyed, and it has a flag set indicating that the + Debugger needs to recompile all functions, it calls Debugger::recompileAllJSFunctions. + This flag is only used by Debugger to have VMEntryScope notify it when the + Debugger is safe to recompile all functions. This patch will substitute this + Debugger-specific recompilation flag with a list of callbacks that are notified + when the outermost VMEntryScope dies. This creates a general purpose interface + for being notified when the VM stops executing code via the event of the outermost + VMEntryScope dying. + + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): + * runtime/VMEntryScope.cpp: + (JSC::VMEntryScope::VMEntryScope): + (JSC::VMEntryScope::addEntryScopeDidPopListener): + (JSC::VMEntryScope::~VMEntryScope): + * runtime/VMEntryScope.h: + (JSC::VMEntryScope::setRecompilationNeeded): Deleted. + +2014-08-01 Carlos Alberto Lopez Perez <clopez@igalia.com> + + REGRESSION(r171942): [CMAKE] [GTK] build broken (clean build). + https://bugs.webkit.org/show_bug.cgi?id=135522 + + Reviewed by Martin Robinson. + + * CMakeLists.txt: Output the inspector headers inside inspector + subdirectory. + +2014-08-01 Mark Lam <mark.lam@apple.com> + + Add some structure related assertions. + <https://webkit.org/b/135523> + + Reviewed by Geoffrey Garen. + + Adding 2 assertions: + 1. assert that we don't index pass the end of the StructureIDTable. + This should never happen, but this assertion will help catch bugs + where a bad structureID gets passed in. + 2. assert that cells in MarkedBlock::callDestructor() that are not + zapped should have a non-null StructureID. This will help us catch + bugs where the other cell header flag bits get set after the cell is + zapped, thereby making the cell look like an unzapped cell but has a + null structureID. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::callDestructor): + * runtime/StructureIDTable.h: + (JSC::StructureIDTable::get): + +2014-08-01 Csaba Osztrogonác <ossy@webkit.org> + + URTBF after r171946 to fix non-Apple builds. + + * bytecode/InlineCallFrameSet.cpp: + +2014-08-01 Mark Hahnenberg <mhahnenberg@apple.com> + + CodeBlock fails to visit the Executables of its InlineCallFrames + https://bugs.webkit.org/show_bug.cgi?id=135471 + + Reviewed by Geoffrey Garen. + + CodeBlock needs to visit its InlineCallFrames' owner Executables. If it doesn't, they + can be prematurely collected and cause crashes. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::stronglyVisitStrongReferences): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::visitAggregate): + * bytecode/InlineCallFrameSet.cpp: + (JSC::InlineCallFrameSet::visitAggregate): + * bytecode/InlineCallFrameSet.h: + +2014-08-01 Alex Christensen <achristensen@webkit.org> + + Progress towards cmake on Windows. + https://bugs.webkit.org/show_bug.cgi?id=135484 + + Reviewed by Martin Robinson. + + * CMakeLists.txt: + Generate code directly to inspector directory to avoid using the cp command + which is not available on Windows. + * PlatformWin.cmake: Added. + +2014-07-31 Andreas Kling <akling@apple.com> + + Remove the JSC::OverridesVisitChildren flag. + <https://webkit.org/b/135489> + + Except for 3 special classes, the visitChildren() call is always + dispatched through the method table (see SlotVisitor.cpp.) + + The OverridesVisitChildren flag doesn't actually do anything. + It could be used to implement a non-virtual direct call to + JSCell::visitChildren, bypassing the method table for some objects, + but such a micro-optimization seems like a weak trade for all this + code complexity. Instead, just remove the flag. + + This change frees up an inline flag bit in JSCell. + + Reviewed by Geoffrey Garen. + + * API/JSAPIWrapperObject.h: + * API/JSAPIWrapperObject.mm: + (JSC::JSAPIWrapperObject::visitChildren): + * API/JSCallbackObject.h: + (JSC::JSCallbackObject::visitChildren): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::visitChildren): + (JSC::UnlinkedCodeBlock::visitChildren): + (JSC::UnlinkedProgramCodeBlock::visitChildren): + * bytecode/UnlinkedCodeBlock.h: + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::visitChildren): + * debugger/DebuggerScope.h: + * jsc.cpp: + * runtime/Arguments.cpp: + (JSC::Arguments::visitChildren): + * runtime/Arguments.h: + * runtime/Executable.cpp: + (JSC::EvalExecutable::visitChildren): + (JSC::ProgramExecutable::visitChildren): + (JSC::FunctionExecutable::visitChildren): + * runtime/Executable.h: + * runtime/GetterSetter.cpp: + (JSC::GetterSetter::visitChildren): + * runtime/GetterSetter.h: + (JSC::GetterSetter::createStructure): + * runtime/JSAPIValueWrapper.h: + (JSC::JSAPIValueWrapper::createStructure): + * runtime/JSActivation.cpp: + (JSC::JSActivation::visitChildren): + * runtime/JSActivation.h: + * runtime/JSArrayIterator.cpp: + (JSC::JSArrayIterator::visitChildren): + * runtime/JSArrayIterator.h: + * runtime/JSBoundFunction.cpp: + (JSC::JSBoundFunction::visitChildren): + * runtime/JSBoundFunction.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::setStructure): + * runtime/JSFunction.cpp: + (JSC::JSFunction::visitChildren): + * runtime/JSFunction.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + * runtime/JSMap.h: + * runtime/JSMapIterator.cpp: + (JSC::JSMapIterator::visitChildren): + * runtime/JSMapIterator.h: + * runtime/JSNameScope.cpp: + (JSC::JSNameScope::visitChildren): + * runtime/JSNameScope.h: + * runtime/JSPromise.cpp: + (JSC::JSPromise::visitChildren): + * runtime/JSPromise.h: + * runtime/JSPromiseDeferred.cpp: + (JSC::JSPromiseDeferred::visitChildren): + * runtime/JSPromiseDeferred.h: + * runtime/JSPromiseReaction.cpp: + (JSC::JSPromiseReaction::visitChildren): + * runtime/JSPromiseReaction.h: + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::visitChildren): + * runtime/JSPropertyNameIterator.h: + * runtime/JSProxy.cpp: + (JSC::JSProxy::visitChildren): + * runtime/JSProxy.h: + * runtime/JSScope.cpp: + (JSC::JSScope::visitChildren): + * runtime/JSScope.h: + * runtime/JSSegmentedVariableObject.cpp: + (JSC::JSSegmentedVariableObject::visitChildren): + * runtime/JSSegmentedVariableObject.h: + * runtime/JSSet.h: + * runtime/JSSetIterator.cpp: + (JSC::JSSetIterator::visitChildren): + * runtime/JSSetIterator.h: + * runtime/JSSymbolTableObject.cpp: + (JSC::JSSymbolTableObject::visitChildren): + * runtime/JSSymbolTableObject.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::overridesVisitChildren): Deleted. + * runtime/JSWeakMap.h: + * runtime/JSWithScope.cpp: + (JSC::JSWithScope::visitChildren): + * runtime/JSWithScope.h: + * runtime/JSWrapperObject.cpp: + (JSC::JSWrapperObject::visitChildren): + * runtime/JSWrapperObject.h: + * runtime/MapData.h: + * runtime/NativeErrorConstructor.cpp: + (JSC::NativeErrorConstructor::visitChildren): + * runtime/NativeErrorConstructor.h: + * runtime/PropertyMapHashTable.h: + * runtime/PropertyTable.cpp: + (JSC::PropertyTable::visitChildren): + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::visitChildren): + * runtime/RegExpConstructor.h: + * runtime/RegExpMatchesArray.cpp: + (JSC::RegExpMatchesArray::visitChildren): + * runtime/RegExpMatchesArray.h: + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::visitChildren): + * runtime/RegExpObject.h: + * runtime/SparseArrayValueMap.h: + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::visitChildren): + * runtime/StructureChain.cpp: + (JSC::StructureChain::visitChildren): + * runtime/StructureChain.h: + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::visitChildren): + * runtime/StructureRareData.h: + * runtime/WeakMapData.h: + +2014-07-31 Mark Lam <mark.lam@apple.com> + + JSCell::classInfo() belongs in JSCellInlines.h. + <https://webkit.org/b/135475> + + Reviewed by Mark Hahnenberg. + + * runtime/JSCellInlines.h: + (JSC::JSCell::classInfo): + * runtime/JSDestructibleObject.h: + (JSC::JSCell::classInfo): Deleted. + +2014-07-31 Tanay C <tanay.c@samsung.com> + + Build warning in webkit/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp + https://bugs.webkit.org/show_bug.cgi?id=135414 + + Reviewed by Csaba Osztrogonác. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::putToScopeCommon):removed unused parameter from function definition + +2014-07-30 Filip Pizlo <fpizlo@apple.com> + + NewFunctionExpression and NewFunctionNoCheck should setHaveStructures(true) + https://bugs.webkit.org/show_bug.cgi?id=135430 + + Reviewed by Mark Hahnenberg. + + We already handled this correctly after the ftlopt merge, but it's useful to have the test. + + * tests/stress/new-function-expression-has-structures.js: Added. + (foo.f): + (foo.f.prototype.f): + (foo): + +2014-07-30 Andreas Kling <akling@apple.com> + + Speculative Windows build fix. + + Try to dllimport the dllexported global object HashTable. + + * jsc.cpp: + * testRegExp.cpp: + +2014-07-30 Andreas Kling <akling@apple.com> + + PropertyName's internal string is always atomic. + <https://webkit.org/b/135451> + + Now that we've merged the JSC::Identifier and WTF::AtomicString tables, + we know that any string that's an Identifier is guaranteed to be atomic. + + A PropertyName can be either an Identifier or a PrivateName, and the + private names are also guaranteed to be atomic internally. + + Make PropertyName vend AtomicStringImpl* instead of StringImpl*. + + Reviewed by Benjamin Poulain. + + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + (JSC::PropertyName::uid): + (JSC::PropertyName::publicName): + +2014-07-30 Andy Estes <aestes@apple.com> + + USE(CONTENT_FILTERING) should be ENABLE(CONTENT_FILTERING) + https://bugs.webkit.org/show_bug.cgi?id=135439 + + Reviewed by Tim Horton. + + We now support two different platform content filters, and will soon support a mock content filter (as part of + webkit.org/b/128858). This makes content filtering a feature of WebKit, not just an adoption of a third-party + library. ENABLE() is the correct macro to use for such a feature. + + * Configurations/FeatureDefines.xcconfig: + +2014-07-30 Andreas Kling <akling@apple.com> + + Static hash tables no longer need to be coupled with a VM. + <https://webkit.org/b/135421> + + Now that the static hash tables are using char** instead of StringImpl**, + it's no longer necessary to make them per-VM. + + This patch removes the hook in ClassInfo for providing your own static + hash table getter. Everyone now uses ClassInfo::staticPropHashTable. + Most of this patch is tweaking ClassInfo construction sites to pass one + less null pointer. + + Also simplified Lookup.h to stop requiring ExecState/VM to access the + static hash tables. + + Reviewed by Geoffrey Garen. + + * API/JSAPIWrapperObject.mm: + * API/JSCallbackConstructor.cpp: + * API/JSCallbackFunction.cpp: + * API/JSCallbackObject.cpp: + * API/ObjCCallbackFunction.mm: + * bytecode/UnlinkedCodeBlock.cpp: + * create_hash_table: + * debugger/DebuggerScope.cpp: + * inspector/JSInjectedScriptHost.cpp: + * inspector/JSInjectedScriptHostPrototype.cpp: + * inspector/JSJavaScriptCallFrame.cpp: + * inspector/JSJavaScriptCallFramePrototype.cpp: + * interpreter/CallFrame.h: + (JSC::ExecState::arrayConstructorTable): Deleted. + (JSC::ExecState::arrayPrototypeTable): Deleted. + (JSC::ExecState::booleanPrototypeTable): Deleted. + (JSC::ExecState::dataViewTable): Deleted. + (JSC::ExecState::dateTable): Deleted. + (JSC::ExecState::dateConstructorTable): Deleted. + (JSC::ExecState::errorPrototypeTable): Deleted. + (JSC::ExecState::globalObjectTable): Deleted. + (JSC::ExecState::jsonTable): Deleted. + (JSC::ExecState::numberConstructorTable): Deleted. + (JSC::ExecState::numberPrototypeTable): Deleted. + (JSC::ExecState::objectConstructorTable): Deleted. + (JSC::ExecState::privateNamePrototypeTable): Deleted. + (JSC::ExecState::regExpTable): Deleted. + (JSC::ExecState::regExpConstructorTable): Deleted. + (JSC::ExecState::regExpPrototypeTable): Deleted. + (JSC::ExecState::stringConstructorTable): Deleted. + (JSC::ExecState::promisePrototypeTable): Deleted. + (JSC::ExecState::promiseConstructorTable): Deleted. + * jsc.cpp: + * parser/Lexer.h: + (JSC::Keywords::isKeyword): + (JSC::Keywords::getKeyword): + * runtime/Arguments.cpp: + * runtime/ArgumentsIteratorConstructor.cpp: + * runtime/ArgumentsIteratorPrototype.cpp: + * runtime/ArrayBufferNeuteringWatchpoint.cpp: + * runtime/ArrayConstructor.cpp: + (JSC::ArrayConstructor::getOwnPropertySlot): + * runtime/ArrayIteratorConstructor.cpp: + * runtime/ArrayIteratorPrototype.cpp: + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::getOwnPropertySlot): + * runtime/BooleanConstructor.cpp: + * runtime/BooleanObject.cpp: + * runtime/BooleanPrototype.cpp: + (JSC::BooleanPrototype::getOwnPropertySlot): + * runtime/ClassInfo.h: + (JSC::ClassInfo::hasStaticProperties): + (JSC::ClassInfo::propHashTable): Deleted. + * runtime/ConsolePrototype.cpp: + * runtime/CustomGetterSetter.cpp: + * runtime/DateConstructor.cpp: + (JSC::DateConstructor::getOwnPropertySlot): + * runtime/DateInstance.cpp: + * runtime/DatePrototype.cpp: + (JSC::DatePrototype::getOwnPropertySlot): + * runtime/Error.cpp: + * runtime/ErrorConstructor.cpp: + * runtime/ErrorInstance.cpp: + * runtime/ErrorPrototype.cpp: + (JSC::ErrorPrototype::getOwnPropertySlot): + * runtime/ExceptionHelpers.cpp: + * runtime/Executable.cpp: + * runtime/FunctionConstructor.cpp: + * runtime/FunctionPrototype.cpp: + * runtime/GetterSetter.cpp: + * runtime/InternalFunction.cpp: + * runtime/JSAPIValueWrapper.cpp: + * runtime/JSActivation.cpp: + * runtime/JSArgumentsIterator.cpp: + * runtime/JSArray.cpp: + * runtime/JSArrayBuffer.cpp: + * runtime/JSArrayBufferConstructor.cpp: + * runtime/JSArrayBufferPrototype.cpp: + * runtime/JSArrayBufferView.cpp: + * runtime/JSArrayIterator.cpp: + * runtime/JSBoundFunction.cpp: + * runtime/JSConsole.cpp: + * runtime/JSDataView.cpp: + * runtime/JSDataViewPrototype.cpp: + (JSC::JSDataViewPrototype::getOwnPropertySlot): + * runtime/JSFunction.cpp: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::getOwnPropertySlot): + * runtime/JSMap.cpp: + * runtime/JSMapIterator.cpp: + * runtime/JSNameScope.cpp: + * runtime/JSNotAnObject.cpp: + * runtime/JSONObject.cpp: + (JSC::JSONObject::getOwnPropertySlot): + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + (JSC::JSObject::put): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::findPropertyHashEntry): + (JSC::JSObject::reifyStaticFunctionsForDelete): + * runtime/JSObject.h: + * runtime/JSPromise.cpp: + * runtime/JSPromiseConstructor.cpp: + (JSC::JSPromiseConstructor::getOwnPropertySlot): + * runtime/JSPromiseDeferred.cpp: + * runtime/JSPromisePrototype.cpp: + (JSC::JSPromisePrototype::getOwnPropertySlot): + * runtime/JSPromiseReaction.cpp: + * runtime/JSPropertyNameIterator.cpp: + * runtime/JSProxy.cpp: + * runtime/JSSet.cpp: + * runtime/JSSetIterator.cpp: + * runtime/JSString.cpp: + * runtime/JSTypedArrayConstructors.cpp: + * runtime/JSTypedArrayPrototypes.cpp: + * runtime/JSTypedArrays.cpp: + * runtime/JSVariableObject.cpp: + * runtime/JSWeakMap.cpp: + * runtime/JSWithScope.cpp: + * runtime/Lookup.cpp: + (JSC::HashTable::createTable): + * runtime/Lookup.h: + (JSC::HashTable::initializeIfNeeded): + (JSC::HashTable::entry): + (JSC::HashTable::begin): + (JSC::HashTable::end): + (JSC::getStaticPropertySlot): + (JSC::getStaticFunctionSlot): + (JSC::getStaticValueSlot): + (JSC::lookupPut): + * runtime/MapConstructor.cpp: + * runtime/MapData.cpp: + * runtime/MapIteratorConstructor.cpp: + * runtime/MapIteratorPrototype.cpp: + * runtime/MapPrototype.cpp: + * runtime/MathObject.cpp: + * runtime/NameConstructor.cpp: + * runtime/NameInstance.cpp: + * runtime/NamePrototype.cpp: + (JSC::NamePrototype::getOwnPropertySlot): + * runtime/NativeErrorConstructor.cpp: + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::getOwnPropertySlot): + * runtime/NumberObject.cpp: + * runtime/NumberPrototype.cpp: + (JSC::NumberPrototype::getOwnPropertySlot): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::getOwnPropertySlot): + * runtime/ObjectPrototype.cpp: + * runtime/PropertyTable.cpp: + * runtime/RegExp.cpp: + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::getOwnPropertySlot): + * runtime/RegExpMatchesArray.cpp: + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::getOwnPropertySlot): + * runtime/RegExpPrototype.cpp: + (JSC::RegExpPrototype::getOwnPropertySlot): + * runtime/SetConstructor.cpp: + * runtime/SetIteratorConstructor.cpp: + * runtime/SetIteratorPrototype.cpp: + * runtime/SetPrototype.cpp: + * runtime/SparseArrayValueMap.cpp: + * runtime/StrictEvalActivation.cpp: + * runtime/StringConstructor.cpp: + (JSC::StringConstructor::getOwnPropertySlot): + * runtime/StringObject.cpp: + * runtime/StringPrototype.cpp: + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::freezeTransition): + (JSC::ClassInfo::hasStaticSetterOrReadonlyProperties): + * runtime/StructureChain.cpp: + * runtime/StructureRareData.cpp: + * runtime/SymbolTable.cpp: + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::~VM): + * runtime/VM.h: + * runtime/WeakMapConstructor.cpp: + * runtime/WeakMapData.cpp: + * runtime/WeakMapPrototype.cpp: + * testRegExp.cpp: + +2014-07-29 Brent Fulgham <bfulgham@apple.com> + + [Win] Modify version numbering scheme to support 5-tuple versions + https://bugs.webkit.org/show_bug.cgi?id=135400 + <rdar://problem/17849033> + + Reviewed by David Kilzer. + + * JavaScriptCore.vcxproj/JavaScriptCorePostBuild.cmd: Use the + new version-stamp.pl script to version JavaScriptCore.dll. + +2014-07-29 Daniel Bates <dabates@apple.com> + + Use WTF::move() instead of std::move() to help ensure move semantics + https://bugs.webkit.org/show_bug.cgi?id=135351 + + Reviewed by Alexey Proskuryakov. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::GetByIdVariant): + +2014-07-28 Tamas Gergely <tgergely.u-szeged@partner.samsung.com> + + BuildFix: JavaScriptCore/bytecode/StructureSet.h:262:77: warning. + https://bugs.webkit.org/show_bug.cgi?id=135287 + + Reviewed by Darin Adler. + + The set() method tries to use a part of the old value (the reservedFlag bit) which + was not defined when the constructor is called. Initialize m_pointer to 0 explicitely. + + * bytecode/StructureSet.h: + (JSC::StructureSet::StructureSet): + +2014-07-28 Benjamin Poulain <bpoulain@apple.com> + + [JSC] JIT::assertStackPointerOffset() crashes on ARM64 + https://bugs.webkit.org/show_bug.cgi?id=135316 + + Reviewed by Geoffrey Garen. + + JIT::assertStackPointerOffset() does a compare between an arbitrary register + and the stack pointer. This was not supported by the ARM64 assembler. + + There are no variation that can take a stack pointer for Xd. There is one version of subs + that can take a stack pointer, but only for the Xn: the shift+extend one. + To solve the problem, I changed cmp to swap the registers if necessary, and I fixed + the implementation of sub. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::sub): + In the generic sub(reg, reg), I added assertions to catch the condition that cannot be generated + with either version of sub. + + In sub(with shift), I remove the weird special case for SP. First, it was quite misleading because + the Rd case only works if "setflag == false". The other confusing part is going to addSubtractShiftedRegister() + gives you a reduce shift range, which could create subtle bug that only appear when SP is used. + + Since I removed the weird case, I need to differentiate between the sub() that support SP, and the one that does + not elsewhere. That is why that branch has moved to the generic sub(reg, reg). Since at that point we know + the shift value must be zero, it is safe to call either variant. + + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::branch64): + With the changes described above, we can now use SP for the left register. What do we do if the rightmost + register is SP? + + For the case of JIT::assertStackPointerOffset(), the comparison is Equal so the order really does not matter, + we just switch the registers before generating the instruction. + + For the generic case, just move the value of SP to a GPR before doing the CMP. + +2014-07-28 Brian J. Burg <burg@cs.washington.edu> + + Unreviewed build fix after r171682. + + * replay/EncodedValue.h: Don't mark the inlined Vector<char> specialization + as an exported symbol. + +2014-07-28 Mark Hahnenberg <mhahnenberg@apple.com> + + REGRESSION: JSObjectSetPrototype() does not work on result of JSGetGlobalObject() + https://bugs.webkit.org/show_bug.cgi?id=135322 + + Reviewed by Oliver Hunt. + + The prototype chain of the JSProxy object should match that of the JSGlobalObject. + + This is a separate but related issue with JSObjectSetPrototype which doesn't correctly + account for JSProxies. I also audited the rest of the C API to check that we correctly + handle JSProxies in all other situations where we expect a JSCallbackObject of some sort + and found some SPI calls (JSObject*PrivateProperty) that didn't behave correctly when + passed a JSProxy. + + I also added some new tests for these cases. + + * API/JSObjectRef.cpp: + (JSObjectSetPrototype): + (JSObjectGetPrivateProperty): + (JSObjectSetPrivateProperty): + (JSObjectDeletePrivateProperty): + * API/JSWeakObjectMapRefPrivate.cpp: + * API/tests/CustomGlobalObjectClassTest.c: + (globalObjectSetPrototypeTest): + (globalObjectPrivatePropertyTest): + * API/tests/CustomGlobalObjectClassTest.h: + * API/tests/testapi.c: + (main): + +2014-07-28 Filip Pizlo <fpizlo@apple.com> + + Make sure that we don't use non-speculative BooleanToNumber for a speculative Branch + https://bugs.webkit.org/show_bug.cgi?id=135350 + <rdar://problem/17509889> + + Reviewed by Mark Hahnenberg and Oliver Hunt. + + If we have an exiting node that uses a conversion node, then that exiting node + needs to have a Phantom after it for the the original node. But we can't do that + for Branch because https://bugs.webkit.org/show_bug.cgi?id=126778. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::clearPhantomsAtEnd): + * tests/stress/branch-check-int32-on-boolean-to-number-untyped.js: Added. + (foo): + (test): + * tests/stress/branch-check-number-on-boolean-to-number-untyped.js: Added. + (foo): + (test): + +2014-07-28 Joseph Pecoraro <pecoraro@apple.com> + + JSContext Inspector: crash when using step-into + https://bugs.webkit.org/show_bug.cgi?id=135345 + + Reviewed by Timothy Hatcher. + + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::stepInto): + Null check m_listener since it may not be set. + +2014-07-28 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: auto-decoding of parameterized vector's elements is incorrect + https://bugs.webkit.org/show_bug.cgi?id=135343 + + Reviewed by Timothy Hatcher. + + Fix an incorrect type argument in EncodingTraits<Vector<T>>::encodeValue + that was using the element's decoded type as the type parameter to + EncodedValue::append<T>. It should instead be the raw type T. This + causes problems when encoding Vector<RefPtr<T>>, as it later tries to + use encoding traits for RefPtr<T> rather than for T. + + Fix incorrect generated encoding traits argument for vectors of + RefCounted objects. Updated test to cover this scenario. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (Type.encoding_type_argument): + (VectorType.type_name): + (VectorType): + (VectorType.encoding_type_argument): + (Generator.generate_input_encode_implementation): + (Generator.generate_input_decode_implementation): + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.cpp: + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.h: + * replay/scripts/tests/generate-input-with-vector-members.json: Updated. + +2014-07-28 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: incorrect serialization code generated for enum classes inside class scope + https://bugs.webkit.org/show_bug.cgi?id=135342 + + Reviewed by Timothy Hatcher. + + If an enum class is defined inside of a class scope, then the enum class + cannot be forward-declared and the relevant header should be included. + Some generated code used incorrectly-scoped enum values in this situation. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (Generator.generate_includes.declaration.is): + (Generator.generate_enum_trait_implementation.is): + (Generator.generate_enum_trait_implementation): + + Tests: + + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.cpp: Rebaselined. + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.h: Rebaselined. + * replay/scripts/tests/generate-enums-with-same-base-name.json: Add enum + class types to this test case. + +2014-07-28 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: vectors of characters should be base64-encoded + https://bugs.webkit.org/show_bug.cgi?id=135341 + + Reviewed by Timothy Hatcher. + + Without this specialization, encode/decode methods try to create an + array of single characters in JSON, rather than treating the + vector as a binary blob. + + * replay/EncodedValue.cpp: + (JSC::EncodingTraits<Vector<char>>::encodeValue): Added. + (JSC::EncodingTraits<Vector<char>>::decodeValue): Added. + * replay/EncodedValue.h: + +2014-07-28 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed build fix. + + * JavaScriptCore.vcxproj/JavaScriptCore.proj: Switch from the 'Rebuild' target for MSBuild + builds to the 'Build' target to avoid a spurious 'clean' in between build steps. + +2014-07-27 Ryuan Choi <ryuan.choi@samsung.com> + + Unreviewed build fix on the EFL port + + Build break because of -Werror=return-type + + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::oldStructureForTransition): + * dfg/DFGValueStrength.h: + (JSC::DFG::merge): + +2014-07-27 Filip Pizlo <fpizlo@apple.com> + + [REGRESSION][ftlopt merge][32-bit] stress/prune-multi-put-by-offset-replace-or-transition-variant.js.dfg-eager hits an assertion in SpeculativeJIT::silentSavePlanForGPR + https://bugs.webkit.org/show_bug.cgi?id=135323 + + Reviewed by Oliver Hunt. + + SpeculativeJIT::silentSavePlanForGPR likes to believe that if a node is a constant, + then it's a constant that can be represented using that node's current DataFormat. + This doesn't work if the constant had been filled as a JSValue, and then one of the + fillSpeculateBlah() methods had speculated that it's of some type that the constant + isn't. Unless fillSpeculateBlah() specifically defends against this case, we'll have + a constant that claims to have a contradictory data format. + + This patch fixes such a bug in the 32-bit fillSpeculateCell(). The 64-bit + fillSpeculateCell() appears to not have this bug, but I added a similar defense + mechanism anyway just in case, since this is one of those mistakes that keeps + reappearing. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + +2014-07-27 Filip Pizlo <fpizlo@apple.com> + + Merge r170090, r170092, r170129, r170141, r170161, r170215, r170275, r170375, r170376, r170382, r170383, r170399, r170436, r170489, r170490, r170556 from ftlopt. + + This fixes the previous mismerge and adds test coverage for the thing that went wrong. + + Additional changes listed here: + + * jsc.cpp: + (functionHasCustomProperties): Expose a way of checking hasCustomProperties(), which the DOM relies on. The regression I previously introduced was because this didn't work right. Now we can test it! + * runtime/Structure.cpp: + (JSC::Structure::Structure): This was supposed to be setDidTransition(true); the last merge had it set to false. + * tests/stress/has-custom-properties.js: Added. This test failed with the mismerge. + + 2014-06-27 Michael Saboff <msaboff@apple.com> + + Unreviewed build fix after r169795. + + Fixed ASSERT for 32 bit build. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + + 2014-06-24 Saam Barati <sbarati@apple.com> + + Web Inspector: debugger should be able to show variable types + https://bugs.webkit.org/show_bug.cgi?id=133395 + + Reviewed by Filip Pizlo. + + Increase the amount of type information the VM gathers when directed + to do so. This initial commit is working towards the goal of + capturing, and then showing (via the Web Inspector) type information for all + assignment and load operations. This patch doesn't have the feature fully + implemented, but it ensures the VM has no performance regressions + unless the feature is specifically turned on. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecode/CodeBlock.h: + * bytecode/Instruction.h: + * bytecode/TypeLocation.h: Added. + (JSC::TypeLocation::TypeLocation): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): + (JSC::BytecodeGenerator::emitPutToScope): + (JSC::BytecodeGenerator::emitPutById): + (JSC::BytecodeGenerator::emitPutByVal): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity): + * bytecompiler/NodesCodegen.cpp: + (JSC::PostfixNode::emitResolve): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::ForInNode::emitBytecode): + * heap/Heap.cpp: + (JSC::Heap::collect): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + * jsc.cpp: + (GlobalObject::finishCreation): + (functionDumpTypesForAllVariables): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (JSC::LLInt::putToScopeCommon): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * runtime/HighFidelityLog.cpp: Added. + (JSC::HighFidelityLog::initializeHighFidelityLog): + (JSC::HighFidelityLog::~HighFidelityLog): + (JSC::HighFidelityLog::recordTypeInformationForLocation): + (JSC::HighFidelityLog::processHighFidelityLog): + (JSC::HighFidelityLog::actuallyProcessLogThreadFunction): + * runtime/HighFidelityLog.h: Added. + (JSC::HighFidelityLog::HighFidelityLog): + * runtime/HighFidelityTypeProfiler.cpp: Added. + (JSC::HighFidelityTypeProfiler::getTypesForVariableInRange): + (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableInRange): + (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableInRange): + (JSC::HighFidelityTypeProfiler::insertNewLocation): + (JSC::HighFidelityTypeProfiler::getLocationBasedHash): + * runtime/HighFidelityTypeProfiler.h: Added. + * runtime/Options.h: + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + * runtime/Structure.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::SymbolTable): + (JSC::SymbolTable::cloneCapturedNames): + (JSC::SymbolTable::uniqueIDForVariable): + (JSC::SymbolTable::uniqueIDForRegister): + (JSC::SymbolTable::globalTypeSetForRegister): + (JSC::SymbolTable::globalTypeSetForVariable): + * runtime/SymbolTable.h: + (JSC::SymbolTable::add): + (JSC::SymbolTable::set): + * runtime/TypeSet.cpp: Added. + (JSC::TypeSet::TypeSet): + (JSC::TypeSet::getRuntimeTypeForValue): + (JSC::TypeSet::addTypeForValue): + (JSC::TypeSet::removeDuplicatesInStructureHistory): + (JSC::TypeSet::seenTypes): + (JSC::TypeSet::dumpSeenTypes): + (JSC::StructureShape::StructureShape): + (JSC::StructureShape::markAsFinal): + (JSC::StructureShape::addProperty): + (JSC::StructureShape::propertyHash): + (JSC::StructureShape::leastUpperBound): + (JSC::StructureShape::stringRepresentation): + * runtime/TypeSet.h: Added. + (JSC::StructureShape::create): + (JSC::TypeSet::create): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::getTypesForVariableInRange): + (JSC::VM::updateHighFidelityTypeProfileState): + (JSC::VM::dumpHighFidelityProfilingTypes): + * runtime/VM.h: + (JSC::VM::isProfilingTypesWithHighFidelity): + (JSC::VM::highFidelityLog): + (JSC::VM::highFidelityTypeProfiler): + (JSC::VM::nextLocation): + (JSC::VM::getNextUniqueVariableID): + + 2014-06-26 Mark Lam <mark.lam@apple.com> + + Remove unused instantiation of the WithScope structure. + <https://webkit.org/b/134331> + + Reviewed by Oliver Hunt. + + The WithScope structure instance is the VM is unused, and is now removed. + + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + + 2014-06-25 Mark Hahnenberg <mhahnenberg@apple.com> + + Structure bit fields should have a consistent format + https://bugs.webkit.org/show_bug.cgi?id=134307 + + Reviewed by Filip Pizlo. + + Currently we use C-style bit fields for a number of member variables in Structure to save space. + This makes it difficult to load these fields in the JIT. We should instead use our own bitfield + format to make it easy to load and test these variables in JIT code. + + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::reifyStaticFunctionsForDelete): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::StructureTransitionTable::add): + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::freezeTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::takePropertyTableOrCloneIfPinned): + (JSC::Structure::nonPropertyTransition): + (JSC::Structure::flattenDictionaryStructure): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::pin): + (JSC::Structure::allocateRareData): + (JSC::Structure::cloneRareDataFrom): + (JSC::Structure::getConcurrently): + (JSC::Structure::putSpecificValue): + (JSC::Structure::getPropertyNamesFromStructure): + (JSC::Structure::visitChildren): + (JSC::Structure::checkConsistency): + * runtime/Structure.h: + (JSC::Structure::isExtensible): + (JSC::Structure::isDictionary): + (JSC::Structure::isUncacheableDictionary): + (JSC::Structure::propertyAccessesAreCacheable): + (JSC::Structure::previousID): + (JSC::Structure::setHasGetterSetterPropertiesWithProtoCheck): + (JSC::Structure::setContainsReadOnlyProperties): + (JSC::Structure::disableSpecificFunctionTracking): + (JSC::Structure::objectToStringValue): + (JSC::Structure::setObjectToStringValue): + (JSC::Structure::setPreviousID): + (JSC::Structure::clearPreviousID): + (JSC::Structure::previous): + (JSC::Structure::rareData): + (JSC::Structure::didTransition): Deleted. + (JSC::Structure::hasGetterSetterProperties): Deleted. + (JSC::Structure::hasReadOnlyOrGetterSetterPropertiesExcludingProto): Deleted. + (JSC::Structure::setHasGetterSetterProperties): Deleted. + (JSC::Structure::hasNonEnumerableProperties): Deleted. + (JSC::Structure::staticFunctionsReified): Deleted. + (JSC::Structure::setStaticFunctionsReified): Deleted. + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::enumerationCache): + (JSC::Structure::checkOffsetConsistency): + + 2014-06-24 Mark Lam <mark.lam@apple.com> + + [ftlopt] Renamed DebuggerActivation to DebuggerScope. + <https://webkit.org/b/134273> + + Reviewed by Michael Saboff. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * debugger/DebuggerActivation.cpp: Removed. + * debugger/DebuggerActivation.h: Removed. + * debugger/DebuggerScope.cpp: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.cpp. + (JSC::DebuggerScope::DebuggerScope): + (JSC::DebuggerScope::finishCreation): + (JSC::DebuggerScope::visitChildren): + (JSC::DebuggerScope::className): + (JSC::DebuggerScope::getOwnPropertySlot): + (JSC::DebuggerScope::put): + (JSC::DebuggerScope::deleteProperty): + (JSC::DebuggerScope::getOwnPropertyNames): + (JSC::DebuggerScope::defineOwnProperty): + (JSC::DebuggerActivation::DebuggerActivation): Deleted. + (JSC::DebuggerActivation::finishCreation): Deleted. + (JSC::DebuggerActivation::visitChildren): Deleted. + (JSC::DebuggerActivation::className): Deleted. + (JSC::DebuggerActivation::getOwnPropertySlot): Deleted. + (JSC::DebuggerActivation::put): Deleted. + (JSC::DebuggerActivation::deleteProperty): Deleted. + (JSC::DebuggerActivation::getOwnPropertyNames): Deleted. + (JSC::DebuggerActivation::defineOwnProperty): Deleted. + * debugger/DebuggerScope.h: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.h. + (JSC::DebuggerScope::create): + (JSC::DebuggerActivation::create): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] PutByIdFlush can also be converted to a PutByOffset so don't assert otherwise + https://bugs.webkit.org/show_bug.cgi?id=134265 + + Reviewed by Geoffrey Garen. + + More assertion fallout from the PutById folding work. + + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPutByOffset): + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] GC should notify us if it resets to_this + https://bugs.webkit.org/show_bug.cgi?id=128231 + + Reviewed by Geoffrey Garen. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecode/Instruction.h: + * bytecode/ToThisStatus.cpp: Added. + (JSC::merge): + (WTF::printInternal): + * bytecode/ToThisStatus.h: Added. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] StructureAbstractValue::onlyStructure() should return nullptr if isClobbered() + https://bugs.webkit.org/show_bug.cgi?id=134256 + + Reviewed by Michael Saboff. + + This isn't testable right now (i.e. it's benign) but we should get it right anyway. The + point is to be able to precisely model what goes on in the snippets of code between a + side-effect and an InvalidationPoint. + + This patch also cleans up onlyStructure() by delegating more work to + StructureSet::onlyStructure(). + + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::onlyStructure): + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt][REGRESSION] PutById AI is introducing watchable structures without watching them + https://bugs.webkit.org/show_bug.cgi?id=134260 + + Reviewed by Geoffrey Garen. + + This was causing loads of assertion failures in debug builds. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + + 2014-06-21 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets + https://bugs.webkit.org/show_bug.cgi?id=134090 + + Reviewed by Oliver Hunt. + + This pretty much finishes off the work to eliminate the special-casing of singleton + structure sets by making it possible to fold GetById and PutById to various polymorphic + forms of the ByOffset nodes. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdStatus.h: + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::constantChecks): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addChecks): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToMultiGetByOffset): + (JSC::DFG::Node::convertToMultiPutByOffset): + * dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging. + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::set): + + 2014-06-19 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] StructureSet::onlyStructure() should return nullptr if it's not a singleton (instead of asserting) + https://bugs.webkit.org/show_bug.cgi?id=134077 + + Reviewed by Sam Weinig. + + This makes StructureSet and StructureAbstractValue more consistent and fixes a debug assert + in the abstract interpreter. + + * bytecode/StructureSet.h: + (JSC::StructureSet::onlyStructure): + + 2014-06-18 Filip Pizlo <fpizlo@apple.com> + + DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton + https://bugs.webkit.org/show_bug.cgi?id=133918 + + Reviewed by Mark Hahnenberg. + + This also adds pruning of PutStructure, since I basically had no choice but + to implement such logic within MultiPutByOffset. + + Also adds a bunch of PutById cache status dumping to bytecode dumping. + + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::dumpInContext): + * bytecode/GetByIdVariant.h: + (JSC::GetByIdVariant::structureSet): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::oldStructure): + * bytecode/StructureSet.cpp: + (JSC::StructureSet::filter): + (JSC::StructureSet::filterArrayModes): + * bytecode/StructureSet.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::changeStructure): + (JSC::DFG::AbstractValue::contains): + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::couldBeType): + (JSC::DFG::AbstractValue::isType): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addBaseCheck): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::freezeStrong): + * dfg/DFGGraph.h: + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::operator=): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + * tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added. + (foo): + (fu): + (bar): + (baz): + (.bar): + (.baz): + * tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added. + (foo): + (fu): + (bar): + (baz): + (.bar): + (.baz): + * tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added. + (foo): + (fu): + (bar): + (baz): + (.bar): + (.baz): + + 2014-06-18 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove CompoundType and LeafType + https://bugs.webkit.org/show_bug.cgi?id=134037 + + Reviewed by Filip Pizlo. + + We don't use them for anything. We'll replace them with a generic CellType type for all + the objects that are JSCells, aren't JSObjects, and for which we generally don't care about + their JSType at runtime. + + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * runtime/ArrayBufferNeuteringWatchpoint.cpp: + (JSC::ArrayBufferNeuteringWatchpoint::createStructure): + * runtime/Executable.h: + (JSC::ExecutableBase::createStructure): + (JSC::NativeExecutable::createStructure): + * runtime/JSPromiseDeferred.h: + (JSC::JSPromiseDeferred::createStructure): + * runtime/JSPromiseReaction.h: + (JSC::JSPromiseReaction::createStructure): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::createStructure): + * runtime/JSType.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::TypeInfo): + * runtime/MapData.h: + (JSC::MapData::createStructure): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::createStructure): + * runtime/RegExp.h: + (JSC::RegExp::createStructure): + * runtime/SparseArrayValueMap.cpp: + (JSC::SparseArrayValueMap::createStructure): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + * runtime/StructureChain.h: + (JSC::StructureChain::createStructure): + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::createStructure): + * runtime/SymbolTable.h: + (JSC::SymbolTable::createStructure): + * runtime/WeakMapData.h: + (JSC::WeakMapData::createStructure): + + 2014-06-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] PutStructure and PhantomPutStructure shouldn't leave the world in a clobbered state + https://bugs.webkit.org/show_bug.cgi?id=134002 + + Reviewed by Mark Hahnenberg. + + The effect of this bug was that if we had a PutStructure or PhantomPutStructure then any + JSConstants would be in a Clobbered state, so we wouldn't take advantage of our knowledge + of the structure if that structure was watchable. + + Also kill PhantomPutStructure. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::visitChildren): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasTransition): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.cpp: + (JSC::DFG::StructureAbstractValue::observeTransition): + (JSC::DFG::StructureAbstractValue::observeTransitions): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGWatchableStructureWatchingPhase.cpp: + (JSC::DFG::WatchableStructureWatchingPhase::run): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePhantomPutStructure): Deleted. + + 2014-06-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base + https://bugs.webkit.org/show_bug.cgi?id=133964 + + Reviewed by Mark Hahnenberg. + + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::appendVariant): + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::oldStructureForTransition): + (JSC::PutByIdVariant::writesStructures): + (JSC::PutByIdVariant::reallocatesStorage): + (JSC::PutByIdVariant::attemptToMerge): + (JSC::PutByIdVariant::attemptToMergeTransitionWithReplace): + (JSC::PutByIdVariant::dumpInContext): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::PutByIdVariant): + (JSC::PutByIdVariant::replace): + (JSC::PutByIdVariant::transition): + (JSC::PutByIdVariant::structure): + (JSC::PutByIdVariant::oldStructure): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::visitChildren): + * dfg/DFGNode.cpp: + (JSC::DFG::MultiPutByOffsetData::writesStructures): + (JSC::DFG::MultiPutByOffsetData::reallocatesStorage): + * ftl/FTLAbbreviations.h: + (JSC::FTL::getLinkage): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): + +2014-07-26 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, roll out r171641-r171644. It broke some tests; will investigate and + reland later. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::printPutByIdCacheStatus): Deleted. + * bytecode/CodeBlock.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::dumpInContext): + * bytecode/GetByIdVariant.h: + (JSC::GetByIdVariant::structureSet): + * bytecode/Instruction.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::appendVariant): + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdStatus.h: + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::dumpInContext): + (JSC::PutByIdVariant::oldStructureForTransition): Deleted. + (JSC::PutByIdVariant::writesStructures): Deleted. + (JSC::PutByIdVariant::reallocatesStorage): Deleted. + (JSC::PutByIdVariant::attemptToMerge): Deleted. + (JSC::PutByIdVariant::attemptToMergeTransitionWithReplace): Deleted. + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::PutByIdVariant): + (JSC::PutByIdVariant::replace): + (JSC::PutByIdVariant::transition): + (JSC::PutByIdVariant::structure): + (JSC::PutByIdVariant::oldStructure): + (JSC::PutByIdVariant::newStructure): + (JSC::PutByIdVariant::constantChecks): + * bytecode/StructureSet.cpp: + (JSC::StructureSet::filter): Deleted. + (JSC::StructureSet::filterArrayModes): Deleted. + * bytecode/StructureSet.h: + (JSC::StructureSet::onlyStructure): + * bytecode/ToThisStatus.cpp: Removed. + * bytecode/ToThisStatus.h: Removed. + * bytecode/TypeLocation.h: Removed. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitPutToScope): + (JSC::BytecodeGenerator::emitPutById): + (JSC::BytecodeGenerator::emitPutByVal): + (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): Deleted. + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::PostfixNode::emitResolve): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::ForInNode::emitBytecode): + * debugger/DebuggerActivation.cpp: Added. + (JSC::DebuggerActivation::DebuggerActivation): + (JSC::DebuggerActivation::finishCreation): + (JSC::DebuggerActivation::visitChildren): + (JSC::DebuggerActivation::className): + (JSC::DebuggerActivation::getOwnPropertySlot): + (JSC::DebuggerActivation::put): + (JSC::DebuggerActivation::deleteProperty): + (JSC::DebuggerActivation::getOwnPropertyNames): + (JSC::DebuggerActivation::defineOwnProperty): + * debugger/DebuggerActivation.h: Added. + (JSC::DebuggerActivation::create): + (JSC::DebuggerActivation::createStructure): + * debugger/DebuggerScope.cpp: Removed. + * debugger/DebuggerScope.h: Removed. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::changeStructure): Deleted. + (JSC::DFG::AbstractValue::contains): Deleted. + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::couldBeType): + (JSC::DFG::AbstractValue::isType): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addBaseCheck): Deleted. + (JSC::DFG::ConstantFoldingPhase::addChecks): Deleted. + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::visitChildren): + (JSC::DFG::Graph::freezeStrong): + * dfg/DFGGraph.h: + * dfg/DFGNode.cpp: + (JSC::DFG::MultiPutByOffsetData::writesStructures): + (JSC::DFG::MultiPutByOffsetData::reallocatesStorage): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPutByOffset): + (JSC::DFG::Node::hasTransition): + (JSC::DFG::Node::convertToMultiGetByOffset): Deleted. + (JSC::DFG::Node::convertToMultiPutByOffset): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.cpp: + (JSC::DFG::StructureAbstractValue::observeTransition): + (JSC::DFG::StructureAbstractValue::observeTransitions): + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::onlyStructure): + (JSC::DFG::StructureAbstractValue::operator=): Deleted. + (JSC::DFG::StructureAbstractValue::set): Deleted. + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGWatchableStructureWatchingPhase.cpp: + (JSC::DFG::WatchableStructureWatchingPhase::run): + * ftl/FTLAbbreviations.h: + (JSC::FTL::getLinkage): Deleted. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePhantomPutStructure): + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): + * heap/Heap.cpp: + (JSC::Heap::collect): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange): Deleted. + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + * jsc.cpp: + (GlobalObject::finishCreation): + (functionDumpTypesForAllVariables): Deleted. + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (JSC::LLInt::putToScopeCommon): Deleted. + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/ArrayBufferNeuteringWatchpoint.cpp: + (JSC::ArrayBufferNeuteringWatchpoint::createStructure): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/Executable.h: + (JSC::ExecutableBase::createStructure): + (JSC::NativeExecutable::createStructure): + * runtime/HighFidelityLog.cpp: Removed. + * runtime/HighFidelityLog.h: Removed. + * runtime/HighFidelityTypeProfiler.cpp: Removed. + * runtime/HighFidelityTypeProfiler.h: Removed. + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectCustomAccessor): + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::reifyStaticFunctionsForDelete): + * runtime/JSPromiseDeferred.h: + (JSC::JSPromiseDeferred::createStructure): + * runtime/JSPromiseReaction.h: + (JSC::JSPromiseReaction::createStructure): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::createStructure): + * runtime/JSType.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::TypeInfo): + * runtime/MapData.h: + (JSC::MapData::createStructure): + * runtime/Options.h: + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::createStructure): + * runtime/RegExp.h: + (JSC::RegExp::createStructure): + * runtime/SparseArrayValueMap.cpp: + (JSC::SparseArrayValueMap::createStructure): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::StructureTransitionTable::add): + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::freezeTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::takePropertyTableOrCloneIfPinned): + (JSC::Structure::nonPropertyTransition): + (JSC::Structure::flattenDictionaryStructure): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::pin): + (JSC::Structure::allocateRareData): + (JSC::Structure::cloneRareDataFrom): + (JSC::Structure::getConcurrently): + (JSC::Structure::putSpecificValue): + (JSC::Structure::getPropertyNamesFromStructure): + (JSC::Structure::visitChildren): + (JSC::Structure::checkConsistency): + (JSC::Structure::toStructureShape): Deleted. + * runtime/Structure.h: + (JSC::Structure::isExtensible): + (JSC::Structure::didTransition): + (JSC::Structure::isDictionary): + (JSC::Structure::isUncacheableDictionary): + (JSC::Structure::hasBeenFlattenedBefore): + (JSC::Structure::propertyAccessesAreCacheable): + (JSC::Structure::previousID): + (JSC::Structure::hasGetterSetterProperties): + (JSC::Structure::hasReadOnlyOrGetterSetterPropertiesExcludingProto): + (JSC::Structure::setHasGetterSetterProperties): + (JSC::Structure::hasCustomGetterSetterProperties): + (JSC::Structure::setHasCustomGetterSetterProperties): + (JSC::Structure::setContainsReadOnlyProperties): + (JSC::Structure::hasNonEnumerableProperties): + (JSC::Structure::disableSpecificFunctionTracking): + (JSC::Structure::objectToStringValue): + (JSC::Structure::setObjectToStringValue): + (JSC::Structure::staticFunctionsReified): + (JSC::Structure::setStaticFunctionsReified): + (JSC::Structure::transitionWatchpointSet): + (JSC::Structure::setPreviousID): + (JSC::Structure::clearPreviousID): + (JSC::Structure::previous): + (JSC::Structure::rareData): + (JSC::Structure::setHasGetterSetterPropertiesWithProtoCheck): Deleted. + (JSC::Structure::setHasCustomGetterSetterPropertiesWithProtoCheck): Deleted. + * runtime/StructureChain.h: + (JSC::StructureChain::createStructure): + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::enumerationCache): + (JSC::Structure::checkOffsetConsistency): + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::createStructure): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::SymbolTable): + (JSC::SymbolTable::cloneCapturedNames): + (JSC::SymbolTable::uniqueIDForVariable): Deleted. + (JSC::SymbolTable::uniqueIDForRegister): Deleted. + (JSC::SymbolTable::globalTypeSetForRegister): Deleted. + (JSC::SymbolTable::globalTypeSetForVariable): Deleted. + * runtime/SymbolTable.h: + (JSC::SymbolTable::createStructure): + (JSC::SymbolTable::add): + (JSC::SymbolTable::set): + * runtime/TypeSet.cpp: Removed. + * runtime/TypeSet.h: Removed. + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::getTypesForVariableInRange): Deleted. + (JSC::VM::updateHighFidelityTypeProfileState): Deleted. + (JSC::VM::dumpHighFidelityProfilingTypes): Deleted. + * runtime/VM.h: + (JSC::VM::isProfilingTypesWithHighFidelity): Deleted. + (JSC::VM::highFidelityLog): Deleted. + (JSC::VM::highFidelityTypeProfiler): Deleted. + (JSC::VM::nextLocation): Deleted. + (JSC::VM::getNextUniqueVariableID): Deleted. + * runtime/WeakMapData.h: + (JSC::WeakMapData::createStructure): + * tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Removed. + * tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Removed. + * tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Removed. + +2014-07-25 Filip Pizlo <fpizlo@apple.com> + + Attempt to fix non-Xcode platforms. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + +2014-07-25 Filip Pizlo <fpizlo@apple.com> + + Fix cloop. + + * bytecode/CodeBlock.cpp: + (JSC::dumpChain): + (JSC::CodeBlock::printPutByIdCacheStatus): + * bytecode/StructureSet.cpp: + * bytecode/StructureSet.h: + +2014-07-25 Filip Pizlo <fpizlo@apple.com> + + Merge r170090, r170092, r170129, r170141, r170161, r170215, r170275, r170375, r170376, r170382, r170383, r170399, r170436, r170489, r170490, r170556 from ftlopt. + + 2014-06-27 Michael Saboff <msaboff@apple.com> + + Unreviewed build fix after r169795. + + Fixed ASSERT for 32 bit build. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + + 2014-06-24 Saam Barati <sbarati@apple.com> + + Web Inspector: debugger should be able to show variable types + https://bugs.webkit.org/show_bug.cgi?id=133395 + + Reviewed by Filip Pizlo. + + Increase the amount of type information the VM gathers when directed + to do so. This initial commit is working towards the goal of + capturing, and then showing (via the Web Inspector) type information for all + assignment and load operations. This patch doesn't have the feature fully + implemented, but it ensures the VM has no performance regressions + unless the feature is specifically turned on. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecode/CodeBlock.h: + * bytecode/Instruction.h: + * bytecode/TypeLocation.h: Added. + (JSC::TypeLocation::TypeLocation): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity): + (JSC::BytecodeGenerator::emitPutToScope): + (JSC::BytecodeGenerator::emitPutById): + (JSC::BytecodeGenerator::emitPutByVal): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::isProfilingTypesWithHighFidelity): + * bytecompiler/NodesCodegen.cpp: + (JSC::PostfixNode::emitResolve): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::ForInNode::emitBytecode): + * heap/Heap.cpp: + (JSC::Heap::collect): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypeForVariableInTextRange): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + * jsc.cpp: + (GlobalObject::finishCreation): + (functionDumpTypesForAllVariables): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (JSC::LLInt::putToScopeCommon): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * runtime/HighFidelityLog.cpp: Added. + (JSC::HighFidelityLog::initializeHighFidelityLog): + (JSC::HighFidelityLog::~HighFidelityLog): + (JSC::HighFidelityLog::recordTypeInformationForLocation): + (JSC::HighFidelityLog::processHighFidelityLog): + (JSC::HighFidelityLog::actuallyProcessLogThreadFunction): + * runtime/HighFidelityLog.h: Added. + (JSC::HighFidelityLog::HighFidelityLog): + * runtime/HighFidelityTypeProfiler.cpp: Added. + (JSC::HighFidelityTypeProfiler::getTypesForVariableInRange): + (JSC::HighFidelityTypeProfiler::getGlobalTypesForVariableInRange): + (JSC::HighFidelityTypeProfiler::getLocalTypesForVariableInRange): + (JSC::HighFidelityTypeProfiler::insertNewLocation): + (JSC::HighFidelityTypeProfiler::getLocationBasedHash): + * runtime/HighFidelityTypeProfiler.h: Added. + * runtime/Options.h: + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + * runtime/Structure.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::SymbolTable): + (JSC::SymbolTable::cloneCapturedNames): + (JSC::SymbolTable::uniqueIDForVariable): + (JSC::SymbolTable::uniqueIDForRegister): + (JSC::SymbolTable::globalTypeSetForRegister): + (JSC::SymbolTable::globalTypeSetForVariable): + * runtime/SymbolTable.h: + (JSC::SymbolTable::add): + (JSC::SymbolTable::set): + * runtime/TypeSet.cpp: Added. + (JSC::TypeSet::TypeSet): + (JSC::TypeSet::getRuntimeTypeForValue): + (JSC::TypeSet::addTypeForValue): + (JSC::TypeSet::removeDuplicatesInStructureHistory): + (JSC::TypeSet::seenTypes): + (JSC::TypeSet::dumpSeenTypes): + (JSC::StructureShape::StructureShape): + (JSC::StructureShape::markAsFinal): + (JSC::StructureShape::addProperty): + (JSC::StructureShape::propertyHash): + (JSC::StructureShape::leastUpperBound): + (JSC::StructureShape::stringRepresentation): + * runtime/TypeSet.h: Added. + (JSC::StructureShape::create): + (JSC::TypeSet::create): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::getTypesForVariableInRange): + (JSC::VM::updateHighFidelityTypeProfileState): + (JSC::VM::dumpHighFidelityProfilingTypes): + * runtime/VM.h: + (JSC::VM::isProfilingTypesWithHighFidelity): + (JSC::VM::highFidelityLog): + (JSC::VM::highFidelityTypeProfiler): + (JSC::VM::nextLocation): + (JSC::VM::getNextUniqueVariableID): + + 2014-06-26 Mark Lam <mark.lam@apple.com> + + Remove unused instantiation of the WithScope structure. + <https://webkit.org/b/134331> + + Reviewed by Oliver Hunt. + + The WithScope structure instance is the VM is unused, and is now removed. + + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + + 2014-06-25 Mark Hahnenberg <mhahnenberg@apple.com> + + Structure bit fields should have a consistent format + https://bugs.webkit.org/show_bug.cgi?id=134307 + + Reviewed by Filip Pizlo. + + Currently we use C-style bit fields for a number of member variables in Structure to save space. + This makes it difficult to load these fields in the JIT. We should instead use our own bitfield + format to make it easy to load and test these variables in JIT code. + + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::reifyStaticFunctionsForDelete): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::StructureTransitionTable::add): + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::freezeTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::takePropertyTableOrCloneIfPinned): + (JSC::Structure::nonPropertyTransition): + (JSC::Structure::flattenDictionaryStructure): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::pin): + (JSC::Structure::allocateRareData): + (JSC::Structure::cloneRareDataFrom): + (JSC::Structure::getConcurrently): + (JSC::Structure::putSpecificValue): + (JSC::Structure::getPropertyNamesFromStructure): + (JSC::Structure::visitChildren): + (JSC::Structure::checkConsistency): + * runtime/Structure.h: + (JSC::Structure::isExtensible): + (JSC::Structure::isDictionary): + (JSC::Structure::isUncacheableDictionary): + (JSC::Structure::propertyAccessesAreCacheable): + (JSC::Structure::previousID): + (JSC::Structure::setHasGetterSetterPropertiesWithProtoCheck): + (JSC::Structure::setContainsReadOnlyProperties): + (JSC::Structure::disableSpecificFunctionTracking): + (JSC::Structure::objectToStringValue): + (JSC::Structure::setObjectToStringValue): + (JSC::Structure::setPreviousID): + (JSC::Structure::clearPreviousID): + (JSC::Structure::previous): + (JSC::Structure::rareData): + (JSC::Structure::didTransition): Deleted. + (JSC::Structure::hasGetterSetterProperties): Deleted. + (JSC::Structure::hasReadOnlyOrGetterSetterPropertiesExcludingProto): Deleted. + (JSC::Structure::setHasGetterSetterProperties): Deleted. + (JSC::Structure::hasNonEnumerableProperties): Deleted. + (JSC::Structure::staticFunctionsReified): Deleted. + (JSC::Structure::setStaticFunctionsReified): Deleted. + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::enumerationCache): + (JSC::Structure::checkOffsetConsistency): + + 2014-06-24 Mark Lam <mark.lam@apple.com> + + [ftlopt] Renamed DebuggerActivation to DebuggerScope. + <https://webkit.org/b/134273> + + Reviewed by Michael Saboff. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * debugger/DebuggerActivation.cpp: Removed. + * debugger/DebuggerActivation.h: Removed. + * debugger/DebuggerScope.cpp: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.cpp. + (JSC::DebuggerScope::DebuggerScope): + (JSC::DebuggerScope::finishCreation): + (JSC::DebuggerScope::visitChildren): + (JSC::DebuggerScope::className): + (JSC::DebuggerScope::getOwnPropertySlot): + (JSC::DebuggerScope::put): + (JSC::DebuggerScope::deleteProperty): + (JSC::DebuggerScope::getOwnPropertyNames): + (JSC::DebuggerScope::defineOwnProperty): + (JSC::DebuggerActivation::DebuggerActivation): Deleted. + (JSC::DebuggerActivation::finishCreation): Deleted. + (JSC::DebuggerActivation::visitChildren): Deleted. + (JSC::DebuggerActivation::className): Deleted. + (JSC::DebuggerActivation::getOwnPropertySlot): Deleted. + (JSC::DebuggerActivation::put): Deleted. + (JSC::DebuggerActivation::deleteProperty): Deleted. + (JSC::DebuggerActivation::getOwnPropertyNames): Deleted. + (JSC::DebuggerActivation::defineOwnProperty): Deleted. + * debugger/DebuggerScope.h: Copied from ../../trunk/Source/JavaScriptCore/debugger/DebuggerActivation.h. + (JSC::DebuggerScope::create): + (JSC::DebuggerActivation::create): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] PutByIdFlush can also be converted to a PutByOffset so don't assert otherwise + https://bugs.webkit.org/show_bug.cgi?id=134265 + + Reviewed by Geoffrey Garen. + + More assertion fallout from the PutById folding work. + + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPutByOffset): + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] GC should notify us if it resets to_this + https://bugs.webkit.org/show_bug.cgi?id=128231 + + Reviewed by Geoffrey Garen. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecode/Instruction.h: + * bytecode/ToThisStatus.cpp: Added. + (JSC::merge): + (WTF::printInternal): + * bytecode/ToThisStatus.h: Added. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] StructureAbstractValue::onlyStructure() should return nullptr if isClobbered() + https://bugs.webkit.org/show_bug.cgi?id=134256 + + Reviewed by Michael Saboff. + + This isn't testable right now (i.e. it's benign) but we should get it right anyway. The + point is to be able to precisely model what goes on in the snippets of code between a + side-effect and an InvalidationPoint. + + This patch also cleans up onlyStructure() by delegating more work to + StructureSet::onlyStructure(). + + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::onlyStructure): + + 2014-06-24 Filip Pizlo <fpizlo@apple.com> + + [ftlopt][REGRESSION] PutById AI is introducing watchable structures without watching them + https://bugs.webkit.org/show_bug.cgi?id=134260 + + Reviewed by Geoffrey Garen. + + This was causing loads of assertion failures in debug builds. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + + 2014-06-21 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets + https://bugs.webkit.org/show_bug.cgi?id=134090 + + Reviewed by Oliver Hunt. + + This pretty much finishes off the work to eliminate the special-casing of singleton + structure sets by making it possible to fold GetById and PutById to various polymorphic + forms of the ByOffset nodes. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdStatus.h: + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::constantChecks): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addChecks): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToMultiGetByOffset): + (JSC::DFG::Node::convertToMultiPutByOffset): + * dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging. + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::set): + + 2014-06-19 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] StructureSet::onlyStructure() should return nullptr if it's not a singleton (instead of asserting) + https://bugs.webkit.org/show_bug.cgi?id=134077 + + Reviewed by Sam Weinig. + + This makes StructureSet and StructureAbstractValue more consistent and fixes a debug assert + in the abstract interpreter. + + * bytecode/StructureSet.h: + (JSC::StructureSet::onlyStructure): + + 2014-06-18 Filip Pizlo <fpizlo@apple.com> + + DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton + https://bugs.webkit.org/show_bug.cgi?id=133918 + + Reviewed by Mark Hahnenberg. + + This also adds pruning of PutStructure, since I basically had no choice but + to implement such logic within MultiPutByOffset. + + Also adds a bunch of PutById cache status dumping to bytecode dumping. + + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::dumpInContext): + * bytecode/GetByIdVariant.h: + (JSC::GetByIdVariant::structureSet): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::oldStructure): + * bytecode/StructureSet.cpp: + (JSC::StructureSet::filter): + (JSC::StructureSet::filterArrayModes): + * bytecode/StructureSet.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::changeStructure): + (JSC::DFG::AbstractValue::contains): + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::couldBeType): + (JSC::DFG::AbstractValue::isType): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addBaseCheck): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::freezeStrong): + * dfg/DFGGraph.h: + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::operator=): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + * tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added. + (foo): + (fu): + (bar): + (baz): + (.bar): + (.baz): + * tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added. + (foo): + (fu): + (bar): + (baz): + (.bar): + (.baz): + * tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added. + (foo): + (fu): + (bar): + (baz): + (.bar): + (.baz): + + 2014-06-18 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove CompoundType and LeafType + https://bugs.webkit.org/show_bug.cgi?id=134037 + + Reviewed by Filip Pizlo. + + We don't use them for anything. We'll replace them with a generic CellType type for all + the objects that are JSCells, aren't JSObjects, and for which we generally don't care about + their JSType at runtime. + + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * runtime/ArrayBufferNeuteringWatchpoint.cpp: + (JSC::ArrayBufferNeuteringWatchpoint::createStructure): + * runtime/Executable.h: + (JSC::ExecutableBase::createStructure): + (JSC::NativeExecutable::createStructure): + * runtime/JSPromiseDeferred.h: + (JSC::JSPromiseDeferred::createStructure): + * runtime/JSPromiseReaction.h: + (JSC::JSPromiseReaction::createStructure): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::createStructure): + * runtime/JSType.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::TypeInfo): + * runtime/MapData.h: + (JSC::MapData::createStructure): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::createStructure): + * runtime/RegExp.h: + (JSC::RegExp::createStructure): + * runtime/SparseArrayValueMap.cpp: + (JSC::SparseArrayValueMap::createStructure): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + * runtime/StructureChain.h: + (JSC::StructureChain::createStructure): + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::createStructure): + * runtime/SymbolTable.h: + (JSC::SymbolTable::createStructure): + * runtime/WeakMapData.h: + (JSC::WeakMapData::createStructure): + + 2014-06-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] PutStructure and PhantomPutStructure shouldn't leave the world in a clobbered state + https://bugs.webkit.org/show_bug.cgi?id=134002 + + Reviewed by Mark Hahnenberg. + + The effect of this bug was that if we had a PutStructure or PhantomPutStructure then any + JSConstants would be in a Clobbered state, so we wouldn't take advantage of our knowledge + of the structure if that structure was watchable. + + Also kill PhantomPutStructure. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::visitChildren): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasTransition): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.cpp: + (JSC::DFG::StructureAbstractValue::observeTransition): + (JSC::DFG::StructureAbstractValue::observeTransitions): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGWatchableStructureWatchingPhase.cpp: + (JSC::DFG::WatchableStructureWatchingPhase::run): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePhantomPutStructure): Deleted. + + 2014-06-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base + https://bugs.webkit.org/show_bug.cgi?id=133964 + + Reviewed by Mark Hahnenberg. + + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::appendVariant): + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::oldStructureForTransition): + (JSC::PutByIdVariant::writesStructures): + (JSC::PutByIdVariant::reallocatesStorage): + (JSC::PutByIdVariant::attemptToMerge): + (JSC::PutByIdVariant::attemptToMergeTransitionWithReplace): + (JSC::PutByIdVariant::dumpInContext): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::PutByIdVariant): + (JSC::PutByIdVariant::replace): + (JSC::PutByIdVariant::transition): + (JSC::PutByIdVariant::structure): + (JSC::PutByIdVariant::oldStructure): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::visitChildren): + * dfg/DFGNode.cpp: + (JSC::DFG::MultiPutByOffsetData::writesStructures): + (JSC::DFG::MultiPutByOffsetData::reallocatesStorage): + * ftl/FTLAbbreviations.h: + (JSC::FTL::getLinkage): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): + +2014-07-25 Filip Pizlo <fpizlo@apple.com> + + Add an option to disable native call inlining. Disable it for now to see how it + affects the bots. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + * runtime/Options.h: + +2014-07-25 Filip Pizlo <fpizlo@apple.com> + + Fix cloop. + + * dfg/DFGMayExit.cpp: + +2014-07-25 Filip Pizlo <fpizlo@apple.com> + + Merge r169795, r169819, r169864, r169902, r169949, r169950, r170016, r170017, r170060, r170064 from ftlopt. + + 2014-06-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Fold constant Phis + https://bugs.webkit.org/show_bug.cgi?id=133967 + + Reviewed by Mark Hahnenberg. + + It's surprising but we didn't really do this before. Or, rather, we only did it + incidentally when we would likely crash if it ever happened. + + Making this work required cleaning up the validater a bit, so I did that too. I also added + mayExit() validation for nodes that didn't have origin.forExit (i.e. nodes that end up in + the Phi header of basic blocks). But this required beefing up mayExit() a bit. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAdjacencyList.h: + (JSC::DFG::AdjacencyList::isEmpty): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::run): + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::fixUpsilons): + * dfg/DFGInPlaceAbstractState.h: + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::run): + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + (JSC::DFG::Validate::validateSSA): + + 2014-06-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Get rid of NodeDoesNotExit and also get rid of StoreEliminationPhase + https://bugs.webkit.org/show_bug.cgi?id=133985 + + Reviewed by Michael Saboff and Mark Hahnenberg. + + Store elimination phase has never been very profitable, and now that LLVM can do dead + store elimination for us, this phase is just completely pointless. + + This phase is also the primary user of NodeDoesNotExit, which is a flag that the CFA + computes. It computes it poorly and we often get bugs in it. It's also a lot of code to + maintain. + + This patch does introduce a new mayExit() calculator that is independent of the CFA and + should be enough for most of the previous NodeDoesNotExit users. Currently it's only used + for assertions in the DFG backend, but we could use it if we ever brought back any of the + other optimizations that previously relied upon NodeDoesNotExit. + + This is performance-neutral, except for SunSpider, where it's a speed-up. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::filterEdgeByUse): + (JSC::DFG::AbstractInterpreter::filterByType): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::startExecuting): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::CSEPhase): + (JSC::DFG::CSEPhase::invalidationPointElimination): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::performBlockCSE): + (JSC::DFG::performCSE): + (JSC::DFG::CSEPhase::globalVarStoreElimination): Deleted. + (JSC::DFG::CSEPhase::scopedVarStoreElimination): Deleted. + (JSC::DFG::CSEPhase::putStructureStoreElimination): Deleted. + (JSC::DFG::CSEPhase::putByOffsetStoreElimination): Deleted. + (JSC::DFG::CSEPhase::SetLocalStoreEliminationResult::SetLocalStoreEliminationResult): Deleted. + (JSC::DFG::performStoreElimination): Deleted. + * dfg/DFGCSEPhase.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::resetExitStates): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGMayExit.cpp: Added. + (JSC::DFG::mayExit): + * dfg/DFGMayExit.h: Added. + * dfg/DFGNode.h: + (JSC::DFG::Node::mergeFlags): + (JSC::DFG::Node::filterFlags): + (JSC::DFG::Node::setCanExit): Deleted. + (JSC::DFG::Node::canExit): Deleted. + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + * dfg/DFGNodeType.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::terminateSpeculativeExecution): + (JSC::DFG::SpeculativeJIT::bail): + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + + 2014-06-15 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Remove the DFG optimization fixpoint and remove some obvious reasons why we previously benefited from it + https://bugs.webkit.org/show_bug.cgi?id=133931 + + Reviewed by Oliver Hunt. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): Trigger constant-folding for GetMyArgumentByVal (which means turning it into GetLocalUnlinked) and correct the handling of Upsilon so we don't fold them away. + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): Implement constant-folding for GetMyArgumentByVal. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): Remove the fixpoint. + + 2014-06-15 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG OSR entry should have a crystal-clear story for when it's safe to enter at a block with a set of values + https://bugs.webkit.org/show_bug.cgi?id=133935 + + Reviewed by Oliver Hunt. + + * bytecode/Operands.h: + (JSC::Operands::Operands): + (JSC::Operands::ensureLocals): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::filter): Now we can compute intersections of abstract values! + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::makeFullTop): Completeness. + (JSC::DFG::AbstractValue::bytecodeTop): Completeness. + (JSC::DFG::AbstractValue::fullTop): Completeness. We end up using this one. + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::BasicBlock): + (JSC::DFG::BasicBlock::ensureLocals): + * dfg/DFGBasicBlock.h: Remember the intersection of all things ever proven. + * dfg/DFGCFAPhase.cpp: + (JSC::DFG::CFAPhase::run): Compute the intersection. + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): No need for the weirdo merge check since this fixes the root of the problem. + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dumpBlockHeader): Better dumping. + (JSC::DFG::Graph::dump): Better dumping. + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::noticeOSREntry): Use the intersected abstract value. + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): Assert if the intersected state indicates the block shouldn't execute. + + 2014-06-12 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] A DFG inlined ById access variant should not speak of a chain, but only of what structures to test the base for, whether to use a constant as an alternate base for the actual access, and what structures to check on what additional cell constants + https://bugs.webkit.org/show_bug.cgi?id=133821 + + Reviewed by Mark Hahnenberg. + + This allows us to efficiently cache accesses that differ only in the prototypes on the path + from the base to the prototype that has the field. + + It also simplifies a bunch of code - IntendedStructureChain is now just an intermediate + data structure. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/ConstantStructureCheck.cpp: Added. + (JSC::ConstantStructureCheck::dumpInContext): + (JSC::ConstantStructureCheck::dump): + (JSC::structureFor): + (JSC::areCompatible): + (JSC::mergeInto): + * bytecode/ConstantStructureCheck.h: Added. + (JSC::ConstantStructureCheck::ConstantStructureCheck): + (JSC::ConstantStructureCheck::operator!): + (JSC::ConstantStructureCheck::constant): + (JSC::ConstantStructureCheck::structure): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::GetByIdVariant): + (JSC::GetByIdVariant::operator=): + (JSC::GetByIdVariant::attemptToMerge): + (JSC::GetByIdVariant::dumpInContext): + * bytecode/GetByIdVariant.h: + (JSC::GetByIdVariant::constantChecks): + (JSC::GetByIdVariant::alternateBase): + (JSC::GetByIdVariant::GetByIdVariant): Deleted. + (JSC::GetByIdVariant::chain): Deleted. + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::dumpInContext): + * bytecode/PutByIdVariant.h: + (JSC::PutByIdVariant::transition): + (JSC::PutByIdVariant::constantChecks): + (JSC::PutByIdVariant::structureChain): Deleted. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitChecks): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::cellConstantWithStructureCheck): Deleted. + (JSC::DFG::ByteCodeParser::structureChainIsStillValid): Deleted. + (JSC::DFG::ByteCodeParser::emitPrototypeChecks): Deleted. + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck): + * dfg/DFGDesiredStructureChains.cpp: Removed. + * dfg/DFGDesiredStructureChains.h: Removed. + * dfg/DFGGraph.h: + (JSC::DFG::Graph::watchpoints): + (JSC::DFG::Graph::chains): Deleted. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::isStillValid): + (JSC::DFG::Plan::checkLivenessAndVisitChildren): + (JSC::DFG::Plan::cancel): + * dfg/DFGPlan.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::gatherChecks): + * runtime/IntendedStructureChain.h: + (JSC::IntendedStructureChain::at): + (JSC::IntendedStructureChain::operator[]): + + 2014-06-12 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Constant folding and strength reduction should work in SSA + https://bugs.webkit.org/show_bug.cgi?id=133839 + + Reviewed by Oliver Hunt. + + * dfg/DFGAtTailAbstractState.cpp: + (JSC::DFG::AtTailAbstractState::AtTailAbstractState): + (JSC::DFG::AtTailAbstractState::forNode): + * dfg/DFGAtTailAbstractState.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::convertToConstant): + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::rangeKeyAndAddend): Fix an unrelated regression that this uncovered. + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::LICMPhase): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + + 2014-06-11 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG get_by_id should inline chain accesses with a slightly polymorphic base + https://bugs.webkit.org/show_bug.cgi?id=133751 + + Reviewed by Mark Hahnenberg. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::appendVariant): + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::attemptToMerge): + * bytecode/GetByIdVariant.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPrototypeChecks): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::IntendedStructureChain): + (JSC::IntendedStructureChain::isStillValid): + (JSC::IntendedStructureChain::isNormalized): + (JSC::IntendedStructureChain::terminalPrototype): + (JSC::IntendedStructureChain::operator==): + (JSC::IntendedStructureChain::visitChildren): + (JSC::IntendedStructureChain::dumpInContext): + (JSC::IntendedStructureChain::chain): Deleted. + * runtime/IntendedStructureChain.h: + (JSC::IntendedStructureChain::prototype): + (JSC::IntendedStructureChain::operator!=): + (JSC::IntendedStructureChain::head): Deleted. + + 2014-06-11 Matthew Mirman <mmirman@apple.com> + + Readded native calling to the FTL and Split the DFG nodes + Call and Construct into NativeCall and NativeConstruct + to better represent their semantics. + https://bugs.webkit.org/show_bug.cgi?id=133660 + + Reviewed by Filip Pizlo. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + Added NativeCall and NativeConstruct case + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCall): added NativeCall case. + (JSC::DFG::ByteCodeParser::handleCall): + set to return NativeCall or NativeConstruct instead of Call or Construct + in the presence of a native function. + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): added NativeCall and NativeConstruct case. + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): added NativeCall and NativeConstruct case. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): added NativeCall and NativeConstruct case. + * dfg/DFGNode.h: + (JSC::DFG::Node::hasHeapPrediction): added NativeCall and NativeConstruct case. + (JSC::DFG::Node::canBeKnownFunction): changed to NativeCall and NativeConstruct. + (JSC::DFG::Node::hasKnownFunction): changed to NativeCall and NativeConstruct. + * dfg/DFGNodeType.h: added NativeCall and NativeConstruct. + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): added NativeCall and NativeConstruct case. + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): added NativeCall and NativeConstruct case. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): ditto + (JSC::DFG::SpeculativeJIT::compile): ditto + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): ditto + (JSC::DFG::SpeculativeJIT::compile): ditto + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): ditto + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): ditto + (JSC::FTL::LowerDFGToLLVM::compileNode): ditto. + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): Added. + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): removed NativeCall and NativeConstruct functionality. + (JSC::FTL::LowerDFGToLLVM::didOverflowStack): added NativeCall and NativeConstruct case. + * runtime/JSCJSValue.h: added JS_EXPORT_PRIVATE to toInteger as it is apparently needed. + + 2014-06-11 Matthew Mirman <mmirman@apple.com> + + Ensured Native Calls and Construct and associated checks + are only emitted during ftl mode. + https://bugs.webkit.org/show_bug.cgi?id=133718 + + Reviewed by Filip Pizlo. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): Added check for ftl mode + before attaching the native function to Call or Construct. + + 2014-06-10 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG should use its own notion of JSValue, which we should call FrozenValue, that will carry around a copy of its structure + https://bugs.webkit.org/show_bug.cgi?id=133426 + + Reviewed by Geoffrey Garen. + + The impetus for this was to provide some sense and reason to race conditions arising from + cell constants having their structure changed on the main thread - this is harmess because + we defend against it, but when it goes wrong, it can be difficult to reproduce because it + requires a race. Giving the DFG the ability to "freeze" a cell's structure fixes this. + + But this patch goes quite a bit further, and completely rationalizes how the DFG reasons + about constants. It no longer relies on the CodeBlock constant pool at all, which allows + for a more object-oriented approach: for example a Node that has a constant can tell you + what constant it has without needing a CodeBlock. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeExitSiteData): + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): + (JSC::exitKindIsCountable): + * bytecode/ExitKind.h: + (JSC::isWatchpoint): Deleted. + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::hasExitSite): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::hasExitSite): + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::filterByValue): + (JSC::DFG::AbstractInterpreter::setBuiltInConstant): + (JSC::DFG::AbstractInterpreter::setConstant): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterByValue): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::setOSREntryValue): + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::filterByValue): + (JSC::DFG::AbstractValue::setMostSpecific): Deleted. + * dfg/DFGAbstractValue.h: + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::isNotNegZero): + (JSC::DFG::BackwardsPropagationPhase::isNotPosZero): + (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwoForConstant): + (JSC::DFG::BackwardsPropagationPhase::isWithinPowerOfTwo): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::ByteCodeParser): + (JSC::DFG::ByteCodeParser::getDirect): + (JSC::DFG::ByteCodeParser::get): + (JSC::DFG::ByteCodeParser::getLocal): + (JSC::DFG::ByteCodeParser::setLocal): + (JSC::DFG::ByteCodeParser::setArgument): + (JSC::DFG::ByteCodeParser::jsConstant): + (JSC::DFG::ByteCodeParser::weakJSConstant): + (JSC::DFG::ByteCodeParser::cellConstantWithStructureCheck): + (JSC::DFG::ByteCodeParser::InlineStackEntry::remapOperand): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::emitFunctionChecks): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleMinMax): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::prepareToParseBlock): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::buildOperandMapsIfNecessary): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + (JSC::DFG::ByteCodeParser::addConstant): Deleted. + (JSC::DFG::ByteCodeParser::getJSConstantForValue): Deleted. + (JSC::DFG::ByteCodeParser::getJSConstant): Deleted. + (JSC::DFG::ByteCodeParser::isJSConstant): Deleted. + (JSC::DFG::ByteCodeParser::isInt32Constant): Deleted. + (JSC::DFG::ByteCodeParser::valueOfJSConstant): Deleted. + (JSC::DFG::ByteCodeParser::valueOfInt32Constant): Deleted. + (JSC::DFG::ByteCodeParser::constantUndefined): Deleted. + (JSC::DFG::ByteCodeParser::constantNull): Deleted. + (JSC::DFG::ByteCodeParser::one): Deleted. + (JSC::DFG::ByteCodeParser::constantNaN): Deleted. + (JSC::DFG::ByteCodeParser::cellConstant): Deleted. + (JSC::DFG::ByteCodeParser::inferredConstant): Deleted. + (JSC::DFG::ByteCodeParser::ConstantRecord::ConstantRecord): Deleted. + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::run): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::constantCSE): + (JSC::DFG::CSEPhase::checkFunctionElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::weakConstantCSE): Deleted. + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixupMakeRope): + (JSC::DFG::FixupPhase::truncateConstantToInt32): + (JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteLength): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGFrozenValue.cpp: Added. + (JSC::DFG::FrozenValue::emptySingleton): + (JSC::DFG::FrozenValue::dumpInContext): + (JSC::DFG::FrozenValue::dump): + * dfg/DFGFrozenValue.h: Added. + (JSC::DFG::FrozenValue::FrozenValue): + (JSC::DFG::FrozenValue::operator!): + (JSC::DFG::FrozenValue::value): + (JSC::DFG::FrozenValue::structure): + (JSC::DFG::FrozenValue::strengthenTo): + (JSC::DFG::FrozenValue::strength): + (JSC::DFG::FrozenValue::freeze): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::tryGetActivation): + (JSC::DFG::Graph::tryGetFoldableView): + (JSC::DFG::Graph::registerFrozenValues): + (JSC::DFG::Graph::visitChildren): + (JSC::DFG::Graph::freezeFragile): + (JSC::DFG::Graph::freeze): + (JSC::DFG::Graph::freezeStrong): + (JSC::DFG::Graph::convertToConstant): + (JSC::DFG::Graph::convertToStrongConstant): + (JSC::DFG::Graph::assertIsWatched): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addImmediateShouldSpeculateInt32): + (JSC::DFG::Graph::convertToConstant): Deleted. + (JSC::DFG::Graph::constantRegisterForConstant): Deleted. + (JSC::DFG::Graph::getJSConstantSpeculation): Deleted. + (JSC::DFG::Graph::isConstant): Deleted. + (JSC::DFG::Graph::isJSConstant): Deleted. + (JSC::DFG::Graph::isInt32Constant): Deleted. + (JSC::DFG::Graph::isDoubleConstant): Deleted. + (JSC::DFG::Graph::isNumberConstant): Deleted. + (JSC::DFG::Graph::isBooleanConstant): Deleted. + (JSC::DFG::Graph::isCellConstant): Deleted. + (JSC::DFG::Graph::isFunctionConstant): Deleted. + (JSC::DFG::Graph::isInternalFunctionConstant): Deleted. + (JSC::DFG::Graph::valueOfJSConstant): Deleted. + (JSC::DFG::Graph::valueOfInt32Constant): Deleted. + (JSC::DFG::Graph::valueOfNumberConstant): Deleted. + (JSC::DFG::Graph::valueOfBooleanConstant): Deleted. + (JSC::DFG::Graph::valueOfFunctionConstant): Deleted. + (JSC::DFG::Graph::mulImmediateShouldSpeculateInt32): Deleted. + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertConstant): + (JSC::DFG::InsertionSet::insertConstantForUse): + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::rangeKeyAndAddend): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGLazyJSValue.cpp: + (JSC::DFG::LazyJSValue::getValue): + (JSC::DFG::LazyJSValue::strictEqual): + (JSC::DFG::LazyJSValue::dumpInContext): + * dfg/DFGLazyJSValue.h: + (JSC::DFG::LazyJSValue::LazyJSValue): + (JSC::DFG::LazyJSValue::tryGetValue): + (JSC::DFG::LazyJSValue::value): + (JSC::DFG::LazyJSValue::switchLookupValue): + * dfg/DFGMinifiedNode.cpp: + (JSC::DFG::MinifiedNode::fromNode): + * dfg/DFGMinifiedNode.h: + (JSC::DFG::belongsInMinifiedGraph): + (JSC::DFG::MinifiedNode::hasConstant): + (JSC::DFG::MinifiedNode::constant): + (JSC::DFG::MinifiedNode::hasConstantNumber): Deleted. + (JSC::DFG::MinifiedNode::constantNumber): Deleted. + (JSC::DFG::MinifiedNode::hasWeakConstant): Deleted. + (JSC::DFG::MinifiedNode::weakConstant): Deleted. + * dfg/DFGNode.h: + (JSC::DFG::Node::hasConstant): + (JSC::DFG::Node::constant): + (JSC::DFG::Node::convertToConstant): + (JSC::DFG::Node::asJSValue): + (JSC::DFG::Node::isInt32Constant): + (JSC::DFG::Node::asInt32): + (JSC::DFG::Node::asUInt32): + (JSC::DFG::Node::isDoubleConstant): + (JSC::DFG::Node::isNumberConstant): + (JSC::DFG::Node::asNumber): + (JSC::DFG::Node::isMachineIntConstant): + (JSC::DFG::Node::asMachineInt): + (JSC::DFG::Node::isBooleanConstant): + (JSC::DFG::Node::asBoolean): + (JSC::DFG::Node::isCellConstant): + (JSC::DFG::Node::asCell): + (JSC::DFG::Node::dynamicCastConstant): + (JSC::DFG::Node::function): + (JSC::DFG::Node::isWeakConstant): Deleted. + (JSC::DFG::Node::constantNumber): Deleted. + (JSC::DFG::Node::convertToWeakConstant): Deleted. + (JSC::DFG::Node::weakConstant): Deleted. + (JSC::DFG::Node::valueOfJSConstant): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + (JSC::DFG::SpeculativeJIT::silentSavePlanForFPR): + (JSC::DFG::SpeculativeJIT::silentFill): + (JSC::DFG::SpeculativeJIT::compileIn): + (JSC::DFG::SpeculativeJIT::compilePeepHoleBooleanBranch): + (JSC::DFG::SpeculativeJIT::compilePeepHoleInt32Branch): + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + (JSC::DFG::SpeculativeJIT::compileDoubleRep): + (JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileAdd): + (JSC::DFG::SpeculativeJIT::compileArithSub): + (JSC::DFG::SpeculativeJIT::compileArithMod): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::valueOfJSConstantAsImm64): + (JSC::DFG::SpeculativeJIT::initConstantInfo): + (JSC::DFG::SpeculativeJIT::isConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isJSConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isInt32Constant): Deleted. + (JSC::DFG::SpeculativeJIT::isDoubleConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isNumberConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isBooleanConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isFunctionConstant): Deleted. + (JSC::DFG::SpeculativeJIT::valueOfInt32Constant): Deleted. + (JSC::DFG::SpeculativeJIT::valueOfNumberConstant): Deleted. + (JSC::DFG::SpeculativeJIT::addressOfDoubleConstant): Deleted. + (JSC::DFG::SpeculativeJIT::valueOfJSConstant): Deleted. + (JSC::DFG::SpeculativeJIT::valueOfBooleanConstant): Deleted. + (JSC::DFG::SpeculativeJIT::valueOfFunctionConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isNullConstant): Deleted. + (JSC::DFG::SpeculativeJIT::isInteger): Deleted. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGValueStrength.cpp: Added. + (WTF::printInternal): + * dfg/DFGValueStrength.h: Added. + (JSC::DFG::merge): + * dfg/DFGVariableEventStream.cpp: + (JSC::DFG::VariableEventStream::tryToSetConstantRecovery): + (JSC::DFG::VariableEventStream::reconstruct): + * dfg/DFGVariableEventStream.h: + * dfg/DFGWatchableStructureWatchingPhase.cpp: + (JSC::DFG::WatchableStructureWatchingPhase::run): + (JSC::DFG::WatchableStructureWatchingPhase::tryWatch): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileDoubleConstant): + (JSC::FTL::LowerDFGToLLVM::compileInt52Constant): + (JSC::FTL::LowerDFGToLLVM::compileCheckStructure): + (JSC::FTL::LowerDFGToLLVM::compileCheckFunction): + (JSC::FTL::LowerDFGToLLVM::compileCompareEqConstant): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEqConstant): + (JSC::FTL::LowerDFGToLLVM::lowInt32): + (JSC::FTL::LowerDFGToLLVM::lowCell): + (JSC::FTL::LowerDFGToLLVM::lowBoolean): + (JSC::FTL::LowerDFGToLLVM::lowJSValue): + (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument): + (JSC::FTL::LowerDFGToLLVM::compileWeakJSConstant): Deleted. + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::dumpInContext): + (JSC::JSValue::dumpInContextAssumingStructure): + * runtime/JSCJSValue.h: + +2014-07-24 Brent Fulgham <bfulgham@apple.com> + + [Win] Correct build order in JavaScriptCore.submit.sln + https://bugs.webkit.org/show_bug.cgi?id=135282 + <rdar://problem/17805592> + + Unreviewed build fix. + + * JavaScriptCore.vcxproj/JavaScriptCore.submit.sln: Correct build order + such that LLIntDesiredOffset is built prior to the rest of JSC. + +2014-07-24 Mark Lam <mark.lam@apple.com> + + JSWrapperMap's jsWrapperForObject() needs to keep weak prototype and constructors from being GCed. + <https://webkit.org/b/135258> + + Reviewed by Mark Hahnenberg. + + Where needed, we cache the prototype object pointer in a stack local var. + This allows it to be scanned by the GC, and hence be kept alive until + we use it. The constructor object will in turn be kept alive by the + prototype object. + + Also added some comments to warn against future code additions that could + regress this issue. + + * API/JSWrapperMap.mm: + (-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): + (-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): + (-[JSObjCClassInfo wrapperForObject:]): + (-[JSObjCClassInfo constructor]): + +2014-07-24 Joseph Pecoraro <pecoraro@apple.com> + + JSLock release should only modify the AtomicStringTable if it modified in acquire + https://bugs.webkit.org/show_bug.cgi?id=135143 + + Reviewed by Darin Adler. + + * runtime/JSLock.cpp: + (JSC::JSLock::JSLock): + Initialize the member variable to nullptr. + + (JSC::JSLock::willDestroyVM): + Update style to use nullptr instead of 0. + + (JSC::JSLock::willReleaseLock): + We should only reset the thread data's atomic string table if + didAcquireLock changed it. m_entryAtomicStringTable will have + been set by didAcquireLock if it changed, or nullptr if it didn't. + This way we are sure we are balanced, regardless of m_vm changes. + +2014-07-24 Peyton Randolph <prandolph@apple.com> + + Rename feature flag for long-press gesture on Mac. + https://bugs.webkit.org/show_bug.cgi?id=135259 + + Reviewed by Beth Dakin. + + * Configurations/FeatureDefines.xcconfig: + Rename LINK_LONG_PRESS to MAC_LONG_PRESS. + +2014-07-24 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r171527. + https://bugs.webkit.org/show_bug.cgi?id=135265 + + Breaks JSC API tests (Requested by mlam on #webkit). + + Reverted changeset: + + "JSWrapperMap's jsWrapperForObject() needs to defer GC." + https://bugs.webkit.org/show_bug.cgi?id=135258 + http://trac.webkit.org/changeset/171527 + +2014-07-24 Mark Hahnenberg <mhahnenberg@apple.com> + + Creating a JSGlobalObject with a custom JSClassRef results in a JSProxy with the wrong prototype + https://bugs.webkit.org/show_bug.cgi?id=135250 + + Reviewed by Geoffrey Garen. + + JSGlobalObject::resetPrototype (which is called from JSGlobalContextCreateInGroup) doesn't change its + JSProxy's prototype as well. This results in a JSProxy where no properties in the original prototype + chain (as created from the JSClassRef hierarchy) are accessible. Changing resetPrototype to also change + the JSProxy's prototype fixes the issue. + + * API/JSValueRef.cpp: + (JSValueIsObjectOfClass): Also fixed a bug where a JSProxy for a JSGlobalObject with a custom JSClassRef + would claim it wasn't of the specified class, even if the target was of the specified class. + * API/tests/CustomGlobalObjectClassTest.c: Added. + (jsDoSomething): + (customGlobalObjectClassTest): + * API/tests/CustomGlobalObjectClassTest.h: Added. + * API/tests/testapi.c: + (assertTrue): + (main): + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::resetPrototype): + +2014-07-24 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: don't encode/decode primitive types that lack explicit sizes + https://bugs.webkit.org/show_bug.cgi?id=133430 + + Reviewed by Anders Carlsson. + + Don't support encode/decode of unsigned long, since its size is compiler-dependent. + + * replay/EncodedValue.cpp: + (JSC::EncodedValue::convertTo<unsigned long>): + (JSC::unsigned long>::encodeValue): Deleted. + * replay/EncodedValue.h: + +2014-07-24 Mark Lam <mark.lam@apple.com> + + JSWrapperMap's jsWrapperForObject() needs to defer GC. + <https://webkit.org/b/135258> + + Reviewed by Oliver Hunt. + + In the process of creating a JS wrapper, jsWrapperForObject() will create + the prototype and constructor of the corresponding ObjC class, as well as + for classes in its inheritance chain. These prototypes and constructors + are stored in Weak references in the JSObjCClassInfo objects. During all + the allocation that is being done to create all the prototypes and + constructors as well as the wrapper objects, a GC may occur thereby + collecting one or more of these newly created prototype and constructor + objects. + + One example of where this problem can manifest is in wrapperForObject() + which is called from jsWrapperForObject(). In wrapperFoObject(), we do + the following steps: + + 1. reallocateConstructorAndOrPrototype() which creates the prototype + object and store it in JSObjCClassInfo's m_prototype which is a Weak + ref. + 2. makeWrapper() to create the wrapper object, which may trigger a GC. + GC will collect the prototype object and nullify the corresponding + JSObjCClassInfo's m_prototype Weak ref. + 3. call JSObjectSetPrototype() to set the JSObjCClassInfo's m_prototype + in the newly created wrapper. This results in the wrapper getting a + jsNull as a prototype instead of the expected prototype object. + + To ensure that the prototype and constructor objects are retained until + they can be referenced properly from the wrapper object, + jsWrapperForObject() should defer GC until it's done with its work. + + * API/JSWrapperMap.mm: + (-[JSWrapperMap jsWrapperForObject:]): + +2014-07-23 Brent Fulgham <bfulgham@apple.com> + + Build fix after r171482. + + Rubberstamped by Joe Pecoraro. + + * runtime/Identifier.h: Make header declarations match + implementation file. + +2014-07-23 Brent Fulgham <bfulgham@apple.com> + + [Win] Use NO_RETURN_DUE_TO_CRASH on Windows + https://bugs.webkit.org/show_bug.cgi?id=135199 + + Reviewed by Mark Lam. + + * jsc.cpp: + (WTF::RuntimeArray::deleteProperty): Stop using ugly + compiler work-around on Windows; use NO_RETURN_DUE_TO_CRASH + codepath instead. + * runtime/Identifier.h: Add NO_RETURN_DUE_TO_CRASH + to header so function declaration matches implementation. + +2014-07-23 Bem Jones-Bey <bjonesbe@adobe.com> + + Remove CSS_EXCLUSIONS compile flag and leftover code + https://bugs.webkit.org/show_bug.cgi?id=135175 + + Reviewed by Zoltan Horvath. + + At this point, the CSS_EXCLUSIONS flag guards nothing but some useless + stubs. This removes the flag and the useless code. + + * Configurations/FeatureDefines.xcconfig: + +2014-07-23 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r171367. + https://bugs.webkit.org/show_bug.cgi?id=135192 + + broke three API tests (Requested by thorton on #webkit). + + Reverted changeset: + + "JSLock release should only modify the AtomicStringTable if it + modified in acquire" + https://bugs.webkit.org/show_bug.cgi?id=135143 + http://trac.webkit.org/changeset/171367 + +2014-07-22 László Langó <llango.u-szeged@partner.samsung.com> + + [EFL] Build fix after the [ftlopt] branch merge. + + Reviewed by Csaba Osztrogonác. + + * dfg/DFGBranchDirection.h: + (JSC::DFG::branchDirectionToString): + * dfg/DFGStructureClobberState.h: + (JSC::DFG::merge): + +2014-07-22 Brent Fulgham <bfulgham@apple.com> + + Build fix for non-clang compile. + + * jsc.cpp: + (WTF::RuntimeArray::put): Remove incorrect return statement + I added. + +2014-07-22 Brent Fulgham <bfulgham@apple.com> + + Build fix for non-clang compile. + + * jsc.cpp: + (WTF::RuntimeArray::deleteProperty): Need (fake) return + value when NO_RETURN_DUE_TO_CRASH is not defined. + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + Merge r169628 from ftlopt. + + 2014-06-04 Matthew Mirman <mmirman@apple.com> + + Added system for inlining native functions via the FTL. + https://bugs.webkit.org/show_bug.cgi?id=131515 + + Reviewed by Filip Pizlo. + + Also fixed the build to not compress the bitcode and to + include all of the relevant runtime. With GCC_GENERATE_DEBUGGING_SYMBOLS = NO, + the produced bitcode files are a 100th the size they were before. + Now we can include all of the relevant runtime files with only a 3mb overhead. + This is the same overhead as for two compressed files before, + but done more efficiently (on both ends) and with less code. + + Deciding whether to inline native functions is left up to LLVM. + The entire module containing the function is linked into the current + compiled JS so that inlining the native functions shouldn't make them smaller. + + Rather than loading Runtime.symtbl at runtime FTLState.cpp now generates a file + InlineRuntimeSymbolTable.h which statically builds the symbol table hash table. + + * JavaScriptCore.xcodeproj/project.pbxproj: Added back runtime files to compile. + * build-symbol-table-index.py: Changed bitcode suffix. + Added inclusion of only tested symbols. + Added output to InlineRuntimeSymbolTable.h. + * build-symbol-table-index.sh: Changed bitcode suffix. + * copy-llvm-ir-to-derived-sources.sh: Removed gzip compression. + * tested-symbols.symlst: Added. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + Now sets the knownFunction of the call node if such a function exists + and emits a check that during runtime the callee is in fact known. + * dfg/DFGNode.h: + Added functions to set the known function of a call node. + (JSC::DFG::Node::canBeKnownFunction): Added. + (JSC::DFG::Node::hasKnownFunction): Added. + (JSC::DFG::Node::knownFunction): Added. + (JSC::DFG::Node::giveKnownFunction): Added. + * ftl/FTLAbbreviatedTypes.h: Added a typedef for LLVMMemoryBufferRef + * ftl/FTLAbbreviations.h: Added some abbreviations. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Added. Hardcoded threshold to 275. + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Added. + (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Added. + (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Added. + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): + Added call to possiblyCompileInlineableNativeCall + * ftl/FTLOutput.h: + (JSC::FTL::Output::allocaName): Added. Useful for debugging. + * ftl/FTLState.cpp: + (JSC::FTL::State::State): Added an include for InlineRuntimeSymbolTable.h + * ftl/FTLState.h: Added symbol table hash table. + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): Added inlining and dead function elimination passes. + * heap/HandleStack.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile. + * llvm/InitializeLLVMMac.mm: Deleted. + * llvm/InitializeLLVMMac.cpp: Added. + * llvm/LLVMAPIFunctions.h: Added macros to include Bitcode parsing and linking functions. + * llvm/LLVMHeaders.h: Added includes for Bitcode parsing and linking. + * runtime/BundlePath.h: Added. + * runtime/BundlePath.mm: Added. + * runtime/DateInstance.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile. + * runtime/DateInstance.h: ditto. + * runtime/DateConversion.h: ditto. + * runtime/ExceptionHelpers.h: ditto. + * runtime/JSCJSValue.h: ditto. + * runtime/JSArray.h: ditto. + * runtime/JSDateMath.h: ditto. + * runtime/JSObject.h: ditto. + * runtime/JSObject.h: ditto. + * runtime/RegExp.h: ditto. + * runtime/Structure.h: ditto. + * runtime/Options.h: Added maximumLLVMInstructionCountForNativeInlining. + +2014-07-22 Mark Lam <mark.lam@apple.com> + + Array.concat() should work on runtime arrays too. + <https://webkit.org/b/135179> + + Reviewed by Geoffrey Garen. + + * jsc.cpp: + (WTF::RuntimeArray::create): + (WTF::RuntimeArray::~RuntimeArray): + (WTF::RuntimeArray::destroy): + (WTF::RuntimeArray::getOwnPropertySlot): + (WTF::RuntimeArray::getOwnPropertySlotByIndex): + (WTF::RuntimeArray::put): + (WTF::RuntimeArray::deleteProperty): + (WTF::RuntimeArray::getLength): + (WTF::RuntimeArray::createPrototype): + (WTF::RuntimeArray::createStructure): + (WTF::RuntimeArray::finishCreation): + (WTF::RuntimeArray::RuntimeArray): + (WTF::RuntimeArray::lengthGetter): + (GlobalObject::finishCreation): + (functionCreateRuntimeArray): + - Added support to create a runtime array for testing purpose. + * runtime/ArrayPrototype.cpp: + (JSC::getLength): + - Added fast case for when the array object is a JSArray. + (JSC::arrayProtoFuncJoin): + - Added a needed but missing exception check. + (JSC::arrayProtoFuncConcat): + - Use getLength() to compute the array length instead of assuming that + the array is a JSArray instance. + * tests/stress/regexp-matches-array.js: Added. + (testArrayConcat): + * tests/stress/runtime-array.js: Added. + (testArrayConcat): + +2014-07-22 Brent Fulgham <bfulgham@apple.com> + + Fix Windows (return a value!) + + * jsc.cpp: + (functionQuit): Satisfy compiler's need for + a return value. + +2014-07-22 Brent Fulgham <bfulgham@apple.com> + + Fix Windows (sleep -> Sleep) + + * jsc.cpp: + (WTF::jscExit): + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + Fix Windows. + + * jsc.cpp: + (WTF::jscExit): + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + Fix 32-bit. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + Merge r169148, r169185, r169188, r169578, r169582, r169584, r169588, r169753 from ftlopt. + + Note that r169753 is merged out of order because it fixes a bug in r169588. + + 2014-06-10 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Structure::dfgShouldWatchIfPossible() is unsound + https://bugs.webkit.org/show_bug.cgi?id=133624 + + Reviewed by Mark Hahnenberg. + + * runtime/Structure.h: + (JSC::Structure::dfgShouldWatchIfPossible): Make it sound and add some verbiage. + + 2014-06-04 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] AI should be able track structure sets larger than 1 + https://bugs.webkit.org/show_bug.cgi?id=128073 + + Reviewed by Oliver Hunt. + + This makes two major changes to how AI (abstract interpreter) proves that a value has + some structure: + + - StructureAbstractValue can now track an arbitrary number of structures. A set whose + size is greater than one means that the value may have any of the structures, and we + don't know which - but we do know that it cannot be any structure not in the set. The + structure abstract value can still be TOP, which means the set of all structures. We + artificially limit the set size to StructureAbstractValue::polymorphismLimit to guard + memory explosion on pathological programs. This limit is big enough that it wouldn't + kick in for normal code, since we have other heuristics that limit the number of + structures that we would allow an inline cache to know about. + + - We eagerly set watchpoints on all watchable structures and then we assume that + watchable structures are being watched, and that the watchpoint will jettison the code. + This allows tracking of watchable structures to be far simpler than before. Previously, + a structure being tracked as "future possible" was predicated on it being watchable but + we might not actually watch it. This makes algebra over sets of future possible + structures quite weird. But watching all watchable structures means that we simple say + that a structure set can be in the following states: unclobbered, which means it's just + a set of structures and it doesn't matter what is watchable or what isn't because we've + proven that the value must have one of these structures right now; and clobbered, which + means that we have a set of structures, plus all possible structures temporarily, with + invalidation removing the "plus all possible structures". Clobbering a set means that + if any of its structures are unwatchable, the set just becomes TOP; but if all + structures in the set are watchable then we just set the clobbered bit to add the "plus + all possible structures temporarily" thing. This precisely tracks the exact meaning of + watchability and invalidation points. + + Slight SunSpider slow-down, neutral on Octane, slight AsmBench speed-up. I believe that + we will ultimately undo the SunSpider slow-down by making further improvements to the set + representation. I believe that Octane perfromance will ultimately improve once we remove + remaining singleton special-cases. The ultimate goal of this is to remove the need to + try quite so desperately hard to make everything monomorphic as we do currently. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/StructureSet.cpp: + (JSC::StructureSet::clear): + (JSC::StructureSet::remove): + (JSC::StructureSet::filter): + (JSC::StructureSet::copyFromOutOfLine): + (JSC::StructureSet::StructureSet): Deleted. + (JSC::StructureSet::operator=): Deleted. + (JSC::StructureSet::copyFrom): Deleted. + * bytecode/StructureSet.h: + (JSC::StructureSet::StructureSet): + (JSC::StructureSet::operator=): + (JSC::StructureSet::isEmpty): + (JSC::StructureSet::genericFilter): + (JSC::StructureSet::ContainsOutOfLine::ContainsOutOfLine): + (JSC::StructureSet::ContainsOutOfLine::operator()): + (JSC::StructureSet::copyFrom): + (JSC::StructureSet::deleteStructureListIfNecessary): + (JSC::StructureSet::setEmpty): + (JSC::StructureSet::getReservedFlag): + (JSC::StructureSet::setReservedFlag): + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::setBuiltInConstant): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::booleanResult): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::verifyEdge): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberCapturedVars): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberStructures): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransition): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::setDidClobber): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::dump): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::observeTransitions): + (JSC::DFG::AbstractValue::setMostSpecific): + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::filter): + (JSC::DFG::AbstractValue::shouldBeClear): + (JSC::DFG::AbstractValue::normalizeClarity): + (JSC::DFG::AbstractValue::checkConsistency): + (JSC::DFG::AbstractValue::assertIsWatched): + (JSC::DFG::AbstractValue::dumpInContext): + (JSC::DFG::AbstractValue::setFuturePossibleStructure): Deleted. + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::clear): + (JSC::DFG::AbstractValue::clobberStructures): + (JSC::DFG::AbstractValue::clobberStructuresFor): + (JSC::DFG::AbstractValue::observeInvalidationPoint): + (JSC::DFG::AbstractValue::observeInvalidationPointFor): + (JSC::DFG::AbstractValue::observeTransition): + (JSC::DFG::AbstractValue::TransitionObserver::TransitionObserver): + (JSC::DFG::AbstractValue::TransitionObserver::operator()): + (JSC::DFG::AbstractValue::TransitionsObserver::TransitionsObserver): + (JSC::DFG::AbstractValue::TransitionsObserver::operator()): + (JSC::DFG::AbstractValue::isHeapTop): + (JSC::DFG::AbstractValue::setType): + (JSC::DFG::AbstractValue::operator==): + (JSC::DFG::AbstractValue::merge): + (JSC::DFG::AbstractValue::validate): + (JSC::DFG::AbstractValue::hasClobberableState): + (JSC::DFG::AbstractValue::assertIsWatched): + (JSC::DFG::AbstractValue::observeIndexingTypeTransition): + (JSC::DFG::AbstractValue::makeTop): + (JSC::DFG::AbstractValue::bestProvenStructure): Deleted. + * dfg/DFGAllocator.h: + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::alreadyChecked): + * dfg/DFGAtTailAbstractState.h: + (JSC::DFG::AtTailAbstractState::structureClobberState): + (JSC::DFG::AtTailAbstractState::setStructureClobberState): + (JSC::DFG::AtTailAbstractState::setFoundConstants): + (JSC::DFG::AtTailAbstractState::haveStructures): Deleted. + (JSC::DFG::AtTailAbstractState::setHaveStructures): Deleted. + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::BasicBlock): + * dfg/DFGBasicBlock.h: + * dfg/DFGBranchDirection.h: + (JSC::DFG::branchDirectionToString): + (WTF::printInternal): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handlePutById): + * dfg/DFGCFAPhase.cpp: + (JSC::DFG::CFAPhase::performBlockCFA): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::checkStructureElimination): + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.cpp: + (JSC::DFG::startCrashing): + (JSC::DFG::isCrashing): + * dfg/DFGCommon.h: + * dfg/DFGCommonData.cpp: + (JSC::DFG::CommonData::notifyCompilingStructureTransition): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck): + * dfg/DFGDesiredWatchpoints.cpp: + (JSC::DFG::DesiredWatchpoints::consider): + (JSC::DFG::DesiredWatchpoints::addLazily): Deleted. + * dfg/DFGDesiredWatchpoints.h: + (JSC::DFG::GenericDesiredWatchpoints::reallyAdd): + (JSC::DFG::GenericDesiredWatchpoints::areStillValid): + (JSC::DFG::GenericDesiredWatchpoints::isWatched): + (JSC::DFG::DesiredWatchpoints::isWatched): + (JSC::DFG::WatchpointForGenericWatchpointSet::WatchpointForGenericWatchpointSet): Deleted. + (JSC::DFG::GenericDesiredWatchpoints::addLazily): Deleted. + (JSC::DFG::GenericDesiredWatchpoints::isStillValid): Deleted. + (JSC::DFG::GenericDesiredWatchpoints::shouldAssumeMixedState): Deleted. + (JSC::DFG::GenericDesiredWatchpoints::isValidOrMixed): Deleted. + (JSC::DFG::DesiredWatchpoints::isStillValid): Deleted. + (JSC::DFG::DesiredWatchpoints::shouldAssumeMixedState): Deleted. + (JSC::DFG::DesiredWatchpoints::isValidOrMixed): Deleted. + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::~Graph): + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::dumpBlockHeader): + (JSC::DFG::Graph::tryGetFoldableView): + (JSC::DFG::Graph::visitChildren): + (JSC::DFG::Graph::assertIsWatched): + (JSC::DFG::Graph::handleAssertionFailure): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::convertToConstant): + (JSC::DFG::Graph::masqueradesAsUndefinedWatchpointIsStillValid): + (JSC::DFG::Graph::addStructureTransitionData): Deleted. + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::beginBasicBlock): + (JSC::DFG::InPlaceAbstractState::initialize): + (JSC::DFG::InPlaceAbstractState::endBasicBlock): + (JSC::DFG::InPlaceAbstractState::reset): + (JSC::DFG::InPlaceAbstractState::merge): + * dfg/DFGInPlaceAbstractState.h: + (JSC::DFG::InPlaceAbstractState::structureClobberState): + (JSC::DFG::InPlaceAbstractState::setStructureClobberState): + (JSC::DFG::InPlaceAbstractState::setFoundConstants): + (JSC::DFG::InPlaceAbstractState::haveStructures): Deleted. + (JSC::DFG::InPlaceAbstractState::setHaveStructures): Deleted. + * dfg/DFGLivenessAnalysisPhase.cpp: + (JSC::DFG::LivenessAnalysisPhase::run): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasTransition): + (JSC::DFG::Node::transition): + (JSC::DFG::Node::hasStructure): + (JSC::DFG::StructureTransitionData::StructureTransitionData): Deleted. + (JSC::DFG::Node::convertToStructureTransitionWatchpoint): Deleted. + (JSC::DFG::Node::hasStructureTransitionData): Deleted. + (JSC::DFG::Node::structureTransitionData): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage): + (JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureAbstractValue.cpp: Added. + (JSC::DFG::StructureAbstractValue::assertIsWatched): + (JSC::DFG::StructureAbstractValue::clobber): + (JSC::DFG::StructureAbstractValue::observeTransition): + (JSC::DFG::StructureAbstractValue::observeTransitions): + (JSC::DFG::StructureAbstractValue::add): + (JSC::DFG::StructureAbstractValue::merge): + (JSC::DFG::StructureAbstractValue::mergeSlow): + (JSC::DFG::StructureAbstractValue::mergeNotTop): + (JSC::DFG::StructureAbstractValue::filter): + (JSC::DFG::StructureAbstractValue::filterSlow): + (JSC::DFG::StructureAbstractValue::contains): + (JSC::DFG::StructureAbstractValue::isSubsetOf): + (JSC::DFG::StructureAbstractValue::isSupersetOf): + (JSC::DFG::StructureAbstractValue::overlaps): + (JSC::DFG::StructureAbstractValue::equalsSlow): + (JSC::DFG::StructureAbstractValue::dumpInContext): + (JSC::DFG::StructureAbstractValue::dump): + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::StructureAbstractValue): + (JSC::DFG::StructureAbstractValue::operator=): + (JSC::DFG::StructureAbstractValue::clear): + (JSC::DFG::StructureAbstractValue::makeTop): + (JSC::DFG::StructureAbstractValue::assertIsWatched): + (JSC::DFG::StructureAbstractValue::observeInvalidationPoint): + (JSC::DFG::StructureAbstractValue::top): + (JSC::DFG::StructureAbstractValue::isClear): + (JSC::DFG::StructureAbstractValue::isTop): + (JSC::DFG::StructureAbstractValue::isNeitherClearNorTop): + (JSC::DFG::StructureAbstractValue::isClobbered): + (JSC::DFG::StructureAbstractValue::merge): + (JSC::DFG::StructureAbstractValue::filter): + (JSC::DFG::StructureAbstractValue::operator==): + (JSC::DFG::StructureAbstractValue::size): + (JSC::DFG::StructureAbstractValue::at): + (JSC::DFG::StructureAbstractValue::operator[]): + (JSC::DFG::StructureAbstractValue::onlyStructure): + (JSC::DFG::StructureAbstractValue::isSupersetOf): + (JSC::DFG::StructureAbstractValue::makeTopWhenThin): + (JSC::DFG::StructureAbstractValue::setClobbered): + (JSC::DFG::StructureAbstractValue::add): Deleted. + (JSC::DFG::StructureAbstractValue::addAll): Deleted. + (JSC::DFG::StructureAbstractValue::contains): Deleted. + (JSC::DFG::StructureAbstractValue::isSubsetOf): Deleted. + (JSC::DFG::StructureAbstractValue::doesNotContainAnyOtherThan): Deleted. + (JSC::DFG::StructureAbstractValue::isClearOrTop): Deleted. + (JSC::DFG::StructureAbstractValue::last): Deleted. + (JSC::DFG::StructureAbstractValue::speculationFromStructures): Deleted. + (JSC::DFG::StructureAbstractValue::isValidOffset): Deleted. + (JSC::DFG::StructureAbstractValue::hasSingleton): Deleted. + (JSC::DFG::StructureAbstractValue::singleton): Deleted. + (JSC::DFG::StructureAbstractValue::dumpInContext): Deleted. + (JSC::DFG::StructureAbstractValue::dump): Deleted. + (JSC::DFG::StructureAbstractValue::topValue): Deleted. + * dfg/DFGStructureClobberState.h: Added. + (JSC::DFG::merge): + (WTF::printInternal): + * dfg/DFGTransition.cpp: Added. + (JSC::DFG::Transition::dumpInContext): + (JSC::DFG::Transition::dump): + * dfg/DFGTransition.h: Added. + (JSC::DFG::Transition::Transition): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): + * dfg/DFGWatchableStructureWatchingPhase.cpp: Added. + (JSC::DFG::WatchableStructureWatchingPhase::WatchableStructureWatchingPhase): + (JSC::DFG::WatchableStructureWatchingPhase::run): + (JSC::DFG::WatchableStructureWatchingPhase::tryWatch): + (JSC::DFG::performWatchableStructureWatching): + * dfg/DFGWatchableStructureWatchingPhase.h: Added. + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + (JSC::DFG::WatchpointCollectionPhase::handleEdge): Deleted. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::ftlUnreachable): + (JSC::FTL::LowerDFGToLLVM::createPhiVariables): + (JSC::FTL::LowerDFGToLLVM::compileBlock): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileUpsilon): + (JSC::FTL::LowerDFGToLLVM::compilePhi): + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::compileValueRep): + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::compileGetArgument): + (JSC::FTL::LowerDFGToLLVM::compileGetLocal): + (JSC::FTL::LowerDFGToLLVM::compileSetLocal): + (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): + (JSC::FTL::LowerDFGToLLVM::compileArithMul): + (JSC::FTL::LowerDFGToLLVM::compileArithDiv): + (JSC::FTL::LowerDFGToLLVM::compileArithMod): + (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): + (JSC::FTL::LowerDFGToLLVM::compileArithAbs): + (JSC::FTL::LowerDFGToLLVM::compileArithNegate): + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + (JSC::FTL::LowerDFGToLLVM::compilePutStructure): + (JSC::FTL::LowerDFGToLLVM::compileGetById): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileArrayPush): + (JSC::FTL::LowerDFGToLLVM::compileArrayPop): + (JSC::FTL::LowerDFGToLLVM::compileNewArray): + (JSC::FTL::LowerDFGToLLVM::compileNewArrayBuffer): + (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compileToString): + (JSC::FTL::LowerDFGToLLVM::compileMakeRope): + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::compare): + (JSC::FTL::LowerDFGToLLVM::boolify): + (JSC::FTL::LowerDFGToLLVM::terminate): + (JSC::FTL::LowerDFGToLLVM::lowInt32): + (JSC::FTL::LowerDFGToLLVM::lowInt52): + (JSC::FTL::LowerDFGToLLVM::opposite): + (JSC::FTL::LowerDFGToLLVM::lowCell): + (JSC::FTL::LowerDFGToLLVM::lowBoolean): + (JSC::FTL::LowerDFGToLLVM::lowDouble): + (JSC::FTL::LowerDFGToLLVM::lowJSValue): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::isArrayType): + (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID): + (JSC::FTL::LowerDFGToLLVM::callCheck): + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode): + (JSC::FTL::LowerDFGToLLVM::setInt52): + (JSC::FTL::LowerDFGToLLVM::crash): + (JSC::FTL::LowerDFGToLLVM::compileStructureTransitionWatchpoint): Deleted. + * ftl/FTLOutput.cpp: + (JSC::FTL::Output::crashNonTerminal): Deleted. + * ftl/FTLOutput.h: + (JSC::FTL::Output::crash): Deleted. + * jit/JITOperations.h: + * jsc.cpp: + (WTF::jscExit): + (functionQuit): + (main): + (printUsageStatement): + (CommandLine::parseArguments): + * runtime/Structure.h: + (JSC::Structure::dfgShouldWatchIfPossible): + (JSC::Structure::dfgShouldWatch): + * tests/stress/arrayify-to-structure-contradiction.js: Added. + (foo): + * tests/stress/ftl-getmyargumentslength-inline.js: Added. + (foo): + * tests/stress/multi-put-by-offset-multiple-transitions.js: Added. + (foo): + (Foo): + * tests/stress/throw-from-ftl-in-loop.js: Added. + * tests/stress/throw-from-ftl.js: Added. + (foo): + + 2014-06-03 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Unreviewed, roll out r169578. The build system needs some more love. + + * InlineRuntimeSymbolTable.h: Removed. + * JavaScriptCore.xcodeproj/project.pbxproj: + * build-symbol-table-index.py: + * build-symbol-table-index.sh: + * copy-llvm-ir-to-derived-sources.sh: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + * dfg/DFGNode.h: + (JSC::DFG::Node::canBeKnownFunction): Deleted. + (JSC::DFG::Node::hasKnownFunction): Deleted. + (JSC::DFG::Node::knownFunction): Deleted. + (JSC::DFG::Node::giveKnownFunction): Deleted. + * ftl/FTLAbbreviatedTypes.h: + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM): + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Deleted. + (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Deleted. + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Deleted. + (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Deleted. + * ftl/FTLState.cpp: + (JSC::FTL::State::State): + * ftl/FTLState.h: + * heap/HandleStack.h: + * llvm/InitializeLLVM.h: + * llvm/InitializeLLVMMac.cpp: Removed. + * llvm/InitializeLLVMMac.mm: Added. + (JSC::initializeLLVMImpl): + * llvm/LLVMAPIFunctions.h: + * llvm/LLVMHeaders.h: + * runtime/BundlePath.h: Removed. + * runtime/BundlePath.mm: Removed. + * runtime/DateConversion.h: + * runtime/DateInstance.h: + * runtime/ExceptionHelpers.h: + * runtime/JSArray.h: + * runtime/JSCJSValue.h: + (JSC::JSValue::toFloat): + * runtime/JSDateMath.h: + * runtime/JSObject.h: + * runtime/JSWrapperObject.h: + * runtime/Options.h: + * runtime/RegExp.h: + * runtime/StringObject.h: + * runtime/Structure.h: + * tested-symbols.symlst: Removed. + + 2014-06-03 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] FTL native inlining tests take far too long + https://bugs.webkit.org/show_bug.cgi?id=133498 + + Unreviewed test gardening. + + Added a new exceptions test since the other one appears to not work. + + * tests/stress/ftl-library-exception.js: + * tests/stress/ftl-library-inline-gettimezoneoffset.js: Added. + (foo): + * tests/stress/ftl-library-inlining-exceptions-dataview.js: Added. + (foo): + * tests/stress/ftl-library-inlining-exceptions.js: Copied from LayoutTests/js/regress/script-tests/ftl-library-inlining-exceptions.js. + * tests/stress/ftl-library-inlining-loops.js: Copied from LayoutTests/js/regress/script-tests/ftl-library-inlining-loops.js. + * tests/stress/ftl-library-inlining-random.js: + * tests/stress/ftl-library-substring.js: + + 2014-06-03 Matthew Mirman <mmirman@apple.com> + + [ftlopt] Added system for inlining native functions via the FTL. + https://bugs.webkit.org/show_bug.cgi?id=131515 + + Reviewed by Filip Pizlo. + + Also fixed the build to not compress the bitcode and to + include all of the relevant runtime. With GCC_GENERATE_DEBUGGING_SYMBOLS = NO, + the produced bitcode files are a 100th the size they were before. + Now we can include all of the relevant runtime files with only a 3mb overhead. + This is the same overhead as for two compressed files before, + but done more efficiently (on both ends) and with less code. + + Deciding whether to inline native functions is left up to LLVM. + The entire module containing the function is linked into the current + compiled JS so that inlining the native functions shouldn't make them smaller. + + Rather than loading Runtime.symtbl at runtime FTLState.cpp now includes a file + InlineRuntimeSymbolTable.h which statically builds the symbol table hash table. + Currently build-symbol-table-index.py updates this file from the + contents of tested-symbols.symlst when done building as a matter of convenience. + However, in order to include the new contents of the file in the build + you'd need to build twice. This will be fixed in future versions. + + * JavaScriptCore.xcodeproj/project.pbxproj: Added back runtime files to compile. + * build-symbol-table-index.py: Changed bitcode suffix. + Added inclusion of only tested symbols. + Added output to InlineRuntimeSymbolTable.h. + * build-symbol-table-index.sh: Changed bitcode suffix. + * copy-llvm-ir-to-derived-sources.sh: Removed gzip compression. + * tested-symbols.symlst: Added. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + Now sets the knownFunction of the call node if such a function exists + and emits a check that during runtime the callee is in fact known. + * dfg/DFGNode.h: + Added functions to set the known function of a call node. + (JSC::DFG::Node::canBeKnownFunction): Added. + (JSC::DFG::Node::hasKnownFunction): Added. + (JSC::DFG::Node::knownFunction): Added. + (JSC::DFG::Node::giveKnownFunction): Added. + * ftl/FTLAbbreviatedTypes.h: Added a typedef for LLVMMemoryBufferRef + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::isInlinableSize): Added. Hardcoded threshold to 275. + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): Added. + (JSC::FTL::LowerDFGToLLVM::getFunctionBySymbol): Added. + (JSC::FTL::LowerDFGToLLVM::possiblyCompileInlineableNativeCall): Added. + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): + Added call to possiblyCompileInlineableNativeCall + * ftl/FTLOutput.h: + (JSC::FTL::Output::allocaName): Added. Useful for debugging. + * ftl/FTLState.cpp: + (JSC::FTL::State::State): Added an include for InlineRuntimeSymbolTable.h + * ftl/FTLState.h: Added symbol table hash table. + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): Added inlining and dead function elimination passes. + * heap/HandleStack.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile. + * InlineRuntimeSymbolTable.h: Added. + * llvm/InitializeLLVMMac.mm: Deleted. + * llvm/InitializeLLVMMac.cpp: Added. + * llvm/LLVMAPIFunctions.h: Added macros to include Bitcode parsing and linking functions. + * llvm/LLVMHeaders.h: Added includes for Bitcode parsing and linking. + * runtime/BundlePath.h: Added. + * runtime/BundlePath.mm: Added. + * runtime/DateInstance.h: Added JS_EXPORT_PRIVATE to a few functions to get inlining to compile. + * runtime/DateInstance.h: ditto. + * runtime/DateConversion.h: ditto. + * runtime/ExceptionHelpers.h: ditto. + * runtime/JSCJSValue.h: ditto. + * runtime/JSArray.h: ditto. + * runtime/JSDateMath.h: ditto. + * runtime/JSObject.h: ditto. + * runtime/JSObject.h: ditto. + * runtime/RegExp.h: ditto. + * runtime/Structure.h: ditto. + * runtime/Options.h: Added maximumLLVMInstructionCountForNativeInlining. + * tests/stress/ftl-library-inlining-random.js: Added. + * tests/stress/ftl-library-substring.js: Added. + + 2014-05-21 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG::clobberize should be blind to the effects of GC + https://bugs.webkit.org/show_bug.cgi?id=133166 + + Reviewed by Goeffrey Garen. + + Move the computation of where GCs happen to DFG::doesGC(). + + Large (>5x) speed-up on programs that do loop-invariant string concatenations. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractHeap.h: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + (JSC::DFG::clobberizeForAllocation): Deleted. + * dfg/DFGDoesGC.cpp: Added. + (JSC::DFG::doesGC): + * dfg/DFGDoesGC.h: Added. + * dfg/DFGStoreBarrierElisionPhase.cpp: + (JSC::DFG::StoreBarrierElisionPhase::handleNode): + (JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): Deleted. + + 2014-05-16 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] A StructureSet with one element should only require one word and no allocation + https://bugs.webkit.org/show_bug.cgi?id=133014 + + Reviewed by Oliver Hunt. + + This makes it more efficient to use StructureSet in situations where the common case is + just one structure. + + I also took the opportunity to use the same set terminology we use in BitVector: merge, + filter, exclude, contains, etc. + + Eventually, this will be used to implement StructureAbstractValue as well. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/StructureSet.cpp: Added. + (JSC::StructureSet::StructureSet): + (JSC::StructureSet::operator=): + (JSC::StructureSet::clear): + (JSC::StructureSet::add): + (JSC::StructureSet::remove): + (JSC::StructureSet::contains): + (JSC::StructureSet::merge): + (JSC::StructureSet::filter): + (JSC::StructureSet::exclude): + (JSC::StructureSet::isSubsetOf): + (JSC::StructureSet::overlaps): + (JSC::StructureSet::operator==): + (JSC::StructureSet::speculationFromStructures): + (JSC::StructureSet::arrayModesFromStructures): + (JSC::StructureSet::dumpInContext): + (JSC::StructureSet::dump): + (JSC::StructureSet::addOutOfLine): + (JSC::StructureSet::containsOutOfLine): + (JSC::StructureSet::copyFrom): + (JSC::StructureSet::OutOfLineList::create): + (JSC::StructureSet::OutOfLineList::destroy): + * bytecode/StructureSet.h: + (JSC::StructureSet::StructureSet): + (JSC::StructureSet::~StructureSet): + (JSC::StructureSet::onlyStructure): + (JSC::StructureSet::isEmpty): + (JSC::StructureSet::size): + (JSC::StructureSet::at): + (JSC::StructureSet::operator[]): + (JSC::StructureSet::last): + (JSC::StructureSet::OutOfLineList::list): + (JSC::StructureSet::OutOfLineList::OutOfLineList): + (JSC::StructureSet::deleteStructureListIfNecessary): + (JSC::StructureSet::isThin): + (JSC::StructureSet::pointer): + (JSC::StructureSet::singleStructure): + (JSC::StructureSet::structureList): + (JSC::StructureSet::set): + (JSC::StructureSet::clear): Deleted. + (JSC::StructureSet::add): Deleted. + (JSC::StructureSet::addAll): Deleted. + (JSC::StructureSet::remove): Deleted. + (JSC::StructureSet::contains): Deleted. + (JSC::StructureSet::containsOnly): Deleted. + (JSC::StructureSet::isSubsetOf): Deleted. + (JSC::StructureSet::overlaps): Deleted. + (JSC::StructureSet::singletonStructure): Deleted. + (JSC::StructureSet::speculationFromStructures): Deleted. + (JSC::StructureSet::arrayModesFromStructures): Deleted. + (JSC::StructureSet::operator==): Deleted. + (JSC::StructureSet::dumpInContext): Deleted. + (JSC::StructureSet::dump): Deleted. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPrototypeChecks): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToStructureTransitionWatchpoint): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::noticeStructureCheck): + +2014-07-22 Ryuan Choi <ryuan.choi@samsung.com> + + Unreviewed build fix attempt on the EFL port after r171362. + + Build break because of -Werror=return-type + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::makesCalls): + +2014-07-22 Joseph Pecoraro <pecoraro@apple.com> + + JSLock release should only modify the AtomicStringTable if it modified in acquire + https://bugs.webkit.org/show_bug.cgi?id=135143 + + Reviewed by Pratik Solanki. + + * runtime/JSLock.cpp: + (JSC::JSLock::willDestroyVM): + (JSC::JSLock::willReleaseLock): + Only set the AtomicStringTable when there was a VM, to balance JSLock::didAcquireLock. + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + Fix cloop build. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeExitSiteData): + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + Merge r168635, r168780, r169005, r169014, and r169143 from ftlopt. + + 2014-05-20 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to + https://bugs.webkit.org/show_bug.cgi?id=133105 + + Reviewed by Michael Saboff. + + - GetByIdStatus now knows about getters and can report intelligent things about them. + As is usually the case with how we do these things, GetByIdStatus knows more about + getters than the DFG can actually handle: it'll report details about polymorphic + getter calls even though the DFG won't be able to handle those. This is fine; the DFG + will see those statuses and bail to a generic slow path. + + - The DFG::ByteCodeParser now knows how to set up and do handleCall() for a getter call. + This can, and usually does, result in inlining of getters! + + - CodeOrigin and OSR exit know about inlined getter calls. When you OSR out of an + inlined getter, we set the return PC to a getter return thunk that fixes up the stack. + We use the usual offset-true-return-PC trick, where OSR exit places the true return PC + of the getter's caller as a phony argument that only the thunk knows how to find. + + - Removed a bunch of dead monomorphic chain support from StructureStubInfo. + + - A large chunk of this change is dragging GetGetterSetterByOffset, GetGetter, and + GetSetter through the DFG and FTL. GetGetterSetterByOffset is like GetByOffset except + that we know that we're returning a GetterSetter cell. GetGetter and GetSetter extract + the getter, or setter, from the GetterSetter. + + This is a ~2.5x speed-up on the getter microbenchmarks that we already had. So far none + of the "real" benchmarks exercise getters enough for this to matter. But I noticed that + some of the variants of the Richards benchmark in other languages - for example + Wolczko's Java translation of a C++ translation of Deutsch's Smalltalk version - use + getters and setters extensively. So, I created a getter/setter JavaScript version of + Richards and put it in regress/script-tests/getter-richards.js. That sees about a 2.4x + speed-up from this patch, which is very reassuring. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printGetByIdCacheStatus): + (JSC::CodeBlock::findStubInfo): + * bytecode/CodeBlock.h: + * bytecode/CodeOrigin.cpp: + (WTF::printInternal): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::specializationKindFor): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + (JSC::GetByIdStatus::computeForStubInfo): + (JSC::GetByIdStatus::makesCalls): + (JSC::GetByIdStatus::computeForChain): Deleted. + * bytecode/GetByIdStatus.h: + (JSC::GetByIdStatus::makesCalls): Deleted. + * bytecode/GetByIdVariant.cpp: + (JSC::GetByIdVariant::~GetByIdVariant): + (JSC::GetByIdVariant::GetByIdVariant): + (JSC::GetByIdVariant::operator=): + (JSC::GetByIdVariant::dumpInContext): + * bytecode/GetByIdVariant.h: + (JSC::GetByIdVariant::GetByIdVariant): + (JSC::GetByIdVariant::callLinkStatus): + * bytecode/PolymorphicGetByIdList.cpp: + (JSC::GetByIdAccess::fromStructureStubInfo): + (JSC::PolymorphicGetByIdList::from): + * bytecode/SpeculatedType.h: + * bytecode/StructureStubInfo.cpp: + (JSC::StructureStubInfo::deref): + (JSC::StructureStubInfo::visitWeakReferences): + * bytecode/StructureStubInfo.h: + (JSC::isGetByIdAccess): + (JSC::StructureStubInfo::initGetByIdChain): Deleted. + * dfg/DFGAbstractHeap.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleGetByOffset): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination): + (JSC::DFG::CSEPhase::getInternalFieldLoadElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::getTypedArrayByteOffsetLoadElimination): Deleted. + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::linkFunction): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasStorageAccessData): + * dfg/DFGNodeType.h: + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLAbstractHeapRepository.cpp: + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetGetter): + (JSC::FTL::LowerDFGToLLVM::compileGetSetter): + * jit/AccessorCallJITStubRoutine.h: + * jit/JIT.cpp: + (JSC::JIT::assertStackPointerOffset): + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_id): + * jit/ThunkGenerators.cpp: + (JSC::arityFixupGenerator): + (JSC::baselineGetterReturnThunkGenerator): + (JSC::baselineSetterReturnThunkGenerator): + (JSC::arityFixup): Deleted. + * jit/ThunkGenerators.h: + * runtime/CommonSlowPaths.cpp: + (JSC::setupArityCheckData): + * tests/stress/exit-from-getter.js: Added. + * tests/stress/poly-chain-getter.js: Added. + (Cons): + (foo): + (test): + * tests/stress/poly-chain-then-getter.js: Added. + (Cons1): + (Cons2): + (foo): + (test): + * tests/stress/poly-getter-combo.js: Added. + (Cons1): + (Cons2): + (foo): + (test): + (.test): + * tests/stress/poly-getter-then-chain.js: Added. + (Cons1): + (Cons2): + (foo): + (test): + * tests/stress/poly-getter-then-self.js: Added. + (foo): + (test): + (.test): + * tests/stress/poly-self-getter.js: Added. + (foo): + (test): + (getter): + * tests/stress/poly-self-then-getter.js: Added. + (foo): + (test): + * tests/stress/weird-getter-counter.js: Added. + (foo): + (test): + + 2014-05-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] Factor out how CallLinkStatus uses exit site data + https://bugs.webkit.org/show_bug.cgi?id=133042 + + Reviewed by Anders Carlsson. + + This makes it easier to use CallLinkStatus from clients that are calling into after + already holding some of the relevant locks. This is necessary because we use a "one lock + at a time" policy for CodeBlock locks: if you hold one then you're not allowed to acquire + any of the others. So, any code that needs to lock multiple CodeBlock locks needs to sort + of lock one, do some stuff, release it, then lock another, and then do more stuff. The + exit site data corresponds to the stuff you do while holding the baseline lock, while the + CallLinkInfo method corresponds to the stuff you do while holding the CallLinkInfo owner's + lock. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeExitSiteData): + (JSC::CallLinkStatus::computeDFGStatuses): + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::ExitSiteData::ExitSiteData): + + 2014-05-17 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] InlineCallFrame::isCall should be an enumeration + https://bugs.webkit.org/show_bug.cgi?id=133034 + + Reviewed by Sam Weinig. + + Once we start inlining getters and setters, we'll want InlineCallFrame to be able to tell + us that the inlined call was a getter call or a setter call. Initially I thought I would + have a new field called "kind" that would have components NormalCall, GetterCall, and + SetterCall. But that doesn't make sense, because for GetterCall and SetterCall, isCall + would have to be true. Hence, It makes more sense to have one enumeration that is Call, + Construct, GetterCall, or SetterCall. This patch is a first step towards this. + + It's interesting that isClosureCall should probably still be separate, since getter and + setter inlining could inline closure calls. + + * bytecode/CodeBlock.h: + (JSC::baselineCodeBlockForInlineCallFrame): + * bytecode/CodeOrigin.cpp: + (JSC::InlineCallFrame::dumpInContext): + (WTF::printInternal): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::kindFor): + (JSC::InlineCallFrame::specializationKindFor): + (JSC::InlineCallFrame::InlineCallFrame): + (JSC::InlineCallFrame::specializationKind): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGOSRExitPreparation.cpp: + (JSC::DFG::prepareCodeOriginForOSRExit): + * runtime/Arguments.h: + (JSC::Arguments::finishCreation): + + 2014-05-13 Filip Pizlo <fpizlo@apple.com> + + [ftlopt] DFG should not exit due to inadequate profiling coverage when it can trivially fill in the profiling coverage due to variable constant inference and the better prediction modeling of typed array GetByVals + https://bugs.webkit.org/show_bug.cgi?id=132896 + + Reviewed by Geoffrey Garen. + + This is a slight win on SunSpider, but it's meant to ultimately help us on + embenchen/lua. We already do well on that benchmark but our convergence is slower than + I'd like. + + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::refine): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + + 2014-05-08 Filip Pizlo <fpizlo@apple.com> + + jsSubstring() should be lazy + https://bugs.webkit.org/show_bug.cgi?id=132556 + + Reviewed by Andreas Kling. + + jsSubstring() is now lazy by using a special rope that is a substring instead of a + concatenation. To make this patch super simple, we require that a substring's base is + never a rope. Hence, when resolving a rope, we either go down a non-recursive substring + path, or we go down a concatenation path which may see exactly one level of substrings in + its fibers. + + This is up to a 50% speed-up on microbenchmarks and a 10% speed-up on Octane/regexp. + + Relanding this with assertion fixes. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::specializedSweep): + * runtime/JSString.cpp: + (JSC::JSRopeString::visitFibers): + (JSC::JSRopeString::resolveRopeInternal8): + (JSC::JSRopeString::resolveRopeInternal16): + (JSC::JSRopeString::clearFibers): + (JSC::JSRopeString::resolveRope): + (JSC::JSRopeString::resolveRopeSlowCase8): + (JSC::JSRopeString::resolveRopeSlowCase): + * runtime/JSString.h: + (JSC::JSRopeString::finishCreation): + (JSC::JSRopeString::append): + (JSC::JSRopeString::create): + (JSC::JSRopeString::offsetOfFibers): + (JSC::JSRopeString::fiber): + (JSC::JSRopeString::substringBase): + (JSC::JSRopeString::substringOffset): + (JSC::JSRopeString::notSubstringSentinel): + (JSC::JSRopeString::substringSentinel): + (JSC::JSRopeString::isSubstring): + (JSC::JSRopeString::setIsSubstring): + (JSC::jsSubstring): + * runtime/RegExpMatchesArray.cpp: + (JSC::RegExpMatchesArray::reifyAllProperties): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncSubstring): + +2014-07-21 Sam Weinig <sam@webkit.org> + + [Cocoa] WKScriptMessageHandlers don't seem to function properly after navigating + https://bugs.webkit.org/show_bug.cgi?id=135148 + + Reviewed by Geoffrey Garen. + + * runtime/CommonIdentifiers.h: + Add a common identifier for the string "webkit". + +2014-07-22 Filip Pizlo <fpizlo@apple.com> + + ASSERTION FAILED: info.spillFormat() & DataFormatJS in JSC::DFG::SpeculativeJIT::fillSpeculateCell + https://bugs.webkit.org/show_bug.cgi?id=135155 + <rdar://problem/17763909> + + Reviewed by Oliver Hunt. + + The DFG fillSpeculate code paths all need to be mindful of the fact that they may be stumbling upon a + contradiction, and that this is OK. In this case, we were speculating cell on an int. + + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + * tests/stress/regress-135155.js: Added. + (run.t.length): + (run): + +2014-07-18 Filip Pizlo <fpizlo@apple.com> + + Extend exception fuzzing to the LLInt + https://bugs.webkit.org/show_bug.cgi?id=135076 + + Reviewed by Oliver Hunt. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * jit/JITOperations.cpp: + (JSC::numberOfExceptionFuzzChecks): Deleted. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::setUpCall): + * runtime/CommonSlowPaths.cpp: + * runtime/ExceptionFuzz.cpp: Added. + (JSC::numberOfExceptionFuzzChecks): + (JSC::doExceptionFuzzing): + * runtime/ExceptionFuzz.h: Added. + (JSC::doExceptionFuzzingIfEnabled): + +2014-07-21 Mark Lam <mark.lam@apple.com> + + Refactor ArrayPrototype to use getLength() and putLength() utility functions. + https://bugs.webkit.org/show_bug.cgi?id=135139. + + Reviewed by Oliver Hunt. + + - Specialize putProperty() to putLength() because it is only used for setting + the length property. + - Added a getLength() utility function to get the value of the length property. + - Use these getLength() and putLength() functions instead of the existing code + to get and put the length property. Less code to read, easier to understand. + + * runtime/ArrayPrototype.cpp: + (JSC::getLength): + (JSC::putLength): + (JSC::arrayProtoFuncToString): + (JSC::arrayProtoFuncToLocaleString): + (JSC::arrayProtoFuncJoin): + (JSC::arrayProtoFuncPop): + (JSC::arrayProtoFuncPush): + (JSC::arrayProtoFuncReverse): + (JSC::arrayProtoFuncShift): + (JSC::arrayProtoFuncSlice): + (JSC::arrayProtoFuncSort): + (JSC::arrayProtoFuncSplice): + (JSC::arrayProtoFuncUnShift): + (JSC::arrayProtoFuncReduce): + (JSC::arrayProtoFuncReduceRight): + (JSC::arrayProtoFuncIndexOf): + (JSC::arrayProtoFuncLastIndexOf): + (JSC::putProperty): Deleted. + +2014-07-21 Diego Pino Garcia <dpino@igalia.com> + + new Int32Array(new ArrayBuffer(100), 1, 1) shouldn't throw an error that says "RangeError: Byte offset and length out of range of buffer" + https://bugs.webkit.org/show_bug.cgi?id=125391 + + Reviewed by Darin Adler. + + Create own method for verifying byte offset alignment. + + * runtime/ArrayBufferView.h: + (JSC::ArrayBufferView::verifyByteOffsetAlignment): + (JSC::ArrayBufferView::verifySubRangeLength): + (JSC::ArrayBufferView::verifySubRange): Deleted. + * runtime/GenericTypedArrayViewInlines.h: + (JSC::GenericTypedArrayView<Adaptor>::create): + * runtime/JSDataView.cpp: + (JSC::JSDataView::create): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::create): + +2014-07-20 Diego Pino Garcia <dpino@igalia.com> + + ES6: Implement Math.sign() + https://bugs.webkit.org/show_bug.cgi?id=134980 + + Reviewed by Darin Adler. + + * runtime/MathObject.cpp: + (JSC::MathObject::finishCreation): + (JSC::mathProtoFuncSign): + +2014-07-18 Filip Pizlo <fpizlo@apple.com> + + Exception fuzzing should work on iOS + https://bugs.webkit.org/show_bug.cgi?id=135070 + + Reviewed by Mark Hahnenberg. + + * tests/exceptionFuzz.yaml: + +2014-07-18 Filip Pizlo <fpizlo@apple.com> + + Fix cloop build. + + * jsc.cpp: + (jscmain): + +2014-07-15 Filip Pizlo <fpizlo@apple.com> + + Need ability to fuzz exception throwing + https://bugs.webkit.org/show_bug.cgi?id=134945 + <rdar://problem/17722027> + + Reviewed by Sam Weinig. + + Adds the ability to instrument exception checks, and to force some random + exception check to artificially throw an exception. Also adds new tests that + are suitable for testing this. Note that this is closely tied to the Tools + directory changes that are also part of this changeset. + + This also fixes an activation tear-off bug that arises if we ever throw an + exception from operationOptimize, or if due to some other bug it's only due + to the operationOptimize exception check that we realize that there is an + exception to be thrown. + + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::fastExceptionCheck): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::callCheck): + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::callExceptionFuzz): + (JSC::AssemblyHelpers::emitExceptionCheck): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::emitExceptionCheck): Deleted. + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_enter): + * jit/JITOperations.cpp: + (JSC::numberOfExceptionFuzzChecks): + * jit/JITOperations.h: + * jsc.cpp: + (jscmain): + * runtime/Options.h: + * runtime/TestRunnerUtils.h: + * tests/exceptionFuzz.yaml: Added. + * tests/exceptionFuzz: Added. + * tests/exceptionFuzz/3d-cube.js: Added. + * tests/exceptionFuzz/date-format-xparb.js: Added. + * tests/exceptionFuzz/earley-boyer.js: Added. + +2014-07-17 David Kilzer <ddkilzer@apple.com> + + SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig + <http://webkit.org/b/135006> + + Reviewed by Darin Adler. + + * Configurations/Base.xcconfig: Move SECTORDER_FLAGS to + JavaScriptCore.xcconfig. + * Configurations/CompileRuntimeToLLVMIR.xcconfig: Remove empty + SECTORDER_FLAGS definition. + * Configurations/DebugRelease.xcconfig: Ditto. + * Configurations/JavaScriptCore.xcconfig: Use $(CONFIGURATION) + so SECTORDER_FLAGS is only set on Production builds. + +2014-07-17 Juergen Ributzka <juergen@apple.com> + + Disable live-out calculation for stackmap intrinsics. + https://bugs.webkit.org/show_bug.cgi?id=134366 + + The live-out variables are not required for the stackmaps, because we + don't care about preserving the state when we perform destructive + patching. + + Reviewed by Filip Pizlo. + + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-07-17 Joseph Pecoraro <pecoraro@apple.com> + + Follow-up fix to r171195 to prevent ASSERT in fast/profiler/profile-with-no-title.html + + Rubber-stamped by Alexey Proskuryakov. + + Null / empty titles should be fine. Tests pass in release builds + which allowed empty titles, and it looks like the LegacyProfiler + stopProfiling handles empty titles as expected already. + + * profiler/LegacyProfiler.cpp: + (JSC::LegacyProfiler::startProfiling): + +2014-07-16 Filip Pizlo <fpizlo@apple.com> + + DFG Flush(SetLocal) store elimination is overzealous for captured variables in the presence of nodes that have no effects but may throw + https://bugs.webkit.org/show_bug.cgi?id=134988 + <rdar://problem/17706349> + + Reviewed by Oliver Hunt. + + Luckily, we also don't need this optimization to be super powerful: the only place + where it really matters is for getting rid of the redundancy between op_enter and + op_init_lazy_reg, and in that case, there is a small set of possible nodes between the + two things. This change updates the store eliminator to know about only that small, + obviously safe, set of nodes over which we can store-eliminate. + + This shouldn't have any performance impact in the DFG because this optimization kicks + in relatively rarely already. And once we tier up into the FTL, we get a much better + store elimination over LLVM IR, so this really shouldn't matter at all. + + The tricky part of this patch is that there is a close relative of this optimization, + for uncaptured variables that got flushed. This happens for arguments to inlined calls. + I make this work by splitting it into two different store eliminators. + + Note that in the process of crafting the tests, I realized that we were incorrectly + DCEing NewArrayWithSize. That's not cool, since that can throw an exception for + negative array sizes. If we ever did want to DCE this node, we'd need to lower the node + to a check node followed by the actual allocation. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::uncapturedSetLocalStoreElimination): + (JSC::DFG::CSEPhase::capturedSetLocalStoreElimination): + (JSC::DFG::CSEPhase::setLocalStoreElimination): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::SetLocalStoreEliminationResult::SetLocalStoreEliminationResult): Deleted. + * dfg/DFGNodeType.h: + * tests/stress/capture-escape-and-throw.js: Added. + (foo.f): + (foo): + * tests/stress/new-array-with-size-throw-exception-and-tear-off-arguments.js: Added. + (foo): + (bar): + +2014-07-15 Benjamin Poulain <benjamin@webkit.org> + + Reduce the overhead of updating the AssemblerBuffer + https://bugs.webkit.org/show_bug.cgi?id=134659 + + Reviewed by Gavin Barraclough. + + In r164548, the linker was changed to allow the LinkBuffer to survive its MacroAssembler. + That feature is useful for JSC to get offsets inside a linked buffer in order to jump directly + there. + + On ARM, we use branch compaction and we need to keep the "compaction offset" somewher to be able + to get the real address of a lable. That is done by reusing the memory of AssemblerData. + + To share the memory between LinkBuffer and the Assembler, r164548 moved the AssemblerData into + a ref-counted object. Unfortunately, the extra complexity related to the new AssemblerData was enough + to make clang give up a bunch of optimizations. + + This patch solve (some of) the problems by making AssemblerBuffer and AssemblerData super low overhead structures. + In particular, the grow() function becomes 8 Thumb instructions, which is easily inlined everywhere it is used. + + Instead of sharing ownership between the Assembler and LinkBuffer, LinkBuffer now takes full ownership of + the AssemblerData. I feel this is also safer since LinkBuffer is reusing the AssemblerData is a very + specific way that would make it unusable for the Assembler. + + -- Technical details -- + + From LinkBuffer, we don't want to ever access the Assembler after releasing its buffer (or writting anything + into it really). This was obviously already the case, but that was hard to prove from LinkBuffer::copyCompactAndLinkCode(). + To make this easier to work with, I changed all the assembler specific function to be static. This way we know + exactly what code access the Assembler instance. The code that does access the instance is then moved + at the beginning, before we modify anything. + + The function recordLinkOffsets() that was on the MacroAssembler and copied in Assembler was moved directly + to LinkBuffer. This make the modification of AssemblerData completely explicit, and that code is specific + to LinkBuffer anyway (see LinkBuffer::executableOffsetFor()). + + -- Perf impact -- + + This does not put us exactly at before r164548 due to the missing inline buffer. Still, it is very close. + On ARMv7, this reduces the time spent in Assembler by half. On the CSS JIT, this reduces the compilation + time by ~20%. + + I could not measure any difference on x86_64. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::jumpSizeDelta): + (JSC::ARM64Assembler::canCompact): + (JSC::ARM64Assembler::computeJumpType): + (JSC::ARM64Assembler::link): + (JSC::ARM64Assembler::recordLinkOffsets): Deleted. + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::ifThenElseConditionBit): + (JSC::ARMv7Assembler::ifThenElse): + (JSC::ARMv7Assembler::jumpSizeDelta): + (JSC::ARMv7Assembler::canCompact): + (JSC::ARMv7Assembler::computeJumpType): + (JSC::ARMv7Assembler::link): + (JSC::ARMv7Assembler::linkJumpT1): + (JSC::ARMv7Assembler::linkJumpT3): + (JSC::ARMv7Assembler::linkConditionalJumpT4): + (JSC::ARMv7Assembler::linkConditionalBX): + (JSC::ARMv7Assembler::recordLinkOffsets): Deleted. + * assembler/AssemblerBuffer.h: + (JSC::AssemblerData::AssemblerData): + (JSC::AssemblerData::operator=): + (JSC::AssemblerData::~AssemblerData): + (JSC::AssemblerData::buffer): + (JSC::AssemblerData::capacity): + (JSC::AssemblerData::grow): + (JSC::AssemblerBuffer::AssemblerBuffer): + (JSC::AssemblerBuffer::isAvailable): + (JSC::AssemblerBuffer::data): + (JSC::AssemblerBuffer::releaseAssemblerData): + (JSC::AssemblerBuffer::putIntegral): + (JSC::AssemblerBuffer::putIntegralUnchecked): + (JSC::AssemblerBuffer::append): + (JSC::AssemblerBuffer::grow): + (JSC::AssemblerBuffer::~AssemblerBuffer): Deleted. + (JSC::AssemblerBuffer::storage): Deleted. + * assembler/LinkBuffer.cpp: + (JSC::recordLinkOffsets): + (JSC::LinkBuffer::copyCompactAndLinkCode): + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::LinkBuffer): + (JSC::LinkBuffer::executableOffsetFor): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::canCompact): + (JSC::MacroAssemblerARM64::computeJumpType): + (JSC::MacroAssemblerARM64::jumpSizeDelta): + (JSC::MacroAssemblerARM64::link): + (JSC::MacroAssemblerARM64::recordLinkOffsets): Deleted. + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::canCompact): + (JSC::MacroAssemblerARMv7::computeJumpType): + (JSC::MacroAssemblerARMv7::jumpSizeDelta): + (JSC::MacroAssemblerARMv7::link): + (JSC::MacroAssemblerARMv7::recordLinkOffsets): Deleted. + +2014-07-15 Mark Hahnenberg <mhahnenberg@apple.com> + + Stores to PropertyTable use the Structure as the owner + https://bugs.webkit.org/show_bug.cgi?id=134595 + + Reviewed by Darin Adler. + + Since PropertyTable is the object that does the marking of these references, it should be the owner. + + Also removed some unused parameters to other methods that historically used the Structure as the owner. + + * runtime/JSPropertyNameIterator.h: + (JSC::StructureRareData::setEnumerationCache): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncToString): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::copy): + * runtime/PropertyTable.cpp: + (JSC::PropertyTable::clone): + (JSC::PropertyTable::PropertyTable): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::changePrototypeTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::attributeChangeTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::takePropertyTableOrCloneIfPinned): + (JSC::Structure::nonPropertyTransition): + (JSC::Structure::copyPropertyTable): + (JSC::Structure::copyPropertyTableForPinning): + (JSC::Structure::putSpecificValue): + * runtime/Structure.h: + (JSC::Structure::setObjectToStringValue): + (JSC::Structure::setPreviousID): + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + * runtime/StructureRareData.h: + * runtime/StructureRareDataInlines.h: + (JSC::StructureRareData::setPreviousID): + (JSC::StructureRareData::setObjectToStringValue): + +2014-07-15 Mark Hahnenberg <mhahnenberg@apple.com> + + ScriptExecutable::forEachCodeBlock can dereference null CodeBlocks + https://bugs.webkit.org/show_bug.cgi?id=134928 + + Reviewed by Andreas Kling. + + * bytecode/CodeBlock.h: + (JSC::ScriptExecutable::forEachCodeBlock): Check for null CodeBlocks before calling forEachRelatedCodeBlock. + +2014-07-15 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + Buildfix if LLINT_SLOW_PATH_TRACING is enabled + https://bugs.webkit.org/show_bug.cgi?id=133790 + + Reviewed by Mark Lam. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + +2014-07-14 Filip Pizlo <fpizlo@apple.com> + + Allow for Int52Rep to see things other than Int32, and make this testable + https://bugs.webkit.org/show_bug.cgi?id=134873 + <rdar://problem/17641915> + + Reviewed by Geoffrey Garen and Mark Hahnenberg. + + A major premise of our type inference is that prediction propagation can say whatever it + wants and we'll still have valid IR after Fixup. This previously didn't work with Int52s. + We required some kind of agreement between prediction propagation and fixup over which + data flow paths were Int52 and which weren't. + + It turns out that we basically had such an agreement, with the exception of code that was + unreachable due to ForceOSRExit. Then, fixup and prediction propagation would disagree. It + might be nice to fix that bug - but it's only in the case of Int52 that such a thing would + be a bug! Normally, we allow sloppiness in prediction propagation. + + This patch allows us to be sloppy with Int52 prediction propagation by giving Int52Rep the + ability to see inputs other than Int32. This fixes the particular ForceOSRExit bug (see + int52-force-osr-exit-path.js for the reduced test case). To make sure that the newly + empowered Int52Rep is actually correct - in case we end up using it on paths other than + ForceOSRExit - this patch introduces an internal intrinsic called fiatInt52() that forces + us to attempt Int52 conversion on the input. This patch adds a bunch of tests that stress + this intrinsic. This means that we're now stressing Int52Rep more so than ever before! + + Note that it would still be a bug for prediction propagation to ever cause us to create an + Int52Rep node for a non-Int32 input. But, this will now be a performance bug, rather than + a crash bug. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::fixTypeForRepresentation): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::isMachineIntConstant): + * dfg/DFGNode.h: + (JSC::DFG::Node::isMachineIntConstant): + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::speculate): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::convertMachineInt): + (JSC::DFG::SpeculativeJIT::speculateMachineInt): + (JSC::DFG::SpeculativeJIT::speculateDoubleRepMachineInt): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + (JSC::DFG::isNumerical): + (JSC::DFG::isDouble): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileInt52Rep): + (JSC::FTL::LowerDFGToLLVM::doubleToInt32): + (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): + (JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52): + (JSC::FTL::LowerDFGToLLVM::doubleToStrictInt52): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateMachineInt): + (JSC::FTL::LowerDFGToLLVM::speculateDoubleRepMachineInt): + * jit/JITOperations.h: + * jsc.cpp: + (GlobalObject::finishCreation): + (functionIdentity): + * runtime/Intrinsic.h: + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::tryConvertToInt52): + (JSC::isInt52): + (JSC::JSValue::isMachineInt): + * tests/stress/dead-fiat-double-to-int52-then-exit-not-int52.js: Added. + (foo): + * tests/stress/dead-fiat-double-to-int52.js: Added. + (foo): + * tests/stress/dead-fiat-int32-to-int52.js: Added. + (foo): + * tests/stress/dead-fiat-value-to-int52-double-path.js: Added. + (foo): + (bar): + * tests/stress/dead-fiat-value-to-int52-then-exit-not-double.js: Added. + (foo): + (bar): + * tests/stress/dead-fiat-value-to-int52-then-exit-not-int52.js: Added. + (foo): + (bar): + * tests/stress/dead-fiat-value-to-int52.js: Added. + (foo): + (bar): + * tests/stress/fiat-double-to-int52-then-exit-not-int52.js: Added. + (foo): + * tests/stress/fiat-double-to-int52-then-fail-to-fold.js: Added. + (foo): + * tests/stress/fiat-double-to-int52-then-fold.js: Added. + (foo): + * tests/stress/fiat-double-to-int52.js: Added. + (foo): + * tests/stress/fiat-int32-to-int52.js: Added. + (foo): + * tests/stress/fiat-value-to-int52-double-path.js: Added. + (foo): + (bar): + * tests/stress/fiat-value-to-int52-then-exit-not-double.js: Added. + (foo): + (bar): + * tests/stress/fiat-value-to-int52-then-exit-not-int52.js: Added. + (foo): + (bar): + * tests/stress/fiat-value-to-int52-then-fail-to-fold.js: Added. + (foo): + * tests/stress/fiat-value-to-int52-then-fold.js: Added. + (foo): + * tests/stress/fiat-value-to-int52.js: Added. + (foo): + (bar): + * tests/stress/int52-force-osr-exit-path.js: Added. + (foo): + +2014-07-14 Mark Hahnenberg <mhahnenberg@apple.com> + + Flattening dictionaries with oversize backing stores can cause crashes + https://bugs.webkit.org/show_bug.cgi?id=134906 + + Reviewed by Filip Pizlo. + + The collector expects any pointers into CopiedSpace passed to copyLater are within 32 KB + of the CopiedBlock header. This was always the case except for when flattening a dictionary + caused the size of the Butterfly to decrease. This was equivalent to moving the base of the + Butterfly to higher addresses. If the object was reduced sufficiently in size, the base + would no longer be within the first 32 KB of the CopiedBlock and the next collection would + choke on the Butterfly pointer. + + This patch fixes this issue by detect this situation during flattening and memmove-ing + the Butterfly down to where the old base was. + + * runtime/JSObject.cpp: + (JSC::JSObject::shiftButterflyAfterFlattening): + * runtime/JSObject.h: + (JSC::JSObject::butterflyPreCapacity): + (JSC::JSObject::butterflyTotalSize): + * runtime/Structure.cpp: + (JSC::Structure::flattenDictionaryStructure): + * tests/stress/flatten-oversize-dictionary-object.js: Added. + (foo): + +2014-07-14 Benjamin Poulain <benjamin@webkit.org> + + Remove some dead code from FTLJITFinalizer + https://bugs.webkit.org/show_bug.cgi?id=134874 + + Reviewed by Geoffrey Garen. + + Not sure what that code was for...but it does not do anything :) + + * ftl/FTLJITFinalizer.cpp: + (JSC::FTL::JITFinalizer::finalizeFunction): + The pointer of the label is computed but never used. + + * ftl/FTLJITFinalizer.h: + * ftl/FTLLink.cpp: + (JSC::FTL::link): + The label is never set to anything. + +2014-07-14 Bear Travis <betravis@adobe.com> + + [Feature Queries] Enable Feature Queries on Mac + https://bugs.webkit.org/show_bug.cgi?id=134404 + + Reviewed by Antti Koivisto. + + Enable Feature Queries on Mac and resume running the + feature tests. + + * Configurations/FeatureDefines.xcconfig: Turn on + ENABLE_CSS3_CONDITIONAL_RULES. + +2014-07-11 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Debugger Pause button does not work + https://bugs.webkit.org/show_bug.cgi?id=134785 + + Reviewed by Timothy Hatcher. + + * CMakeLists.txt: + * DerivedSources.make: + Minification strips the sourceURL command. Add it back with minification. + +2014-07-11 peavo@outlook.com <peavo@outlook.com> + + [Win] Enable DFG JIT. + https://bugs.webkit.org/show_bug.cgi?id=123615 + + Reviewed by Mark Lam. + + When the return type of a JIT generated function call is larger than 64-bit (e.g. SlowPathReturnType), + the normal call() implementation cannot be used on 64-bit Windows, because the 64-bit Windows ABI is different in this case. + Also, when generating calls with double arguments, we need to make sure the arguments are put in the correct registers, + since the register allocation differs on 64-bit Windows. + + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::callWithSlowPathReturnType): Added method to handle function calls where the return value type size is larger than 64-bit. + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): Move arguments to correct registers when there are floating point arguments. + (JSC::CCallHelpers::setupArgumentsWithExecStateForCallWithSlowPathReturnType): Added method. + * jit/JIT.h: + (JSC::JIT::appendCallWithSlowPathReturnType): Added method. + * jit/JITInlines.h: + (JSC::JIT::appendCallWithExceptionCheckAndSlowPathReturnType): Added method. + (JSC::JIT::callOperation): Call new method. + +2014-07-09 Benjamin Poulain <benjamin@webkit.org> + + Use 16bits instructions for push/pop on ARMv7 when possible + https://bugs.webkit.org/show_bug.cgi?id=134753 + + Reviewed by Geoffrey Garen. + + The patch r170839 mixed the code for push/pop pair and single push/pop. + That part was reverted in r170909. + + This patch puts the code back but specialized for single push/pop. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::pop): + (JSC::ARMv7Assembler::push): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::pop): + (JSC::MacroAssemblerARMv7::push): + +2014-07-09 Brent Fulgham <bfulgham@apple.com> + + [Win] Remove uses of 'bash' in build system + https://bugs.webkit.org/show_bug.cgi?id=134782 + <rdar://problem/17615533> + + Reviewed by Dean Jackson. + + Remove uses of 'bash' by replacing Windows-specific bash scripts + with Perl equivalents. + + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make: + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj.filters: + * JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh. + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: Removed. + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.sh. + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.sh: Removed. + * JavaScriptCore.vcxproj/build-generated-files.pl: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/build-generated-files.sh. + * JavaScriptCore.vcxproj/build-generated-files.sh: Removed. + * JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd: + * JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd: + * JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd: + +2014-07-09 Brent Fulgham <bfulgham@apple.com> + + [Win] Remove use of 'grep' in build steps + https://bugs.webkit.org/show_bug.cgi?id=134770 + <rdar://problem/17608783> + + Reviewed by Tim Horton. + + Replace uses of the grep command in Windows builds with the equivalent + Perl program. + + * JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd: + * JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd: + * JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd: + * JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd: + +2014-07-08 Benjamin Poulain <benjamin@webkit.org> + + Restore the assertion changed with 170839 + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::pop): + (JSC::ARMv7Assembler::push): + Revert the Assembler part of 170839. The assertions do not match both encoding. + + I'll add specific version of push and pop instead. + +2014-07-08 Jon Honeycutt <jhoneycutt@apple.com> + + RemoteInspector::shared() should not call WTF::initializeMainThread() + <https://bugs.webkit.org/show_bug.cgi?id=134747> + <rdar://problem/17161482> + + Reviewed by Joseph Pecoraro. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::shared): + Don't call WTF::initializeMainThread(). WTF threading is initialized by + JSC::initializeThreading(). + +2014-07-08 Andreas Kling <akling@apple.com> + + VM::lastCachedString should be a Strong, not a Weak. + <https://webkit.org/b/134746> + + Using Weak<JSString> for this regressed some of our bindings perf tests + due to Weak having to allocate a new WeakImpl every time the last cached + string changed. Make it a Strong instead should make that problem go away. + + Reviewed by Geoffrey Garen. + + * runtime/JSString.cpp: + (JSC::jsStringWithCacheSlowCase): + * runtime/VM.h: + +2014-07-07 Benjamin Poulain <bpoulain@apple.com> + + Fix the build after r170876 + + * assembler/LinkBuffer.cpp: + (JSC::LinkBuffer::linkCode): + +2014-07-07 Benjamin Poulain <benjamin@webkit.org> + + LinkBuffer should not keep a reference to the MacroAssembler + https://bugs.webkit.org/show_bug.cgi?id=134668 + + Reviewed by Geoffrey Garen. + + In FTL, the LinkBuffer can outlive the MacroAssembler that was used for code generation. + When that happens, the pointer m_assembler points to released memory. That was not causing + issues because the attribute is not used after linking, but that was not particularily + future proof. + + This patch refactors LinkBuffer to avoid any lifetime risk. The MacroAssembler is now passed + as a reference, it is used for linking but no reference is ever stored with the LinkBuffer. + + While fixing the call sites to use a reference, I also discovered LinkBuffer.h was included + everywhere. I refactored some #include to avoid that. + + * assembler/LinkBuffer.cpp: + (JSC::LinkBuffer::copyCompactAndLinkCode): + (JSC::LinkBuffer::linkCode): + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::LinkBuffer): + * bytecode/Watchpoint.cpp: + * dfg/DFGDisassembler.cpp: + * dfg/DFGDisassembler.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::linkFunction): + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGPlan.cpp: + * dfg/DFGThunks.cpp: + (JSC::DFG::osrExitGenerationThunkGenerator): + (JSC::DFG::osrEntryThunkGenerator): + * ftl/FTLCompile.cpp: + (JSC::FTL::generateICFastPath): + (JSC::FTL::fixFunctionBasedOnStackMaps): + * ftl/FTLJSCall.cpp: + * ftl/FTLJSCall.h: + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLLowerDFGToLLVM.cpp: + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + * ftl/FTLThunks.cpp: + (JSC::FTL::osrExitGenerationThunkGenerator): + (JSC::FTL::slowPathCallThunkGenerator): + * jit/ArityCheckFailReturnThunks.cpp: + (JSC::ArityCheckFailReturnThunks::returnPCsFor): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITCall.cpp: + (JSC::JIT::privateCompileClosureCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::privateCompileClosureCall): + * jit/JITDisassembler.cpp: + * jit/JITDisassembler.h: + * jit/JITOpcodes.cpp: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::privateCompileGetByVal): + (JSC::JIT::privateCompilePutByVal): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::stringGetByValStubGenerator): + * jit/RegisterPreservationWrapperGenerator.cpp: + (JSC::generateRegisterPreservationWrapper): + (JSC::registerRestorationThunkGenerator): + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::emitPutReplaceStub): + (JSC::emitPutTransitionStub): + (JSC::tryRepatchIn): + (JSC::linkClosureCall): + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::finalize): + * jit/ThunkGenerators.cpp: + (JSC::throwExceptionFromCallSlowPathGenerator): + (JSC::linkForThunkGenerator): + (JSC::linkClosureCallForThunkGenerator): + (JSC::virtualForThunkGenerator): + (JSC::nativeForGenerator): + (JSC::arityFixup): + * llint/LLIntThunks.cpp: + (JSC::LLInt::generateThunkWithJumpTo): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::compile): + +2014-07-07 Andreas Kling <akling@apple.com> + + Fast path for jsStringWithCache() when asked for the same string repeatedly. + <https://webkit.org/b/134635> + + Reviewed by Darin Adler. + + Follow-up to r170818 addressing a review comment by Geoff Garen. + + * runtime/JSString.cpp: + (JSC::jsStringWithCacheSlowCase): + +2014-07-07 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Add missing ENABLE(FTL_JIT) guards + https://bugs.webkit.org/show_bug.cgi?id=134680 + + Reviewed by Darin Adler. + + * ftl/FTLDWARFDebugLineInfo.cpp: + * ftl/FTLDWARFDebugLineInfo.h: + * ftl/FTLGeneratedFunction.h: + +2014-07-07 Zan Dobersek <zdobersek@igalia.com> + + Enable ARMv7 disassembler for the GTK port + https://bugs.webkit.org/show_bug.cgi?id=134676 + + Reviewed by Benjamin Poulain. + + * CMakeLists.txt: Add ARMv7DOpcode.cpp file to the build. + * disassembler/ARMv7/ARMv7DOpcode.cpp: Include the string.h header for strlen(). + +2014-07-06 Benjamin Poulain <benjamin@webkit.org> + + [ARMv7] Use 16 bits instructions for push/pop when possible + https://bugs.webkit.org/show_bug.cgi?id=134656 + + Reviewed by Andreas Kling. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::pop): + (JSC::ARMv7Assembler::push): + (JSC::ARMv7Assembler::ARMInstructionFormatter::oneWordOp7Imm9): + Add the 16 bits version of push and pop. + + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::pop): + (JSC::MacroAssemblerARMv7::push): + Use the new push/pop instead of a regular load/store. + + * disassembler/ARMv7/ARMv7DOpcode.cpp: + (JSC::ARMv7Disassembler::ARMv7DOpcode::appendRegisterList): + * disassembler/ARMv7/ARMv7DOpcode.h: + (JSC::ARMv7Disassembler::ARMv7DOpcodeMiscPushPop::registerMask): + Fix the disassembler for push/pop: + -The register mask was on 7 bits for some reason. + -The code printing the registers was comparing a register ID with a register + mask. + +2014-07-06 Yoav Weiss <yoav@yoav.ws> + + Turn on img@sizes compile flag + https://bugs.webkit.org/show_bug.cgi?id=134634 + + Reviewed by Benjamin Poulain. + + * Configurations/FeatureDefines.xcconfig: Moved compile flag to alphabetical order. + +2014-07-06 Daewoong Jang <daewoong.jang@navercorp.com> + + Flags value of SourceCodeKey should be unique for each case. + https://bugs.webkit.org/show_bug.cgi?id=134435 + + Reviewed by Darin Adler. + + Different combinations of CodeType and JSParserStrictness could generate same m_flags value because + the value of CodeType and the value of JSParserStrictness shares a bit inside m_flags member variable. + Shift the value of CodeType one bit farther to the left so those values don't overlap. + + * runtime/CodeCache.h: + (JSC::SourceCodeKey::SourceCodeKey): + +2014-07-04 Andreas Kling <akling@apple.com> + + Fast path for jsStringWithCache() when asked for the same string repeatedly. + <https://webkit.org/b/134635> + + Also moved the whole thing from WebCore to JavaScriptCore since it + makes more sense here, and inline the lightweight checks, leaving only + the hashmap stuff out of line. + + Reviewed by Darin Adler. + + * runtime/JSString.cpp: + (JSC::jsStringWithCacheSlowCase): + * runtime/JSString.h: + (JSC::jsStringWithCache): + * runtime/VM.h: + +2014-07-03 Daniel Bates <dabates@apple.com> + + Add WTF::move() + https://bugs.webkit.org/show_bug.cgi?id=134500 + + Rubber-stamped by Anders Carlsson. + + Substitute WTF::move() for std::move(). + + * bytecode/CodeBlock.h: + * bytecode/UnlinkedCodeBlock.cpp: + * bytecompiler/BytecodeGenerator.cpp: + * dfg/DFGGraph.cpp: + * dfg/DFGJITCompiler.cpp: + * dfg/DFGStackLayoutPhase.cpp: + * dfg/DFGWorklist.cpp: + * heap/DelayedReleaseScope.h: + * heap/HeapInlines.h: + [...] + +2014-07-03 Filip Pizlo <fpizlo@apple.com> + + SSA DCE should process blocks in forward order + https://bugs.webkit.org/show_bug.cgi?id=134611 + + Reviewed by Andreas Kling. + + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode): + * tests/stress/dead-value-with-mov-hint-in-another-block.js: Added. + (foo): + +2014-07-03 Filip Pizlo <fpizlo@apple.com> + + JSActivation::symbolTablePut() should invalidate variable watchpoints + https://bugs.webkit.org/show_bug.cgi?id=134602 + + Reviewed by Oliver Hunt. + + Usually stores to captured variables cause us to invalidate the variable watchpoint because CodeBlock does so + during linking - we essentially assume that if it's at all possible for an inner function to store to a + variable we declare then this variable cannot be a constant. But this misses the dynamic store case, i.e. + JSActivation::symbolTablePut(). Part of the problem here is that JSActivation duplicates + JSSymbolTableObject's symbolTablePut() logic, which did have the invalidation. This patch keeps that code + duplicated, but fixes JSActivation::symbolTablePut() to do the right thing. + + * runtime/JSActivation.cpp: + (JSC::JSActivation::symbolTablePut): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTablePut): + * tests/stress/constant-closure-var-with-dynamic-invalidation.js: Added. + (.): + +2014-07-01 Mark Lam <mark.lam@apple.com> + + Debugger's breakpoint list should not be a Vector. + <https://webkit.org/b/134514> + + Reviewed by Geoffrey Garen. + + The debugger currently stores breakpoint data as entries in a Vector (see + BreakpointsInLine). It also keeps a fast map look up of breakpoint IDs to + the breakpoint data (see m_breakpointIDToBreakpoint). Because a Vector can + compact or reallocate its backing store, this can causes all sorts of havoc. + The m_breakpointIDToBreakpoint map assumes that the breakpoint data doesn't + move in memory. + + The fix is to replace the BreakpointsInLine Vector with a BreakpointsList + doubly linked list. + + * debugger/Breakpoint.h: + (JSC::Breakpoint::Breakpoint): + (JSC::BreakpointsList::~BreakpointsList): + * debugger/Debugger.cpp: + (JSC::Debugger::setBreakpoint): + (JSC::Debugger::removeBreakpoint): + (JSC::Debugger::hasBreakpoint): + * debugger/Debugger.h: + +2014-06-30 Michael Saboff <msaboff@apple.com> + + Add option to run-jsc-stress-testes to filter out tests that use large heaps + https://bugs.webkit.org/show_bug.cgi?id=134458 + + Reviewed by Filip Pizlo. + + Added test to skip js1_5/Regress/regress-159334.js when testing on a memory limited device. + + * tests/mozilla/mozilla-tests.yaml: + +2014-06-30 Daniel Bates <dabates@apple.com> + + Avoid copying closed variables vector; actually use move semantics + + Rubber-stamped by Oliver Hunt. + + Currently we always copy the closed variables vector passed by Parser::closedVariables() + to ProgramNode::setClosedVariables() because these member functions return and take a const + rvalue reference, respectively. Instead, these member functions should take an return a non- + constant rvalue reference so that we actually move the closed variables vector from the Parser + object to the Node object. + + * parser/Nodes.cpp: + (JSC::ProgramNode::setClosedVariables): Remove const qualifier for argument. + * parser/Nodes.h: + (JSC::ScopeNode::setClosedVariables): Ditto. + * parser/Parser.h: + (JSC::Parser::closedVariables): Remove const qualifier on return type. + (JSC::parse): Remove extraneous call to std::move(). Calling std::move() is unnecessary here + because Parser::closedVariables() returns an rvalue reference. + +2014-06-30 Joseph Pecoraro <pecoraro@apple.com> + + JSContext Inspection: Provide a way to use a non-Main RunLoop for Inspector JavaScript Evaluations + https://bugs.webkit.org/show_bug.cgi?id=134371 + + Reviewed by Timothy Hatcher. + + * API/JSContextPrivate.h: + * API/JSContext.mm: + (-[JSContext _debuggerRunLoop]): + (-[JSContext _setDebuggerRunLoop:]): + Private API for setting the CFRunLoop for a debugger to evaluate in. + + * API/JSContextRefInternal.h: Added. + * API/JSContextRef.cpp: + (JSGlobalContextGetDebuggerRunLoop): + (JSGlobalContextSetDebuggerRunLoop): + Internal API for setting a CFRunLoop on a JSContextRef. + Set this on the debuggable. + + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggableConnection.h: + (Inspector::RemoteInspectorBlock::RemoteInspectorBlock): + (Inspector::RemoteInspectorBlock::~RemoteInspectorBlock): + (Inspector::RemoteInspectorBlock::operator=): + (Inspector::RemoteInspectorBlock::operator()): + Moved into the header. + + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::inspectorDebuggable): + Lets store the RunLoop on the debuggable instead of this core + platform agnostic class, so expose the debuggable. + + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorHandleRunSourceGlobal): + (Inspector::RemoteInspectorQueueTaskOnGlobalQueue): + (Inspector::RemoteInspectorInitializeGlobalQueue): + Rename the global functions for clarity. + + (Inspector::RemoteInspectorHandleRunSourceWithInfo): + Handler for private run loops. + + (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): + (Inspector::RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection): + (Inspector::RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable): + (Inspector::RemoteInspectorDebuggableConnection::setupRunLoop): + (Inspector::RemoteInspectorDebuggableConnection::teardownRunLoop): + (Inspector::RemoteInspectorDebuggableConnection::queueTaskOnPrivateRunLoop): + Setup and teardown and use private run loop sources if the debuggable needs it. + +2014-06-30 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Add missing ENABLE(DFG_JIT) guards + https://bugs.webkit.org/show_bug.cgi?id=134444 + + Reviewed by Darin Adler. + + * dfg/DFGFunctionWhitelist.cpp: + * dfg/DFGFunctionWhitelist.h: + +2014-06-29 Yoav Weiss <yoav@yoav.ws> + + Add support for HTMLImageElement's sizes attribute + https://bugs.webkit.org/show_bug.cgi?id=133620 + + Reviewed by Dean Jackson. + + Added an ENABLE_PICTURE_SIZES compile flag. + + * Configurations/FeatureDefines.xcconfig: + +2014-06-27 Filip Pizlo <fpizlo@apple.com> + + Don't fold a UInt32ToNumber with DoOverflow to Identity since that would result in an Identity that takes an Int32 and returns a DoubleRep + https://bugs.webkit.org/show_bug.cgi?id=134412 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::setReplacement): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * tests/stress/uint32-to-number-fold-constant-with-do-overflow.js: Added. + (foo): + (bar): + (baz): + +2014-06-27 Peyton Randolph <prandolph@apple.com> + + Add feature flag for link long-press gesture. + https://bugs.webkit.org/show_bug.cgi?id=134262 + + Reviewed by Enrica Casucci. + + * Configurations/FeatureDefines.xcconfig: + Add ENABLE_LINK_LONG_PRESS. + +2014-06-27 László Langó <llango.u-szeged@partner.samsung.com> + + [JavaScriptCore] FTL buildfix for EFL platform. + https://bugs.webkit.org/show_bug.cgi?id=133546 + + Reviewed by Darin Adler. + + * ftl/FTLAbstractHeap.cpp: + (JSC::FTL::IndexedAbstractHeap::IndexedAbstractHeap): + * ftl/FTLLocation.cpp: + (JSC::FTL::Location::forStackmaps): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::opposite): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + * ftl/FTLStackMaps.cpp: + (JSC::FTL::StackMaps::Constant::dump): + * llvm/InitializeLLVMPOSIX.cpp: + (JSC::initializeLLVMPOSIX): + +2014-06-26 Benjamin Poulain <benjamin@webkit.org> + + iOS 8 beta 2 ES6 'Set' clear() broken + https://bugs.webkit.org/show_bug.cgi?id=134346 + + Reviewed by Oliver Hunt. + + The object map was not cleared :(. + + Kudos to Ashley Gullen for tracking this and making a regression test. + Credit to Oliver for finding the missing code. + + * runtime/MapData.h: + (JSC::MapData::clear): + +2014-06-25 Brent Fulgham <bfulgham@apple.com> + + [Win] Expose Cache Information to WinLauncher + https://bugs.webkit.org/show_bug.cgi?id=134318 + + Reviewed by Dean Jackson. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Add missing + MemoryStatistics files to the WIndows build. + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-06-26 David Kilzer <ddkilzer@apple.com> + + DFG::FunctionWhitelist::parseFunctionNamesInFile does not close file + <http://webkit.org/b/134343> + <rdar://problem/17459487> + + Reviewed by Michael Saboff. + + * dfg/DFGFunctionWhitelist.cpp: + (JSC::DFG::FunctionWhitelist::parseFunctionNamesInFile): + Close the file handle, and log an error on failure. + +2014-06-25 Dana Burkart <dburkart@apple.com> + + Add support for 5-tuple versioning. + + Reviewed by David Farler. + + * Configurations/Version.xcconfig: + +2014-06-25 Geoffrey Garen <ggaren@apple.com> + + Build fix. + + Unreviewed. + + * runtime/JSDateMath.cpp: + (JSC::parseDateFromNullTerminatedCharacters): + * runtime/VM.cpp: + (JSC::VM::resetDateCache): Use std::numeric_limits instead of QNaN + constant since that constant doesn't exist anymore. + +2014-06-25 Geoffrey Garen <ggaren@apple.com> + + Unreviewed, rolling out r166876. + + Caused some ECMA test262 failures + + Reverted changeset: + + "Date object needs to check for ES5 15.9.1.14 TimeClip limit." + https://bugs.webkit.org/show_bug.cgi?id=131248 + http://trac.webkit.org/changeset/166876 + +2014-06-25 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed gardening. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Update to + put various files in proper IDE categories. + +2014-06-25 peavo@outlook.com <peavo@outlook.com> + + [Win64] ASM LLINT is not enabled. + https://bugs.webkit.org/show_bug.cgi?id=130638 + + This patch adds a new LLINT assembler backend for Win64, and implements it. + It makes adjustments to follow the Win64 ABI spec. where it's found to be needed. + Also, LLINT and JIT is enabled for Win64. + + Reviewed by Mark Lam. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Added JITStubsMSVC64.asm. + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Ditto. + * JavaScriptCore/JavaScriptCore.vcxproj/jsc/jscCommon.props: Increased stack size to avoid stack overflow in tests. + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: Generate assembler source file for Win64. + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::call): Follow Win64 ABI spec. + * jit/JITStubsMSVC64.asm: Added. + * jit/Repatch.cpp: + (JSC::emitPutTransitionStub): Compile fix. + * jit/ThunkGenerators.cpp: + (JSC::nativeForGenerator): Follow Win64 ABI spec. + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): Ditto. + * llint/LLIntOfflineAsmConfig.h: Enable new llint backend for Win64. + * llint/LowLevelInterpreter.asm: Implement new Win64 backend, and follow Win64 ABI spec. + * llint/LowLevelInterpreter64.asm: Ditto. + * offlineasm/asm.rb: Compile fix. + * offlineasm/backends.rb: Add new llint backend for Win64. + * offlineasm/settings.rb: Compile fix. + * offlineasm/x86.rb: Implement new llint Win64 backend. + +2014-06-25 Laszlo Gombos <l.gombos@samsung.com> + + Remove build guard for progress element + https://bugs.webkit.org/show_bug.cgi?id=134292 + + Reviewed by Benjamin Poulain. + + * Configurations/FeatureDefines.xcconfig: + +2014-06-24 Michael Saboff <msaboff@apple.com> + + Add support routines to provide descriptive JavaScript backtraces + https://bugs.webkit.org/show_bug.cgi?id=134278 + + Reviewed by Mark Lam. + + * interpreter/CallFrame.cpp: + (JSC::CallFrame::dump): + (JSC::CallFrame::describeFrame): + * interpreter/CallFrame.h: + * runtime/JSCJSValue.cpp: + (JSC::JSValue::dumpForBacktrace): + * runtime/JSCJSValue.h: + +2014-06-24 Brady Eidson <beidson@apple.com> + + Enable GAMEPAD in the Mac build, but disabled at runtime. + https://bugs.webkit.org/show_bug.cgi?id=134255 + + Reviewed by Dean Jackson. + + * Configurations/FeatureDefines.xcconfig: + + * runtime/JSObject.h: Export JSObject::removeDirect() to allow disabling + functions at runtime. + +2014-06-24 Mark Hahnenberg <mhahnenberg@apple.com> + + REGRESSION (r169703): Invalid cast in JSC::asGetterSetter / JSC::JSObject::defineOwnNonIndexProperty + https://bugs.webkit.org/show_bug.cgi?id=134046 + + Reviewed by Filip Pizlo. + + * runtime/GetterSetter.h: + (JSC::asGetterSetter): + * runtime/JSObject.cpp: + (JSC::JSObject::defineOwnNonIndexProperty): We need to check for a CustomGetterSetter here as well as + a normal GetterSetter. If we encounter a CustomGetterSetter, we delete it, create a new normal GetterSetter, + and insert it like normal. We also need to check for CustomAccessors when checking for unconfigurable properties. + +2014-06-24 Brent Fulgham <bfulgham@apple.com> + + [Win] MSVC mishandles enums in bitfields + https://bugs.webkit.org/show_bug.cgi?id=134237 + + Reviewed by Michael Saboff. + + Replace uses of enum types in bit fields with unsigned to + avoid losing a bit to hold the sign value. This can result + in Windows interpreting the value of the field improperly. + + * bytecode/StructureStubInfo.h: + * parser/Nodes.h: + +2014-06-23 Andreas Kling <akling@apple.com> + + Inline the UnlinkedInstructionStream::Reader logic. + <https://webkit.org/b/134203> + + This class is only used by CodeBlock to unpack the unlinked instructions, + and we were spending 0.5% of total time on PLT calling Reader::next(). + Move the logic to the header file and mark it ALWAYS_INLINE. + + Reviewed by Geoffrey Garen. + + * bytecode/UnlinkedInstructionStream.cpp: + * bytecode/UnlinkedInstructionStream.h: + (JSC::UnlinkedInstructionStream::Reader::Reader): + (JSC::UnlinkedInstructionStream::Reader::read8): + (JSC::UnlinkedInstructionStream::Reader::read32): + (JSC::UnlinkedInstructionStream::Reader::next): + +2014-06-20 Sam Weinig <sam@webkit.org> + + Remove static tables for bindings that use eager reification + https://bugs.webkit.org/show_bug.cgi?id=134126 + + Reviewed by Oliver Hunt. + + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectCustomAccessor): + * runtime/Structure.h: + (JSC::Structure::setHasCustomGetterSetterProperties): + Change setHasCustomGetterSetterProperties to behave like setHasGetterSetterProperties, and set + the m_hasReadOnlyOrGetterSetterPropertiesExcludingProto bit if the property is not __proto__. + Without this, JSObject::put() won't think there are any setters on the prototype chain of an + object that has no static lookup table and uses eagerly reified custom getter/setter properties. + +2014-06-21 Brady Eidson <beidson@apple.com> + + Gamepad API - Deprecate the existing implementation + https://bugs.webkit.org/show_bug.cgi?id=134108 + + Reviewed by Timothy Hatcher. + + -Add new "GAMEPAD_DEPRECATED" build flag, moving the existing implementation to use it + -Move some implementation files into a "deprecated" subdirectory. + + * Configurations/FeatureDefines.xcconfig: + +2014-06-21 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r170244. + https://bugs.webkit.org/show_bug.cgi?id=134157 + + GTK/EFL bindings generator works differently, making this + patch not work there. Will fix entire patch after a rollout. + (Requested by bradee-oh on #webkit). + + Reverted changeset: + + "Gamepad API - Deprecate the existing implementation" + https://bugs.webkit.org/show_bug.cgi?id=134108 + http://trac.webkit.org/changeset/170244 + +2014-06-21 Brady Eidson <beidson@apple.com> + + Gamepad API - Deprecate the existing implementation + https://bugs.webkit.org/show_bug.cgi?id=134108 + + Reviewed by Timothy Hatcher. + + -Add new "GAMEPAD_DEPRECATED" build flag, moving the existing implementation to use it + -Add the "Deprecated" suffix to some implementation files + + * Configurations/FeatureDefines.xcconfig: + +2014-06-21 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + Removing PAGE_VISIBILITY_API compile guard. + https://bugs.webkit.org/show_bug.cgi?id=133844 + + Reviewed by Gavin Barraclough. + + * Configurations/FeatureDefines.xcconfig: + +2014-06-21 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + ARM traditional buildfix after r169942. + https://bugs.webkit.org/show_bug.cgi?id=134100 + + Reviewed by Zoltan Herczeg. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::abortWithReason): Added. + +2014-06-20 Andreas Kling <akling@apple.com> + + [Cocoa] Release freed up blocks from the JS heap after simulated memory pressure. + <https://webkit.org/b/134112> + + Reviewed by Mark Hahnenberg. + + * heap/BlockAllocator.h: + +2014-06-19 Alex Christensen <achristensen@webkit.org> + + Unreviewed fix after r170130. + + * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj: + Corrected directory so it can find common.props when opening Visual Studio. + +2014-06-19 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Remove ENABLE(LLINT) and ENABLE(LLINT_C_LOOP) guards + https://bugs.webkit.org/show_bug.cgi?id=130389 + + Reviewed by Mark Lam. + + Removed ENABLE(LLINT) since we always build with it, and changed ENABLE(LLINT_C_LOOP) + into !ENABLE(JIT) since they are mutually exclusive. + + * CMakeLists.txt: + * assembler/MacroAssemblerCodeRef.h: + (JSC::MacroAssemblerCodePtr::createLLIntCodePtr): + (JSC::MacroAssemblerCodeRef::createLLIntCodeRef): + * assembler/MaxFrameExtentForSlowPathCall.h: + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFromLLInt): + * bytecode/CodeBlock.cpp: + (JSC::dumpStructure): + (JSC::CodeBlock::printGetByIdCacheStatus): + (JSC::CodeBlock::printCallOp): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::~CodeBlock): + (JSC::CodeBlock::propagateTransitions): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::unlinkCalls): + (JSC::CodeBlock::unlinkIncomingCalls): + (JSC::CodeBlock::linkIncomingCall): + (JSC::CodeBlock::frameRegisterCount): + * bytecode/CodeBlock.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitConstruct): + * heap/Heap.cpp: + (JSC::Heap::gatherJSStackRoots): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::initialize): + (JSC::Interpreter::isOpcode): + * interpreter/Interpreter.h: + (JSC::Interpreter::getOpcodeID): + * interpreter/JSStack.cpp: + (JSC::JSStack::JSStack): + (JSC::JSStack::committedByteCount): + * interpreter/JSStack.h: + * interpreter/JSStackInlines.h: + (JSC::JSStack::ensureCapacityFor): + (JSC::JSStack::topOfFrameFor): + (JSC::JSStack::setStackLimit): + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): + * jit/JIT.h: + (JSC::JIT::compileCTINativeCall): + * jit/JITExceptions.h: + * jit/JITThunks.cpp: + (JSC::JITThunks::ctiNativeCall): + (JSC::JITThunks::ctiNativeConstruct): + * llint/LLIntCLoop.cpp: + * llint/LLIntCLoop.h: + * llint/LLIntData.cpp: + (JSC::LLInt::initialize): + (JSC::LLInt::Data::performAssertions): + * llint/LLIntData.h: + (JSC::LLInt::Data::performAssertions): Deleted. + * llint/LLIntEntrypoint.cpp: + * llint/LLIntEntrypoint.h: + * llint/LLIntExceptions.cpp: + * llint/LLIntExceptions.h: + * llint/LLIntOfflineAsmConfig.h: + * llint/LLIntOffsetsExtractor.cpp: + (JSC::LLIntOffsetsExtractor::dummy): + * llint/LLIntOpcode.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LLIntThunks.cpp: + * llint/LLIntThunks.h: + * llint/LowLevelInterpreter.cpp: + * llint/LowLevelInterpreter.h: + * runtime/CommonSlowPaths.cpp: + * runtime/CommonSlowPaths.h: + * runtime/ErrorHandlingScope.cpp: + (JSC::ErrorHandlingScope::ErrorHandlingScope): + (JSC::ErrorHandlingScope::~ErrorHandlingScope): + * runtime/Executable.cpp: + (JSC::setupLLInt): + * runtime/InitializeThreading.cpp: + (JSC::initializeThreading): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::sanitizeStackForVM): + * runtime/VM.h: + (JSC::VM::canUseJIT): Deleted. + +2014-06-18 Alex Christensen <achristensen@webkit.org> + + Add FTL to Windows build. + https://bugs.webkit.org/show_bug.cgi?id=134015 + + Reviewed by Filip Pizlo. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + Added ftl source files. + * JavaScriptCore.vcxproj/JavaScriptCoreCommon.props: + Added ftl and llvm directories to include path. + * JavaScriptCore.vcxproj/libllvmForJSC: Added. + * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.props: Added. + * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj: Added. + * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj.filters: Added. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): + MSVC doesn't like to divide by zero while compiling. Use std::nan instead. + * llvm/InitializeLLVMWin.cpp: Added. + (JSC::initializeLLVMImpl): + Implemented dynamic loading and linking for Windows. + +2014-06-18 Alex Christensen <achristensen@webkit.org> + + Unreviewed build fix after r170107. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithMod): + Use non-template sub for armv7s. + +2014-06-18 David Kilzer <ddkilzer@apple.com> + + -[JSContext setName:] leaks NSString + <http://webkit.org/b/134038> + + Reviewed by Joseph Pecoraro. + + Fixes the following static analyzer warning: + + JavaScriptCore/API/JSContext.mm:200:73: warning: Potential leak of an object + JSStringRef nameJS = name ? JSStringCreateWithCFString((CFStringRef)[name copy]) : nullptr; + ^ + + * API/JSContext.mm: + (-[JSContext setName:]): Autorelease the copy of |name|. + +2014-06-18 Mark Lam <mark.lam@apple.com> + + DFGGraph::m_doubleConstantMap will not map 0 values correctly. + <https://webkit.org/b/133994> + + Reviewed by Geoffrey Garen. + + DFGGraph::m_doubleConstantsMap should not use a double as a key to its HashMap, + because it means two unfortunate things: + - It will probably break for zero. + - It will think that -0 is the same as +0 under some circumstances, size + -0==+0 even though they are distinct values (for example 1/-0 != 1/+0). + + The fix is to use std::unordered_map which does not require special empty + and deleted values, and to use the raw bits instead of the double value as + the key. + + * dfg/DFGGraph.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::addressOfDoubleConstant): + +2014-06-18 Alex Christensen <achristensen@webkit.org> + + Remove duplicate code using sdiv. + https://bugs.webkit.org/show_bug.cgi?id=133764 + + Reviewed by Daniel Bates. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::sdiv): + Make sdiv a template to match arm64. + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithDiv): + (JSC::DFG::SpeculativeJIT::compileArithMod): + Remove duplicate code that was identical except for sdiv not being a template. + +2014-06-17 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r170082. + https://bugs.webkit.org/show_bug.cgi?id=134006 + + Breaks build. (Requested by mlam on #webkit). + + Reverted changeset: + + "DFGGraph::m_doubleConstantMap will not map 0 values + correctly." + https://bugs.webkit.org/show_bug.cgi?id=133994 + http://trac.webkit.org/changeset/170082 + +2014-06-17 Mark Lam <mark.lam@apple.com> + + DFGGraph::m_doubleConstantMap will not map 0 values correctly. + <https://webkit.org/b/133994> + + Reviewed by Geoffrey Garen. + + DFGGraph::m_doubleConstantsMap should not use a double as a key to its HashMap, + because it means two unfortunate things: + - It will probably break for zero. + - It will think that -0 is the same as +0 under some circumstances, size + -0==+0 even though they are distinct values (for example 1/-0 != 1/+0). + + The fix is to use std::unordered_map which does not require special empty + and deleted values, and to use the raw bits instead of the double value as + the key. + + * dfg/DFGGraph.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::addressOfDoubleConstant): + +2014-06-17 Oliver Hunt <oliver@apple.com> + + Fix error messages for incorrect hex literals + https://bugs.webkit.org/show_bug.cgi?id=133998 + + Reviewed by Mark Lam. + + Ensure that the error messages for bogus hex literals actually + make sense. + + * parser/Lexer.cpp: + (JSC::Lexer<T>::lex): + * parser/ParserTokens.h: + +2014-06-17 Matthew Mirman <mmirman@apple.com> + + Fixes bug where building JSC sometimes crashes at build-symbol-table-index.py. Also adds licenses. + https://bugs.webkit.org/show_bug.cgi?id=133814 + + Reviewed by Filip Pizlo. + + Adds the "shopt -s nullglob" line necessary to prevent the loop in the shell + script from using "*.o" as a file when no other files in the directory exist. + + * build-symbol-table-index.sh: Added license. + * copy-llvm-ir-to-derived-sources.sh: Added license and "shopt -s nullglob" line. + +2014-06-16 Sam Weinig <sam@webkit.org> + + Move forward declaration of bindings static functions into their implementation files + https://bugs.webkit.org/show_bug.cgi?id=133943 + + Reviewed by Geoffrey Garen. + + * runtime/CommonIdentifiers.h: + Add a few identifiers that are needed by the DOM. + +2014-06-16 Mark Lam <mark.lam@apple.com> + + Parser statementDepth accounting needs to account for when a function body excludes its braces. + <https://webkit.org/b/133832> + + Reviewed by Oliver Hunt. + + In some cases (e.g. when a Function object is instantiated from a string), the + function body source may not include its braces. The parser needs to account + for this when calculating its statementDepth. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::codeBlockFor): + * bytecode/UnlinkedCodeBlock.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseStatement): + - Also fixed the error message for declaring nested functions in strict mode + to be more accurate. + * parser/Parser.h: + (JSC::Parser<LexerType>::parse): + (JSC::parse): + * runtime/Executable.cpp: + (JSC::ScriptExecutable::newCodeBlockFor): + +2014-06-16 Juergen Ributzka <juergen@apple.com> + + Change the order of the alias analysis passes to align with the opt pipeline of LLVM + https://bugs.webkit.org/show_bug.cgi?id=133753 + + Reviewed by Geoffrey Garen. + + The order in which the alias analysis passes are added affects also the + order in which they are utilized. Change the order to align with the + one use by LLVM itself. The last alias analysis pass added will be + evaluated first. With this change we first perform a basic alias + analysis and then use the type-based alias analysis (if required). + + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): + +2014-06-16 Juergen Ributzka <juergen@apple.com> + + Fix the arguments passed to the LLVM dylib + https://bugs.webkit.org/show_bug.cgi?id=133757 + + Reviewed by Geoffrey Garen. + + The LLVM command line argument parser assumes that the first argument + is the program name. We need to add a fake program name, otherwise the + first argument will be parsed as program name and ignored. + + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-06-16 Michael Saboff <msaboff@apple.com> + + Convert ASSERT in inlineFunctionForCapabilityLevel to early return + https://bugs.webkit.org/show_bug.cgi?id=133903 + + Reviewed by Mark Hahnenberg. + + Hardened code by Converting ASSERT to return CannotCompile. + + * dfg/DFGCapabilities.h: + (JSC::DFG::inlineFunctionForCapabilityLevel): + +2014-06-13 Sam Weinig <sam@webkit.org> + + Store DOM constants directly in the JS object rather than jumping through a custom accessor + https://bugs.webkit.org/show_bug.cgi?id=133898 + + Reviewed by Oliver Hunt. + + * runtime/Lookup.h: + (JSC::HashTableValue::attributes): + Switch attributes to be stored as an unsigned rather than an unsigned char, since there is no difference in memory use + and will make adding more flags possibles. + + (JSC::HashTableValue::propertyGetter): + (JSC::HashTableValue::propertyPutter): + Change assertion to use BuiltinOrFunctionOrConstant. + + (JSC::HashTableValue::constantInteger): + Added. + + (JSC::getStaticPropertySlot): + (JSC::getStaticValueSlot): + Use PropertySlot::setValue() for constants during static lookup. + + (JSC::reifyStaticProperties): + Put the constant directly on the object when eagerly reifying. + + * runtime/PropertySlot.h: + Add ConstantInteger flag and BuiltinOrFunctionOrConstant helper. + +2014-06-14 Michael Saboff <msaboff@apple.com> + + operationCreateArguments could cause a GC during OSR exit + https://bugs.webkit.org/show_bug.cgi?id=133905 + + Reviewed by Filip Pizlo. + + Defer GC via new wrapper functions for operationCreateArguments and operationCreateInlinedArguments + for use by OSR exit stubs. + + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * jit/JITOperations.cpp: + * jit/JITOperations.h: + +2014-06-13 Mark Hahnenberg <mhahnenberg@apple.com> + + OSR exit should barrier the Executables for all InlineCallFrames, not just those on the stack at the time of exit + https://bugs.webkit.org/show_bug.cgi?id=133880 + + Reviewed by Filip Pizlo. + + We could have exited due to a value received from an inlined block that's no longer on + the stack, so we should just barrier all InlineCallFrames. + + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::adjustAndJumpToTarget): + +2014-06-13 Alex Christensen <achristensen@webkit.org> + + Make css jit compile for armv7. + https://bugs.webkit.org/show_bug.cgi?id=133596 + + Reviewed by Benjamin Poulain. + + * assembler/MacroAssembler.h: + Use branchPtr on ARM_THUMB2. + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::addPtrNoFlags): + (JSC::MacroAssemblerARMv7::or32): + (JSC::MacroAssemblerARMv7::test32): + (JSC::MacroAssemblerARMv7::branch): + (JSC::MacroAssemblerARMv7::branchPtr): + Added macros necessary for css jit. + +2014-06-13 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix ARMv7. + + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::abortWithReason): + +2014-06-12 Filip Pizlo <fpizlo@apple.com> + + Even better diagnostics from DFG traps + https://bugs.webkit.org/show_bug.cgi?id=133836 + + Reviewed by Oliver Hunt. + + We now stuff the DFG::NodeType into a register before bailing. Also made the + DFGBailed abort reason a bit more specific. As planned, the new abort reasons use + different numbers than any previous abort reasons. + + * assembler/AbortReason.h: + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::abortWithReason): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::abortWithReason): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::abortWithReason): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::abortWithReason): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::SpeculativeJIT): + (JSC::DFG::SpeculativeJIT::bail): + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + * dfg/DFGSpeculativeJIT.h: + +2014-06-12 Simon Fraser <simon.fraser@apple.com> + + Fix assertions under JSC::setNeverInline() when running js tests in WebKitTestRunner + https://bugs.webkit.org/show_bug.cgi?id=133840 + + Reviewed by Filip Pizlo. + + Fix ASSERT(exec->vm().currentThreadIsHoldingAPILock()); under JSC::setNeverInline() + when running DFG tests. + + * API/JSCTestRunnerUtils.cpp: + (JSC::numberOfDFGCompiles): + (JSC::setNeverInline): + +2014-06-12 Brent Fulgham <bfulgham@apple.com> + + [Win] Avoid fork bomb during build + https://bugs.webkit.org/show_bug.cgi?id=133837 + <rdar://problem/17296034> + + Reviewed by Tim Horton. + + * JavaScriptCore.vcxproj/build-generated-files.sh: Use a + reasonable default value when the 'num-cpus' script is not available. + +2014-06-12 Mark Lam <mark.lam@apple.com> + + Remove some dead / unused code. + <https://webkit.org/b/133828> + + Reviewed by Filip Pizlo. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::create): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::makeFunction): + * parser/Parser.h: + (JSC::DepthManager::DepthManager): Deleted. + (JSC::DepthManager::~DepthManager): Deleted. + * runtime/CodeCache.cpp: + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + +2014-06-12 Mark Hahnenberg <mhahnenberg@apple.com> + + Move structureHasRareData out of TypeInfo + https://bugs.webkit.org/show_bug.cgi?id=133800 + + Reviewed by Andreas Kling. + + StructureHasRareData was originally put in TypeInfo to avoid making Structure bigger, + but we have a few spare bits in Structure so it would be nice to remove this hack. + + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::newImpurePropertyFiresWatchpoints): + (JSC::TypeInfo::structureHasRareData): Deleted. + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::allocateRareData): + (JSC::Structure::cloneRareDataFrom): + * runtime/Structure.h: + (JSC::Structure::previousID): + (JSC::Structure::objectToStringValue): + (JSC::Structure::setObjectToStringValue): + (JSC::Structure::setPreviousID): + (JSC::Structure::clearPreviousID): + (JSC::Structure::previous): + (JSC::Structure::rareData): + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::enumerationCache): + +2014-06-12 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> + + Allow enum guards to be generated from the replay json files + https://bugs.webkit.org/show_bug.cgi?id=133399 + + Reviewed by Csaba Osztrogonác. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (Type.__init__): + (InputsModel.parse_type_with_framework_name): + (Generator.generate_header): + (Generator.generate_implementation): + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.cpp: Added. + (Test::HandleWheelEvent::HandleWheelEvent): + (Test::HandleWheelEvent::~HandleWheelEvent): + (JSC::InputTraits<Test::HandleWheelEvent>::type): + (JSC::InputTraits<Test::HandleWheelEvent>::encode): + (JSC::InputTraits<Test::HandleWheelEvent>::decode): + (JSC::EncodingTraits<WebCore::PlatformWheelEventPhase>::encodeValue): + (JSC::EncodingTraits<WebCore::PlatformWheelEventPhase>::decodeValue): + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.h: Added. + (JSC::InputTraits<Test::HandleWheelEvent>::queue): + (Test::HandleWheelEvent::platformEvent): + * replay/scripts/tests/generate-enum-with-guard.json: Added. + +2014-06-12 Carlos Garcia Campos <cgarcia@igalia.com> + + Unreviewed. Fix GTK+ build after r169823. + + Include StructureInlines.h in a few more files to fix linking + issues due to JSC::Structure::get undefined symbol. + + * runtime/ArrayIteratorConstructor.cpp: + * runtime/ArrayIteratorPrototype.cpp: + * runtime/JSConsole.cpp: + * runtime/JSMapIterator.cpp: + * runtime/JSSet.cpp: + * runtime/JSSetIterator.cpp: + * runtime/JSWeakMap.cpp: + * runtime/MapIteratorPrototype.cpp: + * runtime/MapPrototype.cpp: + * runtime/SetIteratorPrototype.cpp: + * runtime/SetPrototype.cpp: + * runtime/WeakMapPrototype.cpp: + +2014-06-12 Csaba Osztrogonác <ossy@webkit.org> + + [EFL] One more URTBF after r169823 to make ARM64 build happy too. + + * runtime/JSMap.cpp: + +2014-06-11 Mark Hahnenberg <mhahnenberg@apple.com> + + Inline caching should try to flatten uncacheable dictionaries + https://bugs.webkit.org/show_bug.cgi?id=133683 + + Reviewed by Geoffrey Garen. + + There exists a body of JS code that deletes properties off of objects (especially function/constructor objects), + which puts them into an uncacheable dictionary state. This prevents all future inline caching for these objects. + If properties are deleted out of the object during its initialization, we can enable caching for that object by + attempting to flatten it when we see we're trying to do inline caching with that object. We then record that we + performed this flattening optimization in the object's Structure. If it ever re-enters the uncacheable dictionary + state then we can just give up on caching that object. + + In refactoring some of the code in tryCacheGetById and tryBuildGetByIdList to reduce some duplication, I added + the InlineCacheAction enum, a new way to indicate the success or failure of an inline caching attempt. I changed + the other inline caching functions to return this enum rather than the opaque booleans that we were previously + returning. + + * jit/Repatch.cpp: + (JSC::actionForCell): + (JSC::tryCacheGetByID): + (JSC::repatchGetByID): + (JSC::tryBuildGetByIDList): + (JSC::buildGetByIDList): + (JSC::tryCachePutByID): + (JSC::repatchPutByID): + (JSC::tryBuildPutByIdList): + (JSC::buildPutByIdList): + (JSC::tryRepatchIn): + (JSC::repatchIn): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::flattenDictionaryStructure): + * runtime/Structure.h: + (JSC::Structure::hasBeenFlattenedBefore): + +2014-06-11 Csaba Osztrogonác <ossy@webkit.org> + + [EFL] URTBF after r169823. + + * bindings/ScriptValue.cpp: Missing include added. + +2014-06-11 Ryosuke Niwa <rniwa@webkit.org> + + Remove an unnecessary asObject(this) call inside JSObject::fastGetOwnPropertySlot. + + Rubber-stamped by Andreas Kling. + + * runtime/JSObject.h: + (JSC::JSObject::fastGetOwnPropertySlot): + +2014-06-11 Ryosuke Niwa <rniwa@webkit.org> + + Turning on DUMP_PROPERTYMAP_STATS causes a build failure + https://bugs.webkit.org/show_bug.cgi?id=133673 + + Reviewed by Andreas Kling. + + Rewrote the property map statistics code because the old code wasn't building, + and it was also mixing numbers for lookups and insertions/removals. + + New logging code records the number of calls to PropertyTable::find (finds) and + PropertyTable::get/PropertyTable::findWithString separately so that we can quantify + the number of probing during updates and lookups. + + * jsc.cpp: + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::find): + (JSC::PropertyTable::get): + (JSC::PropertyTable::findWithString): + (JSC::PropertyTable::add): + (JSC::PropertyTable::remove): + (JSC::PropertyTable::reinsert): + (JSC::PropertyTable::rehash): + * runtime/Structure.cpp: + (JSC::PropertyMapStatisticsExitLogger::PropertyMapStatisticsExitLogger): + (JSC::PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger): + +2014-06-11 Andreas Kling <akling@apple.com> + + Always inline JSValue::get() and Structure::get(). + <https://webkit.org/b/133755> + + Reviewed by Ryosuke Niwa. + + These functions get really hot, so ask the compiler to be more + aggressive about inlining them. + + ~28% speed-up on Ryosuke's microbenchmark for accessing nextSibling + through GetByVal. + + * runtime/JSArrayIterator.cpp: + * runtime/JSCJSValue.cpp: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::get): + * runtime/JSPromiseDeferred.cpp: + * runtime/StructureInlines.h: + (JSC::Structure::get): + +2014-06-11 Ryosuke Niwa <rniwa@webkit.org> + + Structure::get should instantiate DeferGC only when materializing property map + https://bugs.webkit.org/show_bug.cgi?id=133727 + + Rubber-stamped by Andreas Kling. + + Make materializePropertyMapIfNecessary always inline. + + This is ~12% improvement on the microbenchmark attached in the bug. + + * runtime/Structure.h: + (JSC::Structure::materializePropertyMapIfNecessary): + (JSC::Structure::materializePropertyMapIfNecessaryForPinning): + +2014-06-11 Ryosuke Niwa <rniwa@webkit.org> + + Structure::get should instantiate DeferGC only when materializing property map + https://bugs.webkit.org/show_bug.cgi?id=133727 + + Reviewed by Geoffrey Garen. + + DeferGC instances in Structure::get was added in http://trac.webkit.org/r157539 in order to avoid + collecting the property table newly created by materializePropertyMapIfNecessary since GC can happen + when GCSafeConcurrentJITLocker goes out of scope. + + However, always instantiating DeferGC inside Structure::get introduced a new performance bottleneck + in JSObject::getPropertySlot because frequently incrementing and decrementing a counter in vm.m_heap + and running a release assertion inside Heap::incrementDeferralDepth() is expensive. + + Work around this by instantiating DeferGC only when we're actually calling materializePropertyMap, + and immediately storing a pointer to the newly created property table in the stack before DeferGC + goes out of scope so that the property table will be marked. + + This shows 13-16% improvement on the microbenchmark attached in the bug. + + * runtime/JSCJSValue.cpp: + * runtime/JSObject.h: + (JSC::JSObject::fastGetOwnPropertySlot): + * runtime/Structure.h: + (JSC::Structure::materializePropertyMapIfNecessary): + * runtime/StructureInlines.h: + (JSC::Structure::get): + +2014-06-11 Andreas Kling <akling@apple.com> + + Some JSValue::get() micro-optimzations. + <https://webkit.org/b/133739> + + Tighten some of the property lookup code to improve performance of the + eagerly reified prototype attributes: + + - Instead of converting the property name to an integer at every step + in the prototype chain, move that to a separate pass at the end + since it should be a rare case. + + - Cache the StructureIDTable in a local instead of fetching it from + the Heap on every step. + + - Make fillCustomGetterPropertySlot inline. It was out-of-lined based + on the assumption that clients would mostly be cacheable GetByIds, + and it gets pretty hot (~1%) in GetByVal. + + - Pass the Structure directly to fillCustomGetterPropertySlot instead + of refetching it from the StructureIDTable. + + Reviewed by Geoff Garen. + + * runtime/JSObject.cpp: + (JSC::JSObject::fillCustomGetterPropertySlot): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::inlineGetOwnPropertySlot): + (JSC::JSObject::fillCustomGetterPropertySlot): + (JSC::JSObject::getOwnPropertySlot): + (JSC::JSObject::fastGetOwnPropertySlot): + (JSC::JSObject::getPropertySlot): + (JSC::JSObject::getOwnPropertySlotSlow): Deleted. + +2014-06-10 Sam Weinig <sam@webkit.org> + + Don't create a HashTable for JSObjects that use eager reification + https://bugs.webkit.org/show_bug.cgi?id=133705 + + Reviewed by Geoffrey Garen. + + * runtime/Lookup.h: + (JSC::reifyStaticProperties): + Add a version of reifyStaticProperties that takes an array of HashTableValues + rather than a HashTable. + +2014-06-10 Filip Pizlo <fpizlo@apple.com> + + Prediction propagator should make sure everyone knows that a variable that is in an argument position where other versions of that variable are not MachineInts cannot possibly be flushed as Int52 + https://bugs.webkit.org/show_bug.cgi?id=133698 + + Reviewed by Geoffrey Garen and Mark Hahnenberg. + + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): Use the new utility to figure out if a variable could ever represent an Int52. + * dfg/DFGVariableAccessData.cpp: + (JSC::DFG::VariableAccessData::couldRepresentInt52): Add a new utility to detect early on if a variable could possibly be Int52. + (JSC::DFG::VariableAccessData::couldRepresentInt52Impl): + (JSC::DFG::VariableAccessData::flushFormat): + * dfg/DFGVariableAccessData.h: + * tests/stress/int52-inlined-call-argument.js: Added. + (foo): + (bar): + +2014-06-10 Mark Lam <mark.lam@apple.com> + + Assertion failure at JSC::Structure::checkOffsetConsistency() const + 234. + <https://webkit.org/b/133356> + + Reviewed by Mark Hahnenberg. + + The root cause of this issue is that a nonPropertyTransition can transition + a pinned dictionary structure to an unpinned dictionary structure. The new + structure will get a copy of the property table from the original structure. + However, when a GC occurs, the property table in the new structure will be + cleared because it is unpinned. This leads to complications in subsequent + derivative structures when flattening occurs, which eventually leads to the + assertion failure in this bug. + + The fix is to ensure that the new dictionary structure generated by the + nonPropertyTransition will have a copy of its predecessor's property table + and is pinned. + + * runtime/Structure.cpp: + (JSC::Structure::nonPropertyTransition): + +2014-06-10 Michael Saboff <msaboff@apple.com> + + In a certain app state, Array.prototype.filter() returns incorrect results + https://bugs.webkit.org/show_bug.cgi?id=133577 + + Reviewed by Oliver Hunt. + + Fixed the LLInt processing of op_put_by_val_direct to have the same hole check as op_put_by_val. + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-06-09 Mark Hahnenberg <mhahnenberg@apple.com> + + Global HashTables contain references to atomic StringImpls + https://bugs.webkit.org/show_bug.cgi?id=133661 + + Reviewed by Geoffrey Garen. + + This was a long-standing bug revealed by bug 133558. The issue is that the global static HashTables + cache their set of keys as StringImpls that are associated with a particular VM. This is obviously + incompatible with using multiple VMs on multiple threads (e.g. when using workers). The fix is to + change the "keys" field of the static HashTables to be char** instead of StringImpl**. + + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + * runtime/Lookup.cpp: + (JSC::HashTable::createTable): + (JSC::HashTable::deleteTable): + * runtime/Lookup.h: + (JSC::HashTable::ConstIterator::key): + (JSC::HashTable::entry): + +2014-06-09 Mark Hahnenberg <mhahnenberg@apple.com> + + Build fix after r169703 + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-06-05 Mark Hahnenberg <mhahnenberg@apple.com> + + Eagerly reify DOM prototype attributes + https://bugs.webkit.org/show_bug.cgi?id=133558 + + Reviewed by Oliver Hunt. + + This allows us to get rid of a lot of the additional overhead of pushing DOM attributes up into the prototype. + By eagerly reifying the custom getters and setters into the actual JSObject we avoid having to override + getOwnPropertySlot for all of the DOM prototypes, which is a lot of the overhead of doing property lookups on + DOM wrappers. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LowLevelInterpreter.asm: + * runtime/BatchedTransitionOptimizer.h: + (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): + * runtime/CustomGetterSetter.cpp: Added. + (JSC::callCustomSetter): + * runtime/CustomGetterSetter.h: Added. + (JSC::CustomGetterSetter::create): + (JSC::CustomGetterSetter::getter): + (JSC::CustomGetterSetter::setter): + (JSC::CustomGetterSetter::createStructure): + (JSC::CustomGetterSetter::CustomGetterSetter): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitive): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::isCustomGetterSetter): + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::isCustomGetterSetter): + (JSC::JSCell::canUseFastGetOwnProperty): + * runtime/JSFunction.cpp: + (JSC::JSFunction::isHostOrBuiltinFunction): Deleted. + (JSC::JSFunction::isBuiltinFunction): Deleted. + * runtime/JSFunction.h: + * runtime/JSFunctionInlines.h: Inlined some random functions that appeared hot during profiling. + (JSC::JSFunction::isBuiltinFunction): + (JSC::JSFunction::isHostOrBuiltinFunction): + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::putDirectCustomAccessor): + (JSC::JSObject::fillGetterPropertySlot): + (JSC::JSObject::fillCustomGetterPropertySlot): + (JSC::JSObject::getOwnPropertySlotSlow): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::hasCustomGetterSetterProperties): + (JSC::JSObject::convertToDictionary): + (JSC::JSObject::inlineGetOwnPropertySlot): + (JSC::JSObject::getOwnPropertySlotSlow): Inlined because it looked hot during profiling. + (JSC::JSObject::putOwnDataProperty): + (JSC::JSObject::putDirect): + (JSC::JSObject::putDirectWithoutTransition): + * runtime/JSType.h: + * runtime/Lookup.h: + (JSC::reifyStaticProperties): + * runtime/PropertyDescriptor.h: + (JSC::PropertyDescriptor::PropertyDescriptor): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::nextOutOfLineStorageCapacity): Deleted. + (JSC::Structure::suggestedNewOutOfLineStorageCapacity): Deleted. + (JSC::Structure::get): Deleted. + * runtime/Structure.h: + (JSC::Structure::hasCustomGetterSetterProperties): + (JSC::Structure::setHasCustomGetterSetterProperties): + * runtime/StructureInlines.h: + (JSC::Structure::get): Inlined due to hotness. + (JSC::nextOutOfLineStorageCapacity): Inlined due to hotness. + (JSC::Structure::suggestedNewOutOfLineStorageCapacity): Inlined due to hotness. + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + * runtime/WriteBarrier.h: + (JSC::WriteBarrierBase<Unknown>::isCustomGetterSetter): + +2014-06-07 Mark Lam <mark.lam@apple.com> + + Structure should initialize its previousID in its constructor. + <https://webkit.org/b/133606> + + Reviewed by Mark Hahnenberg. + + Currently, the Structure constructor that takes a previous structure will + initialize its previousID to point to the previous structure's previousID. + This is incorrect. However, the caller of the Structure::create() factory + method (which instantiated the Structure) will later call setPreviousID() + to set the previousID to the correct previous structure. This makes the + code confusing to read and more error prone in that the structure relies + on client code to fix its invalid previousID. + + This patch fixes this by making the Structure constructor initialize + previousID correctly. + + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::nonPropertyTransition): + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::create): + +2014-06-06 Andreas Kling <akling@apple.com> + + Indexed getters should return values directly on the PropertySlot. + <https://webkit.org/b/133586> + + Remove PropertySlot's custom index mode. + + Reviewed by Darin Adler. + + * runtime/JSObject.h: + (JSC::PropertySlot::getValue): + * runtime/PropertySlot.h: + (JSC::PropertySlot::setCustomIndex): Deleted. + +2014-06-04 Timothy Horton <timothy_horton@apple.com> + + iOS Debug build fix + + Rubber-stamped by Filip Pizlo. + + * Configurations/LLVMForJSC.xcconfig: + Dead-code strip the llvmForJSC library unconditionally, to work around <rdar://problem/16920916>. + +2014-06-04 Oliver Hunt <oliver@apple.com> + + ArrayIterator should not be exposed in Safari 8 + https://bugs.webkit.org/show_bug.cgi?id=133494 + + Reviewed by Michael Saboff. + + Separate out types that require constructor objects, and don't + include the iterator types in that list. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObject.h: + +2014-06-04 Filip Pizlo <fpizlo@apple.com> + + DFG::Safepoint::begin() should set m_didCallBegin before releasing the rightToRun lock, because otherwise, Safepoint::checkLivenessAndVisitChildren() may assert due to a race + https://bugs.webkit.org/show_bug.cgi?id=133525 + <rdar://problem/16790296> + + Reviewed by Oliver Hunt. + + * dfg/DFGSafepoint.cpp: + (JSC::DFG::Safepoint::begin): + +2014-06-03 Filip Pizlo <fpizlo@apple.com> + + LLVM soft-linking should be truly fail-silent + https://bugs.webkit.org/show_bug.cgi?id=133482 + + Reviewed by Mark Lam. + + * llvm/InitializeLLVMPOSIX.cpp: + (JSC::initializeLLVMPOSIX): Missing return statement in the dlsym() returning null case. + +2014-06-03 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + REGRESSION(r169092 and r169102): Skip failing JSC tests poperly on non-x86 Darwin platforms + https://bugs.webkit.org/show_bug.cgi?id=133149 + + Reviewed by Csaba Osztrogonác. + + * tests/mozilla/mozilla-tests.yaml: Skip js1_5/Regress/regress-159334.js only if the architecture isn't x86 and the host is Darwin. + +2014-05-31 Anders Carlsson <andersca@apple.com> + + Add a LazyNeverDestroyed class template and use it + https://bugs.webkit.org/show_bug.cgi?id=133425 + + Reviewed by Darin Adler. + + * dfg/DFGFunctionWhitelist.cpp: + (JSC::DFG::FunctionWhitelist::ensureGlobalWhitelist): + * dfg/DFGFunctionWhitelist.h: + +2014-05-28 Filip Pizlo <fpizlo@apple.com> + + DFG::DCEPhase inserts into an insertion set in reverse, causing hilarious basic block corruption if you kill a lot of NewArrays + https://bugs.webkit.org/show_bug.cgi?id=133368 + + Reviewed by Mark Lam. + + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::fixupBlock): Loop in the right order so that we insert in the right order. + * tests/stress/new-array-dead.js: Added. + (foo): + +2014-05-28 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix not-x86 32-bit. + + * llint/LowLevelInterpreter32_64.asm: + +2014-05-27 Filip Pizlo <fpizlo@apple.com> + + Arrayify neglects to inform the clobberizer that it might fire watchpoints + https://bugs.webkit.org/show_bug.cgi?id=133340 + + Reviewed by Mark Lam. + + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): Be honest. + * llint/LowLevelInterpreter32_64.asm: Profile the object, not its structure. + * tests/stress/arrayify-fires-watchpoint.js: Added. + (foo): + (test): + (makeObjectArray): + * tests/stress/arrayify-structure-bad-test.js: Added. + (foo): + (test): + +2014-05-27 Jon Lee <jonlee@apple.com> + + Update ENABLE(MEDIA_SOURCE) on Mac + https://bugs.webkit.org/show_bug.cgi?id=133141 + + Reviewed by Darin Adler. + + * Configurations/FeatureDefines.xcconfig: + +2014-05-27 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Remove BLOB guards + https://bugs.webkit.org/show_bug.cgi?id=132863 + + Reviewed by Csaba Osztrogonác. + + * Configurations/FeatureDefines.xcconfig: + +2014-05-27 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> + + Allow building CMake based ports with WEB_REPLAY + https://bugs.webkit.org/show_bug.cgi?id=133154 + + Reviewed by Csaba Osztrogonác. + + * CMakeLists.txt: + +2014-05-25 Filip Pizlo <fpizlo@apple.com> + + Latest emscripten life benchmark is 4x slower because the DFG doesn't realize that arithmetic on booleans is a thing + https://bugs.webkit.org/show_bug.cgi?id=133136 + + Reviewed by Oliver Hunt. + + Some key concepts: + + - Except for the prediction propagation and type fixup phases, which are super early in + the pipeline, nobody has to know about the fact that booleans may flow into numerical + operations because there will just be a BooleanToNumber node that will take a value + and, if that value is a boolean, will convert it to the equivalent numerical value. It + will have a BooleanUse mode where it will also speculate that the input is a boolean + but it can also do UntypedUse in which case it will pass through any non-booleans. + This operation is very easy to model in all of the compiler tiers. + + - No changes to the baseline JIT. The Baseline JIT will still believe that boolean + inputs require taking the slow path and it will still report that it took slow path + for any such operations. The DFG will now be smart enough to ignore baseline JIT slow + path profiling on operations that were known to have had boolean inputs. That's a + little quirky, but it's probably easier than modifying the baseline JIT to track + booleans correctly. + + 4.1x speed-up on the emscripten "life" benchmark. Up to 10x speed-up on microbenchmarks. + + * bytecode/SpeculatedType.h: + (JSC::isInt32OrBooleanSpeculation): + (JSC::isInt32SpeculationForArithmetic): + (JSC::isInt32OrBooleanSpeculationForArithmetic): + (JSC::isInt32OrBooleanSpeculationExpectingDefined): + (JSC::isInt52Speculation): + (JSC::isMachineIntSpeculation): + (JSC::isFullNumberOrBooleanSpeculation): + (JSC::isFullNumberOrBooleanSpeculationExpectingDefined): + (JSC::isInt32SpeculationExpectingDefined): Deleted. + (JSC::isMachineIntSpeculationExpectingDefined): Deleted. + (JSC::isMachineIntSpeculationForArithmetic): Deleted. + (JSC::isBytecodeNumberSpeculationExpectingDefined): Deleted. + (JSC::isFullNumberSpeculationExpectingDefined): Deleted. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAllocator.h: + (JSC::DFG::Allocator<T>::indexOf): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::makeSafe): + (JSC::DFG::ByteCodeParser::makeDivSafe): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixIntConvertingEdge): + (JSC::DFG::FixupPhase::fixIntOrBooleanEdge): + (JSC::DFG::FixupPhase::fixDoubleOrBooleanEdge): + (JSC::DFG::FixupPhase::attemptToMakeIntegerAdd): + (JSC::DFG::FixupPhase::fixIntEdge): Deleted. + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addSpeculationMode): + (JSC::DFG::Graph::valueAddSpeculationMode): + (JSC::DFG::Graph::arithAddSpeculationMode): + (JSC::DFG::Graph::addShouldSpeculateInt32): + (JSC::DFG::Graph::mulShouldSpeculateInt32): + (JSC::DFG::Graph::mulShouldSpeculateMachineInt): + (JSC::DFG::Graph::negateShouldSpeculateInt32): + (JSC::DFG::Graph::negateShouldSpeculateMachineInt): + (JSC::DFG::Graph::addImmediateShouldSpeculateInt32): + (JSC::DFG::Graph::mulImmediateShouldSpeculateInt32): Deleted. + * dfg/DFGNode.h: + (JSC::DFG::Node::sawBooleans): + (JSC::DFG::Node::shouldSpeculateInt32OrBoolean): + (JSC::DFG::Node::shouldSpeculateInt32ForArithmetic): + (JSC::DFG::Node::shouldSpeculateInt32OrBooleanForArithmetic): + (JSC::DFG::Node::shouldSpeculateInt32OrBooleanExpectingDefined): + (JSC::DFG::Node::shouldSpeculateMachineInt): + (JSC::DFG::Node::shouldSpeculateDouble): + (JSC::DFG::Node::shouldSpeculateNumberOrBoolean): + (JSC::DFG::Node::shouldSpeculateNumberOrBooleanExpectingDefined): + (JSC::DFG::Node::shouldSpeculateNumber): + (JSC::DFG::Node::canSpeculateInt32): + (JSC::DFG::Node::canSpeculateInt52): + (JSC::DFG::Node::sourceFor): + (JSC::DFG::Node::shouldSpeculateInt32ExpectingDefined): Deleted. + (JSC::DFG::Node::shouldSpeculateMachineIntForArithmetic): Deleted. + (JSC::DFG::Node::shouldSpeculateMachineIntExpectingDefined): Deleted. + (JSC::DFG::Node::shouldSpeculateDoubleForArithmetic): Deleted. + (JSC::DFG::Node::shouldSpeculateNumberExpectingDefined): Deleted. + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + (JSC::DFG::nodeMayOverflow): + (JSC::DFG::nodeMayNegZero): + (JSC::DFG::nodeCanSpeculateInt32): + (JSC::DFG::nodeCanSpeculateInt52): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::run): + (JSC::DFG::PredictionPropagationPhase::propagateToFixpoint): + (JSC::DFG::PredictionPropagationPhase::speculatedDoubleTypeForPrediction): + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileValueToInt32): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::asInt32ForArithmetic): + * tests/stress/max-boolean-exit.js: Added. + (foo): + (test): + * tests/stress/mul-boolean-exit.js: Added. + (foo): + (test): + * tests/stress/plus-boolean-exit.js: Added. + (foo): + (test): + * tests/stress/plus-boolean-or-double.js: Added. + (foo): + (test): + * tests/stress/plus-boolean-or-int.js: Added. + (foo): + (test): + +2014-05-26 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> + + Remove dead code from VM.cpp + https://bugs.webkit.org/show_bug.cgi?id=133284 + + Reviewed by Darin Adler. + + This workaround was added in r127505. Since the clang is the + only used compiler in this case, this workaround is obsolete. + + * runtime/VM.cpp: + (JSC::enableAssembler): + +2014-05-26 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + JSC CLoop warning fix + https://bugs.webkit.org/show_bug.cgi?id=133259 + + Reviewed by Darin Adler. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + +2014-05-24 Andreas Kling <akling@apple.com> + + Object.prototype.toString() should use cached strings for null/undefined. + <https://webkit.org/b/133261> + + Normally, when calling Object.prototype.toString() on a regular object, + we'd cache the result of the stringification on the object's structure, + making repeated calls fast. + + For null and undefined, we were not as smart. We'd instead construct a + new string with either "[object Null]" or "[object Undefined]" each time. + + This was exposed by Dromaeo's JS library tests, where some prototype.js + subtests generate millions of strings this way. + + This patch adds two VM-permanent cached strings to the SmallStrings. + Looks like ~10% speed-up on Dromaeo/jslib-traverse-prototype.html + + Reviewed by Darin Adler. + + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncToString): + * runtime/SmallStrings.cpp: + (JSC::SmallStrings::SmallStrings): + (JSC::SmallStrings::initializeCommonStrings): + (JSC::SmallStrings::visitStrongReferences): + * runtime/SmallStrings.h: + (JSC::SmallStrings::nullObjectString): + (JSC::SmallStrings::undefinedObjectString): + +2014-05-23 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove operationCallGetter + + Rubber stamped by Filip Pizlo. + + Nobody calls this function. + + * JavaScriptCore.order: + * jit/JITOperations.cpp: + * jit/JITOperations.h: + +2014-05-23 Andreas Kling <akling@apple.com> + + Templatize GC's destructor invocation for dtor type. + <https://webkit.org/b/133231> + + Get rid of a branch in callDestructor() by templatizing it for + the DestructorType. Removed JSCell::methodTableForDestruction() + since this was the only call site and it was jumping through + a bunch of unnecessary hoops. + + Reviewed by Geoffrey Garen. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::callDestructor): + (JSC::MarkedBlock::specializedSweep): + * heap/MarkedBlock.h: + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::methodTableForDestruction): Deleted. + +2014-05-23 Andreas Kling <akling@apple.com> + + Support inline caching of RegExpMatchesArray.length + <https://webkit.org/b/133234> + + Give RegExpMatchesArray.length the same treatment as JSArray in + repatch so we don't have to go out of line on every access. + + ~13% speed-up on Octane/regexp. + + Reviewed by Geoffrey Garen. + + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + * runtime/RegExpMatchesArray.h: + (JSC::isRegExpMatchesArray): + +2014-05-22 Mark Lam <mark.lam@apple.com> + + REGRESSION(r154797): Debugger crashes when stepping over an uncaught exception. + <https://webkit.org/b/133182> + + Reviewed by Oliver Hunt. + + Before r154797, we used to clear the VM exception before calling into the + debugger. After r154797, we don't. This patch will restore this clearing + of the exception before calling into the debugger. + + Also added assertions after returning from calls into the debugger to + ensure that the debugger did not introduce any exceptions. + + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + (JSC::Interpreter::unwind): + (JSC::Interpreter::debug): + - Fixed the assertion here. Interpreter::debug() should never be called + with a pending exception. Debugger callbacks for exceptions should be + handled by Interpreter::unwind() and Interpreter::unwindCallFrame(). + +2014-05-21 Filip Pizlo <fpizlo@apple.com> + + Store barrier elision should run after DCE in both the DFG path and the FTL path + https://bugs.webkit.org/show_bug.cgi?id=129718 + + Rubber stamped by Mark Hahnenberg. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + +2014-05-21 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> + + [EFL] Add include path of compact_unwind_encoding.h if FTL JIT is enabled + https://bugs.webkit.org/show_bug.cgi?id=132907 + + Reviewed by Gyuyoung Kim. + + * CMakeLists.txt: + +2014-05-16 Martin Robinson <mrobinson@igalia.com> + + [CMake] Improve handling of LIB_INSTALL_DIR, EXEC_INSTALL_DIR, and LIBEXEC_INSTALL_DIR + https://bugs.webkit.org/show_bug.cgi?id=132819 + + Reviewed by Carlos Garcia Campos. + + * javascriptcoregtk.pc.in: Instead of using the special pkg-config variables, + use the common CMake ones directly. + +2014-05-21 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, roll out http://trac.webkit.org/changeset/169159. + + This was a unilateral change and wasn't properly reviewed. + + * tests/mozilla/mozilla-tests.yaml: + +2014-05-21 Antoine Quint <graouts@webkit.org> + + Array.prototype.find and findIndex should skip holes + https://bugs.webkit.org/show_bug.cgi?id=132658 + + Reviewed by Geoffrey Garen. + + Skip holes in the array when iterating such that callback isn't called. + + * builtins/Array.prototype.js: + (find): + (findIndex): + +2014-05-21 Eva Balazsfalvi <evab.u-szeged@partner.samsung.com> + + REGRESSION(r169092 and r169102): Skip failing JSC tests on ARM64 properly + https://bugs.webkit.org/show_bug.cgi?id=133149 + + Reviewed by Csaba Osztrogonác. + + * tests/mozilla/mozilla-tests.yaml: + +2014-05-20 Geoffrey Garen <ggaren@apple.com> + + Rolled out <http://trac.webkit.org/changeset/166184> + https://bugs.webkit.org/show_bug.cgi?id=133144 + + Reviewed by Gavin Barraclough. + + It caused a performance regression. + + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::blockFreeingThreadStartFunc): + +2014-05-20 Filip Pizlo <fpizlo@apple.com> + + DFG prediction propagation should agree with fixup phase over the return type of GetByVal + https://bugs.webkit.org/show_bug.cgi?id=133134 + + Reviewed by Mark Hahnenberg. + + Make prediction propagator use ArrayMode refinement to decide the return type. + + Also introduce a heap prediction intrinsic that allows us to test weird corner cases + like this. The only way we'll see a mismatch like this in the real world is probably + through a gnarly race condition. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGNode.h: + (JSC::DFG::Node::setHeapPrediction): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionFalse1): + (functionFalse2): + (functionUndefined1): + (functionUndefined2): + (functionFalse): Deleted. + (functionOtherFalse): Deleted. + (functionUndefined): Deleted. + * runtime/Intrinsic.h: + * tests/stress/get-by-val-double-predicted-int.js: Added. + (foo): + +2014-05-20 Mark Hahnenberg <mhahnenberg@apple.com> + + Watchdog timer should be lazily allocated + https://bugs.webkit.org/show_bug.cgi?id=133135 + + Reviewed by Geoffrey Garen. + + We incur a noticeable amount of overhead on some benchmarks due to checking if the Watchdog ever fired. + There is no reason to do this checking if we never activated the Watchdog, which can only be done through + JSContextGroupSetExecutionTimeLimit or JSContextGroupClearExecutionTimeLimit. + + By allocating the Watchdog lazily on the VM we can avoid all of the associated overhead when we don't use + these two API functions (which is true of most clients). + + * API/JSContextRef.cpp: + (JSContextGroupSetExecutionTimeLimit): + (JSContextGroupClearExecutionTimeLimit): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_loop_hint): + (JSC::JIT::emitSlow_op_loop_hint): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/VM.h: + * runtime/Watchdog.cpp: + (JSC::Watchdog::Scope::Scope): Deleted. + (JSC::Watchdog::Scope::~Scope): Deleted. + * runtime/Watchdog.h: + (JSC::Watchdog::Scope::Scope): + (JSC::Watchdog::Scope::~Scope): + +2014-05-19 Mark Hahnenberg <mhahnenberg@apple.com> + + JSArray::shiftCountWith* could be more efficient + https://bugs.webkit.org/show_bug.cgi?id=133011 + + Reviewed by Geoffrey Garen. + + Our current implementations of shiftCountWithAnyIndexingType and shiftCountWithArrayStorage + are scared of the presence of any holes in the array. We can mitigate this somewhat by enabling + them to correctly handle holes, thus avoiding the slowest of slow paths in most cases. + + * runtime/ArrayStorage.h: + (JSC::ArrayStorage::indexingHeader): + (JSC::ArrayStorage::length): + (JSC::ArrayStorage::hasHoles): + * runtime/IndexingHeader.h: + (JSC::IndexingHeader::publicLength): + (JSC::IndexingHeader::from): + * runtime/JSArray.cpp: + (JSC::JSArray::shiftCountWithArrayStorage): + (JSC::JSArray::shiftCountWithAnyIndexingType): + (JSC::JSArray::unshiftCountWithArrayStorage): + * runtime/JSArray.h: + (JSC::JSArray::shiftCountForShift): + (JSC::JSArray::shiftCountForSplice): + (JSC::JSArray::shiftCount): + * runtime/Structure.cpp: + (JSC::Structure::holesRequireSpecialBehavior): + * runtime/Structure.h: + +2014-05-19 Filip Pizlo <fpizlo@apple.com> + + Test gardening: skip some failing tests on not-X86. + + * tests/mozilla/mozilla-tests.yaml: + +2014-05-19 Mark Lam <mark.lam@apple.com> + + operationOptimize() should defer the GC for a while. + <https://webkit.org/b/133103> + + Reviewed by Filip Pizlo. + + Currently, operationOptimize() only defers the GC until its end. As a result, + a GC may be triggered just before we return from operationOptimize(), and it may + jettison the optimize codeBlock that we're planning to OSR enter into when we + return from this function. This is because the OSR entry on-ramp code hasn't + been executed yet, and hence, there is not yet a reference to this new codeBlock + from the stack, and there won't be until we've had a chance to return out of + operationOptimize() to run the OSR entry on-ramp code. + + This issue is now fixed by using DeferGCForAWhile instead of DeferGC. This + ensures that the GC will be deferred until after the OSR entry on-ramp can be + executed. + + * jit/JITOperations.cpp: + +2014-05-19 Filip Pizlo <fpizlo@apple.com> + + Take care of some ARM64 test failures + https://bugs.webkit.org/show_bug.cgi?id=133090 + + Reviewed by Geoffrey Garen. + + Constant blinding on ARM64 cannot use the scratch register. + + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::convertInt32ToDouble): + (JSC::MacroAssembler::branchPtr): + (JSC::MacroAssembler::storePtr): + (JSC::MacroAssembler::store64): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::scratchRegisterForBlinding): + +2014-05-19 Tanay C <tanay.c@samsung.com> + + Removing some check-webkit-style warnings from ./dfg + https://bugs.webkit.org/show_bug.cgi?id=132854 + + Reviewed by Darin Adler. + + * dfg/DFGAbstractInterpreter.h: + * dfg/DFGAbstractValue.h: + * dfg/DFGBlockInsertionSet.h: + * dfg/DFGCommonData.h: + * dfg/DFGDominators.h: + * dfg/DFGGraph.h: + * dfg/DFGInPlaceAbstractState.h: + * dfg/DFGPredictionPropagationPhase.h: + +2014-05-18 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, remove bogus comment. We already made the FTL use our calling convention. + That was a long time ago. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileReturn): + +2014-05-18 Rik Cabanier <cabanier@adobe.com> + + support for navigator.hardwareConcurrency + https://bugs.webkit.org/show_bug.cgi?id=132588 + + Reviewed by Filip Pizlo. + + * Configurations/FeatureDefines.xcconfig: + +2014-05-16 Michael Saboff <msaboff@apple.com> + + Crash in JSC::Yarr::YarrGenerator<(JSC::Yarr::YarrJITCompileMode)0>::generatePatternCharacterFixed() due to WTF::CrashOnOverflow::overflowed + 9 + https://bugs.webkit.org/show_bug.cgi?id=133009 + + Reviewed by Oliver Hunt. + + If we determine that any alternative requires a minumum match size greater than + INT_MAX, we handle the match in the interpreter. + + Check to see if the pattern has unsigned lengths before invoking YARR JIT. + * runtime/RegExp.cpp: + (JSC::RegExp::compile): + (JSC::RegExp::compileMatchOnly): + + * tests/stress/large-regexp.js: New test added. + + Set m_containsUnsignedLengthPattern flag if any alternative's minimum length + doesn't fit in an int. + * yarr/YarrPattern.cpp: + (JSC::Yarr::YarrPatternConstructor::setupDisjunctionOffsets): + + Clear new m_containsUnsignedLengthPattern flag. + * yarr/YarrPattern.cpp: + (JSC::Yarr::YarrPattern::YarrPattern): + * yarr/YarrPattern.h: + (JSC::Yarr::YarrPattern::reset): + (JSC::Yarr::YarrPattern::containsUnsignedLengthPattern): + +2014-05-15 Mark Hahnenberg <mhahnenberg@apple.com> + + JSDOMWindow should not claim HasImpureGetOwnPropertySlot + https://bugs.webkit.org/show_bug.cgi?id=132918 + + Reviewed by Geoffrey Garen. + + * jit/Repatch.cpp: + (JSC::tryRepatchIn): We forgot to check for watchpoints when repatching "in". + +2014-05-15 Alex Christensen <achristensen@webkit.org> + + Add pointer lock to features without enabling it. + https://bugs.webkit.org/show_bug.cgi?id=132961 + + Reviewed by Sam Weinig. + + * Configurations/FeatureDefines.xcconfig: + Added ENABLE_POINTER_LOCK to list of features. + +2014-05-14 Mark Hahnenberg <mhahnenberg@apple.com> + + Inline caching for proxies clobbers baseGPR too early + https://bugs.webkit.org/show_bug.cgi?id=132916 + + Reviewed by Filip Pizlo. + + We clobber baseGPR prior to the Structure checks, so if any of the checks fail then the slow path + gets the target of the proxy rather than the proxy itself. We need to delay the clobbering of baseGPR + until we know the inline cache is going to succeed. + + * jit/Repatch.cpp: + (JSC::generateByIdStub): + +2014-05-14 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed build fix. + + * JavaScriptCore.vcxproj/JavaScriptCore.submit.sln: This solution + was missing commands to build LLInt portions of JSC. + * llint/LLIntData.cpp: 64-bit build fix. + +2014-05-14 Martin Hodovan <mhodovan.u-szeged@partner.samsung.com> + + ARM Traditional buildfix after r168776. + https://bugs.webkit.org/show_bug.cgi?id=132903 + + Reviewed by Darin Adler. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::abortWithReason): Added. + +2014-05-14 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Remove CSS_STICKY_POSITION guards + https://bugs.webkit.org/show_bug.cgi?id=132676 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: + +2014-05-13 Filip Pizlo <fpizlo@apple.com> + + JIT breakpoints should be more informative + https://bugs.webkit.org/show_bug.cgi?id=132882 + + Reviewed by Oliver Hunt. + + Introduce the notion of an AbortReason, which is a nice enumeration of coded assertion + failure names. This means that all you need to figure out why the JIT SIGTRAP'd is to look + at that platform's abort reason register (r11 on X86-64 for example). + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/AbortReason.h: Added. + * assembler/AbstractMacroAssembler.h: + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::abortWithReason): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::abortWithReason): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::abortWithReason): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::abortWithReason): + * dfg/DFGSlowPathGenerator.h: + (JSC::DFG::SlowPathGenerator::generate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::bail): + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + (JSC::DFG::SpeculativeJIT::compileMakeRope): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateBasicStorage): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGThunks.cpp: + (JSC::DFG::osrEntryThunkGenerator): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::jitAssertIsInt32): + (JSC::AssemblyHelpers::jitAssertIsJSInt32): + (JSC::AssemblyHelpers::jitAssertIsJSNumber): + (JSC::AssemblyHelpers::jitAssertIsJSDouble): + (JSC::AssemblyHelpers::jitAssertIsCell): + (JSC::AssemblyHelpers::jitAssertTagsInPlace): + (JSC::AssemblyHelpers::jitAssertHasValidCallFrame): + (JSC::AssemblyHelpers::jitAssertIsNull): + (JSC::AssemblyHelpers::jitAssertArgumentCountSane): + (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::checkStackPointerAlignment): + (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): Deleted. + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::emitSlow_op_div): + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_loop_hint): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTINativeCall): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::compileGetDirectOffset): + (JSC::JIT::addStructureTransitionCheck): Deleted. + (JSC::JIT::testPrototype): Deleted. + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::compileGetDirectOffset): + * jit/RegisterPreservationWrapperGenerator.cpp: + (JSC::generateRegisterRestoration): + * jit/Repatch.cpp: + (JSC::addStructureTransitionCheck): + (JSC::linkClosureCall): + * jit/ThunkGenerators.cpp: + (JSC::emitPointerValidation): + (JSC::nativeForGenerator): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::generate): + +2014-05-13 peavo@outlook.com <peavo@outlook.com> + + [Win] Enum type with value zero is compatible with void*, potential cause of crashes. + https://bugs.webkit.org/show_bug.cgi?id=132772 + + Reviewed by Geoffrey Garen. + + Using the MSVC compiler, an instance of an enum type with value zero, is compatible with void* (see bug 132683 for a code example). + This has caused crashes on Windows on two occasions (bug 132683, and bug 121001). + This patch tries to prevent these type of crashes by using a type with explicit constructors instead of void*. + The void* parameter in the loadDouble and storeDouble methods are replaced with TrustedImmPtr. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::loadDouble): + (JSC::MacroAssemblerARM::storeDouble): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::loadDouble): + (JSC::MacroAssemblerARM64::storeDouble): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::loadDouble): + (JSC::MacroAssemblerARMv7::storeDouble): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::loadDouble): + (JSC::MacroAssemblerMIPS::storeDouble): + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::loadDouble): + (JSC::MacroAssemblerSH4::storeDouble): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::storeDouble): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::absDouble): + (JSC::MacroAssemblerX86Common::negateDouble): + (JSC::MacroAssemblerX86Common::loadDouble): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentFill): + (JSC::DFG::compileClampDoubleToByte): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::compile): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::purifyNaN): + * jit/JITInlines.h: + (JSC::JIT::emitLoadDouble): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitFloatTypedArrayGetByVal): + * jit/ThunkGenerators.cpp: + (JSC::floorThunkGenerator): + (JSC::roundThunkGenerator): + (JSC::powThunkGenerator): + +2014-05-12 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r168642. + https://bugs.webkit.org/show_bug.cgi?id=132839 + + Broke ARM build (Requested by jpfau on #webkit). + + Reverted changeset: + + "[Win] Enum type with value zero is compatible with void*, + potential cause of crashes." + https://bugs.webkit.org/show_bug.cgi?id=132772 + http://trac.webkit.org/changeset/168642 + +2014-05-12 peavo@outlook.com <peavo@outlook.com> + + [Win] Enum type with value zero is compatible with void*, potential cause of crashes. + https://bugs.webkit.org/show_bug.cgi?id=132772 + + Reviewed by Geoffrey Garen. + + Using the MSVC compiler, an instance of an enum type with value zero, is compatible with void* (see bug 132683 for a code example). + This has caused crashes on Windows on two occasions (bug 132683, and bug 121001). + This patch tries to prevent these type of crashes by using a type with explicit constructors instead of void*. + The void* parameter in the loadDouble and storeDouble methods are replaced with TrustedImmPtr. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::loadDouble): + (JSC::MacroAssemblerARM::storeDouble): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::loadDouble): + (JSC::MacroAssemblerARM64::storeDouble): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::loadDouble): + (JSC::MacroAssemblerARMv7::storeDouble): + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::loadDouble): + (JSC::MacroAssemblerMIPS::storeDouble): + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::loadDouble): + (JSC::MacroAssemblerSH4::storeDouble): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::storeDouble): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::absDouble): + (JSC::MacroAssemblerX86Common::negateDouble): + (JSC::MacroAssemblerX86Common::loadDouble): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentFill): + (JSC::DFG::compileClampDoubleToByte): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::compile): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::purifyNaN): + * jit/JITInlines.h: + (JSC::JIT::emitLoadDouble): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitFloatTypedArrayGetByVal): + * jit/ThunkGenerators.cpp: + (JSC::floorThunkGenerator): + (JSC::roundThunkGenerator): + (JSC::powThunkGenerator): + +2014-05-12 Andreas Kling <akling@apple.com> + + 0.4% of PLT3 in JSCell::structure() below JSObject::visitChildren(). + <https://webkit.org/b/132828> + <rdar://problem/16886285> + + Reviewed by Michael Saboff. + + * runtime/JSObject.cpp: + (JSC::JSObject::visitButterfly): + (JSC::JSObject::visitChildren): + + Use JSCell::structure(VM&) to reduce the number of hoops we jump + through to find Structures during marking. + +2014-05-12 László Langó <llango.u-szeged@partner.samsung.com> + + [cmake] Add missing FTL source files to the build system. + + Reviewed by Csaba Osztrogonác. + + * CMakeLists.txt: + +2014-05-09 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Allow Remote Inspector to entitlement check UIProcess through WebProcess + https://bugs.webkit.org/show_bug.cgi?id=132409 + + Reviewed by Timothy Hatcher. + + Proxy applications are applications which hold WebViews for other + applications. The WebProcess (Web Content Service) is a proxy application. + For legacy reasons we were supporting a scenario where proxy applications + could potentially host WebViews for more then one other application. That + was never the case for WebProcess and it is now a scenario we don't need + to worry about supporting. + + With this change, a proxy application more naturally only holds WebViews + for a single parent / host application. The proxy process can set the + parent pid / audit_token data on the RemoteInspector singleton, and + that data will be sent on to webinspectord later on to be validated. + In the WebProcess<->UIProcess relationship that information is known + and set immediately. In the Legacy iOS case that information is set + soon after, but not immediately known at the point the WebView is created. + + This allows us to simplify the RemoteInspectorDebuggable interface. + We no longer need a pid per-Debuggable. + + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::RemoteInspector): + (Inspector::RemoteInspector::setParentProcessInformation): + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + (Inspector::RemoteInspector::listingForDebuggable): + (Inspector::RemoteInspector::receivedProxyApplicationSetupMessage): + Handle new proxy application setup message, and provide an API + for a proxy application to set the parent process information. + + * inspector/remote/RemoteInspectorConstants.h: + New setup and response message for proxy applications to pass + their parent / host application information to webinspectord. + + * inspector/remote/RemoteInspectorDebuggable.cpp: + (Inspector::RemoteInspectorDebuggable::info): + * inspector/remote/RemoteInspectorDebuggable.h: + (Inspector::RemoteInspectorDebuggableInfo::RemoteInspectorDebuggableInfo): + (Inspector::RemoteInspectorDebuggableInfo::hasParentProcess): Deleted. + pid per debuggable is no longer needed. + +2014-05-09 Mark Hahnenberg <mhahnenberg@apple.com> + + JSDOMWindow should disable property caching after a certain point + https://bugs.webkit.org/show_bug.cgi?id=132751 + + Reviewed by Filip Pizlo. + + This is part of removing HasImpureGetOwnPropertySlot from JSDOMWindow. After the lookup in the static + hash table for JSDOMWindow fails we want to disable property caching even if the code that follows thinks + that it has provided a cacheable value. + + * runtime/PropertySlot.h: + (JSC::PropertySlot::PropertySlot): + (JSC::PropertySlot::isCacheable): + (JSC::PropertySlot::disableCaching): + +2014-05-09 Andreas Kling <akling@apple.com> + + 8.8% spent in Object.prototype.hasOwnProperty() on sbperftest. + <https://webkit.org/b/132749> + + Leverage the fast-resolve-to-AtomicString optimization for JSRopeString + in Object.prototype.* by using JSString::toIdentifier() in the cases where + we are converting JSString -> String -> Identifier. + + This brings time spent in hasOwnProperty() from 8.8% to 1.3% on + "The Great HTML5 Gaming Performance Test: 2014 edition" + <http://www.scirra.com/demos/c2/sbperftest/> + + Reviewed by Oliver Hunt. + + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncHasOwnProperty): + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + +2014-05-08 Mark Hahnenberg <mhahnenberg@apple.com> + + JSDOMWindow should have a WatchpointSet to fire on window close + https://bugs.webkit.org/show_bug.cgi?id=132721 + + Reviewed by Filip Pizlo. + + This patch allows us to reset the inline caches that assumed they could skip + the first part of JSDOMWindow::getOwnPropertySlot that checks if the window has + been closed. This is part of getting rid of HasImpureGetOwnPropertySlot on JSDOMWindow. + + PropertySlot now accepts a WatchpointSet which the inline cache code can look for + to see if it should create a new Watchpoint for that particular inline cache site. + + * bytecode/Watchpoint.h: + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::tryBuildGetByIDList): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * runtime/PropertySlot.h: + (JSC::PropertySlot::PropertySlot): + (JSC::PropertySlot::watchpointSet): + (JSC::PropertySlot::setWatchpointSet): + +2014-05-09 Tanay C <tanay.c@samsung.com> + + Fix build warning (uninitialized variable) in DFGFixupPhase.cpp + https://bugs.webkit.org/show_bug.cgi?id=132331 + + Reviewed by Darin Adler. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + +2014-05-09 peavo@outlook.com <peavo@outlook.com> + + [Win] Crash when enabling DFG JIT. + https://bugs.webkit.org/show_bug.cgi?id=132683 + + Reviewed by Geoffrey Garen. + + On windows, using register GPRInfo::regT0 as parameter to e.g. JIT::storeDouble(..., GPRInfo::regT0)), + results in a call to JIT::storeDouble(FPRegisterID src, const void* address), + where the address parameter gets the value of GPRInfo::regT0, which is 0 (eax on Windows). + This causes the register to be written to address 0, hence the crash. + + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): Use address in regT0 as parameter. + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): Ditto. + +2014-05-09 Martin Hodovan <mhodovan.u-szeged@partner.samsung.com> + + REGRESSION(r167094): JSC crashes on ARM Traditional + https://bugs.webkit.org/show_bug.cgi?id=132738 + + Reviewed by Zoltan Herczeg. + + PC is two instructions ahead of the current instruction + on ARM Traditional, so the distance is 8 bytes not 2. + + * llint/LowLevelInterpreter.asm: + +2014-05-09 Alberto Garcia <berto@igalia.com> + + jsmin.py license header confusing, mentions non-free license + https://bugs.webkit.org/show_bug.cgi?id=123665 + + Reviewed by Darin Adler. + + Pull the most recent version from upstream, which has a clear + license. + + * inspector/scripts/jsmin.py: + +2014-05-08 Mark Hahnenberg <mhahnenberg@apple.com> + + Base case for get-by-id inline cache doesn't check for HasImpureGetOwnPropertySlot + https://bugs.webkit.org/show_bug.cgi?id=132695 + + Reviewed by Filip Pizlo. + + We check in the case where we're accessing something other than the base object (e.g. the prototype), + but we fail to do so for the base object. + + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + * jsc.cpp: Added some infrastructure to support this test. We don't currently trigger this bug anywhere in WebKit + because all of the values that are returned that could be impure are set to uncacheable anyways. + (WTF::ImpureGetter::ImpureGetter): + (WTF::ImpureGetter::createStructure): + (WTF::ImpureGetter::create): + (WTF::ImpureGetter::finishCreation): + (WTF::ImpureGetter::getOwnPropertySlot): + (WTF::ImpureGetter::visitChildren): + (WTF::ImpureGetter::setDelegate): + (GlobalObject::finishCreation): + (functionCreateImpureGetter): + (functionSetImpureGetterDelegate): + * tests/stress/impure-get-own-property-slot-inline-cache.js: Added. + (foo): + +2014-05-08 Filip Pizlo <fpizlo@apple.com> + + deleteAllCompiledCode() shouldn't use the suspension worklist + https://bugs.webkit.org/show_bug.cgi?id=132708 + + Reviewed by Mark Hahnenberg. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::setOptimizationThresholdBasedOnCompilationResult): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::isStillValid): + * heap/Heap.cpp: + (JSC::Heap::deleteAllCompiledCode): + +2014-05-08 Filip Pizlo <fpizlo@apple.com> + + SSA conversion should delete PhantomLocals for captured variables + https://bugs.webkit.org/show_bug.cgi?id=132693 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGCommon.cpp: + (JSC::DFG::startCrashing): Parallel JIT and a JIT bug means that we man dump IR in parallel. This is the workaround. This patch uses it in all of the places where we dump IR and crash. + * dfg/DFGCommon.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): Use the workaround. + * dfg/DFGLivenessAnalysisPhase.cpp: + (JSC::DFG::LivenessAnalysisPhase::run): Use the workaround. + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): Fix the bug - it's true that PhantomLocal for captured variables doesn't need anything done to it, but it's wrong that we didn't delete it outright. + * dfg/DFGValidate.cpp: Use the workaround. + * tests/stress/phantom-local-captured-but-not-flushed-to-ssa.js: Added. + (foo): + (bar): + +2014-05-07 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r168451. + https://bugs.webkit.org/show_bug.cgi?id=132670 + + Not a speed-up, just do what other compilers do. (Requested by + kling on #webkit). + + Reverted changeset: + + "[X86] Emit BT instruction for single-bit tests." + https://bugs.webkit.org/show_bug.cgi?id=132650 + http://trac.webkit.org/changeset/168451 + +2014-05-07 Filip Pizlo <fpizlo@apple.com> + + Make Executable::clearCode() actually clear all of the entrypoints, and + clean up some other FTL-related calling convention stuff. + <rdar://problem/16720172> + + Rubber stamped by Mark Hahnenberg. + + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGWorklist.cpp: + (JSC::DFG::Worklist::Worklist): + (JSC::DFG::Worklist::finishCreation): + (JSC::DFG::Worklist::create): + (JSC::DFG::ensureGlobalDFGWorklist): + (JSC::DFG::ensureGlobalFTLWorklist): + * dfg/DFGWorklist.h: + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::dump): + * heap/CodeBlockSet.h: + * runtime/Executable.cpp: + (JSC::ExecutableBase::clearCode): + +2014-05-07 Andreas Kling <akling@apple.com> + + [X86] Emit BT instruction for single-bit tests. + <https://webkit.org/b/132650> + + Implement test-bit-and-branch slightly more efficiently by using + BT + JC/JNC instead of TEST + JZ/JNZ when we're only testing for + a single bit. + + Reviewed by Michael Saboff. + + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::singleBitIndex): + (JSC::MacroAssemblerX86Common::branchTest32): + * assembler/X86Assembler.h: + (JSC::X86Assembler::bt_i8r): + (JSC::X86Assembler::bt_i8m): + +2014-05-07 Mark Lam <mark.lam@apple.com> + + REGRESSION(r166678): Dromaeo/cssquery-dojo.html crashes regularly. + <https://webkit.org/b/131356> + + Reviewed by Geoffrey Garen. + + The issue is that GC needs to be made aware of writes to m_inferredValue + in the VariableWatchpointSet, but was not. As a result, if a JSCell* + is written to a VariableWatchpointSet m_inferredValue, and that JSCell + does not survive an eden GC shortly after, we will end up with a stale + JSCell pointer left in the m_inferredValue. + + This issue can be detected more easily by running Dromaeo/cssquery-dojo.html + using DumpRenderTree with the VM heap in zombie mode. + + The fix is to change VariableWatchpointSet m_inferredValue to type + WriteBarrier<Unknown> and ensure that VariableWatchpointSet::notifyWrite() + is executed by all the execution engines so that the WriteBarrier semantics + are honored. + + We still check if the value to be written is the same as the one in the + inferredValue. We'll by-pass calling the slow path notifyWrite() if the + values are the same. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + - need to pass the symbolTable to prepareToWatch() because it will be needed + for instantiating the VariableWatchpointSet in prepareToWatch(). + + * bytecode/VariableWatchpointSet.h: + (JSC::VariableWatchpointSet::VariableWatchpointSet): + - VariableWatchpointSet now tracks its owner symbol table for its m_inferredValue + write barrier, and yes, m_inferredValue is now of type WriteBarrier<Unknown>. + (JSC::VariableWatchpointSet::inferredValue): + (JSC::VariableWatchpointSet::invalidate): + (JSC::VariableWatchpointSet::finalizeUnconditionally): + (JSC::VariableWatchpointSet::addressOfInferredValue): + (JSC::VariableWatchpointSet::notifyWrite): Deleted. + * bytecode/VariableWatchpointSetInlines.h: Added. + (JSC::VariableWatchpointSet::notifyWrite): + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::cellConstant): + - Added an assert in case we try to make constants of zombified JSCells again. + + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + - We now let the slow path handle the cases when the VariableWatchpointSet is + in state ClearWatchpoint and IsWatched, and the slow path will ensure that + we handle the needed write barrier semantics correctly. + We will by-pass the slow path if the value being written is the same as the + inferred value. + + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite): + - Let the slow path handle the cases when the VariableWatchpointSet is + in state ClearWatchpoint and IsWatched. + We will by-pass the slow path if the value being written is the same as the + inferred value. + + * heap/Heap.cpp: + (JSC::Zombify::operator()): + - Use a different value for the zombified bits (to distinguish it from 0xbbadbeef + which is used everywhere else). + * heap/Heap.h: + (JSC::Heap::isZombified): + - Provide a convenience test function to check if JSCells are zombified. This is + currently only used in an assertion in the DFG bytecode parser, but the intent + it that we'll apply this test in other strategic places later to help with early + detection of usage of GC'ed objects when we run in zombie mode. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_captured_mov): + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitNotifyWrite): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitNotifyWrite): + (JSC::JIT::emitSlow_op_put_to_scope): + - Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet + is in state ClearWatchpoint and IsWatched. + We will by-pass the slow path if the value being written is the same as the + inferred value. + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + - Let the slow path for notifyWrite handle the cases when the VariableWatchpointSet + is in state ClearWatchpoint and IsWatched. + We will by-pass the slow path if the value being written is the same as the + inferred value. + + * runtime/CommonSlowPaths.cpp: + + * runtime/JSCJSValue.h: Fixed some typos in the comments. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + * runtime/JSSymbolTableObject.h: + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::prepareToWatch): + (JSC::SymbolTableEntry::notifyWriteSlow): + * runtime/SymbolTable.h: + (JSC::SymbolTableEntry::notifyWrite): + +2014-05-06 Michael Saboff <msaboff@apple.com> + + Unreviewd build fix for C-LOOP after r168396. + + * runtime/TestRunnerUtils.cpp: + (JSC::optimizeNextInvocation): Wrapped actual call inside #if ENABLE(JIT) + +2014-05-06 Michael Saboff <msaboff@apple.com> + + Add test for deleteAllCompiledCode + https://bugs.webkit.org/show_bug.cgi?id=132632 + + Reviewed by Phil Pizlo. + + Added two new hooks to jsc, one to call Heap::deleteAllCompiledCode() and + the other to call CodeBlock::optimizeNextInvocation(). Used these two hooks + to write a test that will queue up loads of DFG compiles and then call + Heap::deleteAllCompiledCode() to make sure that it can handle compiled + code as well as code being compiled. + + * jsc.cpp: + (GlobalObject::finishCreation): + (functionDeleteAllCompiledCode): + (functionOptimizeNextInvocation): + * runtime/TestRunnerUtils.cpp: + (JSC::optimizeNextInvocation): + * runtime/TestRunnerUtils.h: + * tests/stress/deleteAllCompiledCode.js: Added. + (functionList): + (runTest): + +2014-05-06 Andreas Kling <akling@apple.com> + + JSString::toAtomicString() should return AtomicString. + <https://webkit.org/b/132627> + + Remove premature optimization where I was trying to avoid refcount + churn when returning an already atomicized String. + + Instead of using reinterpret_cast to mangle the String member into + a const AtomicString& return value, just return AtomicString. + + Reviewed by Geoff Garen. + + * runtime/JSString.h: + (JSC::JSString::toAtomicString): + +2014-05-06 Mark Hahnenberg <mhahnenberg@apple.com> + + Roll out r167889 + + Rubber stamped by Geoff Garen. + + It broke some websites. + + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::create): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::hasDeletedOffset): + (JSC::PropertyTable::hadDeletedOffset): Deleted. + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::removePropertyTransition): + (JSC::Structure::changePrototypeTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::attributeChangeTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::removePropertyWithoutTransition): + (JSC::Structure::pin): + (JSC::Structure::pinAndPreventTransitions): Deleted. + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::propertyTable): + (JSC::Structure::checkOffsetConsistency): + (JSC::Structure::hadDeletedOffsets): Deleted. + * tests/stress/for-in-after-delete.js: + (foo): Deleted. + +2014-05-05 Andreas Kling <akling@apple.com> + + Fix debug build. + + * runtime/JSCellInlines.h: + (JSC::JSCell::fastGetOwnProperty): + +2014-05-05 Andreas Kling <akling@apple.com> + + Optimize GetByVal when subscript is a rope string. + <https://webkit.org/b/132590> + + Use JSString::toIdentifier() in the various GetByVal implementations + to try and avoid allocating extra strings. + + Added canUseFastGetOwnProperty() and wrap calls to fastGetOwnProperty() + in that, to avoid calling JSString::value() which always resolves ropes + into new strings and de-optimizes subsequent toIdentifier() calls. + + My iMac says ~9% progression on Dromaeo/dom-attr.html + + Reviewed by Phil Pizlo. + + * dfg/DFGOperations.cpp: + * jit/JITOperations.cpp: + (JSC::getByVal): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getByVal): + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::fastGetOwnProperty): + (JSC::JSCell::canUseFastGetOwnProperty): + +2014-05-05 Andreas Kling <akling@apple.com> + + REGRESSION (r168256): ASSERTION FAILED: (buffer + m_length) == position loading vanityfair.com article. + <https://webkit.org/b/168256> + <rdar://problem/16816316> + + Make resolveRopeSlowCase8() behave like its 16-bit counterpart and not + clear the fibers. The caller takes care of this. + + Test: fast/dom/getElementById-with-rope-string-arg.html + + Reviewed by Geoffrey Garen. + + * runtime/JSString.cpp: + (JSC::JSRopeString::resolveRopeSlowCase8): + +2014-05-05 Michael Saboff <msaboff@apple.com> + + REGRESSION: RELEASE_ASSERT in CodeBlock::baselineVersion @ cnn.com + https://bugs.webkit.org/show_bug.cgi?id=132581 + + Reviewed by Filip Pizlo. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::isStillValid): Check that the alternative codeBlock we + started compiling for is still the same at the end of compilation. + Also did some minor restructuring. + +2014-05-05 Andreas Kling <akling@apple.com> + + Optimize PutByVal when subscript is a rope string. + <https://webkit.org/b/132572> + + Add a JSString::toIdentifier() that is smarter when the JSString is + really a rope string. Use this in baseline & DFG's PutByVal to avoid + allocating new StringImpls that we immediately deduplicate anyway. + + Reviewed by Antti Koivisto. + + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * jit/JITOperations.cpp: + * runtime/JSString.h: + (JSC::JSString::toIdentifier): + +2014-05-05 Andreas Kling <akling@apple.com> + + Remove two now-incorrect assertions after r168256. + + * runtime/JSString.cpp: + (JSC::JSRopeString::resolveRopeSlowCase8): + (JSC::JSRopeString::resolveRopeSlowCase): + +2014-05-04 Andreas Kling <akling@apple.com> + + Optimize JSRopeString for resolving directly to AtomicString. + <https://webkit.org/b/132548> + + If we know that the JSRopeString we are resolving is going to be used + as an AtomicString, we can try to avoid creating a new string. + + We do this by first resolving the rope into a stack buffer, and using + that buffer as a key into the AtomicString table. If there is already + an AtomicString with the same characters, we reuse that instead of + constructing a new StringImpl. + + JSString gains these two public functions: + + - AtomicString toAtomicString() + + Returns an AtomicString, tries to avoid allocating a new string + if possible. + + - AtomicStringImpl* toExistingAtomicString() + + Returns a non-null AtomicStringImpl* if one already exists in the + AtomicString table. If none is found, the rope is left unresolved. + + Reviewed by Filip Pizlo. + + * runtime/JSString.cpp: + (JSC::JSRopeString::resolveRopeInternal8): + (JSC::JSRopeString::resolveRopeInternal16): + (JSC::JSRopeString::resolveRopeToAtomicString): + (JSC::JSRopeString::clearFibers): + (JSC::JSRopeString::resolveRopeToExistingAtomicString): + (JSC::JSRopeString::resolveRope): + (JSC::JSRopeString::outOfMemory): + * runtime/JSString.h: + (JSC::JSString::toAtomicString): + (JSC::JSString::toExistingAtomicString): + +2014-05-04 Andreas Kling <akling@apple.com> + + Unreviewed, rolling out r168254. + + Very crashy on debug JSC tests. + + Reverted changeset: + + "jsSubstring() should be lazy" + https://bugs.webkit.org/show_bug.cgi?id=132556 + http://trac.webkit.org/changeset/168254 + +2014-05-04 Filip Pizlo <fpizlo@apple.com> + + jsSubstring() should be lazy + https://bugs.webkit.org/show_bug.cgi?id=132556 + + Reviewed by Andreas Kling. + + jsSubstring() is now lazy by using a special rope that is a substring instead of a + concatenation. To make this patch super simple, we require that a substring's base is + never a rope. Hence, when resolving a rope, we either go down a non-recursive substring + path, or we go down a concatenation path which may see exactly one level of substrings in + its fibers. + + This is up to a 50% speed-up on microbenchmarks and a 10% speed-up on Octane/regexp. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::specializedSweep): + * runtime/JSString.cpp: + (JSC::JSRopeString::visitFibers): + (JSC::JSRopeString::resolveRope): + (JSC::JSRopeString::resolveRopeSlowCase8): + (JSC::JSRopeString::resolveRopeSlowCase): + (JSC::JSRopeString::outOfMemory): + * runtime/JSString.h: + (JSC::JSRopeString::finishCreation): + (JSC::JSRopeString::append): + (JSC::JSRopeString::create): + (JSC::JSRopeString::offsetOfFibers): + (JSC::JSRopeString::fiber): + (JSC::JSRopeString::substringBase): + (JSC::JSRopeString::substringOffset): + (JSC::JSRopeString::substringSentinel): + (JSC::JSRopeString::isSubstring): + (JSC::jsSubstring): + * runtime/RegExpMatchesArray.cpp: + (JSC::RegExpMatchesArray::reifyAllProperties): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncSubstring): + +2014-05-02 Michael Saboff <msaboff@apple.com> + + "arm64 function not 4-byte aligned" warnings when building JSC + https://bugs.webkit.org/show_bug.cgi?id=132495 + + Reviewed by Geoffrey Garen. + + Added ".align 4" for both ARM Thumb2 and ARM 64 to silence the linker. + + * llint/LowLevelInterpreter.cpp: + +2014-05-02 Mark Hahnenberg <mhahnenberg@apple.com> + + Fix cloop build after r168178 + + * bytecode/CodeBlock.cpp: + +2014-05-01 Mark Hahnenberg <mhahnenberg@apple.com> + + Add a DFG function whitelist + https://bugs.webkit.org/show_bug.cgi?id=132437 + + Reviewed by Geoffrey Garen. + + Often times when debugging, using bytecode ranges isn't enough to narrow down to the + particular DFG block that's causing issues. This patch adds the ability to whitelist + specific functions specified in a file to enable further filtering without having to recompile. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGCapabilities.cpp: + (JSC::DFG::isSupported): + (JSC::DFG::mightInlineFunctionForCall): + (JSC::DFG::mightInlineFunctionForClosureCall): + (JSC::DFG::mightInlineFunctionForConstruct): + * dfg/DFGFunctionWhitelist.cpp: Added. + (JSC::DFG::FunctionWhitelist::ensureGlobalWhitelist): + (JSC::DFG::FunctionWhitelist::FunctionWhitelist): + (JSC::DFG::FunctionWhitelist::parseFunctionNamesInFile): + (JSC::DFG::FunctionWhitelist::contains): + * dfg/DFGFunctionWhitelist.h: Added. + * runtime/Options.cpp: + (JSC::parse): + (JSC::Options::dumpOption): + * runtime/Options.h: + +2014-05-02 Filip Pizlo <fpizlo@apple.com> + + DFGAbstractInterpreter should not claim Int52 arithmetic creates Int52s + https://bugs.webkit.org/show_bug.cgi?id=132446 + + Reviewed by Mark Hahnenberg. + + Basically any arithmetic operation can turn an Int52 into an Int32 or vice-versa, and + our modeling of Int52Rep nodes is such that they can have either Int32 or Int52 type + to indicate a bound on the value. This is useful for knowing, for example, that + Int52Rep(Int32:) returns a value that cannot be outside the Int32 range. Also, + ValueRep(Int52Rep:) uses this to determine whether it may return a double or an int. + But this means that all arithmetic operations must be careful to note that they may + turn Int32 inputs into an Int52 output or vice-versa, as these new tests show. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::makeSafe): + * tests/stress/int52-ai-add-then-filter-int32.js: Added. + (foo): + * tests/stress/int52-ai-mul-and-clean-neg-zero-then-filter-int32.js: Added. + (foo): + * tests/stress/int52-ai-mul-then-filter-int32-directly.js: Added. + (foo): + * tests/stress/int52-ai-mul-then-filter-int32.js: Added. + (foo): + * tests/stress/int52-ai-neg-then-filter-int32.js: Added. + (foo): + * tests/stress/int52-ai-sub-then-filter-int32.js: Added. + (foo): + +2014-05-01 Geoffrey Garen <ggaren@apple.com> + + JavaScriptCore fails to build with some versions of clang + https://bugs.webkit.org/show_bug.cgi?id=132436 + + Reviewed by Anders Carlsson. + + * runtime/ArgumentsIteratorConstructor.cpp: Since we call + putDirectWithoutTransition, and it calls putWillGrowOutOfLineStorage, + and both are marked inline, it's valid for the compiler to decide + to inline both and emit neither in the binary. Therefore, we need + both inline definitions to be available in the translation unit at + compile time, or we'll try to link against a function that doesn't exist. + +2014-05-01 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r167964. + https://bugs.webkit.org/show_bug.cgi?id=132431 + + Memory improvements should not regress memory usage (Requested + by olliej on #webkit). + + Reverted changeset: + + "Don't hold on to parameter BindingNodes forever" + https://bugs.webkit.org/show_bug.cgi?id=132360 + http://trac.webkit.org/changeset/167964 + +2014-05-01 Filip Pizlo <fpizlo@apple.com> + + Fix trivial debug-only race-that-crashes in CallLinkStatus and explain why the remaining races are totally awesome + https://bugs.webkit.org/show_bug.cgi?id=132427 + + Reviewed by Mark Hahnenberg. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + +2014-04-30 Simon Fraser <simon.fraser@apple.com> + + Remove ENABLE_PLUGIN_PROXY_FOR_VIDEO + https://bugs.webkit.org/show_bug.cgi?id=132396 + + Reviewed by Eric Carlson. + + Remove ENABLE_PLUGIN_PROXY_FOR_VIDEO and related code. + + * Configurations/FeatureDefines.xcconfig: + +2014-04-30 Filip Pizlo <fpizlo@apple.com> + + Argument flush formats should not be presumed to be JSValue since 'this' is weird + https://bugs.webkit.org/show_bug.cgi?id=132404 + + Reviewed by Michael Saboff. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): Don't assume that arguments are flushed as JSValue. Use the logic for locals instead. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): SetArgument "changes" the format because before this we wouldn't know we had arguments. + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): Ditto. + * dfg/DFGValueSource.cpp: + (JSC::DFG::ValueSource::dumpInContext): Make this easier to dump. + * dfg/DFGValueSource.h: + (JSC::DFG::ValueSource::operator!): Make this easier to dump because Operands<T> uses T::operator!(). + * ftl/FTLOSREntry.cpp: + (JSC::FTL::prepareOSREntry): This had a useful assertion for everything except 'this'. + * tests/stress/strict-to-this-int.js: Added. + (foo): + (Number.prototype.valueOf): + (test): + +2014-04-29 Oliver Hunt <oliver@apple.com> + + Don't hold on to parameterBindingNodes forever + https://bugs.webkit.org/show_bug.cgi?id=132360 + + Reviewed by Geoffrey Garen. + + Don't keep the parameter nodes anymore. Instead we store the + original parameter string and reparse whenever we actually + need them. Because we only actually need them for compilation + this only results in a single extra parse. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + (JSC::UnlinkedFunctionExecutable::visitChildren): + (JSC::UnlinkedFunctionExecutable::finishCreation): + (JSC::UnlinkedFunctionExecutable::paramString): + (JSC::UnlinkedFunctionExecutable::parameters): + (JSC::UnlinkedFunctionExecutable::parameterCount): Deleted. + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::create): + (JSC::UnlinkedFunctionExecutable::parameterCount): + (JSC::UnlinkedFunctionExecutable::parameters): Deleted. + (JSC::UnlinkedFunctionExecutable::finishCreation): Deleted. + * parser/ASTBuilder.h: + (JSC::ASTBuilder::ASTBuilder): + (JSC::ASTBuilder::setFunctionBodyParameters): + * parser/Nodes.h: + (JSC::FunctionBodyNode::parametersStartOffset): + (JSC::FunctionBodyNode::parametersEndOffset): + (JSC::FunctionBodyNode::setParameterLocation): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): + (JSC::parseParameters): + * parser/Parser.h: + (JSC::parse): + * parser/SourceCode.h: + (JSC::SourceCode::subExpression): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::setFunctionBodyParameters): + +2014-04-29 Mark Hahnenberg <mhahnenberg@apple.com> + + JSProxies should be cacheable + https://bugs.webkit.org/show_bug.cgi?id=132351 + + Reviewed by Geoffrey Garen. + + Whenever we encounter a proxy in an inline cache we should try to cache on the + proxy's target instead of giving up. + + This patch adds support for a simple "recursive" inline cache if the base object + we're accessing is a pure forwarding proxy. JSGlobalObject and its subclasses + are the only ones to benefit from this right now. + + This is performance neutral on the benchmarks we track. Currently we won't + cache on JSDOMWindow due to HasImpureGetOwnPropertySlot, but this issue will be fixed soon. + + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::tryBuildGetByIDList): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionCreateProxy): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::isNormalized): + * runtime/JSCellInlines.h: + (JSC::JSCell::isProxy): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::finishCreation): + * runtime/JSProxy.h: + (JSC::JSProxy::createStructure): + (JSC::JSProxy::targetOffset): + * runtime/JSType.h: + * runtime/Operations.h: + (JSC::isPrototypeChainNormalized): + * runtime/Structure.h: + (JSC::Structure::isProxy): + * tests/stress/proxy-inline-cache.js: Added. + (cacheOnTarget.getX): + (cacheOnTarget): + (cacheOnPrototypeOfTarget.getX): + (cacheOnPrototypeOfTarget): + (dontCacheOnProxyInPrototypeChain.getX): + (dontCacheOnProxyInPrototypeChain): + (dontCacheOnTargetOfProxyInPrototypeChainOfTarget.getX): + (dontCacheOnTargetOfProxyInPrototypeChainOfTarget): + +2014-04-29 Filip Pizlo <fpizlo@apple.com> + + Use LLVM as a backend for the fourth-tier DFG JIT (a.k.a. the FTL JIT) + https://bugs.webkit.org/show_bug.cgi?id=112840 + + Rubber stamped by Geoffrey Garen. + + * Configurations/FeatureDefines.xcconfig: + +2014-04-29 Geoffrey Garen <ggaren@apple.com> + + String.prototype.trim removes U+200B from strings. + https://bugs.webkit.org/show_bug.cgi?id=130184 + + Reviewed by Michael Saboff. + + * runtime/StringPrototype.cpp: + (JSC::trimString): + (JSC::isTrimWhitespace): Deleted. + +2014-04-29 Mark Lam <mark.lam@apple.com> + + Zombifying sweep should ignore retired blocks. + <https://webkit.org/b/132344> + + Reviewed by Mark Hahnenberg. + + By definition, retired blocks do not have "dead" objects, or at least + none that we know of yet until the next marking phase has been run + over it. So, we should not be sweeping them (even for zombie mode). + + * heap/Heap.cpp: + (JSC::Heap::zombifyDeadObjects): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::zombifySweep): + * heap/MarkedSpace.h: + (JSC::ZombifySweep::operator()): + +2014-04-29 Mark Lam <mark.lam@apple.com> + + Fix bit rot in zombie mode heap code. + <https://webkit.org/b/132342> + + Reviewed by Mark Hahnenberg. + + Need to enter a DelayedReleaseScope before doing a sweep. + + * heap/Heap.cpp: + (JSC::Heap::zombifyDeadObjects): + +2014-04-29 Tomas Popela <tpopela@redhat.com> + + LLINT loadisFromInstruction doesn't need special case for big endians + https://bugs.webkit.org/show_bug.cgi?id=132330 + + Reviewed by Mark Lam. + + The change introduced in r167076 was wrong. We should not apply the offset + adjustment on loadisFromInstruction usage as the instruction + (UnlinkedInstruction) is declared as an union (i.e. with the int32_t + operand variable). The offset of the other union members will be the + same as the offset of the first one, that is 0. The behavior here is the + same on little and big endian architectures. Thus we don't need + special case for big endians. + + * llint/LowLevelInterpreter.asm: + +2014-04-28 Mark Hahnenberg <mhahnenberg@apple.com> + + Simplify tryCacheGetById + https://bugs.webkit.org/show_bug.cgi?id=132314 + + Reviewed by Oliver Hunt and Filip Pizlo. + + This is neutral across all benchmarks we track, although it looks like a wee 0.5% progression on sunspider. + + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): If we fail to cache on self, we just repatch to call tryBuildGetByIDList next time. + +2014-04-28 Michael Saboff <msaboff@apple.com> + + REGRESSION(r153142) ASSERT from CodeBlock::dumpBytecode dumping String Switch Jump Tables + https://bugs.webkit.org/show_bug.cgi?id=132315 + + Reviewed by Mark Hahnenberg. + + Used the StringImpl version of utf8() instead of creating a String first. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + +2014-04-28 Filip Pizlo <fpizlo@apple.com> + + The LLInt is awesome and it should get more of the action. + + Rubber stamped by Geoffrey Garen. + + 5% speed-up on JSBench and no meaningful regressions. Should be a PLT/DYE speed-up also. + + * runtime/Options.h: + +2014-04-27 Filip Pizlo <fpizlo@apple.com> + + GC should be able to remove things from the DFG worklist and cancel on-going compilations if it knows that the compilation would already be invalidated + https://bugs.webkit.org/show_bug.cgi?id=132166 + + Reviewed by Oliver Hunt and Mark Hahnenberg. + + The GC can aid type inference by removing structures that are dead and jettisoning + code that relies on those structures. This can dramatically accelerate type inference + for some tricky programs. + + Unfortunately, we previously pinned any structures that enqueued compilations depended + on. This means that if you're on a machine that only runs a single compilation thread + and where compilations are relatively slow, you have a high chance of large numbers of + structures being pinned during any GC since the compilation queue is likely to be full + of random stuff. + + This comprehensively fixes this issue by allowing the GC to remove compilation plans + if the things they depend on are dead, and to even cancel safepointed compilations. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan): + (JSC::CodeBlock::isKnownToBeLiveDuringGC): + (JSC::CodeBlock::finalizeUnconditionally): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan): Deleted. + * dfg/DFGDesiredIdentifiers.cpp: + (JSC::DFG::DesiredIdentifiers::DesiredIdentifiers): + * dfg/DFGDesiredIdentifiers.h: + * dfg/DFGDesiredWatchpoints.h: + * dfg/DFGDesiredWeakReferences.cpp: + (JSC::DFG::DesiredWeakReferences::DesiredWeakReferences): + * dfg/DFGDesiredWeakReferences.h: + * dfg/DFGGraphSafepoint.cpp: + (JSC::DFG::GraphSafepoint::GraphSafepoint): + * dfg/DFGGraphSafepoint.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::Plan): + (JSC::DFG::Plan::compileInThread): + (JSC::DFG::Plan::compileInThreadImpl): + (JSC::DFG::Plan::notifyCompiling): + (JSC::DFG::Plan::notifyCompiled): + (JSC::DFG::Plan::notifyReady): + (JSC::DFG::Plan::checkLivenessAndVisitChildren): + (JSC::DFG::Plan::isKnownToBeLiveDuringGC): + (JSC::DFG::Plan::cancel): + (JSC::DFG::Plan::visitChildren): Deleted. + * dfg/DFGPlan.h: + * dfg/DFGSafepoint.cpp: + (JSC::DFG::Safepoint::Result::~Result): + (JSC::DFG::Safepoint::Result::didGetCancelled): + (JSC::DFG::Safepoint::Safepoint): + (JSC::DFG::Safepoint::~Safepoint): + (JSC::DFG::Safepoint::checkLivenessAndVisitChildren): + (JSC::DFG::Safepoint::isKnownToBeLiveDuringGC): + (JSC::DFG::Safepoint::cancel): + (JSC::DFG::Safepoint::visitChildren): Deleted. + * dfg/DFGSafepoint.h: + (JSC::DFG::Safepoint::Result::Result): + * dfg/DFGWorklist.cpp: + (JSC::DFG::Worklist::compilationState): + (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady): + (JSC::DFG::Worklist::removeAllReadyPlansForVM): + (JSC::DFG::Worklist::completeAllReadyPlansForVM): + (JSC::DFG::Worklist::visitWeakReferences): + (JSC::DFG::Worklist::removeDeadPlans): + (JSC::DFG::Worklist::runThread): + (JSC::DFG::Worklist::visitChildren): Deleted. + * dfg/DFGWorklist.h: + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): + * ftl/FTLCompile.h: + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::visitCompilerWorklistWeakReferences): + (JSC::Heap::removeDeadCompilerWorklistEntries): + (JSC::Heap::visitWeakHandles): + (JSC::Heap::collect): + (JSC::Heap::visitCompilerWorklists): Deleted. + * heap/Heap.h: + +2014-04-28 Mark Hahnenberg <mhahnenberg@apple.com> + + Deleting properties poisons objects + https://bugs.webkit.org/show_bug.cgi?id=131551 + + Reviewed by Oliver Hunt. + + This is ~3% progression on Dromaeo with a ~6% progression on the jslib portion of Dromaeo in particular. + + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::create): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::hasDeletedOffset): + (JSC::PropertyTable::hadDeletedOffset): If we ever had deleted properties we can no longer cache offsets when + iterating properties because we're required to iterate properties in insertion order. + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): We now re-use deleted properties when materializing the property map. + (JSC::Structure::removePropertyTransition): We allow up to 5 deletes for a particular path through the tree of + Structure transitions. After that, we convert to an uncacheable dictionary like we used to. We don't cache + delete transitions, but we allow transitioning from them. + (JSC::Structure::changePrototypeTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::attributeChangeTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::removePropertyWithoutTransition): + (JSC::Structure::pin): Now does only what it says it does--marks the property table as pinned. + (JSC::Structure::pinAndPreventTransitions): More descriptive version of what the old pin() was doing. + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::hadDeletedOffsets): + (JSC::Structure::propertyTable): + (JSC::Structure::checkOffsetConsistency): Rearranged variables to be more sensible. + * tests/stress/for-in-after-delete.js: Added. + (foo): + +2014-04-25 Andreas Kling <akling@apple.com> + + Inline (C++) GetByVal with numeric indices more aggressively. + <https://webkit.org/b/132218> + + We were already inlining the string indexed GetByVal path pretty well, + while the path for numeric indices got neglected. No more! + + ~9.5% improvement on Dromaeo/dom-traverse.html on my MBP: + + Before: 199.50 runs/s + After: 218.58 runs/s + + Reviewed by Phil Pizlo. + + * dfg/DFGOperations.cpp: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::get): + + ALWAYS_INLINE all the things. + + * runtime/JSObject.h: + (JSC::JSObject::getPropertySlot): + + Avoid fetching the Structure more than once. We have the same + optimization in the string-indexed code path. + +2014-04-25 Oliver Hunt <oliver@apple.com> + + Need earlier cell test + https://bugs.webkit.org/show_bug.cgi?id=132211 + + Reviewed by Mark Lam. + + Move cell test to before the function call repatch + location, as the repatch logic for 32bit assumes that the + caller will already have performed a cell check. + + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + +2014-04-25 Andreas Kling <akling@apple.com> + + Un-fast-allocate JSGlobalObjectRareData because Windows doesn't build and I'm not in the mood. + + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObjectRareData::JSGlobalObjectRareData): + (JSC::JSGlobalObject::JSGlobalObjectRareData::~JSGlobalObjectRareData): Deleted. + +2014-04-25 Andreas Kling <akling@apple.com> + + Windows build fix attempt. + + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObjectRareData::~JSGlobalObjectRareData): + +2014-04-25 Mark Lam <mark.lam@apple.com> + + Refactor debugging code to use BreakpointActions instead of Vector<ScriptBreakpointAction>. + <https://webkit.org/b/132201> + + Reviewed by Joseph Pecoraro. + + BreakpointActions is Vector<ScriptBreakpointAction>. Let's just consistently use + BreakpointActions everywhere. + + * inspector/ScriptBreakpoint.h: + (Inspector::ScriptBreakpoint::ScriptBreakpoint): + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::setBreakpoint): + (Inspector::ScriptDebugServer::getActionsForBreakpoint): + * inspector/ScriptDebugServer.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::removeBreakpoint): + * inspector/agents/InspectorDebuggerAgent.h: + +2014-04-24 Filip Pizlo <fpizlo@apple.com> + + DFG worklist scanning should not treat the key as a separate entity + https://bugs.webkit.org/show_bug.cgi?id=132167 + + Reviewed by Mark Hahnenberg. + + This simplifies the interface to the GC and will enable more optimizations. + + * dfg/DFGCompilationKey.cpp: + (JSC::DFG::CompilationKey::visitChildren): Deleted. + * dfg/DFGCompilationKey.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::visitChildren): + * dfg/DFGWorklist.cpp: + (JSC::DFG::Worklist::visitChildren): + +2014-04-25 Oliver Hunt <oliver@apple.com> + + Remove unused parameter from codeblock linking function + https://bugs.webkit.org/show_bug.cgi?id=132199 + + Reviewed by Anders Carlsson. + + No change in behaviour. This is just a small change to make it + slightly easier to reason about what the offsets in UnlinkedFunctionExecutable + actually mean. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::link): + * bytecode/UnlinkedCodeBlock.h: + * runtime/Executable.cpp: + (JSC::ProgramExecutable::initializeGlobalProperties): + +2014-04-25 Andreas Kling <akling@apple.com> + + Mark some things with WTF_MAKE_FAST_ALLOCATED. + <https://webkit.org/b/132198> + + Use FastMalloc for more things. + + Reviewed by Anders Carlsson. + + * builtins/BuiltinExecutables.h: + * heap/GCThreadSharedData.h: + * inspector/JSConsoleClient.h: + * inspector/agents/InspectorAgent.h: + * runtime/CodeCache.h: + * runtime/JSGlobalObject.h: + * runtime/Lookup.cpp: + (JSC::HashTable::createTable): + (JSC::HashTable::deleteTable): + * runtime/WeakGCMap.h: + +2014-04-25 Antoine Quint <graouts@webkit.org> + + Implement Array.prototype.find() + https://bugs.webkit.org/show_bug.cgi?id=130966 + + Reviewed by Oliver Hunt. + + Implement Array.prototype.find() and Array.prototype.findIndex() as proposed in the Harmony spec. + + * builtins/Array.prototype.js: + (find): + (findIndex): + * runtime/ArrayPrototype.cpp: + +2014-04-24 Brady Eidson <beidson@apple.com> + + Rename "IMAGE_CONTROLS" feature to "SERVICE_CONTROLS" + https://bugs.webkit.org/show_bug.cgi?id=132155 + + Reviewed by Tim Horton. + + * Configurations/FeatureDefines.xcconfig: + +2014-04-24 Michael Saboff <msaboff@apple.com> + + REGRESSION: Apparent hang of PCE.js Mac OS System 7.0.1 on ARM64 devices + https://bugs.webkit.org/show_bug.cgi?id=132147 + + Reviewed by Mark Lam. + + Fixed or64(), eor32( ) and eor64() to use "src" register when we have a valid logicalImm. + + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::or64): + (JSC::MacroAssemblerARM64::xor32): + (JSC::MacroAssemblerARM64::xor64): + * tests/stress/regress-132147.js: Added test. + +2014-04-24 Mark Lam <mark.lam@apple.com> + + Make slowPathAllocsBetweenGCs a runtime option. + <https://webkit.org/b/132137> + + Reviewed by Mark Hahnenberg. + + This will make it easier to more casually run tests with this configuration + as well as to reproduce issues (instead of requiring a code mod and rebuild). + We will now take --slowPathAllocsBetweenGCs=N where N is the number of + slow path allocations before we trigger a collection. + + The option defaults to 0, which is reserved to mean that we will not trigger + any collections there. + + * heap/Heap.h: + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::doTestCollectionsIfNeeded): + (JSC::MarkedAllocator::allocateSlowCase): + * heap/MarkedAllocator.h: + * runtime/Options.h: + +2014-04-23 Mark Lam <mark.lam@apple.com> + + The GC should only resume compiler threads that it suspended in the same GC pass. + <https://webkit.org/b/132088> + + Reviewed by Mark Hahnenberg. + + Previously, this scenario can occur: + 1. Thread 1 starts a GC and tries to suspend DFG worklist threads. However, + no worklists were created yet at the that time. + 2. Thread 2 starts to compile some functions and creates a DFG worklist, and + acquires the worklist thread's lock. + 3. Thread 1's GC completes and tries to resume suspended DFG worklist thread. + This time, it sees the worklist created by Thread 2 and ends up unlocking + the worklist thread's lock that is supposedly held by Thread 2. + Thereafter, chaos ensues. + + The fix is to cache the worklists that were actually suspended by each GC pass, + and only resume those when the GC is done. + + This issue was discovered by enabling COLLECT_ON_EVERY_ALLOCATION and running + the fast/workers layout tests. + + * heap/Heap.cpp: + (JSC::Heap::visitCompilerWorklists): + (JSC::Heap::deleteAllCompiledCode): + (JSC::Heap::suspendCompilerThreads): + (JSC::Heap::resumeCompilerThreads): + * heap/Heap.h: + +2014-04-23 Mark Hahnenberg <mhahnenberg@apple.com> + + Arguments::copyBackingStore needs to update m_registers in tandem with m_registerArray + https://bugs.webkit.org/show_bug.cgi?id=132079 + + Reviewed by Michael Saboff. + + Since we're moving the register backing store, we don't want to leave a dangling pointer into a random CopiedBlock. + + Also added a test that previously triggered this bug. + + * runtime/Arguments.cpp: + (JSC::Arguments::copyBackingStore): D'oh! + * tests/stress/arguments-copy-register-array-backing-store.js: Added. + (foo): + (bar): + +2014-04-23 Mark Rowe <mrowe@apple.com> + + [Mac] REGRESSION (r164823): Building JavaScriptCore creates files under /tmp/JavaScriptCore.dst + <https://webkit.org/b/132053> + + Reviewed by Dan Bernstein. + + * JavaScriptCore.xcodeproj/project.pbxproj: Don't try to create a symlink at /usr/local/bin/jsc inside + the DSTROOT unless we're building to the deployment location. Also remove the unnecessary -x argument + from /bin/sh since that generates unnecessary output. + +2014-04-22 Mark Lam <mark.lam@apple.com> + + DFG::Worklist should acquire the m_lock before iterating DFG plans. + <https://webkit.org/b/132032> + + Reviewed by Filip Pizlo. + + Currently, there's a rightToRun mechanism that ensures that no compilation + threads are running when the GC is iterating through the DFG worklists. + However, this does not prevent a Worker thread from doing a DFG compilation + and modifying the plans in the worklists thereby invalidating the plan + iterator that the GC is using. This patch fixes the issue by acquiring + the worklist m_lock before iterating the worklist plans. + + This issue was uncovered by running the fast/workers layout tests with + COLLECT_ON_EVERY_ALLOCATION enabled. + + * dfg/DFGWorklist.cpp: + (JSC::DFG::Worklist::isActiveForVM): + (JSC::DFG::Worklist::visitChildren): + +2014-04-22 Brent Fulgham <bfulgham@apple.com> + + [Win] Support Python 2.7 in Cygwin + https://bugs.webkit.org/show_bug.cgi?id=132023 + + Reviewed by Michael Saboff. + + * DerivedSources.make: Use a conditional variable to define + the path to Python/Perl. + +2014-04-22 Filip Pizlo <fpizlo@apple.com> + + Switch the LLVMForJSC target to using the LLVM in /usr/local rather than /usr/local/LLVMForJavaScriptCore on iOS + https://bugs.webkit.org/show_bug.cgi?id=130867 + <rdar://problem/16432456> + + Reviewed by Mark Hahnenberg. + + * Configurations/Base.xcconfig: + * Configurations/LLVMForJSC.xcconfig: + +2014-04-22 Alex Christensen <achristensen@webkit.org> + + [Win] Unreviewed build fix after my r167666. + + * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractorCommon.props: + Added ../../../ again to include headers in Source/JavaScriptCore. + +2014-04-22 Alex Christensen <achristensen@webkit.org> + + Removed old stdbool and inttypes headers. + https://bugs.webkit.org/show_bug.cgi?id=131966 + + Reviewed by Brent Fulgham. + + * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractorCommon.props: + * JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props: + Removed references to os-win32 directory. + * os-win32: Removed. + * os-win32/inttypes.h: Removed. + * os-win32/stdbool.h: Removed. + +2014-04-21 Filip Pizlo <fpizlo@apple.com> + + DFG::clobberize() should honestly admit that profiler and debugger nodes are effectful + https://bugs.webkit.org/show_bug.cgi?id=131971 + <rdar://problem/16676511> + + Reviewed by Mark Lam. + + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + +2014-04-21 Filip Pizlo <fpizlo@apple.com> + + Switch statements that skip the baseline JIT should work + https://bugs.webkit.org/show_bug.cgi?id=131965 + + Reviewed by Mark Hahnenberg. + + * bytecode/JumpTable.h: + (JSC::SimpleJumpTable::ensureCTITable): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitSwitchIntJump): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_switch_imm): + (JSC::JIT::emit_op_switch_char): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_switch_imm): + (JSC::JIT::emit_op_switch_char): + * tests/stress/inline-llint-with-switch.js: Added. + (foo): + (bar): + (test): + +2014-04-21 Mark Hahnenberg <mhahnenberg@apple.com> + + Arguments objects shouldn't need a destructor + https://bugs.webkit.org/show_bug.cgi?id=131899 + + Reviewed by Oliver Hunt. + + This patch rids Arguments objects of their destructors. It does this by + switching their backing stores to use CopiedSpace rather than malloc memory. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateArguments): Fix the code emitted for inline + Arguments allocation so that it only emits an extra write for strict mode code rather + than unconditionally. + * heap/CopyToken.h: New CopyTokens for the two different types of Arguments backing stores. + * runtime/Arguments.cpp: + (JSC::Arguments::visitChildren): We need to tell the collector to copy the back stores now. + (JSC::Arguments::copyBackingStore): Do the actual copying of the backing stores. + (JSC::Arguments::deletePropertyByIndex): Update all the accesses to SlowArgumentData and m_registerArray. + (JSC::Arguments::deleteProperty): + (JSC::Arguments::defineOwnProperty): + (JSC::Arguments::allocateRegisterArray): + (JSC::Arguments::tearOff): + (JSC::Arguments::destroy): Deleted. We don't need the destructor any more. + * runtime/Arguments.h: + (JSC::Arguments::registerArraySizeInBytes): + (JSC::Arguments::SlowArgumentData::SlowArgumentData): Switch SlowArgumentData to being allocated + in CopiedSpace. Now the SlowArgumentData and its backing store are a single contiguous CopiedSpace + allocation. + (JSC::Arguments::SlowArgumentData::slowArguments): + (JSC::Arguments::SlowArgumentData::bytecodeToMachineCaptureOffset): + (JSC::Arguments::SlowArgumentData::setBytecodeToMachineCaptureOffset): + (JSC::Arguments::SlowArgumentData::sizeForNumArguments): + (JSC::Arguments::Arguments): + (JSC::Arguments::allocateSlowArguments): + (JSC::Arguments::tryDeleteArgument): + (JSC::Arguments::isDeletedArgument): + (JSC::Arguments::isArgument): + (JSC::Arguments::argument): + (JSC::Arguments::finishCreation): + * runtime/SymbolTable.h: + +2014-04-21 Eric Carlson <eric.carlson@apple.com> + + [Mac] implement WebKitDataCue + https://bugs.webkit.org/show_bug.cgi?id=131799 + + Reviewed by Dean Jackson. + + * Configurations/FeatureDefines.xcconfig: Define ENABLE_DATACUE_VALUE. + +2014-04-21 Filip Pizlo <fpizlo@apple.com> + + Unreviewed test gardening, run the repeat-out-of-bounds tests again. + + * tests/stress/float32-repeat-out-of-bounds.js: + * tests/stress/int8-repeat-out-of-bounds.js: + +2014-04-21 Filip Pizlo <fpizlo@apple.com> + + OSR exit should know about Int52 and Double constants + https://bugs.webkit.org/show_bug.cgi?id=131945 + + Reviewed by Oliver Hunt. + + The DFG OSR exit machinery's ignorance would lead to some constants becoming + jsUndefined() after OSR exit. + + The FTL OSR exit machinery's ignorance just meant that we would sometimes use a + stackmap constant rather than baking the constant into the OSRExit data structure. + So, not a big deal, but worth fixing. + + Also added some helpful hacks to jsc.cpp for testing such OSR exit pathologies. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGMinifiedNode.h: + (JSC::DFG::belongsInMinifiedGraph): + (JSC::DFG::MinifiedNode::hasConstantNumber): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionOtherFalse): + (functionUndefined): + * runtime/Intrinsic.h: + * tests/stress/fold-to-double-constant-then-exit.js: Added. + (foo): + * tests/stress/fold-to-int52-constant-then-exit.js: Added. + (foo): + +2014-04-21 Filip Pizlo <fpizlo@apple.com> + + Provide feedback when we encounter an unrecognied node in the FTL backend. + + Rubber stamped by Alexey Proskuryakov. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + +2014-04-21 Andreas Kling <akling@apple.com> + + Move the JSString cache from DOMWrapperWorld to VM. + <https://webkit.org/b/131940> + + Reviewed by Geoff Garen. + + * runtime/VM.h: + +2014-04-19 Filip Pizlo <fpizlo@apple.com> + + Take block execution count estimates into account when voting double + https://bugs.webkit.org/show_bug.cgi?id=131906 + + Reviewed by Geoffrey Garen. + + This was a drama in three acts. + + Act I: Slurp in BasicBlock::executionCount and use it as a weight when counting the + number of uses of a variable that want double or non-double. Easy as pie. This + gave me a huge speed-up on FloatMM and a huge slow-down on basically everything + else. + + Act II: Realize that there were some programs where our previous double voting was + just on the edge of disaster and making it more precise tipped it over. In + particular, if you had an integer variable that would infrequently be used in a + computation that resulted in a variable that was frequently used as an array index, + the outer infrequentness would be the thing we'd use in the vote. So, an array + index would become double. We fix this by reviving global backwards propagation + and introducing the concept of ReallyWantsInt, which is used just for array + indices. Any variable transitively flagged as ReallyWantsInt will never be forced + double. We need that flag to be separate from UsedAsInt, since UsedAsInt needs to + be set in bitops for RageConversion but using it for double forcing is too much. + Basically, it's cheaper to have to convert a double to an int for a bitop than it + is to convert a double to an int for an array index; also a variable being used as + an array index is a much stronger hint that it ought to be an int. This recovered + performance on everything except programs that used FTL OSR entry. + + Act III: Realize that OSR entrypoint creation creates blocks that have NaN execution + count, which then completely pollutes the weighting - essentially all votes go + NaN. Fix this with some surgical defenses. Basically, any client of execution + counts should allow for them to be NaN and shouldn't completely fall off a cliff + when it happens. + + This is awesome. 75% speed-up on FloatMM. 11% speed-up on audio-dft. This leads to + 7% speed-up on AsmBench and 2% speed-up on Kraken. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::run): + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dumpBlockHeader): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::voteNode): + (JSC::DFG::Graph::voteChildren): + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + * dfg/DFGOSREntrypointCreationPhase.cpp: + (JSC::DFG::OSREntrypointCreationPhase::run): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): + (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): + * dfg/DFGVariableAccessData.cpp: Added. + (JSC::DFG::VariableAccessData::VariableAccessData): + (JSC::DFG::VariableAccessData::mergeIsCaptured): + (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox): + (JSC::DFG::VariableAccessData::predict): + (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): + (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): + (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): + (JSC::DFG::VariableAccessData::mergeDoubleFormatState): + (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): + (JSC::DFG::VariableAccessData::flushFormat): + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::vote): + (JSC::DFG::VariableAccessData::VariableAccessData): Deleted. + (JSC::DFG::VariableAccessData::mergeIsCaptured): Deleted. + (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox): Deleted. + (JSC::DFG::VariableAccessData::predict): Deleted. + (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): Deleted. + (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): Deleted. + (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): Deleted. + (JSC::DFG::VariableAccessData::mergeDoubleFormatState): Deleted. + (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): Deleted. + (JSC::DFG::VariableAccessData::flushFormat): Deleted. + +2014-04-21 Michael Saboff <msaboff@apple.com> + + REGRESSION(r167591): ARM64 and ARM traditional builds broken + https://bugs.webkit.org/show_bug.cgi?id=131935 + + Reviewed by Mark Hahnenberg. + + Added store8(TrustedImm32, MacroAssembler::Address) to the ARM traditional and ARM64 + macro assemblers. Added a new test for the original patch. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::store8): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::store8): + * tests/stress/dfg-create-arguments-inline-alloc.js: New test. + +2014-04-21 Mark Hahnenberg <mhahnenberg@apple.com> + + Inline allocate Arguments objects in the DFG + https://bugs.webkit.org/show_bug.cgi?id=131897 + + Reviewed by Geoffrey Garen. + + Many libraries/frameworks depend on the arguments object for overloaded API entry points. + This is the first step to making Arguments fast(er). We'll duplicate the logic in Arguments::create + for now and take the slow path for complicated cases like slow arguments, tearing off for strict mode, etc. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateArguments): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateDestructibleObject): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * runtime/Arguments.h: + (JSC::Arguments::offsetOfActivation): + (JSC::Arguments::offsetOfOverrodeLength): + (JSC::Arguments::offsetOfIsStrictMode): + (JSC::Arguments::offsetOfRegisterArray): + (JSC::Arguments::offsetOfCallee): + (JSC::Arguments::allocationSize): + +2014-04-20 Andreas Kling <akling@apple.com> + + Speed up jsStringWithCache() through WeakGCMap inlining. + <https://webkit.org/b/131923> + + Always inline WeakGCMap::add() but move the slow garbage collecting + path out-of-line. + + Reviewed by Darin Adler. + + * runtime/WeakGCMap.h: + (JSC::WeakGCMap::add): + (JSC::WeakGCMap::gcMap): + +2014-04-20 László Langó <llango.u-szeged@partner.samsung.com> + + JavaScriptCore: ARM build fix after r167094. + https://bugs.webkit.org/show_bug.cgi?id=131612 + + Reviewed by Michael Saboff. + + After r167094 there are many build errors on ARM like these: + + /tmp/ccgtHRno.s:370: Error: invalid constant (425a) after fixup + /tmp/ccgtHRno.s:374: Error: invalid constant (426e) after fixup + /tmp/ccgtHRno.s:378: Error: invalid constant (4282) after fixup + /tmp/ccgtHRno.s:382: Error: invalid constant (4296) after fixup + + Problem is caused by the wrong generated assembly like: + "\tmov r2, (" LOCAL_LABEL_STRING(llint_op_strcat) " - " LOCAL_LABEL_STRING(relativePCBase) ")\n" // /home/webkit/WebKit/Source/JavaScriptCore/llint/LowLevelInterpreter.asm:741 + + `mov` can only move 8 bit immediate, but not every constant fit into 8 bit. Clang converts + the mov to a single movw or a movw and a movt, depending on the immediate, but binutils doesn't. + Add a new ARM specific offline assembler instruction (`mvlbl`) for the following llint_entry + use case: move rn, (label1-label2) which is translated to movw and movt. + + * llint/LowLevelInterpreter.asm: + * offlineasm/arm.rb: + * offlineasm/instructions.rb: + +2014-04-20 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Unreviewed build fix after r167336. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::branchAdd32): + +2014-04-20 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r167501. + https://bugs.webkit.org/show_bug.cgi?id=131913 + + It broke DYEBench (Requested by mhahnenberg on #webkit). + + Reverted changeset: + + "Deleting properties poisons objects" + https://bugs.webkit.org/show_bug.cgi?id=131551 + http://trac.webkit.org/changeset/167501 + +2014-04-19 Filip Pizlo <fpizlo@apple.com> + + It should be OK to store new fields into objects that have no prototypes + https://bugs.webkit.org/show_bug.cgi?id=131905 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPrototypeChecks): + * tests/stress/put-by-id-transition-null-prototype.js: Added. + (foo): + +2014-04-19 Benjamin Poulain <bpoulain@apple.com> + + Make the CSS JIT compile for ARM64 + https://bugs.webkit.org/show_bug.cgi?id=131834 + + Reviewed by Gavin Barraclough. + + Extend the ARM64 MacroAssembler to support the code generation required by + the CSS JIT. + + * assembler/MacroAssembler.h: + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::addPtrNoFlags): + (JSC::MacroAssemblerARM64::or32): + (JSC::MacroAssemblerARM64::branchPtr): + (JSC::MacroAssemblerARM64::test32): + (JSC::MacroAssemblerARM64::branch): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::test32): + +2014-04-19 Andreas Kling <akling@apple.com> + + Two little shortcuts to the JSType. + <https://webkit.org/b/131896> + + Tweak two sites that take the long road through JSCell::structure()->typeInfo() + to look at data that's already in JSCell::type(). + + Reviewed by Darin Adler. + + * runtime/NameInstance.h: + (JSC::isName): + * runtime/NumberPrototype.cpp: + (JSC::toThisNumber): + +2014-04-19 Filip Pizlo <fpizlo@apple.com> + + Make it easier to check if an integer sum would overflow + https://bugs.webkit.org/show_bug.cgi?id=131900 + + Reviewed by Darin Adler. + + * dfg/DFGOperations.cpp: + * runtime/Operations.h: + (JSC::jsString): + +2014-04-19 Filip Pizlo <fpizlo@apple.com> + + Address some feedback on https://bugs.webkit.org/show_bug.cgi?id=130684. + + * dfg/DFGOperations.cpp: + * runtime/JSString.h: + (JSC::JSRopeString::RopeBuilder::append): + +2014-04-18 Mark Lam <mark.lam@apple.com> + + REGRESSION(r164205): WebKit crash @StructureIDTable::get. + <https://webkit.org/b/130539> + + Reviewed by Geoffrey Garen. + + prepareOSREntry() prepares for OSR entry by first copying the local var + values from the baseline frame to a scartch buffer, which is then used + to fill in the locals in their new position in the DFG frame. Unfortunately, + prepareOSREntry() was using the DFG frame's frameRegisterCount as the frame + size of the baseline frame. As a result, some values of locals in the + baseline frame were not saved off, and the DFG frame may get initialized + with random content that happened to be in the uninitialized (and possibly + unallocated) portions of the scratch buffer. + + The fix is to use OSREntryData::m_expectedValues.numberOfLocals() as the + number of locals in the baseline frame that we want to copy to the scratch + buffer. + + Note: osrEntryThunkGenerator() is expecting the DFG frameRegisterCount + at offset 0 in the scratch buffer. So, we continue to write that value + there, not the baseline frame size. + + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + +2014-04-18 Timothy Hatcher <timothy@apple.com> + + Web Inspector: Move InspectorProfilerAgent to JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=131673 + + Passes existing profiler and inspector tests. + + Reviewed by Joseph Pecoraro. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/JSConsoleClient.cpp: + (Inspector::JSConsoleClient::JSConsoleClient): + (Inspector::JSConsoleClient::profile): + (Inspector::JSConsoleClient::profileEnd): + (Inspector::JSConsoleClient::count): Deleted. + * inspector/JSConsoleClient.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + * inspector/agents/InspectorProfilerAgent.cpp: Added. + (Inspector::InspectorProfilerAgent::InspectorProfilerAgent): + (Inspector::InspectorProfilerAgent::~InspectorProfilerAgent): + (Inspector::InspectorProfilerAgent::addProfile): + (Inspector::InspectorProfilerAgent::createProfileHeader): + (Inspector::InspectorProfilerAgent::enable): + (Inspector::InspectorProfilerAgent::disable): + (Inspector::InspectorProfilerAgent::getUserInitiatedProfileName): + (Inspector::InspectorProfilerAgent::getProfileHeaders): + (Inspector::buildInspectorObject): + (Inspector::InspectorProfilerAgent::buildProfileInspectorObject): + (Inspector::InspectorProfilerAgent::getCPUProfile): + (Inspector::InspectorProfilerAgent::removeProfile): + (Inspector::InspectorProfilerAgent::reset): + (Inspector::InspectorProfilerAgent::didCreateFrontendAndBackend): + (Inspector::InspectorProfilerAgent::willDestroyFrontendAndBackend): + (Inspector::InspectorProfilerAgent::start): + (Inspector::InspectorProfilerAgent::stop): + (Inspector::InspectorProfilerAgent::setRecordingProfile): + (Inspector::InspectorProfilerAgent::startProfiling): + (Inspector::InspectorProfilerAgent::stopProfiling): + * inspector/agents/InspectorProfilerAgent.h: Added. + * inspector/agents/JSGlobalObjectProfilerAgent.cpp: Copied from Source/WebCore/inspector/ScriptProfile.idl. + (Inspector::JSGlobalObjectProfilerAgent::JSGlobalObjectProfilerAgent): + (Inspector::JSGlobalObjectProfilerAgent::profilingGlobalExecState): + * inspector/agents/JSGlobalObjectProfilerAgent.h: Copied from Source/WebCore/inspector/ScriptProfile.idl. + * inspector/protocol/Profiler.json: Renamed from Source/WebCore/inspector/protocol/Profiler.json. + * profiler/Profile.h: + * runtime/ConsoleClient.h: + +2014-04-18 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r167527. + https://bugs.webkit.org/show_bug.cgi?id=131883 + + Broke 32-bit build (Requested by ap on #webkit). + + Reverted changeset: + + "[Mac] implement WebKitDataCue" + https://bugs.webkit.org/show_bug.cgi?id=131799 + http://trac.webkit.org/changeset/167527 + +2014-04-18 Eric Carlson <eric.carlson@apple.com> + + [Mac] implement WebKitDataCue + https://bugs.webkit.org/show_bug.cgi?id=131799 + + Reviewed by Dean Jackson. + + * Configurations/FeatureDefines.xcconfig: Define ENABLE_DATACUE_VALUE. + +2014-04-18 Filip Pizlo <fpizlo@apple.com> + + Actually address Mark's review feedback. + + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::handleExitCounts): + +2014-04-18 Filip Pizlo <fpizlo@apple.com> + + Options::maximumExecutionCountsBetweenCheckpoints() should be higher for DFG->FTL tier-up but the same for other tier-ups + https://bugs.webkit.org/show_bug.cgi?id=131850 + + Reviewed by Mark Hahnenberg. + + Templatize ExecutionCounter to allow for two different styles of calculating the + checkpoint threshold. + + Appears to be a slight speed-up on DYEBench. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::llintExecuteCounter): + (JSC::CodeBlock::offsetOfJITExecuteCounter): + (JSC::CodeBlock::offsetOfJITExecutionActiveThreshold): + (JSC::CodeBlock::offsetOfJITExecutionTotalCount): + (JSC::CodeBlock::jitExecuteCounter): + * bytecode/ExecutionCounter.cpp: + (JSC::ExecutionCounter<countingVariant>::ExecutionCounter): + (JSC::ExecutionCounter<countingVariant>::forceSlowPathConcurrently): + (JSC::ExecutionCounter<countingVariant>::checkIfThresholdCrossedAndSet): + (JSC::ExecutionCounter<countingVariant>::setNewThreshold): + (JSC::ExecutionCounter<countingVariant>::deferIndefinitely): + (JSC::applyMemoryUsageHeuristics): + (JSC::applyMemoryUsageHeuristicsAndConvertToInt): + (JSC::ExecutionCounter<countingVariant>::hasCrossedThreshold): + (JSC::ExecutionCounter<countingVariant>::setThreshold): + (JSC::ExecutionCounter<countingVariant>::reset): + (JSC::ExecutionCounter<countingVariant>::dump): + (JSC::ExecutionCounter::ExecutionCounter): Deleted. + (JSC::ExecutionCounter::forceSlowPathConcurrently): Deleted. + (JSC::ExecutionCounter::checkIfThresholdCrossedAndSet): Deleted. + (JSC::ExecutionCounter::setNewThreshold): Deleted. + (JSC::ExecutionCounter::deferIndefinitely): Deleted. + (JSC::ExecutionCounter::applyMemoryUsageHeuristics): Deleted. + (JSC::ExecutionCounter::applyMemoryUsageHeuristicsAndConvertToInt): Deleted. + (JSC::ExecutionCounter::hasCrossedThreshold): Deleted. + (JSC::ExecutionCounter::setThreshold): Deleted. + (JSC::ExecutionCounter::reset): Deleted. + (JSC::ExecutionCounter::dump): Deleted. + * bytecode/ExecutionCounter.h: + (JSC::formattedTotalExecutionCount): + (JSC::ExecutionCounter::maximumExecutionCountsBetweenCheckpoints): + (JSC::ExecutionCounter::clippedThreshold): + (JSC::ExecutionCounter::formattedTotalCount): Deleted. + * dfg/DFGJITCode.h: + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::handleExitCounts): + * llint/LowLevelInterpreter.asm: + * runtime/Options.h: + +2014-04-17 Mark Hahnenberg <mhahnenberg@apple.com> + + Deleting properties poisons objects + https://bugs.webkit.org/show_bug.cgi?id=131551 + + Reviewed by Geoffrey Garen. + + This is ~3% progression on Dromaeo with a ~6% progression on the jslib portion of Dromaeo in particular. + + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::materializePropertyMap): We now re-use deleted properties when materializing the property map. + (JSC::Structure::removePropertyTransition): We allow up to 5 deletes for a particular path through the tree of + Structure transitions. After that, we convert to an uncacheable dictionary like we used to. We don't cache + delete transitions, but we allow transitioning from them. + (JSC::Structure::changePrototypeTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::attributeChangeTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::preventExtensionsTransition): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::removePropertyWithoutTransition): + (JSC::Structure::pin): Now does only what it says it does--marks the property table as pinned. + (JSC::Structure::pinAndPreventTransitions): More descriptive version of what the old pin() was doing. + * runtime/Structure.h: + * runtime/StructureInlines.h: + (JSC::Structure::checkOffsetConsistency): Rearranged variables to be more sensible. + +2014-04-17 Filip Pizlo <fpizlo@apple.com> + + InlineCallFrameSet should be refcounted + https://bugs.webkit.org/show_bug.cgi?id=131829 + + Reviewed by Geoffrey Garen. + + And DFG::Plan should hold a ref to it. Previously it was owned by Graph until it + became owned by JITCode. Except that if we're "failing" to compile, JITCode may die. + Even as it dies, the GC may still want to scan the DFG::Plan, which leads to scanning + the DesiredWriteBarriers, which leads to scanning the InlineCallFrameSet. + + So, just make the darn thing refcounted. + + * bytecode/InlineCallFrameSet.h: + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGCommonData.h: + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + (JSC::DFG::Graph::requiredRegisterCountForExit): + * dfg/DFGGraph.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::Plan): + * dfg/DFGPlan.h: + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + * ftl/FTLFail.cpp: + (JSC::FTL::fail): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + +2014-04-17 Filip Pizlo <fpizlo@apple.com> + + FTL::fail() should manage memory "correctly" + https://bugs.webkit.org/show_bug.cgi?id=131823 + <rdar://problem/16384297> + + Reviewed by Oliver Hunt. + + * ftl/FTLFail.cpp: + (JSC::FTL::fail): + +2014-04-17 Filip Pizlo <fpizlo@apple.com> + + Prediction propagator should correctly model Int52s flowing through arguments + https://bugs.webkit.org/show_bug.cgi?id=131822 + <rdar://problem/16641408> + + Reviewed by Oliver Hunt. + + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * tests/stress/int52-argument.js: Added. + (foo): + * tests/stress/int52-variable.js: Added. + (foo): + +2014-04-17 Filip Pizlo <fpizlo@apple.com> + + REGRESSION: ASSERT(!typeInfo().hasImpureGetOwnPropertySlot() || typeInfo().newImpurePropertyFiresWatchpoints()) on jquery tests + https://bugs.webkit.org/show_bug.cgi?id=131798 + + Reviewed by Alexey Proskuryakov. + + Some day, we will fix https://bugs.webkit.org/show_bug.cgi?id=131810 and some version + of this assertion can return. For now, it's not clear that the assertion is guarding + any truly undesirable behavior - so it should just go away and be replaced with a + FIXME. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * runtime/Structure.h: + (JSC::Structure::takesSlowPathInDFGForImpureProperty): + +2014-04-17 David Kilzer <ddkilzer@apple.com> + + Blind attempt to fix Windows build after r166837 + <http://webkit.org/b/131246> + + Hoping to fix this build error: + + warning MSB8027: Two or more files with the name of GCLogging.cpp will produce outputs to the same location. This can lead to an incorrect build result. The files involved are ..\heap\GCLogging.cpp, ..\heap\GCLogging.cpp. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Fix copy-paste + boo-boo by changing the GCLogging.cpp ClCompile entry to a + GCLogging.h ClInclude entry. + +2014-04-16 Filip Pizlo <fpizlo@apple.com> + + AI for GetLocal should match the DFG backend, and in this case, the best way to do that is to get rid of the "exit if empty prediction" thing since it's a vestige of a time long gone + https://bugs.webkit.org/show_bug.cgi?id=131764 + + Reviewed by Geoffrey Garen. + + The attached test case can be made to not crash by deleting old code. It used to be + the case that the DFG needed empty prediction guards, for shady reasons. We fixed that + long ago. At this point, these guards just make life difficult. So get rid of them. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * tests/stress/bug-131764.js: Added. + (test1): + (test2): + +2014-04-17 Darin Adler <darin@apple.com> + + Add separate flag for IndexedDatabase in workers since the current implementation is not threadsafe + https://bugs.webkit.org/show_bug.cgi?id=131785 + rdar://problem/16003108 + + Reviewed by Brady Eidson. + + * Configurations/FeatureDefines.xcconfig: Added INDEXED_DATABASE_IN_WORKERS. + +2014-04-16 Alexey Proskuryakov <ap@apple.com> + + Build fix after http://trac.webkit.org/changeset/167416 (Sink NaN sanitization) + + * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::speculate): + +2014-04-16 Filip Pizlo <fpizlo@apple.com> + + Extra error reporting for invalid value conversions + https://bugs.webkit.org/show_bug.cgi?id=131786 + + Rubber stamped by Ryosuke Niwa. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + +2014-04-16 Filip Pizlo <fpizlo@apple.com> + + Sink NaN sanitization to uses and remove it when it's unnecessary + https://bugs.webkit.org/show_bug.cgi?id=131419 + + Reviewed by Oliver Hunt. + + This moves NaN purification to stores that could see an impure NaN. + + 5% speed-up on AsmBench, 50% speed-up on AsmBench/n-body. It is a regression on FloatMM + though, because of the other bug that causes that benchmark to box doubles in a loop. + + * bytecode/SpeculatedType.h: + (JSC::isInt32SpeculationForArithmetic): + (JSC::isMachineIntSpeculationForArithmetic): + (JSC::isDoubleSpeculation): + (JSC::isDoubleSpeculationForArithmetic): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::fixTypeForRepresentation): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileValueRep): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileValueRep): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + * runtime/PureNaN.h: + * tests/stress/float32-array-nan-inlined.js: Added. + (foo): + (test): + * tests/stress/float32-array-nan.js: Added. + (foo): + (test): + * tests/stress/float64-array-nan-inlined.js: Added. + (foo): + (isBigEndian): + (test): + * tests/stress/float64-array-nan.js: Added. + (foo): + (isBigEndian): + (test): + +2014-04-16 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed Windows gardening. Restrict our new 'isinf' check + to 32-bit builds, and revise the comment to explain what we are + doing. + + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::isMachineInt): Provide motivation for the new + 'isinf' check for our 32-bit code path. + +2014-04-16 Juergen Ributzka <juergen@apple.com> + + Allocate the data section on the heap again for FTL on ARM64 + https://bugs.webkit.org/show_bug.cgi?id=130156 + + Reviewed by Geoffrey Garen and Filip Pizlo. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLDataSection.cpp: + (JSC::FTL::DataSection::DataSection): + (JSC::FTL::DataSection::~DataSection): + * ftl/FTLDataSection.h: + +2014-04-16 Mark Lam <mark.lam@apple.com> + + Crash in CodeBlock::setOptimizationThresholdBasedOnCompilationResult() when the debugger activates. + <https://webkit.org/b/131747> + + Reviewed by Filip Pizlo. + + When the debugger is about to activate (e.g. enter stepping mode), it first + waits for all DFG compilations to complete. However, when the DFG completes, + if compilation is successful, it will install a new DFG codeBlock. The + CodeBlock installation process is required to register codeBlocks with the + debugger. Debugger::registerCodeBlock() will eventually call + CodeBlock::setSteppingMode() which may jettison the DFG codeBlock that we're + trying to install. Thereafter, chaos ensues. + + This jettison'ing only happens because the debugger currently set its + m_steppingMode flag before waiting for compilation to complete. The fix is + simply to set that flag only after compilation is complete. + + * debugger/Debugger.cpp: + (JSC::Debugger::setSteppingMode): + (JSC::Debugger::registerCodeBlock): + +2014-04-16 Filip Pizlo <fpizlo@apple.com> + + Discern between NaNs that would be safe to tag and NaNs that need some purification before tagging + https://bugs.webkit.org/show_bug.cgi?id=131420 + + Reviewed by Oliver Hunt. + + Rationalizes our handling of NaNs. We now have the notion of pureNaN(), or PNaN, which + replaces QNaN and represents a "safe" NaN for our tagging purposes. NaN purification now + goes through the purifyNaN() API. + + SpeculatedType and its clients can now distinguish between a PureNaN and an ImpureNaN. + + Prediction propagator is made slightly more cautious when dealing with NaNs. It doesn't + have to be too cautious since most prediction-based logic only cares about whether or not + a value could be an integer. + + AI is made much more cautious when dealing with NaNs. We don't yet introduce ImpureNaN + anywhere in the compiler, but when we do, we ought to be able to trust AI to propagate it + soundly and precisely. + + No performance change because this just unblocks + https://bugs.webkit.org/show_bug.cgi?id=131419. + + * API/JSValueRef.cpp: + (JSValueMakeNumber): + (JSValueToNumber): + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/SpeculatedType.cpp: + (JSC::dumpSpeculation): + (JSC::speculationFromValue): + (JSC::typeOfDoubleSum): + (JSC::typeOfDoubleDifference): + (JSC::typeOfDoubleProduct): + (JSC::polluteDouble): + (JSC::typeOfDoubleQuotient): + (JSC::typeOfDoubleMinMax): + (JSC::typeOfDoubleNegation): + (JSC::typeOfDoubleAbs): + (JSC::typeOfDoubleFRound): + (JSC::typeOfDoubleBinaryOp): + (JSC::typeOfDoubleUnaryOp): + * bytecode/SpeculatedType.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGCriticalEdgeBreakingPhase.cpp: + (JSC::DFG::CriticalEdgeBreakingPhase::breakCriticalEdge): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): + * dfg/DFGLoopPreHeaderCreationPhase.cpp: + (JSC::DFG::createPreHeader): + * dfg/DFGNode.h: + (JSC::DFG::BranchTarget::BranchTarget): + * dfg/DFGOSREntrypointCreationPhase.cpp: + (JSC::DFG::OSREntrypointCreationPhase::run): + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::speculatedDoubleTypeForPrediction): + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateJSArray): + (JSC::DFG::SpeculativeJIT::compileValueToInt32): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileArrayPush): + (JSC::FTL::LowerDFGToLLVM::compileArrayPop): + (JSC::FTL::LowerDFGToLLVM::compileNewArrayWithSize): + (JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32): + (JSC::FTL::LowerDFGToLLVM::allocateJSArray): + * ftl/FTLValueFormat.cpp: + (JSC::FTL::reboxAccordingToFormat): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::purifyNaN): + (JSC::AssemblyHelpers::sanitizeDouble): Deleted. + * jit/AssemblyHelpers.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitFloatTypedArrayGetByVal): + * runtime/DateConstructor.cpp: + (JSC::constructDate): + * runtime/DateInstanceCache.h: + (JSC::DateInstanceData::DateInstanceData): + (JSC::DateInstanceCache::reset): + * runtime/ExceptionHelpers.cpp: + (JSC::TerminatedExecutionError::defaultValue): + * runtime/JSArray.cpp: + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::shiftCountWithAnyIndexingType): + (JSC::JSArray::sortVector): + (JSC::JSArray::compactForSorting): + * runtime/JSArray.h: + (JSC::JSArray::create): + (JSC::JSArray::tryCreateUninitialized): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::toNumberSlowCase): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::jsNaN): + (JSC::JSValue::JSValue): + (JSC::JSValue::getPrimitiveNumber): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::parseInt): + (JSC::jsStrDecimalLiteral): + (JSC::toDouble): + (JSC::jsToNumber): + (JSC::parseFloat): + * runtime/JSObject.cpp: + (JSC::JSObject::createInitialDouble): + (JSC::JSObject::convertUndecidedToDouble): + (JSC::JSObject::convertInt32ToDouble): + (JSC::JSObject::deletePropertyByIndex): + (JSC::JSObject::ensureLengthSlow): + * runtime/MathObject.cpp: + (JSC::mathProtoFuncMax): + (JSC::mathProtoFuncMin): + * runtime/PureNaN.h: Added. + (JSC::pureNaN): + (JSC::isImpureNaN): + (JSC::purifyNaN): + * runtime/TypedArrayAdaptors.h: + (JSC::FloatTypedArrayAdaptor::toJSValue): + +2014-04-16 Juergen Ributzka <juergen@apple.com> + + Enable system library calls in FTL for ARM64 + https://bugs.webkit.org/show_bug.cgi?id=130154 + + Reviewed by Geoffrey Garen and Filip Pizlo. + + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLOutput.h: + (JSC::FTL::Output::doubleRem): + (JSC::FTL::Output::doubleSin): + (JSC::FTL::Output::doubleCos): + +2014-04-16 peavo@outlook.com <peavo@outlook.com> + + Fix JSC Debug Regressions on Windows + https://bugs.webkit.org/show_bug.cgi?id=131182 + + Reviewed by Brent Fulgham. + + The cast static_cast<int64_t>(number) in JSValue::isMachineInt() can generate a floating point error, + and set the st floating point register tags, if the value of the number parameter is infinite. + If the st floating point register tags are not cleared, this can cause strange floating point behavior later on. + This can be avoided by checking for infinity first. + + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::isMachineInt): Avoid floating point error by checking for infinity first. + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): Re-enable jit for Windows. + +2014-04-16 Oliver Hunt <oliver@apple.com> + + Simple ES6 feature:Array.prototype.fill + https://bugs.webkit.org/show_bug.cgi?id=131703 + + Reviewed by David Hyatt. + + Add support for Array.prototype.fill + + * builtins/Array.prototype.js: + (fill): + * runtime/ArrayPrototype.cpp: + +2014-04-16 Mark Hahnenberg <mhahnenberg@apple.com> + + [WebKit] Cleanup the build from uninitialized variable in JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=131728 + + Reviewed by Darin Adler. + + * runtime/JSObject.cpp: + (JSC::JSObject::genericConvertDoubleToContiguous): Add a RELEASE_ASSERT on the + path we expect to never take. Also shut up confused compilers about uninitialized things. + +2014-04-16 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, ARMv7 build fix after r167336. + + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::branchAdd32): + +2014-04-16 Gabor Rapcsanyi <rgabor@webkit.org> + + Unreviewed, ARM64 buildfix after r167336. + + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::branchAdd32): Add missing function. + +2014-04-15 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, add the obvious thing that marks MakeRope as exiting since it can exit. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + +2014-04-15 Filip Pizlo <fpizlo@apple.com> + + compileMakeRope does not emit necessary bounds checks + https://bugs.webkit.org/show_bug.cgi?id=130684 + <rdar://problem/16398388> + + Reviewed by Oliver Hunt. + + Add string length bounds checks in a bunch of places. We should never allow a string + to have a length greater than 2^31-1 because it's not clear that the language has + semantics for it and because there is code that assumes that this cannot happen. + + Also add a bunch of tests to that effect to cover the various ways in which this was + previously allowed to happen. + + * dfg/DFGOperations.cpp: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileMakeRope): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMakeRope): + * runtime/JSString.cpp: + (JSC::JSRopeString::RopeBuilder::expand): + * runtime/JSString.h: + (JSC::JSString::create): + (JSC::JSRopeString::RopeBuilder::append): + (JSC::JSRopeString::RopeBuilder::release): + (JSC::JSRopeString::append): + * runtime/Operations.h: + (JSC::jsString): + (JSC::jsStringFromRegisterArray): + (JSC::jsStringFromArguments): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncIndexOf): + (JSC::stringProtoFuncSlice): + (JSC::stringProtoFuncSubstring): + (JSC::stringProtoFuncToLowerCase): + * tests/stress/make-large-string-jit-strcat.js: Added. + (foo): + * tests/stress/make-large-string-jit.js: Added. + (foo): + * tests/stress/make-large-string-strcat.js: Added. + * tests/stress/make-large-string.js: Added. + +2014-04-15 Julien Brianceau <jbriance@cisco.com> + + Remove invalid sh4 specific code in JITInlines header. + https://bugs.webkit.org/show_bug.cgi?id=131692 + + Reviewed by Geoffrey Garen. + + * jit/JITInlines.h: + (JSC::JIT::callOperation): Prototype is not F_JITOperation_EJJZ + anymore since r160244, so the sh4 specific code is invalid now + and has to be removed. + +2014-04-15 Mark Hahnenberg <mhahnenberg@apple.com> + + Fix precedence issue in JSCell:setRemembered + + Rubber stamped by Filip Pizlo. + + * runtime/JSCell.h: + (JSC::JSCell::setRemembered): + +2014-04-15 Mark Hahnenberg <mhahnenberg@apple.com> + + Objective-C API external object graphs don't handle generational collection properly + https://bugs.webkit.org/show_bug.cgi?id=131634 + + Reviewed by Geoffrey Garen. + + If the set of Objective-C objects transitively reachable through an object changes, we + need to update the set of opaque roots accordingly. If we don't, the next EdenCollection + won't rescan the external object graph, which would lead us to consider a newly allocated + JSManagedValue to be dead. + + * API/JSBase.cpp: + (JSSynchronousEdenCollectForDebugging): + * API/JSVirtualMachine.mm: + (-[JSVirtualMachine initWithContextGroupRef:]): + (-[JSVirtualMachine dealloc]): + (-[JSVirtualMachine isOldExternalObject:]): + (-[JSVirtualMachine addExternalRememberedObject:]): + (-[JSVirtualMachine addManagedReference:withOwner:]): + (-[JSVirtualMachine removeManagedReference:withOwner:]): + (-[JSVirtualMachine externalRememberedSet]): + (scanExternalObjectGraph): + (scanExternalRememberedSet): + * API/JSVirtualMachineInternal.h: + * API/tests/testapi.mm: + * heap/Heap.cpp: + (JSC::Heap::markRoots): + * heap/Heap.h: + (JSC::Heap::slotVisitor): + * heap/SlotVisitor.h: + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::containsOpaqueRoot): + (JSC::SlotVisitor::containsOpaqueRootTriState): + +2014-04-15 Filip Pizlo <fpizlo@apple.com> + + DFG IR should keep the data flow of doubles and int52's separate from the data flow of JSValue's + https://bugs.webkit.org/show_bug.cgi?id=131423 + + Reviewed by Geoffrey Garen. + + This introduces more static typing into DFG IR. Previously we just had the notion of + JSValues and Storage. This was weird because doubles weren't always convertible to + JSValues, and Int52s weren't always convertible to either doubles or JSValues. We would + sort of insert explicit conversion nodes just for the places where we knew that an + implicit conversion wouldn't have been possible -- but there was no hard and fast rule so + we'd get bugs from forgetting to do the right conversion. + + This patch introduces a hard and fast rule: doubles can never be implicitly converted to + anything but doubles, and likewise Int52's can never be implicitly converted. Conversion + nodes are used for all of the conversions. Int52Rep, DoubleRep, and ValueRep are the + conversions. They are like Identity but return the same value using a different + representation. Likewise, constants may now be represented using either JSConstant, + Int52Constant, or DoubleConstant. UseKinds have been adjusted accordingly, as well. + Int52RepUse and DoubleRepUse are node uses that mean "the node must be of Int52 (or + Double) type". They don't imply checks. There is also DoubleRepRealUse, which means that + we speculate DoubleReal and expect Double representation. + + In addition to simplifying a bunch of rules in the IR and making the IR more verifiable, + this also makes it easier to introduce optimizations in the future. It's now possible for + AI to model when/how conversion take place. For example if doing a conversion results in + NaN sanitization, then AI can model this and can allow us to sink sanitizations. That's + what https://bugs.webkit.org/show_bug.cgi?id=131419 will be all about. + + This was a big change, so I had to do some interesting things, like finally get rid of + the DFG's weird variadic template macro hacks and use real C++11 variadic templates. Also + the ByteCodeParser no longer emits Identity nodes since that was always pointless. + + No performance change because this mostly just rationalizes preexisting behavior. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/MacroAssemblerX86.h: + * bytecode/CodeBlock.cpp: + * bytecode/CodeBlock.h: + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::setBuiltInConstant): + (JSC::DFG::AbstractInterpreter::setConstant): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::fixTypeForRepresentation): + (JSC::DFG::AbstractValue::checkConsistency): + * dfg/DFGAbstractValue.h: + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGBasicBlock.h: + * dfg/DFGBasicBlockInlines.h: + (JSC::DFG::BasicBlock::appendNode): + (JSC::DFG::BasicBlock::appendNonTerminal): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::constantCSE): + (JSC::DFG::CSEPhase::performNodeCSE): + (JSC::DFG::CSEPhase::int32ToDoubleCSE): Deleted. + * dfg/DFGCapabilities.h: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::fixupBlock): + * dfg/DFGEdge.h: + (JSC::DFG::Edge::willNotHaveCheck): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::run): + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixupGetAndSetLocalsInBlock): + (JSC::DFG::FixupPhase::observeUseKindOnNode): + (JSC::DFG::FixupPhase::fixIntEdge): + (JSC::DFG::FixupPhase::attemptToMakeIntegerAdd): + (JSC::DFG::FixupPhase::injectTypeConversionsInBlock): + (JSC::DFG::FixupPhase::tryToRelaxRepresentation): + (JSC::DFG::FixupPhase::fixEdgeRepresentation): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + (JSC::DFG::FixupPhase::addRequiredPhantom): + (JSC::DFG::FixupPhase::addPhantomsIfNecessary): + (JSC::DFG::FixupPhase::clearPhantomsAtEnd): + (JSC::DFG::FixupPhase::fixupSetLocalsInBlock): Deleted. + * dfg/DFGFlushFormat.h: + (JSC::DFG::resultFor): + (JSC::DFG::useKindFor): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addNode): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertNode): + (JSC::DFG::InsertionSet::insertConstant): + (JSC::DFG::InsertionSet::insertConstantForUse): + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::insertAdd): + (JSC::DFG::IntegerCheckCombiningPhase::insertMustAdd): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::convertToIdentity): + (WTF::printInternal): + * dfg/DFGNode.h: + (JSC::DFG::Node::Node): + (JSC::DFG::Node::setResult): + (JSC::DFG::Node::result): + (JSC::DFG::Node::isConstant): + (JSC::DFG::Node::hasConstant): + (JSC::DFG::Node::convertToConstant): + (JSC::DFG::Node::valueOfJSConstant): + (JSC::DFG::Node::hasResult): + (JSC::DFG::Node::hasInt32Result): + (JSC::DFG::Node::hasInt52Result): + (JSC::DFG::Node::hasNumberResult): + (JSC::DFG::Node::hasDoubleResult): + (JSC::DFG::Node::hasJSResult): + (JSC::DFG::Node::hasBooleanResult): + (JSC::DFG::Node::hasStorageResult): + (JSC::DFG::Node::defaultUseKind): + (JSC::DFG::Node::defaultEdge): + (JSC::DFG::Node::convertToIdentity): Deleted. + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + (JSC::DFG::canonicalResultRepresentation): + * dfg/DFGNodeType.h: + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGResurrectionForValidationPhase.cpp: + (JSC::DFG::ResurrectionForValidationPhase::run): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::silentSavePlanForGPR): + (JSC::DFG::SpeculativeJIT::silentSavePlanForFPR): + (JSC::DFG::SpeculativeJIT::silentFill): + (JSC::DFG::JSValueRegsTemporary::JSValueRegsTemporary): + (JSC::DFG::JSValueRegsTemporary::~JSValueRegsTemporary): + (JSC::DFG::JSValueRegsTemporary::regs): + (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch): + (JSC::DFG::SpeculativeJIT::checkGeneratedTypeForToInt32): + (JSC::DFG::SpeculativeJIT::compileValueToInt32): + (JSC::DFG::SpeculativeJIT::compileDoubleRep): + (JSC::DFG::SpeculativeJIT::compileValueRep): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compileAdd): + (JSC::DFG::SpeculativeJIT::compileArithSub): + (JSC::DFG::SpeculativeJIT::compileArithNegate): + (JSC::DFG::SpeculativeJIT::compileArithMul): + (JSC::DFG::SpeculativeJIT::compileArithDiv): + (JSC::DFG::SpeculativeJIT::compileArithMod): + (JSC::DFG::SpeculativeJIT::compare): + (JSC::DFG::SpeculativeJIT::compileStrictEq): + (JSC::DFG::SpeculativeJIT::speculateNumber): + (JSC::DFG::SpeculativeJIT::speculateDoubleReal): + (JSC::DFG::SpeculativeJIT::speculate): + (JSC::DFG::SpeculativeJIT::compileInt32ToDouble): Deleted. + (JSC::DFG::SpeculativeJIT::speculateMachineInt): Deleted. + (JSC::DFG::SpeculativeJIT::speculateRealNumber): Deleted. + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::allocate): + (JSC::DFG::SpeculativeJIT::use): + (JSC::DFG::SpeculativeJIT::boxDouble): + (JSC::DFG::SpeculativeJIT::spill): + (JSC::DFG::SpeculativeJIT::jsValueResult): + (JSC::DFG::SpeculateInt52Operand::SpeculateInt52Operand): + (JSC::DFG::SpeculateStrictInt52Operand::SpeculateStrictInt52Operand): + (JSC::DFG::SpeculateWhicheverInt52Operand::SpeculateWhicheverInt52Operand): + (JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::convertToDouble): Deleted. + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillJSValue): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + (JSC::DFG::SpeculativeJIT::compileLogicalNot): + (JSC::DFG::SpeculativeJIT::emitBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::convertToDouble): Deleted. + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + (JSC::DFG::shouldNotHaveTypeCheck): + (JSC::DFG::mayHaveTypeCheck): + (JSC::DFG::isNumerical): + (JSC::DFG::isDouble): + (JSC::DFG::isCell): + (JSC::DFG::usesStructure): + (JSC::DFG::useKindForResult): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGVariadicFunction.h: Removed. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::createPhiVariables): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileUpsilon): + (JSC::FTL::LowerDFGToLLVM::compilePhi): + (JSC::FTL::LowerDFGToLLVM::compileDoubleConstant): + (JSC::FTL::LowerDFGToLLVM::compileInt52Constant): + (JSC::FTL::LowerDFGToLLVM::compileWeakJSConstant): + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::compileValueRep): + (JSC::FTL::LowerDFGToLLVM::compileInt52Rep): + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): + (JSC::FTL::LowerDFGToLLVM::compileArithMul): + (JSC::FTL::LowerDFGToLLVM::compileArithDiv): + (JSC::FTL::LowerDFGToLLVM::compileArithMod): + (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): + (JSC::FTL::LowerDFGToLLVM::compileArithAbs): + (JSC::FTL::LowerDFGToLLVM::compileArithNegate): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compare): + (JSC::FTL::LowerDFGToLLVM::boolify): + (JSC::FTL::LowerDFGToLLVM::lowInt52): + (JSC::FTL::LowerDFGToLLVM::lowStrictInt52): + (JSC::FTL::LowerDFGToLLVM::lowWhicheverInt52): + (JSC::FTL::LowerDFGToLLVM::lowDouble): + (JSC::FTL::LowerDFGToLLVM::lowJSValue): + (JSC::FTL::LowerDFGToLLVM::strictInt52ToDouble): + (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateNumber): + (JSC::FTL::LowerDFGToLLVM::speculateDoubleReal): + (JSC::FTL::LowerDFGToLLVM::compileInt52ToValue): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileInt32ToDouble): Deleted. + (JSC::FTL::LowerDFGToLLVM::setInt52WithStrictValue): Deleted. + (JSC::FTL::LowerDFGToLLVM::speculateRealNumber): Deleted. + (JSC::FTL::LowerDFGToLLVM::speculateMachineInt): Deleted. + * ftl/FTLValueFormat.cpp: + (JSC::FTL::reboxAccordingToFormat): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::sanitizeDouble): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::boxDouble): + +2014-04-15 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r167199 and r167251. + https://bugs.webkit.org/show_bug.cgi?id=131678 + + Caused a DYEBench regression and does not seem to improve perf + on relevant websites (Requested by rniwa on #webkit). + + Reverted changesets: + + "Rewrite Function.bind as a builtin" + https://bugs.webkit.org/show_bug.cgi?id=131083 + http://trac.webkit.org/changeset/167199 + + "Update test result" + http://trac.webkit.org/changeset/167251 + +2014-04-14 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r167272. + https://bugs.webkit.org/show_bug.cgi?id=131666 + + Broke multiple tests (Requested by ap on #webkit). + + Reverted changeset: + + "Function.bind itself is too slow" + https://bugs.webkit.org/show_bug.cgi?id=131636 + http://trac.webkit.org/changeset/167272 + +2014-04-14 Geoffrey Garen <ggaren@apple.com> + + ASSERT when firing low memory warning + https://bugs.webkit.org/show_bug.cgi?id=131659 + + Reviewed by Mark Hahnenberg. + + * heap/Heap.cpp: + (JSC::Heap::deleteAllCompiledCode): Allow deleteAllCompiledCode to be + called when no GC is happening because that is what we do when a low + memory warning fires, and it is harmless. + +2014-04-14 Mark Hahnenberg <mhahnenberg@apple.com> + + emit_op_put_by_id should not emit a write barrier that filters on value + https://bugs.webkit.org/show_bug.cgi?id=131654 + + Reviewed by Filip Pizlo. + + The 32-bit implementation does this, and it can cause crashes if we later repatch the + code to allocate and store new Butterflies. + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitWriteBarrier): We also weren't verifying that the base was a cell on + 32-bit if we were passed ShouldFilterBase. I also took the liberty of sinking the tag + load down into the if statement so that we don't do it if we're not filtering on the value. + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_put_by_id): + +2014-04-14 Oliver Hunt <oliver@apple.com> + + Function.bind itself is too slow + https://bugs.webkit.org/show_bug.cgi?id=131636 + + Reviewed by Geoffrey Garen. + + Rather than forcing creation of an activation, we now store + bound function properties directly on the returned closure. + This is necessary to deal with code that creates many function + bindings, but does not call them very often. + + This is a 60% speed up in the included js/regress test. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * builtins/Function.prototype.js: + (bind.bindingFunction): + (bind.else.switch.case.1.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk): + (bind.else.switch.case.1.bindingFunction): + (bind.else.switch.case.2.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk): + (bind.else.switch.case.2.bindingFunction): + (bind.else.switch.case.3.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk): + (bind.else.switch.case.3.bindingFunction): + (bind.else.switch.bindingFunction): + (bind): + (bind.else.switch.case.1.bindingFunction.oversizedCall): Deleted. + (bind.else.switch.case.2.bindingFunction.oversizedCall): Deleted. + (bind.else.switch.case.3.bindingFunction.oversizedCall): Deleted. + * runtime/CommonIdentifiers.h: + +2014-04-14 Julien Brianceau <jbriance@cisco.com> + + [sh4] Allow use of SubImmediates in LLINT. + https://bugs.webkit.org/show_bug.cgi?id=131608 + + Reviewed by Mark Lam. + + Allow use of SubImmediates with const pool so the sh4 architecture can + share the arm path for setEntryAddress macro. It reduces architecture + specific code and lead to a more optimal generated code for sh4. + + * llint/LowLevelInterpreter.asm: + * offlineasm/sh4.rb: + +2014-04-14 Andreas Kling <akling@apple.com> + + Array.prototype.concat should allocate output storage only once. + <https://webkit.org/b/131609> + + Do a first pass across 'this' and any arguments to compute the + final size of the resulting array from Array.prototype.concat. + This avoids having to grow the output incrementally as we go. + + This also includes two other micro-optimizations: + + - Mark getProperty() with ALWAYS_INLINE. + + - Use JSArray::length() instead of taking the generic property + lookup path when we know an argument is an Array. + + My MBP says ~3% progression on Dromaeo/jslib-traverse-jquery. + + Reviewed by Oliver & Darin. + + * runtime/ArrayPrototype.cpp: + (JSC::getProperty): + (JSC::arrayProtoFuncConcat): + +2014-04-14 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r167249. + https://bugs.webkit.org/show_bug.cgi?id=131621 + + broke 3 tests on cloop (Requested by kling on #webkit). + + Reverted changeset: + + "Array.prototype.concat should allocate output storage only + once." + https://bugs.webkit.org/show_bug.cgi?id=131609 + http://trac.webkit.org/changeset/167249 + +2014-04-14 Alex Christensen <achristensen@webkit.org> + + Fixed potential integer truncation. + https://bugs.webkit.org/show_bug.cgi?id=131615 + + Reviewed by Darin Adler. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::fillNops): + Truncate the size_t to an unsigned after it is limited to 15 instead of before. + +2014-04-14 Andreas Kling <akling@apple.com> + + Array.prototype.concat should allocate output storage only once. + <https://webkit.org/b/131609> + + Do a first pass across 'this' and any arguments to compute the + final size of the resulting array from Array.prototype.concat. + This avoids having to grow the output incrementally as we go. + + This also includes two other micro-optimizations: + + - Mark getProperty() with ALWAYS_INLINE. + + - Use JSArray::length() instead of taking the generic property + lookup path when we know an argument is an Array. + + My MBP says ~3% progression on Dromaeo/jslib-traverse-jquery. + + Reviewed by Darin Adler. + + * runtime/ArrayPrototype.cpp: + (JSC::getProperty): + (JSC::arrayProtoFuncConcat): + +2014-04-14 Benjamin Poulain <benjamin@webkit.org> + + [JSC] Improve the call site of string comparison in some hot path + https://bugs.webkit.org/show_bug.cgi?id=131605 + + Reviewed by Darin Adler. + + When resolved, the String of a JSString is never null. It can be empty but not null. + The null value is reserved for ropes but those would be resolved when getting the value. + + Consequently, we should use the equal() operation that do not handle null values. + Using the StringImpl directly is already common in StringPrototype but it was not used here for some reason. + + * jit/JITOperations.cpp: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::equalSlowCaseInline): + (JSC::JSValue::strictEqualSlowCaseInline): + (JSC::JSValue::pureStrictEqual): + +2014-04-08 Oliver Hunt <oliver@apple.com> + + Rewrite Function.bind as a builtin + https://bugs.webkit.org/show_bug.cgi?id=131083 + + Reviewed by Geoffrey Garen. + + This change removes the existing function.bind implementation + entirely so JSBoundFunction is no more. + + Instead we just return a regular JS closure with a few + private properties hanging off it that allow us to perform + the necessary bound function fakery. While most of this is + simple, a couple of key changes: + + - The parser and lexer now directly track whether they're + parsing code for call or construct and convert the private + name @IsConstructor into TRUETOK or FALSETOK as appropriate. + This automatically gives us the ability to vary behaviour + from within the builtin. It also leaves a lot of headroom + for trivial future improvements. + - The instanceof operator now uses the prototypeForHasInstance + private name, and we have a helper function to ensure that + all objects that need to can update their magical 'prototype' + property pair correctly. + + * API/JSScriptRef.cpp: + (parseScript): + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * builtins/Function.prototype.js: + (bind.bindingFunction): + (bind.else.bindingFunction): + (bind): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + * bytecompiler/NodesCodegen.cpp: + (JSC::InstanceOfNode::emitBytecode): + * interpreter/Interpreter.cpp: + * parser/Lexer.cpp: + (JSC::Lexer<T>::Lexer): + (JSC::Lexer<LChar>::parseIdentifier): + (JSC::Lexer<UChar>::parseIdentifier): + * parser/Lexer.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + (JSC::Parser<LexerType>::parseInner): + * parser/Parser.h: + (JSC::parse): + * parser/ParserModes.h: + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + * runtime/CommonIdentifiers.h: + * runtime/Completion.cpp: + (JSC::checkSyntax): + * runtime/Executable.cpp: + (JSC::ProgramExecutable::checkSyntax): + * runtime/FunctionPrototype.cpp: + (JSC::FunctionPrototype::addFunctionProperties): + (JSC::functionProtoFuncBind): Deleted. + * runtime/JSBoundFunction.cpp: Removed. + * runtime/JSBoundFunction.h: Removed. + * runtime/JSFunction.cpp: + (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): + (JSC::RetrieveCallerFunctionFunctor::operator()): + (JSC::retrieveCallerFunction): + (JSC::JSFunction::getOwnPropertySlot): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncSetTypeErrorAccessor): + * runtime/JSGlobalObjectFunctions.h: + * runtime/JSObject.h: + (JSC::JSObject::inlineGetOwnPropertySlot): + +2014-04-12 Filip Pizlo <fpizlo@apple.com> + + Math.fround() should be an intrinsic + https://bugs.webkit.org/show_bug.cgi?id=131583 + + Reviewed by Geoffrey Garen. + + Makes programs that use Math.fround() run up to 6x faster. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileArithFRound): + * runtime/Intrinsic.h: + * runtime/MathObject.cpp: + (JSC::MathObject::finishCreation): + +2014-04-12 Filip Pizlo <fpizlo@apple.com> + + FTL should use stackmap register liveness + https://bugs.webkit.org/show_bug.cgi?id=130791 + + Reviewed by Goeffrey Garen. + + Enable the stackmap register liveness support by fixing the two last bugs: + + - If everything is dead after the patchpoint - a good possibility for a put_by_id - + then we shouldn't crash due to a null scratch buffer. + + - Always consider callee-saves as if they were live. More precisely, we should + consider those callee-saves that are not saved by the enclosing function to be live. + For now we do the much simpler thing and consider callee-saves to be always live + since it has minimal impact on the scratch register allocator. It will know not to + preserve those for calls, anyway. + + I tried writing a test for the null scratch buffer thing, but failed. I will land the + test anyway since it seems useful. + + * ftl/FTLCompile.cpp: + (JSC::FTL::usedRegistersFor): + * jit/ScratchRegisterAllocator.cpp: + (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall): + (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall): + * runtime/Options.h: + * tests/stress/repeated-put-by-id-reallocating-transition.js: Added. + (foo): + +2014-04-11 Filip Pizlo <fpizlo@apple.com> + + DFG::FixupPhase should insert conversion nodes after the rest of fixup so that we know how the types settled + https://bugs.webkit.org/show_bug.cgi?id=131424 + + Reviewed by Geoffrey Garen. + + This defers type conversion injection until we've decided on types. This makes the + process of deciding types a bit more flexible - for example we can naturally fixpoint + and change our minds. Only when things are settled do we actually insert conversions. + + This is a necessary prerequisite for keeping double, int52, and JSValue data flow + separate. A SetLocal/GetLocal will appear to be JSValue until we fixpoint and realize + that there are typed uses. If we were eagerly inserting type conversions then we would + first insert a to/from-JSValue conversion in some cases only to then replace it by + the other conversions. It's probably trivial to remove those redundant conversions later + but I think it's better if we don't insert them to begin with. + + * bytecode/CodeOrigin.h: + (JSC::CodeOrigin::operator!): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::run): + (JSC::DFG::FixupPhase::fixupBlock): + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixupSetLocalsInBlock): + (JSC::DFG::FixupPhase::fixEdge): + (JSC::DFG::FixupPhase::fixIntEdge): + (JSC::DFG::FixupPhase::injectTypeConversionsInBlock): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + (JSC::DFG::FixupPhase::addRequiredPhantom): + (JSC::DFG::FixupPhase::addPhantomsIfNecessary): + (JSC::DFG::FixupPhase::clearPhantomsAtEnd): + (JSC::DFG::FixupPhase::observeUntypedEdge): Deleted. + (JSC::DFG::FixupPhase::fixupUntypedSetLocalsInBlock): Deleted. + (JSC::DFG::FixupPhase::injectInt32ToDoubleNode): Deleted. + +2014-04-11 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: code generator should consider enclosing class when computing duplicate type names + https://bugs.webkit.org/show_bug.cgi?id=131554 + + Reviewed by Timothy Hatcher. + + We need to prepend an enum's enclosing class, if any, so that multiple enums with the same name + can coexist without triggering a "duplicate types" error. Now, such enums must be referenced + by the enclosing class and enum name. + + Added tests for the new syntax, and rebaselined one test to reflect a previous patch's change. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (Type.type_name): Prepend the enclosing class name. + (Type.type_name.is): + * replay/scripts/tests/expected/fail-on-duplicate-enum-type.json-error: Added. + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.cpp: Added. + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.h: Added. + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.h: Rebaseline. + * replay/scripts/tests/fail-on-duplicate-enum-type.json: Added. + * replay/scripts/tests/generate-enums-with-same-base-name.json: Added. + +2014-04-11 Gavin Barraclough <baraclough@apple.com> + + Rollout - Rewrite Function.bind as a builtin + https://bugs.webkit.org/show_bug.cgi?id=131083 + + Unreviewed. + + Rolling out r167020 while investigating a performance regression. + + * API/JSObjectRef.cpp: + (JSObjectMakeConstructor): + * API/JSScriptRef.cpp: + (parseScript): + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * builtins/Function.prototype.js: + (apply): + (bind.bindingFunction): Deleted. + (bind.else.bindingFunction): Deleted. + (bind): Deleted. + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + * bytecompiler/NodesCodegen.cpp: + (JSC::InstanceOfNode::emitBytecode): + * interpreter/Interpreter.cpp: + * parser/Lexer.cpp: + (JSC::Lexer<T>::Lexer): + (JSC::Lexer<LChar>::parseIdentifier): + (JSC::Lexer<UChar>::parseIdentifier): + * parser/Lexer.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + (JSC::Parser<LexerType>::parseInner): + * parser/Parser.h: + (JSC::parse): + * parser/ParserModes.h: + * runtime/ArgumentsIteratorConstructor.cpp: + (JSC::ArgumentsIteratorConstructor::finishCreation): + * runtime/ArrayConstructor.cpp: + (JSC::ArrayConstructor::finishCreation): + * runtime/BooleanConstructor.cpp: + (JSC::BooleanConstructor::finishCreation): + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + * runtime/CommonIdentifiers.h: + * runtime/Completion.cpp: + (JSC::checkSyntax): + * runtime/DateConstructor.cpp: + (JSC::DateConstructor::finishCreation): + * runtime/ErrorConstructor.cpp: + (JSC::ErrorConstructor::finishCreation): + * runtime/Executable.cpp: + (JSC::ProgramExecutable::checkSyntax): + * runtime/FunctionConstructor.cpp: + (JSC::FunctionConstructor::finishCreation): + * runtime/FunctionPrototype.cpp: + (JSC::FunctionPrototype::addFunctionProperties): + (JSC::functionProtoFuncBind): + * runtime/JSArrayBufferConstructor.cpp: + (JSC::JSArrayBufferConstructor::finishCreation): + * runtime/JSBoundFunction.cpp: Added. + (JSC::boundFunctionCall): + (JSC::boundFunctionConstruct): + (JSC::JSBoundFunction::create): + (JSC::JSBoundFunction::destroy): + (JSC::JSBoundFunction::customHasInstance): + (JSC::JSBoundFunction::JSBoundFunction): + (JSC::JSBoundFunction::finishCreation): + (JSC::JSBoundFunction::visitChildren): + * runtime/JSBoundFunction.h: Added. + (JSC::JSBoundFunction::targetFunction): + (JSC::JSBoundFunction::boundThis): + (JSC::JSBoundFunction::boundArgs): + (JSC::JSBoundFunction::createStructure): + * runtime/JSFunction.cpp: + (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): + (JSC::RetrieveCallerFunctionFunctor::operator()): + (JSC::retrieveCallerFunction): + (JSC::JSFunction::getOwnPropertySlot): + (JSC::JSFunction::getOwnNonIndexPropertyNames): + (JSC::JSFunction::put): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSGenericTypedArrayViewConstructorInlines.h: + (JSC::JSGenericTypedArrayViewConstructor<ViewClass>::finishCreation): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncSetTypeErrorAccessor): Deleted. + * runtime/JSGlobalObjectFunctions.h: + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectPrototypeProperty): Deleted. + (JSC::JSObject::putDirectPrototypePropertyWithoutTransitions): Deleted. + * runtime/JSObject.h: + * runtime/JSPromiseConstructor.cpp: + (JSC::JSPromiseConstructor::finishCreation): + * runtime/MapConstructor.cpp: + (JSC::MapConstructor::finishCreation): + * runtime/MapIteratorConstructor.cpp: + (JSC::MapIteratorConstructor::finishCreation): + * runtime/NameConstructor.cpp: + (JSC::NameConstructor::finishCreation): + * runtime/NativeErrorConstructor.cpp: + (JSC::NativeErrorConstructor::finishCreation): + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::finishCreation): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::finishCreation): + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::finishCreation): + * runtime/SetConstructor.cpp: + (JSC::SetConstructor::finishCreation): + * runtime/SetIteratorConstructor.cpp: + (JSC::SetIteratorConstructor::finishCreation): + * runtime/StringConstructor.cpp: + (JSC::StringConstructor::finishCreation): + * runtime/WeakMapConstructor.cpp: + (JSC::WeakMapConstructor::finishCreation): + +2014-04-11 David Kilzer <ddkilzer@apple.com> + + [ASan] Build broke because libCompileRuntimeToLLVMIR.a links to libclang_rt.asan_osx_dynamic.dylib + <http://webkit.org/b/131556> + <rdar://problem/16591856> + + Reviewed by Brent Fulgham. + + * Configurations/CompileRuntimeToLLVMIR.xcconfig: Clear + OTHER_LDFLAGS so the ASan build does not try to link to + libclang_rt.asan_osx_dynamic.dylib. + +2014-04-11 Mark Lam <mark.lam@apple.com> + + JSMainThreadExecState::call() should clear exceptions before returning. + <https://webkit.org/b/131530> + + Reviewed by Geoffrey Garen. + + Added a version of JSC::call() that return any uncaught exception instead + of leaving it pending in the VM. + + As part of this change, I updated various parts of the code base to use the + new API as needed. + + * bindings/ScriptFunctionCall.cpp: + (Deprecated::ScriptFunctionCall::call): + - ScriptFunctionCall::call() is only used by the inspector to inject scripts. + The injected scripts that will include Inspector scripts that should catch + and handle any exceptions that were thrown. We should not be seeing any + exceptions returned from this call. However, we do have checks for + exceptions in case there are bugs in the Inspector scripts which allowed + the exception to leak through. Hence, it is proper to clear the exception + here, and only record the fact that an exception was seen (if present). + + * bindings/ScriptFunctionCall.h: + * inspector/InspectorEnvironment.h: + * runtime/CallData.cpp: + (JSC::call): + * runtime/CallData.h: + +2014-04-11 Oliver Hunt <oliver@apple.com> + + Add BuiltinLog function to make debugging builtins easier + https://bugs.webkit.org/show_bug.cgi?id=131550 + + Reviewed by Andreas Kling. + + Add a logging function that builtins can use for debugging. + + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncBuiltinLog): + * runtime/JSGlobalObjectFunctions.h: + +2014-04-11 Julien Brianceau <jbriance@cisco.com> + + Fix LLInt for sh4 architecture (broken since C stack merge). + https://bugs.webkit.org/show_bug.cgi?id=131532 + + Reviewed by Mark Lam. + + This patch fixes build and also implements sh4 parts for initPCRelative and + setEntryAddress macros introduced in http://trac.webkit.org/changeset/167094. + + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * offlineasm/instructions.rb: + * offlineasm/sh4.rb: + +2014-04-10 Michael Saboff <msaboff@apple.com> + + Crash beneath DFG JIT code @ video.disney.com + https://bugs.webkit.org/show_bug.cgi?id=131447 + + Reviewed by Geoffrey Garen. + + The 32-bit path of speculateMisc() uses an 'is not int32' check followed by + 'tag not less than Undefined' check. The first check was incorrectly elided if we + knew that the value *was* an int32, when it should have been elided if we already + knew that the value *was not* an int32. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::speculateMisc): + * tests/stress/test-spec-misc.js: Added test. + (getX): + (foo): + (bar): + +2014-04-08 Filip Pizlo <fpizlo@apple.com> + + Make room for additional types in SpeculatedType.h + https://bugs.webkit.org/show_bug.cgi?id=131422 + + Reviewed by Sam Weinig. + + This'll make it easier to add DoubleHeavyNaN and DoubleEmptyNaN. + + * bytecode/SpeculatedType.h: + +2014-04-10 Alex Christensen <achristensen@webkit.org> + + Compile fix for Win64. + https://bugs.webkit.org/show_bug.cgi?id=131508 + + Reviewed by Geoffrey Garen. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::fillNops): + Added unsigned template parameter to distinguish between size_t and unsigned long. + +2014-04-10 Michael Saboff <msaboff@apple.com> + + LLInt interpreter code should be generated as part of one function + https://bugs.webkit.org/show_bug.cgi?id=131205 + + Reviewed by Mark Lam. + + Changed the generation of llint opcodes so that they are all part of the same + global function, llint_entry. That function is used to fill in an entry point + table that includes each of the opcodes and helpers. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.sh: + * JavaScriptCore.xcodeproj/project.pbxproj: + Added appropriate use of new -I option to offline assembler and offset + generator scripts. + + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter.cpp: + * llint/LowLevelInterpreter.h: + * offlineasm/arm.rb: + * offlineasm/arm64.rb: + * offlineasm/asm.rb: + * offlineasm/ast.rb: + * offlineasm/backends.rb: + * offlineasm/cloop.rb: + * offlineasm/generate_offset_extractor.rb: + * offlineasm/instructions.rb: + * offlineasm/parser.rb: + * offlineasm/registers.rb: + * offlineasm/self_hash.rb: + * offlineasm/settings.rb: + * offlineasm/transform.rb: + * offlineasm/x86.rb: + Added a new "global" keyword to the offline assembler that denotes a label that + should be exported. Added opcode and operand support to get the absolute + address of a local label using position independent calculations. Updated the + offline assembler to handle included files, both when generating the checksum + as well as including files from other than the local directory via a newly + added -I option. The offline assembler now automatically determines external + functions by keeping track of referenced functions that are defined within the + assembly source. This is used both for choosing the correct macro for external + references as well as generating the needed EXTERN directives for masm. + Updated the generation of the masm only .sym file to be written once at the end + of the offline assembler. + + * assembler/MacroAssemblerCodeRef.h: + (JSC::MacroAssemblerCodePtr::createLLIntCodePtr): + (JSC::MacroAssemblerCodeRef::createLLIntCodeRef): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JITStubs.h: + * llint/LLIntCLoop.cpp: + (JSC::LLInt::initialize): + * llint/LLIntData.h: + (JSC::LLInt::getCodeFunctionPtr): + (JSC::LLInt::getOpcode): Deleted. + (JSC::LLInt::getCodePtr): Deleted. + * llint/LLIntOpcode.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntThunks.cpp: + (JSC::LLInt::functionForCallEntryThunkGenerator): + (JSC::LLInt::functionForConstructEntryThunkGenerator): + (JSC::LLInt::functionForCallArityCheckThunkGenerator): + (JSC::LLInt::functionForConstructArityCheckThunkGenerator): + (JSC::LLInt::evalEntryThunkGenerator): + (JSC::LLInt::programEntryThunkGenerator): + * llint/LLIntThunks.h: + Changed references to llint helpers to go through the entry point table populated + by llint_entry. Added helpers to OpcodeID enum for all builds. + + * bytecode/BytecodeList.json: + * generate-bytecode-files: + * llint/LLIntCLoop.cpp: + (JSC::LLInt::CLoop::initialize): + Reordered sections to match the order that the functions are added to the entry point + table. Added new "asmPrefix" property for symbols that have one name but are generated + with a prefix, e.g. op_enter -> llint_op_enter. Eliminated the "emitDefineID" property + as we are using enums for all bytecode references. Changed the C Loop only + llint_c_loop_init to llint_entry. + +2014-04-10 Matthew Mirman <mmirman@apple.com> + + WIP for inlining C++. Added a build target to produce LLVM IR. + https://bugs.webkit.org/show_bug.cgi?id=130523 + + Reviewed by Mark Rowe. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * build-symbol-table-index.py: Added. + * build-symbol-table-index.sh: Added. + * Configurations/CompileRuntimeToLLVMIR.xcconfig: Added. + * copy-llvm-ir-to-derived-sources.sh: Added. + +2014-04-10 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: memoize plugin data for navigator.mimeTypes and navigator.plugins + https://bugs.webkit.org/show_bug.cgi?id=131341 + + Reviewed by Timothy Hatcher. + + Add support for encoding/decoding unsigned long with EncodedValue. + It is a distinct type from uint32_t and uint64_t. + + * replay/EncodedValue.cpp: + (JSC::EncodedValue::convertTo<unsigned long>): + * replay/EncodedValue.h: + +2014-04-10 Mark Lam <mark.lam@apple.com> + + LLINT loadisFromInstruction should handle the big endian case. + <https://webkit.org/b/131495> + + Reviewed by Mark Hahnenberg. + + The LLINT loadisFromInstruction macro aims to load the least significant + 32-bit word from the 64-bit bytecode instruction stream and sign extend + it. For big endian machines, the current implementation would load the + wrong 32-bit word. + + Without this fix, the JSC tests will crash on big endian machines. + Thanks to Tomas Popela for diagnosing this issue. + + * llint/LowLevelInterpreter.asm: + +2014-04-09 Mark Lam <mark.lam@apple.com> + + Temporarily disable the JIT for the Windows port. + <https://webkit.org/b/131470> + + Reviewed by Brent Fulgham. + + This is a temporary stop gap measure to green the Windows bots until + we have a fix for https://webkit.org/b/131182. + + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + +2014-04-09 Juergen Ributzka <juergen@apple.com> + + [FTL] Emit multibyte NOPs on X86-64 + https://bugs.webkit.org/show_bug.cgi?id=131394 + + Reviewed by Michael Saboff. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::fillNops): + +2014-04-09 Julien Brianceau <jbriance@cisco.com> + + Get rid of JITOperationWrappers.h header file. + https://bugs.webkit.org/show_bug.cgi?id=131450 + + Reviewed by Michael Saboff. + + JITOperationWrappers header file contains architecture specific code that is + not needed anymore, so get rid of it. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGOperations.cpp: + * jit/JITOperationWrappers.h: Removed. + * jit/JITOperations.cpp: + +2014-04-09 Mark Lam <mark.lam@apple.com> + + Ensure that LLINT accessing of the ProtoCallFrame is big endian friendly. + <https://webkit.org/b/131449> + + Reviewed by Mark Hahnenberg. + + Change ProtoCallFrame::paddedArgCount to be of type uint32_t. The argCount + that it pads is of type int anyway. It doesn't need to be 64 bit. This + also makes it work with the LLINT which is loading it with a loadi + instruction. + + We should add the PayLoadOffset to ProtoCallFrame::argCountAndCodeOriginValue + when loading the argCount. + + The paddedArgCount issue was causing failures when running the JSC tests on a + 64-bit big endian machine. In this case, the paddedArgCount in the + ProtoCallFrame has the value 2. However, because the paddedArgCount was stored + as a 64-bit size_t and the LLINT was loading only the low address 32-bits of + that field, the LLINT got a value of 0 instead of the expected 2. With this + patch, we now have a matching store and load of a 32-bit value, and endianness + no longer comes into play. + + As for ProtoCallFrame::argCountAndCodeOriginValue, the argCount is stored in + the payload field of the Register. In the definition of EncodedValueDescriptor, + We already ensure that that the payload is in the least significant 32-bits for + little endian machines, and in the most significant 32-bits for big endian + machines. This means that there is no endianness bug when loading this value + using loadi. However, adding the PayLoadOffset clarifies the intent of the + code to load the payload part of the Register value. + + * interpreter/ProtoCallFrame.h: + (JSC::ProtoCallFrame::setPaddedArgCount): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-04-08 Oliver Hunt <oliver@apple.com> + + Rewrite Function.bind as a builtin + https://bugs.webkit.org/show_bug.cgi?id=131083 + + Reviewed by Geoffrey Garen. + + This change removes the existing function.bind implementation + entirely so JSBoundFunction is no more. + + Instead we just return a regular JS closure with a few + private properties hanging off it that allow us to perform + the necessary bound function fakery. While most of this is + simple, a couple of key changes: + + - The parser and lexer now directly track whether they're + parsing code for call or construct and convert the private + name @IsConstructor into TRUETOK or FALSETOK as appropriate. + This automatically gives us the ability to vary behaviour + from within the builtin. It also leaves a lot of headroom + for trivial future improvements. + - The instanceof operator now uses the prototypeForHasInstance + private name, and we have a helper function to ensure that + all objects that need to can update their magical 'prototype' + property pair correctly. + + * API/JSScriptRef.cpp: + (parseScript): + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * builtins/Function.prototype.js: + (bind.bindingFunction): + (bind.else.bindingFunction): + (bind): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + * bytecompiler/NodesCodegen.cpp: + (JSC::InstanceOfNode::emitBytecode): + * interpreter/Interpreter.cpp: + * parser/Lexer.cpp: + (JSC::Lexer<T>::Lexer): + (JSC::Lexer<LChar>::parseIdentifier): + (JSC::Lexer<UChar>::parseIdentifier): + * parser/Lexer.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + (JSC::Parser<LexerType>::parseInner): + * parser/Parser.h: + (JSC::parse): + * parser/ParserModes.h: + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + * runtime/CommonIdentifiers.h: + * runtime/Completion.cpp: + (JSC::checkSyntax): + * runtime/Executable.cpp: + (JSC::ProgramExecutable::checkSyntax): + * runtime/FunctionPrototype.cpp: + (JSC::FunctionPrototype::addFunctionProperties): + (JSC::functionProtoFuncBind): Deleted. + * runtime/JSBoundFunction.cpp: Removed. + * runtime/JSBoundFunction.h: Removed. + * runtime/JSFunction.cpp: + (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): + (JSC::RetrieveCallerFunctionFunctor::operator()): + (JSC::retrieveCallerFunction): + (JSC::JSFunction::getOwnPropertySlot): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncSetTypeErrorAccessor): + * runtime/JSGlobalObjectFunctions.h: + * runtime/JSObject.h: + (JSC::JSObject::inlineGetOwnPropertySlot): + +2014-04-08 Jon Lee <jonlee@apple.com> + + Turn MSE on by default + https://bugs.webkit.org/show_bug.cgi?id=131313 + <rdar://problem/16525223> + + Reviewed by Jer Noble. + + * Configurations/FeatureDefines.xcconfig: + +2014-04-08 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Prevent deadlocks receiving WIRPermissionDenied message + https://bugs.webkit.org/show_bug.cgi?id=131406 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::stop): + (Inspector::RemoteInspector::stopInternal): + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + Provide a way to stop externally and a path to stop when in + the middle of handling a message already with the locked mutex. + + * inspector/remote/RemoteInspectorXPCConnection.h: + * inspector/remote/RemoteInspectorXPCConnection.mm: + (Inspector::RemoteInspectorXPCConnection::close): + (Inspector::RemoteInspectorXPCConnection::closeFromMessage): + Provide a way to close externally and a path to close when in + the middle of handling a message already with a mutex. + +2014-04-08 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Address stale FIXMEs concerning console in JSContext inspection + https://bugs.webkit.org/show_bug.cgi?id=131398 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + The console object can be deleted from a page or JSContext, + so keep code that expects that it could have been deleted + to be resilient in those cases. + + * inspector/JSGlobalObjectScriptDebugServer.h: + * inspector/agents/JSGlobalObjectDebuggerAgent.h: + * inspector/agents/JSGlobalObjectRuntimeAgent.h: + Change the FIXMEs to NOTEs that explain why these functions + have empty implementations for JSContext inspection. + +2014-04-08 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix a goofy assertion to fix debug. + + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::isSetter): + (JSC::PutByIdAccess::oldStructure): + (JSC::PutByIdAccess::chain): + (JSC::PutByIdAccess::stubRoutine): + (JSC::PutByIdAccess::customSetter): + +2014-04-08 Filip Pizlo <fpizlo@apple.com> + + Fail silently if the LLVM dylib isn't found + https://bugs.webkit.org/show_bug.cgi?id=131385 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * llvm/InitializeLLVM.cpp: + (JSC::initializeLLVM): + * llvm/InitializeLLVM.h: + * llvm/InitializeLLVMPOSIX.cpp: + (JSC::initializeLLVMPOSIX): + +2014-04-07 Filip Pizlo <fpizlo@apple.com> + + Repatch should support setters and plant calls to them directly + https://bugs.webkit.org/show_bug.cgi?id=130750 + + Reviewed by Geoffrey Garen. + + All of the infrastructure was in place so this just enables setter optimization. + + This is a 12x speed-up on setter microbenchmarks. This is a 1% speed-up on Octane. + + * bytecode/PolymorphicPutByIdList.cpp: + (JSC::PutByIdAccess::visitWeak): + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::setter): + (JSC::PutByIdAccess::customSetter): Deleted. + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + * jit/Repatch.cpp: + (JSC::toString): + (JSC::kindFor): + (JSC::customFor): + (JSC::generateByIdStub): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * runtime/JSObject.cpp: + (JSC::JSObject::put): + * runtime/Lookup.h: + (JSC::putEntry): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::setCacheableSetter): + (JSC::PutPropertySlot::isCacheableSetter): + (JSC::PutPropertySlot::isCacheableCustom): + (JSC::PutPropertySlot::setCacheableCustomProperty): Deleted. + (JSC::PutPropertySlot::isCacheableCustomProperty): Deleted. + * tests/stress/setter.js: Added. + (foo): + +2014-04-07 Filip Pizlo <fpizlo@apple.com> + + Setters are just getters that take an extra argument and don't return a value + https://bugs.webkit.org/show_bug.cgi?id=131336 + + Reviewed by Geoffrey Garen. + + Other than that, they're totally the same thing. + + This isn't as dumb as it sounds. + + Most of the work in calling an accessor has to do with emitting the necessary checks for + figuring out whether we're calling the accessor we expected, followed by the boilerplate + needed for setting up a call inside of a stub. It makes sense for the code to be totally + common. + + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::storeValue): + (JSC::AssemblyHelpers::moveTrustedValue): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupResults): + * jit/Repatch.cpp: + (JSC::kindFor): + (JSC::customFor): + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + (JSC::generateGetByIdStub): Deleted. + (JSC::emitCustomSetterStub): Deleted. + * runtime/JSCJSValue.h: + (JSC::JSValue::asValue): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::cachedOffset): + +2014-04-07 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Hang in debuggable application after receiving WIRPermissionDenied + https://bugs.webkit.org/show_bug.cgi?id=131321 + + Reviewed by Mark Rowe. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::xpcConnectionReceivedMessage): + Avoid attempting to take the same lock twice. Move the received message + lock grab after the WIRPermissionDenied branch, which takes the lock + inside RemoteInspector::stop. + +2014-04-07 Filip Pizlo <fpizlo@apple.com> + + Make it possible to disable some of the FTL's more interesting features + https://bugs.webkit.org/show_bug.cgi?id=131312 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parse): + * runtime/Options.h: + +2014-04-04 Mark Lam <mark.lam@apple.com> + + Date object needs to check for ES5 15.9.1.14 TimeClip limit. + <https://webkit.org/b/131248> + + Reviewed by Mark Hahnenberg. + + The current Date object code does not adequately check for the ES5 + 15.9.1.14 TimeClip limit. As a result, some calculations can underflow + / overflow and produce unexpected results. + + For example, we were getting an assertion failure in + WTF::equivalentYearForDST() due int underflows in this function, which + in turn were due to an int overflow in WTF::msToYear(). + + This patch adds the needed checks, and adds some assertions to ensure + that the used values are sane. + + The changes have no noticeable impact on benchmark results. + + * runtime/DateConstructor.cpp: + (JSC::callDate): + * runtime/JSDateMath.cpp: + (JSC::localTimeOffset): + (JSC::gregorianDateTimeToMS): + (JSC::msToGregorianDateTime): + (JSC::parseDateFromNullTerminatedCharacters): + (JSC::parseDate): + * runtime/JSDateMath.h: + - parseDateFromNullTerminatedCharacters() does not need to be public. + Made it a static function. + * runtime/VM.cpp: + (JSC::VM::resetDateCache): + - Changed cachedDateStringValue to use std::numeric_limits<double>::quiet_NaN() + to be consistent with other Date code. + +2014-04-06 Csaba Osztrogonác <ossy@webkit.org> + + Unreviewed speculative 32-bit buildfix after r166837. + + * heap/Heap.cpp: + (JSC::Heap::updateObjectCounts): + +2014-04-06 Dan Bernstein <mitz@apple.com> + + 32-bit build fix. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::setInputCursor): + +2014-04-04 Brian J. Burg <burg@cs.washington.edu> + + Enable WEB_REPLAY for PLATFORM(MAC) + https://bugs.webkit.org/show_bug.cgi?id=130700 + + Reviewed by Timothy Hatcher. + + * Configurations/FeatureDefines.xcconfig: + +2014-04-05 Mark Hahnenberg <mhahnenberg@apple.com> + + Add missing files from r166837 + + * heap/GCLogging.cpp: Added. + (JSC::GCLogging::levelAsString): + (JSC::LoggingFunctor::LoggingFunctor): + (JSC::LoggingFunctor::~LoggingFunctor): + (JSC::LoggingFunctor::operator()): + (JSC::LoggingFunctor::log): + (JSC::LoggingFunctor::reviveCells): + (JSC::LoggingFunctor::returnValue): + (JSC::GCLogging::dumpObjectGraph): + * heap/GCLogging.h: Added. + +2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com> + + Enhanced GC logging + https://bugs.webkit.org/show_bug.cgi?id=131246 + + Reviewed by Geoff Garen. + + Getting data on the state of the JSC Heap at runtime is currently in a sad state. + The OBJECT_MARK_LOGGING macro enables some basic GC logging, but it requires a full + recompile to turn it on. It would be nice if we could runtime enable our GC logging + infrastructure while incurring minimal cost when it is disabled. + + It would also be nice to get a complete view of the Heap. Currently OBJECT_MARK_LOGGING + provides us with the discovered roots along with parent-child relationships as objects + are scanned. However, once an object is scanned it will never be declared as the child + of another object during that collection. This gives us a tree-like view of the + Heap (i.e. each scanned node only reports having a single parent), where the actual + Heap can be an arbitrary graph. + + This patch replaces OBJECT_MARK_LOGGING and gives us these nice to haves. First it enhances + our logGC() runtime Option by changing it to be a tri-state value of None, Basic, or Verbose + logging levels. None means no logging is done, Basic is what logGC() = true would have done + prior to this patch, and Verbose logs all object relationships. + + JSCell has new dump/dumpToStream methods, the latter of which is "virtual" to allow + subclasses to override the default string representation that will be dumped. These + methods allow JSCells to be dumped using the standard dataLog() calls similar to much of + the logging infrastructure in our compilers. + + This patch also adds a GCLogging class that handles dumping the relationships between objects. + It does this by using the pre-existing visitChildren virtual methods to obtain the immediate + children of each live cell at the end of garbage collection. + + This change meets our goal of being neutral on the benchmarks we track. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/GCLogging.cpp: Added. + (JSC::GCLogging::levelAsString): + (JSC::LoggingFunctor::LoggingFunctor): + (JSC::LoggingFunctor::operator()): + (JSC::LoggingFunctor::log): + (JSC::LoggingFunctor::reviveCells): + (JSC::LoggingFunctor::returnValue): + (JSC::GCLogging::dumpObjectGraph): + * heap/GCLogging.h: Added. + * heap/GCSegmentedArray.h: + (JSC::GCSegmentedArray::begin): + (JSC::GCSegmentedArray::end): + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::visitSmallStrings): + (JSC::Heap::visitConservativeRoots): + (JSC::Heap::visitCompilerWorklists): + (JSC::Heap::visitProtectedObjects): + (JSC::Heap::visitTempSortVectors): + (JSC::Heap::visitArgumentBuffers): + (JSC::Heap::visitException): + (JSC::Heap::visitStrongHandles): + (JSC::Heap::visitHandleStack): + (JSC::Heap::traceCodeBlocksAndJITStubRoutines): + (JSC::Heap::visitWeakHandles): + (JSC::Heap::updateObjectCounts): + (JSC::Heap::collect): + (JSC::Heap::didFinishCollection): + * heap/Heap.h: + * heap/MarkStack.h: + * heap/SlotVisitor.cpp: + (JSC::SlotVisitor::dump): + * heap/SlotVisitor.h: + (JSC::SlotVisitor::markStack): + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::internalAppend): + * runtime/ClassInfo.h: + * runtime/JSCell.cpp: + (JSC::JSCell::dump): + (JSC::JSCell::dumpToStream): + (JSC::JSCell::className): + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::visitChildren): + * runtime/JSString.cpp: + (JSC::JSString::dumpToStream): + (JSC::JSString::visitChildren): + * runtime/JSString.h: + (JSC::JSString::length): + (JSC::JSRopeString::RopeBuilder::length): + * runtime/Options.cpp: + (JSC::parse): + (JSC::Options::setOption): + (JSC::Options::dumpOption): + * runtime/Options.h: + +2014-04-05 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove bogus ASSERT in -JSVirtualMachine scanObjectGraph + https://bugs.webkit.org/show_bug.cgi?id=131251 + + Reviewed by Geoffrey Garen. + + * API/JSVirtualMachine.mm: + (scanExternalObjectGraph): + * API/tests/testapi.mm: + +2014-04-03 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: hook up probe samples to TimelineAgent's records + https://bugs.webkit.org/show_bug.cgi?id=131127 + + Reviewed by Timothy Hatcher. + + * inspector/ScriptDebugListener.h: Add a proper forward declaration for ScriptBreakpointAction. + +2014-04-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r166820. + https://bugs.webkit.org/show_bug.cgi?id=131256 + + Broke builds. (Requested by bdash on #webkit). + + Reverted changeset: + + "WIP for inlining C++. Added a build target to produce llvm + ir." + https://bugs.webkit.org/show_bug.cgi?id=130523 + http://trac.webkit.org/changeset/166820 + +2014-04-04 Matthew Mirman <mmirman@apple.com> + + WIP for inlining C++. Added a build target to produce llvm ir. + https://bugs.webkit.org/show_bug.cgi?id=130523 + + Reviewed by Filip Pizlo. + + The llvm ir gets placed JavaScriptCoreRuntimeToLLVMir.build with the extension .o + + * JavaScriptCore.xcodeproj/project.pbxproj: + * build_index.py: Added. + * Configurations/CompileRuntimeToLLVMir.xcconfig: Added. + +2014-04-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Log JS Exceptions to System Console if JavaScriptCoreOutputConsoleMessagesToSystemConsole enabled + https://bugs.webkit.org/show_bug.cgi?id=131241 + + Reviewed by Timothy Hatcher. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + Log the exception to the system console if system console output is enabled. + +2014-04-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Provide a way for JSContext console to log to system console + https://bugs.webkit.org/show_bug.cgi?id=131050 + + Reviewed by Timothy Hatcher. + + Applications often re-expose some log -> NSLog functionality. + We already have the capability ourselves, which includes extra + information such as sourceURL:line:column, all arguments instead + of just one argument, and backtrace information on console.trace. + Therefore it would be convenient if developers could just use + the built-in console.log and get rich output in both the inspector + and the console, without writing their own logger. + + The logging will be enabled in debug builds by default, and can be enabled + otherwise by setting a user default before creating the first context. + + For example, in the application itself: + + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"JavaScriptCoreOutputConsoleMessagesToSystemConsole"]; + + Or from outside the application: + + shell> defaults write <app-bundle-identifier> JavaScriptCoreOutputConsoleMessagesToSystemConsole -bool YES + + * inspector/JSConsoleClient.h: + * inspector/JSConsoleClient.cpp: + (Inspector::JSConsoleClient::logToSystemConsole): + (Inspector::JSConsoleClient::setLogToSystemConsole): + (Inspector::JSConsoleClient::initializeLogToSystemConsole): + (Inspector::JSConsoleClient::JSConsoleClient): + Global setting for logging to system console. Enabled on + debug builds, and by a user default on supported platforms. + + (Inspector::JSConsoleClient::messageWithTypeAndLevel): + Log to system console when the static setting is enabled. + + * runtime/ConsoleClient.h: + * runtime/ConsoleClient.cpp: + (JSC::appendURLAndPosition): + (JSC::appendMessagePrefix): + (JSC::ConsoleClient::printConsoleMessage): + (JSC::ConsoleClient::printConsoleMessageWithArguments): + Clean up printing. Build strings and use WTFLogAlways instead of printf + for consistant logging. + + * runtime/ConsoleClient.cpp: + (JSC::ConsoleClient::printConsoleMessageWithArguments): + Clean up printing. If there is no source URL, don't print a leading colon. + +2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com> + + Use JSCell::indexingType instead of Structure::indexingType wherever possible + https://bugs.webkit.org/show_bug.cgi?id=131230 + + Reviewed by Mark Lam. + + Avoid the indirection through the Structure. + + * bytecode/ArrayAllocationProfile.cpp: + (JSC::ArrayAllocationProfile::updateIndexingType): + * bytecode/ArrayAllocationProfile.h: + (JSC::ArrayAllocationProfile::selectIndexingType): + * heap/HeapStatistics.cpp: + (JSC::StorageStatistics::operator()): + * runtime/ArrayPrototype.cpp: + (JSC::attemptFastSort): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::objectPrototypeIsSane): + (JSC::JSGlobalObject::arrayPrototypeChainIsSane): + (JSC::JSGlobalObject::stringPrototypeChainIsSane): + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::create): + +2014-04-04 Mark Hahnenberg <mhahnenberg@apple.com> + + Use JSCell::type instead of TypeInfo::type wherever possible + https://bugs.webkit.org/show_bug.cgi?id=131229 + + Reviewed by Michael Saboff. + + Avoid going through the Structure and reifying the TypeInfo. + + * runtime/Executable.h: + (JSC::ExecutableBase::isEvalExecutable): + (JSC::ExecutableBase::isProgramExecutable): + +2014-04-03 Andreas Kling <akling@apple.com> + + Fast-path for casting JS wrappers to JSNode. + <https://webkit.org/b/131196> + + Allow code outside of JSC (well, WebCore) to extend the JSType spectrum + a little bit. We do this by exposing a LastJSCObjectType constant so + WebCore can encode its own wrapper types after that. + + Reviewed by Mark Hahnenberg and Geoff Garen. + + * runtime/JSType.h: + + Added LastJSCObjectType for use by WebCore. + + * runtime/JSObject.h: + (JSC::JSObject::isVariableObject): + + Updated since this can no longer assume that types >= VariableObjectType + are all variable objects. + +2014-04-03 Mark Hahnenberg <mhahnenberg@apple.com> + + All Heap::writeBarriers should be inline + https://bugs.webkit.org/show_bug.cgi?id=131197 + + Reviewed by Mark Lam. + + One is in a JSCellInlines.h, another is in Heap.cpp. These are all critical + enough and small enough to belong in HeapInlines.h. Also added the proper + ENABLE(GGC) ifdefs to minimize the cost of C++ barriers for !ENABLE(GGC) builds. + + * heap/Heap.cpp: + (JSC::Heap::writeBarrier): Deleted. + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::writeBarrier): + * runtime/JSCellInlines.h: + (JSC::Heap::writeBarrier): Deleted. + +2014-04-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: JSContext inspection provide a way to opt-out of including Native Call Stacks in Exception traces reported to Web Inspector + https://bugs.webkit.org/show_bug.cgi?id=131186 + + Reviewed by Geoffrey Garen. + + * API/JSContextPrivate.h: + * API/JSContext.mm: + (-[JSContext _includesNativeCallStackWhenReportingExceptions]): + (-[JSContext _setIncludesNativeCallStackWhenReportingExceptions:]): + JSContext ObjC SPI to opt-out of including native call stacks in exceptions. + + * API/JSContextRefPrivate.h: + * API/JSContextRef.cpp: + (JSGlobalContextGetIncludesNativeCallStackWhenReportingExceptions): + (JSGlobalContextSetIncludesNativeCallStackWhenReportingExceptions): + JSContext C SPI to opt-out of including native call stacks in exceptions. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + Only include the native call stack if the setting is enabled. It is enabled by default. + +2014-04-03 Mark Lam <mark.lam@apple.com> + + Fix bit rot in ARMv7 JIT probe mechanism. + <https://webkit.org/b/131167> + + Reviewed by Geoffrey Garen. + + 1. The macro assembler does not support pushing the SP register. Worked + around this by pushing the LR register as a placeholder, and then + writing the original SP value to that slot. + 2. The CPUState field in the ProbeContext needs to be aligned on a 4 + byte boundary, not an 8 byte boundary. + + * assembler/MacroAssemblerARMv7.cpp: + (JSC::MacroAssemblerARMv7::probe): + * jit/JITStubsARMv7.h: + +2014-04-02 Mark Lam <mark.lam@apple.com> + + ARMv7 compare32() should not use TST to do CMP's job. + <https://webkit.org/b/131146> + + Reviewed by Geoffrey Garen. + + The ARMv7 implementation of "compare32(RegisterID left, TrustedImm32 right)" + was using "tst reg, reg" to implement "cmp reg, #0". Unfortunately, the tst + instruction doesn't set the Overflow (V) flag and this results in random + results depending on whether there was a preceeding instruction that did set + the Overflow (V) flag. This issue was causing emscripten-cube2hash to run + with a lot of OSR exits where not expected as well as producing wrong results. + + The fix is to use "cmp reg, #0" to do the job properly. + + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::compare32): + +2014-04-02 Mark Hahnenberg <mhahnenberg@apple.com> + + CodeBlockSet should be generational + https://bugs.webkit.org/show_bug.cgi?id=127152 + + Reviewed by Geoffrey Garen. + + During EdenCollections we now only visit those CodeBlocks that: + a) Are new since the last collection if they were somehow otherwise reachable. + b) Are reachable from an Executable that is part of the remembered set. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): Initialize uninitialized variables. + (JSC::CodeBlock::visitAggregate): Move the addition of the weak reference harvester after the + shouldImmediatelyAssumeLivenessDuringScan check since it's redundant if we assume liveness. + * bytecode/CodeBlock.h: + (JSC::CodeBlock::forEachRelatedCodeBlock): Executes a functor for each CodeBlock reachable from the current CodeBlock (including this). + We use this to clear marks for the CodeBlocks of remembered Executables (see: CodeBlockSet::clearMarksForEdenCollection). + (JSC::CodeBlockSet::mark): Also check the set of new CodeBlocks for memebership when doing conservative scanning. + (JSC::ScriptExecutable::forEachCodeBlock): Executes a functor for each of this Executable's CodeBlocks. + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::~CodeBlockSet): + (JSC::CodeBlockSet::add): + (JSC::CodeBlockSet::promoteYoungCodeBlocks): Moves all CodeBlocks currently in the set of new CodeBlocks into + the set of old CodeBlocks. + (JSC::CodeBlockSet::clearMarksForFullCollection): Clears the marks for all CodeBlocks. + (JSC::CodeBlockSet::clearMarksForEdenCollection): Clears the marks for CodeBlocks owned by Executables in the + remembered set. When an Executable is added to the remembered set it's typically because we need to do something + with its CodeBlock. + (JSC::CodeBlockSet::clearMarks): + (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): Fixpoints over either just the new CodeBlocks or all CodeBlocks + to determine which CodeBlocks are dead and eagerly finalizes/deletes them. + (JSC::CodeBlockSet::remove): + (JSC::CodeBlockSet::traceMarked): Iterate only the currently executing CodeBlocks instead of all CodeBlocks. + (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): Clear m_mayBeExecuting for all currently executing + CodeBlocks because we no longer always do this at the beginning of EdenCollections. + * heap/CodeBlockSet.h: + (JSC::CodeBlockSet::iterate): + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::deleteAllCompiledCode): + (JSC::Heap::deleteUnmarkedCompiledCode): + * runtime/Executable.cpp: + (JSC::ScriptExecutable::installCode): Write barrier code on installation. We do this due to the following situation: + a) A CodeBlock is created and is compiled on a DFG worker thread. + b) No GC happens. + c) The CodeBlock has finished being compiled and is installed in the Executable. + d) The function never executes before the next GC. + e) The next GC needs needs to visit the new CodeBlock but the Executable won't be revisited unless + it's added to the remembered set. + +2014-04-02 Mark Lam <mark.lam@apple.com> + + Added some more dataLog info for OSR exits. + <https://webkit.org/b/131120> + + Reviewed by Michael Saboff. + + Adding info about the OSR exit index, the bytecode index of the bytecode + that is OSR exiting, and the reason for the OSR exit. This change is + for debugging code which only comes into play when we use the + --printEachOSRExit option. + + * dfg/DFGOSRExit.h: + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOperations.cpp: + +2014-04-02 Martin Robinson <mrobinson@igalia.com> + + REGRESSION(r165704): [GTK] Inspector resources not correctly generated + https://bugs.webkit.org/show_bug.cgi?id=130343 + + Reviewed by Gustavo Noronha Silva. + + * CMakeLists.txt: We generate the inspector JavaScript file into a directory like the one + in which it should be distributed. This allows us to more easily package it for GTK+. + +2014-04-01 Timothy Hatcher <timothy@apple.com> + + Remove HeapProfiler from the Web Inspector protocol. + + https://bugs.webkit.org/show_bug.cgi?id=131070 + + Reviewed by Joseph Pecoraro. + + * inspector/agents/InspectorConsoleAgent.h: + * inspector/agents/JSGlobalObjectConsoleAgent.cpp: + (Inspector::JSGlobalObjectConsoleAgent::addInspectedHeapObject): Deleted. + * inspector/agents/JSGlobalObjectConsoleAgent.h: + * inspector/protocol/Console.json: + +2014-03-31 Simon Fraser <simon.fraser@apple.com> + + Enable WEB_TIMING on Mac and iOS + https://bugs.webkit.org/show_bug.cgi?id=128064 + + Reviewed by Sam Weinig, Brent Fulgham. + + Enable WEB_TIMING. + + * Configurations/FeatureDefines.xcconfig: + +2014-03-31 Michael Saboff <msaboff@apple.com> + + REGRESSION(r166415): JSObject{Get,Set}Private() don't work with proxies objects + https://bugs.webkit.org/show_bug.cgi?id=130992 + + Reviewed by Mark Hahnenberg. + + Forward JSObjectGetPrivate() and JSObjectSetPrivate() to the wrapped object. + + * API/JSObjectRef.cpp: + (JSObjectGetPrivate): + (JSObjectSetPrivate): + * API/tests/testapi.c: + (main): Added new test case to validate we are properly foarwarding. + +2014-03-31 Mark Hahnenberg <mhahnenberg@apple.com> + + Improve GC_LOGGING + https://bugs.webkit.org/show_bug.cgi?id=130988 + + Reviewed by Geoffrey Garen. + + GC_LOGGING can be useful for diagnosing where we're spending our time during collection, + but it doesn't distinguish between Eden and Full collections in the data it gathers. This + patch updates it so that it can. It also adds the process ID to the beginning of each line + of input to be able to distinguish between the output of multiple processes exiting at the + same time. + + * heap/Heap.cpp: + (JSC::Heap::collect): + +2014-03-31 Dean Jackson <dino@apple.com> + + Remove WEB_ANIMATIONS + https://bugs.webkit.org/show_bug.cgi?id=130989 + + Reviewed by Simon Fraser. + + Remove this feature flag until we plan to implement. + + * Configurations/FeatureDefines.xcconfig: + +2014-03-31 Filip Pizlo <fpizlo@apple.com> + + More validation for FTL inline caches + https://bugs.webkit.org/show_bug.cgi?id=130948 + + Reviewed by Geoffrey Garen. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + * runtime/Options.h: + +2014-03-31 Filip Pizlo <fpizlo@apple.com> + + LLVM IR for store barriers should be nicely arranged and they don't need exception checks + https://bugs.webkit.org/show_bug.cgi?id=130950 + + Reviewed by Mark Hahnenberg. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + +2014-03-31 Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> + + [CMake] Stop checking for WTF_USE_ICU_UNICODE. + https://bugs.webkit.org/show_bug.cgi?id=130965 + + Reviewed by Martin Robinson. + + This is somewhat of a follow-up to r162782, which got rid of + WTF_USE_ICU_UNICODE in CMake but did not remove the check in JSC's + CMakeLists.txt. This meant the includes and libraries were not + being properly included since then. + + * CMakeLists.txt: + +2014-03-31 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Remove hostThisRegister() and hostThisValue() + https://bugs.webkit.org/show_bug.cgi?id=130895 + + Reviewed by Geoffrey Garen. + + Removed hostThisRegister() and hostThisValue() and instead use thisArgumentOffset() and thisValue() respectively. + + * API/APICallbackFunction.h: + (JSC::APICallbackFunction::call): + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::call): + * dfg/DFGOSREntry.cpp: + (JSC::DFG::prepareOSREntry): + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::jsInjectedScriptHostPrototypeAttributeEvaluate): + (Inspector::jsInjectedScriptHostPrototypeFunctionInternalConstructorName): + (Inspector::jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection): + (Inspector::jsInjectedScriptHostPrototypeFunctionType): + (Inspector::jsInjectedScriptHostPrototypeFunctionFunctionDetails): + (Inspector::jsInjectedScriptHostPrototypeFunctionGetInternalProperties): + * inspector/JSJavaScriptCallFramePrototype.cpp: + (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluate): + (Inspector::jsJavaScriptCallFramePrototypeFunctionScopeType): + (Inspector::jsJavaScriptCallFrameAttributeCaller): + (Inspector::jsJavaScriptCallFrameAttributeSourceID): + (Inspector::jsJavaScriptCallFrameAttributeLine): + (Inspector::jsJavaScriptCallFrameAttributeColumn): + (Inspector::jsJavaScriptCallFrameAttributeFunctionName): + (Inspector::jsJavaScriptCallFrameAttributeScopeChain): + (Inspector::jsJavaScriptCallFrameAttributeThisObject): + (Inspector::jsJavaScriptCallFrameAttributeType): + * interpreter/CallFrame.h: + (JSC::ExecState::hostThisRegister): Deleted. + (JSC::ExecState::hostThisValue): Deleted. + * runtime/Arguments.cpp: + (JSC::argumentsFuncIterator): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncToString): + (JSC::arrayProtoFuncToLocaleString): + (JSC::arrayProtoFuncJoin): + (JSC::arrayProtoFuncConcat): + (JSC::arrayProtoFuncPop): + (JSC::arrayProtoFuncPush): + (JSC::arrayProtoFuncReverse): + (JSC::arrayProtoFuncShift): + (JSC::arrayProtoFuncSlice): + (JSC::arrayProtoFuncSort): + (JSC::arrayProtoFuncSplice): + (JSC::arrayProtoFuncUnShift): + (JSC::arrayProtoFuncReduce): + (JSC::arrayProtoFuncReduceRight): + (JSC::arrayProtoFuncIndexOf): + (JSC::arrayProtoFuncLastIndexOf): + (JSC::arrayProtoFuncValues): + (JSC::arrayProtoFuncEntries): + (JSC::arrayProtoFuncKeys): + * runtime/BooleanPrototype.cpp: + (JSC::booleanProtoFuncToString): + (JSC::booleanProtoFuncValueOf): + * runtime/ConsolePrototype.cpp: + (JSC::consoleLogWithLevel): + (JSC::consoleProtoFuncClear): + (JSC::consoleProtoFuncDir): + (JSC::consoleProtoFuncDirXML): + (JSC::consoleProtoFuncTable): + (JSC::consoleProtoFuncTrace): + (JSC::consoleProtoFuncAssert): + (JSC::consoleProtoFuncCount): + (JSC::consoleProtoFuncProfile): + (JSC::consoleProtoFuncProfileEnd): + (JSC::consoleProtoFuncTime): + (JSC::consoleProtoFuncTimeEnd): + (JSC::consoleProtoFuncTimeStamp): + (JSC::consoleProtoFuncGroup): + (JSC::consoleProtoFuncGroupCollapsed): + (JSC::consoleProtoFuncGroupEnd): + * runtime/DatePrototype.cpp: + (JSC::formateDateInstance): + (JSC::dateProtoFuncToISOString): + (JSC::dateProtoFuncToLocaleString): + (JSC::dateProtoFuncToLocaleDateString): + (JSC::dateProtoFuncToLocaleTimeString): + (JSC::dateProtoFuncGetTime): + (JSC::dateProtoFuncGetFullYear): + (JSC::dateProtoFuncGetUTCFullYear): + (JSC::dateProtoFuncGetMonth): + (JSC::dateProtoFuncGetUTCMonth): + (JSC::dateProtoFuncGetDate): + (JSC::dateProtoFuncGetUTCDate): + (JSC::dateProtoFuncGetDay): + (JSC::dateProtoFuncGetUTCDay): + (JSC::dateProtoFuncGetHours): + (JSC::dateProtoFuncGetUTCHours): + (JSC::dateProtoFuncGetMinutes): + (JSC::dateProtoFuncGetUTCMinutes): + (JSC::dateProtoFuncGetSeconds): + (JSC::dateProtoFuncGetUTCSeconds): + (JSC::dateProtoFuncGetMilliSeconds): + (JSC::dateProtoFuncGetUTCMilliseconds): + (JSC::dateProtoFuncGetTimezoneOffset): + (JSC::dateProtoFuncSetTime): + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + (JSC::dateProtoFuncGetYear): + (JSC::dateProtoFuncToJSON): + * runtime/ErrorPrototype.cpp: + (JSC::errorProtoFuncToString): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): + (JSC::functionProtoFuncBind): + * runtime/NamePrototype.cpp: + (JSC::privateNameProtoFuncToString): + * runtime/NumberPrototype.cpp: + (JSC::numberProtoFuncToExponential): + (JSC::numberProtoFuncToFixed): + (JSC::numberProtoFuncToPrecision): + (JSC::numberProtoFuncClz): + (JSC::numberProtoFuncToString): + (JSC::numberProtoFuncToLocaleString): + (JSC::numberProtoFuncValueOf): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncValueOf): + (JSC::objectProtoFuncHasOwnProperty): + (JSC::objectProtoFuncIsPrototypeOf): + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + (JSC::objectProtoFuncPropertyIsEnumerable): + (JSC::objectProtoFuncToLocaleString): + (JSC::objectProtoFuncToString): + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoFuncTest): + (JSC::regExpProtoFuncExec): + (JSC::regExpProtoFuncCompile): + (JSC::regExpProtoFuncToString): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncReplace): + (JSC::stringProtoFuncToString): + (JSC::stringProtoFuncCharAt): + (JSC::stringProtoFuncCharCodeAt): + (JSC::stringProtoFuncConcat): + (JSC::stringProtoFuncIndexOf): + (JSC::stringProtoFuncLastIndexOf): + (JSC::stringProtoFuncMatch): + (JSC::stringProtoFuncSearch): + (JSC::stringProtoFuncSlice): + (JSC::stringProtoFuncSplit): + (JSC::stringProtoFuncSubstr): + (JSC::stringProtoFuncSubstring): + (JSC::stringProtoFuncToLowerCase): + (JSC::stringProtoFuncToUpperCase): + (JSC::stringProtoFuncLocaleCompare): + (JSC::stringProtoFuncBig): + (JSC::stringProtoFuncSmall): + (JSC::stringProtoFuncBlink): + (JSC::stringProtoFuncBold): + (JSC::stringProtoFuncFixed): + (JSC::stringProtoFuncItalics): + (JSC::stringProtoFuncStrike): + (JSC::stringProtoFuncSub): + (JSC::stringProtoFuncSup): + (JSC::stringProtoFuncFontcolor): + (JSC::stringProtoFuncFontsize): + (JSC::stringProtoFuncAnchor): + (JSC::stringProtoFuncLink): + (JSC::stringProtoFuncTrim): + (JSC::stringProtoFuncTrimLeft): + (JSC::stringProtoFuncTrimRight): + +2014-03-28 Filip Pizlo <fpizlo@apple.com> + + Land the stackmap register liveness glue with the uses of the liveness disabled + https://bugs.webkit.org/show_bug.cgi?id=130924 + + Reviewed by Oliver Hunt. + + Add the liveness and fix other bugs I found. + + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * ftl/FTLCompile.cpp: + (JSC::FTL::usedRegistersFor): + (JSC::FTL::fixFunctionBasedOnStackMaps): + * ftl/FTLSlowPathCall.cpp: + * ftl/FTLSlowPathCallKey.cpp: + (JSC::FTL::SlowPathCallKey::dump): + * ftl/FTLSlowPathCallKey.h: + (JSC::FTL::SlowPathCallKey::SlowPathCallKey): + (JSC::FTL::SlowPathCallKey::argumentRegisters): + (JSC::FTL::SlowPathCallKey::withCallTarget): + * ftl/FTLStackMaps.cpp: + (JSC::FTL::StackMaps::Record::locationSet): + (JSC::FTL::StackMaps::Record::liveOutsSet): + (JSC::FTL::StackMaps::Record::usedRegisterSet): + * ftl/FTLStackMaps.h: + * ftl/FTLThunks.cpp: + (JSC::FTL::registerClobberCheck): + (JSC::FTL::slowPathCallThunkGenerator): + * jit/RegisterSet.cpp: + (JSC::RegisterSet::stackRegisters): + (JSC::RegisterSet::reservedHardwareRegisters): + (JSC::RegisterSet::runtimeRegisters): + (JSC::RegisterSet::specialRegisters): + (JSC::RegisterSet::dump): + * jit/RegisterSet.h: + (JSC::RegisterSet::RegisterSet): + (JSC::RegisterSet::setAny): + (JSC::RegisterSet::setMany): + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + (JSC::tryCachePutByID): + (JSC::tryRepatchIn): + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + * runtime/Options.h: + +2014-03-28 Mark Lam <mark.lam@apple.com> + + mandreel throws a checksum error on 32-bit x86. + <https://webkit.org/b/125706> + + Reviewed by Filip Pizlo. + + The 32-bit DFG can emit code that loads double constants from its + CodeBlock's m_constantRegisters vector. The emitted instruction will + embed the address of the constant from the vector's backing store. + Subsequently, while inserting new constants, the DFG may resize the + vector, thereby reallocating the backing store. This renders the + previously embedded constant addresses stale. + + The fix is to use a dedicated doubles constant pool stored in the DFG + CommonData instead. This constant pool won't be reallocated, and + hence will not manifest this issue. + + * dfg/DFGCommonData.h: + * dfg/DFGGraph.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::addressOfDoubleConstant): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::addressOfDoubleConstant): Deleted. + +2014-03-28 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: console.warn is showing as error instead of warning + https://bugs.webkit.org/show_bug.cgi?id=130921 + + Reviewed by Timothy Hatcher. + + * runtime/ConsolePrototype.cpp: + (JSC::consoleProtoFuncWarn): + console.warn should be MessageLevel Warning, not Error. + +2014-03-28 Oliver Hunt <oliver@apple.com> + + Fix cloop build. + + * bytecode/BytecodeList.json: + +2014-03-28 Michael Saboff <msaboff@apple.com> + + Unreviewed, rolling r166248 back in. + + Turns out r166070 didn't cause a 2% performance loss in page load times + + Reverted changeset: + + Unreviewed, rolling out r166126. + Rollout r166126 in prepartion to roll out prerequisite r166070 + +2014-03-27 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r166376. + https://bugs.webkit.org/show_bug.cgi?id=130887 + + This was a misguided optimization. (Requested by kling on + #webkit). + + Reverted changeset: + + "Avoid fetching JSObject::structure() repeatedly in + putDirectInternal." + https://bugs.webkit.org/show_bug.cgi?id=130857 + http://trac.webkit.org/changeset/166376 + +2014-03-27 Oliver Hunt <oliver@apple.com> + + Support spread operand in |new| expressions + https://bugs.webkit.org/show_bug.cgi?id=130877 + + Reviewed by Michael Saboff. + + Add support for the spread operator being applied in + |new| expressions. This required adding support for + a new opcode, op_construct_varargs. This is a relatively + simple refactoring of the call_varargs implementation. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::unlink): + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::callTypeFor): + (JSC::CallLinkInfo::specializationKind): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCallVarargs): + (JSC::BytecodeGenerator::emitConstructVarargs): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + (JSC::JIT::compileOpCallSlowCase): + (JSC::JIT::emit_op_construct_varargs): + (JSC::JIT::emitSlow_op_construct_varargs): + * jit/JITCall32_64.cpp: + (JSC::JIT::emitSlow_op_construct_varargs): + (JSC::JIT::emit_op_construct_varargs): + (JSC::JIT::compileOpCall): + (JSC::JIT::compileOpCallSlowCase): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseMemberExpression): + +2014-03-27 Filip Pizlo <fpizlo@apple.com> + + Revert http://trac.webkit.org/changeset/166386 because it broke builds. + + * Configurations/Base.xcconfig: + * Configurations/LLVMForJSC.xcconfig: + +2014-03-27 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, skip this test for now. + + * tests/stress/recurse-infinitely-on-getter.js: + +2014-03-27 Filip Pizlo <fpizlo@apple.com> + + Switch the LLVMForJSC target to using the LLVM in /usr/local rather than /usr/local/LLVMForJavaScriptCore on iOS + https://bugs.webkit.org/show_bug.cgi?id=130867 + <rdar://problem/16432456> + + Reviewed by Mark Hahnenberg. + + * Configurations/Base.xcconfig: + * Configurations/LLVMForJSC.xcconfig: + +2014-03-27 Andreas Kling <akling@apple.com> + + Avoid fetching JSObject::structure() repeatedly in putDirectInternal. + <https://webkit.org/b/130857> + + Use the cached Structure* instead of re-fetching it over and over since + that's a non-trivial operation these days. + + Reviewed by Mark Hahnenberg. + + * runtime/JSObject.h: + (JSC::JSObject::putDirectInternal): + +2014-03-27 Mark Hahnenberg <mhahnenberg@apple.com> + + Check the remembered set bit faster + https://bugs.webkit.org/show_bug.cgi?id=130860 + + Reviewed by Oliver Hunt. + + Currently we look up the remembered set bit in the MarkedBlock in C++ code, but + that bit is also stored in the object. We should look it up there whenever possible. + + * heap/CopiedBlockInlines.h: + (JSC::CopiedBlock::shouldReportLiveBytes): + * heap/Heap.cpp: + (JSC::Heap::addToRememberedSet): + * heap/Heap.h: + * heap/HeapInlines.h: Removed. + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::reportExtraMemoryUsage): + +2014-03-27 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Provide SPI to disallow remote inspection of a JSContext + https://bugs.webkit.org/show_bug.cgi?id=130853 + + Reviewed by Timothy Hatcher. + + * API/JSContextPrivate.h: Added. + * API/JSContext.mm: + (-[JSContext _remoteInspectionEnabled]): + (-[JSContext _setRemoteInspectionEnabled:]): + ObjC SPI to enable/disable remote inspection. + + * API/JSContextRefPrivate.h: + * API/JSContextRef.cpp: + (JSGlobalContextGetRemoteInspectionEnabled): + (JSGlobalContextSetRemoteInspectionEnabled): + C SPI to enable/disable remote inspection. + + * JavaScriptCore.xcodeproj/project.pbxproj: + Add new private header, and export as a private header. + +2014-03-27 Mark Hahnenberg <mhahnenberg@apple.com> + + Clean up questionable style in ScriptExecutable::prepareForExecutionImpl + https://bugs.webkit.org/show_bug.cgi?id=130845 + + Reviewed by Filip Pizlo. + + There was a hack added to make sure C Loop LLInt worked which included overriding the + global Options::useLLInt setting, which makes no sense to do here. We should put the + update of the global setting in Options::recomputeDependentOptions along with the other + execution engine flags. + + * runtime/Executable.cpp: + (JSC::ScriptExecutable::prepareForExecutionImpl): + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + +2014-03-26 Filip Pizlo <fpizlo@apple.com> + + Enable LLVM stackmap liveOuts computation + https://bugs.webkit.org/show_bug.cgi?id=130821 + + Reviewed by Andy Estes and Sam Weinig. + + * ftl/FTLStackMaps.cpp: + (JSC::FTL::StackMaps::Record::dump): + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-03-26 Filip Pizlo <fpizlo@apple.com> + + Parse stackmaps liveOuts + https://bugs.webkit.org/show_bug.cgi?id=130801 + + Reviewed by Geoffrey Garen. + + This just adds the code to parse them but doesn't do anything with them, yet. + + * ftl/FTLLocation.cpp: + (JSC::FTL::Location::forStackmaps): + * ftl/FTLLocation.h: + (JSC::FTL::Location::forRegister): + (JSC::FTL::Location::forIndirect): + * ftl/FTLStackMaps.cpp: + (JSC::FTL::StackMaps::Location::parse): + (JSC::FTL::StackMaps::Location::dump): + (JSC::FTL::StackMaps::LiveOut::parse): + (JSC::FTL::StackMaps::LiveOut::dump): + (JSC::FTL::StackMaps::Record::parse): + (JSC::FTL::StackMaps::Record::dump): + * ftl/FTLStackMaps.h: + +2014-03-26 Mark Lam <mark.lam@apple.com> + + Build fix after r166307. + + Not reviewed. + + * runtime/JSCell.h: + - The inline function isAPIValueWrapper() should not be exported. This + was causing a linkage error when building for 32-bit x86 on Mac. + +2014-03-26 Filip Pizlo <fpizlo@apple.com> + + Reasoning about DWARF register numbers should be moved out of FTL::Location + https://bugs.webkit.org/show_bug.cgi?id=130792 + + Reviewed by Oliver Hunt. + + Moving this code makes it possible for things other than FTL::Location to reason about + DWARF register encoding. This refactoring also appears to reduce some code duplication + and makes FTLLocation.cpp cleaner. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + * ftl/FTLDWARFRegister.cpp: Added. + (JSC::FTL::DWARFRegister::reg): + (JSC::FTL::DWARFRegister::dump): + * ftl/FTLDWARFRegister.h: Added. + (JSC::FTL::DWARFRegister::DWARFRegister): + (JSC::FTL::DWARFRegister::dwarfRegNum): + * ftl/FTLLocation.cpp: + (JSC::FTL::Location::dump): + (JSC::FTL::Location::isGPR): + (JSC::FTL::Location::gpr): + (JSC::FTL::Location::isFPR): + (JSC::FTL::Location::fpr): + * ftl/FTLLocation.h: + (JSC::FTL::Location::hasDwarfReg): + (JSC::FTL::Location::dwarfReg): + +2014-03-26 Brent Fulgham <bfulgham@apple.com> + + Unreviewed build fix. + + * runtime/JSCell.h: VS2013 confused about argument type. + +2014-03-26 Zoltan Horvath <zoltan@webkit.org> + + [CSS Shapes] Remove shape-inside support + https://bugs.webkit.org/show_bug.cgi?id=130698 + + Reviewed by David Hyatt. + + * Configurations/FeatureDefines.xcconfig: + +2014-03-26 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Rename hasFastArrayStorage to be more appropriate + https://bugs.webkit.org/show_bug.cgi?id=130773 + + Reviewed by Filip Pizlo. + + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::alreadyChecked): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNewArray): + (JSC::FTL::LowerDFGToLLVM::compileNewArrayBuffer): + (JSC::FTL::LowerDFGToLLVM::compileNewArrayWithSize): + * runtime/ButterflyInlines.h: + (JSC::Butterfly::unshift): + (JSC::Butterfly::shift): + * runtime/IndexingHeaderInlines.h: + (JSC::IndexingHeader::preCapacity): + * runtime/IndexingType.h: + (JSC::hasArrayStorage): + (JSC::hasAnyArrayStorage): + (JSC::hasFastArrayStorage): Deleted. + * runtime/JSArray.cpp: + (JSC::JSArray::sortVector): + (JSC::JSArray::compactForSorting): + * runtime/JSArray.h: + (JSC::JSArray::create): + (JSC::JSArray::tryCreateUninitialized): + * runtime/JSGlobalObject.cpp: + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage): + * runtime/JSObject.h: + (JSC::JSObject::ensureArrayStorage): + (JSC::JSObject::arrayStorage): + * runtime/StructureTransitionTable.h: + (JSC::newIndexingType): + +2014-03-26 Zan Dobersek <zdobersek@igalia.com> + + Unreviewed. Removing the remaining Automake cruft. + + * GNUmakefile.list.am: Removed. + +2014-03-25 Filip Pizlo <fpizlo@apple.com> + + Arguments simplification phase should be fine with marking the arguments local itself as an arguments alias + https://bugs.webkit.org/show_bug.cgi?id=130764 + <rdar://problem/16304788> + + Reviewed by Sam Weinig. + + Being an arguments alias just means that your OSR exit recovery should attempt arguments + creation. This is true of arguments locals. We had special cases that tried to make it not + true of arguments locals. The only consequence of those special cases was to cause crashes + in case of arguments that are also captured variables (i.e. we have SlowArguments). This + change just removes those special cases. + + This change means that the FTL will now see SetLocals with a FlushedArguments format. + Previously you wouldn't see them because previously only non-captured variable would be + arguments aliases, and non-captured variables get completely SSAified - i.e. no SetLocals + left. Adding handling for FlushedArguments is a benign and simple change since its + behavior is identical to FlushedJSValue for that code's purposes. + + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileSetLocal): + * tests/stress/captured-arguments-variable.js: Added. + (foo): + (noInline): + +2014-03-25 Mark Hahnenberg <mhahnenberg@apple.com> + + Add HeapInlines + https://bugs.webkit.org/show_bug.cgi?id=130759 + + Reviewed by Filip Pizlo. + + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/Heap.cpp: + (JSC::MarkedBlockSnapshotFunctor::MarkedBlockSnapshotFunctor): + (JSC::MarkedBlockSnapshotFunctor::operator()): + * heap/Heap.h: Also reindented while we're here. + (JSC::Heap::writeBarrierBuffer): + (JSC::Heap::vm): + (JSC::Heap::objectSpace): + (JSC::Heap::machineThreads): + (JSC::Heap::operationInProgress): + (JSC::Heap::allocatorForObjectWithoutDestructor): + (JSC::Heap::allocatorForObjectWithNormalDestructor): + (JSC::Heap::allocatorForObjectWithImmortalStructureDestructor): + (JSC::Heap::storageAllocator): + (JSC::Heap::notifyIsSafeToCollect): + (JSC::Heap::isSafeToCollect): + (JSC::Heap::handleSet): + (JSC::Heap::handleStack): + (JSC::Heap::lastFullGCLength): + (JSC::Heap::lastEdenGCLength): + (JSC::Heap::increaseLastFullGCLength): + (JSC::Heap::sizeBeforeLastEdenCollection): + (JSC::Heap::sizeAfterLastEdenCollection): + (JSC::Heap::sizeBeforeLastFullCollection): + (JSC::Heap::sizeAfterLastFullCollection): + (JSC::Heap::jitStubRoutines): + (JSC::Heap::isDeferred): + (JSC::Heap::structureIDTable): + (JSC::Heap::removeCodeBlock): + * heap/HeapInlines.h: Added. + (JSC::Heap::shouldCollect): + (JSC::Heap::isBusy): + (JSC::Heap::isCollecting): + (JSC::Heap::heap): + (JSC::Heap::isLive): + (JSC::Heap::isInRememberedSet): + (JSC::Heap::isMarked): + (JSC::Heap::testAndSetMarked): + (JSC::Heap::setMarked): + (JSC::Heap::isWriteBarrierEnabled): + (JSC::Heap::writeBarrier): + (JSC::Heap::reportExtraMemoryCost): + (JSC::Heap::forEachProtectedCell): + (JSC::Heap::forEachCodeBlock): + (JSC::Heap::allocateWithNormalDestructor): + (JSC::Heap::allocateWithImmortalStructureDestructor): + (JSC::Heap::allocateWithoutDestructor): + (JSC::Heap::tryAllocateStorage): + (JSC::Heap::tryReallocateStorage): + (JSC::Heap::ascribeOwner): + (JSC::Heap::blockAllocator): + (JSC::Heap::releaseSoon): + (JSC::Heap::incrementDeferralDepth): + (JSC::Heap::decrementDeferralDepth): + (JSC::Heap::collectIfNecessaryOrDefer): + (JSC::Heap::decrementDeferralDepthAndGCIfNeeded): + (JSC::Heap::markListSet): + * runtime/JSCInlines.h: + +2014-03-25 Filip Pizlo <fpizlo@apple.com> + + DFG::ByteCodeParser::SetMode should distinguish between setting immediately without a flush and setting immediately with a flush + https://bugs.webkit.org/show_bug.cgi?id=130760 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::setLocal): + (JSC::DFG::ByteCodeParser::setArgument): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + * tests/stress/assign-argument-in-inlined-call.js: Added. + (f1): + (getF2Arguments): + (f2): + (f3): + * tests/stress/assign-captured-argument-in-inlined-call.js: Added. + (f1): + (f2): + (f3): + +2014-03-25 Filip Pizlo <fpizlo@apple.com> + + Fix 32-bit getter call alignment. + + Reviewed by Mark Hahnenberg. + + * jit/Repatch.cpp: + (JSC::generateGetByIdStub): + +2014-03-25 Filip Pizlo <fpizlo@apple.com> + + Repatch should plant calls to getters directly rather than through a C helper + https://bugs.webkit.org/show_bug.cgi?id=129589 + + Reviewed by Mark Hahnenberg. + + As the title says. All of the superstructure for this was already in place, so now it + was just a matter of actually emitting the call. + + 8x speed-up for getter microbenchmarks. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/PolymorphicGetByIdList.h: + (JSC::GetByIdAccess::doesCalls): + * jit/AccessorCallJITStubRoutine.cpp: Added. + (JSC::AccessorCallJITStubRoutine::AccessorCallJITStubRoutine): + (JSC::AccessorCallJITStubRoutine::~AccessorCallJITStubRoutine): + (JSC::AccessorCallJITStubRoutine::visitWeak): + * jit/AccessorCallJITStubRoutine.h: Added. + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::storeCell): + * jit/GCAwareJITStubRoutine.h: + * jit/Repatch.cpp: + (JSC::generateGetByIdStub): + * runtime/GetterSetter.h: + (JSC::GetterSetter::offsetOfGetter): + (JSC::GetterSetter::offsetOfSetter): + +2014-03-25 Michael Saboff <msaboff@apple.com> + + Unreviewed, rolling out r166126. + + Rollout r166126 in prepartion to roll out prerequisite r166070 + + Reverted changeset: + + "toThis() on a JSWorkerGlobalScope should return a JSProxy and + not undefined" + https://bugs.webkit.org/show_bug.cgi?id=130554 + http://trac.webkit.org/changeset/166126 + +2014-03-25 Oliver Hunt <oliver@apple.com> + + AST incorrectly conflates readable and writable locations + https://bugs.webkit.org/show_bug.cgi?id=130734 + + Reviewed by Filip Pizlo. + + We need to distinguish between "locations" that are valid for reading + and writing, vs those that may only be written. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitBytecode): + (JSC::ForOfNode::emitBytecode): + * parser/Nodes.h: + (JSC::ExpressionNode::isAssignmentLocation): + +2014-03-24 Oliver Hunt <oliver@apple.com> + + ASSERTION FAILED in Parser: dst != localReg + https://bugs.webkit.org/show_bug.cgi?id=130710 + + Reviewed by Filip Pizlo. + + Just make sure we don't try to write to a captured constant, + following the change to track captured variables separately. + + * bytecompiler/NodesCodegen.cpp: + (JSC::PostfixNode::emitResolve): + (JSC::PrefixNode::emitResolve): + +2014-03-25 Martin Robinson <mrobinson@igalia.com> + + [GTK] Remove the autotools build + https://bugs.webkit.org/show_bug.cgi?id=130717 + + Reviewed by Anders Carlsson. + + * GNUmakefile.am: Removed. + * config.h: Remove references to the autotools configure file. + +2014-03-24 Filip Pizlo <fpizlo@apple.com> + + More scaffolding for a stub routine to have a stub recursively embedded inside it + https://bugs.webkit.org/show_bug.cgi?id=130770 + + Reviewed by Oliver Hunt. + + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::unlink): VM& argument is superfluous. + (JSC::CallLinkInfo::visitWeak): Factor this out, it used to be in CodeBlock::finalizeUnconditionally(). + * bytecode/CallLinkInfo.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::finalizeUnconditionally): Factor out some functionality into CallLinkInfo::visitWeak(), and make sure we pass RepatchBuffer& in more places. + (JSC::CodeBlock::unlinkCalls): + (JSC::CodeBlock::unlinkIncomingCalls): + * bytecode/PolymorphicGetByIdList.cpp: Pass RepatchBuffer& through and call JITStubRoutine::visitWeak(). + (JSC::GetByIdAccess::visitWeak): + (JSC::PolymorphicGetByIdList::visitWeak): + * bytecode/PolymorphicGetByIdList.h: + * bytecode/PolymorphicPutByIdList.cpp: Pass RepatchBuffer& through and call JITStubRoutine::visitWeak(). + (JSC::PutByIdAccess::visitWeak): + (JSC::PolymorphicPutByIdList::visitWeak): + * bytecode/PolymorphicPutByIdList.h: + * bytecode/StructureStubInfo.cpp: Pass RepatchBuffer& through. + (JSC::StructureStubInfo::visitWeakReferences): + * bytecode/StructureStubInfo.h: + * jit/ClosureCallStubRoutine.cpp: isClosureCall is unused. + (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine): + * jit/GCAwareJITStubRoutine.cpp: + (JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine): + (JSC::createJITStubRoutine): + * jit/GCAwareJITStubRoutine.h: Make it easier to construct one of these. + (JSC::GCAwareJITStubRoutine::isClosureCall): Deleted. + * jit/JITStubRoutine.cpp: + (JSC::JITStubRoutine::visitWeak): This will allow future JITStubRoutine subclasses to have stubs recursively embedded inside them. + * jit/JITStubRoutine.h: + * jit/Repatch.cpp: + (JSC::generateGetByIdStub): Fix a possible GC bug where we weren't making the stub routine GC aware. + (JSC::emitCustomSetterStub): Clean up some code. + +2014-03-24 Geoffrey Garen <ggaren@apple.com> + + Safari crashes in JavaScriptCore: JSC::JSObject::growOutOfLineStorage + when WebKit is compiled with fcatch-undefined-behavior + https://bugs.webkit.org/show_bug.cgi?id=130652 + + Reviewed by Mark Hahnenberg. + + Use a static member function because the butterfly we pass in might be + NULL, and passing NULL to a member function is undefined behavior. + + Stylistically, I think this new way reads a little more clearly, since it + matches createOrGrowArrayRight, and it helps to convey that m_butterfly + might not exist yet. + + * runtime/Butterfly.h: + * runtime/ButterflyInlines.h: + (JSC::Butterfly::createOrGrowPropertyStorage): Renamed from growPropertyStorage + because we might create. Split out the create path to avoid using NULL + in a member function expression. + + Removed some unused versions of this function. + + * runtime/JSObject.cpp: + (JSC::JSObject::growOutOfLineStorage): Updated for interface change. + +2014-03-24 Oliver Hunt <oliver@apple.com> + + Strict mode destructuring assignment crashes the parser. + https://bugs.webkit.org/show_bug.cgi?id=130538 + + Reviewed by Michael Saboff. + + The SyntaxChecker mode always return 1 for success, except + for a small subset of functions where we needed exact information. + This ends up just being a poor design decision as it means + the parser can get confused between a function return 1, and + the Resolve constant which was also 1. So we now use a unique + type for every creation method. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createSourceElements): + (JSC::SyntaxChecker::createFunctionBody): + (JSC::SyntaxChecker::createArguments): + (JSC::SyntaxChecker::createSpreadExpression): + (JSC::SyntaxChecker::createArgumentsList): + (JSC::SyntaxChecker::createPropertyList): + (JSC::SyntaxChecker::createElementList): + (JSC::SyntaxChecker::createFormalParameterList): + (JSC::SyntaxChecker::createClause): + (JSC::SyntaxChecker::createClauseList): + (JSC::SyntaxChecker::createFuncDeclStatement): + (JSC::SyntaxChecker::createBlockStatement): + (JSC::SyntaxChecker::createExprStatement): + (JSC::SyntaxChecker::createIfStatement): + (JSC::SyntaxChecker::createForLoop): + (JSC::SyntaxChecker::createForInLoop): + (JSC::SyntaxChecker::createForOfLoop): + (JSC::SyntaxChecker::createEmptyStatement): + (JSC::SyntaxChecker::createVarStatement): + (JSC::SyntaxChecker::createReturnStatement): + (JSC::SyntaxChecker::createBreakStatement): + (JSC::SyntaxChecker::createContinueStatement): + (JSC::SyntaxChecker::createTryStatement): + (JSC::SyntaxChecker::createSwitchStatement): + (JSC::SyntaxChecker::createWhileStatement): + (JSC::SyntaxChecker::createWithStatement): + (JSC::SyntaxChecker::createDoWhileStatement): + (JSC::SyntaxChecker::createLabelStatement): + (JSC::SyntaxChecker::createThrowStatement): + (JSC::SyntaxChecker::createDebugger): + (JSC::SyntaxChecker::createConstStatement): + (JSC::SyntaxChecker::appendConstDecl): + (JSC::SyntaxChecker::combineCommaNodes): + (JSC::SyntaxChecker::operatorStackPop): + +2014-03-24 Brent Fulgham <bfulgham@apple.com> + + Activate WebVTT Tests Once Merging is Complete + https://bugs.webkit.org/show_bug.cgi?id=130420 + + Reviewed by Eric Carlson. + + * Configurations/FeatureDefines.xcconfig: Turn on ENABLE(WEBVTT_REGIONS) + +2014-03-24 Andreas Kling <akling@apple.com> + + Stop pulling in all the macro assemblers from VM.h + <https://webkit.org/b/130691> + + Remove #include of "GPRInfo.h". This breaks WebCore's dependency + on macro assemblers headers and removes 8 includes from every + .cpp file in the JS bindings. + + Reviewed by Geoff Garen. + + * runtime/VM.h: + +2014-03-24 Gavin Barraclough <barraclough@apple.com> + + Add support for thread QoS + https://bugs.webkit.org/show_bug.cgi?id=130688 + + Reviewed by Andreas Kling. + + * heap/BlockAllocator.cpp: + (JSC::BlockAllocator::blockFreeingThreadStartFunc): + - block freeing is a utility activity. + +2014-03-24 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix CLOOP build. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printCallOp): + (JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): + (JSC::CodeBlock::resetStubDuringGCInternal): Deleted. + * bytecode/CodeBlock.h: + (JSC::CodeBlock::callLinkInfosEnd): Deleted. + +2014-03-24 Gabor Rapcsanyi <rgabor@webkit.org> + + [ARM64] GNU assembler doesn't work with LLInt arm64 backend. + https://bugs.webkit.org/show_bug.cgi?id=130453 + + Reviewed by Filip Pizlo. + + Change fp and lr to x29 and x30. Add both operand kinds to emitARM64() + at sxtw and uxtw instructions. + + * offlineasm/arm64.rb: + +2014-03-23 Hyowon Kim <hw1008.kim@samsung.com> + + Move all EFL typedefs into EflTypedefs.h. + https://bugs.webkit.org/show_bug.cgi?id=130511 + + Reviewed by Gyuyoung Kim + + * heap/HeapTimer.h: Remove EFL typedefs. + +2014-03-23 Filip Pizlo <fpizlo@apple.com> + + Gotta grow the locals vectors if we are about to do SetLocals beyond the bytecode's numCalleeRegisters + https://bugs.webkit.org/show_bug.cgi?id=130650 + <rdar://problem/16122966> + + Reviewed by Michael Saboff. + + Previously, it was only in the case of inlining that we would do SetLocal's beyond the + previously established numLocals limit. But then we added generalized op_call_varargs + handling, which results in us emitting SetLocals that didn't previously exist in the + bytecode. + + This factors out the inliner's ensureLocals loop and calls it from op_call_varargs. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::ensureLocals): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::parse): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): Make this do alignment correctly. + * runtime/Options.h: + * tests/stress/call-varargs-from-inlined-code.js: Added. + * tests/stress/call-varargs-from-inlined-code-with-odd-number-of-arguments.js: Added. + +2014-03-22 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, adjust sizes for ARM64. + + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCall): + +2014-03-22 Filip Pizlo <fpizlo@apple.com> + + Protect the silent spiller/filler's desire to fill Int32Constants by making sure that we don't mark something as having a Int32 register format if it's a non-Int32 constant + https://bugs.webkit.org/show_bug.cgi?id=130649 + <rdar://problem/16399949> + + Reviewed by Andreas Kling. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + * tests/stress/fuzz-bug-16399949.js: Added. + (tryItOut.f): + (tryItOut): + +2014-03-22 Filip Pizlo <fpizlo@apple.com> + + Call linking slow paths should be passed a CallLinkInfo* directly so that you can create a call IC without adding it to any CodeBlocks + https://bugs.webkit.org/show_bug.cgi?id=130644 + + Reviewed by Andreas Kling. + + This is conceptually a really simple change but it involves the following: + + - The inline part of the call IC stuffs a pointer to the CallLinkInfo into regT2. + + - CodeBlock uses a Bag of CallLinkInfos instead of a Vector. + + - Remove the significance of a CallLinkInfo's index. This means that DFG::JITCode no + longer has a vector of slow path counts that shadows the CallLinkInfo vector. + + - Make CallLinkInfo have its own slowPathCount, which counts actual slow path executions + and not all relinking. + + This makes planting JS->JS calls inside other inline caches or stubs a lot easier, since + the CallLinkInfo and the call IC slow paths no longer rely on the call being associated + with a op_call/op_construct instruction and a machine code return PC within such an + instruction. + + * bytecode/CallLinkInfo.h: + (JSC::getCallLinkInfoCodeOrigin): + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeDFGStatuses): + * bytecode/CallLinkStatus.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printCallOp): + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::getCallLinkInfoMap): + (JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): + (JSC::CodeBlock::addCallLinkInfo): + (JSC::CodeBlock::unlinkCalls): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::stubInfoBegin): + (JSC::CodeBlock::stubInfoEnd): + (JSC::CodeBlock::callLinkInfosBegin): + (JSC::CodeBlock::callLinkInfosEnd): + (JSC::CodeBlock::byValInfo): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGJITCode.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::addJSCall): + (JSC::DFG::JITCompiler::JSCallRecord::JSCallRecord): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCall): + * ftl/FTLJSCall.cpp: + (JSC::FTL::JSCall::JSCall): + (JSC::FTL::JSCall::emit): + (JSC::FTL::JSCall::link): + * ftl/FTLJSCall.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + (JSC::JIT::compileOpCallSlowCase): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + (JSC::JIT::compileOpCallSlowCase): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + (JSC::operationLinkFor): + (JSC::operationVirtualFor): + (JSC::operationLinkClosureCallFor): + * jit/Repatch.cpp: + (JSC::linkClosureCall): + * jit/ThunkGenerators.cpp: + (JSC::slowPathFor): + (JSC::virtualForThunkGenerator): + * tests/stress/eval-that-is-not-eval.js: Added. + +2014-03-22 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix mispelled test name. + + * tests/stress/constand-folding-osr-exit.js: Removed. + * tests/stress/constant-folding-osr-exit.js: Copied from Source/JavaScriptCore/tests/stress/constand-folding-osr-exit.js. + +2014-03-22 Andreas Kling <akling@apple.com> + + CREATE_DOM_WRAPPER doesn't need the ExecState. + <https://webkit.org/b/130648> + + Add a fast path from JSGlobalObject to the VM so we don't have + to dance via the Heap. + + Reviewed by Darin Adler. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::vm): + +2014-03-22 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix FTL build. + + * ftl/FTLJITFinalizer.cpp: + +2014-03-22 Michael Saboff <msaboff@apple.com> + + toThis() on a JSWorkerGlobalScope should return a JSProxy and not undefined + https://bugs.webkit.org/show_bug.cgi?id=130554 + + Reviewed by Geoffrey Garen. + + Fixed toThis() on WorkerGlobalScope to return a JSProxy instead of the JSGlobalObject. + Did some cleanup as well. Moved the setting of the thisObject in a JSGlobalObject to + happen in finishCreation() so that it will also happen for other derived classes including + JSWorkerGlobalScopeBase. + + * API/JSContextRef.cpp: + (JSGlobalContextCreateInGroup): + * jsc.cpp: + (GlobalObject::create): + * API/tests/testapi.c: + (globalObject_initialize): Eliminated ASSERT that the global object we are creating matches + the result from JSContextGetGlobalObject() as that will return the proxy. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): Removed thisValue parameter and the call to setGlobalThis() since + we now call setGlobalThis in finishCreation(). + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::finishCreation): + (JSC::JSGlobalObject::setGlobalThis): Made this a private method. + +2014-03-22 Andreas Kling <akling@apple.com> + + Fix debug build. + + * bytecode/CodeBlock.cpp: + * runtime/Executable.cpp: + +2014-03-22 Andreas Kling <akling@apple.com> + + Cut down on JSC profiler includes in WebCore & co. + <https://webkit.org/b/130637> + + Most of WebKit was pulling in JSC's profiler headers via VM.h. + + Reviewed by Darin Adler. + + * dfg/DFGDisassembler.cpp: + * dfg/DFGDisassembler.h: + * dfg/DFGJITFinalizer.cpp: + * jsc.cpp: + * runtime/VM.cpp: + * runtime/VM.h: + +2014-03-22 Landry Breuil <landry@openbsd.org> + + Use pthread_stackseg_np() to find the stack bounds on OpenBSD. + https://bugs.webkit.org/show_bug.cgi?id=129965 + + Reviewed By Anders Carlsson. + +2014-03-21 Mark Lam <mark.lam@apple.com> + + Crash when BytecodeGenerator::emitJump calls Label::bind on null pointer. + <https://webkit.org/b/124508> + + Reviewed by Oliver Hunt. + + The issue is that BreakNode::emitBytecode() is holding onto a LabelScope + pointer from the BytecodeGenerator's m_localScopes vector, and then it + calls emitPopScopes(). emitPopScopes() may do finally clause handling + which will require the m_localScopes to be cloned so that it can change + the local scopes for the finally block, and then restore it after + handling the finally clause. These modifications of the m_localScopes + vector will result in the LabelScope pointer in BreakNode::emitBytecode() + becoming stale, thereby causing the crash. + + The same issue applies to the ContinueNode as well. + + The fix is to use the existing LabelScopePtr abstraction instead of raw + LabelScope pointers. The LabelScopePtr is resilient to the underlying + vector re-allocating its backing store. + + I also changed the LabelScopePtr constructor that takes a LabelScopeStore + to expect a reference to the owner store instead of a pointer because the + owner store should never be a null pointer. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::newLabelScope): + (JSC::BytecodeGenerator::breakTarget): + (JSC::BytecodeGenerator::continueTarget): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/LabelScope.h: + (JSC::LabelScopePtr::LabelScopePtr): + (JSC::LabelScopePtr::operator bool): + (JSC::LabelScopePtr::null): + * bytecompiler/NodesCodegen.cpp: + (JSC::ContinueNode::trivialTarget): + (JSC::ContinueNode::emitBytecode): + (JSC::BreakNode::trivialTarget): + (JSC::BreakNode::emitBytecode): + +2014-03-21 Mark Hahnenberg <mhahnenberg@apple.com> + + 6% SunSpider commandline regression due to r165940 + https://bugs.webkit.org/show_bug.cgi?id=130617 + + Reviewed by Michael Saboff. + + In GCActivityCallback::didAllocate, lastGCLength() returns 0 if we've never collected + before. Some of the benchmarks are never running a single EdenCollection, which causes + them to repeatedly call scheduleTimer with a newDelay of 0. This defeats our timer + slop heuristic, causing us to invoke CFRunLoopTimerSetNextFireDate a couple orders of + magnitude more than we normally would. + + The fix is to seed the last GC lengths in Heap with a non-zero length so that our heuristic works. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + +2014-03-21 Filip Pizlo <fpizlo@apple.com> + + Constants folded by DFG::ByteCodeParser should not be dead. + https://bugs.webkit.org/show_bug.cgi?id=130576 + + Reviewed by Mark Hahnenberg. + + This fixes bugs in the ByteCodeParser's constant folder by removing that constant folder. This + reduces the number of folders in JSC from fourish to just threeish (parser, DFG AI, and one + or more folders in LLVM). Doing so has no performance impact since the other constant folders + already subsume this one. + + Also added a test case for the specific bug that instigated this. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getJSConstantForValue): + (JSC::DFG::ByteCodeParser::getJSConstant): + (JSC::DFG::ByteCodeParser::inferredConstant): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGNode.h: + * dfg/DFGNodeFlags.h: + * tests/stress/constand-folding-osr-exit.js: Added. + (foo): + (test): + (.var): + +2014-03-21 Mark Lam <mark.lam@apple.com> + + StackLayoutPhase should find the union'ed calleeVariable before accessing its machineLocal. + <https://webkit.org/b/130566> + + Reviewed by Filip Pizlo. + + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + +2014-03-20 Filip Pizlo <fpizlo@apple.com> + + FTL should correctly compile GetByVal on Uint32Array that claims to return non-int32 values + https://bugs.webkit.org/show_bug.cgi?id=130562 + <rdar://problem/16382842> + + Reviewed by Geoffrey Garen. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + * tests/stress/uint32array-unsigned-load.js: Added. + (foo): + +2014-03-20 Brian Burg <bburg@apple.com> + + Web Inspector: add frontend controller and models for replay sessions + https://bugs.webkit.org/show_bug.cgi?id=130145 + + Reviewed by Joseph Pecoraro. + + * inspector/scripts/CodeGeneratorInspector.py: Add the conditional Replay domain. + +2014-03-20 Filip Pizlo <fpizlo@apple.com> + + FTL ValueToInt32 mishandles the constant case, and by the way, there is a constant case that the FTL sees + https://bugs.webkit.org/show_bug.cgi?id=130546 + <rdar://problem/16383308> + + Reviewed by Mark Hahnenberg. + + Make AI do a better job of folding this. + + Also made the FTL backend be more tolerant of data representations. In this case it + didn't know that "constant" was a valid representation. There is a finite set of + possible representations, but broadly, we don't write code that presumes anything + about the representation of an input; that's what methods like lowJSValue() are for. + ValueToInt32 was previously not relying on those methods at all because it had some + hacks. Now, those hacks are just a fast-path optimization but ultimately we fall down + to lowJSValue(). + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32): + * tests/stress/value-to-int32-undefined-constant.js: Added. + (foo): + * tests/stress/value-to-int32-undefined.js: Added. + (foo): + +2014-03-20 Mark Hahnenberg <mhahnenberg@apple.com> + + Add some assertions back + https://bugs.webkit.org/show_bug.cgi?id=130531 + + Reviewed by Geoffrey Garen. + + We removed a useful set of assertions for verifying that MarkedBlocks were + in the state that we expected them to be in after clearing marks in the Heap. + We should add these back to catch bugs earlier. + + * heap/MarkedBlock.h: + * heap/MarkedSpace.cpp: + (JSC::VerifyMarkedOrRetired::operator()): + (JSC::MarkedSpace::clearMarks): + +2014-03-20 Filip Pizlo <fpizlo@apple.com> + + Implement stackmap header version check and support new stackmap formats + https://bugs.webkit.org/show_bug.cgi?id=130535 + <rdar://problem/16164284> + + Reviewed by Geoffrey Garen. + + Add the notion of versioning so that LLVMers can happily implement new stackmap formats + without worrying about WebKit getting version-locked to LLVM. In the future, we will have + to implement parsing for a new LLVM stackmap format before it lands in LLVM, or we'll have + to have a "max usable LLVM revision" limit. But, thanks to versioning, we'll always be + happy to move backward in time to older versions of LLVM. + + * ftl/FTLStackMaps.cpp: + (JSC::FTL::readObject): + (JSC::FTL::StackMaps::Constant::parse): + (JSC::FTL::StackMaps::StackSize::parse): + (JSC::FTL::StackMaps::Location::parse): + (JSC::FTL::StackMaps::Record::parse): + (JSC::FTL::StackMaps::parse): + (JSC::FTL::StackMaps::dump): + (JSC::FTL::StackMaps::dumpMultiline): + * ftl/FTLStackMaps.h: + +2014-03-20 Filip Pizlo <fpizlo@apple.com> + + Crash beneath operationTearOffActivation running this JS compression demo + https://bugs.webkit.org/show_bug.cgi?id=130295 + <rdar://problem/16332337> + + Reviewed by Oliver Hunt. + + Make sure that we flush things as if we were at a terminal, if we are at a block with + no forward edges. This fixes infinitely loopy code with captured variables. + + Make sure that the CFG simplifier adds explicit flushes whenever it jettisons a block. + + Make it so that NodeIsFlushed is a thing. Previously only SSA used it and it computed + it by itself. Now it's an artifact of CPS rethreading. + + Add a bunch of tests. All of them previously either crashed or returned bad output due + to memory corruption. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::isCaptured): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::flushForTerminal): + (JSC::DFG::ByteCodeParser::flushForReturn): + (JSC::DFG::ByteCodeParser::flushIfTerminal): + (JSC::DFG::ByteCodeParser::branchData): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::keepOperandAlive): + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::run): + (JSC::DFG::CPSRethreadingPhase::computeIsFlushed): + (JSC::DFG::CPSRethreadingPhase::addFlushedLocalOp): + (JSC::DFG::CPSRethreadingPhase::addFlushedLocalEdge): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::performNodeCSE): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::clearFlagsOnAllNodes): + * dfg/DFGGraph.h: + * dfg/DFGNode.h: + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * tests/stress/activation-test-loop.js: Added. + (Inner.this.doStuff): + (Inner): + (foo.inner.isDone): + (foo): + * tests/stress/inferred-infinite-loop-that-uses-captured-variables.js: Added. + (bar): + (foo): + (noInline): + * tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js: Added. + (bar): + (foo): + (noInline): + * tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js: Added. + (bar): + (foo): + (noInline): + * tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js: Added. + (bar): + (foo): + (noInline): + * tests/stress/infinite-loop-that-uses-captured-variables.js: Added. + (bar): + (foo): + (noInline): + * tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added. + (bar): + (fuzz): + (foo.f): + (foo): + * tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added. + (bar): + (foo.f): + (foo): + * tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added. + (bar): + (foo.f): + (foo): + * tests/stress/tricky-infinite-loop-that-uses-captured-variables.js: Added. + (bar): + (foo): + (noInline): + +2014-03-20 Oliver Hunt <oliver@apple.com> + + Incorrect behavior when mutating a typed array during set. + https://bugs.webkit.org/show_bug.cgi?id=130428 + + Reviewed by Geoffrey Garen. + + This fixes a null derefence that occurs if a typed array + is mutated during the set() operation. The patch gets rid + of the "Quickly" version of setIndex that is assigning + JSValues of unknown type, as the numeric conversion can trigger + side effects that lead to neutering, and so we deref null. + + * runtime/JSGenericTypedArrayView.h: + (JSC::JSGenericTypedArrayView::setIndex): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::set): + (JSC::JSGenericTypedArrayView<Adaptor>::putByIndex): + +2014-03-20 Gavin Barraclough <barraclough@apple.com> + + Remove IdentifierTable typedef, isIdentifier() + https://bugs.webkit.org/show_bug.cgi?id=130533 + + Rubber stamped by Geoff Garen. + + Code should use AtomicStringTable, isAtomic() directly. + + * API/JSClassRef.cpp: + (OpaqueJSClass::~OpaqueJSClass): + (OpaqueJSClassContextData::OpaqueJSClassContextData): + (OpaqueJSClass::className): + * API/JSClassRef.h: + * bytecode/SpeculatedType.cpp: + (JSC::speculationFromCell): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::speculateStringIdent): + * heap/Heap.cpp: + (JSC::Heap::collect): + * interpreter/CallFrame.h: + (JSC::ExecState::atomicStringTable): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::addVar): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::createBindingPattern): + * runtime/Completion.cpp: + (JSC::checkSyntax): + (JSC::evaluate): + * runtime/Identifier.cpp: + (JSC::Identifier::checkCurrentAtomicStringTable): + * runtime/Identifier.h: + (JSC::Identifier::Identifier): + * runtime/IdentifierInlines.h: + (JSC::Identifier::add): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::dumpInContext): + * runtime/JSLock.cpp: + (JSC::JSLock::didAcquireLock): + (JSC::JSLock::willReleaseLock): + (JSC::JSLock::DropAllLocks::DropAllLocks): + (JSC::JSLock::DropAllLocks::~DropAllLocks): + * runtime/JSLock.h: + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::find): + (JSC::PropertyTable::get): + (JSC::PropertyTable::findWithString): + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::~VM): + * runtime/VM.h: + (JSC::VM::atomicStringTable): + +2014-03-20 Gavin Barraclough <barraclough@apple.com> + + Merge AtomicString, Identifier + https://bugs.webkit.org/show_bug.cgi?id=128624 + + Reviewed by Geoff Garen. + + WTF::StringImpl currently supports two uniquing mechanism - AtomicString and + Identifer - that is one too many. + + Remove Identifier in favour of AtomicString. Identifier had two interesting + mechanisms that we preserve. + + (1) JSC API VMs each get their own string table, switch the string table on + API entry/exit. + (2) JSC caches a pointer to the string table on the VM to avoid a thread + specific access. Adds a new AtomicString::add method to support this. + + * API/JSAPIWrapperObject.mm: + - updated includes. + * JavaScriptCore.xcodeproj/project.pbxproj: + - added IdentifierInlines.h. + * inspector/JSInjectedScriptHostPrototype.cpp: + * inspector/JSJavaScriptCallFramePrototype.cpp: + - updated includes. + * interpreter/CallFrame.h: + (JSC::ExecState::atomicStringTable): + - added, used via AtomicString::add to avoid thread-specific access. + * runtime/ConsolePrototype.cpp: + - updated includes. + * runtime/Identifier.cpp: + (JSC::Identifier::add): + (JSC::Identifier::add8): + - vm->smallStrings.singleCharacterStringRep now returns Atomic strings, use AtomicString::add. + * runtime/Identifier.h: + (JSC::Identifier::Identifier): + - added ASSERTS. + (JSC::Identifier::add): + - vm->smallStrings.singleCharacterStringRep now returns Atomic strings, use AtomicString::add. + * runtime/IdentifierInlines.h: Added. + (JSC::Identifier::add): + - moved from Identifier.h, use AtomicString::add. + * runtime/JSCInlines.h: + - added IdentifierInlines.h. + * runtime/JSLock.h: + - removed IdentifierTable. + * runtime/PropertyNameArray.cpp: + - updated includes. + * runtime/SmallStrings.cpp: + (JSC::SmallStringsStorage::SmallStringsStorage): + - ensure all single character strings are Atomic. + * runtime/VM.cpp: + (JSC::VM::VM): + - instantiate CommonIdentifiers with the correct AtomicStringTable set on thread data. + * runtime/VM.h: + (JSC::VM::atomicStringTable): + - added, used via AtomicString::add to avoid thread-specific access. + +2014-03-20 Gabor Rapcsanyi <rgabor@webkit.org> + + [ARM64] Fix assembler build issues and add cacheFlush support for Linux + https://bugs.webkit.org/show_bug.cgi?id=130502 + + Reviewed by Michael Saboff. + + Add limits.h for INT_MIN in ARM64Assembler(). Delete shouldBlindForSpecificArch(uintptr_t) + because on ARM64 uint64_t and uintptr_t is the same with GCC and Clang as well. + Add cacheFlush support for Linux. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::linuxPageFlush): + (JSC::ARM64Assembler::cacheFlush): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::shouldBlindForSpecificArch): + +2014-03-19 Gavin Barraclough <barraclough@apple.com> + + https://bugs.webkit.org/show_bug.cgi?id=130494 + EmptyUnique strings are Identifiers/Atomic + + Reviewed by Geoff Garen. + + EmptyUnique strings should set the Identifier/Atomic flag. + + This fixes an unreproducible bug we believe exists in Identifier handling. + Expected behaviour is that while Identifiers may reference EmptyUniques + (StringImpls allocated as UIDs for PrivateNames), these are not created + through the main Identifier constructor, the Identifier flag is not set + on PrivateNames, and we should never lookup EmptyUnique strings in the + IdentifierTable. + + Unfortunately that was happening. Some tables used to implement property + access in the JIT hold StringImpl*s, and turn these back into Identifiers + using the identfiier constructor. Since the code generator will now plant + by-id (cachable) accesses to PrivateNames we can end up passing an + EmptyUnique to Identifier::add, potentially leading to PrivateNames being + uniqued together (though hard to prove, since the hash codes are random). + + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + (JSC::PropertyName::uid): + (JSC::PropertyName::publicName): + (JSC::PropertyName::asIndex): + - PropertyName assumed that PrivateNames are not Identifiers - instead check isEmptyUnique(). + * runtime/Structure.cpp: + (JSC::Structure::getPropertyNamesFromStructure): + - Structure assumed that PrivateNames are not Identifiers - instead check isEmptyUnique(). + +2014-03-19 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, revert the DFGCommon.h change in r165938. It was not intentional. + + * dfg/DFGCommon.h: + +2014-03-19 Mark Hahnenberg <mhahnenberg@apple.com> + + GC timer should intelligently choose between EdenCollections and FullCollections + https://bugs.webkit.org/show_bug.cgi?id=128261 + + Reviewed by Geoffrey Garen. + + Most of the GCs while browsing the web are due to the GC timer. Currently the GC timer + always does FullCollections. To reduce the impact of the GC timer on the system this patch + changes Heap so that it has two timers, one for each type of collection. The FullCollection + timer is notified at the end of EdenCollections how much the Heap has grown since the last + FullCollection and when somebody notifies the Heap of abandoned memory (which usually wouldn't + be detected by an EdenCollection). + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/EdenGCActivityCallback.cpp: Added. + (JSC::EdenGCActivityCallback::EdenGCActivityCallback): + (JSC::EdenGCActivityCallback::doCollection): + (JSC::EdenGCActivityCallback::lastGCLength): + (JSC::EdenGCActivityCallback::deathRate): + (JSC::EdenGCActivityCallback::gcTimeSlice): + * heap/EdenGCActivityCallback.h: Added. + (JSC::GCActivityCallback::createEdenTimer): + * heap/FullGCActivityCallback.cpp: Added. + (JSC::FullGCActivityCallback::FullGCActivityCallback): + (JSC::FullGCActivityCallback::doCollection): + (JSC::FullGCActivityCallback::lastGCLength): + (JSC::FullGCActivityCallback::deathRate): + (JSC::FullGCActivityCallback::gcTimeSlice): + * heap/FullGCActivityCallback.h: Added. + (JSC::GCActivityCallback::createFullTimer): + * heap/GCActivityCallback.cpp: + (JSC::GCActivityCallback::GCActivityCallback): + (JSC::GCActivityCallback::doWork): + (JSC::GCActivityCallback::scheduleTimer): + (JSC::GCActivityCallback::cancelTimer): + (JSC::GCActivityCallback::didAllocate): + (JSC::GCActivityCallback::willCollect): + (JSC::GCActivityCallback::cancel): + * heap/GCActivityCallback.h: + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::reportAbandonedObjectGraph): + (JSC::Heap::didAbandon): + (JSC::Heap::collectAllGarbage): + (JSC::Heap::collect): + (JSC::Heap::willStartCollection): + (JSC::Heap::updateAllocationLimits): + (JSC::Heap::didFinishCollection): + (JSC::Heap::setFullActivityCallback): + (JSC::Heap::setEdenActivityCallback): + (JSC::Heap::fullActivityCallback): + (JSC::Heap::edenActivityCallback): + (JSC::Heap::setGarbageCollectionTimerEnabled): + (JSC::Heap::didAllocate): + (JSC::Heap::shouldDoFullCollection): + * heap/Heap.h: + (JSC::Heap::lastFullGCLength): + (JSC::Heap::lastEdenGCLength): + (JSC::Heap::increaseLastFullGCLength): + (JSC::Heap::sizeBeforeLastEdenCollection): + (JSC::Heap::sizeAfterLastEdenCollection): + (JSC::Heap::sizeBeforeLastFullCollection): + (JSC::Heap::sizeAfterLastFullCollection): + * heap/HeapOperation.h: + * heap/HeapStatistics.cpp: + (JSC::HeapStatistics::showObjectStatistics): + * heap/HeapTimer.cpp: + (JSC::HeapTimer::timerDidFire): + * jsc.cpp: + (functionFullGC): + (functionEdenGC): + * runtime/Options.h: + +2014-03-19 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r165926. + https://bugs.webkit.org/show_bug.cgi?id=130488 + + broke the iOS build (Requested by estes on #webkit). + + Reverted changeset: + + "GC timer should intelligently choose between EdenCollections + and FullCollections" + https://bugs.webkit.org/show_bug.cgi?id=128261 + http://trac.webkit.org/changeset/165926 + +2014-03-13 Mark Hahnenberg <mhahnenberg@apple.com> + + GC timer should intelligently choose between EdenCollections and FullCollections + https://bugs.webkit.org/show_bug.cgi?id=128261 + + Reviewed by Geoffrey Garen. + + Most of the GCs while browsing the web are due to the GC timer. Currently the GC timer + always does FullCollections. To reduce the impact of the GC timer on the system this patch + changes Heap so that it has two timers, one for each type of collection. The FullCollection + timer is notified at the end of EdenCollections how much the Heap has grown since the last + FullCollection and when somebody notifies the Heap of abandoned memory (which wouldn't be + detected by an EdenCollection). + + * heap/GCActivityCallback.cpp: + (JSC::GCActivityCallback::GCActivityCallback): + (JSC::GCActivityCallback::doWork): + (JSC::FullGCActivityCallback::FullGCActivityCallback): + (JSC::FullGCActivityCallback::doCollection): + (JSC::EdenGCActivityCallback::EdenGCActivityCallback): + (JSC::EdenGCActivityCallback::doCollection): + (JSC::GCActivityCallback::scheduleTimer): + (JSC::GCActivityCallback::cancelTimer): + (JSC::GCActivityCallback::didAllocate): + (JSC::GCActivityCallback::willCollect): + (JSC::GCActivityCallback::cancel): + * heap/GCActivityCallback.h: + (JSC::GCActivityCallback::GCActivityCallback): + (JSC::GCActivityCallback::createFullTimer): + (JSC::GCActivityCallback::createEdenTimer): + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::didAbandon): + (JSC::Heap::willStartCollection): + (JSC::Heap::updateAllocationLimits): + (JSC::Heap::setFullActivityCallback): + (JSC::Heap::setEdenActivityCallback): + (JSC::Heap::fullActivityCallback): + (JSC::Heap::edenActivityCallback): + (JSC::Heap::setGarbageCollectionTimerEnabled): + (JSC::Heap::didAllocate): + * heap/Heap.h: + * heap/HeapTimer.cpp: + (JSC::HeapTimer::timerDidFire): + +2014-03-19 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(r165459): It broke 109 jsc stress test on ARM Thumb2 and Mac 32 bit + https://bugs.webkit.org/show_bug.cgi?id=130134 + + Reviewed by Mark Hahnenberg. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): Can't do some optimizations if you don't have a lot of registers. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): Move stuff around before going into the IC code to ensure that we give the IC code the invariants it needs. This only happens in case of GetByIdFlush, where we are forced into using weird combinations of registers because the results have to be in t0/t1. + (JSC::DFG::SpeculativeJIT::compile): For a normal GetById, the register allocator should just do the right thing so nobody has to move anything around. + * jit/JITInlineCacheGenerator.cpp: + (JSC::JITGetByIdGenerator::JITGetByIdGenerator): Assert the things we want. + * jit/JITInlineCacheGenerator.h: + * jit/Repatch.cpp: + (JSC::generateGetByIdStub): Remove a previous incomplete hack to try to work around the DFG's problem. + +2014-03-19 Mark Hahnenberg <mhahnenberg@apple.com> + + Normalize some of the older JSC options + https://bugs.webkit.org/show_bug.cgi?id=128753 + + Reviewed by Michael Saboff. + + * runtime/Options.cpp: + (JSC::Options::initialize): + +2014-03-12 Mark Lam <mark.lam@apple.com> + + Update type of local vars to match the type of String length. + <https://webkit.org/b/130077> + + Reviewed by Geoffrey Garen. + + * runtime/JSStringJoiner.cpp: + (JSC::JSStringJoiner::join): + +2014-03-18 Filip Pizlo <fpizlo@apple.com> + + Get rid of Flush in SSA + https://bugs.webkit.org/show_bug.cgi?id=130440 + + Reviewed by Sam Weinig. + + This is basically a red patch. We used to use backwards flow for determining what was + flushed, until it became clear that this doesn't make sense. Now the Flush nodes don't + accomplish anything. Keeping them around in SSA can only make things hard. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::SSAData::SSAData): + * dfg/DFGBasicBlock.h: + * dfg/DFGFlushLivenessAnalysisPhase.cpp: Removed. + * dfg/DFGFlushLivenessAnalysisPhase.h: Removed. + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + +2014-03-18 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix iOS production build. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-03-18 Michael Saboff <msaboff@apple.com> + + Update RegExp Tracing code + https://bugs.webkit.org/show_bug.cgi?id=130381 + + Reviewed by Andreas Kling. + + Updated the regular expression tracing code for 8/16 bit JIT as + well as match only entry points. Also added average string length + metric. + + * runtime/RegExp.cpp: + (JSC::RegExp::RegExp): + (JSC::RegExp::match): + (JSC::RegExp::printTraceData): + * runtime/RegExp.h: + * runtime/VM.cpp: + (JSC::VM::addRegExpToTrace): + (JSC::VM::dumpRegExpTrace): + * runtime/VM.h: + * yarr/YarrJIT.h: + (JSC::Yarr::YarrCodeBlock::get8BitMatchOnlyAddr): + (JSC::Yarr::YarrCodeBlock::get16BitMatchOnlyAddr): + (JSC::Yarr::YarrCodeBlock::get8BitMatchAddr): + (JSC::Yarr::YarrCodeBlock::get16BitMatchAddr): + +2014-03-17 Filip Pizlo <fpizlo@apple.com> + + Add CompareStrictEq(StringIdent:, NotStringVar:) and CompareStrictEq(String:, Untyped:) + https://bugs.webkit.org/show_bug.cgi?id=130300 + + Reviewed by Mark Hahnenberg. + + We can quickly strictly compare StringIdent's to NotStringVar's and String's to Untyped's. + This makes the DFG aware of this. + + Also adds StringIdent-to-StringIdent and StringIdent-to-NotStringVar strict comparisons to + the FTL. Also adds StringIdent-to-StringIdent non-strict comparisons to the FTL. + + This also gives the DFG some abstractions for checking something is a cell or is other. + This made this patch easier to write and also simplified a bunch of other stuff. + + 1% speed-up on Octane. + + * assembler/AbstractMacroAssembler.h: + (JSC::AbstractMacroAssembler::JumpList::JumpList): + * bytecode/SpeculatedType.h: + (JSC::isNotStringVarSpeculation): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::childFor): + (JSC::DFG::Node::shouldSpeculateNotStringVar): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + (JSC::DFG::SpeculativeJIT::compileValueToInt32): + (JSC::DFG::SpeculativeJIT::compileInstanceOfForObject): + (JSC::DFG::SpeculativeJIT::compileInstanceOf): + (JSC::DFG::SpeculativeJIT::compileStrictEq): + (JSC::DFG::SpeculativeJIT::compileBooleanCompare): + (JSC::DFG::SpeculativeJIT::compileStringEquality): + (JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality): + (JSC::DFG::SpeculativeJIT::compileStringIdentEquality): + (JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality): + (JSC::DFG::SpeculativeJIT::compileStringZeroLength): + (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): + (JSC::DFG::SpeculativeJIT::speculateString): + (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage): + (JSC::DFG::SpeculativeJIT::speculateNotStringVar): + (JSC::DFG::SpeculativeJIT::speculateNotCell): + (JSC::DFG::SpeculativeJIT::speculateOther): + (JSC::DFG::SpeculativeJIT::speculate): + (JSC::DFG::SpeculativeJIT::emitSwitchChar): + (JSC::DFG::SpeculativeJIT::emitSwitchString): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::blessedBooleanResult): + (JSC::DFG::SpeculativeJIT::unblessedBooleanResult): + (JSC::DFG::SpeculativeJIT::booleanResult): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::branchIsCell): + (JSC::DFG::branchNotCell): + (JSC::DFG::SpeculativeJIT::branchIsOther): + (JSC::DFG::SpeculativeJIT::branchNotOther): + (JSC::DFG::SpeculativeJIT::moveTrueTo): + (JSC::DFG::SpeculativeJIT::moveFalseTo): + (JSC::DFG::SpeculativeJIT::blessBoolean): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::writeBarrier): + (JSC::DFG::SpeculativeJIT::branchIsCell): + (JSC::DFG::SpeculativeJIT::branchNotCell): + (JSC::DFG::SpeculativeJIT::branchIsOther): + (JSC::DFG::SpeculativeJIT::branchNotOther): + (JSC::DFG::SpeculativeJIT::moveTrueTo): + (JSC::DFG::SpeculativeJIT::moveFalseTo): + (JSC::DFG::SpeculativeJIT::blessBoolean): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::lowString): + (JSC::FTL::LowerDFGToLLVM::lowStringIdent): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateString): + (JSC::FTL::LowerDFGToLLVM::speculateStringIdent): + (JSC::FTL::LowerDFGToLLVM::speculateNotStringVar): + * runtime/JSCJSValue.h: + * tests/stress/string-ident-to-not-string-var-equality.js: Added. + (foo): + (bar): + (test): + +2014-03-18 Joseph Pecoraro <pecoraro@apple.com> + + Add Copyright to framework.sb + https://bugs.webkit.org/show_bug.cgi?id=130413 + + Reviewed by Timothy Hatcher. + + Other sb files got the copyright. Follow suit. + + * framework.sb: + +2014-03-18 Matthew Mirman <mmirman@apple.com> + + Removed extra parens from if statement in a preprocessor define. + https://bugs.webkit.org/show_bug.cgi?id=130408 + + Reviewed by Filip Pizlo. + + * parser/Parser.cpp: + +2014-03-18 Filip Pizlo <fpizlo@apple.com> + + More FTL enabling. + + Rubber stamped by Dan Bernstein and Mark Hahnenberg. + + * Configurations/FeatureDefines.xcconfig: + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): + +2014-03-17 Michael Saboff <msaboff@apple.com> + + V8 regexp spends most of its time in operationGetById + https://bugs.webkit.org/show_bug.cgi?id=130380 + + Reviewed by Filip Pizlo. + + Added String.length case to tryCacheGetByID that will only help the BaseLine JIT. + When V8 regexp is run from the command line, this nets a 2% performance improvement. + When the test is run for a longer amount of time, there is much less benefit as the + DFG will emit the appropriate code for String.length. This does remove + operationGetById as the hottest function whne run from the command line. + + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + +2014-03-17 Andreas Kling <akling@apple.com> + + Add one-deep cache to opaque roots hashset. + <https://webkit.org/b/130357> + + The vast majority of WebCore JS wrappers will have their Document* + as the root(). This change adds a simple optimization where we cache + the last lookup and avoid going to the hashset for repeated queries. + + Looks like 0.4% progression on DYEB on my MBP. + + Reviewed by Mark Hahnenberg. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/OpaqueRootSet.h: Added. + (JSC::OpaqueRootSet::OpaqueRootSet): + (JSC::OpaqueRootSet::contains): + (JSC::OpaqueRootSet::isEmpty): + (JSC::OpaqueRootSet::clear): + (JSC::OpaqueRootSet::add): + (JSC::OpaqueRootSet::size): + (JSC::OpaqueRootSet::begin): + (JSC::OpaqueRootSet::end): + * heap/SlotVisitor.h: + +2014-03-17 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Implement Math.hypot + https://bugs.webkit.org/show_bug.cgi?id=129486 + + Reviewed by Darin Adler. + + * runtime/MathObject.cpp: + (JSC::MathObject::finishCreation): + (JSC::mathProtoFuncHypot): + +2014-03-17 Zsolt Borbely <borbezs@inf.u-szeged.hu> + + Fix the !ENABLE(PROMISES) build + https://bugs.webkit.org/show_bug.cgi?id=130328 + + Reviewed by Darin Adler. + + Add missing ENABLE(PROMISES) guards. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + * runtime/JSPromiseDeferred.cpp: + * runtime/JSPromiseDeferred.h: + * runtime/JSPromiseReaction.cpp: + * runtime/JSPromiseReaction.h: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2014-03-16 Andreas Kling <akling@apple.com> + + REGRESSION(r165703): JSC tests crashing in StringImpl::destroy(). + <https://webkit.org/b/130304> + + Reviewed by Anders Carlsson. + + Unreviewed, restoring the old behavior of OpaqueJSString::identifier() + that doesn't put a potentially unwanted string into the Identifier table. + + * API/OpaqueJSString.cpp: + (OpaqueJSString::identifier): + +2014-03-16 Brian Burg <bburg@apple.com> + + Web Inspector: generated backend commands should reflect build system ENABLE settings + https://bugs.webkit.org/show_bug.cgi?id=130111 + + Reviewed by Timothy Hatcher. + + * CMakeLists.txt: + + Combine only the Inspector domains listed in INSPECTOR_DOMAINS, + instead of globbing any .json file. + + * DerivedSources.make: + + Force the combined inspector protocol file to be regenerated if + the content or list of domains itself changes. + +2014-03-16 Brian Burg <bburg@apple.com> + + Web Inspector: vended backend commands file should be generated as part of the build + https://bugs.webkit.org/show_bug.cgi?id=130110 + + Reviewed by Timothy Hatcher. + + * JavaScriptCore.xcodeproj/project.pbxproj: Copy InspectorJSBackendCommands.js to the + private headers directory. + +2014-03-16 Darin Adler <darin@apple.com> + + Remove all uses of deprecatedCharacters from JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=130304 + + Reviewed by Anders Carlsson. + + * API/JSValueRef.cpp: + (JSValueMakeFromJSONString): Use characters16 in the 16-bit code path. + * API/OpaqueJSString.cpp: + (OpaqueJSString::~OpaqueJSString): Use characters 16 in the 16-bit code path. + (OpaqueJSString::identifier): Get rid of custom Identifier constructor, and + juse use the standard one that takes a String. + (OpaqueJSString::characters): Use getCharactersWithUpconvert instead of a + hand-written alternative. + + * bindings/ScriptValue.cpp: + (Deprecated::jsToInspectorValue): Create InspectorString from String directly + instead of involving a character pointer. Use the String from Identifier + directly instead of making a new String. + + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::createSearchRegexSource): Use StringBuilder + instead of building a String a character at a time. This is still a very slow + way to do this. Also use strchr to search for a character instead of building + a String every time just to use find on it. + + * inspector/InspectorValues.cpp: + (Inspector::doubleQuoteString): Remove unnecessary trip through a + character pointer. This is still a really slow way to do this. + (Inspector::InspectorValue::parseJSON): Use StringView::upconvertedCharacters + instead of String::deprecatedCharacters. Still slow to always upconvert. + + * runtime/DateConstructor.cpp: Removed unneeded include. + * runtime/DatePrototype.cpp: Ditto. + + * runtime/Identifier.h: Removed deprecatedCharacters function. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::encode): Added a type cast to avoid ambiguity with the two character- + appending functions from JSStringBuilder. Removed unneeded code duplicating + what JSStringBuilder already does in its character append function. + (JSC::decode): Deleted code that creates a JSStringBuilder that is never used. + (JSC::parseIntOverflow): Changed lengths to unsigned. Made only the overload that + is used outside this file have external linkage. Added a new overload that takes + a StringView. + (JSC::parseInt): Use StringView::substring to call parseIntOverflow. + (JSC::globalFuncEscape): Use JSBuilder::append in a more efficient way for a + single character. + + * runtime/JSGlobalObjectFunctions.h: Removed unused overloads of parseIntOverflow. + + * runtime/JSStringBuilder.h: Marked this "lightly deprecated". + (JSC::JSStringBuilder::append): Overloaded for better speed with 8-bit characters. + Made one overload private. Fixed a performance bug where we would reserve capacity + in the 8-bit buffer but then append to the 16-bit buffer. + + * runtime/ObjectPrototype.cpp: Removed unneeded include. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncFontsize): Use StringView::getCharactersWithUpconvert. + (JSC::stringProtoFuncLink): Ditto. + +2014-03-15 Filip Pizlo <fpizlo@apple.com> + + FTL ArrayifyToStructure shouldn't fail every time that it actually arrayifies + https://bugs.webkit.org/show_bug.cgi?id=130296 + + Reviewed by Andreas Kling. + + During the 32-bit structure ID work, the second load of the structure was removed. + That's wrong. The whole point of loading the structure ID again is that the structure + ID would have been changed by the arrayification call, and we're verifying that the + arrayification succeeded in changing the structure. If we check the old structure - as + the code was doing after the 32-bit structure ID work - then this check is guaranteed + to fail, causing a significant performance regression. + + It's actually amazing that the regression wasn't bigger. The reason is that if FTL + code pathologically exits but the equivalent DFG code doesn't, then the exponential + backoff almost perfectly guarantees that we just end up in the DFG. For this code, at + the time at least, the DFG wasn't much slower so this didn't cause too much pain. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + +2014-03-15 Filip Pizlo <fpizlo@apple.com> + + FTL should support CheckHasInstance/InstanceOf + https://bugs.webkit.org/show_bug.cgi?id=130285 + + Reviewed by Sam Weinig. + + Fairly straightforward; I also discovered an inaccurate FIXME in the process. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCheckHasInstance): + (JSC::FTL::LowerDFGToLLVM::compileInstanceOf): + * ftl/FTLOutput.h: + (JSC::FTL::Output::phi): + * tests/stress/instanceof.js: Added. + * tests/stress/instanceof-not-cell.js: Added. + +2014-03-15 Michael Saboff <msaboff@apple.com> + + It should be possible to adjust DFG and FTL compiler thread priorities + https://bugs.webkit.org/show_bug.cgi?id=130288 + + Reviewed by Filip Pizlo. + + Added ability to change thread priorities relative to its current priority. + Created options to adjust the priority of the DFG and FTL compilation work thread + pools. For two core systems, there might be three runnable threads, the main thread, + the DFG compilation thread and the FTL compilation thread. With the same priority, + the scheduler is free to schedule whatever thread it wants. By lowering the + compilation threads, the main thread can run. Further tests may suggest better values + for the new options, priorityDeltaOfDFGCompilerThreads and priorityDeltaOfFTLCompilerThreads. + + For a two-core device, this change has a net positive improvement of 1-3% across + SunSpider, Octane, Kraken and AsmBench. + + * dfg/DFGWorklist.cpp: + (JSC::DFG::Worklist::finishCreation): + (JSC::DFG::Worklist::create): + (JSC::DFG::ensureGlobalDFGWorklist): + (JSC::DFG::ensureGlobalFTLWorklist): + * dfg/DFGWorklist.h: + * runtime/Options.cpp: + (JSC::computePriorityDeltaOfWorkerThreads): + * runtime/Options.h: + +2014-03-15 David Kilzer <ddkilzer@apple.com> + + [iOS] Define SYSTEM_VERSION_PREFIX consistently + <http://webkit.org/b/130293> + <rdar://problem/15926359> + + Reviewed by Dan Bernstein. + + * Configurations/Version.xcconfig: + (SYSTEM_VERSION_PREFIX_iphoneos): Sync with + Source/WebKit/mac/Version.xcconfig. + +2014-03-15 David Kilzer <ddkilzer@apple.com> + + Fix build: using integer absolute value function 'abs' when argument is of floating point type + <http://webkit.org/b/130286> + + Reviewed by Filip Pizlo. + + Fixes the following build failure using trunk clang: + + JavaScriptCore/assembler/MacroAssembler.h:992:17: error: using integer absolute value function 'abs' when argument is of floating point type [-Werror,-Wabsolute-value] + value = abs(value); + ^ + JavaScriptCore/assembler/MacroAssembler.h:992:17: note: use function 'fabs' instead + value = abs(value); + ^~~ + fabs + + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::shouldBlindDouble): Switch from abs() to + fabs(). + +2014-03-14 Oliver Hunt <oliver@apple.com> + + Reinstate intialiser syntax in for-in loops + https://bugs.webkit.org/show_bug.cgi?id=130269 + + Reviewed by Michael Saboff. + + Disallowing the initialiser broke some sites so this patch re-allows + the syntax. We still disallow the syntax in 'of' and pattern based + enumeration. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::isBindingNode): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclarationList): + (JSC::Parser<LexerType>::parseForStatement): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::operatorStackPop): + +2014-03-14 Mark Lam <mark.lam@apple.com> + + Accessing __lookupGetter__ and __lookupSetter__ should not crash the VM when undefined. + <https://webkit.org/b/130279> + + Reviewed by Filip Pizlo. + + If neither the getter nor setter are defined, accessing __lookupGetter__ + and __lookupSetter__ will return undefined as expected. However, if the + getter is defined but the setter is not, accessing __lookupSetter__ will + crash the VM. Similarly, accessing __lookupGetter__ when only the setter + is defined will crash the VM. + + The reason is because objectProtoFuncLookupGetter() and + objectProtoFuncLookupSetter() did not check if the getter and setter + value is non-null before returning it as an EncodedJSValue. The fix is + to add the appropriate null checks. + + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + +2014-03-14 Mark Rowe <mrowe@apple.com> + + Fix the production build. + + Don't rely on USE_INTERNAL_SDK being set for the Production configuration since UseInternalSDK.xcconfig won't + be at the expected relative path when working from installed source. + + * Configurations/Base.xcconfig: + +2014-03-14 Maciej Stachowiak <mjs@apple.com> + + Replace "Apple Computer, Inc." with "Apple Inc." in copyright headers + https://bugs.webkit.org/show_bug.cgi?id=130276 + <rdar://problem/16266927> + + Reviewed by Simon Fraser. + + * API/APICast.h: + * API/JSBase.cpp: + * API/JSBase.h: + * API/JSBasePrivate.h: + * API/JSCallbackConstructor.cpp: + * API/JSCallbackConstructor.h: + * API/JSCallbackFunction.cpp: + * API/JSCallbackFunction.h: + * API/JSCallbackObject.cpp: + * API/JSCallbackObject.h: + * API/JSCallbackObjectFunctions.h: + * API/JSClassRef.cpp: + * API/JSClassRef.h: + * API/JSContextRef.cpp: + * API/JSContextRef.h: + * API/JSContextRefPrivate.h: + * API/JSObjectRef.cpp: + * API/JSObjectRef.h: + * API/JSProfilerPrivate.cpp: + * API/JSProfilerPrivate.h: + * API/JSRetainPtr.h: + * API/JSStringRef.cpp: + * API/JSStringRef.h: + * API/JSStringRefBSTR.cpp: + * API/JSStringRefBSTR.h: + * API/JSStringRefCF.cpp: + * API/JSStringRefCF.h: + * API/JSValueRef.cpp: + * API/JSValueRef.h: + * API/JavaScript.h: + * API/JavaScriptCore.h: + * API/OpaqueJSString.cpp: + * API/OpaqueJSString.h: + * API/tests/JSNode.c: + * API/tests/JSNode.h: + * API/tests/JSNodeList.c: + * API/tests/JSNodeList.h: + * API/tests/Node.c: + * API/tests/Node.h: + * API/tests/NodeList.c: + * API/tests/NodeList.h: + * API/tests/minidom.c: + * API/tests/minidom.js: + * API/tests/testapi.c: + * API/tests/testapi.js: + * DerivedSources.make: + * bindings/ScriptValue.cpp: + * bytecode/CodeBlock.cpp: + * bytecode/CodeBlock.h: + * bytecode/EvalCodeCache.h: + * bytecode/Instruction.h: + * bytecode/JumpTable.cpp: + * bytecode/JumpTable.h: + * bytecode/Opcode.cpp: + * bytecode/Opcode.h: + * bytecode/SamplingTool.cpp: + * bytecode/SamplingTool.h: + * bytecode/SpeculatedType.cpp: + * bytecode/SpeculatedType.h: + * bytecode/ValueProfile.h: + * bytecompiler/BytecodeGenerator.cpp: + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/Label.h: + * bytecompiler/LabelScope.h: + * bytecompiler/RegisterID.h: + * debugger/DebuggerCallFrame.cpp: + * debugger/DebuggerCallFrame.h: + * dfg/DFGDesiredStructureChains.cpp: + * dfg/DFGDesiredStructureChains.h: + * heap/GCActivityCallback.cpp: + * heap/GCActivityCallback.h: + * inspector/ConsoleMessage.cpp: + * inspector/ConsoleMessage.h: + * inspector/IdentifiersFactory.cpp: + * inspector/IdentifiersFactory.h: + * inspector/InjectedScriptManager.cpp: + * inspector/InjectedScriptManager.h: + * inspector/InjectedScriptSource.js: + * inspector/ScriptBreakpoint.h: + * inspector/ScriptDebugListener.h: + * inspector/ScriptDebugServer.cpp: + * inspector/ScriptDebugServer.h: + * inspector/agents/InspectorAgent.cpp: + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + * inspector/agents/InspectorDebuggerAgent.h: + * interpreter/Interpreter.cpp: + * interpreter/Interpreter.h: + * interpreter/JSStack.cpp: + * interpreter/JSStack.h: + * interpreter/Register.h: + * jit/CompactJITCodeMap.h: + * jit/JITStubs.cpp: + * jit/JITStubs.h: + * jit/JITStubsARM.h: + * jit/JITStubsARMv7.h: + * jit/JITStubsX86.h: + * jit/JITStubsX86_64.h: + * os-win32/stdbool.h: + * parser/SourceCode.h: + * parser/SourceProvider.h: + * profiler/LegacyProfiler.cpp: + * profiler/LegacyProfiler.h: + * profiler/ProfileNode.cpp: + * profiler/ProfileNode.h: + * runtime/ArrayBufferView.cpp: + * runtime/ArrayBufferView.h: + * runtime/BatchedTransitionOptimizer.h: + * runtime/CallData.h: + * runtime/ConstructData.h: + * runtime/DumpContext.cpp: + * runtime/DumpContext.h: + * runtime/ExceptionHelpers.cpp: + * runtime/ExceptionHelpers.h: + * runtime/InitializeThreading.cpp: + * runtime/InitializeThreading.h: + * runtime/IntegralTypedArrayBase.h: + * runtime/IntendedStructureChain.cpp: + * runtime/IntendedStructureChain.h: + * runtime/JSActivation.cpp: + * runtime/JSActivation.h: + * runtime/JSExportMacros.h: + * runtime/JSGlobalObject.cpp: + * runtime/JSNotAnObject.cpp: + * runtime/JSNotAnObject.h: + * runtime/JSPropertyNameIterator.cpp: + * runtime/JSPropertyNameIterator.h: + * runtime/JSSegmentedVariableObject.cpp: + * runtime/JSSegmentedVariableObject.h: + * runtime/JSSymbolTableObject.cpp: + * runtime/JSSymbolTableObject.h: + * runtime/JSTypeInfo.h: + * runtime/JSVariableObject.cpp: + * runtime/JSVariableObject.h: + * runtime/PropertyTable.cpp: + * runtime/PutPropertySlot.h: + * runtime/SamplingCounter.cpp: + * runtime/SamplingCounter.h: + * runtime/Structure.cpp: + * runtime/Structure.h: + * runtime/StructureChain.cpp: + * runtime/StructureChain.h: + * runtime/StructureInlines.h: + * runtime/StructureTransitionTable.h: + * runtime/SymbolTable.cpp: + * runtime/SymbolTable.h: + * runtime/TypedArrayBase.h: + * runtime/TypedArrayType.cpp: + * runtime/TypedArrayType.h: + * runtime/VM.cpp: + * runtime/VM.h: + * yarr/RegularExpression.cpp: + * yarr/RegularExpression.h: + +2014-03-14 Filip Pizlo <fpizlo@apple.com> + + Final FTL iOS build magic + https://bugs.webkit.org/show_bug.cgi?id=130281 + + Reviewed by Michael Saboff. + + * Configurations/Base.xcconfig: For now our LLVM headers are in /usr/local/LLVMForJavaScriptCore/include, which is the same as OS X. + * Configurations/LLVMForJSC.xcconfig: We need to be more careful about how we specify library paths if we want to get the prioritzation right. Also we need protobuf because things. :-/ + +2014-03-14 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Gracefully handle nil name -[JSContext setName:] + https://bugs.webkit.org/show_bug.cgi?id=130262 + + Reviewed by Mark Hahnenberg. + + * API/JSContext.mm: + (-[JSContext setName:]): + Gracefully handle nil input. + + * API/tests/testapi.c: + (globalContextNameTest): + * API/tests/testapi.mm: + Test for nil / NULL names in the ObjC and C APIs. + +2014-03-11 Oliver Hunt <oliver@apple.com> + + Improve dom error messages + https://bugs.webkit.org/show_bug.cgi?id=130103 + + Reviewed by Andreas Kling. + + Add new helper function. + + * runtime/Error.h: + (JSC::throwVMTypeError): + +2014-03-14 László Langó <llango.u-szeged@partner.samsung.com> + + Remove unused method declaration. + https://bugs.webkit.org/show_bug.cgi?id=130238 + + Reviewed by Filip Pizlo. + + The implementation of CallFrame::dumpCaller was removed in + http://trac.webkit.org/changeset/153183, but the declaration of it was not. + + * interpreter/CallFrame.h: + Remove CallFrame::dumpCaller() method declaration. + +2014-03-12 Sergio Villar Senin <svillar@igalia.com> + + Rename DEFINE_STATIC_LOCAL to DEPRECATED_DEFINE_STATIC_LOCAL + https://bugs.webkit.org/show_bug.cgi?id=129612 + + Reviewed by Darin Adler. + + For new code use static NeverDestroyed<T> instead. + + * API/JSAPIWrapperObject.mm: + (jsAPIWrapperObjectHandleOwner): + * API/JSManagedValue.mm: + (managedValueHandleOwner): + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::objectGroupForBreakpointAction): + * inspector/scripts/CodeGeneratorInspectorStrings.py: + * interpreter/JSStack.cpp: + (JSC::stackStatisticsMutex): + * jit/ExecutableAllocator.cpp: + (JSC::DemandExecutableAllocator::allocators): + +2014-03-12 Gavin Barraclough <barraclough@apple.com> + + Reduce memory use for static property maps + https://bugs.webkit.org/show_bug.cgi?id=129986 + + Reviewed by Andreas Kling. + + Static property tables are currently duplicated on first use from read-only memory into dirty memory + in every process, and since the entries are large (48 bytes) and the tables can be unusually sparse + (we use a custom hash table without a rehash) a lot of memory may be wasted. + + First, reduce the size of the hashtable. Instead of storing values in the table the hashtable maps + from string hashes to indicies into a densely packed array of values. Compute the index table at + compile time as a part of the derived sources step, such that this may be read-only data. + + Second, don't copy all data from the HashTableValue array into a HashEntry objects. Instead refer + directly to the HashTableValue entries. The only data that needs to be allocated at runtime are the + keys, which are Identifiers. + + * create_hash_table: + - emit the hash table index into the derived source (we were calculating this already to ensure chaining does not get too deep). + * parser/Lexer.cpp: + (JSC::Lexer<LChar>::parseIdentifier): + (JSC::Lexer<UChar>::parseIdentifier): + (JSC::Lexer<T>::parseIdentifierSlowCase): + - HashEntry -> HashTableValue. + * parser/Lexer.h: + (JSC::Keywords::getKeyword): + - HashEntry -> HashTableValue. + * runtime/ClassInfo.h: + - removed HashEntry. + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + - use HashTable::ConstIterator. + (JSC::JSObject::put): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::findPropertyHashEntry): + - HashEntry -> HashTableValue. + (JSC::JSObject::reifyStaticFunctionsForDelete): + - changed HashTable::ConstIterator interface. + * runtime/JSObject.h: + - HashEntry -> HashTableValue. + * runtime/Lookup.cpp: + (JSC::HashTable::createTable): + - table -> keys, keys array is now densely packed. + (JSC::HashTable::deleteTable): + - table -> keys. + (JSC::setUpStaticFunctionSlot): + - HashEntry -> HashTableValue. + * runtime/Lookup.h: + (JSC::HashTableValue::builtinGenerator): + (JSC::HashTableValue::function): + (JSC::HashTableValue::functionLength): + (JSC::HashTableValue::propertyGetter): + (JSC::HashTableValue::propertyPutter): + (JSC::HashTableValue::lexerValue): + - added accessor methods from HashEntry. + (JSC::HashTable::copy): + - fields changed. + (JSC::HashTable::initializeIfNeeded): + - table -> keys. + (JSC::HashTable::entry): + - HashEntry -> HashTableValue. + (JSC::HashTable::ConstIterator::ConstIterator): + - iterate packed value array, so no need to skipInvalidKeys(). + (JSC::HashTable::ConstIterator::value): + (JSC::HashTable::ConstIterator::key): + (JSC::HashTable::ConstIterator::operator->): + - accessors now get HashTableValue/StringImpl* separately. + (JSC::HashTable::ConstIterator::operator++): + - iterate packed value array, so no need to skipInvalidKeys(). + (JSC::HashTable::end): + - end is now size of dense not sparse array. + (JSC::getStaticPropertySlot): + (JSC::getStaticFunctionSlot): + (JSC::getStaticValueSlot): + (JSC::putEntry): + (JSC::lookupPut): + - HashEntry -> HashTableValue. + +2014-03-13 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix Mac no-FTL build. + + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-03-13 Juergen Ributzka <juergen@apple.com> + + Only export initializeAndGetJSCLLVMAPI from libllvmForJSC.dylib + https://bugs.webkit.org/show_bug.cgi?id=130224 + + Reviewed by Filip Pizlo. + + This limits the exported symbols to only initializeAndGetJSCLLVMAPI from + the LLVM dylib. This allows the dylib to be safely used with other LLVM + dylibs on the same system. It also reduces the dynamic linking overhead + and also reduces the size by 6MB, because the linker can now dead strip + many unused functions. + + * Configurations/LLVMForJSC.xcconfig: + +2014-03-13 Andreas Kling <akling@apple.com> + + VM::discardAllCode() should clear the RegExp cache. + <https://webkit.org/b/130144> + + Reviewed by Michael Saboff. + + * runtime/VM.cpp: + (JSC::VM::discardAllCode): + +2014-03-13 Andreas Kling <akling@apple.com> + + Revert "Short-circuit JSGlobalObjectInspectorController when not inspecting." + <https://webkit.org/b/129995> + + This code path is not taken anymore on DYEB, and I can't explain why + it was showing up in my profiles. Backing it out per JoePeck's suggestion. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + +2014-03-13 Filip Pizlo <fpizlo@apple.com> + + FTL should support IsBlah + https://bugs.webkit.org/show_bug.cgi?id=130202 + + Reviewed by Geoffrey Garen. + + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileIsUndefined): + (JSC::FTL::LowerDFGToLLVM::compileIsBoolean): + (JSC::FTL::LowerDFGToLLVM::compileIsNumber): + (JSC::FTL::LowerDFGToLLVM::compileIsString): + (JSC::FTL::LowerDFGToLLVM::compileIsObject): + (JSC::FTL::LowerDFGToLLVM::compileIsFunction): + (JSC::FTL::LowerDFGToLLVM::compileStoreBarrier): + (JSC::FTL::LowerDFGToLLVM::compileStoreBarrierWithNullCheck): + (JSC::FTL::LowerDFGToLLVM::isNotCellOrMisc): + (JSC::FTL::LowerDFGToLLVM::isNumber): + (JSC::FTL::LowerDFGToLLVM::isNotNumber): + (JSC::FTL::LowerDFGToLLVM::isBoolean): + * ftl/FTLOSRExitCompiler.cpp: + * tests/stress/is-undefined-exit-on-masquerader.js: Added. + (bar): + (foo): + (test): + * tests/stress/is-undefined-jettison-on-masquerader.js: Added. + (foo): + (test): + * tests/stress/is-undefined-masquerader.js: Added. + (foo): + (test): + +2014-03-13 Mark Lam <mark.lam@apple.com> + + JS benchmarks crash with a bus error on 32-bit x86. + <https://webkit.org/b/130203> + + Reviewed by Geoffrey Garen. + + The issue is that generateGetByIdStub() can potentially use the same register + for the JSValue base register and the target tag register. After loading the + tag value into the target tag register, the JSValue base address is lost. + The code then proceeds to load the payload value using the base register, and + this results in a crash. + + The fix is to check if the base register is the same as the target tag register. + If so, we should make a copy the base register first before loading the tag + value, and use the copy to load the payload value instead. + + * jit/Repatch.cpp: + (JSC::generateGetByIdStub): + +2014-03-12 Filip Pizlo <fpizlo@apple.com> + + WebKit shouldn't crash on uniprocessor machines + https://bugs.webkit.org/show_bug.cgi?id=130176 + + Reviewed by Michael Saboff. + + Previously the math for computing the number of JIT compiler threads would come up with + zero threads on uniprocessor machines, and then the Worklist code would assert. + + * runtime/Options.cpp: + (JSC::computeNumberOfWorkerThreads): + * runtime/Options.h: + +2014-03-13 Radu Stavila <stavila@adobe.com> + + Webkit not building on XCode 5.1 due to garbage collection no longer being supported + https://bugs.webkit.org/show_bug.cgi?id=130087 + + Reviewed by Mark Rowe. + + Disable garbage collection on macosx when not using internal SDK. + + * Configurations/Base.xcconfig: + +2014-03-10 Darin Adler <darin@apple.com> + + Avoid copy-prone idiom "for (auto item : collection)" + https://bugs.webkit.org/show_bug.cgi?id=129990 + + Reviewed by Geoffrey Garen. + + * heap/CodeBlockSet.h: + (JSC::CodeBlockSet::iterate): Use auto& to be sure we don't copy by accident. + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::dispatchBreakpointActionLog): Use auto* to + make explicit that we are iterating through pointers. + (Inspector::ScriptDebugServer::dispatchBreakpointActionSound): Ditto. + (Inspector::ScriptDebugServer::dispatchBreakpointActionProbe): Ditto. + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::removeBreakpoint): Use auto&, and also + get rid of an unneeded local variable. + +2014-03-13 Brian Burg <bburg@apple.com> + + Web Inspector: Remove unused callId parameter from evaluateInWebInspector + https://bugs.webkit.org/show_bug.cgi?id=129744 + + Reviewed by Timothy Hatcher. + + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::enable): + (Inspector::InspectorAgent::evaluateForTestInFrontend): + * inspector/agents/InspectorAgent.h: + * inspector/protocol/InspectorDomain.json: + +2014-03-11 Filip Pizlo <fpizlo@apple.com> + + ASSERTION FAILED: node->op() == Phi || node->op() == SetArgument + https://bugs.webkit.org/show_bug.cgi?id=130069 + + Reviewed by Geoffrey Garen. + + This was a great assertion, and it represents our strictest interpretation of the rules of + our intermediate representation. However, fixing DCE to actually preserve the relevant + property would be hard, and it wouldn't have an observable effect right now because nobody + actually uses the propery of CPS that this assertion is checking for. + + In particular, we do always require, and rely on, the fact that non-captured variables + have variablesAtTail refer to the last interesting use of the variable: a SetLocal if the + block assigns to the variable, a GetLocal if it only reads from it, and a Flush, + PhantomLocal, or Phi otherwise. We do preserve this property successfully and DCE was not + broken in this regard. But, in the strictest sense, CPS also means that for captured + variables, variablesAtTail also continues to point to the last relevant use of the + variable. In particular, if there are multiple GetLocals, then it should point to the last + one. This is hard for DCE to preserve. Also, nobody relies on variablesAtTail for captured + variables, except to check the VariableAccessData; but in that case, we don't really need + the *last* relevant use of the variable - any node that mentions the same variable will do + just fine. + + So, this change loosens the assertion and adds a detailed FIXME describing what we would + have to do if we wanted to preserve the more strict property. + + This also makes changes to various debug printing paths so that validation doesn't crash + during graph dump. This also adds tests for the interesting cases of DCE failing to + preserve CPS in the strictest sense. This also attempts to win the record for longest test + name. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::hashAsStringIfPossible): + (JSC::CodeBlock::dumpAssumingJITType): + * bytecode/CodeBlock.h: + * bytecode/CodeOrigin.cpp: + (JSC::InlineCallFrame::hashAsStringIfPossible): + (JSC::InlineCallFrame::dumpBriefFunctionInformation): + * bytecode/CodeOrigin.h: + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::run): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::cleanVariables): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): + * runtime/FunctionExecutableDump.cpp: + (JSC::FunctionExecutableDump::dump): + * tests/stress/dead-access-to-captured-variable-preceded-by-a-live-store-in-function-with-multiple-basic-blocks.js: Added. + (foo): + * tests/stress/dead-access-to-captured-variable-preceded-by-a-live-store.js: Added. + (foo): + +2014-03-12 Brian Burg <bburg@apple.com> + + Web Replay: add infrastructure for memoizing nondeterministic DOM APIs + https://bugs.webkit.org/show_bug.cgi?id=129445 + + Reviewed by Timothy Hatcher. + + There was a bug in the replay inputs code generator that would include + headers for definitions of enum classes, even though they can be safely + forward-declared. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (Generator.generate_includes): Only include for copy constructor if the + type is a heavy scalar (i.e., String, URL), not a normal scalar + (i.e., int, double, enum classes). + + (Generator.generate_type_forward_declarations): Forward-declare scalars + that are enums or enum classes. + +2014-03-12 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Disable REMOTE_INSPECTOR in earlier OS X releases + https://bugs.webkit.org/show_bug.cgi?id=130118 + + Reviewed by Timothy Hatcher. + + * Configurations/FeatureDefines.xcconfig: + +2014-03-12 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Hang in Remote Inspection triggering breakpoint from console + https://bugs.webkit.org/show_bug.cgi?id=130032 + + Reviewed by Timothy Hatcher. + + * inspector/EventLoop.h: + * inspector/EventLoop.cpp: + (Inspector::EventLoop::remoteInspectorRunLoopMode): + (Inspector::EventLoop::cycle): + Expose the run loop mode name so it can be used if needed by others. + + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorBlock::RemoteInspectorBlock): + (Inspector::RemoteInspectorBlock::~RemoteInspectorBlock): + (Inspector::RemoteInspectorBlock::operator=): + (Inspector::RemoteInspectorBlock::operator()): + (Inspector::RemoteInspectorQueueTask): + Instead of a dispatch_queue, have our own static Vector of debugger tasks. + + (Inspector::RemoteInspectorHandleRunSource): + (Inspector::RemoteInspectorInitializeQueue): + Initialize the static queue and run loop source. When the run loop source + fires, it will exhaust the queue of debugger messages. + + (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): + (Inspector::RemoteInspectorDebuggableConnection::~RemoteInspectorDebuggableConnection): + When we get a debuggable connection add a run loop source for inspector commands. + + (Inspector::RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable): + (Inspector::RemoteInspectorDebuggableConnection::sendMessageToBackend): + Enqueue blocks on our Vector instead of our dispatch_queue. + +2014-03-12 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r165482. + https://bugs.webkit.org/show_bug.cgi?id=130157 + + Broke the windows build; "error C2466: cannot allocate an + array of constant size 0" (Requested by jernoble on #webkit). + + Reverted changeset: + + "Reduce memory use for static property maps" + https://bugs.webkit.org/show_bug.cgi?id=129986 + http://trac.webkit.org/changeset/165482 + +2014-03-12 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove HandleSet::m_nextToFinalize + https://bugs.webkit.org/show_bug.cgi?id=130109 + + Reviewed by Mark Lam. + + This is a remnant of when HandleSet contained things that needed to be finalized. + + * heap/HandleSet.cpp: + (JSC::HandleSet::HandleSet): + (JSC::HandleSet::writeBarrier): + * heap/HandleSet.h: + (JSC::HandleSet::allocate): + (JSC::HandleSet::deallocate): + +2014-03-12 Mark Hahnenberg <mhahnenberg@apple.com> + + Layout Test fast/workers/worker-gc.html is failing + https://bugs.webkit.org/show_bug.cgi?id=130135 + + Reviewed by Geoffrey Garen. + + When removing MarkedBlocks, we always expect them to be in the MarkedAllocator's + main list of blocks, i.e. not in the retired list. When shutting down the VM this + wasn't always the case which was causing ASSERTs to fire. We should rearrange things + so that allocators are notified with lastChanceToFinalize. This will give them + the chance to move their retired blocks back into the main list before removing them all. + + * heap/MarkedAllocator.cpp: + (JSC::LastChanceToFinalize::operator()): + (JSC::MarkedAllocator::lastChanceToFinalize): + * heap/MarkedAllocator.h: + * heap/MarkedSpace.cpp: + (JSC::LastChanceToFinalize::operator()): + (JSC::MarkedSpace::lastChanceToFinalize): + +2014-03-12 Gavin Barraclough <barraclough@apple.com> + + Reduce memory use for static property maps + https://bugs.webkit.org/show_bug.cgi?id=129986 + + Reviewed by Andreas Kling. + + Static property tables are currently duplicated on first use from read-only memory into dirty memory + in every process, and since the entries are large (48 bytes) and the tables can be unusually sparse + (we use a custom hash table without a rehash) a lot of memory may be wasted. + + First, reduce the size of the hashtable. Instead of storing values in the table the hashtable maps + from string hashes to indicies into a densely packed array of values. Compute the index table at + compile time as a part of the derived sources step, such that this may be read-only data. + + Second, don't copy all data from the HashTableValue array into a HashEntry objects. Instead refer + directly to the HashTableValue entries. The only data that needs to be allocated at runtime are the + keys, which are Identifiers. + + * create_hash_table: + - emit the hash table index into the derived source (we were calculating this already to ensure chaining does not get too deep). + * parser/Lexer.cpp: + (JSC::Lexer<LChar>::parseIdentifier): + (JSC::Lexer<UChar>::parseIdentifier): + (JSC::Lexer<T>::parseIdentifierSlowCase): + - HashEntry -> HashTableValue. + * parser/Lexer.h: + (JSC::Keywords::getKeyword): + - HashEntry -> HashTableValue. + * runtime/ClassInfo.h: + - removed HashEntry. + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + - use HashTable::ConstIterator. + (JSC::JSObject::put): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::findPropertyHashEntry): + - HashEntry -> HashTableValue. + (JSC::JSObject::reifyStaticFunctionsForDelete): + - changed HashTable::ConstIterator interface. + * runtime/JSObject.h: + - HashEntry -> HashTableValue. + * runtime/Lookup.cpp: + (JSC::HashTable::createTable): + - table -> keys, keys array is now densely packed. + (JSC::HashTable::deleteTable): + - table -> keys. + (JSC::setUpStaticFunctionSlot): + - HashEntry -> HashTableValue. + * runtime/Lookup.h: + (JSC::HashTableValue::builtinGenerator): + (JSC::HashTableValue::function): + (JSC::HashTableValue::functionLength): + (JSC::HashTableValue::propertyGetter): + (JSC::HashTableValue::propertyPutter): + (JSC::HashTableValue::lexerValue): + - added accessor methods from HashEntry. + (JSC::HashTable::copy): + - fields changed. + (JSC::HashTable::initializeIfNeeded): + - table -> keys. + (JSC::HashTable::entry): + - HashEntry -> HashTableValue. + (JSC::HashTable::ConstIterator::ConstIterator): + - iterate packed value array, so no need to skipInvalidKeys(). + (JSC::HashTable::ConstIterator::value): + (JSC::HashTable::ConstIterator::key): + (JSC::HashTable::ConstIterator::operator->): + - accessors now get HashTableValue/StringImpl* separately. + (JSC::HashTable::ConstIterator::operator++): + - iterate packed value array, so no need to skipInvalidKeys(). + (JSC::HashTable::end): + - end is now size of dense not sparse array. + (JSC::getStaticPropertySlot): + (JSC::getStaticFunctionSlot): + (JSC::getStaticValueSlot): + (JSC::putEntry): + (JSC::lookupPut): + - HashEntry -> HashTableValue. + +2014-03-11 Filip Pizlo <fpizlo@apple.com> + + It should be possible to build WebKit with FTL on iOS + https://bugs.webkit.org/show_bug.cgi?id=130116 + + Reviewed by Dan Bernstein. + + * Configurations/Base.xcconfig: + +2014-03-10 Filip Pizlo <fpizlo@apple.com> + + GetById list caching should use something object-oriented rather than PolymorphicAccessStructureList + https://bugs.webkit.org/show_bug.cgi?id=129778 + + Reviewed by Geoffrey Garen. + + Also deduplicate the GetById getter call caching. Also add some small tests for + get stubs. + + This change reduces the amount of code involved in GetById access caching and it + creates data structures that can serve as an elegant scaffold for introducing other + kinds of caches or improving current caching styles. It will definitely make getter + performance improvements easier to implement. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printGetByIdCacheStatus): + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/PolymorphicGetByIdList.cpp: Added. + (JSC::GetByIdAccess::GetByIdAccess): + (JSC::GetByIdAccess::~GetByIdAccess): + (JSC::GetByIdAccess::fromStructureStubInfo): + (JSC::GetByIdAccess::visitWeak): + (JSC::PolymorphicGetByIdList::PolymorphicGetByIdList): + (JSC::PolymorphicGetByIdList::from): + (JSC::PolymorphicGetByIdList::~PolymorphicGetByIdList): + (JSC::PolymorphicGetByIdList::currentSlowPathTarget): + (JSC::PolymorphicGetByIdList::addAccess): + (JSC::PolymorphicGetByIdList::isFull): + (JSC::PolymorphicGetByIdList::isAlmostFull): + (JSC::PolymorphicGetByIdList::didSelfPatching): + (JSC::PolymorphicGetByIdList::visitWeak): + * bytecode/PolymorphicGetByIdList.h: Added. + (JSC::GetByIdAccess::GetByIdAccess): + (JSC::GetByIdAccess::isSet): + (JSC::GetByIdAccess::operator!): + (JSC::GetByIdAccess::type): + (JSC::GetByIdAccess::structure): + (JSC::GetByIdAccess::chain): + (JSC::GetByIdAccess::chainCount): + (JSC::GetByIdAccess::stubRoutine): + (JSC::GetByIdAccess::doesCalls): + (JSC::PolymorphicGetByIdList::isEmpty): + (JSC::PolymorphicGetByIdList::size): + (JSC::PolymorphicGetByIdList::at): + (JSC::PolymorphicGetByIdList::operator[]): + * bytecode/StructureStubInfo.cpp: + (JSC::StructureStubInfo::deref): + (JSC::StructureStubInfo::visitWeakReferences): + * bytecode/StructureStubInfo.h: + (JSC::isGetByIdAccess): + (JSC::StructureStubInfo::initGetByIdList): + * jit/Repatch.cpp: + (JSC::generateGetByIdStub): + (JSC::tryCacheGetByID): + (JSC::patchJumpToGetByIdStub): + (JSC::tryBuildGetByIDList): + (JSC::tryBuildPutByIdList): + * tests/stress/getter.js: Added. + (foo): + (.o): + * tests/stress/polymorphic-prototype-accesses.js: Added. + (Foo): + (Bar): + (foo): + * tests/stress/prototype-getter.js: Added. + (Foo): + (foo): + * tests/stress/simple-prototype-accesses.js: Added. + (Foo): + (foo): + +2014-03-11 Mark Hahnenberg <mhahnenberg@apple.com> + + MarkedBlocks that are "full enough" shouldn't be swept after EdenCollections + https://bugs.webkit.org/show_bug.cgi?id=129920 + + Reviewed by Geoffrey Garen. + + This patch introduces the notion of "retiring" MarkedBlocks. We retire a MarkedBlock + when the amount of free space in a MarkedBlock drops below a certain threshold. + Retired blocks are not considered for sweeping. + + This is profitable because it reduces churn during sweeping. To build a free list, + we have to scan through each cell in a block. After a collection, all objects that + are live in the block will remain live until the next FullCollection, at which time + we un-retire all previously retired blocks. Thus, a small number of objects in a block + that die during each EdenCollection could cause us to do a disproportiante amount of + sweeping for how much free memory we get back. + + This patch looks like a consistent ~2% progression on boyer and is neutral everywhere else. + + * heap/Heap.h: + (JSC::Heap::didRetireBlockWithFreeListSize): + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::tryAllocateHelper): + (JSC::MarkedAllocator::removeBlock): + (JSC::MarkedAllocator::reset): + * heap/MarkedAllocator.h: + (JSC::MarkedAllocator::MarkedAllocator): + (JSC::MarkedAllocator::forEachBlock): + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::sweepHelper): + (JSC::MarkedBlock::clearMarksWithCollectionType): + (JSC::MarkedBlock::didRetireBlock): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::willRemoveBlock): + (JSC::MarkedBlock::isLive): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::clearNewlyAllocated): + (JSC::MarkedSpace::clearMarks): + * runtime/Options.h: + +2014-03-11 Andreas Kling <akling@apple.com> + + Streamline PropertyTable for lookup-only access. + <https://webkit.org/b/130060> + + The PropertyTable lookup algorithm was written to support both read + and write access. This wasn't actually needed in most places. + + This change adds a PropertyTable::get() that just returns the value + type (instead of an insertion iterator.) It also adds an early return + for empty tables. + + Finally, up the minimum table capacity from 8 to 16. It was lowered + to 8 in order to save memory, but that was before PropertyTables were + GC allocated. Nowadays we don't have nearly as many tables, since all + the unpinned transitions die off. + + Reviewed by Darin Adler. + + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::get): + * runtime/Structure.cpp: + (JSC::Structure::despecifyDictionaryFunction): + (JSC::Structure::attributeChangeTransition): + (JSC::Structure::get): + (JSC::Structure::despecifyFunction): + * runtime/StructureInlines.h: + (JSC::Structure::get): + +2014-03-10 Mark Hahnenberg <mhahnenberg@apple.com> + + REGRESSION(r165407): DoYouEvenBench crashes in DRT + https://bugs.webkit.org/show_bug.cgi?id=130066 + + Reviewed by Geoffrey Garen. + + The baseline JIT does a conditional store barrier for the put_by_id, but we need + an unconditional store barrier so that we cover the butterfly case as well in emitPutTransitionStub. + + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_put_by_id): + (JSC::JIT::emitWriteBarrier): + +2014-03-10 Mark Lam <mark.lam@apple.com> + + Resurrect bit-rotted JIT::probe() mechanism. + <https://webkit.org/b/130067> + + Reviewed by Geoffrey Garen. + + * jit/JITStubs.cpp: + - Added the needed #include <wtf/InlineASM.h>. + +2014-03-10 Joseph Pecoraro <pecoraro@apple.com> + + Fix typo in EXCLUDED_SOURCE_FILE_NAMES_iphoneos. + + Rubber-stamped by Dan Bernstein. + + * Configurations/JavaScriptCore.xcconfig: + +2014-03-10 Mark Lam <mark.lam@apple.com> + + r165414 broke the 32-bit x86 tests: ASSERTION FAILED: result != InvalidIndex @ GPRInfo.h:330. + <https://webkit.org/b/130065> + + Reviewed by Michael Saboff. + + There is code in ScratchRegisterAllocator.cpp that is relying on GPRInfo::toIndex() + being able to return InvalidIndex. Hence, the assertion is invalid. Ditto for + FPRInfo::toIndex(). + + The fix is to remove the "result != InvalidIndex" assertions. + + * jit/FPRInfo.h: + (JSC::FPRInfo::toIndex): + * jit/GPRInfo.h: + (JSC::GPRInfo::toIndex): + +2014-03-10 Mark Lam <mark.lam@apple.com> + + Crash on a stack overflow on 32-bit x86 in http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html. + <https://webkit.org/b/129955> + + Reviewed by Geoffrey Garen. + + The 32-bit x86 version of getHostCallReturnValue() was leaking 16 bytes + stack memory every time it was called. This is now fixed. + + * jit/JITOperations.cpp: + +2014-03-10 Joseph Pecoraro <pecoraro@apple.com> + + Better JSContext API for named evaluations (other than //# sourceURL) + https://bugs.webkit.org/show_bug.cgi?id=129911 + + Reviewed by Geoffrey Garen. + + * API/JSBase.h: + * API/JSContext.h: + * API/JSContext.mm: + (-[JSContext evaluateScript:]): + (-[JSContext evaluateScript:withSourceURL:]): + Add new evaluateScript:withSourceURL:. + + * API/tests/testapi.c: + (main): + * API/tests/testapi.mm: + (testObjectiveCAPI): + Add tests for sourceURL in evaluate APIs. It should + affect the exception objects. + +2014-03-10 Filip Pizlo <fpizlo@apple.com> + + Repatch should save and restore all used registers - not just temp ones - when making a call + https://bugs.webkit.org/show_bug.cgi?id=130041 + + Reviewed by Geoffrey Garen and Mark Hahnenberg. + + The save/restore code was written back when the only client was the DFG, which only uses a + subset of hardware registers: the "temp" registers in our lingo. But the FTL may use many + other registers, especially on ARM64. The fact that Repatch doesn't know to save those can + lead to data corruption on ARM64. + + * jit/RegisterSet.cpp: + (JSC::RegisterSet::calleeSaveRegisters): + (JSC::RegisterSet::numberOfSetGPRs): + (JSC::RegisterSet::numberOfSetFPRs): + * jit/RegisterSet.h: + * jit/Repatch.cpp: + (JSC::storeToWriteBarrierBuffer): + (JSC::emitPutTransitionStub): + * jit/ScratchRegisterAllocator.cpp: + (JSC::ScratchRegisterAllocator::ScratchRegisterAllocator): + (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing): + (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping): + (JSC::ScratchRegisterAllocator::usedRegistersForCall): + (JSC::ScratchRegisterAllocator::desiredScratchBufferSizeForCall): + (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBufferForCall): + (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBufferForCall): + * jit/ScratchRegisterAllocator.h: + +2014-03-10 Mark Hahnenberg <mhahnenberg@apple.com> + + Remove ConditionalStore barrier + https://bugs.webkit.org/show_bug.cgi?id=130040 + + Reviewed by Geoffrey Garen. + + ConditionalStoreBarrier was created when barriers were much more expensive. Now that + they're cheap(er), we can get rid of them. This also allows us to get rid of the write + barrier logic in emitPutTransitionStub because we always will have executed a write barrier + on the base object in the case where we are allocating and storing a new Butterfly into it. + Previously, a ConditionalStoreBarrier might or might not have barrier-ed the base object, + so we'd have to emit a write barrier in the transition case. + + This is performance neutral on the benchmarks we track. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::insertStoreBarrier): + * dfg/DFGNode.h: + (JSC::DFG::Node::isStoreBarrier): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStoreBarrier): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * jit/Repatch.cpp: + (JSC::emitPutTransitionStub): + +2014-03-10 Filip Pizlo <fpizlo@apple.com> + + DFG and FTL should know that comparing anything to Misc is cheap and easy + https://bugs.webkit.org/show_bug.cgi?id=130001 + + Reviewed by Geoffrey Garen. + + - Expand CompareStrictEq(Misc:, Misc:) to work for cases where either side of the + comparison is just Untyped:. + + - This obviates the need for CompareStrictEqConstant, so remove it. + + - FTL had a thing called "Nully" which is really "Other". Rename it and add + OtherUse. + + 9% speed-up on box2d. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::isBinaryUseKind): + (JSC::DFG::Node::shouldSpeculateOther): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch): + (JSC::DFG::SpeculativeJIT::compare): + (JSC::DFG::SpeculativeJIT::compileStrictEq): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::isNotOther): + (JSC::FTL::LowerDFGToLLVM::isOther): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): + (JSC::FTL::LowerDFGToLLVM::speculateNotCell): + (JSC::FTL::LowerDFGToLLVM::speculateOther): + (JSC::FTL::LowerDFGToLLVM::speculateMisc): + * tests/stress/compare-strict-eq-integer-to-misc.js: Added. + +2014-03-10 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, remove unintended change. + + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + +2014-03-10 Filip Pizlo <fpizlo@apple.com> + + jsc commandline shouldn't have a "console" because that confuses some tests into thinking + that they're running in the browser. + + Rubber stamped by Mark Hahnenberg. + + * jsc.cpp: + (GlobalObject::finishCreation): + +2014-03-10 Filip Pizlo <fpizlo@apple.com> + + Out-line ScratchRegisterAllocator + + Rubber stamped by Mark Hahnenberg. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * jit/ScratchRegisterAllocator.cpp: Added. + (JSC::ScratchRegisterAllocator::ScratchRegisterAllocator): + (JSC::ScratchRegisterAllocator::~ScratchRegisterAllocator): + (JSC::ScratchRegisterAllocator::lock): + (JSC::ScratchRegisterAllocator::allocateScratch): + (JSC::ScratchRegisterAllocator::allocateScratchGPR): + (JSC::ScratchRegisterAllocator::allocateScratchFPR): + (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing): + (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping): + (JSC::ScratchRegisterAllocator::desiredScratchBufferSize): + (JSC::ScratchRegisterAllocator::preserveUsedRegistersToScratchBuffer): + (JSC::ScratchRegisterAllocator::restoreUsedRegistersFromScratchBuffer): + * jit/ScratchRegisterAllocator.h: + +2014-03-10 Brent Fulgham <bfulgham@apple.com> + + [Win] Pass environment to Pre-Build, Pre-link, and Post-Build Stages. + https://bugs.webkit.org/show_bug.cgi?id=130023 + + Reviewed by Dean Jackson. + + * JavaScriptCore.vcxproj/JavaScriptCore.proj: Avoid trailing backslashes in + path names to avoid accidental escaping of later string substitutions. + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for testb_i8r when register is accumulator. + <https://webkit.org/b/130026> + + Generate the shorthand version of "test al, imm" when possible. + + Reviewed by Michael Saboff. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::testb_i8r): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for sub_ir when register is accumulator. + <https://webkit.org/b/130025> + + Generate the shorthand version of "sub eax, imm" when possible. + + Reviewed by Michael Saboff. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::subl_ir): + (JSC::X86Assembler::subq_ir): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for add_ir when register is accumulator. + <https://webkit.org/b/130024> + + Generate the shorthand version of "add eax, imm" when possible. + + Reviewed by Michael Saboff. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::addl_ir): + (JSC::X86Assembler::addq_ir): + +2014-03-10 Mark Hahnenberg <mhahnenberg@apple.com> + + writeBarrier in emitPutReplaceStub is unnecessary + https://bugs.webkit.org/show_bug.cgi?id=130030 + + Reviewed by Filip Pizlo. + + We already emit write barriers for each put-by-id when they're first compiled, so it's + redundant to emit a write barrier as part of the repatched code. + + * jit/Repatch.cpp: + (JSC::emitPutReplaceStub): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for xor_ir when register is accumulator. + <https://webkit.org/b/130008> + + Generate the shorthand version of "xor eax, imm" when possible. + + Reviewed by Benjamin Poulain. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::xorl_ir): + (JSC::X86Assembler::xorq_ir): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for or_ir when register is accumulator. + <https://webkit.org/b/130007> + + Generate the shorthand version of "or eax, imm" when possible. + + Reviewed by Benjamin Poulain. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::orl_ir): + (JSC::X86Assembler::orq_ir): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for test_ir when register is accumulator. + <https://webkit.org/b/130006> + + Generate the shorthand version of "test eax, imm" when possible. + + Reviewed by Benjamin Poulain. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::testl_i32r): + (JSC::X86Assembler::testq_i32r): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for cmp_ir when register is accumulator. + <https://webkit.org/b/130005> + + Generate the shorthand version of "cmp eax, imm" when possible. + + Reviewed by Benjamin Poulain. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::cmpl_ir): + (JSC::X86Assembler::cmpq_ir): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for store64(imm, address) when imm fits in 32 bits. + <https://webkit.org/b/130002> + + Generate this: + + mov [address], imm32 + + Instead of this: + + mov scratchRegister, imm32 + mov [address], scratchRegister + + For store64(imm, address) where the 64-bit immediate can be passed as + a sign-extended 32-bit value. + + Reviewed by Benjamin Poulain. + + * assembler/MacroAssemblerX86_64.h: + (CAN_SIGN_EXTEND_32_64): + (JSC::MacroAssemblerX86_64::store64): + +2014-03-10 Andreas Kling <akling@apple.com> + + [X86_64] Smaller code for xchg_rr when one register is accumulator. + <https://webkit.org/b/130004> + + Generate the 1-byte version of "xchg eax, reg" when possible. + + Reviewed by Benjamin Poulain. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::xchgl_rr): + (JSC::X86Assembler::xchgq_rr): + +2014-03-09 Filip Pizlo <fpizlo@apple.com> + + GPRInfo::toIndex should return InvalidIndex for non-temp registers on ARM64 + https://bugs.webkit.org/show_bug.cgi?id=129998 + + Reviewed by Geoffrey Garen. + + Not only is that the established contract, but this is used to signal to + ScratchRegisterAllocator that the register doesn't need locking since it isn't a register + that this allocator would use. In the FTL, we may have an inline cache where LLVM had used + some non-temp register (i.e. a register that JSC itself wouldn't have used). This is totally + fine but previously it would have led to either an assertion failure, or data corruption, in + the ScratchRegisterAllocator. + + * jit/GPRInfo.h: + (JSC::GPRInfo::toIndex): + +2014-03-09 Filip Pizlo <fpizlo@apple.com> + + FTL fails the new equals-masquerader strictEqualConstant test + https://bugs.webkit.org/show_bug.cgi?id=129996 + + Reviewed by Mark Lam. + + It turns out that the FTL was trying to do the masquerading stuff for ===null. But + that's wrong since none of the other engines do it. The DFG even had an ancient + FIXME about doing it - but that doesn't make sense since the LLInt and baseline JIT + don't do it and JSValue::strictEqual() doesn't do it. + + Remove the FIXME and remove the extra checks in the FTL. + + This is a glorious patch: nothing but red and it fixes a test failure. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStrictEqForConstant): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEqConstant): + +2014-03-09 Andreas Kling <akling@apple.com> + + Short-circuit JSGlobalObjectInspectorController when not inspecting. + <https://webkit.org/b/129995> + + Add an early return in reportAPIException() when the console agent + is disabled. This avoids expensive symbolication during exceptions + if there's nobody expecting the fancy backtrace anyway. + + ~2% progression on DYEB on my MBP. + + Reviewed by Geoff Garen. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + +2014-03-09 Andreas Kling <akling@apple.com> + + Inline the trivial parts of GC deferral. + <https://webkit.org/b/129984> + + Made most of the functions called by the DeferGC RAII object inline + to avoid function call overhead. + + Looks like ~1% progression on DYEB. + + Reviewed by Geoffrey Garen. + + * heap/Heap.cpp: + * heap/Heap.h: + (JSC::Heap::incrementDeferralDepth): + (JSC::Heap::decrementDeferralDepth): + (JSC::Heap::collectIfNecessaryOrDefer): + (JSC::Heap::decrementDeferralDepthAndGCIfNeeded): + +2014-03-08 Mark Lam <mark.lam@apple.com> + + 32-bit x86 handleUncaughtException returns to wrong location after a stack overflow. + <https://webkit.org/b/129969> + + Reviewed by Geoffrey Garen. + + The 32-bit version of handleUncaughtException was missing the handling of an + edge case for stack overflows where the current frame may already be the + sentinel frame. This edge case was handled in the 64-bit version. The fix + is to bring the 32-bit version up to parity. + + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * llint/LowLevelInterpreter32_64.asm: + +2014-03-07 Mark Lam <mark.lam@apple.com> + + Fix bugs in 32-bit Structure implementation. + <https://webkit.org/b/129947> + + Reviewed by Mark Hahnenberg. + + Added the loading of the Structure (from the JSCell) before use that was + missing in a few places. Also added more test cases to equals-masquerader.js. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * llint/LowLevelInterpreter32_64.asm: + * tests/stress/equals-masquerader.js: + (equalsNull): + (notEqualsNull): + (strictEqualsNull): + (strictNotEqualsNull): + (equalsUndefined): + (notEqualsUndefined): + (strictEqualsUndefined): + (strictNotEqualsUndefined): + (isFalsey): + (test): + +2014-03-07 Andrew Trick <atrick@apple.com> + + Temporarily disable repeat-out-of-bounds stress tests pending fix for 129953. + https://bugs.webkit.org/show_bug.cgi?id=129954 + + Reviewed by Filip Pizlo. + + * tests/stress/float32-repeat-out-of-bounds.js: + * tests/stress/int8-repeat-out-of-bounds.js: + +2014-03-07 Michael Saboff <msaboff@apple.com> + + .cfi directives in LowLevelInterpreter.cpp are providing no benefit + https://bugs.webkit.org/show_bug.cgi?id=129945 + + Reviewed by Mark Lam. + + Removed .cfi directive. Verified that stack traces didn't regress in crash reporter + or in lldb. + + * llint/LowLevelInterpreter.cpp: + +2014-03-07 Oliver Hunt <oliver@apple.com> + + Continue hangs when performing for-of over arguments + https://bugs.webkit.org/show_bug.cgi?id=129915 + + Reviewed by Geoffrey Garen. + + Put the continue label in the right place + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitEnumeration): + +2014-03-07 peavo@outlook.com <peavo@outlook.com> + + [Win64] Compile error after r165128. + https://bugs.webkit.org/show_bug.cgi?id=129807 + + Reviewed by Mark Lam. + + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: + Check platform environment variable to determine if an assembler file should be generated. + +2014-03-07 Michael Saboff <msaboff@apple.com> + + Clarify how we deal with "special" registers + https://bugs.webkit.org/show_bug.cgi?id=129806 + + Already reviewed change being relanded. + + Relanding change set r165196 as it wasn't responsible for the breakage reported in + https://bugs.webkit.org/show_bug.cgi?id=129822. That appears to be a build or + + Reviewed by Michael Saboff. + configuration issue. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::lastRegister): + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::nextRegister): + * ftl/FTLLocation.cpp: + (JSC::FTL::Location::restoreInto): + * ftl/FTLSaveRestore.cpp: + (JSC::FTL::saveAllRegisters): + (JSC::FTL::restoreAllRegisters): + * ftl/FTLSlowPathCall.cpp: + * jit/RegisterSet.cpp: + (JSC::RegisterSet::reservedHardwareRegisters): + (JSC::RegisterSet::runtimeRegisters): + (JSC::RegisterSet::specialRegisters): + (JSC::RegisterSet::calleeSaveRegisters): + * jit/RegisterSet.h: + +2014-03-07 Mark Hahnenberg <mhahnenberg@apple.com> + + Move GCActivityCallback to heap + https://bugs.webkit.org/show_bug.cgi?id=129457 + + Reviewed by Geoffrey Garen. + + All the other GC timer related stuff is there already. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/GCActivityCallback.cpp: Copied from Source/JavaScriptCore/runtime/GCActivityCallback.cpp. + * heap/GCActivityCallback.h: Copied from Source/JavaScriptCore/runtime/GCActivityCallback.h. + * runtime/GCActivityCallback.cpp: Removed. + * runtime/GCActivityCallback.h: Removed. + +2014-03-07 Andrew Trick <atrick@apple.com> + + Correct a comment typo from: + FLT should call fmod directly on platforms where LLVM cannot relocate the libcall + https://bugs.webkit.org/show_bug.cgi?id=129865 + + Reviewed by Mark Lam. + + * ftl/FTLOutput.h: + (JSC::FTL::Output::doubleRem): + +2014-03-07 Mark Hahnenberg <mhahnenberg@apple.com> + + Use OwnPtr in StructureIDTable + https://bugs.webkit.org/show_bug.cgi?id=129828 + + Reviewed by Geoffrey Garen. + + This reduces the amount of boilerplate and fixes a memory leak. + + * runtime/StructureIDTable.cpp: + (JSC::StructureIDTable::StructureIDTable): + (JSC::StructureIDTable::resize): + (JSC::StructureIDTable::flushOldTables): + (JSC::StructureIDTable::allocateID): + (JSC::StructureIDTable::deallocateID): + * runtime/StructureIDTable.h: + (JSC::StructureIDTable::table): + (JSC::StructureIDTable::get): + +2014-03-07 Andrew Trick <atrick@apple.com> + + FLT should call fmod directly on platforms where LLVM cannot relocate the libcall + https://bugs.webkit.org/show_bug.cgi?id=129865 + + Reviewed by Filip Pizlo. + + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLOutput.h: + (JSC::FTL::Output::doubleRem): + +2014-03-06 Filip Pizlo <fpizlo@apple.com> + + If the FTL is build-time enabled then it should be run-time enabled. + + Rubber stamped by Geoffrey Garen. + + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + * runtime/Options.h: + +2014-03-06 Joseph Pecoraro <pecoraro@apple.com> + + [OS X] Web Inspector: Allow Apps using JavaScriptCore to access "com.apple.webinspector" mach port + https://bugs.webkit.org/show_bug.cgi?id=129852 + + Reviewed by Geoffrey Garen. + + * framework.sb: Added. + Sandbox extension to allow access to "com.apple.webinspector". + + * JavaScriptCore.xcodeproj/project.pbxproj: + Add a Copy Resources build phase and include framework.sb. + + * Configurations/JavaScriptCore.xcconfig: + Do not copy framework.sb on iOS. + +2014-03-06 Mark Hahnenberg <mhahnenberg@apple.com> + + JSGlobalContextRelease incorrectly handles saving/restoring IdentifierTable + https://bugs.webkit.org/show_bug.cgi?id=129858 + + Reviewed by Mark Lam. + + It was correct (but really ugly) prior to the combining of APIEntryShim and JSLock, + but now it ends up overwriting the IdentifierTable that JSLock just restored. + + * API/JSContextRef.cpp: + (JSGlobalContextRelease): + +2014-03-06 Oliver Hunt <oliver@apple.com> + + Fix FTL build. + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + +2014-03-06 Brent Fulgham <bfulgham@apple.com> + + Unreviewed build fix after r165128. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: The SEH flag was not getting set when + performing 'Production' and 'DebugSuffix' type builds. + +2014-03-06 Julien Brianceau <jbriance@cisco.com> + + Unreviewed, fix style in my previous commit. + https://bugs.webkit.org/show_bug.cgi?id=129833 + + * runtime/JSConsole.cpp: + +2014-03-06 Julien Brianceau <jbriance@cisco.com> + + Build fix: add missing include in JSConole.cpp. + https://bugs.webkit.org/show_bug.cgi?id=129833 + + Reviewed by Oliver Hunt. + + * runtime/JSConsole.cpp: + +2014-03-06 Oliver Hunt <oliver@apple.com> + + Fix ARMv7 + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2014-03-06 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r165196. + http://trac.webkit.org/changeset/165196 + https://bugs.webkit.org/show_bug.cgi?id=129822 + + broke arm64 on hardware (Requested by bfulgham on #webkit). + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::lastRegister): + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::isStackRelated): + (JSC::MacroAssembler::firstRealRegister): + (JSC::MacroAssembler::nextRegister): + (JSC::MacroAssembler::secondRealRegister): + * ftl/FTLLocation.cpp: + (JSC::FTL::Location::restoreInto): + * ftl/FTLSaveRestore.cpp: + (JSC::FTL::saveAllRegisters): + (JSC::FTL::restoreAllRegisters): + * ftl/FTLSlowPathCall.cpp: + * jit/RegisterSet.cpp: + (JSC::RegisterSet::specialRegisters): + (JSC::RegisterSet::calleeSaveRegisters): + * jit/RegisterSet.h: + +2014-03-06 Mark Lam <mark.lam@apple.com> + + REGRESSION(r165205): broke the CLOOP build (Requested by smfr on #webkit). + <https://webkit.org/b/129813> + + Reviewed by Michael Saboff. + + Fixed broken C loop LLINT build. + + * llint/LowLevelInterpreter.cpp: + (JSC::CLoop::execute): + * offlineasm/cloop.rb: + +2014-03-03 Oliver Hunt <oliver@apple.com> + + Support caching of custom setters + https://bugs.webkit.org/show_bug.cgi?id=129519 + + Reviewed by Filip Pizlo. + + This patch adds caching of assignment to properties that + are backed by C functions. This provides most of the leg + work required to start supporting setters, and resolves + the remaining regressions from moving DOM properties up + the prototype chain. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/PolymorphicPutByIdList.cpp: + (JSC::PutByIdAccess::visitWeak): + (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): + (JSC::PolymorphicPutByIdList::from): + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::transition): + (JSC::PutByIdAccess::replace): + (JSC::PutByIdAccess::customSetter): + (JSC::PutByIdAccess::isCustom): + (JSC::PutByIdAccess::oldStructure): + (JSC::PutByIdAccess::chain): + (JSC::PutByIdAccess::stubRoutine): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::dump): + * bytecode/PutByIdStatus.h: + (JSC::PutByIdStatus::PutByIdStatus): + (JSC::PutByIdStatus::takesSlowPath): + (JSC::PutByIdStatus::makesCalls): + * bytecode/StructureStubInfo.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPutById): + (JSC::DFG::ByteCodeParser::handlePutById): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifier): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compile): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JITInlineCacheGenerator.cpp: + (JSC::JITByIdGenerator::JITByIdGenerator): + (JSC::JITPutByIdGenerator::JITPutByIdGenerator): + * jit/JITInlineCacheGenerator.h: + (JSC::JITGetByIdGenerator::JITGetByIdGenerator): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_put_by_id): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_put_by_id): + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::emitCustomSetterStub): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * jit/SpillRegistersMode.h: Added. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Lookup.h: + (JSC::putEntry): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::setCacheableCustomProperty): + (JSC::PutPropertySlot::customSetter): + (JSC::PutPropertySlot::isCacheablePut): + (JSC::PutPropertySlot::isCacheableCustomProperty): + (JSC::PutPropertySlot::cachedOffset): + +2014-03-06 Filip Pizlo <fpizlo@apple.com> + + FTL arity fixup should work on ARM64 + https://bugs.webkit.org/show_bug.cgi?id=129810 + + Reviewed by Michael Saboff. + + - Using regT5 to pass the thunk return address to arityFixup is shady since that's a + callee-save. + + - The FTL path was assuming X86 conventions for where SP points at the top of the prologue. + + This makes some more tests pass. + + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compileFunction): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::prologueStackPointerDelta): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/ThunkGenerators.cpp: + (JSC::arityFixup): + * llint/LowLevelInterpreter64.asm: + * offlineasm/arm64.rb: + * offlineasm/x86.rb: In addition to the t7 change, make t6 agree with GPRInfo.h. + +2014-03-06 Mark Hahnenberg <mhahnenberg@apple.com> + + Fix write barriers in Repatch.cpp for !ENABLE(DFG_JIT) platforms after r165128 + https://bugs.webkit.org/show_bug.cgi?id=129760 + + Reviewed by Geoffrey Garen. + + r165128 disabled the write barrier fast path for inline caches on !ENABLE(DFG_JIT) platforms. + The fix is to refactor the write barrier code into AssemblyHelpers and use that everywhere. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::checkMarkByte): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + * jit/Repatch.cpp: + (JSC::writeBarrier): + +2014-03-06 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Expose the console object in JSContexts to interact with Web Inspector + https://bugs.webkit.org/show_bug.cgi?id=127944 + + Reviewed by Geoffrey Garen. + + Always expose the Console object in JSContexts, just like we + do for web pages. The default behavior will route to an + attached JSContext inspector. This can be overriden by + setting the ConsoleClient on the JSGlobalObject, which WebCore + does to get slightly different behavior. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + Update build systems. + + * API/tests/testapi.js: + * API/tests/testapi.mm: + Test that "console" exists in C and ObjC contexts. + + * runtime/ConsoleClient.cpp: Added. + (JSC::ConsoleClient::printURLAndPosition): + (JSC::ConsoleClient::printMessagePrefix): + (JSC::ConsoleClient::printConsoleMessage): + (JSC::ConsoleClient::printConsoleMessageWithArguments): + (JSC::ConsoleClient::internalMessageWithTypeAndLevel): + (JSC::ConsoleClient::logWithLevel): + (JSC::ConsoleClient::clear): + (JSC::ConsoleClient::dir): + (JSC::ConsoleClient::dirXML): + (JSC::ConsoleClient::table): + (JSC::ConsoleClient::trace): + (JSC::ConsoleClient::assertCondition): + (JSC::ConsoleClient::group): + (JSC::ConsoleClient::groupCollapsed): + (JSC::ConsoleClient::groupEnd): + * runtime/ConsoleClient.h: Added. + (JSC::ConsoleClient::~ConsoleClient): + New private interface for handling the console object's methods. + A lot of the methods funnel through messageWithTypeAndLevel. + + * runtime/ConsoleTypes.h: Renamed from Source/JavaScriptCore/inspector/ConsoleTypes.h. + Moved to JSC namespace. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::visitChildren): + Create the "console" object when initializing the environment. + Also set the default console client to be the JS context inspector. + + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::setConsoleClient): + (JSC::JSGlobalObject::consoleClient): + Ability to change the console client, so WebCore can set a custom client. + + * runtime/ConsolePrototype.cpp: Added. + (JSC::ConsolePrototype::finishCreation): + (JSC::valueToStringWithUndefinedOrNullCheck): + (JSC::consoleLogWithLevel): + (JSC::consoleProtoFuncDebug): + (JSC::consoleProtoFuncError): + (JSC::consoleProtoFuncLog): + (JSC::consoleProtoFuncWarn): + (JSC::consoleProtoFuncClear): + (JSC::consoleProtoFuncDir): + (JSC::consoleProtoFuncDirXML): + (JSC::consoleProtoFuncTable): + (JSC::consoleProtoFuncTrace): + (JSC::consoleProtoFuncAssert): + (JSC::consoleProtoFuncCount): + (JSC::consoleProtoFuncProfile): + (JSC::consoleProtoFuncProfileEnd): + (JSC::consoleProtoFuncTime): + (JSC::consoleProtoFuncTimeEnd): + (JSC::consoleProtoFuncTimeStamp): + (JSC::consoleProtoFuncGroup): + (JSC::consoleProtoFuncGroupCollapsed): + (JSC::consoleProtoFuncGroupEnd): + * runtime/ConsolePrototype.h: Added. + (JSC::ConsolePrototype::create): + (JSC::ConsolePrototype::createStructure): + (JSC::ConsolePrototype::ConsolePrototype): + Define the console object interface. Parse out required / expected + arguments and throw expcetions when methods are misused. + + * runtime/JSConsole.cpp: Added. + * runtime/JSConsole.h: Added. + (JSC::JSConsole::createStructure): + (JSC::JSConsole::create): + (JSC::JSConsole::JSConsole): + Empty "console" object. Everything is in the prototype. + + * inspector/JSConsoleClient.cpp: Added. + (Inspector::JSConsoleClient::JSGlobalObjectConsole): + (Inspector::JSConsoleClient::count): + (Inspector::JSConsoleClient::profile): + (Inspector::JSConsoleClient::profileEnd): + (Inspector::JSConsoleClient::time): + (Inspector::JSConsoleClient::timeEnd): + (Inspector::JSConsoleClient::timeStamp): + (Inspector::JSConsoleClient::warnUnimplemented): + (Inspector::JSConsoleClient::internalAddMessage): + * inspector/JSConsoleClient.h: Added. + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::consoleClient): + * inspector/JSGlobalObjectInspectorController.h: + Default JSContext ConsoleClient implementation. Handle nearly + everything exception profile/profileEnd and timeStamp. + +2014-03-06 Andreas Kling <akling@apple.com> + + Drop unlinked function code on memory pressure. + <https://webkit.org/b/129789> + + Make VM::discardAllCode() also drop UnlinkedFunctionCodeBlocks that + are not currently being compiled. + + 4.5 MB progression on Membuster. + + Reviewed by Geoffrey Garen. + + * heap/Heap.cpp: + (JSC::Heap::deleteAllUnlinkedFunctionCode): + * heap/Heap.h: + * runtime/VM.cpp: + (JSC::VM::discardAllCode): + +2014-03-06 Filip Pizlo <fpizlo@apple.com> + + Clarify how we deal with "special" registers + https://bugs.webkit.org/show_bug.cgi?id=129806 + + Reviewed by Michael Saboff. + + Previously we had two different places that defined what "stack" registers are, a thing + called "specialRegisters" that had unclear meaning, and a really weird "firstRealRegister"/ + "secondRealRegister"/"nextRegister" idiom in MacroAssembler that appeared to only be used by + one place and had a baked-in notion of what it meant for a register to be "real" or not. + + It's not cool to use words like "real" and "special" to describe registers, especially if you + fail to qualify what that means. This originally made sense on X86 - "real" registers were + the ones that weren't "stack related" (so "real" was the opposite of "stack"). But on ARM64, + you also have to worry about the LR register, which we'd want to say is "not real" but it's + also not a "stack" register. This got super confusing. + + So, this patch removes any mention of "real" registers, consolidates the knowledge of what is + a "stack" register, and uses the word special only in places where it's clearly defined and + where no better word comes to mind. + + This cleans up the code and fixes what seems like it was probably a harmless ARM64 bug: the + Reg and RegisterSet data structures would sometimes think that FP was Q0. Somehow this + magically didn't break anything because you never need to save/restore either FP or Q0, but + it was still super weird. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::lastRegister): + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::nextRegister): + * ftl/FTLLocation.cpp: + (JSC::FTL::Location::restoreInto): + * ftl/FTLSaveRestore.cpp: + (JSC::FTL::saveAllRegisters): + (JSC::FTL::restoreAllRegisters): + * ftl/FTLSlowPathCall.cpp: + * jit/RegisterSet.cpp: + (JSC::RegisterSet::reservedHardwareRegisters): + (JSC::RegisterSet::runtimeRegisters): + (JSC::RegisterSet::specialRegisters): + (JSC::RegisterSet::calleeSaveRegisters): + * jit/RegisterSet.h: + +2014-03-06 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix build. + + * disassembler/ARM64Disassembler.cpp: + +2014-03-06 Filip Pizlo <fpizlo@apple.com> + + Use the LLVM disassembler on ARM64 if we are enabling the FTL + https://bugs.webkit.org/show_bug.cgi?id=129785 + + Reviewed by Geoffrey Garen. + + Our disassembler can't handle some of the code sequences that LLVM emits. LLVM's disassembler + is strictly more capable at this point. Use it if it's available. + + * disassembler/ARM64Disassembler.cpp: + (JSC::tryToDisassemble): + +2014-03-05 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Reduce RWI message frequency + https://bugs.webkit.org/show_bug.cgi?id=129767 + + Reviewed by Timothy Hatcher. + + This used to be 0.2s and changed by accident to 0.02s. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::pushListingSoon): + +2014-03-05 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r165141, r165157, and r165158. + http://trac.webkit.org/changeset/165141 + http://trac.webkit.org/changeset/165157 + http://trac.webkit.org/changeset/165158 + https://bugs.webkit.org/show_bug.cgi?id=129772 + + "broke ftl" (Requested by olliej_ on #webkit). + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/PolymorphicPutByIdList.cpp: + (JSC::PutByIdAccess::visitWeak): + (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): + (JSC::PolymorphicPutByIdList::from): + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::transition): + (JSC::PutByIdAccess::replace): + (JSC::PutByIdAccess::oldStructure): + (JSC::PutByIdAccess::chain): + (JSC::PutByIdAccess::stubRoutine): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::dump): + * bytecode/PutByIdStatus.h: + (JSC::PutByIdStatus::PutByIdStatus): + (JSC::PutByIdStatus::takesSlowPath): + * bytecode/StructureStubInfo.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPutById): + (JSC::DFG::ByteCodeParser::handlePutById): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifier): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JITInlineCacheGenerator.cpp: + (JSC::JITByIdGenerator::JITByIdGenerator): + (JSC::JITPutByIdGenerator::JITPutByIdGenerator): + * jit/JITInlineCacheGenerator.h: + (JSC::JITGetByIdGenerator::JITGetByIdGenerator): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_put_by_id): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_put_by_id): + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * jit/SpillRegistersMode.h: Removed. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Lookup.h: + (JSC::putEntry): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::isCacheable): + (JSC::PutPropertySlot::cachedOffset): + +2014-03-05 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Prevent possible deadlock in view indication + https://bugs.webkit.org/show_bug.cgi?id=129766 + + Reviewed by Geoffrey Garen. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::receivedIndicateMessage): + +2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> + + JSObject::fastGetOwnPropertySlot does a slow check for OverridesGetOwnPropertySlot + https://bugs.webkit.org/show_bug.cgi?id=129754 + + Reviewed by Geoffrey Garen. + + InlineTypeFlags are stored in JSCell, so we can just load those instead of going through the TypeInfo. + + * runtime/JSCell.h: + (JSC::JSCell::inlineTypeFlags): + * runtime/JSObject.h: + (JSC::JSObject::fastGetOwnPropertySlot): + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::TypeInfo): + (JSC::TypeInfo::overridesGetOwnPropertySlot): + +2014-03-05 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ASSERTION FAILED: m_javaScriptBreakpoints.isEmpty() + https://bugs.webkit.org/show_bug.cgi?id=129763 + + Reviewed by Geoffrey Garen. + + Clear the list of all breakpoints, including unresolved breakpoints. + + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): + +2014-03-05 Mark Lam <mark.lam@apple.com> + + llint_slow_path_check_has_instance() should not adjust PC before accessing operands. + <https://webkit.org/b/129768> + + Reviewed by Mark Hahnenberg. + + When evaluating "a instanceof b" where b is an object that ImplementsHasInstance + and OverridesHasInstance (e.g. a bound function), the LLINT will take the slow + path llint_slow_path_check_has_instance(), and execute a code path that does the + following: + 1. Adjusts the byte code PC to the jump target PC. + 2. For the purpose of storing the result, get the result registerIndex from the + 1st operand using the PC as if the PC is still pointing to op_check_has_instance + bytecode. + + The result is that whatever value resides after where the jump target PC is will + be used as a result register value. Depending on what that value is, the result + can be: + 1. the code coincidently works correctly + 2. memory corruption + 3. crashes + + The fix is to only adjust the byte code PC after we have stored the result. + + * llint/LLIntSlowPaths.cpp: + (llint_slow_path_check_has_instance): + +2014-03-05 Ryosuke Niwa <rniwa@webkit.org> + + Another build fix attempt after r165141. + + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + +2014-03-05 Ryosuke Niwa <rniwa@webkit.org> + + FTL build fix attempt after r165141. + + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + +2014-03-05 Gavin Barraclough <barraclough@apple.com> + + https://bugs.webkit.org/show_bug.cgi?id=128625 + Add fast mapping from StringImpl to JSString + + Unreviewed roll-out. + + Reverting r164347, r165054, r165066 - not clear the performance tradeoff was right. + + * runtime/JSString.cpp: + * runtime/JSString.h: + * runtime/VM.cpp: + (JSC::VM::createLeaked): + * runtime/VM.h: + +2014-03-03 Oliver Hunt <oliver@apple.com> + + Support caching of custom setters + https://bugs.webkit.org/show_bug.cgi?id=129519 + + Reviewed by Filip Pizlo. + + This patch adds caching of assignment to properties that + are backed by C functions. This provides most of the leg + work required to start supporting setters, and resolves + the remaining regressions from moving DOM properties up + the prototype chain. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/PolymorphicPutByIdList.cpp: + (JSC::PutByIdAccess::visitWeak): + (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): + (JSC::PolymorphicPutByIdList::from): + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::transition): + (JSC::PutByIdAccess::replace): + (JSC::PutByIdAccess::customSetter): + (JSC::PutByIdAccess::isCustom): + (JSC::PutByIdAccess::oldStructure): + (JSC::PutByIdAccess::chain): + (JSC::PutByIdAccess::stubRoutine): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::dump): + * bytecode/PutByIdStatus.h: + (JSC::PutByIdStatus::PutByIdStatus): + (JSC::PutByIdStatus::takesSlowPath): + (JSC::PutByIdStatus::makesCalls): + * bytecode/StructureStubInfo.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPutById): + (JSC::DFG::ByteCodeParser::handlePutById): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifier): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::compile): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JITInlineCacheGenerator.cpp: + (JSC::JITByIdGenerator::JITByIdGenerator): + (JSC::JITPutByIdGenerator::JITPutByIdGenerator): + * jit/JITInlineCacheGenerator.h: + (JSC::JITGetByIdGenerator::JITGetByIdGenerator): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_put_by_id): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_put_by_id): + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::emitCustomSetterStub): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + * jit/SpillRegistersMode.h: Added. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Lookup.h: + (JSC::putEntry): + * runtime/PutPropertySlot.h: + (JSC::PutPropertySlot::setCacheableCustomProperty): + (JSC::PutPropertySlot::customSetter): + (JSC::PutPropertySlot::isCacheablePut): + (JSC::PutPropertySlot::isCacheableCustomProperty): + (JSC::PutPropertySlot::cachedOffset): + +2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> + + JSCell::m_gcData should encode its information differently + https://bugs.webkit.org/show_bug.cgi?id=129741 + + Reviewed by Geoffrey Garen. + + We want to keep track of three GC states for an object: + + 1. Not marked (which implies not in the remembered set) + 2. Marked but not in the remembered set + 3. Marked and in the remembered set + + Currently we only indicate marked vs. not marked in JSCell::m_gcData. During a write + barrier, we only want to take the slow path if the object being stored to is in state #2. + We'd like to make the test for state #2 as fast as possible, which means making it a + compare against 0. + + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::osrWriteBarrier): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::checkMarkByte): + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::allocateCell): + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + * heap/Heap.cpp: + (JSC::Heap::clearRememberedSet): + (JSC::Heap::addToRememberedSet): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::checkMarkByte): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::checkMarkByte): + (JSC::JIT::emitWriteBarrier): + * jit/Repatch.cpp: + (JSC::writeBarrier): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSCell.h: + (JSC::JSCell::mark): + (JSC::JSCell::remember): + (JSC::JSCell::forget): + (JSC::JSCell::isMarked): + (JSC::JSCell::isRemembered): + * runtime/JSCellInlines.h: + (JSC::JSCell::JSCell): + * runtime/StructureIDBlob.h: + (JSC::StructureIDBlob::StructureIDBlob): + +2014-03-05 Filip Pizlo <fpizlo@apple.com> + + More FTL ARM fixes + https://bugs.webkit.org/show_bug.cgi?id=129755 + + Reviewed by Geoffrey Garen. + + - Be more defensive about inline caches that have degenerate chains. + + - Temporarily switch to allocating all MCJIT memory in the executable pool on non-x86 + platforms. The bug tracking the real fix is: https://bugs.webkit.org/show_bug.cgi?id=129756 + + - Don't even emit intrinsic declarations on non-x86 platforms. + + - More debug printing support. + + - Don't use vmCall() in the prologue. This should have crashed on all platforms all the time + but somehow it gets lucky on x86. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::appendVariant): + (JSC::GetByIdStatus::computeForChain): + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdStatus.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::appendVariant): + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.h: + * bytecode/StructureSet.h: + (JSC::StructureSet::overlaps): + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLDataSection.cpp: + (JSC::FTL::DataSection::DataSection): + (JSC::FTL::DataSection::~DataSection): + * ftl/FTLDataSection.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + * ftl/FTLOutput.h: + (JSC::FTL::Output::doubleSin): + (JSC::FTL::Output::doubleCos): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::dumpInContext): + * runtime/JSCell.h: + (JSC::JSCell::structureID): + +2014-03-05 peavo@outlook.com <peavo@outlook.com> + + [Win32][LLINT] Crash when running JSC stress tests. + https://bugs.webkit.org/show_bug.cgi?id=129429 + + On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory, + where the guard page is a barrier between committed and uncommitted memory. + When data from the guard page is read or written, the guard page is moved, and memory is committed. + This is how the system grows the stack. + When using the C stack on Windows we need to precommit the needed stack space. + Otherwise we might crash later if we access uncommitted stack memory. + This can happen if we allocate stack space larger than the page guard size (4K). + The system does not get the chance to move the guard page, and commit more memory, + and we crash if uncommitted memory is accessed. + The MSVC compiler fixes this by inserting a call to the _chkstk() function, + when needed, see http://support.microsoft.com/kb/100775. + + Reviewed by Geoffrey Garen. + + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.sh: Enable LLINT. + * jit/Repatch.cpp: + (JSC::writeBarrier): Compile fix when DFG_JIT is not enabled. + * offlineasm/x86.rb: Compile fix, and small simplification. + * runtime/VM.cpp: + (JSC::preCommitStackMemory): Added function to precommit stack memory. + (JSC::VM::updateStackLimit): Call function to precommit stack memory when stack limit is updated. + +2014-03-05 Michael Saboff <msaboff@apple.com> + + JSDataViewPrototype::getData() and setData() crash on platforms that don't allow unaligned accesses + https://bugs.webkit.org/show_bug.cgi?id=129746 + + Reviewed by Filip Pizlo. + + Changed to use a union to manually assemble or disassemble the various types + from / to the corresponding bytes. All memory access is now done using + byte accesses. + + * runtime/JSDataViewPrototype.cpp: + (JSC::getData): + (JSC::setData): + +2014-03-05 Filip Pizlo <fpizlo@apple.com> + + FTL loadStructure always generates invalid IR + https://bugs.webkit.org/show_bug.cgi?id=129747 + + Reviewed by Mark Hahnenberg. + + As the comment at the top of FTL::Output states, the FTL doesn't use LLVM's notion + of pointers. LLVM's notion of pointers tries to model C, in the sense that you have + to have a pointer to a type, and you can only load things of that type from that + pointer. Pointer arithmetic is basically not possible except through the bizarre + getelementptr operator. This doesn't fit with how the JS object model works since + the JS object model doesn't consist of nice and tidy C types placed in C arrays. + Also, it would be impossible to use getelementptr and LLVM pointers for accessing + any of JSC's C or C++ objects unless we went through the exercise of redeclaring + all of our fundamental data structures in LLVM IR as LLVM types. Clang could do + this for us, but that would require that to use the FTL, JSC itself would have to + be compiled with clang. Worse, it would have to be compiled with a clang that uses + a version of LLVM that is compatible with the one against which the FTL is linked. + Yuck! + + The solution is to NEVER use LLVM pointers. This has always been the case in the + FTL. But it causes some confusion. + + Not using LLVM pointers means that if the FTL has a "pointer", it's actually a + pointer-wide integer (m_out.intPtr in FTL-speak). The act of "loading" and + "storing" from or to a pointer involves first bitcasting the intPtr to a real LLVM + pointer that has the type that we want. The load and store operations over pointers + are called Output::load* and Output::store*, where * is one of "8", "16", "32", + "64", "Ptr", "Float", or "Double. + + There is unavoidable confusion here. It would be bizarre for the FTL to call its + "pointer-wide integers" anything other than "pointers", since they are, in all + respects that we care about, simply pointers. But they are *not* LLVM pointers and + they never will be that. + + There is one exception to this "no pointers" rule. The FTL does use actual LLVM + pointers for refering to LLVM alloca's - i.e. local variables. To try to reduce + confusion, we call these "references". So an "FTL reference" is actually an "LLVM + pointer", while an "FTL pointer" is actually an "LLVM integer". FTL references have + methods for access called Output::get and Output::set. These lower to LLVM load + and store, since FTL references are just LLVM pointers. + + This confusion appears to have led to incorrect code in loadStructure(). + loadStructure() was using get() and set() to access FTL pointers. But those methods + don't work on FTL pointers and never will, since they are for FTL references. + + The worst part of this is that it was previously impossible to have test coverage + for the relevant path (MasqueradesAsUndefined) without writing a DRT test. This + patch fixes this by introducing a Masquerader object to jsc.cpp. + + * ftl/FTLAbstractHeapRepository.h: Add an abstract heap for the structure table. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::loadStructure): This was wrong. + * ftl/FTLOutput.h: Add a comment to disuade people from using get() and set(). + * jsc.cpp: Give us the power to test for MasqueradesAsUndefined. + (WTF::Masquerader::Masquerader): + (WTF::Masquerader::create): + (WTF::Masquerader::createStructure): + (GlobalObject::finishCreation): + (functionMakeMasquerader): + * tests/stress/equals-masquerader.js: Added. + (foo): + (test): + +2014-03-05 Anders Carlsson <andersca@apple.com> + + Tweak after r165109 to avoid extra copies + https://bugs.webkit.org/show_bug.cgi?id=129745 + + Reviewed by Geoffrey Garen. + + * heap/Heap.cpp: + (JSC::Heap::visitProtectedObjects): + (JSC::Heap::visitTempSortVectors): + (JSC::Heap::clearRememberedSet): + * heap/Heap.h: + (JSC::Heap::forEachProtectedCell): + +2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> + + DFGStoreBarrierElisionPhase should should GCState directly instead of m_gcClobberSet when calling writesOverlap() + https://bugs.webkit.org/show_bug.cgi?id=129717 + + Reviewed by Filip Pizlo. + + * dfg/DFGStoreBarrierElisionPhase.cpp: + (JSC::DFG::StoreBarrierElisionPhase::StoreBarrierElisionPhase): + (JSC::DFG::StoreBarrierElisionPhase::couldCauseGC): + +2014-03-05 Mark Hahnenberg <mhahnenberg@apple.com> + + Use range-based loops where possible in Heap methods + https://bugs.webkit.org/show_bug.cgi?id=129513 + + Reviewed by Mark Lam. + + Replace old school iterator based loops with the new range-based loop hotness + for a better tomorrow. + + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::~CodeBlockSet): + (JSC::CodeBlockSet::clearMarks): + (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): + (JSC::CodeBlockSet::traceMarked): + * heap/Heap.cpp: + (JSC::Heap::visitProtectedObjects): + (JSC::Heap::visitTempSortVectors): + (JSC::Heap::clearRememberedSet): + * heap/Heap.h: + (JSC::Heap::forEachProtectedCell): + +2014-03-04 Filip Pizlo <fpizlo@apple.com> + + DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null) + https://bugs.webkit.org/show_bug.cgi?id=129563 + + Reviewed by Geoffrey Garen. + + Rolling this back in after fixing an assertion failure. speculateMisc() should have + said DFG_TYPE_CHECK instead of typeCheck. + + This adds a specialization of CompareStrictEq over Misc. I noticed the need for this + when I saw that we didn't support CompareStrictEq(Untyped) in FTL but that the main + user of this was EarleyBoyer, and in that benchmark what it was really doing was + comparing undefined, null, and booleans to each other. + + This also adds support for miscellaneous things that I needed to make my various test + cases work. This includes comparison over booleans and the various Throw-related node + types. + + This also improves constant folding of CompareStrictEq and CompareEq. + + Also found a bug where we were claiming that GetByVals on typed arrays are OutOfBounds + based on profiling, which caused some downstream badness. We don't actually support + compiling OutOfBounds GetByVals on typed arrays. The DFG would ignore the flag and just + emit a bounds check, but in the FTL path, the SSA lowering phase would assume that it + shouldn't factor out the bounds check since the access is not InBounds but then the + backend would ignore the flag and assume that the bounds check was already emitted. + This showed up on an existing test but I added a test for this explicitly to have more + certain coverage. The fix is to not mark something as OutOfBounds if the semantics are + that we'll have a bounds check anyway. + + This is a 1% speed-up on Octane mostly because of raytrace, but also because of just + general progressions across the board. No speed-up yet on EarleyBoyer, since there is + still a lot more coverage work to be done there. + + * bytecode/SpeculatedType.cpp: + (JSC::speculationToAbbreviatedString): + (JSC::leastUpperBoundOfStrictlyEquivalentSpeculations): + (JSC::valuesCouldBeEqual): + * bytecode/SpeculatedType.h: + (JSC::isMiscSpeculation): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::refine): + * dfg/DFGArrayMode.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateMisc): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStrictEq): + (JSC::DFG::SpeculativeJIT::speculateMisc): + (JSC::DFG::SpeculativeJIT::speculate): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compileThrow): + (JSC::FTL::LowerDFGToLLVM::isNotMisc): + (JSC::FTL::LowerDFGToLLVM::isMisc): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateMisc): + * tests/stress/float32-array-out-of-bounds.js: Added. + * tests/stress/weird-equality-folding-cases.js: Added. + +2014-03-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r165085. + http://trac.webkit.org/changeset/165085 + https://bugs.webkit.org/show_bug.cgi?id=129729 + + Broke imported/w3c/html-templates/template-element/template- + content.html (Requested by ap on #webkit). + + * bytecode/SpeculatedType.cpp: + (JSC::speculationToAbbreviatedString): + * bytecode/SpeculatedType.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::refine): + * dfg/DFGArrayMode.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateBoolean): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStrictEq): + (JSC::DFG::SpeculativeJIT::speculate): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + * dfg/DFGSpeculativeJIT64.cpp: + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::speculate): + * tests/stress/float32-array-out-of-bounds.js: Removed. + * tests/stress/weird-equality-folding-cases.js: Removed. + +2014-03-04 Brian Burg <bburg@apple.com> + + Inspector does not restore breakpoints after a page reload + https://bugs.webkit.org/show_bug.cgi?id=129655 + + Reviewed by Joseph Pecoraro. + + Fix a regression introduced by r162096 that erroneously removed + the inspector backend's mapping of files to breakpoints whenever the + global object was cleared. + + The inspector's breakpoint mappings should only be cleared when the + debugger agent is disabled or destroyed. We should only clear the + debugger's breakpoint state when the global object is cleared. + + To make it clearer what state is being cleared, the two cases have + been split into separate methods. + + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::disable): + (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): + (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState): + (Inspector::InspectorDebuggerAgent::didClearGlobalObject): + * inspector/agents/InspectorDebuggerAgent.h: + +2014-03-04 Andreas Kling <akling@apple.com> + + Streamline JSValue::get(). + <https://webkit.org/b/129720> + + Fetch each Structure and VM only once when walking the prototype chain + in JSObject::getPropertySlot(), then pass it along to the functions + we call from there, so they don't have to re-fetch it. + + Reviewed by Geoff Garen. + + * runtime/JSObject.h: + (JSC::JSObject::inlineGetOwnPropertySlot): + (JSC::JSObject::fastGetOwnPropertySlot): + (JSC::JSObject::getPropertySlot): + +2014-03-01 Filip Pizlo <fpizlo@apple.com> + + DFG and FTL should specialize for and support CompareStrictEq over Misc (i.e. boolean, undefined, or null) + https://bugs.webkit.org/show_bug.cgi?id=129563 + + Reviewed by Geoffrey Garen. + + This adds a specialization of CompareStrictEq over Misc. I noticed the need for this + when I saw that we didn't support CompareStrictEq(Untyped) in FTL but that the main + user of this was EarleyBoyer, and in that benchmark what it was really doing was + comparing undefined, null, and booleans to each other. + + This also adds support for miscellaneous things that I needed to make my various test + cases work. This includes comparison over booleans and the various Throw-related node + types. + + This also improves constant folding of CompareStrictEq and CompareEq. + + Also found a bug where we were claiming that GetByVals on typed arrays are OutOfBounds + based on profiling, which caused some downstream badness. We don't actually support + compiling OutOfBounds GetByVals on typed arrays. The DFG would ignore the flag and just + emit a bounds check, but in the FTL path, the SSA lowering phase would assume that it + shouldn't factor out the bounds check since the access is not InBounds but then the + backend would ignore the flag and assume that the bounds check was already emitted. + This showed up on an existing test but I added a test for this explicitly to have more + certain coverage. The fix is to not mark something as OutOfBounds if the semantics are + that we'll have a bounds check anyway. + + This is a 1% speed-up on Octane mostly because of raytrace, but also because of just + general progressions across the board. No speed-up yet on EarleyBoyer, since there is + still a lot more coverage work to be done there. + + * bytecode/SpeculatedType.cpp: + (JSC::speculationToAbbreviatedString): + (JSC::leastUpperBoundOfStrictlyEquivalentSpeculations): + (JSC::valuesCouldBeEqual): + * bytecode/SpeculatedType.h: + (JSC::isMiscSpeculation): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateMisc): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStrictEq): + (JSC::DFG::SpeculativeJIT::speculateMisc): + (JSC::DFG::SpeculativeJIT::speculate): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compileMiscStrictEq): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compileThrow): + (JSC::FTL::LowerDFGToLLVM::isNotMisc): + (JSC::FTL::LowerDFGToLLVM::isMisc): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateMisc): + * tests/stress/float32-array-out-of-bounds.js: Added. + * tests/stress/weird-equality-folding-cases.js: Added. + +2014-03-04 Andreas Kling <akling@apple.com> + + Spam static branch prediction hints on JS bindings. + <https://webkit.org/b/129703> + + Add LIKELY hint to jsDynamicCast since it's always used in a context + where we expect it to succeed and takes an error path when it doesn't. + + Reviewed by Geoff Garen. + + * runtime/JSCell.h: + (JSC::jsDynamicCast): + +2014-03-04 Andreas Kling <akling@apple.com> + + Get to Structures more efficiently in JSCell::methodTable(). + <https://webkit.org/b/129702> + + In JSCell::methodTable(), get the VM once and pass that along to + structure(VM&) instead of using the heavier structure(). + + In JSCell::methodTable(VM&), replace calls to structure() with + calls to structure(VM&). + + Reviewed by Mark Hahnenberg. + + * runtime/JSCellInlines.h: + (JSC::JSCell::methodTable): + +2014-03-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Listen for the XPC_ERROR_CONNECTION_INVALID event to deref + https://bugs.webkit.org/show_bug.cgi?id=129697 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspectorXPCConnection.mm: + (Inspector::RemoteInspectorXPCConnection::RemoteInspectorXPCConnection): + (Inspector::RemoteInspectorXPCConnection::handleEvent): + +2014-03-04 Mark Hahnenberg <mhahnenberg@apple.com> + + Merge API shims and JSLock + https://bugs.webkit.org/show_bug.cgi?id=129650 + + Reviewed by Mark Lam. + + JSLock is now taking on all of APIEntryShim's responsibilities since there is never a reason + to take just the JSLock. Ditto for DropAllLocks and APICallbackShim. + + * API/APICallbackFunction.h: + (JSC::APICallbackFunction::call): + (JSC::APICallbackFunction::construct): + * API/APIShims.h: Removed. + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + (JSGarbageCollect): + (JSReportExtraMemoryCost): + (JSSynchronousGarbageCollectForDebugging): + * API/JSCallbackConstructor.cpp: + * API/JSCallbackFunction.cpp: + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::init): + (JSC::JSCallbackObject<Parent>::getOwnPropertySlot): + (JSC::JSCallbackObject<Parent>::put): + (JSC::JSCallbackObject<Parent>::putByIndex): + (JSC::JSCallbackObject<Parent>::deleteProperty): + (JSC::JSCallbackObject<Parent>::construct): + (JSC::JSCallbackObject<Parent>::customHasInstance): + (JSC::JSCallbackObject<Parent>::call): + (JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames): + (JSC::JSCallbackObject<Parent>::getStaticValue): + (JSC::JSCallbackObject<Parent>::callbackGetter): + * API/JSContext.mm: + (-[JSContext setException:]): + (-[JSContext wrapperForObjCObject:]): + (-[JSContext wrapperForJSObject:]): + * API/JSContextRef.cpp: + (JSContextGroupRelease): + (JSContextGroupSetExecutionTimeLimit): + (JSContextGroupClearExecutionTimeLimit): + (JSGlobalContextCreateInGroup): + (JSGlobalContextRetain): + (JSGlobalContextRelease): + (JSContextGetGlobalObject): + (JSContextGetGlobalContext): + (JSGlobalContextCopyName): + (JSGlobalContextSetName): + * API/JSManagedValue.mm: + (-[JSManagedValue value]): + * API/JSObjectRef.cpp: + (JSObjectMake): + (JSObjectMakeFunctionWithCallback): + (JSObjectMakeConstructor): + (JSObjectMakeFunction): + (JSObjectMakeArray): + (JSObjectMakeDate): + (JSObjectMakeError): + (JSObjectMakeRegExp): + (JSObjectGetPrototype): + (JSObjectSetPrototype): + (JSObjectHasProperty): + (JSObjectGetProperty): + (JSObjectSetProperty): + (JSObjectGetPropertyAtIndex): + (JSObjectSetPropertyAtIndex): + (JSObjectDeleteProperty): + (JSObjectGetPrivateProperty): + (JSObjectSetPrivateProperty): + (JSObjectDeletePrivateProperty): + (JSObjectIsFunction): + (JSObjectCallAsFunction): + (JSObjectCallAsConstructor): + (JSObjectCopyPropertyNames): + (JSPropertyNameArrayRelease): + (JSPropertyNameAccumulatorAddName): + * API/JSScriptRef.cpp: + * API/JSValue.mm: + (isDate): + (isArray): + (containerValueToObject): + (valueToArray): + (valueToDictionary): + (objectToValue): + * API/JSValueRef.cpp: + (JSValueGetType): + (JSValueIsUndefined): + (JSValueIsNull): + (JSValueIsBoolean): + (JSValueIsNumber): + (JSValueIsString): + (JSValueIsObject): + (JSValueIsObjectOfClass): + (JSValueIsEqual): + (JSValueIsStrictEqual): + (JSValueIsInstanceOfConstructor): + (JSValueMakeUndefined): + (JSValueMakeNull): + (JSValueMakeBoolean): + (JSValueMakeNumber): + (JSValueMakeString): + (JSValueMakeFromJSONString): + (JSValueCreateJSONString): + (JSValueToBoolean): + (JSValueToNumber): + (JSValueToStringCopy): + (JSValueToObject): + (JSValueProtect): + (JSValueUnprotect): + * API/JSVirtualMachine.mm: + (-[JSVirtualMachine addManagedReference:withOwner:]): + (-[JSVirtualMachine removeManagedReference:withOwner:]): + * API/JSWeakObjectMapRefPrivate.cpp: + * API/JSWrapperMap.mm: + (constructorHasInstance): + (makeWrapper): + (tryUnwrapObjcObject): + * API/ObjCCallbackFunction.mm: + (JSC::objCCallbackFunctionCallAsFunction): + (JSC::objCCallbackFunctionCallAsConstructor): + (objCCallbackFunctionForInvocation): + * CMakeLists.txt: + * ForwardingHeaders/JavaScriptCore/APIShims.h: Removed. + * GNUmakefile.list.am: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGWorklist.cpp: + * heap/DelayedReleaseScope.h: + (JSC::DelayedReleaseScope::~DelayedReleaseScope): + * heap/HeapTimer.cpp: + (JSC::HeapTimer::timerDidFire): + (JSC::HeapTimer::timerEvent): + * heap/IncrementalSweeper.cpp: + * inspector/InjectedScriptModule.cpp: + (Inspector::InjectedScriptModule::ensureInjected): + * jsc.cpp: + (jscmain): + * runtime/GCActivityCallback.cpp: + (JSC::DefaultGCActivityCallback::doWork): + * runtime/JSGlobalObjectDebuggable.cpp: + (JSC::JSGlobalObjectDebuggable::connect): + (JSC::JSGlobalObjectDebuggable::disconnect): + (JSC::JSGlobalObjectDebuggable::dispatchMessageFromRemoteFrontend): + * runtime/JSLock.cpp: + (JSC::JSLock::lock): + (JSC::JSLock::didAcquireLock): + (JSC::JSLock::unlock): + (JSC::JSLock::willReleaseLock): + (JSC::JSLock::DropAllLocks::DropAllLocks): + (JSC::JSLock::DropAllLocks::~DropAllLocks): + * runtime/JSLock.h: + * testRegExp.cpp: + (realMain): + +2014-03-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r164812. + http://trac.webkit.org/changeset/164812 + https://bugs.webkit.org/show_bug.cgi?id=129699 + + it made things run slower (Requested by pizlo on #webkit). + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * jsc.cpp: + (GlobalObject::finishCreation): + * runtime/BatchedTransitionOptimizer.h: + (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): + (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer): + +2014-03-02 Filip Pizlo <fpizlo@apple.com> + + GetMyArgumentByVal in FTL + https://bugs.webkit.org/show_bug.cgi?id=128850 + + Reviewed by Oliver Hunt. + + This would have been easy if the OSR exit compiler's arity checks hadn't been wrong. + They checked arity by doing "exec->argumentCount == codeBlock->numParameters", which + caused it to think that the arity check had failed if the caller had passed more + arguments than needed. This would cause the call frame copying to sort of go into + reverse (because the amount-by-which-we-failed-arity would have opposite sign, + throwing off a bunch of math) and the stack would end up being corrupted. + + The bug was revealed by two existing tests although as far as I could tell, neither + test was intending to cover this case directly. So, I added a new test. + + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::compileCheckArgumentsNotCreated): + (JSC::FTL::LowerDFGToLLVM::checkArgumentsNotCreated): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + * ftl/FTLState.h: + * tests/stress/exit-from-ftl-when-caller-passed-extra-args-then-use-function-dot-arguments.js: Added. + * tests/stress/ftl-get-my-argument-by-val-inlined-and-not-inlined.js: Added. + * tests/stress/ftl-get-my-argument-by-val-inlined.js: Added. + * tests/stress/ftl-get-my-argument-by-val.js: Added. + +2014-03-04 Zan Dobersek <zdobersek@igalia.com> + + [GTK] Build the Udis86 disassembler + https://bugs.webkit.org/show_bug.cgi?id=129679 + + Reviewed by Michael Saboff. + + * GNUmakefile.am: Generate the Udis86-related derived sources. Distribute the required files. + * GNUmakefile.list.am: Add the Udis86 disassembler files to the build. + +2014-03-04 Andreas Kling <akling@apple.com> + + Fix too-narrow assertion I added in r165054. + + It's okay for a 1-character string to come in here. This will happen + if the VM small string optimization doesn't apply (ch > 0xFF) + + * runtime/JSString.h: + (JSC::jsStringWithWeakOwner): + +2014-03-04 Andreas Kling <akling@apple.com> + + Micro-optimize Strings in JS bindings. + <https://webkit.org/b/129673> + + Make jsStringWithWeakOwner() take a StringImpl& instead of a String. + This avoids branches in length() and operator[]. + + Also call JSString::create() directly instead of jsString() and just + assert that the string length is >1. This way we don't duplicate the + optimizations for empty and single-character strings. + + Reviewed by Ryosuke Niwa. + + * runtime/JSString.h: + (JSC::jsStringWithWeakOwner): + +2014-03-04 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Implement Number.prototype.clz() + https://bugs.webkit.org/show_bug.cgi?id=129479 + + Reviewed by Oliver Hunt. + + Implemented Number.prototype.clz() as specified in the ES6 standard. + + * runtime/NumberPrototype.cpp: + (JSC::numberProtoFuncClz): + +2014-03-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Avoid too early deref caused by RemoteInspectorXPCConnection::close + https://bugs.webkit.org/show_bug.cgi?id=129631 + + Reviewed by Timothy Hatcher. + + Avoid deref() too early if a client calls close(). The xpc_connection_close + will cause another XPC_ERROR event to come in from the queue, deref then. + Likewise, protect multithreaded access to m_client. If a client calls + close() we want to immediately clear the pointer to prevent calls to it. + + Overall the multi-threading aspects of RemoteInspectorXPCConnection are + growing too complicated for probably little benefit. We may want to + clean this up later. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::xpcConnectionFailed): + * inspector/remote/RemoteInspectorXPCConnection.h: + * inspector/remote/RemoteInspectorXPCConnection.mm: + (Inspector::RemoteInspectorXPCConnection::RemoteInspectorXPCConnection): + (Inspector::RemoteInspectorXPCConnection::close): + (Inspector::RemoteInspectorXPCConnection::closeOnQueue): + (Inspector::RemoteInspectorXPCConnection::deserializeMessage): + (Inspector::RemoteInspectorXPCConnection::handleEvent): + (Inspector::RemoteInspectorXPCConnection::sendMessage): + +2014-03-03 Michael Saboff <msaboff@apple.com> + + AbstractMacroAssembler::CachedTempRegister should start out invalid + https://bugs.webkit.org/show_bug.cgi?id=129657 + + Reviewed by Filip Pizlo. + + * assembler/AbstractMacroAssembler.h: + (JSC::AbstractMacroAssembler::AbstractMacroAssembler): + - Invalidate all cached registers in constructor as we don't know the + contents of any register at the entry to the code we are going to + generate. + +2014-03-03 Andreas Kling <akling@apple.com> + + StructureOrOffset should be fastmalloced. + <https://webkit.org/b/129640> + + Reviewed by Geoffrey Garen. + + * runtime/StructureIDTable.h: + +2014-03-03 Michael Saboff <msaboff@apple.com> + + Crash in JIT code while watching a video @ storyboard.tumblr.com + https://bugs.webkit.org/show_bug.cgi?id=129635 + + Reviewed by Filip Pizlo. + + Clear m_set before we set bits in the TempRegisterSet(const RegisterSet& other) + construtor. + + * jit/TempRegisterSet.cpp: + (JSC::TempRegisterSet::TempRegisterSet): Clear map before setting it. + * jit/TempRegisterSet.h: + (JSC::TempRegisterSet::TempRegisterSet): Use new clearAll() helper. + (JSC::TempRegisterSet::clearAll): New private helper. + +2014-03-03 Benjamin Poulain <benjamin@webkit.org> + + [x86] Improve code generation of byte test + https://bugs.webkit.org/show_bug.cgi?id=129597 + + Reviewed by Geoffrey Garen. + + When possible, test the 8 bit register to itself instead of comparing it + to a literal. + + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::test32): + +2014-03-03 Mark Lam <mark.lam@apple.com> + + Web Inspector: debugger statements do not break. + <https://webkit.org/b/129524> + + Reviewed by Geoff Garen. + + Since we no longer call op_debug hooks unless there is a debugger request + made on the CodeBlock, the op_debug for the debugger statement never gets + serviced. + + With this fix, we check in the CodeBlock constructor if any debugger + statements are present. If so, we set a m_hasDebuggerStatement flag that + causes the CodeBlock to show as having debugger requests. Hence, + breaking at debugger statements is now restored. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::hasDebuggerRequests): + (JSC::CodeBlock::clearDebuggerRequests): + +2014-03-03 Mark Lam <mark.lam@apple.com> + + ASSERTION FAILED: m_numBreakpoints >= numBreakpoints when deleting breakpoints. + <https://webkit.org/b/129393> + + Reviewed by Geoffrey Garen. + + The issue manifests because the debugger will iterate all CodeBlocks in + the heap when setting / clearing breakpoints, but it is possible for a + CodeBlock to have been instantiate but is not yet registered with the + debugger. This can happen because of the following: + + 1. DFG worklist compilation is still in progress, and the target + codeBlock is not ready for installation in its executable yet. + + 2. DFG compilation failed and we have a codeBlock that will never be + installed in its executable, and the codeBlock has not been cleaned + up by the GC yet. + + The code for installing the codeBlock in its executable is the same code + that registers it with the debugger. Hence, these codeBlocks are not + registered with the debugger, and any pending breakpoints that would map + to that CodeBlock is as yet unset or will never be set. As such, an + attempt to remove a breakpoint in that CodeBlock will fail that assertion. + + To fix this, we do the following: + + 1. We'll eagerly clean up any zombie CodeBlocks due to failed DFG / FTL + compilation. This is achieved by providing a + DeferredCompilationCallback::compilationDidComplete() that does this + clean up, and have all sub classes call it at the end of their + compilationDidComplete() methods. + + 2. Before the debugger or profiler iterates CodeBlocks in the heap, they + will wait for all compilations to complete before proceeding. This + ensures that: + 1. any zombie CodeBlocks would have been cleaned up, and won't be + seen by the debugger or profiler. + 2. all CodeBlocks that the debugger and profiler needs to operate on + will be "ready" for whatever needs to be done to them e.g. + jettison'ing of DFG codeBlocks. + + * bytecode/DeferredCompilationCallback.cpp: + (JSC::DeferredCompilationCallback::compilationDidComplete): + * bytecode/DeferredCompilationCallback.h: + - Provide default implementation method to clean up zombie CodeBlocks. + + * debugger/Debugger.cpp: + (JSC::Debugger::forEachCodeBlock): + - Utility function to iterate CodeBlocks. It ensures that all compilations + are complete before proceeding. + (JSC::Debugger::setSteppingMode): + (JSC::Debugger::toggleBreakpoint): + (JSC::Debugger::recompileAllJSFunctions): + (JSC::Debugger::clearBreakpoints): + (JSC::Debugger::clearDebuggerRequests): + - Use the utility iterator function. + + * debugger/Debugger.h: + * dfg/DFGOperations.cpp: + - Added an assert to ensure that zombie CodeBlocks will be imminently cleaned up. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::finalizeWithoutNotifyingCallback): + - Remove unneeded code (that was not the best solution anyway) for ensuring + that we don't generate new DFG codeBlocks after enabling the debugger or + profiler. Now that we wait for compilations to complete before proceeding + with debugger and profiler work, this scenario will never happen. + + * dfg/DFGToFTLDeferredCompilationCallback.cpp: + (JSC::DFG::ToFTLDeferredCompilationCallback::compilationDidComplete): + - Call the super class method to clean up zombie codeBlocks. + + * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp: + (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidComplete): + - Call the super class method to clean up zombie codeBlocks. + + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::remove): + * heap/CodeBlockSet.h: + * heap/Heap.h: + (JSC::Heap::removeCodeBlock): + - New method to remove a codeBlock from the codeBlock set. + + * jit/JITOperations.cpp: + - Added an assert to ensure that zombie CodeBlocks will be imminently cleaned up. + + * jit/JITToDFGDeferredCompilationCallback.cpp: + (JSC::JITToDFGDeferredCompilationCallback::compilationDidComplete): + - Call the super class method to clean up zombie codeBlocks. + + * runtime/VM.cpp: + (JSC::VM::waitForCompilationsToComplete): + - Renamed from prepareToDiscardCode() to be clearer about what it does. + + (JSC::VM::discardAllCode): + (JSC::VM::releaseExecutableMemory): + (JSC::VM::setEnabledProfiler): + - Wait for compilation to complete before enabling the profiler. + + * runtime/VM.h: + +2014-03-03 Brian Burg <bburg@apple.com> + + Another unreviewed build fix attempt for Windows after r164986. + + We never told Visual Studio to copy over the web replay code generator scripts + and the generated headers for JavaScriptCore replay inputs as if they were + private headers. + + * JavaScriptCore.vcxproj/copy-files.cmd: + +2014-03-03 Brian Burg <bburg@apple.com> + + Web Replay: upstream input storage, capture/replay machinery, and inspector domain + https://bugs.webkit.org/show_bug.cgi?id=128782 + + Reviewed by Timothy Hatcher. + + Alter the replay inputs code generator so that it knows when it is necessary to + to include headers for HEAVY_SCALAR types such as WTF::String and WebCore::URL. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * replay/scripts/CodeGeneratorReplayInputs.py: + (Framework.fromString): + (Frameworks): Add WTF as an allowed framework for code generation. + (Generator.generate_includes): Include headers for HEAVY_SCALAR types in the header file. + (Generator.generate_includes.declaration): + (Generator.generate_includes.or): + (Generator.generate_type_forward_declarations): Skip HEAVY_SCALAR types. + +2014-03-02 Filip Pizlo <fpizlo@apple.com> + + PolymorphicPutByIdList should have a simpler construction API with basically a single entrypoint + https://bugs.webkit.org/show_bug.cgi?id=129591 + + Reviewed by Michael Saboff. + + * bytecode/PolymorphicPutByIdList.cpp: + (JSC::PutByIdAccess::fromStructureStubInfo): This function can figure out the slow path target for itself. + (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): This constuctor should be private, only from() should call it. + (JSC::PolymorphicPutByIdList::from): + * bytecode/PolymorphicPutByIdList.h: + (JSC::PutByIdAccess::stubRoutine): + * jit/Repatch.cpp: + (JSC::tryBuildPutByIdList): Don't pass the slow path target since it can be derived from the stubInfo. + +2014-03-02 Filip Pizlo <fpizlo@apple.com> + + Debugging improvements from my gbemu investigation session + https://bugs.webkit.org/show_bug.cgi?id=129599 + + Reviewed by Mark Lam. + + Various improvements from when I was investigating bug 129411. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::optimizationThresholdScalingFactor): Make the dataLog() statement print the actual multiplier. + * jsc.cpp: + (GlobalObject::finishCreation): + (functionDescribe): Make describe() return a string rather than printing the string. + (functionDescribeArray): Like describe(), but prints details about arrays. + +2014-02-25 Andreas Kling <akling@apple.com> + + JSDOMWindow::commonVM() should return a reference. + <https://webkit.org/b/129293> + + Added a DropAllLocks constructor that takes VM& without null checks. + + Reviewed by Geoff Garen. + +2014-03-02 Mark Lam <mark.lam@apple.com> + + CodeBlock::hasDebuggerRequests() should returning a bool instead of an int. + <https://webkit.org/b/129584> + + Reviewed by Darin Adler. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::hasDebuggerRequests): + +2014-03-02 Mark Lam <mark.lam@apple.com> + + Clean up use of Options::enableConcurrentJIT(). + <https://webkit.org/b/129582> + + Reviewed by Filip Pizlo. + + DFG Driver was conditionally checking Options::enableConcurrentJIT() + only if ENABLE(CONCURRENT_JIT). Otherwise, it bypasses it with a local + enableConcurrentJIT set to false. + + Instead we should configure Options::enableConcurrentJIT() to be false + in Options.cpp if !ENABLE(CONCURRENT_JIT), and DFG Driver should always + check Options::enableConcurrentJIT(). This makes the code read a little + cleaner. + + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + +2014-03-01 Filip Pizlo <fpizlo@apple.com> + + This shouldn't have been a layout test since it runs only under jsc. Moving it to JSC + stress tests. + + * tests/stress/generational-opaque-roots.js: Copied from LayoutTests/js/script-tests/generational-opaque-roots.js. + +2014-03-01 Andreas Kling <akling@apple.com> + + JSCell::fastGetOwnProperty() should get the Structure more efficiently. + <https://webkit.org/b/129560> + + Now that structure() is nontrivial and we have a faster structure(VM&), + make use of that in fastGetOwnProperty() since we already have VM. + + Reviewed by Sam Weinig. + + * runtime/JSCellInlines.h: + (JSC::JSCell::fastGetOwnProperty): + +2014-03-01 Andreas Kling <akling@apple.com> + + Avoid going through ExecState for VM when we already have it (in some places.) + <https://webkit.org/b/129554> + + Tweak some places that jump through unnecessary hoops to get the VM. + There are many more like this. + + Reviewed by Sam Weinig. + + * runtime/JSObject.cpp: + (JSC::JSObject::putByIndexBeyondVectorLength): + (JSC::JSObject::putDirectIndexBeyondVectorLength): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncToString): + +2014-02-28 Filip Pizlo <fpizlo@apple.com> + + FTL should support PhantomArguments + https://bugs.webkit.org/show_bug.cgi?id=113986 + + Reviewed by Oliver Hunt. + + Adding PhantomArguments to the FTL mostly means wiring the recovery of the Arguments + object into the FTL's OSR exit compiler. + + This isn't a speed-up yet, since there is still more to be done to fully support + all of the arguments craziness that our varargs benchmarks do. + + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): move the recovery code to DFGOSRExitCompilerCommon.cpp + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): move the recovery code to DFGOSRExitCompilerCommon.cpp + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::ArgumentsRecoveryGenerator::ArgumentsRecoveryGenerator): + (JSC::DFG::ArgumentsRecoveryGenerator::~ArgumentsRecoveryGenerator): + (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): this is the common place for the recovery code + * dfg/DFGOSRExitCompilerCommon.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::dumpInContext): + * ftl/FTLExitValue.h: + (JSC::FTL::ExitValue::argumentsObjectThatWasNotCreated): + (JSC::FTL::ExitValue::isArgumentsObjectThatWasNotCreated): + (JSC::FTL::ExitValue::valueFormat): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePhantomArguments): + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + (JSC::FTL::LowerDFGToLLVM::tryToSetConstantExitArgument): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): Call into the ArgumentsRecoveryGenerator + * tests/stress/slightly-more-difficult-to-fold-reflective-arguments-access.js: Added. + * tests/stress/trivially-foldable-reflective-arguments-access.js: Added. + +2014-02-28 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, uncomment some code. It wasn't meant to be commented in the first place. + + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination): + +2014-02-28 Andreas Kling <akling@apple.com> + + JSObject::findPropertyHashEntry() should take VM instead of ExecState. + <https://webkit.org/b/129529> + + Callers already have VM in a local, and findPropertyHashEntry() only + uses the VM, no need to go all the way through ExecState. + + Reviewed by Geoffrey Garen. + + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::findPropertyHashEntry): + * runtime/JSObject.h: + +2014-02-28 Joseph Pecoraro <pecoraro@apple.com> + + Deadlock remotely inspecting iOS Simulator + https://bugs.webkit.org/show_bug.cgi?id=129511 + + Reviewed by Timothy Hatcher. + + Avoid synchronous setup. Do it asynchronously, and let + the RemoteInspector singleton know later if it failed. + + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::setupFailed): + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + +2014-02-28 Oliver Hunt <oliver@apple.com> + + REGRESSION(r164835): It broke 10 JSC stress test on 32 bit platforms + https://bugs.webkit.org/show_bug.cgi?id=129488 + + Reviewed by Mark Lam. + + Whoops, modify the right register. + + * jit/JITCall32_64.cpp: + (JSC::JIT::compileLoadVarargs): + +2014-02-28 Filip Pizlo <fpizlo@apple.com> + + FTL should be able to call sin/cos directly on platforms where the intrinsic is busted + https://bugs.webkit.org/show_bug.cgi?id=129503 + + Reviewed by Mark Lam. + + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLOutput.h: + (JSC::FTL::Output::doubleSin): + (JSC::FTL::Output::doubleCos): + (JSC::FTL::Output::intrinsicOrOperation): + +2014-02-28 Mark Hahnenberg <mhahnenberg@apple.com> + + Fix !ENABLE(GGC) builds + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::gatherJSStackRoots): Also fix one of the names of the GC phases. + +2014-02-27 Mark Hahnenberg <mhahnenberg@apple.com> + + Clean up Heap::collect and Heap::markRoots + https://bugs.webkit.org/show_bug.cgi?id=129464 + + Reviewed by Geoffrey Garen. + + These functions have built up a lot of cruft recently. + We should do a bit of cleanup to make them easier to grok. + + * heap/Heap.cpp: + (JSC::Heap::finalizeUnconditionalFinalizers): + (JSC::Heap::gatherStackRoots): + (JSC::Heap::gatherJSStackRoots): + (JSC::Heap::gatherScratchBufferRoots): + (JSC::Heap::clearLivenessData): + (JSC::Heap::visitSmallStrings): + (JSC::Heap::visitConservativeRoots): + (JSC::Heap::visitCompilerWorklists): + (JSC::Heap::markProtectedObjects): + (JSC::Heap::markTempSortVectors): + (JSC::Heap::markArgumentBuffers): + (JSC::Heap::visitException): + (JSC::Heap::visitStrongHandles): + (JSC::Heap::visitHandleStack): + (JSC::Heap::traceCodeBlocksAndJITStubRoutines): + (JSC::Heap::converge): + (JSC::Heap::visitWeakHandles): + (JSC::Heap::clearRememberedSet): + (JSC::Heap::updateObjectCounts): + (JSC::Heap::resetVisitors): + (JSC::Heap::markRoots): + (JSC::Heap::copyBackingStores): + (JSC::Heap::deleteUnmarkedCompiledCode): + (JSC::Heap::collect): + (JSC::Heap::collectIfNecessaryOrDefer): + (JSC::Heap::suspendCompilerThreads): + (JSC::Heap::willStartCollection): + (JSC::Heap::deleteOldCode): + (JSC::Heap::flushOldStructureIDTables): + (JSC::Heap::flushWriteBarrierBuffer): + (JSC::Heap::stopAllocation): + (JSC::Heap::reapWeakHandles): + (JSC::Heap::sweepArrayBuffers): + (JSC::Heap::snapshotMarkedSpace): + (JSC::Heap::deleteSourceProviderCaches): + (JSC::Heap::notifyIncrementalSweeper): + (JSC::Heap::rememberCurrentlyExecutingCodeBlocks): + (JSC::Heap::resetAllocators): + (JSC::Heap::updateAllocationLimits): + (JSC::Heap::didFinishCollection): + (JSC::Heap::resumeCompilerThreads): + * heap/Heap.h: + +2014-02-27 Ryosuke Niwa <rniwa@webkit.org> + + indexOf and lastIndexOf shouldn't resolve ropes when needle is longer than haystack + https://bugs.webkit.org/show_bug.cgi?id=129466 + + Reviewed by Michael Saboff. + + Refactored the code to avoid calling JSString::value when needle is longer than haystack. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncIndexOf): + (JSC::stringProtoFuncLastIndexOf): + +2014-02-27 Timothy Hatcher <timothy@apple.com> + + Improve how ContentSearchUtilities::lineEndings works by supporting the three common line endings. + + https://bugs.webkit.org/show_bug.cgi?id=129458 + + Reviewed by Joseph Pecoraro. + + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::textPositionFromOffset): Remove assumption about line ending length. + (Inspector::ContentSearchUtilities::getRegularExpressionMatchesByLines): Remove assumption about + line ending type and don't try to strip the line ending. Use size_t + (Inspector::ContentSearchUtilities::lineEndings): Use findNextLineStart to find the lines. + This will include the line ending in the lines, but that is okay. + (Inspector::ContentSearchUtilities::buildObjectForSearchMatch): Use size_t. + (Inspector::ContentSearchUtilities::searchInTextByLines): Modernize. + +2014-02-27 Joseph Pecoraro <pecoraro@apple.com> + + [Mac] Warning: Multiple build commands for output file GCSegmentedArray and InspectorAgent + https://bugs.webkit.org/show_bug.cgi?id=129446 + + Reviewed by Timothy Hatcher. + + Remove duplicate header entries in Copy Header build phase. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-02-27 Oliver Hunt <oliver@apple.com> + + Whoops, include all of last patch. + + * jit/JITCall32_64.cpp: + (JSC::JIT::compileLoadVarargs): + +2014-02-27 Oliver Hunt <oliver@apple.com> + + Slow cases for function.apply and function.call should not require vm re-entry + https://bugs.webkit.org/show_bug.cgi?id=129454 + + Reviewed by Geoffrey Garen. + + Implement call and apply using builtins. Happily the use + of @call and @apply don't perform function equality checks + and just plant direct var_args calls. This did expose a few + codegen issues, but they're all covered by existing tests + once call and apply are implemented in JS. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/Function.prototype.js: Added. + (call): + (apply): + * bytecompiler/NodesCodegen.cpp: + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * interpreter/Interpreter.cpp: + (JSC::sizeFrameForVarargs): + (JSC::loadVarargs): + * interpreter/Interpreter.h: + * jit/JITCall.cpp: + (JSC::JIT::compileLoadVarargs): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::makeFunctionCallNode): + * parser/Lexer.cpp: + (JSC::isSafeBuiltinIdentifier): + * runtime/CommonIdentifiers.h: + * runtime/FunctionPrototype.cpp: + (JSC::FunctionPrototype::addFunctionProperties): + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectBuiltinFunction): + (JSC::JSObject::putDirectBuiltinFunctionWithoutTransition): + * runtime/JSObject.h: + +2014-02-27 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Better name for RemoteInspectorDebuggableConnection dispatch queue + https://bugs.webkit.org/show_bug.cgi?id=129443 + + Reviewed by Timothy Hatcher. + + This queue is specific to the JSContext debuggable connections, + there is no XPC involved. Give it a better name. + + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::RemoteInspectorDebuggableConnection): + +2014-02-27 David Kilzer <ddkilzer@apple.com> + + Remove jsc symlink if it already exists + + This is a follow-up fix for: + + Create symlink to /usr/local/bin/jsc during installation + <http://webkit.org/b/129399> + <rdar://problem/16168734> + + * JavaScriptCore.xcodeproj/project.pbxproj: + (Create /usr/local/bin/jsc symlink): If a jsc symlink already + exists where we're about to create the symlink, remove the old + one first. + +2014-02-27 Michael Saboff <msaboff@apple.com> + + Unreviewed build fix for Mac tools after r164814 + + * Configurations/ToolExecutable.xcconfig: + - Added JavaScriptCore.framework/PrivateHeaders to ToolExecutable include path. + * JavaScriptCore.xcodeproj/project.pbxproj: + - Changed productName to testRegExp for testRegExp target. + +2014-02-27 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: JSContext inspection should report exceptions in the console + https://bugs.webkit.org/show_bug.cgi?id=128776 + + Reviewed by Timothy Hatcher. + + When JavaScript API functions have an exception, let the inspector + know so it can log the JavaScript and Native backtrace that caused + the exception. + + Include some clean up of ConsoleMessage and ScriptCallStack construction. + + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + * API/JSObjectRef.cpp: + (JSObjectMakeFunction): + (JSObjectMakeArray): + (JSObjectMakeDate): + (JSObjectMakeError): + (JSObjectMakeRegExp): + (JSObjectGetProperty): + (JSObjectSetProperty): + (JSObjectGetPropertyAtIndex): + (JSObjectSetPropertyAtIndex): + (JSObjectDeleteProperty): + (JSObjectCallAsFunction): + (JSObjectCallAsConstructor): + * API/JSValue.mm: + (reportExceptionToInspector): + (valueToArray): + (valueToDictionary): + * API/JSValueRef.cpp: + (JSValueIsEqual): + (JSValueIsInstanceOfConstructor): + (JSValueCreateJSONString): + (JSValueToNumber): + (JSValueToStringCopy): + (JSValueToObject): + When seeing an exception, let the inspector know there was an exception. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + Log API exceptions by also grabbing the native backtrace. + + * inspector/ScriptCallStack.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::firstNonNativeCallFrame): + (Inspector::ScriptCallStack::append): + Minor extensions to ScriptCallStack to make it easier to work with. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + Provide better default information if the first call frame was native. + + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::extractSourceInformationFromException): + (Inspector::createScriptCallStackFromException): + Perform the handling here of inserting a fake call frame for exceptions + if there was no call stack (e.g. a SyntaxError) or if the first call + frame had no information. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + * inspector/ConsoleMessage.h: + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::createScriptCallStackForConsole): + * inspector/ScriptCallStackFactory.h: + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::enable): + (Inspector::InspectorConsoleAgent::addMessageToConsole): + (Inspector::InspectorConsoleAgent::count): + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): + ConsoleMessage cleanup. + +2014-02-27 David Kilzer <ddkilzer@apple.com> + + Create symlink to /usr/local/bin/jsc during installation + <http://webkit.org/b/129399> + <rdar://problem/16168734> + + Reviewed by Dan Bernstein. + + * JavaScriptCore.xcodeproj/project.pbxproj: + - Add "Create /usr/local/bin/jsc symlink" build phase script to + create the symlink during installation. + +2014-02-27 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Math.{max, min}() must not return after first NaN value + https://bugs.webkit.org/show_bug.cgi?id=104147 + + Reviewed by Oliver Hunt. + + According to the spec, ToNumber going to be called on each argument + even if a `NaN` value was already found + + * runtime/MathObject.cpp: + (JSC::mathProtoFuncMax): + (JSC::mathProtoFuncMin): + +2014-02-27 Gergo Balogh <gbalogh.u-szeged@partner.samsung.com> + + JSType upper limit (0xff) assertion can be removed. + https://bugs.webkit.org/show_bug.cgi?id=129424 + + Reviewed by Geoffrey Garen. + + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::TypeInfo): + +2014-02-26 Michael Saboff <msaboff@apple.com> + + Auto generate bytecode information for bytecode parser and LLInt + https://bugs.webkit.org/show_bug.cgi?id=129181 + + Reviewed by Mark Lam. + + Added new bytecode/BytecodeList.json that contains a list of bytecodes and related + helpers. It also includes bytecode length and other information used to generate files. + Added a new generator, generate-bytecode-files that generates Bytecodes.h and InitBytecodes.asm + in DerivedSources/JavaScriptCore/. + + Added the generation of these files to the "DerivedSource" build step. + Slighty changed the build order, since the Bytecodes.h file is needed by + JSCLLIntOffsetsExtractor. Moved the offline assembly to a separate step since it needs + to be run after JSCLLIntOffsetsExtractor. + + Made related changes to OPCODE macros and their use. + + Added JavaScriptCore.framework/PrivateHeaders to header file search path for building + jsc to resolve Mac build issue. + + * CMakeLists.txt: + * Configurations/JSC.xcconfig: + * DerivedSources.make: + * GNUmakefile.am: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * llint/LLIntCLoop.cpp: + (JSC::LLInt::CLoop::initialize): + * llint/LLIntCLoop.h: + * llint/LLIntData.cpp: + (JSC::LLInt::initialize): + * llint/LLIntOpcode.h: + * llint/LowLevelInterpreter.asm: + +2014-02-27 Julien Brianceau <jbriance@cisco.com> + + Fix 32-bit V_JITOperation_EJ callOperation introduced in r162652. + https://bugs.webkit.org/show_bug.cgi?id=129420 + + Reviewed by Geoffrey Garen. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): Payload and tag are swapped. + Also, EABI_32BIT_DUMMY_ARG is missing for arm EABI and mips. + +2014-02-27 Filip Pizlo <fpizlo@apple.com> + + Octane/closure thrashes between flattening dictionaries during global object initialization in a global eval + https://bugs.webkit.org/show_bug.cgi?id=129435 + + Reviewed by Oliver Hunt. + + This is a 5-10% speed-up on Octane/closure. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionClearCodeCache): + * runtime/BatchedTransitionOptimizer.h: + (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): + (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer): + +2014-02-27 Alexey Proskuryakov <ap@apple.com> + + Added svn:ignore to two directories, so that .pyc files don't show up as unversioned. + + * inspector/scripts: Added property svn:ignore. + * replay/scripts: Added property svn:ignore. + +2014-02-27 Gabor Rapcsanyi <rgabor@webkit.org> + + r164764 broke the ARM build + https://bugs.webkit.org/show_bug.cgi?id=129415 + + Reviewed by Zoltan Herczeg. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::moveWithPatch): Change reinterpret_cast to static_cast. + (JSC::MacroAssemblerARM::canJumpReplacePatchableBranch32WithPatch): Add missing function. + (JSC::MacroAssemblerARM::startOfPatchableBranch32WithPatchOnAddress): Add missing function. + (JSC::MacroAssemblerARM::revertJumpReplacementToPatchableBranch32WithPatch): Add missing function. + +2014-02-27 Mark Hahnenberg <mhahnenberg@apple.com> + + r164764 broke the ARM build + https://bugs.webkit.org/show_bug.cgi?id=129415 + + Reviewed by Geoffrey Garen. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::moveWithPatch): + +2014-02-26 Mark Hahnenberg <mhahnenberg@apple.com> + + r164764 broke the ARM build + https://bugs.webkit.org/show_bug.cgi?id=129415 + + Reviewed by Geoffrey Garen. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::branch32WithPatch): Missing this function. + +2014-02-26 Mark Hahnenberg <mhahnenberg@apple.com> + + EFL build fix + + * dfg/DFGSpeculativeJIT32_64.cpp: Remove unused variables. + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + +2014-02-25 Mark Hahnenberg <mhahnenberg@apple.com> + + Make JSCells have 32-bit Structure pointers + https://bugs.webkit.org/show_bug.cgi?id=123195 + + Reviewed by Filip Pizlo. + + This patch changes JSCells such that they no longer have a full 64-bit Structure + pointer in their header. Instead they now have a 32-bit index into + a per-VM table of Structure pointers. 32-bit platforms still use normal Structure + pointers. + + This change frees up an additional 32 bits of information in our object headers. + We then use this extra space to store the indexing type of the object, the JSType + of the object, some various type flags, and garbage collection data (e.g. mark bit). + Because this inline type information is now faster to read, it pays for the slowdown + incurred by having to perform an extra indirection through the StructureIDTable. + + This patch also threads a reference to the current VM through more of the C++ runtime + to offset the cost of having to look up the VM to get the actual Structure pointer. + + * API/JSContext.mm: + (-[JSContext setException:]): + (-[JSContext wrapperForObjCObject:]): + (-[JSContext wrapperForJSObject:]): + * API/JSContextRef.cpp: + (JSContextGroupRelease): + (JSGlobalContextRelease): + * API/JSObjectRef.cpp: + (JSObjectIsFunction): + (JSObjectCopyPropertyNames): + * API/JSValue.mm: + (containerValueToObject): + * API/JSWrapperMap.mm: + (tryUnwrapObjcObject): + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/AbstractMacroAssembler.h: + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::patchableBranch32WithPatch): + (JSC::MacroAssembler::patchableBranch32): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::branchPtrWithPatch): + (JSC::MacroAssemblerARM64::patchableBranch32WithPatch): + (JSC::MacroAssemblerARM64::canJumpReplacePatchableBranch32WithPatch): + (JSC::MacroAssemblerARM64::startOfPatchableBranch32WithPatchOnAddress): + (JSC::MacroAssemblerARM64::revertJumpReplacementToPatchableBranch32WithPatch): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::store8): + (JSC::MacroAssemblerARMv7::branch32WithPatch): + (JSC::MacroAssemblerARMv7::patchableBranch32WithPatch): + (JSC::MacroAssemblerARMv7::canJumpReplacePatchableBranch32WithPatch): + (JSC::MacroAssemblerARMv7::startOfPatchableBranch32WithPatchOnAddress): + (JSC::MacroAssemblerARMv7::revertJumpReplacementToPatchableBranch32WithPatch): + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::branch32WithPatch): + (JSC::MacroAssemblerX86::canJumpReplacePatchableBranch32WithPatch): + (JSC::MacroAssemblerX86::startOfPatchableBranch32WithPatchOnAddress): + (JSC::MacroAssemblerX86::revertJumpReplacementToPatchableBranch32WithPatch): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::store32): + (JSC::MacroAssemblerX86_64::moveWithPatch): + (JSC::MacroAssemblerX86_64::branch32WithPatch): + (JSC::MacroAssemblerX86_64::canJumpReplacePatchableBranch32WithPatch): + (JSC::MacroAssemblerX86_64::startOfBranch32WithPatchOnRegister): + (JSC::MacroAssemblerX86_64::startOfPatchableBranch32WithPatchOnAddress): + (JSC::MacroAssemblerX86_64::revertJumpReplacementToPatchableBranch32WithPatch): + * assembler/RepatchBuffer.h: + (JSC::RepatchBuffer::startOfPatchableBranch32WithPatchOnAddress): + (JSC::RepatchBuffer::revertJumpReplacementToPatchableBranch32WithPatch): + * assembler/X86Assembler.h: + (JSC::X86Assembler::revertJumpTo_movq_i64r): + (JSC::X86Assembler::revertJumpTo_movl_i32r): + * bytecode/ArrayProfile.cpp: + (JSC::ArrayProfile::computeUpdatedPrediction): + * bytecode/ArrayProfile.h: + (JSC::ArrayProfile::ArrayProfile): + (JSC::ArrayProfile::addressOfLastSeenStructureID): + (JSC::ArrayProfile::observeStructure): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::heap): + * bytecode/UnlinkedCodeBlock.h: + * debugger/Debugger.h: + * dfg/DFGAbstractHeap.h: + * dfg/DFGArrayifySlowPathGenerator.h: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::branchWeakStructure): + (JSC::DFG::JITCompiler::branchStructurePtr): + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::osrWriteBarrier): + (JSC::DFG::adjustAndJumpToTarget): + * dfg/DFGOperations.cpp: + (JSC::DFG::putByVal): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::checkArray): + (JSC::DFG::SpeculativeJIT::arrayify): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): + (JSC::DFG::SpeculativeJIT::compileInstanceOfForObject): + (JSC::DFG::SpeculativeJIT::compileInstanceOf): + (JSC::DFG::SpeculativeJIT::compileToStringOnCell): + (JSC::DFG::SpeculativeJIT::speculateObject): + (JSC::DFG::SpeculativeJIT::speculateFinalObject): + (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): + (JSC::DFG::SpeculativeJIT::speculateString): + (JSC::DFG::SpeculativeJIT::speculateStringObject): + (JSC::DFG::SpeculativeJIT::speculateStringOrStringObject): + (JSC::DFG::SpeculativeJIT::emitSwitchChar): + (JSC::DFG::SpeculativeJIT::emitSwitchString): + (JSC::DFG::SpeculativeJIT::genericWriteBarrier): + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateJSCell): + (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGWorklist.cpp: + * ftl/FTLAbstractHeapRepository.cpp: + (JSC::FTL::AbstractHeapRepository::AbstractHeapRepository): + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCheckStructure): + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + (JSC::FTL::LowerDFGToLLVM::compilePutStructure): + (JSC::FTL::LowerDFGToLLVM::compileToString): + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::speculateTruthyObject): + (JSC::FTL::LowerDFGToLLVM::allocateCell): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::isObject): + (JSC::FTL::LowerDFGToLLVM::isString): + (JSC::FTL::LowerDFGToLLVM::isArrayType): + (JSC::FTL::LowerDFGToLLVM::hasClassInfo): + (JSC::FTL::LowerDFGToLLVM::isType): + (JSC::FTL::LowerDFGToLLVM::speculateStringOrStringObject): + (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForCell): + (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID): + (JSC::FTL::LowerDFGToLLVM::speculateNonNullObject): + (JSC::FTL::LowerDFGToLLVM::loadMarkByte): + (JSC::FTL::LowerDFGToLLVM::loadStructure): + (JSC::FTL::LowerDFGToLLVM::weakStructure): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + * ftl/FTLOutput.h: + (JSC::FTL::Output::store8): + * heap/GCAssertions.h: + * heap/Heap.cpp: + (JSC::Heap::getConservativeRegisterRoots): + (JSC::Heap::collect): + (JSC::Heap::writeBarrier): + * heap/Heap.h: + (JSC::Heap::structureIDTable): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::forEachBlock): + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::internalAppend): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::branchIfCellNotObject): + (JSC::AssemblyHelpers::genericWriteBarrier): + (JSC::AssemblyHelpers::emitLoadStructure): + (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + (JSC::JIT::privateCompileClosureCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::emit_op_ret_object_or_this): + (JSC::JIT::compileOpCall): + (JSC::JIT::privateCompileClosureCall): + * jit/JITInlineCacheGenerator.cpp: + (JSC::JITByIdGenerator::generateFastPathChecks): + * jit/JITInlineCacheGenerator.h: + * jit/JITInlines.h: + (JSC::JIT::emitLoadCharacterString): + (JSC::JIT::checkStructure): + (JSC::JIT::emitJumpIfCellNotObject): + (JSC::JIT::emitAllocateJSObject): + (JSC::JIT::emitArrayProfilingSiteWithCell): + (JSC::JIT::emitArrayProfilingSiteForBytecodeIndexWithCell): + (JSC::JIT::branchStructure): + (JSC::branchStructure): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_check_has_instance): + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emit_op_is_undefined): + (JSC::JIT::emit_op_is_string): + (JSC::JIT::emit_op_ret_object_or_this): + (JSC::JIT::emit_op_to_primitive): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emit_op_get_pnames): + (JSC::JIT::emit_op_next_pname): + (JSC::JIT::emit_op_eq_null): + (JSC::JIT::emit_op_neq_null): + (JSC::JIT::emit_op_to_this): + (JSC::JIT::emitSlow_op_to_this): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_check_has_instance): + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emit_op_is_undefined): + (JSC::JIT::emit_op_is_string): + (JSC::JIT::emit_op_to_primitive): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emitSlow_op_eq): + (JSC::JIT::emitSlow_op_neq): + (JSC::JIT::compileOpStrictEq): + (JSC::JIT::emit_op_eq_null): + (JSC::JIT::emit_op_neq_null): + (JSC::JIT::emit_op_get_pnames): + (JSC::JIT::emit_op_next_pname): + (JSC::JIT::emit_op_to_this): + * jit/JITOperations.cpp: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_get_by_pname): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emitLoadWithStructureCheck): + (JSC::JIT::emitSlow_op_get_from_scope): + (JSC::JIT::emitSlow_op_put_to_scope): + (JSC::JIT::checkMarkWord): + (JSC::JIT::emitWriteBarrier): + (JSC::JIT::addStructureTransitionCheck): + (JSC::JIT::emitIntTypedArrayGetByVal): + (JSC::JIT::emitFloatTypedArrayGetByVal): + (JSC::JIT::emitIntTypedArrayPutByVal): + (JSC::JIT::emitFloatTypedArrayPutByVal): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::stringGetByValStubGenerator): + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::emit_op_get_by_id): + (JSC::JIT::emit_op_get_by_pname): + (JSC::JIT::emitLoadWithStructureCheck): + * jit/JSInterfaceJIT.h: + (JSC::JSInterfaceJIT::emitJumpIfNotType): + * jit/Repatch.cpp: + (JSC::repatchByIdSelfAccess): + (JSC::addStructureTransitionCheck): + (JSC::replaceWithJump): + (JSC::generateProtoChainAccessStub): + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::writeBarrier): + (JSC::emitPutReplaceStub): + (JSC::emitPutTransitionStub): + (JSC::tryBuildPutByIdList): + (JSC::tryRepatchIn): + (JSC::linkClosureCall): + (JSC::resetGetByID): + (JSC::resetPutByID): + * jit/SpecializedThunkJIT.h: + (JSC::SpecializedThunkJIT::loadJSStringArgument): + (JSC::SpecializedThunkJIT::loadArgumentWithSpecificClass): + * jit/ThunkGenerators.cpp: + (JSC::virtualForThunkGenerator): + (JSC::arrayIteratorNextThunkGenerator): + * jit/UnusedPointer.h: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/Arguments.cpp: + (JSC::Arguments::createStrictModeCallerIfNecessary): + (JSC::Arguments::createStrictModeCalleeIfNecessary): + * runtime/Arguments.h: + (JSC::Arguments::createStructure): + * runtime/ArrayPrototype.cpp: + (JSC::shift): + (JSC::unshift): + (JSC::arrayProtoFuncToString): + (JSC::arrayProtoFuncPop): + (JSC::arrayProtoFuncReverse): + (JSC::performSlowSort): + (JSC::arrayProtoFuncSort): + (JSC::arrayProtoFuncSplice): + (JSC::arrayProtoFuncUnShift): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/Executable.h: + (JSC::ExecutableBase::isFunctionExecutable): + (JSC::ExecutableBase::clearCodeVirtual): + (JSC::ScriptExecutable::unlinkCalls): + * runtime/GetterSetter.cpp: + (JSC::callGetter): + (JSC::callSetter): + * runtime/InitializeThreading.cpp: + * runtime/JSArray.cpp: + (JSC::JSArray::unshiftCountSlowCase): + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::push): + (JSC::JSArray::shiftCountWithArrayStorage): + (JSC::JSArray::shiftCountWithAnyIndexingType): + (JSC::JSArray::unshiftCountWithArrayStorage): + (JSC::JSArray::unshiftCountWithAnyIndexingType): + (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/JSCJSValueInlines.h: + (JSC::JSValue::toThis): + (JSC::JSValue::put): + (JSC::JSValue::putByIndex): + (JSC::JSValue::equalSlowCaseInline): + * runtime/JSCell.cpp: + (JSC::JSCell::put): + (JSC::JSCell::putByIndex): + (JSC::JSCell::deleteProperty): + (JSC::JSCell::deletePropertyByIndex): + * runtime/JSCell.h: + (JSC::JSCell::clearStructure): + (JSC::JSCell::mark): + (JSC::JSCell::isMarked): + (JSC::JSCell::structureIDOffset): + (JSC::JSCell::typeInfoFlagsOffset): + (JSC::JSCell::typeInfoTypeOffset): + (JSC::JSCell::indexingTypeOffset): + (JSC::JSCell::gcDataOffset): + * runtime/JSCellInlines.h: + (JSC::JSCell::JSCell): + (JSC::JSCell::finishCreation): + (JSC::JSCell::type): + (JSC::JSCell::indexingType): + (JSC::JSCell::structure): + (JSC::JSCell::visitChildren): + (JSC::JSCell::isObject): + (JSC::JSCell::isString): + (JSC::JSCell::isGetterSetter): + (JSC::JSCell::isProxy): + (JSC::JSCell::isAPIValueWrapper): + (JSC::JSCell::setStructure): + (JSC::JSCell::methodTable): + (JSC::Heap::writeBarrier): + * runtime/JSDataView.cpp: + (JSC::JSDataView::createStructure): + * runtime/JSDestructibleObject.h: + (JSC::JSCell::classInfo): + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnNonIndexPropertyNames): + (JSC::JSFunction::put): + (JSC::JSFunction::defineOwnProperty): + * runtime/JSGenericTypedArrayView.h: + (JSC::JSGenericTypedArrayView::createStructure): + * runtime/JSObject.cpp: + (JSC::getCallableObjectSlow): + (JSC::JSObject::copyButterfly): + (JSC::JSObject::visitButterfly): + (JSC::JSFinalObject::visitChildren): + (JSC::JSObject::getOwnPropertySlotByIndex): + (JSC::JSObject::put): + (JSC::JSObject::putByIndex): + (JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists): + (JSC::JSObject::enterDictionaryIndexingMode): + (JSC::JSObject::notifyPresenceOfIndexedAccessors): + (JSC::JSObject::createInitialIndexedStorage): + (JSC::JSObject::createInitialUndecided): + (JSC::JSObject::createInitialInt32): + (JSC::JSObject::createInitialDouble): + (JSC::JSObject::createInitialContiguous): + (JSC::JSObject::createArrayStorage): + (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::genericConvertDoubleToContiguous): + (JSC::JSObject::convertDoubleToArrayStorage): + (JSC::JSObject::convertContiguousToArrayStorage): + (JSC::JSObject::ensureInt32Slow): + (JSC::JSObject::ensureDoubleSlow): + (JSC::JSObject::ensureContiguousSlow): + (JSC::JSObject::ensureArrayStorageSlow): + (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode): + (JSC::JSObject::switchToSlowPutArrayStorage): + (JSC::JSObject::setPrototype): + (JSC::JSObject::setPrototypeWithCycleCheck): + (JSC::JSObject::putDirectNonIndexAccessor): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::hasOwnProperty): + (JSC::JSObject::deletePropertyByIndex): + (JSC::JSObject::getPrimitiveNumber): + (JSC::JSObject::hasInstance): + (JSC::JSObject::getPropertySpecificValue): + (JSC::JSObject::getPropertyNames): + (JSC::JSObject::getOwnPropertyNames): + (JSC::JSObject::getOwnNonIndexPropertyNames): + (JSC::JSObject::seal): + (JSC::JSObject::freeze): + (JSC::JSObject::preventExtensions): + (JSC::JSObject::reifyStaticFunctionsForDelete): + (JSC::JSObject::removeDirect): + (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes): + (JSC::JSObject::putByIndexBeyondVectorLength): + (JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage): + (JSC::JSObject::putDirectIndexBeyondVectorLength): + (JSC::JSObject::getNewVectorLength): + (JSC::JSObject::countElements): + (JSC::JSObject::increaseVectorLength): + (JSC::JSObject::ensureLengthSlow): + (JSC::JSObject::growOutOfLineStorage): + (JSC::JSObject::getOwnPropertyDescriptor): + (JSC::putDescriptor): + (JSC::JSObject::defineOwnNonIndexProperty): + * runtime/JSObject.h: + (JSC::getJSFunction): + (JSC::JSObject::getArrayLength): + (JSC::JSObject::getVectorLength): + (JSC::JSObject::putByIndexInline): + (JSC::JSObject::canGetIndexQuickly): + (JSC::JSObject::getIndexQuickly): + (JSC::JSObject::tryGetIndexQuickly): + (JSC::JSObject::getDirectIndex): + (JSC::JSObject::canSetIndexQuickly): + (JSC::JSObject::canSetIndexQuicklyForPutDirect): + (JSC::JSObject::setIndexQuickly): + (JSC::JSObject::initializeIndex): + (JSC::JSObject::hasSparseMap): + (JSC::JSObject::inSparseIndexingMode): + (JSC::JSObject::getDirect): + (JSC::JSObject::getDirectOffset): + (JSC::JSObject::isSealed): + (JSC::JSObject::isFrozen): + (JSC::JSObject::flattenDictionaryObject): + (JSC::JSObject::ensureInt32): + (JSC::JSObject::ensureDouble): + (JSC::JSObject::ensureContiguous): + (JSC::JSObject::rageEnsureContiguous): + (JSC::JSObject::ensureArrayStorage): + (JSC::JSObject::arrayStorage): + (JSC::JSObject::arrayStorageOrNull): + (JSC::JSObject::ensureLength): + (JSC::JSObject::currentIndexingData): + (JSC::JSObject::getHolyIndexQuickly): + (JSC::JSObject::currentRelevantLength): + (JSC::JSObject::isGlobalObject): + (JSC::JSObject::isVariableObject): + (JSC::JSObject::isStaticScopeObject): + (JSC::JSObject::isNameScopeObject): + (JSC::JSObject::isActivationObject): + (JSC::JSObject::isErrorInstance): + (JSC::JSObject::inlineGetOwnPropertySlot): + (JSC::JSObject::fastGetOwnPropertySlot): + (JSC::JSObject::getPropertySlot): + (JSC::JSObject::putDirectInternal): + (JSC::JSObject::setStructureAndReallocateStorageIfNecessary): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::createStructure): + * runtime/JSProxy.cpp: + (JSC::JSProxy::getOwnPropertySlot): + (JSC::JSProxy::getOwnPropertySlotByIndex): + (JSC::JSProxy::put): + (JSC::JSProxy::putByIndex): + (JSC::JSProxy::defineOwnProperty): + (JSC::JSProxy::deleteProperty): + (JSC::JSProxy::deletePropertyByIndex): + (JSC::JSProxy::getPropertyNames): + (JSC::JSProxy::getOwnPropertyNames): + * runtime/JSScope.cpp: + (JSC::JSScope::objectAtScope): + * runtime/JSString.h: + (JSC::JSString::createStructure): + (JSC::isJSString): + * runtime/JSType.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::TypeInfo): + (JSC::TypeInfo::isObject): + (JSC::TypeInfo::structureIsImmortal): + (JSC::TypeInfo::zeroedGCDataOffset): + (JSC::TypeInfo::inlineTypeFlags): + * runtime/MapData.h: + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyNames): + (JSC::objectConstructorKeys): + (JSC::objectConstructorDefineProperty): + (JSC::defineProperties): + (JSC::objectConstructorSeal): + (JSC::objectConstructorFreeze): + (JSC::objectConstructorIsSealed): + (JSC::objectConstructorIsFrozen): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + (JSC::objectProtoFuncToString): + * runtime/Operations.cpp: + (JSC::jsTypeStringForValue): + (JSC::jsIsObjectType): + * runtime/Operations.h: + (JSC::normalizePrototypeChainForChainAccess): + (JSC::normalizePrototypeChain): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::createStructure): + * runtime/RegExp.h: + (JSC::RegExp::createStructure): + * runtime/SparseArrayValueMap.h: + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::~Structure): + (JSC::Structure::prototypeChainMayInterceptStoreTo): + * runtime/Structure.h: + (JSC::Structure::id): + (JSC::Structure::idBlob): + (JSC::Structure::objectInitializationFields): + (JSC::Structure::structureIDOffset): + * runtime/StructureChain.h: + (JSC::StructureChain::createStructure): + * runtime/StructureIDTable.cpp: Added. + (JSC::StructureIDTable::StructureIDTable): + (JSC::StructureIDTable::~StructureIDTable): + (JSC::StructureIDTable::resize): + (JSC::StructureIDTable::flushOldTables): + (JSC::StructureIDTable::allocateID): + (JSC::StructureIDTable::deallocateID): + * runtime/StructureIDTable.h: Added. + (JSC::StructureIDTable::base): + (JSC::StructureIDTable::get): + * runtime/SymbolTable.h: + * runtime/TypedArrayType.cpp: + (JSC::typeForTypedArrayType): + * runtime/TypedArrayType.h: + * runtime/WeakMapData.h: + +2014-02-26 Mark Hahnenberg <mhahnenberg@apple.com> + + Unconditional logging in compileFTLOSRExit + https://bugs.webkit.org/show_bug.cgi?id=129407 + + Reviewed by Michael Saboff. + + This was causing tests to fail with the FTL enabled. + + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileFTLOSRExit): + +2014-02-26 Oliver Hunt <oliver@apple.com> + + Remove unused access types + https://bugs.webkit.org/show_bug.cgi?id=129385 + + Reviewed by Filip Pizlo. + + Remove unused cruft. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printGetByIdCacheStatus): + * bytecode/StructureStubInfo.cpp: + (JSC::StructureStubInfo::deref): + * bytecode/StructureStubInfo.h: + (JSC::isGetByIdAccess): + (JSC::isPutByIdAccess): + +2014-02-26 Oliver Hunt <oliver@apple.com> + + Function.prototype.apply has a bad time with the spread operator + https://bugs.webkit.org/show_bug.cgi?id=129381 + + Reviewed by Mark Hahnenberg. + + Make sure our apply logic handle the spread operator correctly. + To do this we simply emit the enumeration logic that we'd normally + use for other enumerations, but only store the first two results + to registers. Then perform a varargs call. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ApplyFunctionCallDotNode::emitBytecode): + +2014-02-26 Mark Lam <mark.lam@apple.com> + + Compilation policy management belongs in operationOptimize(), not the DFG Driver. + <https://webkit.org/b/129355> + + Reviewed by Filip Pizlo. + + By compilation policy, I mean the rules for determining whether to + compile, when to compile, when to attempt compilation again, etc. The + few of these policy decisions that were previously being made in the + DFG driver are now moved to operationOptimize() where we keep the rest + of the policy logic. Decisions that are based on the capabilities + supported by the DFG are moved to DFG capabiliityLevel(). + + I've run the following benchmarks: + 1. the collection of jsc benchmarks on the jsc executable vs. its + baseline. + 2. Octane 2.0 in browser without the WebInspector. + 3. Octane 2.0 in browser with the WebInspector open and a breakpoint + set somewhere where it won't break. + + In all of these, the results came out to be a wash as expected. + + * dfg/DFGCapabilities.cpp: + (JSC::DFG::isSupported): + (JSC::DFG::mightCompileEval): + (JSC::DFG::mightCompileProgram): + (JSC::DFG::mightCompileFunctionForCall): + (JSC::DFG::mightCompileFunctionForConstruct): + (JSC::DFG::mightInlineFunctionForCall): + (JSC::DFG::mightInlineFunctionForClosureCall): + (JSC::DFG::mightInlineFunctionForConstruct): + * dfg/DFGCapabilities.h: + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * jit/JITOperations.cpp: + +2014-02-26 Mark Lam <mark.lam@apple.com> + + ASSERTION FAILED: m_heap->vm()->currentThreadIsHoldingAPILock() in inspector-protocol/*. + <https://webkit.org/b/129364> + + Reviewed by Alexey Proskuryakov. + + InjectedScriptModule::ensureInjected() needs an APIEntryShim. + + * inspector/InjectedScriptModule.cpp: + (Inspector::InjectedScriptModule::ensureInjected): + - Added the needed but missing APIEntryShim. + +2014-02-25 Mark Lam <mark.lam@apple.com> + + Web Inspector: CRASH when evaluating in console of JSContext RWI with disabled breakpoints. + <https://webkit.org/b/128766> + + Reviewed by Geoffrey Garen. + + Make the JSLock::grabAllLocks() work the same way as for the C loop LLINT. + The reasoning is that we don't know of any clients that need unordered + re-entry into the VM from different threads. So, we're enforcing ordered + re-entry i.e. we must re-grab locks in the reverse order of dropping locks. + + The crash in this bug happened because we were allowing unordered re-entry, + and the following type of scenario occurred: + + 1. Thread T1 locks the VM, and enters the VM to execute some JS code. + 2. On entry, T1 detects that VM::m_entryScope is null i.e. this is the + first time it entered the VM. + T1 sets VM::m_entryScope to T1's entryScope. + 3. T1 drops all locks. + + 4. Thread T2 locks the VM, and enters the VM to execute some JS code. + On entry, T2 sees that VM::m_entryScope is NOT null, and therefore + does not set the entryScope. + 5. T2 drops all locks. + + 6. T1 re-grabs locks. + 7. T1 returns all the way out of JS code. On exit from the outer most + JS function, T1 clears VM::m_entryScope (because T1 was the one who + set it). + 8. T1 unlocks the VM. + + 9. T2 re-grabs locks. + 10. T2 proceeds to execute some code and expects VM::m_entryScope to be + NOT null, but it turns out to be null. Assertion failures and + crashes ensue. + + With ordered re-entry, at step 6, T1 will loop and yield until T2 exits + the VM. Hence, the issue will no longer manifest. + + * runtime/JSLock.cpp: + (JSC::JSLock::dropAllLocks): + (JSC::JSLock::grabAllLocks): + * runtime/JSLock.h: + (JSC::JSLock::DropAllLocks::dropDepth): + +2014-02-25 Mark Lam <mark.lam@apple.com> + + Need to initialize VM stack data even when the VM is on an exclusive thread. + <https://webkit.org/b/129265> + + Not reviewed. + + Relanding r164627 now that <https://webkit.org/b/129341> is fixed. + + * API/APIShims.h: + (JSC::APIEntryShim::APIEntryShim): + (JSC::APICallbackShim::shouldDropAllLocks): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::addCurrentThread): + * runtime/JSLock.cpp: + (JSC::JSLockHolder::JSLockHolder): + (JSC::JSLockHolder::init): + (JSC::JSLockHolder::~JSLockHolder): + (JSC::JSLock::JSLock): + (JSC::JSLock::setExclusiveThread): + (JSC::JSLock::lock): + (JSC::JSLock::unlock): + (JSC::JSLock::currentThreadIsHoldingLock): + (JSC::JSLock::dropAllLocks): + (JSC::JSLock::grabAllLocks): + * runtime/JSLock.h: + (JSC::JSLock::hasExclusiveThread): + (JSC::JSLock::exclusiveThread): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + (JSC::VM::hasExclusiveThread): + (JSC::VM::exclusiveThread): + (JSC::VM::setExclusiveThread): + (JSC::VM::currentThreadIsHoldingAPILock): + +2014-02-25 Filip Pizlo <fpizlo@apple.com> + + Inline caching in the FTL on ARM64 should "work" + https://bugs.webkit.org/show_bug.cgi?id=129334 + + Reviewed by Mark Hahnenberg. + + Gets us to the point where simple tests that use inline caching are passing. + + * assembler/LinkBuffer.cpp: + (JSC::LinkBuffer::copyCompactAndLinkCode): + (JSC::LinkBuffer::shrink): + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfGetById): + (JSC::FTL::sizeOfPutById): + (JSC::FTL::sizeOfCall): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileFTLOSRExit): + * ftl/FTLThunks.cpp: + (JSC::FTL::osrExitGenerationThunkGenerator): + * jit/GPRInfo.h: + * offlineasm/arm64.rb: + +2014-02-25 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r164627. + http://trac.webkit.org/changeset/164627 + https://bugs.webkit.org/show_bug.cgi?id=129325 + + Broke SubtleCrypto tests (Requested by ap on #webkit). + + * API/APIShims.h: + (JSC::APIEntryShim::APIEntryShim): + (JSC::APICallbackShim::shouldDropAllLocks): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::addCurrentThread): + * runtime/JSLock.cpp: + (JSC::JSLockHolder::JSLockHolder): + (JSC::JSLockHolder::init): + (JSC::JSLockHolder::~JSLockHolder): + (JSC::JSLock::JSLock): + (JSC::JSLock::lock): + (JSC::JSLock::unlock): + (JSC::JSLock::currentThreadIsHoldingLock): + (JSC::JSLock::dropAllLocks): + (JSC::JSLock::grabAllLocks): + * runtime/JSLock.h: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + (JSC::VM::currentThreadIsHoldingAPILock): + +2014-02-25 Filip Pizlo <fpizlo@apple.com> + + ARM64 rshift64 should be an arithmetic shift + https://bugs.webkit.org/show_bug.cgi?id=129323 + + Reviewed by Mark Hahnenberg. + + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::rshift64): + +2014-02-25 Sergio Villar Senin <svillar@igalia.com> + + [CSS Grid Layout] Add ENABLE flag + https://bugs.webkit.org/show_bug.cgi?id=129153 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: added ENABLE_CSS_GRID_LAYOUT feature flag. + +2014-02-25 Michael Saboff <msaboff@apple.com> + + JIT Engines use the wrong stack limit for stack checks + https://bugs.webkit.org/show_bug.cgi?id=129314 + + Reviewed by Filip Pizlo. + + Change the Baseline and DFG code to use VM::m_stackLimit for stack limit checks. + + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compileFunction): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITCall.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileLoadVarargs): + * runtime/VM.h: + (JSC::VM::addressOfStackLimit): + +2014-02-25 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, roll out http://trac.webkit.org/changeset/164493. + + It causes crashes, apparently because it's removing too many barriers. I will investigate + later. + + * bytecode/SpeculatedType.cpp: + (JSC::speculationToAbbreviatedString): + * bytecode/SpeculatedType.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::insertStoreBarrier): + * dfg/DFGNode.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::isNotNully): + (JSC::FTL::LowerDFGToLLVM::isNully): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): + (JSC::FTL::LowerDFGToLLVM::speculateNotCell): + +2014-02-24 Oliver Hunt <oliver@apple.com> + + Fix build. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2014-02-24 Oliver Hunt <oliver@apple.com> + + Spread operator has a bad time when applied to call function + https://bugs.webkit.org/show_bug.cgi?id=128853 + + Reviewed by Geoffrey Garen. + + Follow on from the previous patch the added an extra slot to + op_call_varargs (and _call, _call_eval, _construct). We now + use the slot as an offset to in effect act as a 'slice' on + the spread subject. This allows us to automatically retain + all our existing argument and array optimisatons. Most of + this patch is simply threading the offset around. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitCallVarargs): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::getArgumentByVal): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + * interpreter/Interpreter.cpp: + (JSC::sizeFrameForVarargs): + (JSC::loadVarargs): + * interpreter/Interpreter.h: + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileLoadVarargs): + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::copyToArguments): + * runtime/Arguments.h: + * runtime/JSArray.cpp: + (JSC::JSArray::copyToArguments): + * runtime/JSArray.h: + +2014-02-24 Mark Lam <mark.lam@apple.com> + + Need to initialize VM stack data even when the VM is on an exclusive thread. + <https://webkit.org/b/129265> + + Reviewed by Geoffrey Garen. + + We check VM::exclusiveThread as an optimization to forego the need to do + JSLock locking. However, we recently started piggy backing on JSLock's + lock() and unlock() to initialize VM stack data (stackPointerAtVMEntry + and lastStackTop) to appropriate values for the current thread. This is + needed because we may be acquiring the lock to enter the VM on a different + thread. + + As a result, we ended up not initializing the VM stack data when + VM::exclusiveThread causes us to bypass the locking activity. Even though + the VM::exclusiveThread will not have to deal with the VM being entered + on a different thread, it still needs to initialize the VM stack data. + The VM relies on that data being initialized properly once it has been + entered. + + With this fix, we push the check for exclusiveThread down into the JSLock, + and handle the bypassing of unneeded locking activity there while still + executing the necessary the VM stack data initialization. + + * API/APIShims.h: + (JSC::APIEntryShim::APIEntryShim): + (JSC::APICallbackShim::shouldDropAllLocks): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::addCurrentThread): + * runtime/JSLock.cpp: + (JSC::JSLockHolder::JSLockHolder): + (JSC::JSLockHolder::init): + (JSC::JSLockHolder::~JSLockHolder): + (JSC::JSLock::JSLock): + (JSC::JSLock::setExclusiveThread): + (JSC::JSLock::lock): + (JSLock::unlock): + (JSLock::currentThreadIsHoldingLock): + (JSLock::dropAllLocks): + (JSLock::grabAllLocks): + * runtime/JSLock.h: + (JSC::JSLock::exclusiveThread): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + (JSC::VM::exclusiveThread): + (JSC::VM::setExclusiveThread): + (JSC::VM::currentThreadIsHoldingAPILock): + +2014-02-24 Filip Pizlo <fpizlo@apple.com> + + FTL should do polymorphic PutById inlining + https://bugs.webkit.org/show_bug.cgi?id=129210 + + Reviewed by Mark Hahnenberg and Oliver Hunt. + + This makes PutByIdStatus inform us about polymorphic cases by returning an array of + PutByIdVariants. The DFG now has a node called MultiPutByOffset that indicates a + selection of multiple inlined PutByIdVariants. + + MultiPutByOffset is almost identical to MultiGetByOffset, which we added in + http://trac.webkit.org/changeset/164207. + + This also does some FTL refactoring to make MultiPutByOffset share code with some nodes + that generate similar code. + + 1% speed-up on V8v7 due to splay improving by 6.8%. Splay does the thing where it + sometimes swaps field insertion order, creating fake polymorphism. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::computeForStubInfo): + (JSC::PutByIdStatus::dump): + * bytecode/PutByIdStatus.h: + (JSC::PutByIdStatus::PutByIdStatus): + (JSC::PutByIdStatus::isSimple): + (JSC::PutByIdStatus::numVariants): + (JSC::PutByIdStatus::variants): + (JSC::PutByIdStatus::at): + (JSC::PutByIdStatus::operator[]): + * bytecode/PutByIdVariant.cpp: Added. + (JSC::PutByIdVariant::dump): + (JSC::PutByIdVariant::dumpInContext): + * bytecode/PutByIdVariant.h: Added. + (JSC::PutByIdVariant::PutByIdVariant): + (JSC::PutByIdVariant::replace): + (JSC::PutByIdVariant::transition): + (JSC::PutByIdVariant::kind): + (JSC::PutByIdVariant::isSet): + (JSC::PutByIdVariant::operator!): + (JSC::PutByIdVariant::structure): + (JSC::PutByIdVariant::oldStructure): + (JSC::PutByIdVariant::newStructure): + (JSC::PutByIdVariant::structureChain): + (JSC::PutByIdVariant::offset): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::emitPrototypeChecks): + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::emitPutById): + (JSC::DFG::ByteCodeParser::handlePutById): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCSEPhase.cpp: + (JSC::DFG::CSEPhase::checkStructureElimination): + (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): + (JSC::DFG::CSEPhase::putStructureStoreElimination): + (JSC::DFG::CSEPhase::getByOffsetLoadElimination): + (JSC::DFG::CSEPhase::putByOffsetStoreElimination): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + * dfg/DFGNode.cpp: + (JSC::DFG::MultiPutByOffsetData::writesStructures): + (JSC::DFG::MultiPutByOffsetData::reallocatesStorage): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPutByOffset): + (JSC::DFG::Node::hasMultiPutByOffsetData): + (JSC::DFG::Node::multiPutByOffsetData): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePutStructure): + (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compileGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compilePutByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + (JSC::FTL::LowerDFGToLLVM::loadProperty): + (JSC::FTL::LowerDFGToLLVM::storeProperty): + (JSC::FTL::LowerDFGToLLVM::addressOfProperty): + (JSC::FTL::LowerDFGToLLVM::storageForTransition): + (JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage): + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + * tests/stress/fold-multi-put-by-offset-to-put-by-offset.js: Added. + * tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js: Added. + * tests/stress/multi-put-by-offset-reallocation-cases.js: Added. + +2014-02-24 peavo@outlook.com <peavo@outlook.com> + + JSC regressions after r164494 + https://bugs.webkit.org/show_bug.cgi?id=129272 + + Reviewed by Mark Lam. + + * offlineasm/x86.rb: Only avoid reverse opcode (fdivr) for Windows. + +2014-02-24 Tamas Gergely <tgergely.u-szeged@partner.samsung.com> + + Code cleanup: remove leftover ENABLE(WORKERS) macros and support. + https://bugs.webkit.org/show_bug.cgi?id=129255 + + Reviewed by Csaba Osztrogonác. + + ENABLE_WORKERS macro was removed in r159679. + Support is now also removed from xcconfig files. + + * Configurations/FeatureDefines.xcconfig: + +2014-02-24 David Kilzer <ddkilzer@apple.com> + + Remove redundant setting in FeatureDefines.xcconfig + + * Configurations/FeatureDefines.xcconfig: + +2014-02-23 Sam Weinig <sam@webkit.org> + + Update FeatureDefines.xcconfig + + Rubber-stamped by Anders Carlsson. + + * Configurations/FeatureDefines.xcconfig: + +2014-02-23 Dean Jackson <dino@apple.com> + + Sort the project file with sort-Xcode-project-file. + + Rubber-stamped by Sam Weinig. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-02-23 Sam Weinig <sam@webkit.org> + + Move telephone number detection behind its own ENABLE macro + https://bugs.webkit.org/show_bug.cgi?id=129236 + + Reviewed by Dean Jackson. + + * Configurations/FeatureDefines.xcconfig: + Add ENABLE_TELEPHONE_NUMBER_DETECTION. + +2014-02-22 Filip Pizlo <fpizlo@apple.com> + + Refine DFG+FTL inlining and compilation limits + https://bugs.webkit.org/show_bug.cgi?id=129212 + + Reviewed by Mark Hahnenberg. + + Allow larger functions to be DFG-compiled. Institute a limit on FTL compilation, + and set that limit quite high. Institute a limit on inlining-into. The idea here is + that large functions tend to be autogenerated, and code generators like emscripten + appear to leave few inlining opportunities anyway. Also, we don't want the code + size explosion that we would risk if we allowed compilation of a large function and + then inlined a ton of stuff into it. + + This is a 0.5% speed-up on Octane v2 and almost eliminates the typescript + regression. This is a 9% speed-up on AsmBench. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::noticeIncomingCall): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + * dfg/DFGCapabilities.h: + (JSC::DFG::isSmallEnoughToInlineCodeInto): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLState.h: + (JSC::FTL::shouldShowDisassembly): + * runtime/Options.h: + +2014-02-22 Dan Bernstein <mitz@apple.com> + + REGRESSION (r164507): Crash beneath JSGlobalObjectInspectorController::reportAPIException at facebook.com, twitter.com, youtube.com + https://bugs.webkit.org/show_bug.cgi?id=129227 + + Reviewed by Eric Carlson. + + Reverted r164507. + + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + * API/JSObjectRef.cpp: + (JSObjectMakeFunction): + (JSObjectMakeArray): + (JSObjectMakeDate): + (JSObjectMakeError): + (JSObjectMakeRegExp): + (JSObjectGetProperty): + (JSObjectSetProperty): + (JSObjectGetPropertyAtIndex): + (JSObjectSetPropertyAtIndex): + (JSObjectDeleteProperty): + (JSObjectCallAsFunction): + (JSObjectCallAsConstructor): + * API/JSValue.mm: + (valueToArray): + (valueToDictionary): + * API/JSValueRef.cpp: + (JSValueIsEqual): + (JSValueIsInstanceOfConstructor): + (JSValueCreateJSONString): + (JSValueToNumber): + (JSValueToStringCopy): + (JSValueToObject): + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + * inspector/ConsoleMessage.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/ScriptCallStack.cpp: + * inspector/ScriptCallStack.h: + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::createScriptCallStackForConsole): + (Inspector::createScriptCallStackFromException): + * inspector/ScriptCallStackFactory.h: + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::enable): + (Inspector::InspectorConsoleAgent::addMessageToConsole): + (Inspector::InspectorConsoleAgent::count): + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): + +2014-02-22 Joseph Pecoraro <pecoraro@apple.com> + + Remove some unreachable code (-Wunreachable-code) + https://bugs.webkit.org/show_bug.cgi?id=129220 + + Reviewed by Eric Carlson. + + * API/tests/testapi.c: + (EvilExceptionObject_convertToType): + * disassembler/udis86/udis86_decode.c: + (decode_operand): + +2014-02-22 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, ARMv7 build fix. + + * assembler/ARMv7Assembler.h: + +2014-02-21 Filip Pizlo <fpizlo@apple.com> + + It should be possible for a LinkBuffer to outlive the MacroAssembler and still be useful + https://bugs.webkit.org/show_bug.cgi?id=124733 + + Reviewed by Oliver Hunt. + + This also takes the opportunity to de-duplicate some branch compaction code. + + * assembler/ARM64Assembler.h: + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::buffer): + * assembler/AssemblerBuffer.h: + (JSC::AssemblerData::AssemblerData): + (JSC::AssemblerBuffer::AssemblerBuffer): + (JSC::AssemblerBuffer::storage): + (JSC::AssemblerBuffer::grow): + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::LinkBuffer): + (JSC::LinkBuffer::executableOffsetFor): + (JSC::LinkBuffer::applyOffset): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::link): + * assembler/MacroAssemblerARMv7.h: + +2014-02-21 Brent Fulgham <bfulgham@apple.com> + + Extend media support for WebVTT sources + https://bugs.webkit.org/show_bug.cgi?id=129156 + + Reviewed by Eric Carlson. + + * Configurations/FeatureDefines.xcconfig: Add new feature define for AVF_CAPTIONS + +2014-02-21 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: JSContext inspection should report exceptions in the console + https://bugs.webkit.org/show_bug.cgi?id=128776 + + Reviewed by Timothy Hatcher. + + When JavaScript API functions have an exception, let the inspector + know so it can log the JavaScript and Native backtrace that caused + the exception. + + Include some clean up of ConsoleMessage and ScriptCallStack construction. + + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + * API/JSObjectRef.cpp: + (JSObjectMakeFunction): + (JSObjectMakeArray): + (JSObjectMakeDate): + (JSObjectMakeError): + (JSObjectMakeRegExp): + (JSObjectGetProperty): + (JSObjectSetProperty): + (JSObjectGetPropertyAtIndex): + (JSObjectSetPropertyAtIndex): + (JSObjectDeleteProperty): + (JSObjectCallAsFunction): + (JSObjectCallAsConstructor): + * API/JSValue.mm: + (reportExceptionToInspector): + (valueToArray): + (valueToDictionary): + * API/JSValueRef.cpp: + (JSValueIsEqual): + (JSValueIsInstanceOfConstructor): + (JSValueCreateJSONString): + (JSValueToNumber): + (JSValueToStringCopy): + (JSValueToObject): + When seeing an exception, let the inspector know there was an exception. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + Log API exceptions by also grabbing the native backtrace. + + * inspector/ScriptCallStack.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::firstNonNativeCallFrame): + (Inspector::ScriptCallStack::append): + Minor extensions to ScriptCallStack to make it easier to work with. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + Provide better default information if the first call frame was native. + + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::extractSourceInformationFromException): + (Inspector::createScriptCallStackFromException): + Perform the handling here of inserting a fake call frame for exceptions + if there was no call stack (e.g. a SyntaxError) or if the first call + frame had no information. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + * inspector/ConsoleMessage.h: + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::createScriptCallStackForConsole): + * inspector/ScriptCallStackFactory.h: + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::enable): + (Inspector::InspectorConsoleAgent::addMessageToConsole): + (Inspector::InspectorConsoleAgent::count): + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): + ConsoleMessage cleanup. + +2014-02-21 Oliver Hunt <oliver@apple.com> + + Add extra space to op_call and related opcodes + https://bugs.webkit.org/show_bug.cgi?id=129170 + + Reviewed by Mark Lam. + + No change in behaviour, just some refactoring to add an extra + slot to the op_call instructions, and refactoring to make similar + changes easier in future. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printCallOp): + * bytecode/Opcode.h: + (JSC::padOpcodeName): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitCallVarargs): + (JSC::BytecodeGenerator::emitConstruct): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-02-21 Mark Lam <mark.lam@apple.com> + + gatherFromOtherThread() needs to align the sp before gathering roots. + <https://webkit.org/b/129169> + + Reviewed by Geoffrey Garen. + + The GC scans the stacks of other threads using MachineThreads::gatherFromOtherThread(). + gatherFromOtherThread() defines the range of the other thread's stack as + being bounded by the other thread's stack pointer and stack base. While + the stack base will always be aligned to sizeof(void*), the stack pointer + may not be. This is because the other thread may have just pushed a 32-bit + value on its stack before we suspended it for scanning. + + The fix is to round the stack pointer up to the next aligned address of + sizeof(void*) and start scanning from there. On 64-bit systems, we will + effectively ignore the 32-bit word at the bottom of the stack (top of the + stack for stacks growing up) because it cannot be a 64-bit pointer anyway. + 64-bit pointers should always be stored on 64-bit aligned boundaries (our + conservative scan algorithm already depends on this assumption). + + On 32-bit systems, the rounding is effectively a no-op. + + * heap/ConservativeRoots.cpp: + (JSC::ConservativeRoots::genericAddSpan): + - Hardened somne assertions so that we can catch misalignment issues on + release builds as well. + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::gatherFromOtherThread): + +2014-02-21 Matthew Mirman <mmirman@apple.com> + + Added a GetMyArgumentsLengthSafe and added a speculation check. + https://bugs.webkit.org/show_bug.cgi?id=129051 + + Reviewed by Filip Pizlo. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): + +2014-02-21 peavo@outlook.com <peavo@outlook.com> + + [Win][LLINT] Many JSC stress test failures. + https://bugs.webkit.org/show_bug.cgi?id=129155 + + Reviewed by Michael Saboff. + + Intel syntax has reversed operand order compared to AT&T syntax, so we need to swap the operand order, in this case on floating point operations. + Also avoid using the reverse opcode (e.g. fdivr), as this puts the result at the wrong position in the floating point stack. + E.g. "divd ft0, ft1" would translate to fdivr st, st(1) (Intel syntax) on Windows, but this puts the result in st, when it should be in st(1). + + * offlineasm/x86.rb: Swap operand order on Windows. + +2014-02-21 Filip Pizlo <fpizlo@apple.com> + + DFG write barriers should do more speculations + https://bugs.webkit.org/show_bug.cgi?id=129160 + + Reviewed by Mark Hahnenberg. + + Replace ConditionalStoreBarrier with the cheapest speculation that you could do + instead. + + Miniscule speed-up on some things. It's a decent difference in code size, though. + + * bytecode/SpeculatedType.cpp: + (JSC::speculationToAbbreviatedString): + * bytecode/SpeculatedType.h: + (JSC::isNotCellSpeculation): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::insertStoreBarrier): + (JSC::DFG::FixupPhase::insertPhantomCheck): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateOther): + (JSC::DFG::Node::shouldSpeculateNotCell): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::isNotOther): + (JSC::FTL::LowerDFGToLLVM::isOther): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): + (JSC::FTL::LowerDFGToLLVM::speculateOther): + (JSC::FTL::LowerDFGToLLVM::speculateNotCell): + +2014-02-21 Joseph Pecoraro <pecoraro@apple.com> + + Revert r164486, causing a number of test failures. + + Unreviewed rollout. + +2014-02-21 Filip Pizlo <fpizlo@apple.com> + + Revive SABI (aka shouldAlwaysBeInlined) + https://bugs.webkit.org/show_bug.cgi?id=129159 + + Reviewed by Mark Hahnenberg. + + This is a small Octane speed-up. + + * jit/Repatch.cpp: + (JSC::linkFor): This code was assuming that if it's invoked then the caller is a DFG code block. That's wrong, since it's now used by all of the JITs. + +2014-02-21 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: JSContext inspection should report exceptions in the console + https://bugs.webkit.org/show_bug.cgi?id=128776 + + Reviewed by Timothy Hatcher. + + When JavaScript API functions have an exception, let the inspector + know so it can log the JavaScript and Native backtrace that caused + the exception. + + Include some clean up of ConsoleMessage and ScriptCallStack construction. + + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + * API/JSObjectRef.cpp: + (JSObjectMakeFunction): + (JSObjectMakeArray): + (JSObjectMakeDate): + (JSObjectMakeError): + (JSObjectMakeRegExp): + (JSObjectGetProperty): + (JSObjectSetProperty): + (JSObjectGetPropertyAtIndex): + (JSObjectSetPropertyAtIndex): + (JSObjectDeleteProperty): + (JSObjectCallAsFunction): + (JSObjectCallAsConstructor): + * API/JSValue.mm: + (reportExceptionToInspector): + (valueToArray): + (valueToDictionary): + * API/JSValueRef.cpp: + (JSValueIsEqual): + (JSValueIsInstanceOfConstructor): + (JSValueCreateJSONString): + (JSValueToNumber): + (JSValueToStringCopy): + (JSValueToObject): + When seeing an exception, let the inspector know there was an exception. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + Log API exceptions by also grabbing the native backtrace. + + * inspector/ScriptCallStack.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::firstNonNativeCallFrame): + (Inspector::ScriptCallStack::append): + Minor extensions to ScriptCallStack to make it easier to work with. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + Provide better default information if the first call frame was native. + + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::extractSourceInformationFromException): + (Inspector::createScriptCallStackFromException): + Perform the handling here of inserting a fake call frame for exceptions + if there was no call stack (e.g. a SyntaxError) or if the first call + frame had no information. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::ConsoleMessage): + (Inspector::ConsoleMessage::autogenerateMetadata): + * inspector/ConsoleMessage.h: + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::createScriptCallStackForConsole): + * inspector/ScriptCallStackFactory.h: + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::enable): + (Inspector::InspectorConsoleAgent::addMessageToConsole): + (Inspector::InspectorConsoleAgent::count): + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): + ConsoleMessage cleanup. + +2014-02-20 Anders Carlsson <andersca@apple.com> + + Modernize JSGlobalLock and JSLockHolder + https://bugs.webkit.org/show_bug.cgi?id=129105 + + Reviewed by Michael Saboff. + + Use std::mutex and std::thread::id where possible. + + * runtime/JSLock.cpp: + (JSC::GlobalJSLock::GlobalJSLock): + (JSC::GlobalJSLock::~GlobalJSLock): + (JSC::GlobalJSLock::initialize): + (JSC::JSLock::JSLock): + (JSC::JSLock::lock): + (JSC::JSLock::unlock): + (JSC::JSLock::currentThreadIsHoldingLock): + * runtime/JSLock.h: + +2014-02-20 Mark Lam <mark.lam@apple.com> + + virtualForWithFunction() should not throw an exception with a partially initialized frame. + <https://webkit.org/b/129134> + + Reviewed by Michael Saboff. + + Currently, when JITOperations.cpp's virtualForWithFunction() fails to + prepare the callee function for execution, it proceeds to throw the + exception using the callee frame which is only partially initialized + thus far. Instead, it should be throwing the exception using the caller + frame because: + 1. the error happened "in" the caller while preparing the callee for + execution i.e. the caller frame is the top fully initialized frame + on the stack. + 2. the callee frame is not fully initialized yet, and the unwind + mechanism cannot depend on the data in it. + + * jit/JITOperations.cpp: + +2014-02-20 Mark Lam <mark.lam@apple.com> + + DefaultGCActivityCallback::doWork() should reschedule if GC is deferred. + <https://webkit.org/b/129131> + + Reviewed by Mark Hahnenberg. + + Currently, DefaultGCActivityCallback::doWork() does not check if the GC + needs to be deferred before commencing. As a result, the GC may crash + and/or corrupt data because the VM is not in the consistent state needed + for the GC to run. With this fix, doWork() now checks if the GC is + supposed to be deferred and re-schedules if needed. It only commences + with GC'ing when it's safe to do so. + + * runtime/GCActivityCallback.cpp: + (JSC::DefaultGCActivityCallback::doWork): + +2014-02-20 Geoffrey Garen <ggaren@apple.com> + + Math.imul gives wrong results + https://bugs.webkit.org/show_bug.cgi?id=126345 + + Reviewed by Mark Hahnenberg. + + Don't truncate non-int doubles to 0 -- that's just not how ToInt32 works. + Instead, take a slow path that will do the right thing. + + * jit/ThunkGenerators.cpp: + (JSC::imulThunkGenerator): + +2014-02-20 Filip Pizlo <fpizlo@apple.com> + + DFG should do its own static estimates of execution frequency before it starts creating OSR entrypoints + https://bugs.webkit.org/show_bug.cgi?id=129129 + + Reviewed by Geoffrey Garen. + + We estimate execution counts based on loop depth, and then use those to estimate branch + weights. These weights then get carried all the way down to LLVM prof branch_weights + meta-data. + + This is better than letting LLVM do its own static estimates, since by the time we + generate LLVM IR, we may have messed up the CFG due to OSR entrypoint creation. Of + course, it would be even better if we just slurped in some kind of execution counts + from profiling, but we don't do that, yet. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::BasicBlock): + * dfg/DFGBasicBlock.h: + * dfg/DFGBlockInsertionSet.cpp: + (JSC::DFG::BlockInsertionSet::insert): + (JSC::DFG::BlockInsertionSet::insertBefore): + * dfg/DFGBlockInsertionSet.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGCriticalEdgeBreakingPhase.cpp: + (JSC::DFG::CriticalEdgeBreakingPhase::breakCriticalEdge): + * dfg/DFGLoopPreHeaderCreationPhase.cpp: + (JSC::DFG::createPreHeader): + * dfg/DFGNaturalLoops.h: + (JSC::DFG::NaturalLoops::loopDepth): + * dfg/DFGOSREntrypointCreationPhase.cpp: + (JSC::DFG::OSREntrypointCreationPhase::run): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGStaticExecutionCountEstimationPhase.cpp: Added. + (JSC::DFG::StaticExecutionCountEstimationPhase::StaticExecutionCountEstimationPhase): + (JSC::DFG::StaticExecutionCountEstimationPhase::run): + (JSC::DFG::StaticExecutionCountEstimationPhase::applyCounts): + (JSC::DFG::performStaticExecutionCountEstimation): + * dfg/DFGStaticExecutionCountEstimationPhase.h: Added. + +2014-02-20 Filip Pizlo <fpizlo@apple.com> + + FTL may not see a compact_unwind section if there weren't any stackmaps + https://bugs.webkit.org/show_bug.cgi?id=129125 + + Reviewed by Geoffrey Garen. + + It's OK to not have an unwind section, so long as the function also doesn't have any + OSR exits. + + * ftl/FTLCompile.cpp: + (JSC::FTL::fixFunctionBasedOnStackMaps): + (JSC::FTL::compile): + * ftl/FTLUnwindInfo.cpp: + (JSC::FTL::UnwindInfo::parse): + * ftl/FTLUnwindInfo.h: + +== Rolled over to ChangeLog-2014-02-20 == diff --git a/ChangeLog-2015-07-23 b/ChangeLog-2015-07-23 new file mode 100644 index 0000000..acc233a --- /dev/null +++ b/ChangeLog-2015-07-23 @@ -0,0 +1,34401 @@ +2015-07-20 Matthew Hanson <matthew_hanson@apple.com> + + Merge r186819. rdar://problem/21729083 + + 2015-07-14 Matthew Mirman <mmirman@apple.com> + + Repatch. Makes compileArithSub in the DFG ensure that the constant is an int32. + https://bugs.webkit.org/show_bug.cgi?id=146910 + rdar://problem/21729083 + + Reviewed by Filip Pizlo. + + Also fixes the debug build problem where all edges are assumed to + have UntypedUse before the fixup phase. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithSub): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateEdgeWithDoubleResultIfNecessary): + * tests/stress/arith-add-with-constants.js: Added some tests for this case. + (arithAdd42WrittenAsInteger): + (testArithAdd42WrittenAsInteger): + (arithSub42WrittenAsDouble): + (testArithSub42WrittenAsDouble): + (doubleConstant): + (testDoubleConstant): Added test for the case of +0.0 and Math.min(0.0) + (arithAdd42WrittenAsDouble): Deleted. + (testArithAdd42WrittenAsDouble): Deleted. + +2015-07-20 Matthew Hanson <matthew_hanson@apple.com> + + Merge r187028. rdar://problem/21869970 + + 2015-07-18 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(186691): OSR entry is broken on loop headers that have no live variables + https://bugs.webkit.org/show_bug.cgi?id=147074 + rdar://problem/21869970 + + Reviewed by Michael Saboff. + + The OSR entry must-handle block/value widening introduced in r186691 would cause the + CFA to reexecute if it caused any live local variables to change value. But this fails + if the must-handle block has no live local variables, and the entry block otherwise + appears to be unreachable. + + This fixes the bug by having the change detection include whether the block hadn't been + visited in addition to whether any local variable values got widened. + + This is a ~4% speed-up on SunSpider in browser. + + * dfg/DFGCFAPhase.cpp: + (JSC::DFG::CFAPhase::run): + +2015-07-16 Matthew Hanson <matthew_hanson@apple.com> + + Merge r186920. rdar://problem/21764196 + + 2015-07-16 Mark Lam <mark.lam@apple.com> + + RegExp::match() should set m_state to ByteCode if compilation fails. + https://bugs.webkit.org/show_bug.cgi?id=147023 + + Reviewed by Michael Saboff. + + A RegExp has a YarrCodeBlock that has 4 MacroAssemblerCodeRefs for compiled code. + If one of these compilations succeeds, RegExp::m_state will be set to JITCode. + Subsequently, if RegExp tries to compile another one of these but fails, m_state + will be left untouched i.e. it still says JITCode. As a result, when + RegExp::match() later tries to execute the non-existant compiled code, it will + crash. + + The fix is to downgrade m_state to ByteCode if RegExp ever fails to compile. + This failure should be rare. We'll do the minimal work here to fix the issue and + keep an eye on the perf bots. If perf regresses, we can do some optimization work then. + + This issue is difficult to test for since it either requires a low memory condition + to trigger a failed RegExp compilation at the right moment, or for the RegExp to + succeed compilation in the MatchedOnly mode but fail in IncludeSubpatterns mode. + Instead, I manually tested it by instrumenting RegExp::compile() to fail once in every + 10 compilation attempts. + + * runtime/RegExp.cpp: + (JSC::RegExp::compile): + (JSC::RegExp::compileMatchOnly): + +2015-07-15 Lucas Forschler <lforschler@apple.com> + + Merge r186826 + + 2015-07-14 Anders Carlsson <andersca@apple.com> + + Assertions.h should include ExportMacros.h + https://bugs.webkit.org/show_bug.cgi?id=146948 + + Reviewed by Tim Horton. + + Remove now unneeded WTF_EXPORT_PRIVATE define. + + * API/JSBase.h: + +2015-07-13 Babak Shafiei <bshafiei@apple.com> + + Merge r186777. + + 2015-07-13 Anders Carlsson <andersca@apple.com> + + Apps linked with a deployment target of iOS 7.x or earlier crash when using modern WebKit API + https://bugs.webkit.org/show_bug.cgi?id=146913 + rdar://problem/21789252 + + Reviewed by Dan Bernstein. + + Make a top-level symlink from /System/Library/PrivateFrameworks/JavaScriptCore.framework to + /System/Library/Frameworks/JavaScriptCore.framework. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-07-12 Babak Shafiei <bshafiei@apple.com> + + Merge r186702. + + 2015-07-10 Filip Pizlo <fpizlo@apple.com> + + AI folding of IsObjectOrNull is broken for non-object types that may be null + https://bugs.webkit.org/show_bug.cgi?id=146867 + + Reviewed by Ryosuke Niwa. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): Fix the bug and add some text describing what is going on. + * tests/stress/misc-is-object-or-null.js: Added. Test for the bug. + (foo): + * tests/stress/other-is-object-or-null.js: Added. Test for a bug I almost introduced. + (foo): + +2015-07-12 Babak Shafiei <bshafiei@apple.com> + + Merge r186691. + + 2015-07-04 Filip Pizlo <fpizlo@apple.com> + + DFG fragile frozen values are fundamentally broken + https://bugs.webkit.org/show_bug.cgi?id=146602 + + Reviewed by Mark Lam. + + This change gets rid of the FragileValue value strength, because it was fundamentally + broken. + + FragileValue was a value known to the compiler but not tracked by the GC in any way - + it wasn't marked and it wasn't weak. This was used to support AI bootstrap for OSR + must-handle values. The philosophy was that if the compiler did use the value for + optimization, it would have been strengthened to a weak value (or maybe even a strong + value, though we probably won't do that). But this was too much of a pipe dream. I've + found at least one case where the compiler did use the value, but never strengthened + it: it would happen if the value ended up in an OSR entry data expected value. Then if + we GCed, we might have killed the value, but OSR entry would still try to use it for + validation. That might have sort of just worked, but it's clearly shady. + + The reason why we made must-handle values fragile and not weak is that most of the time + the values disappear from the abstract state: they are LUBed to a non-constant. If we + kept them around as weak, we'd have too many cases of the GC killing the code because + it thought that the value was somehow meaningful to the code when it was only used as a + temporary artifact of optimization. + + So, it's true that it's very important for must-handle values not to automatically be + weak or strong. It's also true that the values are necessary for AI bootstrap because + we need to know what values OSR entry will require. But we shouldn't accomplish these + goals by having the compiler hold onto what are essentially dangling pointers. + + This implements a better solution: instead of having InPlaceAbstractState bootstrap the + AI with must-handle values at the beginning, we now widen the valuesAtHead of the + must-handle block after AI converges. This widening is done in CFAPhase. This allows us + to see if the must-handle values are necessary at all. In most cases, the widening + takes a non-constant abstract value and simply amends something to its type based on + the type of the must-handle value, and so the must-handle value never actually shows up + in either the IR or any abstract value. In the unlikely event that the value at head is + bottom, we freeze the must-handle value. This change removes FragileValue, and this + freezing uses WeakValue as the strength. That makes sense: since the abstract value was + bottom, the must-handle value becomes integral to the IR and so it makes no sense for + the GC to keep the resulting CodeBlock alive if that must-handle value dies. This will + sometimes happen for example if you have a very long-running loop whose pre-header + allocates some object, but that pre-header appears to always exit to the optimizing JIT + because it was only profiled once in the LLInt and that profiling appears insufficient + to the DFG. In that case, we'll effectively constant-fold the references to the object + inside the loop, which is both efficient (yay constant folding!) and necessary + (otherwise we wouldn't know what the type of the variable should have been). + + Testing and debugging this is complicated. So, this adds some new capabilities: + + - DFG IR dumps also dump all of the FrozenValues that point to the heap along with + their strengths, so that it's easy to see what GC objects the DFG feels are necessary + for the compilation. + + - DFG OSR entry preparation prints out the OSR entry data structures, so that it's easy + to see what GC pointers (and other things) are used for OSR entry validation. The + printouts are quite detailed, and should also help other kinds of OSR entry + debugging. + + - DFG::Plan now validates whether all of the GC pointers planted in the various JITCode + data structures are also properly registered as either weak or strong pointers in the + CodeBlock. This validation check previously failed due to fragile values ending up in + the OSR entry data structures, both in the newly added test (dead-osr-entry-value.js) + and in some pre-existing tests (like earley-boyer and 3d-raytrace). + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::stronglyVisitStrongReferences): + * bytecode/CodeOrigin.cpp: + (JSC::InlineCallFrame::visitAggregate): + * bytecode/Operands.h: + (JSC::Operands::operand): + (JSC::Operands::hasOperand): + * bytecode/StructureSet.cpp: + (JSC::StructureSet::dump): + (JSC::StructureSet::validateReferences): + * bytecode/StructureSet.h: + * bytecode/TrackedReferences.cpp: Added. + (JSC::TrackedReferences::TrackedReferences): + (JSC::TrackedReferences::~TrackedReferences): + (JSC::TrackedReferences::add): + (JSC::TrackedReferences::check): + (JSC::TrackedReferences::dump): + * bytecode/TrackedReferences.h: Added. + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::observeTransitions): + (JSC::DFG::AbstractValue::set): + (JSC::DFG::AbstractValue::fixTypeForRepresentation): + (JSC::DFG::AbstractValue::mergeOSREntryValue): + (JSC::DFG::AbstractValue::filter): + (JSC::DFG::AbstractValue::dumpInContext): + (JSC::DFG::AbstractValue::validateReferences): + (JSC::DFG::AbstractValue::setOSREntryValue): Deleted. + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::fullTop): + (JSC::DFG::AbstractValue::merge): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGCFAPhase.cpp: + (JSC::DFG::CFAPhase::run): + * dfg/DFGCommonData.cpp: + (JSC::DFG::CommonData::invalidate): + (JSC::DFG::CommonData::validateReferences): + * dfg/DFGCommonData.h: + (JSC::DFG::CommonData::requiredRegisterCountForExecutionAndExit): + * dfg/DFGFrozenValue.h: + (JSC::DFG::FrozenValue::FrozenValue): + (JSC::DFG::FrozenValue::strengthenTo): + (JSC::DFG::FrozenValue::pointsToHeap): + (JSC::DFG::FrozenValue::strength): + (JSC::DFG::FrozenValue::freeze): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::registerFrozenValues): + (JSC::DFG::Graph::visitChildren): + (JSC::DFG::Graph::freeze): + (JSC::DFG::Graph::freezeStrong): + (JSC::DFG::Graph::freezeFragile): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + * dfg/DFGJITCode.cpp: + (JSC::DFG::JITCode::setOptimizationThresholdBasedOnCompilationResult): + (JSC::DFG::JITCode::validateReferences): + * dfg/DFGJITCode.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::addressOfDoubleConstant): + (JSC::DFG::JITCompiler::noticeOSREntry): + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::branchStructurePtr): + (JSC::DFG::JITCompiler::jitCode): + (JSC::DFG::JITCompiler::noticeOSREntry): Deleted. + * dfg/DFGMinifiedGraph.cpp: Added. + (JSC::DFG::MinifiedGraph::prepareAndShrink): + (JSC::DFG::MinifiedGraph::validateReferences): + * dfg/DFGMinifiedGraph.h: + (JSC::DFG::MinifiedGraph::append): + (JSC::DFG::MinifiedGraph::prepareAndShrink): Deleted. + * dfg/DFGOSREntry.cpp: + (JSC::DFG::OSREntryData::dumpInContext): + (JSC::DFG::OSREntryData::dump): + (JSC::DFG::prepareOSREntry): + * dfg/DFGOSREntry.h: + (JSC::DFG::getOSREntryDataBytecodeIndex): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::finalizeWithoutNotifyingCallback): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::linkOSREntries): + (JSC::DFG::SpeculativeJIT::compileDoublePutByVal): + * dfg/DFGStructureAbstractValue.cpp: + (JSC::DFG::StructureAbstractValue::dump): + (JSC::DFG::StructureAbstractValue::validateReferences): + * dfg/DFGStructureAbstractValue.h: + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * dfg/DFGValueStrength.cpp: + (WTF::printInternal): + * dfg/DFGValueStrength.h: + (JSC::DFG::merge): + * ftl/FTLExitPropertyValue.cpp: + (JSC::FTL::ExitPropertyValue::dump): + (JSC::FTL::ExitPropertyValue::validateReferences): + * ftl/FTLExitPropertyValue.h: + * ftl/FTLExitTimeObjectMaterialization.cpp: + (JSC::FTL::ExitTimeObjectMaterialization::dump): + (JSC::FTL::ExitTimeObjectMaterialization::validateReferences): + * ftl/FTLExitTimeObjectMaterialization.h: + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::dump): + (JSC::FTL::ExitValue::validateReferences): + * ftl/FTLExitValue.h: + * ftl/FTLJITCode.cpp: + (JSC::FTL::JITCode::dfgCommon): + (JSC::FTL::JITCode::validateReferences): + * ftl/FTLJITCode.h: + (JSC::FTL::JITCode::handles): + (JSC::FTL::JITCode::dataSections): + * ftl/FTLOSRExit.cpp: + (JSC::FTL::OSRExit::codeLocationForRepatch): + (JSC::FTL::OSRExit::validateReferences): + * ftl/FTLOSRExit.h: + (JSC::FTL::OSRExit::considerAddingAsFrequentExitSite): + * jit/JITCode.cpp: + (JSC::JITCode::typeName): + (JSC::JITCode::validateReferences): + (JSC::JITCode::execute): + * jit/JITCode.h: + (JSC::JITCode::start): + * tests/stress/dead-osr-entry-value.js: Added. + (foo): + +2015-07-10 Matthew Hanson <matthew_hanson@apple.com> + + Disable non-shipping features. + + * Configurations/FeatureDefines.xcconfig: + +2015-07-09 Mark Lam <mark.lam@apple.com> + + SymbolTable::entryFor() should do a bounds check before indexing into the localToEntry vector. + https://bugs.webkit.org/show_bug.cgi?id=146807 + + Reviewed by Filip Pizlo. + + When we capture an argument by name and we use "arguments", we put all of the + arguments into the scope. But destructured arguments are put into the scope + anonymously i.e. the SymbolTable knows that the scope offset is in use via + SymbolTable::m_maxScopeOffset, but that ScopeOffset won't appear in + SymbolTable::m_map. + + The SymbolTable's m_localToEntry vector is synthesized from its m_map, and will + have a size which is based on the largest ScopeOffset in the m_map. If we have a + scenario where the anonymous argument is at a higher ScopeOffset than all the + named arguments, then the m_localsToEntry vector will not have an entry for it + i.e. the m_localsToEntry vector will have a size that is <= the ScopeOffset of + the anonymous argument. + + Hence, SymbolTable::entryFor() should ensure that the requested ScopeOffset is + within the bounds of the m_localToEntry vector before indexing into it. + + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::entryFor): + +2015-07-09 Michael Saboff <msaboff@apple.com> + + REGRESSION (r180248): Repro Crash: com.apple.WebKit.WebContent at com.apple.JavaScriptCore: JSC::createRangeError + 20 + https://bugs.webkit.org/show_bug.cgi?id=146767 + + Reviewed by Geoffrey Garen. + + If the stack check fails at the top most frame, we must use that frame to + generate the exception. Reverted the code to always use the current frame to + throw an out of stack exception. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + +2015-07-03 Filip Pizlo <fpizlo@apple.com> + + OSR exit fuzzing should allow us to select a static exit site + https://bugs.webkit.org/show_bug.cgi?id=146601 + + Reviewed by Geoffrey Garen. + + The original implementation of the fuzzer allows us to trigger an exit based on its index + in the dynamic sequence of exit sites encountered. But there are usually millions of + dynamically encountered exit sites, even if the program only has thousands of static exit + sites. That means that we would at best be able to do a random sampling of exits, and + those would be biased to the hottest exit sites. + + This change allows us to also select exit sites based on their index in the static + sequence of exit sites that the compiler compiled. Then, once that static exit site is + selected, we can select which dynamic exit at that exit site we should trigger. Since the + number of static exit sites is usually smallish (it's bounded by program size), we can do + an exhaustive search over all exit sites in most programs. + + * dfg/DFGOSRExitFuzz.cpp: + (JSC::numberOfStaticOSRExitFuzzChecks): + (JSC::numberOfOSRExitFuzzChecks): + * dfg/DFGOSRExitFuzz.h: + (JSC::DFG::doOSRExitFuzzing): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitOSRExitFuzzCheck): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExit): + * jsc.cpp: + (jscmain): + * runtime/Options.h: + * runtime/TestRunnerUtils.h: + +2015-07-08 Joseph Pecoraro <pecoraro@apple.com> + + Fix grammar issue in TypeError attempting to change an unconfigurable property + https://bugs.webkit.org/show_bug.cgi?id=146774 + + Reviewed by Brent Fulgham. + + * runtime/JSFunction.cpp: + (JSC::JSFunction::defineOwnProperty): + * runtime/JSObject.cpp: + (JSC::JSObject::defineOwnNonIndexProperty): + * runtime/StringObject.cpp: + (JSC::StringObject::defineOwnProperty): + +2015-07-06 Csaba Osztrogonác <ossy@webkit.org> + + Remove the unused HeapBlock.h + https://bugs.webkit.org/show_bug.cgi?id=146580 + + Reviewed by Andreas Kling. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/CopiedBlock.h: + * heap/CopiedSpace.h: + * heap/CopiedSpaceInlines.h: + * heap/HandleBlock.h: + * heap/HeapBlock.h: Removed. + * heap/MarkedBlock.h: + +2015-07-06 Saam barati <saambarati1@gmail.com> + + JSC's parser should follow the ES6 spec with respect to parsing Declarations + https://bugs.webkit.org/show_bug.cgi?id=146621 + + Reviewed by Mark Lam. + + There were a few locations where JSC would allow declaration statements + in incorrect ways. JSC didn't distinguish between 'Statement' and + 'StatementListItem' grammar productions. The relevant grammar is here: + http://www.ecma-international.org/ecma-262/6.0/index.html#sec-statements + + From the ECMA Script 6.0 spec: + 1. Section 13.6 The if Statement (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-if-statement) + says that IfStatements only takes Statements for the "then-else" clauses, not StatementListItems. + (Same with 'while/for/do-while' loop bodies). + 2. Section 13 ECMAScript Language: Statements and Declarations + (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-ecmascript-language-statements-and-declarations) + defines the syntax of Statements, and they do not include ClassDeclarations and LexicalDeclarations + (const, let, see 13.3.1 Let and Const Declarations). + Declarations can only be in the âthen-elseâ clauses when embedded in a StatementListItem in a BlockStatement (see 13.2). + + Hence, the following style of declarations are no longer allowed: + 'if/for/while (condition) const x = 40;' + 'if/for/while (condition) class C { }' + + Instead, we mandate such declaration constructs are within a StatementList + (which is the production that JSC's Parser::parseSourceElements function parses): + 'if/for/while (condition) { const x = 40; }' + 'if/for/while (condition) { class C { } }' + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseSourceElements): + (JSC::Parser<LexerType>::parseStatementListItem): + (JSC::Parser<LexerType>::parseVarDeclaration): + (JSC::Parser<LexerType>::parseStatement): + (JSC::Parser<LexerType>::parseExpressionStatement): + * parser/Parser.h: + (JSC::Parser::getLabel): + +2015-07-06 Alex Christensen <achristensen@webkit.org> + + Unreviewed debug build fix after r186358. + + * runtime/JSArray.cpp: + (JSC::JSArray::fastConcatWith): + Pass vm parameter to fastConcatType. + +2015-07-06 Ryosuke Niwa <rniwa@webkit.org> + + Array.concat should be fast for integer or double arrays + https://bugs.webkit.org/show_bug.cgi?id=146260 + + Reviewed by Darin Adler. + + Added a fast path to Array.prototype.concat. When concatenating two Int32, Double, or Contiguous + arrays, simply memcopy the arrays into a new uninitialized buffer. + + This improves huffman encoding in CompressionBench by 3.7x on a Mid 2014 MacBookPro. + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncConcat): + * runtime/JSArray.cpp: + (JSC::JSArray::fastConcatWith): Added. + * runtime/JSArray.h: + (JSC::JSArray::fastConcatType): Added. Returns the resultant array's indexing type if we can use + the fact path. Returns NonArray otherwise. + +2015-07-06 Youenn Fablet <youenn.fablet@crf.canon.fr> + + [Streams API] Remove ReadableStream custom constructor + https://bugs.webkit.org/show_bug.cgi?id=146547 + + Reviewed by Darin Adler. + + Adding helper function to throw range errors. + + * runtime/Error.h: + (JSC::throwRangeError): + (JSC::throwVMRangeError): + +2015-07-05 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement the latest Promise spec in JS + https://bugs.webkit.org/show_bug.cgi?id=146229 + + Reviewed by Sam Weinig. + + Updated the Promise implementation to meet to the ES6 spec. + This patch + 1. Implement ES6 Promise and related abstract operations in builtins JS + 2. Expose @enqueueJob private function to JS world to post the microtask + + Updated implementation has one-on-one correspondence to the ES6 spec description. + And keep the JSPromiseDeferred because it is the interface used from the WebCore. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/Array.prototype.js: + (reduce): + (reduceRight): + (every): + (forEach): + (filter): + (map): + (some): + (fill): + (find): + (findIndex): + (includes): + (copyWithin): + ToInteger / ToLength are renamed to toInteger and toLength. + * builtins/ArrayConstructor.js: + (from): + ToInteger / ToLength are renamed to toInteger and toLength. + * builtins/GlobalObject.js: + (toInteger): + (toLength): + (isObject): + (ToInteger): Deleted. + (ToLength): Deleted. + ToInteger / ToLength are renamed to toInteger and toLength. + Add new abstract operation, isObject. + * builtins/Operations.Promise.js: Added. + (isPromise): + (newPromiseReaction): + (newPromiseDeferred): + (newPromiseCapability.executor): + (newPromiseCapability): + (triggerPromiseReactions): + (rejectPromise): + (fulfillPromise): + (createResolvingFunctions.resolve): + (createResolvingFunctions.reject): + (createResolvingFunctions): + (promiseReactionJob): + (promiseResolveThenableJob): + (initializePromise): + Added Promise related abstract operations. + * builtins/Promise.prototype.js: + (catch): + (.onFulfilled): + (.onRejected): + (then): + Promise#then implementation in JS. + * builtins/PromiseConstructor.js: Added. + (all.newResolveElement): + (all): + (race): + (reject): + (resolve): + Promise static functions implementations in JS. + * builtins/StringConstructor.js: + (raw): + ToInteger / ToLength are renamed to toInteger and toLength. + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::getInternalProperties): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::enqueueJob): + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::initializePromiseFunction): + (JSC::JSGlobalObject::newPromiseDeferredFunction): + * runtime/JSJob.cpp: Renamed from Source/JavaScriptCore/runtime/JSPromiseReaction.h. + (JSC::createJSJob): + (JSC::JSJobMicrotask::run): + * runtime/JSJob.h: Renamed from Source/JavaScriptCore/runtime/JSPromiseFunctions.h. + * runtime/JSPromise.cpp: + (JSC::JSPromise::create): + (JSC::JSPromise::JSPromise): + (JSC::JSPromise::finishCreation): + (JSC::JSPromise::result): + (JSC::JSPromise::destroy): Deleted. + (JSC::JSPromise::visitChildren): Deleted. + (JSC::JSPromise::reject): Deleted. + (JSC::JSPromise::resolve): Deleted. + (JSC::JSPromise::appendResolveReaction): Deleted. + (JSC::JSPromise::appendRejectReaction): Deleted. + (JSC::triggerPromiseReactions): Deleted. + * runtime/JSPromise.h: + (JSC::JSPromise::status): Deleted. + (JSC::JSPromise::result): Deleted. + (JSC::JSPromise::constructor): Deleted. + * runtime/JSPromiseConstructor.cpp: + (JSC::constructPromise): + (JSC::JSPromiseConstructorFuncResolve): Deleted. + (JSC::JSPromiseConstructorFuncReject): Deleted. + (JSC::performPromiseRaceLoop): Deleted. + (JSC::JSPromiseConstructorFuncRace): Deleted. + (JSC::performPromiseAll): Deleted. + (JSC::JSPromiseConstructorFuncAll): Deleted. + * runtime/JSPromiseDeferred.cpp: + (JSC::JSPromiseDeferred::create): + (JSC::createJSPromiseDeferredFromConstructor): Deleted. + (JSC::updateDeferredFromPotentialThenable): Deleted. + (JSC::performDeferredResolve): Deleted. + (JSC::performDeferredReject): Deleted. + (JSC::abruptRejection): Deleted. + * runtime/JSPromiseDeferred.h: + * runtime/JSPromiseFunctions.cpp: Removed. + (JSC::deferredConstructionFunction): Deleted. + (JSC::createDeferredConstructionFunction): Deleted. + (JSC::identifyFunction): Deleted. + (JSC::createIdentifyFunction): Deleted. + (JSC::promiseAllCountdownFunction): Deleted. + (JSC::createPromiseAllCountdownFunction): Deleted. + (JSC::promiseResolutionHandlerFunction): Deleted. + (JSC::createPromiseResolutionHandlerFunction): Deleted. + (JSC::rejectPromiseFunction): Deleted. + (JSC::createRejectPromiseFunction): Deleted. + (JSC::resolvePromiseFunction): Deleted. + (JSC::createResolvePromiseFunction): Deleted. + (JSC::throwerFunction): Deleted. + (JSC::createThrowerFunction): Deleted. + * runtime/JSPromisePrototype.cpp: + (JSC::JSPromisePrototypeFuncThen): Deleted. + * runtime/JSPromiseReaction.cpp: Removed. + (JSC::createExecutePromiseReactionMicrotask): Deleted. + (JSC::ExecutePromiseReactionMicrotask::run): Deleted. + (JSC::JSPromiseReaction::create): Deleted. + (JSC::JSPromiseReaction::JSPromiseReaction): Deleted. + (JSC::JSPromiseReaction::finishCreation): Deleted. + (JSC::JSPromiseReaction::visitChildren): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): Deleted. + * runtime/VM.h: + +2015-07-04 Chris Dumez <cdumez@apple.com> + + Drop RefPtr::clear() method + https://bugs.webkit.org/show_bug.cgi?id=146556 + + Reviewed by Brady Eidson. + + Drop RefPtr::clear() method in favor of "= nullptr;" pattern. + +2015-07-03 Dan Bernstein <mitz@apple.com> + + Just give up on -Wunreachable-code in JavaScriptCore. + + * Configurations/Base.xcconfig: + * llint/LowLevelInterpreter.cpp: + (JSC::CLoop::execute): + +2015-07-03 Dan Bernstein <mitz@apple.com> + + Fixed the LLINT CLoop build. + + * llint/LowLevelInterpreter.cpp: + (JSC::CLoop::execute): + +2015-07-03 Dan Bernstein <mitz@apple.com> + + [Xcode] Update some build settings as recommended by Xcode 7 + https://bugs.webkit.org/show_bug.cgi?id=146597 + + Reviewed by Sam Weinig. + + * Configurations/Base.xcconfig: Enabled CLANG_WARN_UNREACHABLE_CODE and + GCC_NO_COMMON_BLOCKS. Removed GCC_MODEL_TUNING. + + * JavaScriptCore.xcodeproj/project.pbxproj: Updated LastUpgradeCheck. + + * dfg/DFGGraph.h: Tweaked the definition of DFG_CRASH to suppress unreachable code warnings. + +2015-07-03 Yusuke Suzuki <utatane.tea@gmail.com> + + Relax builtin JS restriction about try-catch + https://bugs.webkit.org/show_bug.cgi?id=146555 + + Reviewed by Sam Weinig. + + When retrieving the captured variables from the full activated scope, + it swapped the given vector with the stored declared variables vector. + This is because retrieving the captured variables are executed in the + last sequence of the parser, so declared variables are no longer used. + However, in builtins functions case, after retrieving the captured + variables, we check the variables by using declared variables vector. + So at that time, the declared variables vector becomes empty and it + raises assertion failures when the builtins function contains the full + activated scope. try-catch's catch scope requires the upper scope full + activated, so JS code in the builtins cannot use the try-catch. + + This patch relaxes this restriction. When retrieving the captured + variables from the scope, just copy to the given vector. + + * parser/Parser.h: + (JSC::Scope::getCapturedVariables): + +2015-07-02 Filip Pizlo <fpizlo@apple.com> + + DFG and FTL should have an OSR exit fuzzer + https://bugs.webkit.org/show_bug.cgi?id=146562 + + Reviewed by Benjamin Poulain. + + Adds a basic OSR exit fuzzer to JSC. This isn't hooked into any test harnesses yet, but I + spot-checked it on v8-earley-boyer.js and so far found no bugs. I'd like to figure out how + to harness this after I land it. + + Since it's turned off by default, it should have no effect on behavior. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGOSRExitFuzz.cpp: Added. + (JSC::numberOfOSRExitFuzzChecks): + * dfg/DFGOSRExitFuzz.h: Added. + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitGetArgumentStart): + (JSC::DFG::SpeculativeJIT::emitOSRExitFuzzCheck): + (JSC::DFG::SpeculativeJIT::speculationCheck): + * dfg/DFGSpeculativeJIT.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::DFG::LowerDFGToLLVM::appendOSRExit): + * jsc.cpp: + (jscmain): + * runtime/Options.h: + * runtime/TestRunnerUtils.h: + +2015-07-02 Saam barati <saambarati1@gmail.com> + + Rename "Deconstruction" to "Destructuring" throughout JSC + https://bugs.webkit.org/show_bug.cgi?id=146100 + + Reviewed by Mark Lam. + + It is good to use the same naming conventions as the ES6 + spec because it is the de facto way of speaking about these + language features. This also has the benefit of improving JSC's + hackability because it improves code readability for newcomers + to JSC or newcomers to this part of the code base. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::initializeNextParameter): + (JSC::BytecodeGenerator::visibleNameForParameter): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::registerFor): + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::tryGetBoundLocal): + (JSC::ForInNode::emitLoopHeader): + (JSC::ForOfNode::emitBytecode): + (JSC::ClassExprNode::emitBytecode): + (JSC::DestructuringAssignmentNode::emitBytecode): + (JSC::DestructuringPatternNode::~DestructuringPatternNode): + (JSC::ArrayPatternNode::collectBoundIdentifiers): + (JSC::DeconstructingAssignmentNode::emitBytecode): Deleted. + (JSC::DeconstructionPatternNode::~DeconstructionPatternNode): Deleted. + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createElementList): + (JSC::ASTBuilder::createFormalParameterList): + (JSC::ASTBuilder::createClause): + (JSC::ASTBuilder::createClauseList): + (JSC::ASTBuilder::createForInLoop): + (JSC::ASTBuilder::createForOfLoop): + (JSC::ASTBuilder::isBindingNode): + (JSC::ASTBuilder::isResolve): + (JSC::ASTBuilder::createDestructuringAssignment): + (JSC::ASTBuilder::createArrayPattern): + (JSC::ASTBuilder::appendArrayPatternSkipEntry): + (JSC::ASTBuilder::appendArrayPatternEntry): + (JSC::ASTBuilder::appendArrayPatternRestEntry): + (JSC::ASTBuilder::createObjectPattern): + (JSC::ASTBuilder::appendObjectPatternEntry): + (JSC::ASTBuilder::createDeconstructingAssignment): Deleted. + * parser/NodeConstructors.h: + (JSC::TryNode::TryNode): + (JSC::ParameterNode::ParameterNode): + (JSC::ForOfNode::ForOfNode): + (JSC::DestructuringPatternNode::DestructuringPatternNode): + (JSC::ArrayPatternNode::ArrayPatternNode): + (JSC::ArrayPatternNode::create): + (JSC::ObjectPatternNode::ObjectPatternNode): + (JSC::BindingNode::create): + (JSC::BindingNode::BindingNode): + (JSC::DestructuringAssignmentNode::DestructuringAssignmentNode): + (JSC::DeconstructionPatternNode::DeconstructionPatternNode): Deleted. + (JSC::DeconstructingAssignmentNode::DeconstructingAssignmentNode): Deleted. + * parser/Nodes.cpp: + (JSC::FunctionParameters::create): + * parser/Nodes.h: + (JSC::ExpressionNode::isResolveNode): + (JSC::ExpressionNode::isBracketAccessorNode): + (JSC::ExpressionNode::isDotAccessorNode): + (JSC::ExpressionNode::isDestructuringNode): + (JSC::ExpressionNode::isFuncExprNode): + (JSC::ExpressionNode::isCommaNode): + (JSC::ExpressionNode::isSimpleArray): + (JSC::ParameterNode::pattern): + (JSC::ParameterNode::nextParam): + (JSC::FunctionParameters::size): + (JSC::FunctionParameters::at): + (JSC::FunctionParameters::patterns): + (JSC::DestructuringPatternNode::isBindingNode): + (JSC::DestructuringPatternNode::emitDirectBinding): + (JSC::ArrayPatternNode::appendIndex): + (JSC::ObjectPatternNode::appendEntry): + (JSC::BindingNode::boundProperty): + (JSC::DestructuringAssignmentNode::bindings): + (JSC::ExpressionNode::isDeconstructionNode): Deleted. + (JSC::DeconstructionPatternNode::isBindingNode): Deleted. + (JSC::DeconstructionPatternNode::emitDirectBinding): Deleted. + (JSC::DeconstructingAssignmentNode::bindings): Deleted. + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclaration): + (JSC::Parser<LexerType>::parseWhileStatement): + (JSC::Parser<LexerType>::parseVarDeclarationList): + (JSC::Parser<LexerType>::createBindingPattern): + (JSC::Parser<LexerType>::tryParseDestructuringPatternExpression): + (JSC::Parser<LexerType>::parseDestructuringPattern): + (JSC::Parser<LexerType>::parseDefaultValueForDestructuringPattern): + (JSC::Parser<LexerType>::parseForStatement): + (JSC::Parser<LexerType>::parseFormalParameters): + (JSC::Parser<LexerType>::parseFunctionParameters): + (JSC::Parser<LexerType>::parseAssignmentExpression): + (JSC::Parser<LexerType>::tryParseDeconstructionPatternExpression): Deleted. + (JSC::Parser<LexerType>::parseDeconstructionPattern): Deleted. + (JSC::Parser<LexerType>::parseDefaultValueForDeconstructionPattern): Deleted. + * parser/Parser.h: + (JSC::isEvalNode): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createPropertyList): + (JSC::SyntaxChecker::createElementList): + (JSC::SyntaxChecker::createFormalParameterList): + (JSC::SyntaxChecker::createClause): + (JSC::SyntaxChecker::createClauseList): + (JSC::SyntaxChecker::operatorStackPop): + * tests/stress/reserved-word-with-escape.js: + * tests/stress/rest-elements.js: + +2015-07-02 Mark Lam <mark.lam@apple.com> + + Build fix for Win EWS bot. + https://bugs.webkit.org/show_bug.cgi?id=146551 + + Not reviewed. + + * tools/JSDollarVMPrototype.cpp: + (JSC::functionCrash): + +2015-07-02 Dan Bernstein <mitz@apple.com> + + <rdar://problem/21429613> [iOS] Stop making symlinks from PrivateFrameworks to Frameworks + https://bugs.webkit.org/show_bug.cgi?id=146542 + + Reviewed by Sam Weinig. + + * JavaScriptCore.xcodeproj/project.pbxproj: Removed the build phase that makes the symlink. + +2015-07-01 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Aggregate profile call information on the backend to drastically reduce profile sizes + https://bugs.webkit.org/show_bug.cgi?id=146536 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Timeline.json: + Change a CPUProfile from sending a required "calls" param to sending a required + "callInfo" param which includes aggregated information about the calls. + +2015-06-30 Filip Pizlo <fpizlo@apple.com> + + DFG::freezeFragile should register the frozen value's structure + https://bugs.webkit.org/show_bug.cgi?id=136055 + rdar://problem/21042120 + + Reviewed by Mark Lam and Geoffrey Garen. + + This fixes weird concurrency bugs where the constant folding phase tries to convert + something to a constant but then crashes because the constant's structure wasn't + registered. The AI was registering the structure of any value it saw, but constant folding + wasn't - and that's fine so long as there ain't no concurrency. + + The best fix is to just make it impossible to introduce a constant into the IR without + registering its structure. That's what this change does. This is not only a great + concurrency fix - it also makes the compiler somewhat easier to hack on because it's one + less case of structure registering that you have to remember about. + + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::setOSREntryValue): No need to register. + (JSC::DFG::AbstractValue::set): We still call register, but just to get the watchpoint state. + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::freezeFragile): Register the structure. + * dfg/DFGStructureRegistrationPhase.cpp: + (JSC::DFG::StructureRegistrationPhase::run): Assert that these are all registered. + +2015-07-01 Matthew Mirman <mmirman@apple.com> + + Unreviewed, rolling out r185889 + https://bugs.webkit.org/show_bug.cgi?id=146528 + rdar://problem/21573959 + + Patch breaks chromeexperiments.com + + Reverted changeset: + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/InjectedScriptSource.js: + (.): + * runtime/JSBoundSlotBaseFunction.cpp: Removed. + * runtime/JSBoundSlotBaseFunction.h: Removed. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): Deleted. + (JSC::JSGlobalObject::visitChildren): Deleted. + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::boundSlotBaseFunctionStructure): Deleted. + * runtime/JSObject.cpp: + (JSC::JSObject::getOwnPropertyDescriptor): + (JSC::getBoundSlotBaseFunctionForGetterSetter): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): Deleted. + * runtime/VM.h: + +2015-07-01 Dean Jackson <dino@apple.com> + + Disable the experimental WebGL2 implementation + https://bugs.webkit.org/show_bug.cgi?id=146526 + <rdar://problem/21641235> + + Reviewed by Myles Maxfield. + + Add (and disable) an ENABLE_WEBGL2 flag. + + * Configurations/FeatureDefines.xcconfig: + +2015-07-01 Matthew Daiter <mdaiter@apple.com> + + Enable MEDIA_STREAM flag + https://bugs.webkit.org/show_bug.cgi?id=145947 + <rdar://problem/21365829> + + Reviewed by Eric Carlson. + + * Configurations/FeatureDefines.xcconfig: Added MEDIA_STREAM flag + +2015-06-30 Andy VanWagoner <thetalecrafter@gmail.com> + + Implement ECMAScript Internationalization API + https://bugs.webkit.org/show_bug.cgi?id=90906 + + Reviewed by Benjamin Poulain. + + * CMakeLists.txt: add IntlObject.cpp + * Configurations/FeatureDefines.xcconfig: add ENABLE_INTL flag + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: add IntlObject + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: add IntlObject + * JavaScriptCore.xcodeproj/project.pbxproj: add IntlObject + * runtime/CommonIdentifiers.h: add "Intl" name + * runtime/IntlObject.cpp: Added. + (JSC::IntlObject::IntlObject): + (JSC::IntlObject::create): + (JSC::IntlObject::finishCreation): + (JSC::IntlObject::createStructure): + * runtime/IntlObject.h: Added. + * runtime/JSGlobalObject.cpp: Add global Intl + (JSC::JSGlobalObject::init): + +2015-06-30 Basile Clement <basile_clement@apple.com> + + Allow object allocation sinking through GetScope, GetExecutable and SkipScope nodes + https://bugs.webkit.org/show_bug.cgi?id=146431 + + Reviewed by Filip Pizlo. + + * dfg/DFGNode.h: + (JSC::DFG::Node::isFunctionAllocation): + (JSC::DFG::Node::isPhantomFunctionAllocation): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPromoteHeapAccess.h: + (JSC::DFG::promoteHeapAccess): + +2015-06-30 Matt Baker <mattbaker@apple.com> + + Web Inspector: Reduce rendering frames "Other" time by instrumenting compositing + https://bugs.webkit.org/show_bug.cgi?id=146168 + + Reviewed by Brian Burg. + + * inspector/protocol/Timeline.json: + New timeline record type for compositing events. + +2015-06-29 Dean Jackson <dino@apple.com> + + Temporarily disable PICTURE_SIZES + https://bugs.webkit.org/show_bug.cgi?id=146435 + <rdar://problem/21087013> + + Reviewed by Tim Horton. + + Temporarily disable PICTURE_SIZES because it causes problems with out + of date <picture> polyfills. + + * Configurations/FeatureDefines.xcconfig: + +2015-06-29 Youenn Fablet <youenn.fablet@crf.canon.fr> + + Binding generator should allow using JSC::Value for "any" parameter in lieu of ScriptValue + https://bugs.webkit.org/show_bug.cgi?id=146403 + + Reviewed by Darin Adler. + + * bindings/ScriptValue.h: Added implicit conversion to JSC::JSValue. + +2015-06-28 Aleksandr Skachkov <gskachkov@gmail.com> + + [ES6] Implement ES6 arrow function syntax. No Line terminator between function parameters and => + https://bugs.webkit.org/show_bug.cgi?id=146394 + + Reviewed by Yusuke Suzuki. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): + +2015-06-27 Darin Adler <darin@apple.com> + + Make converting JSString to StringView idiomatically safe + https://bugs.webkit.org/show_bug.cgi?id=146387 + + Reviewed by Anders Carlsson. + + * jsc.cpp: + (functionPrint): Add explicit call to SafeView::get, needed since there + is no StringView temporary. + (functionDebug): Ditto. + + * runtime/ArrayPrototype.cpp: + (JSC::holesMustForwardToPrototype): Refactored into helper function. + (JSC::join): Refactored so that StringView is a function argument, making + the lifetime simpler. + (JSC::arrayProtoFuncJoin): Ditto. + (JSC::arrayProtoFuncReverse): Use new holesMustForwardToPrototype helper. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::encode): Add explicit call to SafeView::get. + + * runtime/JSString.h: Moved declarations of functions to the top of the + file instead of mixing them in with the function definitions. Changed + return type of the view function to return a JSString::SafeView so that + the JSString's lifetime will last as long as the StringView does in + typical coding idioms. + (JSC::JSString::getIndex): Use unsafeView so we can index into the + view; could also have used view.get but here in this class this seems fine. + (JSC::JSRopeString::unsafeView): Renamed existing view function to this. + (JSC::JSString::unsafeView): Ditto. + (JSC::JSString::SafeView::SafeView): Contains reference to an ExecState + and a JSString. The ExecState is needed to create the StringView, and the + JSString needs to be kept alive as long as the StringView is. + (JSC::JSString::SafeView::operator StringView): Call unsafeView. + (JSC::JSString::SafeView::get): Convenience for when we want to call + StringView member functions. + (JSC::JSString::view): Added. Returns a SafeView. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncIndexOf): Add explicit call to SafeView::get. + +2015-06-26 Csaba Osztrogonác <ossy@webkit.org> + + Remove ARMv7Assembler.cpp + https://bugs.webkit.org/show_bug.cgi?id=146340 + + Reviewed by Filip Pizlo. + + * CMakeLists.txt: + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/ARMv7Assembler.cpp: Removed. + +2015-06-26 Csaba Osztrogonác <ossy@webkit.org> + + Fix the !ENABLE(ES6_ARROWFUNCTION_SYNTAX) build after r185989 + https://bugs.webkit.org/show_bug.cgi?id=146344 + + Reviewed by Yusuke Suzuki. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseSourceElements): + +2015-06-26 Aleksandr Skachkov <gskachkov@gmail.com> + + [ES6] Implement ES6 arrow function syntax. Parser of arrow function with execution as common function. + https://bugs.webkit.org/show_bug.cgi?id=144955 + + Reviewed by Yusuke Suzuki. + + Added support of ES6 arrow function. Changes were made according to following spec http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax. Patch does not include any arrow function specific behavior e.g. lexical bind this, arguments and etc. + This patch implements the simplest cases of arrow function declaration: + parameters () => 10 + 20 + parameter x => x + 20 + parameters (x, y) => x + y + function with block x => { return x*10; } + + Not implemented: + bind of the this, arguments, super and etc. + exception in case of trying to use 'new' with arrow function + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createFunctionExpr): + (JSC::ASTBuilder::createArrowFunctionExpr): + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createFuncDeclStatement): + * parser/Lexer.cpp: + (JSC::Lexer<T>::setTokenPosition): + (JSC::Lexer<T>::lex): + * parser/Lexer.h: + (JSC::Lexer::lastTokenLocation): + (JSC::Lexer::setTerminator): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): + (JSC::Parser<LexerType>::parseSourceElements): + (JSC::Parser<LexerType>::parseArrowFunctionSingleExpressionBody): + (JSC::Parser<LexerType>::parseSwitchClauses): + (JSC::Parser<LexerType>::parseSwitchDefaultClause): + (JSC::Parser<LexerType>::parseBlockStatement): + (JSC::Parser<LexerType>::parseFunctionBody): + (JSC::stringForFunctionMode): + (JSC::Parser<LexerType>::parseFunctionParameters): + (JSC::Parser<LexerType>::parseFunctionInfo): + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseClass): + (JSC::Parser<LexerType>::parseAssignmentExpression): + (JSC::Parser<LexerType>::parsePropertyMethod): + (JSC::Parser<LexerType>::parseGetterSetter): + (JSC::Parser<LexerType>::parseArrowFunctionExpression): + * parser/Parser.h: + (JSC::Parser::locationBeforeLastToken): + (JSC::Parser::isEndOfArrowFunction): + (JSC::Parser::isArrowFunctionParamters): + (JSC::Parser::setEndOfStatement): + * parser/ParserFunctionInfo.h: + * parser/ParserTokens.h: + * parser/SourceCode.h: + (JSC::SourceCode::subArrowExpression): + * parser/SourceProviderCacheItem.h: + (JSC::SourceProviderCacheItem::endFunctionToken): + (JSC::SourceProviderCacheItem::SourceProviderCacheItem): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createArrowFunctionExpr): + (JSC::SyntaxChecker::setFunctionNameStart): + +2015-06-25 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Support rest element in destructuring assignments + https://bugs.webkit.org/show_bug.cgi?id=146206 + + Reviewed by Oliver Hunt. + + This patch enables rest element (...rest) in array binding patterns. + It generates array from the iterables. + In variable declarations and parameters, `[...identifier]` form is only allowed, + while expressions can take `[...[...rest]]` pattern. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::emitIteratorNext): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ArrayPatternNode::bindValue): + (JSC::ArrayPatternNode::toString): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::appendArrayPatternSkipEntry): + (JSC::ASTBuilder::appendArrayPatternEntry): + (JSC::ASTBuilder::appendArrayPatternRestEntry): + * parser/Nodes.h: + (JSC::ArrayPatternNode::appendIndex): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseDeconstructionPattern): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::operatorStackPop): + * tests/stress/rest-elements.js: Added. + (shouldBe): + (shouldThrow): + +2015-06-25 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r185956. + https://bugs.webkit.org/show_bug.cgi?id=146321 + + Causes massive crashes on test bots (Requested by bfulgham on + #webkit). + + Reverted changeset: + + "Enabling MEDIA_STREAM" + https://bugs.webkit.org/show_bug.cgi?id=145947 + http://trac.webkit.org/changeset/185956 + +2015-06-25 Michael Saboff <msaboff@apple.com> + + Minor fix to idx bounds check after 185954 + + Rubber Stamped by Ryosuke Niwa. + + Changed "idx > 1" to "idx > 0" in two places. + + * runtime/ExceptionHelpers.cpp: + (JSC::functionCallBase): + +2015-06-25 Keith Miller <keith_miller@apple.com> + + Address Sanitizer does not play well with memcpy in JSC::MachineThreads::tryCopyOtherThreadStack. + https://bugs.webkit.org/show_bug.cgi?id=146297 + + Reviewed by Filip Pizlo. + + Since we cannot blacklist the system memcpy we must use our own naive implementation, + copyMemory. This is not a significant performance loss as tryCopyOtherThreadStack is + only called as part of an O(heapsize) operation. As the heap is generally much larger + than the stack the performance hit is minimal. + + * heap/MachineStackMarker.cpp: + (JSC::copyMemory): + (JSC::MachineThreads::tryCopyOtherThreadStack): + (JSC::asanUnsafeMemcpy): Deleted. + +2015-06-25 Matthew Daiter <mdaiter@apple.com> + + Enabling MEDIA_STREAM + https://bugs.webkit.org/show_bug.cgi?id=145947 + <rdar://problem/21365829> + + Reviewed by Brent Fulgham. + + * Configurations/FeatureDefines.xcconfig: + +2015-06-25 Michael Saboff <msaboff@apple.com> + + REGRESSION (r181889): basspro.com hangs on load under JSC::ErrorInstance::finishCreation(JSC::ExecState*, JSC::VM&, WTF::String const&, bool) + 2801 (JavaScriptCore + 3560689) + https://bugs.webkit.org/show_bug.cgi?id=146298 + + Reviewed by Mark Lam. + + We were underflowing in ExceptionHelpers.cpp::functionCallBase() with a right to left + string index. Added checks that idx stays within the string. Also added a termination + condition when idx is 0. + + * runtime/ExceptionHelpers.cpp: + (JSC::functionCallBase): + +2015-06-24 Chris Dumez <cdumez@apple.com> + + Unreviewed, speculative build fix after r185942. + + Add missing include for StrongInlines.h. + + * runtime/ArrayPrototype.cpp: + +2015-06-24 Darin Adler <darin@apple.com> + + Optimize Array.join and Array.reverse for high speed array types + https://bugs.webkit.org/show_bug.cgi?id=146275 + + Reviewed by Mark Lam. + + This seems to yield another 17% speed improvement in the array + test from the Peacekeeper benchmark. + + * runtime/ArrayPrototype.cpp: + (JSC::isHole): Added. Helper to check for holes. + (JSC::containsHole): Ditto. + (JSC::arrayProtoFuncJoin): Added special cases for the various types + of arrays that could be in a butterfly. + (JSC::arrayProtoFuncReverse): Ditto. + + * runtime/JSStringJoiner.h: Made appendEmptyString public so we can + call it from the new parts of Array.join. + +2015-06-24 Filip Pizlo <fpizlo@apple.com> + + DFG::SpeculativeJIT shouldn't use filter==Contradiction when it meant isClear + https://bugs.webkit.org/show_bug.cgi?id=146291 + rdar://problem/21435366 + + Reviewed by Michael Saboff. + + The filter() method returns Contradiction only when a value *becomes* clear. This is + necessary for supporting the convention that non-JSValue nodes have a bottom proved + type. (We should fix that convention eventually, but for now let's just be consistent + about it.) + + * dfg/DFGFiltrationResult.h: Document the issue. + * dfg/DFGSpeculativeJIT32_64.cpp: Work around the issue. + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + * dfg/DFGSpeculativeJIT64.cpp: Work around the issue. + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + +2015-06-24 Michael Saboff <msaboff@apple.com> + + Crash on gog.com due to PolymorphicCallNode's having stale references to CallLinkInfo + https://bugs.webkit.org/show_bug.cgi?id=146285 + + Reviewed by Filip Pizlo. + + CallLinkInfo's contain a RefPtr to a PolymorphicCallStubRoutine, named stub, which contains + a collection of PolymorphicCallNode. Those PolymorphicCallNodes have a reference back to the + CallLinkInfo. When a CallLinkInfo replaces or clears "stub", the ref count of the + PolymorphicCallStubRoutine is decremented as expected, but since it inherits from + GCAwareJITStubRoutine, it isn't actually deleted until GC. In the mean time, the original + CallLinkInfo can go away. If PolymorphicCallNode::unlink() is called at that point, + it will try to unlink a now deleted CallLinkInfo and crash as a result. + + The fix is to clear the CallLinkInfo references from any PolymorphicCallNode objects when + when we set a new stub or clear an existing stub for a CallLinkInfo. This is done by + calling PolymorphicCallNode::clearCallNodesFor() on the old stub. + + The prior code would only call clearCallNodesFor() from the CallLinkInfo destructor. + This only took care of the last PolymorphicCallStubRoutine held in the CallLinkInfo. + Any prior PolymorphicCallStubRoutine would still have a, now bad, reference to the CallLinkInfo. + + In the process I refactored CallLinkInfo from a struct to a class with proper accessors and + made all the data elements private. + + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::clearStub): Updated to call PolymorphicCallStubRoutine::clearCallNodesFor() + to clear the back references to this CallLinkInfo. + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::~CallLinkInfo): Moved clearCallNodesFor() call to clearStub(). + (JSC::CallLinkInfo::setStub): Clear any prior stub before changing to the new stub. + +2015-06-24 Michael Saboff <msaboff@apple.com> + + Refactor CallLinkInfo from a struct to a class + https://bugs.webkit.org/show_bug.cgi?id=146292 + + Rubber stamped by Filip Pizlo. + + Refactored CallLinkInfo from a struct to a class with proper accessors and made all the + data elements private. + + Done in preparation for fixing https://bugs.webkit.org/show_bug.cgi?id=146285. + + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::clearStub): + (JSC::CallLinkInfo::unlink): + (JSC::CallLinkInfo::visitWeak): + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::callTypeFor): + (JSC::CallLinkInfo::CallLinkInfo): + (JSC::CallLinkInfo::~CallLinkInfo): + (JSC::CallLinkInfo::specializationKindFor): + (JSC::CallLinkInfo::specializationKind): + (JSC::CallLinkInfo::isLinked): + (JSC::CallLinkInfo::setUpCall): + (JSC::CallLinkInfo::setCallLocations): + (JSC::CallLinkInfo::setUpCallFromFTL): + (JSC::CallLinkInfo::callReturnLocation): + (JSC::CallLinkInfo::hotPathBegin): + (JSC::CallLinkInfo::hotPathOther): + (JSC::CallLinkInfo::setCallee): + (JSC::CallLinkInfo::clearCallee): + (JSC::CallLinkInfo::callee): + (JSC::CallLinkInfo::setLastSeenCallee): + (JSC::CallLinkInfo::clearLastSeenCallee): + (JSC::CallLinkInfo::lastSeenCallee): + (JSC::CallLinkInfo::haveLastSeenCallee): + (JSC::CallLinkInfo::setStub): + (JSC::CallLinkInfo::stub): + (JSC::CallLinkInfo::seenOnce): + (JSC::CallLinkInfo::clearSeen): + (JSC::CallLinkInfo::setSeen): + (JSC::CallLinkInfo::hasSeenClosure): + (JSC::CallLinkInfo::setHasSeenClosure): + (JSC::CallLinkInfo::clearedByGC): + (JSC::CallLinkInfo::setCallType): + (JSC::CallLinkInfo::callType): + (JSC::CallLinkInfo::addressOfMaxNumArguments): + (JSC::CallLinkInfo::maxNumArguments): + (JSC::CallLinkInfo::offsetOfSlowPathCount): + (JSC::CallLinkInfo::setCalleeGPR): + (JSC::CallLinkInfo::calleeGPR): + (JSC::CallLinkInfo::slowPathCount): + (JSC::CallLinkInfo::setCodeOrigin): + (JSC::CallLinkInfo::codeOrigin): + (JSC::getCallLinkInfoCodeOrigin): + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeFromCallLinkInfo): + (JSC::CallLinkStatus::computeDFGStatuses): + * bytecode/CallLinkStatus.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printCallOp): + (JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * ftl/FTLJSCallBase.cpp: + (JSC::FTL::JSCallBase::link): + * jit/AccessorCallJITStubRoutine.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileSetupVarargsFrame): + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileSetupVarargsFrame): + (JSC::JIT::compileOpCall): + * jit/JITOperations.cpp: + * jit/PolymorphicCallStubRoutine.cpp: + (JSC::PolymorphicCallNode::unlink): + (JSC::PolymorphicCallNode::clearCallLinkInfo): + * jit/PolymorphicCallStubRoutine.h: + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::linkSlowFor): + (JSC::linkFor): + (JSC::revertCall): + (JSC::unlinkFor): + (JSC::linkPolymorphicCall): + * jit/ThunkGenerators.cpp: + (JSC::virtualForThunkGenerator): + +2015-06-24 Doug Russell <d_russell@apple.com> + + Bug 146177 - AX: AXObjectCache should try to use an unignored accessibilityObject + when posting a selection notification when on the border between two accessibilityObjects + https://bugs.webkit.org/show_bug.cgi?id=146177 + + Add an adopt() function to simplify JSRetainPtr<JSStringRef> { Adopt, string } to adopt(string). + + Reviewed by Darin Adler. + + * API/JSRetainPtr.h: + (adopt): + +2015-06-24 Keith Miller <keith_miller@apple.com> + + Strict Equality on objects should only check that one of the two sides is an object. + https://bugs.webkit.org/show_bug.cgi?id=145992 + + This patch adds a new optimization for checking strict equality on objects. + If we speculate that a strict equality comparison has an object on one side + we only need to type check that side. Equality is then determined by a pointer + comparison between the two values (although in the 32-bit case we must also check + that the other side is a cell). Once LICM hoists type checks out of a loop we + can be cleverer about how we choose the operand we type check if both are + speculated to be objects. + + For testing I added the addressOf function, which returns the address + of a Cell to the runtime. + + Reviewed by Mark Lam. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStrictEq): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectStrictEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectStrictEquality): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectStrictEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectStrictEquality): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::DFG::LowerDFGToLLVM::compileCompareStrictEq): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionAddressOf): + * tests/stress/equality-type-checking.js: Added. + (Foo): + (checkStrictEq): + (checkStrictEqOther): + +2015-06-24 Mark Lam <mark.lam@apple.com> + + Fixed assertion in JSStringJoiner::join() (regression from r185899). + + Not reviewed. + + JSStringJoiner did not account for the case where the array being joined can + have null or undefined elements. As a result, its size may be less than + its initially reserved capacity (which was estimated based on the array length). + + * runtime/JSStringJoiner.cpp: + (JSC::JSStringJoiner::join): + +2015-06-24 Darin Adler <darin@apple.com> + + Fix Array.concat with RuntimeArray (regression from my last patch) + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncConcat): Use getLength instead of JSArray::length. + + * runtime/JSArray.cpp: + (JSC::JSArray::defineOwnProperty): Added comment about use of + JSArray::length here that is incorrect (in a really non-obvious way). + (JSC::JSArray::fillArgList): Ditto. + (JSC::JSArray::copyToArguments): Ditto. + + * runtime/JSArray.h: Added a comment explaining that it is not always + safe to use JSArray::length. + +2015-06-23 Mark Lam <mark.lam@apple.com> + + Gardening: Fixing 2 bad asserts from r185889. + https://bugs.webkit.org/show_bug.cgi?id=140575 + + Not reviewed. + + * runtime/JSBoundSlotBaseFunction.cpp: + (JSC::JSBoundSlotBaseFunction::finishCreation): + +2015-06-23 Dan Bernstein <mitz@apple.com> + + Fixed iOS production builds. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-06-22 Darin Adler <darin@apple.com> + + Make Array.join work directly on substrings without reifying them + https://bugs.webkit.org/show_bug.cgi?id=146191 + + Reviewed by Andreas Kling. + + Besides the Array.join change, this has other optimizations based on + profiling the Peacekeeper array benchmark. + + I measured a 14% speed improvement in the Peacekeeper array benchmark. + + Still a lot of low hanging fruit in that test because so many of functions + on the array prototype are not optimizing for simple cases. For example, + the reverse function does individual get and put calls even when the array + is entirely made up of integers in contiguous storage. + + * runtime/ArrayPrototype.cpp: + (JSC::getProperty): Use tryGetIndexQuickly first before getPropertySlot. + (JSC::argumentClampedIndexFromStartOrEnd): Marked inline. + (JSC::shift): Use the getProperty helper in this file instead of using + getPropertySlot. Use putByIndexInline instead of calling putByIndex directly. + In both cases this can yield a faster code path. + (JSC::unshift): Ditto. + (JSC::arrayProtoFuncToString): Updated to use the new JSStringJoiner + interface. Changed local variable name to thisArray since it's not a + JSObject*. Changed loop index to i instead of k. + (JSC::arrayProtoFuncToLocaleString): Updated to use the new JSStringJoiner + interface. Renamed thisObj to thisObject. Added a missing exception check + after the toLocaleString function is called, but before toString is called + the result of that function. + (JSC::arrayProtoFuncJoin): Updated to use the new JSStringJointer interface. + Added a missing exception check after calling toString on the separator + but before calling get to get the first element in the array-like object + being joined. Changed loop index to i instead of k. Added missing exception + check after calling toString on each string from the array before calling + get for the next element. + (JSC::arrayProtoFuncConcat): Use JSArray::length instead of using the + getLength function. + (JSC::arrayProtoFuncReverse): Ditto. Also use putByIndexInline. + (JSC::arrayProtoFuncShift): Ditto. + (JSC::arrayProtoFuncSplice): Use getIndex instead of get, which includes some + additional optimizations. + (JSC::getOrHole): Deleted. Unused function. + (JSC::arrayProtoFuncUnShift): Use putByIndexInline. + + * runtime/ExceptionHelpers.cpp: + (JSC::errorDescriptionForValue): Removed the duplicate copy of the the logic + from JSValue::toString. + + * runtime/JSCJSValue.cpp: + (JSC::JSValue::toStringSlowCase): Improved the performance when converting a + small integer to a single character string. + (JSC::JSValue::toWTFStringSlowCase): Moved the contents of the + inlineJSValueNotStringtoString function here. + * runtime/JSCJSValue.h: Removed no longer used toWTFStringInline and fixed + a comment with a typo. + + * runtime/JSObject.h: + (JSC::JSObject::putByIndexInline): Marked ALWAYS_INLINE because this was not + getting inlined at some call sites. + (JSC::JSObject::indexingData): Deleted. Unused function. + (JSC::JSObject::currentIndexingData): Deleted. Unused function. + (JSC::JSObject::getHolyIndexQuickly): Deleted. Unused function. + (JSC::JSObject::relevantLength): Deleted. Unused function. + (JSC::JSObject::currentRelevantLength): Deleted. Unused function. + + * runtime/JSString.h: Added the StringViewWithUnderlyingString struct and + the viewWithUnderlyingString function. Removed the inlineJSValueNotStringtoString + and toWTFStringInline functions. + + * runtime/JSStringJoiner.cpp: + (JSC::appendStringToData): Changed this to be a template instead of writing + it out, since StringView::getCharactersWithUpconvert does almsot exactly what + this function was trying to do. + (JSC::joinStrings): Rewrote this to use StringView. + (JSC::JSStringJoiner::joinedLength): Added. Factored out from the join function. + (JSC::JSStringJoiner::join): Rewrote to make it a bit simpler. Added an assertion + that we entirely filled capacity, since we are now reserving capacity and using + uncheckedAppend. Use String instead of RefPtr<StringImpl> because there was no + particular value to using the impl directly. + + * runtime/JSStringJoiner.h: Changed the interface to the class to use StringView. + Also changed this class so it now has the responsibility to convert each JSValue + into a string. This let us share more code between toString and join, and also + lets us use the new viewWithUnderlyingString function, which could be confusing at + all the call sites, but is easier to understand here. + +2015-06-23 Matthew Mirman <mmirman@apple.com> + + Completes native binding descriptors with native getters and potentially setters. + https://bugs.webkit.org/show_bug.cgi?id=140575 + rdar://problem/19506502 + + Reviewed by Mark Lam. + + * CMakeLists.txt: Added JSBoundSlotBaseFunction.cpp + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/InjectedScriptSource.js: Added case for descriptor having a native getter. + * runtime/JSBoundSlotBaseFunction.cpp: Added. + (JSC::boundSlotBaseFunctionCall): + (JSC::JSBoundSlotBaseFunction::JSBoundSlotBaseFunction): + Necessary wrapper for custom getters and setters as objects. + (JSC::JSBoundSlotBaseFunction::create): + (JSC::JSBoundSlotBaseFunction::visitChildren): + (JSC::JSBoundSlotBaseFunction::finishCreation): + * runtime/JSBoundSlotBaseFunction.h: Added. + (JSC::JSBoundSlotBaseFunction::createStructure): + (JSC::JSBoundSlotBaseFunction::boundSlotBase): + (JSC::JSBoundSlotBaseFunction::customGetterSetter): + (JSC::JSBoundSlotBaseFunction::isGetter): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): Added a globally initialized structure for JSBoundSlotBaseFunction + (JSC::JSGlobalObject::visitChildren): visits that structure + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::boundSlotBaseFunctionStructure): added a getter for that structure + * runtime/JSObject.cpp: + (JSC::JSObject::getOwnPropertyDescriptor): extends the case for CustomGetterSetter to + actually include GetterSetter as a JSBoundSlotBaseFunction + * runtime/VM.cpp: Added initializer for customGetterSetterFunctionMap + * runtime/VM.h: Added cache for JSBoundSlotBaseFunction + +2015-06-22 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Allow trailing comma in ArrayBindingPattern and ObjectBindingPattern + https://bugs.webkit.org/show_bug.cgi?id=146192 + + Reviewed by Darin Adler. + + According to the ES6 spec, trailing comma in ArrayBindingPattern and ObjectBindingPattern is allowed. + And empty ArrayBindingPattern and ObjectBindingPattern is also allowed. + + This patch allows trailing comma and empty binding patterns. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ArrayPatternNode::bindValue): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseDeconstructionPattern): + * tests/stress/trailing-comma-in-patterns.js: Added. + (shouldBe): + (iterator): + +2015-06-20 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Destructuring assignment need to accept iterables + https://bugs.webkit.org/show_bug.cgi?id=144111 + + Reviewed by Darin Adler. + + This patch makes that destructuring assignments to array binding patterns accept iterables. + Previously, it just access the indexed properties. + After this patch, it iterates the given value by using ES6 iterator protocol. + + The iteration becomes different from the for-of case. + 1. Since there's no break/continue case, finally scope is not necessary. + 2. When the error is raised, the close status of the iterator becomes true. So IteratorClose is not called for that. + 3. Since the array binding patterns requires a limited count of iterations (if there is no rest(...rest) case), IteratorClose is called when the iteration does not consume the all values of the iterator. + 4. Since the array binding patterns requires a specified count of iterations, iterator's next call is skipped when iterator becomes closed. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitIteratorClose): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ArrayPatternNode::bindValue): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::finishArrayPattern): + * parser/Nodes.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseDeconstructionPattern): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::operatorStackPop): + * tests/stress/destructuring-assignment-accepts-iterables.js: Added. + (shouldBe): + (shouldThrow): + (.set shouldThrow): + +2015-06-19 Devin Rousso <drousso@apple.com> + + Web Inspector: Highlight currently edited CSS selector + https://bugs.webkit.org/show_bug.cgi?id=145658 + + Reviewed by Joseph Pecoraro. + + * inspector/protocol/DOM.json: Added highlightSelector to show highlight over multiple nodes. + +2015-06-19 Mark Lam <mark.lam@apple.com> + + Gardening: fix build for EWS bots. + + Not reviewed. + + * runtime/JSArray.cpp: + (JSC::JSArray::setLengthWithArrayStorage): + +2015-06-19 Michael Saboff <msaboff@apple.com> + + Crash in com.apple.WebKit.WebContent at com.apple.JavaScriptCore: JSC::FTL::fixFunctionBasedOnStackMaps + 17225 + https://bugs.webkit.org/show_bug.cgi?id=146133 + + Reviewed by Geoffrey Garen. + + When generating code to put in inline caching areas, if there isn't enough space, + then create and link to an out of line area. We connect the inline code to this + out of line code area by planting a jump from the inline area to the out of line + code and appending a jump at the end of the out of line code bck to the instruction + following the inline area. We fill the unused inline area with nops, primarily to + ensure the disassembler doesn't get confused. + + * ftl/FTLCompile.cpp: + (generateInlineIfPossibleOutOfLineIfNot): New function that determines if there is enough space + in the inline code area for the code to link. If so, it links inline, otherwise it links the + code out of line and plants appropriate jumps to/from the out of line code. + (generateICFastPath): + (generateCheckInICFastPath): + (fixFunctionBasedOnStackMaps): + Use generateInlineIfPossibleOutOfLineIfNot() to link code intended for inline cache space. + + * ftl/FTLJITFinalizer.cpp: + (JSC::FTL::JITFinalizer::finalizeFunction): + * ftl/FTLJITFinalizer.h: + (JSC::FTL::OutOfLineCodeInfo::OutOfLineCodeInfo): + Added code to finalize any out of line LinkBuffer created by generateInlineIfPossibleOutOfLineIfNot(). + +2015-06-19 Geoffrey Garen <ggaren@apple.com> + + WebKit crash while loading nytimes at JavaScriptCore: JSC::ExecutableAllocator::allocate + 276 + https://bugs.webkit.org/show_bug.cgi?id=146163 + <rdar://problem/20392986> + + Reviewed by Michael Saboff. + + There's no good way to test this in our test harness because we don't + have a way to simulate executable memory pressure, and doing so would + cause the cases that still use JITCompilationMustSucceed to crash. + + Instead, I tested by manually forcing all regexp JIT compilation to + fail and running the JavaScriptCore tests. + + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::compile): Allow compilation to fail. We can + fall back to the regexp interpreter if we need to. + +2015-06-19 Mark Lam <mark.lam@apple.com> + + Employ explicit operator bool() instead of using the UnspecifiedBoolType workaround. + https://bugs.webkit.org/show_bug.cgi?id=146154 + + Reviewed by Darin Adler. + + * assembler/MacroAssemblerCodeRef.h: + (JSC::MacroAssemblerCodePtr::dataLocation): + (JSC::MacroAssemblerCodePtr::operator bool): + (JSC::MacroAssemblerCodePtr::operator==): + (JSC::MacroAssemblerCodeRef::tryToDisassemble): + (JSC::MacroAssemblerCodeRef::operator bool): + (JSC::MacroAssemblerCodeRef::dump): + (JSC::MacroAssemblerCodePtr::operator UnspecifiedBoolType*): Deleted. + (JSC::MacroAssemblerCodeRef::operator UnspecifiedBoolType*): Deleted. + + * bytecode/CodeOrigin.cpp: + (JSC::CodeOrigin::isApproximatelyEqualTo): + - Fixed a bug here where we were expecting to compare Executable pointers, but + ended up comparing a (UnspecifiedBoolType*)1 with another + (UnspecifiedBoolType*)1. + + * bytecode/LLIntCallLinkInfo.h: + (JSC::LLIntCallLinkInfo::~LLIntCallLinkInfo): + (JSC::LLIntCallLinkInfo::isLinked): + (JSC::LLIntCallLinkInfo::unlink): + * dfg/DFGBlockWorklist.h: + (JSC::DFG::BlockWith::BlockWith): + (JSC::DFG::BlockWith::operator bool): + (JSC::DFG::BlockWithOrder::BlockWithOrder): + (JSC::DFG::BlockWithOrder::operator bool): + (JSC::DFG::BlockWith::operator UnspecifiedBoolType*): Deleted. + (JSC::DFG::BlockWithOrder::operator UnspecifiedBoolType*): Deleted. + * dfg/DFGIntegerRangeOptimizationPhase.cpp: + * dfg/DFGLazyNode.h: + (JSC::DFG::LazyNode::operator!): + (JSC::DFG::LazyNode::operator bool): + (JSC::DFG::LazyNode::operator UnspecifiedBoolType*): Deleted. + * heap/CopyWriteBarrier.h: + (JSC::CopyWriteBarrier::operator!): + (JSC::CopyWriteBarrier::operator bool): + (JSC::CopyWriteBarrier::get): + (JSC::CopyWriteBarrier::operator UnspecifiedBoolType*): Deleted. + * heap/Handle.h: + (JSC::HandleBase::operator!): + (JSC::HandleBase::operator bool): + (JSC::HandleBase::slot): + (JSC::HandleBase::operator UnspecifiedBoolType*): Deleted. + * heap/Strong.h: + (JSC::Strong::operator!): + (JSC::Strong::operator bool): + (JSC::Strong::swap): + (JSC::Strong::operator UnspecifiedBoolType*): Deleted. + * jit/JITWriteBarrier.h: + (JSC::JITWriteBarrierBase::operator bool): + (JSC::JITWriteBarrierBase::operator!): + (JSC::JITWriteBarrierBase::setFlagOnBarrier): + (JSC::JITWriteBarrierBase::operator UnspecifiedBoolType*): Deleted. + * runtime/JSArray.cpp: + (JSC::JSArray::setLengthWithArrayStorage): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::JSValue): + (JSC::JSValue::operator bool): + (JSC::JSValue::operator==): + (JSC::JSValue::operator UnspecifiedBoolType*): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::hasSparseMap): + * runtime/PropertyDescriptor.h: + (JSC::PropertyDescriptor::writablePresent): + (JSC::PropertyDescriptor::enumerablePresent): + (JSC::PropertyDescriptor::configurablePresent): + (JSC::PropertyDescriptor::setterPresent): + (JSC::PropertyDescriptor::getterPresent): + * runtime/WriteBarrier.h: + (JSC::WriteBarrierBase::slot): + (JSC::WriteBarrierBase::operator bool): + (JSC::WriteBarrierBase::operator!): + (JSC::WriteBarrierBase<Unknown>::tagPointer): + (JSC::WriteBarrierBase<Unknown>::payloadPointer): + (JSC::WriteBarrierBase<Unknown>::operator bool): + (JSC::WriteBarrierBase<Unknown>::operator!): + (JSC::WriteBarrierBase::operator UnspecifiedBoolType*): Deleted. + (JSC::WriteBarrierBase<Unknown>::operator UnspecifiedBoolType*): Deleted. + +2015-06-19 Anders Carlsson <andersca@apple.com> + + Add a JSC symlink in /System/Library/PrivateFrameworks + https://bugs.webkit.org/show_bug.cgi?id=146158 + rdar://problem/21465968 + + Reviewed by Dan Bernstein. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-06-19 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Avoid getOwnPropertyNames/Symbols on very large lists + https://bugs.webkit.org/show_bug.cgi?id=146141 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.prototype._propertyDescriptors): + Avoid calling getOwnPropertyNames/Symbols on very large lists. Instead + just generate property descriptors for the first 100 indexes. Note + this would behave poorly for sparse arrays with a length > 100, but + general support for lists with more than 100 elements is poor. See: + <https://webkit.org/b/143589> Web Inspector: Better handling for large collections in Object Trees + +2015-06-18 Yusuke Suzuki <utatane.tea@gmail.com> + + [DFG] Avoid OSR exit in the middle of string concatenation + https://bugs.webkit.org/show_bug.cgi?id=145820 + + Reviewed by Filip Pizlo. + + DFG attempt to compile ValueAdd with String type into MakeRope(left, ToString(ToPrimitive(right))). + + So when right is speculated as SpecObject, ToPrimitive(SpecObject) is speculated as SpecString. + It leads ToString to become Identity with a speculated type check. + + However, ToPrimitive and ToString are originated from the same bytecode. And ToPrimitive may have + an observable side effect when the given parameter is an object (calling object.{toString,valueOf}). + + So when object.toString() returns a number (it is allowed in the ES spec), ToPrimitive performs + observable `object.toString()` calling. But ToString is converted into a speculated type check for + SpecString and it raises OSR exit. And we exit to the original ValueAdd's bytecode position and + it redundantly performs an observable ToPrimitive execution. + + To fix this, this patch avoid fixing up for newly introduced ToString node. + Since fix up phase is not iterated repeatedly, by avoiding fixing up when generating the node, + we can avoid conversion from ToString to Check. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::attemptToMakeFastStringAdd): + * tests/stress/toprimitive-speculated-types.js: Added. + (shouldBe): + (raw): + (Counter): + +2015-06-18 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: improve generated types for objects passed to backend commands + https://bugs.webkit.org/show_bug.cgi?id=146091 + + Reviewed by Joseph Pecoraro. + + The main change is that objects passed in will have a type like const T& or const T*, + rather than const RefPtr<T>&&. These protocol objects are owned by the generated dispatcher + methods and only exist to pass data to backend command implementations. So, there is no + reason for callees to add a reference or take ownership of these inputs. + + Some small improvements were made in the code generator to standardize how these + expressions are generated for parameters. Optional in parameters are now prefixed with + 'opt_in_' to make the generated method signatures and implementations clearer. + + * inspector/InspectorValues.cpp: + (Inspector::InspectorArrayBase::get): Add const qualifier. + * inspector/InspectorValues.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::parseLocation): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::continueToLocation): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::callFunctionOn): + (Inspector::InspectorRuntimeAgent::saveResult): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * inspector/agents/InspectorRuntimeAgent.h: + + * inspector/scripts/codegen/cpp_generator.py: Always generate PrimitiveType('array'). + (CppGenerator.cpp_type_for_unchecked_formal_in_parameter): Alter the type signature + for an unchecked input to use pointers or references. + + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py: + (CppBackendDispatcherHeaderGenerator._generate_handler_declaration_for_command): + (CppBackendDispatcherHeaderGenerator._generate_async_handler_declaration_for_command): + Local variables for optional parameters now have the 'opt_' prefix. + + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py: + (CppBackendDispatcherImplementationGenerator._generate_async_dispatcher_class_for_domain): + (CppBackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + Local variables for optional parameters now have the 'opt_' prefix. + Split parameterName and parameterKey into two separate template variables to avoid mixups. + + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + +2015-06-18 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed. Rollout r185670 as it caused some tests to be flakey. + + * debugger/Debugger.cpp: + +2015-06-17 Alex Christensen <achristensen@webkit.org> + + [Content Extensions] Log blocked loads to the WebInspector console + https://bugs.webkit.org/show_bug.cgi?id=146089 + + Reviewed by Joseph Pecoraro. + + * inspector/ConsoleMessage.cpp: + (Inspector::messageSourceValue): + * inspector/protocol/Console.json: + * runtime/ConsoleTypes.h: + Add content blocker message source. + +2015-06-18 Saam Barati <saambarati1@gmail.com> + + [ES6] support default values in deconstruction parameter nodes + https://bugs.webkit.org/show_bug.cgi?id=142679 + + Reviewed by Darin Adler. + + ES6 destructuring allows destructuring properties to assign + default values. A link to the spec: + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-destructuring-binding-patterns + + This patch implements default values for all places where deconstruction + is allowed besides function parameters. This is because function + parameters are parsed in a separate parser arena than the function + body itself and ExpresionNode's which are default values for + deconstruction parameters will be deallocated by the time we parse the body + of the function. I have opened a bug to address this problem: + https://bugs.webkit.org/show_bug.cgi?id=145995 + + * bytecompiler/NodesCodegen.cpp: + (JSC::DeconstructionPatternNode::~DeconstructionPatternNode): + (JSC::assignDefaultValueIfUndefined): + (JSC::ArrayPatternNode::bindValue): + (JSC::ArrayPatternNode::emitDirectBinding): + (JSC::ArrayPatternNode::toString): + (JSC::ArrayPatternNode::collectBoundIdentifiers): + (JSC::ObjectPatternNode::bindValue): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::appendArrayPatternSkipEntry): + (JSC::ASTBuilder::appendArrayPatternEntry): + (JSC::ASTBuilder::createObjectPattern): + (JSC::ASTBuilder::appendObjectPatternEntry): + (JSC::ASTBuilder::createBindingLocation): + * parser/Nodes.h: + (JSC::ArrayPatternNode::appendIndex): + (JSC::ObjectPatternNode::appendEntry): + (JSC::ObjectPatternNode::Entry::Entry): Deleted. + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseDeconstructionPattern): + (JSC::Parser<LexerType>::parseDefaultValueForDeconstructionPattern): + (JSC::Parser<LexerType>::parseConstDeclarationList): + * parser/Parser.h: + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::operatorStackPop): + +2015-06-17 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Do not show JavaScriptCore builtins in inspector + https://bugs.webkit.org/show_bug.cgi?id=146049 + + Reviewed by Timothy Hatcher. + + * debugger/Debugger.cpp: + +2015-06-17 Andreas Kling <akling@apple.com> + + [JSC] jsSubstring() should have a fast path for 0..baseLength "substrings." + <https://webkit.org/b/146051> + + Reviewed by Anders Carlsson. + + If asked to make a substring that actually spans the entire base string, + have jsSubstring() just return the base instead of allocating a new JSString. + + 3% speed-up on Octane/regexp. + + * runtime/JSString.h: + (JSC::jsSubstring): + +2015-06-16 Alex Christensen <achristensen@webkit.org> + + 32-bit build fix after r185640. + + * dfg/DFGIntegerRangeOptimizationPhase.cpp: + Explicitly cast clamped int64_t to an int. + +2015-06-09 Filip Pizlo <fpizlo@apple.com> + + FTL should eliminate array bounds checks in loops + https://bugs.webkit.org/show_bug.cgi?id=145768 + + Reviewed by Benjamin Poulain. + + This adds a phase that does forward propagation of integer inequalities. This allows us + to do the algebraic reasoning we need to eliminate array bounds checks in loops. It + also eliminates overflow checks on ArithAdd with a constant. + + The phase's analysis produces results that are powerful enough to do speculative bounds + check hoisting, but this phase currently only does elimination. We can implement + hoisting later. + + On programs that just loop over an array like: + + for (var i = 0; i < array.length; ++i) + thingy += array[i] + + This change is a 60% speed-up. + + This is also a ~3% speed-up on Kraken, and it shows various speed-ups on individual + tests in Octane. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGIntegerRangeOptimizationPhase.cpp: Added. + (JSC::DFG::performIntegerRangeOptimization): + * dfg/DFGIntegerRangeOptimizationPhase.h: Added. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * tests/stress/add-overflows-after-not-equal.js: Added. + * tests/stress/no-abc-skippy-loop.js: Added. + * tests/stress/no-abc-skippy-paired-loop.js: Added. + * tests/stress/sub-overflows-after-not-equal.js: Added. + +2015-06-16 Andreas Kling <akling@apple.com> + + Remove unused template parameter InlineCapacity from SegmentedVector. + <https://webkit.org/b/146044> + + Reviewed by Anders Carlsson. + + * bytecode/ArrayProfile.h: + * dfg/DFGCommonData.h: + +2015-06-16 Michael Saboff <msaboff@apple.com> + + Inlining in the DFG trashes ByteCodeParser::m_currentInstruction for the calling function + https://bugs.webkit.org/show_bug.cgi?id=146029 + + Reviewed by Benjamin Poulain. + + Save and restore m_currentInstruction around call to ByteCodeParser::inlineCall() as it will + use m_currentInstruction during its own parsing. This happens because inlineCall() parses the + inlined callee's bytecodes by calling parseCodeBlock() which calls parseBlock() on each block. + It is in parseBlock() that we set m_currentInstruction to an instruction before we parse it. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::attemptToInlineCall): + (JSC::DFG::ByteCodeParser::parseBlock): Added an ASSERT to catch this issue. + +2015-06-16 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, roll out unintended JSC change from https://trac.webkit.org/changeset/185425. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::hasExitSite): + (JSC::CodeBlock::exitProfile): + (JSC::CodeBlock::numberOfExitSites): Deleted. + * bytecode/DFGExitProfile.cpp: + (JSC::DFG::ExitProfile::add): + * bytecode/DFGExitProfile.h: + (JSC::DFG::ExitProfile::hasExitSite): + (JSC::DFG::ExitProfile::size): Deleted. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::inliningCost): + * runtime/Options.h: + +2015-06-16 Mark Lam <mark.lam@apple.com> + + Use NakedPtr<Exception>& to return exception results. + https://bugs.webkit.org/show_bug.cgi?id=145870 + + Reviewed by Anders Carlsson and Filip Pizlo. + + Before r185259, calls into the VM takes a JSValue* exception result argument for + returning any uncaught exception that may have been thrown while executing JS code. + As a result, clients of the VM functions will declare a local JSValue exception + result which is automatically initialized to a null value (i.e. the empty value, + not the JS null value). + + With r185259, the VM functions were changed to take an Exception*& exception result + instead, and the VM functions are responsible for initializing the exception result + to null if no exception is thrown. + + This introduces 2 issues: + + 1. the VM functions are vulnerable to modifications that may add early returns + before the exception result is nullified. This can result in the exception + result being used without initialization. + + 2. Previously, a client could technically use the same exception result for more + than one calls into the VM functions. If an earlier call sets it to a thrown + value, the thrown value will stick unless a subsequent call throws a different + exception. + + With the new Exception*& exception result, the VM functions will always clear + the exception result before proceeding. As a result, the client's exception + result will be null after the second call even though the first call saw an + exception thrown. This is a change in the expected behavior. + + To fix these issues, we'll introduce a NakedPtr smart pointer whose sole purpose + is to guarantee that the pointer is initialized. The VM functions will now take + a NakedPtr<Exception>& instead of the Exception*&. This ensures that the + exception result is initialized. + + The VM functions be also reverted to only set the exception result if a new + exception is thrown. + + * API/JSBase.cpp: + (JSEvaluateScript): + * API/JSScriptRef.cpp: + * bindings/ScriptFunctionCall.cpp: + (Deprecated::ScriptFunctionCall::call): + * bindings/ScriptFunctionCall.h: + * debugger/Debugger.cpp: + (JSC::Debugger::hasBreakpoint): + * debugger/Debugger.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::thisValue): + (JSC::DebuggerCallFrame::evaluate): + * debugger/DebuggerCallFrame.h: + (JSC::DebuggerCallFrame::isValid): + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::createInjectedScript): + * inspector/InspectorEnvironment.h: + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::evaluate): + * inspector/JavaScriptCallFrame.h: + (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): + (Inspector::JavaScriptCallFrame::thisValue): + (Inspector::JavaScriptCallFrame::evaluate): + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::evaluateBreakpointAction): + * jsc.cpp: + (functionRun): + (functionLoad): + (runWithScripts): + (runInteractive): + * runtime/CallData.cpp: + (JSC::call): + * runtime/CallData.h: + * runtime/Completion.cpp: + (JSC::checkSyntax): + (JSC::evaluate): + * runtime/Completion.h: + (JSC::evaluate): + +2015-06-15 Filip Pizlo <fpizlo@apple.com> + + FTL boolify() UntypedUse is wrong in the masquerades-as-undefined case + https://bugs.webkit.org/show_bug.cgi?id=146002 + + Reviewed by Darin Adler. + + * ftl/FTLLowerDFGToLLVM.cpp: Put this in an anonymous namespace. We should have done that all along. It makes it easier to add debug code. + (JSC::FTL::DFG::LowerDFGToLLVM::boolify): Fix the bug. + * tests/stress/logical-not-masquerades.js: Added. This test creates a masquerader so that the watchpoint is invalid. Previously this would fail for the normal object cases. + (foo): + +2015-06-16 Andreas Kling <akling@apple.com> + + [JSC] Pre-bake final Structure for RegExp matches arrays. + <https://webkit.org/b/146006> + + Reviewed by Darin Adler. + + Since we always add the "index" and "input" fields to RegExp matches arrays, + cache a finished structure on the global object so we can create these arrays without + starting from scratch with a bare array every time. + + 10% progression on Octane/regexp (on my MBP.) + + * runtime/JSArray.h: + (JSC::JSArray::create): + (JSC::JSArray::tryCreateUninitialized): + (JSC::JSArray::createWithButterfly): Factored out JSArray construction into a helper + so we can call this from RegExpMatchesArray.cpp. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::regExpMatchesArrayStructure): Add a cached Structure for RegExp + subpattern matches arrays. + + * runtime/JSObject.h: + (JSC::JSNonFinalObject::finishCreation): Tweak assertion that used to check that + JSNonFinalObjects always start out with zero capacity. Since RegExp matches arrays now + start out with capacity for 2 properties, that won't work. Change it to check that we + don't have inline storage instead, since that should only be used by final objects. + + * runtime/RegExpMatchesArray.h: + * runtime/RegExpMatchesArray.cpp: + (JSC::tryCreateUninitializedRegExpMatchesArray): Helper to construct a JSArray with + the cached Structure and a Butterfly with 2 slots of property storage. + + (JSC::createRegExpMatchesArray): + (JSC::createRegExpMatchesArrayStructure): Creates the array Structure that gets cached + by the JSGlobalObject. + +2015-06-16 Saam Barati <saambarati1@gmail.com> + + LLInt's code path for get_from_scope with case GlobalVarWithVarInjectionChecks has dead code + https://bugs.webkit.org/show_bug.cgi?id=144268 + + Reviewed by Darin Adler. + + The call to loadVariable(.) both for 32bit and 64bit is unnecessary. + It grabs a value that is immediately overwritten by a call to getGlobalVar(). + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2015-06-14 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Introduce %IteratorPrototype% and drop all XXXIteratorConstructor + https://bugs.webkit.org/show_bug.cgi?id=145963 + + Reviewed by Darin Adler. + + ES6 iterators inherit %IteratorPrototype%. + And these prototype objects of derived iterators don't have @@iterator methods. + Instead they use the %IteratorPrototype%[@@iterator] method. + + To encourage inlining in for-of statement, we define this method in JS builtins. + + And these iterator prototype objects don't have any constructor function. + This patch drops them (like StringIteratorConstructor). + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/Iterator.prototype.js: Renamed from Source/JavaScriptCore/runtime/StringIteratorConstructor.cpp. + (SymbolIterator): + * runtime/ArrayIteratorConstructor.cpp: + (JSC::ArrayIteratorConstructor::finishCreation): Deleted. + * runtime/ArrayIteratorConstructor.h: Removed. + (JSC::ArrayIteratorConstructor::create): Deleted. + (JSC::ArrayIteratorConstructor::createStructure): Deleted. + (JSC::ArrayIteratorConstructor::ArrayIteratorConstructor): Deleted. + * runtime/ArrayIteratorPrototype.cpp: + (JSC::ArrayIteratorPrototype::finishCreation): + (JSC::arrayIteratorProtoFuncIterator): Deleted. + * runtime/IteratorPrototype.cpp: Renamed from Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp. + (JSC::IteratorPrototype::finishCreation): + * runtime/IteratorPrototype.h: Renamed from Source/JavaScriptCore/runtime/SetIteratorConstructor.h. + (JSC::IteratorPrototype::create): + (JSC::IteratorPrototype::createStructure): + (JSC::IteratorPrototype::IteratorPrototype): + * runtime/JSFunction.cpp: + (JSC::JSFunction::createBuiltinFunction): + * runtime/JSFunction.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::iteratorPrototype): + * runtime/MapIteratorConstructor.cpp: Removed. + (JSC::MapIteratorConstructor::finishCreation): Deleted. + * runtime/MapIteratorConstructor.h: Removed. + (JSC::MapIteratorConstructor::create): Deleted. + (JSC::MapIteratorConstructor::createStructure): Deleted. + (JSC::MapIteratorConstructor::MapIteratorConstructor): Deleted. + * runtime/MapIteratorPrototype.cpp: + (JSC::MapIteratorPrototype::finishCreation): Deleted. + (JSC::MapIteratorPrototypeFuncIterator): Deleted. + * runtime/SetIteratorConstructor.cpp: Removed. + (JSC::SetIteratorConstructor::finishCreation): Deleted. + * runtime/SetIteratorConstructor.h: + (JSC::SetIteratorConstructor::create): Deleted. + (JSC::SetIteratorConstructor::createStructure): Deleted. + (JSC::SetIteratorConstructor::SetIteratorConstructor): Deleted. + * runtime/SetIteratorPrototype.cpp: + (JSC::SetIteratorPrototype::finishCreation): Deleted. + (JSC::SetIteratorPrototypeFuncIterator): Deleted. + * runtime/StringIteratorConstructor.cpp: + (JSC::StringIteratorConstructor::finishCreation): Deleted. + * runtime/StringIteratorConstructor.h: Removed. + (JSC::StringIteratorConstructor::create): Deleted. + (JSC::StringIteratorConstructor::createStructure): Deleted. + (JSC::StringIteratorConstructor::StringIteratorConstructor): Deleted. + * runtime/StringIteratorPrototype.cpp: + (JSC::StringIteratorPrototype::finishCreation): + (JSC::stringIteratorPrototypeIterator): Deleted. + * tests/stress/iterator-prototype.js: Added. + (shouldBe): + (inheritIteratorPrototype): + (testChain): + +2015-06-15 Michael Saboff <msaboff@apple.com> + + JIT bug - fails when inspector closed, works when open + https://bugs.webkit.org/show_bug.cgi?id=145243 + + Reviewed by Oliver Hunt. + + We need to provide the Arguments object as the base when creating the HeapLocation for + GetFromArguments and PutToArguments. Otherwise we endup creating a HeapLocation for + any arguments object, not the one we need. + + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + +2015-06-13 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: console.table() with a list of objects no longer works + https://bugs.webkit.org/show_bug.cgi?id=145952 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.RemoteObject.prototype._generatePreview): + Calling generatePreview again was actually starting with a preview + of the current object instead of the sub-value. Go down the other + path that correctly generates sub-previews. Leave filtering on the + backend unimplemented, which we were already ignoring. + +2015-06-13 Youenn Fablet <youenn.fablet@crf.canon.fr> + + [Streams API] ReadableJSStream should handle promises returned by JS source start callback + https://bugs.webkit.org/show_bug.cgi?id=145792 + + Reviewed by Darin Adler. + + Added support for JSFunction implemented by std::function. + + * runtime/JSFunction.cpp: + (JSC::getNativeExecutable): Refactored code to share it with the two JSFunction::create + (JSC::JSFunction::create): + (JSC::runStdFunction): + * runtime/JSFunction.h: Added std::function based JSFunction::create prototype. + * runtime.JSPromise.h: + +2015-06-12 Gyuyoung Kim <gyuyoung.kim@webkit.org> + + Purge PassRefPtr in JavaScriptCore - 2 + https://bugs.webkit.org/show_bug.cgi?id=145834 + + Reviewed by Darin Adler. + + As a step to remove PassRefPtr, this patch cleans up PassRefPtr as much as possible + in JavaScriptCore. + + * API/JSClassRef.cpp: + (OpaqueJSClass::create): + * API/JSClassRef.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::callerFrame): + * debugger/DebuggerCallFrame.h: + * dfg/DFGJITCompiler.h: + (JSC::DFG::JITCompiler::jitCode): + * inspector/ScriptCallStackFactory.cpp: + (Inspector::createScriptCallStack): + (Inspector::createScriptCallStackForConsole): + (Inspector::createScriptCallStackFromException): + (Inspector::createScriptArguments): + * inspector/ScriptCallStackFactory.h: + * jit/ExecutableAllocator.cpp: + (JSC::ExecutableAllocator::allocate): + * jit/ExecutableAllocator.h: + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::ExecutableAllocator::allocate): + * profiler/LegacyProfiler.cpp: + (JSC::LegacyProfiler::stopProfiling): + * profiler/LegacyProfiler.h: + * runtime/DateInstanceCache.h: + * runtime/Executable.cpp: + (JSC::ScriptExecutable::newCodeBlockFor): + * runtime/Executable.h: + * runtime/GenericTypedArrayView.h: + * runtime/GenericTypedArrayViewInlines.h: + (JSC::GenericTypedArrayView<Adaptor>::create): + (JSC::GenericTypedArrayView<Adaptor>::createUninitialized): + +2015-06-12 Darin Adler <darin@apple.com> + + Fix minor ES6 compliance issue in RegExp.prototype.toString and optimize performance a little + https://bugs.webkit.org/show_bug.cgi?id=145935 + + Reviewed by Anders Carlsson. + + Test: js/regexp-toString.html + + * runtime/RegExpPrototype.cpp: + (JSC::getFlags): Avoid memory allocation for the flags string by returning it in a character + buffer instead of constructing a WTF::String for it. + (JSC::regExpProtoFuncToString): Require only that the this value be an object; don't require + that it is actually a regular expression object. This is covered in the ES6 specification. + Also removed comment about the "/(?:)/" trick since that is now the repsonsibility of the + getter for the "source" property. Updated to use getFlags so we do one less memory allocation. + (JSC::regExpProtoGetterFlags): Chagned to use getFlags instead of the old flagsString. + +2015-06-12 Basile Clement <basile_clement@apple.com> + + DFG Object Allocation Sinking should not consider GetClosureVar as escapes + https://bugs.webkit.org/show_bug.cgi?id=145904 + + Reviewed by Filip Pizlo. + + The object allocation sinking phase is currently able to sink + CreateActivation nodes, but will consider any GetClosureVar node as + escaping. + + This is not problematic in general as most of the GetClosureVar nodes + we would have been able to sink over will have been eliminated by CSE + anyway. Still, this is an oversight that we should fix since the + machinery is already in place. + + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPromoteHeapAccess.h: + (JSC::DFG::promoteHeapAccess): + +2015-06-11 Mark Lam <mark.lam@apple.com> + + WebCore::reportException() needs to be able to accept a raw thrown value in addition to Exception objects. + https://bugs.webkit.org/show_bug.cgi?id=145872 + + Reviewed by Michael Saboff. + + In r185259, we changed exception handling code inside the VM to work with + Exception objects instead of the thrown JSValue. The handling code will get the + exception stack trace from the Exception object. + + However, there is some code that cannot be updated to pass the Exception object. + An example of this are the ObjC API functions. Those functions are specified to + return any thrown exception JSValue in a JSValueRef. Since these APIs are + public, we cannot arbitrarily change them to use the Exception object. + + There are client code that calls these APIs and then passes the returned exception + JSValue to WebCore::reportException() to be reported. WebCore::reportException() + previously relied on the VM::exceptionStackTrace() to provide a cache of the + stack trace of the last thrown exception. VM::exceptionStackTrace() no longer + exists in the current code. + + To restore this functionality, we will introduce VM::lastException() which + caches the last thrown Exception object. With this, if the exception passed to + WebCore::reportException() to be reported isn't an Exception object (which has its + own stack trace), reportException() can again use the cached exception stack trace + which is available from VM::lastException(). + + * heap/Heap.cpp: + (JSC::Heap::visitException): + - visit VM::m_lastException on GCs. + + * interpreter/CallFrame.h: + (JSC::ExecState::lastException): + (JSC::ExecState::clearLastException): + - convenience functions to get and clear the last exception. + + * runtime/Exception.cpp: + (JSC::Exception::create): + (JSC::Exception::finishCreation): + - add support to create an Exception object without capturing the JS stack trace. + This is needed for making an Exception object to wrap a thrown value that does + not have a stack trace. + Currently, this is only used by WebCore::reportException() when there is no + Exception object and no last exception available to provide a stack trace. + + * runtime/Exception.h: + (JSC::Exception::cast): Deleted. No longer needed. + + * runtime/VM.h: + (JSC::VM::clearLastException): + (JSC::VM::setException): + (JSC::VM::lastException): + (JSC::VM::addressOfLastException): + - Added support for VM::m_lastException. + VM::m_lastException serves to cache the exception stack of the most recently + thrown exception like VM::exceptionStackTrace() used to before r185259. + + * runtime/VMEntryScope.cpp: + (JSC::VMEntryScope::VMEntryScope): + - Clear VM::m_lastException when we re-enter the VM. Exceptions should have been + handled before we re-enter the VM anyway. So, this is a good place to release + the cached last exception. + + NOTE: this is also where the old code before r185259 clears the last exception + stack trace. So, we're just restoring the previous behavior here in terms of + the lifecycle of the last exception stack. + +2015-06-11 Andreas Kling <akling@apple.com> + + jsSubstring() should support creating substrings from substrings. + <https://webkit.org/b/145427> + + Reviewed by Geoffrey Garen + + Tweak jsSubstring() to support base strings that are themselves substrings. + They will now share the same grandparent base. This avoids creating a new StringImpl. + + * runtime/JSString.h: + (JSC::jsSubstring): Don't force rope resolution here. Instead do that in finishCreation() + if the base string is a non-substring rope. Note that resolveRope() is the very last thing + called, since it may allocate and the JSRopeString needs to be ready for marking. + + (JSC::JSString::isSubstring): Added a helper to find out if a JSString is + a substring. This is just for internal use, so you don't have to cast to + JSRopeString for the real substringness flag. + +2015-06-11 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r185465. + https://bugs.webkit.org/show_bug.cgi?id=145893 + + "This patch is breaking 32bit mac build" (Requested by youenn + on #webkit). + + Reverted changeset: + + "[Streams API] ReadableJSStream should handle promises + returned by JS source start callback" + https://bugs.webkit.org/show_bug.cgi?id=145792 + http://trac.webkit.org/changeset/185465 + +2015-06-11 Youenn Fablet <youenn.fablet@crf.canon.fr> + + [Streams API] ReadableJSStream should handle promises returned by JS source start callback + https://bugs.webkit.org/show_bug.cgi?id=145792 + + Reviewed by Darin Adler. + + Added support for JSFunction implemented by std::function. + + * runtime/JSFunction.cpp: + (JSC::getNativeExecutable): Refactored code to share it with the two JSFunction::create + (JSC::JSFunction::create): + (JSC::runStdFunction): + * runtime/JSFunction.h: Added std::function based JSFunction::create prototype. + * runtime.JSPromise.h: + +2015-06-10 Yusuke Suzuki <utatane.tea@gmail.com> + + ASSERTION FAILED: s.length() > 1 on LayoutTests/js/regexp-flags.html + https://bugs.webkit.org/show_bug.cgi?id=145599 + + Unreviewed, simple follow up patch. + + use jsString instead of jsMakeNontrivialString + since the flag string may be trivial (0 or 1 length). + + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoGetterFlags): + +2015-06-10 Yusuke Suzuki <utatane.tea@gmail.com> + + JavaScript: Drop the âescaped reserved words as identifiersâ compatibility measure + https://bugs.webkit.org/show_bug.cgi?id=90678 + + Reviewed by Darin Adler. + + After ES6, escaped reserved words in identifiers are prohibited. + After parsing Identifier, we should perform `m_buffer16.shrink(0)`. + + * parser/Lexer.cpp: + (JSC::Lexer<CharacterType>::parseIdentifierSlowCase): + * tests/mozilla/ecma_3/Unicode/uc-003.js: + (test): Deleted. + * tests/stress/reserved-word-with-escape.js: Added. + (testSyntax): + (testSyntaxError): + +2015-06-10 Jordan Harband <ljharb@gmail.com> + + Implement RegExp.prototype.flags + https://bugs.webkit.org/show_bug.cgi?id=145599 + + Reviewed by Geoffrey Garen. + Per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-regexp.prototype.flags + + * runtime/CommonIdentifiers.h: + * runtime/RegExpPrototype.cpp: + (JSC::flagsString): + (JSC::regExpProtoFuncToString): + (JSC::regExpProtoGetterFlags): + * tests/stress/static-getter-in-names.js: + +2015-06-10 Filip Pizlo <fpizlo@apple.com> + + DFG ASSERTION FAILED: !iterate() on stress/singleton-scope-then-overwrite.js.ftl-eager + https://bugs.webkit.org/show_bug.cgi?id=145853 + + Unreviewed, remove the assertion. + + * dfg/DFGCSEPhase.cpp: + +2015-06-10 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r185414. + https://bugs.webkit.org/show_bug.cgi?id=145844 + + broke debug and jsc tests (Requested by alexchristensen on + #webkit). + + Reverted changeset: + + "JavaScript: Drop the âescaped reserved words as identifiersâ + compatibility measure" + https://bugs.webkit.org/show_bug.cgi?id=90678 + http://trac.webkit.org/changeset/185414 + +2015-06-10 Yusuke Suzuki <utatane.tea@gmail.com> + + JavaScript: Drop the âescaped reserved words as identifiersâ compatibility measure + https://bugs.webkit.org/show_bug.cgi?id=90678 + + Reviewed by Darin Adler. + + After ES6, escaped reserved words in identifiers are prohibited. + + * parser/Lexer.cpp: + (JSC::Lexer<CharacterType>::parseIdentifierSlowCase): + * tests/stress/reserved-word-with-escape.js: Added. + (testSyntax): + (testSyntaxError): + +2015-06-10 Andreas Kling <akling@apple.com> + + [JSC] InlineCallFrame::arguments should be sized-to-fit. + <https://webkit.org/b/145782> + + Reviewed by Darin Adler. + + I spotted this Vector<ValueRecovery> looking a bit chubby in Instruments, + with 354 kB of memory allocated on cnet.com. + + Use resizeToFit() instead of resize() since we know the final size up front. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + +2015-06-09 Chris Dumez <cdumez@apple.com> + + Allow one sync GC per gcTimer interval on critical memory pressure warning + https://bugs.webkit.org/show_bug.cgi?id=145773 + + Reviewed by Geoffrey Garen. + + On critical memory pressure warning, we were calling GCController::garbageCollectSoon(), + which does not offer any guarantee on when the garbage collection will actually take + place. + + On critical memory pressure, we need to free up memory as soon as possible to avoid + getting killed so this is an issue. Also, the fact that we clear the PageCache on + critical memory pressure means a GC would likely be useful, even if the last + collection did not free much memory. + + This patch adds a new GCController::garbageCollectNowIfNotDoneRecently() API that allows + one synchronous GC per gcTimer interval on critical memory pressure warning. This makes + us more responsive to critical memory pressure and avoids doing synchronous GCs too + often. + + * heap/FullGCActivityCallback.cpp: + (JSC::FullGCActivityCallback::doCollection): + * heap/FullGCActivityCallback.h: + (JSC::GCActivityCallback::createFullTimer): + * heap/GCActivityCallback.h: + * heap/Heap.cpp: + (JSC::Heap::collectAllGarbageIfNotDoneRecently): + * heap/Heap.h: + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::doWork): Deleted. + * heap/IncrementalSweeper.h: + + Drop fullSweep() API as it no longer seems useful. garbageCollectNow() + already does a sweep after the full collection. + +2015-06-09 Andreas Kling <akling@apple.com> + + [JSC] CodeBlock::m_constantRegisters should be sized-to-fit. + <https://webkit.org/b/145784> + + Reviewed by Darin Adler. + + Spotted this Vector looking chubby on cnet.com, with 1.23 MB of memory + allocated below CodeBlock::setConstantRegisters(). + + Use resizeToFit() instead since we know the final size up front. + Also removed some unused functions that operated on this constants vector + and the corresponding one in UnlinkedCodeBlock. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::addOrFindConstant): Deleted. + (JSC::CodeBlock::findConstant): Deleted. + * bytecode/CodeBlock.h: + (JSC::CodeBlock::setConstantRegisters): + (JSC::CodeBlock::numberOfConstantRegisters): Deleted. + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::addOrFindConstant): Deleted. + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::numberOfConstantRegisters): Deleted. + (JSC::UnlinkedCodeBlock::getConstant): Deleted. + +2015-06-09 Andreas Kling <akling@apple.com> + + [JSC] Polymorphic{Get,Put}ByIdList::addAccess() should optimize for size, not speed. + <https://webkit.org/b/145786> + + Reviewed by Darin Adler. + + These functions already contained comments saying they optimize for size over speed, + but they were using Vector::resize() which adds the usual slack for faster append(). + + Switch them over to using Vector::resizeToFit() instead, which makes the Vector + allocate a perfectly sized backing store. + + Spotted 670 kB of the GetById ones, and 165 kB of PutById on cnet.com, so these + Vectors are definitely worth shrink-wrapping. + + * bytecode/PolymorphicGetByIdList.cpp: + (JSC::PolymorphicGetByIdList::addAccess): + * bytecode/PolymorphicPutByIdList.cpp: + (JSC::PolymorphicPutByIdList::addAccess): + +2015-06-09 Andreas Kling <akling@apple.com> + + [JSC] JSPropertyNameEnumerator's property name vector should be sized-to-fit. + <https://webkit.org/b/145787> + + Reviewed by Darin Adler. + + Saw 108 kB worth of JSPropertyNameEnumerator backing store Vectors on cnet.com. + Use Vector::resizeToFit() since we know the perfect size up front. + + * runtime/JSPropertyNameEnumerator.cpp: + (JSC::JSPropertyNameEnumerator::finishCreation): + +2015-06-09 Andreas Kling <akling@apple.com> + + FunctionExecutable::isCompiling() is weird and wrong. + <https://webkit.org/b/145689> + + Reviewed by Geoffrey Garen. + + Remove FunctionExecutable::isCompiling() and the clearCodeIfNotCompiling() style + functions that called it before throwing away code. + + isCompiling() would consider the executable to be "compiling" if it had a CodeBlock + but no JITCode. In practice, every executable gets a JITCode at the same time as it + gets a CodeBlock, by way of prepareForExecutionImpl(). + + * debugger/Debugger.cpp: + * heap/Heap.cpp: + (JSC::Heap::deleteAllCompiledCode): + (JSC::Heap::deleteAllUnlinkedFunctionCode): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::TypeRecompiler::visit): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::clearUnlinkedCodeForRecompilation): + (JSC::FunctionExecutable::clearCodeIfNotCompiling): Deleted. + (JSC::FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling): Deleted. + * runtime/Executable.h: + * runtime/VM.cpp: + (JSC::StackPreservingRecompiler::visit): + +2015-06-09 Yusuke Suzuki <utatane.tea@gmail.com> + + Introduce getter definition into static hash tables and use it for getters in RegExp.prototype. + https://bugs.webkit.org/show_bug.cgi?id=145705 + + Reviewed by Darin Adler. + + In this patch, we introduce Accessor type into property tables. + With Accessor type, create_hash_table creates a static getter property. + This getter property is reified as the same to the static functions. + + In the mean time, we only support getter because `putEntry` and `lookupPut` + only work with null setter currently. However, in the spec, there's + no need to add static setter properties. So we will add it if it becomes + necessary in the future. + + And at the same time, this patch fixes the issue 145738. Before this patch, + `putEntry` in `JSObject::deleteProperty` adds `undefined` property if + `isValidOffset(...)` is false (deleted). As the result, deleting twice + revives the property with `undefined` value. + + If the static functions are reified and the entry is + `BuiltinOrFunctionOrAccessor`, there's no need to execute `putEntry` with + static hash table entry. They should be handled in the normal structure's + looking up because they should be already reified. So added guard for this. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * create_hash_table: + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + (JSC::JSObject::put): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::reifyStaticFunctionsForDelete): + * runtime/Lookup.cpp: + (JSC::reifyStaticAccessor): + (JSC::setUpStaticFunctionSlot): + * runtime/Lookup.h: + (JSC::HashTableValue::propertyGetter): + (JSC::HashTableValue::propertyPutter): + (JSC::HashTableValue::accessorGetter): + (JSC::HashTableValue::accessorSetter): + (JSC::getStaticPropertySlot): + (JSC::getStaticValueSlot): + (JSC::putEntry): + (JSC::reifyStaticProperties): + * runtime/PropertySlot.h: + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::getOwnPropertySlot): + (JSC::regExpObjectGlobal): Deleted. + (JSC::regExpObjectIgnoreCase): Deleted. + (JSC::regExpObjectMultiline): Deleted. + (JSC::appendLineTerminatorEscape<LChar>): Deleted. + (JSC::appendLineTerminatorEscape<UChar>): Deleted. + (JSC::regExpObjectSourceInternal): Deleted. + (JSC::regExpObjectSource): Deleted. + * runtime/RegExpPrototype.cpp: + (JSC::RegExpPrototype::getOwnPropertySlot): + (JSC::regExpProtoGetterGlobal): + (JSC::regExpProtoGetterIgnoreCase): + (JSC::regExpProtoGetterMultiline): + (JSC::appendLineTerminatorEscape<LChar>): + (JSC::appendLineTerminatorEscape<UChar>): + (JSC::regExpProtoGetterSourceInternal): + (JSC::regExpProtoGetterSource): + * tests/stress/static-function-delete.js: Added. + (shouldBe): + * tests/stress/static-function-put.js: Added. + (shouldBe): + * tests/stress/static-getter-delete.js: Added. + (shouldBe): + (shouldThrow): + * tests/stress/static-getter-descriptors.js: Added. + (shouldBe): + * tests/stress/static-getter-enumeration.js: Added. + (shouldBe): + * tests/stress/static-getter-get.js: Added. + (shouldBe): + * tests/stress/static-getter-in-names.js: Added. + (shouldBe): + * tests/stress/static-getter-names.js: Added. + (shouldBe): + * tests/stress/static-getter-put.js: Added. + (shouldBe): + (shouldThrow): + +2015-06-09 Andreas Kling <akling@apple.com> + + [JSC] JSString::getIndex() should avoid reifying substrings. + <https://webkit.org/b/145803> + + Reviewed by Darin Adler. + + Implement getIndex() using JSString::view(), which cuts it down to a one-liner + and also avoids reifying substrings. + + I saw 178 kB of reified substrings below operationGetByVal -> getIndex() + on cnet.com, so this should help. + + * runtime/JSString.cpp: + (JSC::JSRopeString::getIndexSlowCase): Deleted. + * runtime/JSString.h: + (JSC::JSString::getIndex): + +2015-06-09 Andreas Kling <akling@apple.com> + + [JSC] String.prototype.indexOf() should use StringView. + <https://webkit.org/b/145351> + + Reviewed by Darin Adler. + + Use StringView::find() to implement String.prototype.indexOf(). + This avoids reifying the needle and haystack JSStrings in case they + are substrings. + + Reduces malloc memory by ~190 kB on cnet.com. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncIndexOf): + +2015-06-09 Csaba Osztrogonác <ossy@webkit.org> + + [cmake] Fix the style issues in cmake project files + https://bugs.webkit.org/show_bug.cgi?id=145755 + + Reviewed by Darin Adler. + + * CMakeLists.txt: + +2015-06-08 Gyuyoung Kim <gyuyoung.kim@webkit.org> + + Purge PassRefPtr in JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=145750 + + As a step to purge PassRefPtr, this patch replaces PassRefPtr with Ref or RefPtr. + + Reviewed by Darin Adler. + + * API/JSClassRef.cpp: + (OpaqueJSClass::createNoAutomaticPrototype): + * API/JSClassRef.h: + * API/JSContextRef.cpp: + * API/JSScriptRef.cpp: + (OpaqueJSScript::create): + * API/JSStringRef.cpp: + (JSStringCreateWithCharacters): + (JSStringCreateWithUTF8CString): + * API/OpaqueJSString.cpp: + (OpaqueJSString::create): + * API/OpaqueJSString.h: + (OpaqueJSString::create): + * bytecompiler/StaticPropertyAnalysis.h: + (JSC::StaticPropertyAnalysis::create): + * debugger/DebuggerCallFrame.h: + (JSC::DebuggerCallFrame::create): + * dfg/DFGToFTLDeferredCompilationCallback.cpp: + (JSC::DFG::ToFTLDeferredCompilationCallback::create): + * dfg/DFGToFTLDeferredCompilationCallback.h: + * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp: + (JSC::DFG::Ref<ToFTLForOSREntryDeferredCompilationCallback>ToFTLForOSREntryDeferredCompilationCallback::create): + (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::create): Deleted. + * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h: + * dfg/DFGWorklist.cpp: + (JSC::DFG::Worklist::create): + (JSC::DFG::ensureGlobalDFGWorklist): + (JSC::DFG::ensureGlobalFTLWorklist): + * dfg/DFGWorklist.h: + * heap/EdenGCActivityCallback.h: + (JSC::GCActivityCallback::createEdenTimer): + * heap/FullGCActivityCallback.h: + (JSC::GCActivityCallback::createFullTimer): + * heap/GCActivityCallback.h: + * inspector/InjectedScriptHost.h: + * inspector/JavaScriptCallFrame.h: + (Inspector::JavaScriptCallFrame::create): + * inspector/ScriptArguments.cpp: + (Inspector::ScriptArguments::create): + * inspector/ScriptArguments.h: + * jit/JITStubRoutine.h: + (JSC::JITStubRoutine::createSelfManagedRoutine): + * jit/JITToDFGDeferredCompilationCallback.cpp: + (JSC::JITToDFGDeferredCompilationCallback::create): + * jit/JITToDFGDeferredCompilationCallback.h: + * jsc.cpp: + (jscmain): + * parser/NodeConstructors.h: + (JSC::ArrayPatternNode::create): + (JSC::ObjectPatternNode::create): + (JSC::BindingNode::create): + * parser/Nodes.cpp: + (JSC::FunctionParameters::create): + * parser/Nodes.h: + * parser/SourceProvider.h: + (JSC::StringSourceProvider::create): + * profiler/Profile.cpp: + (JSC::Profile::create): + * profiler/Profile.h: + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::create): + * profiler/ProfileGenerator.h: + * profiler/ProfileNode.h: + (JSC::ProfileNode::create): + * runtime/DataView.cpp: + (JSC::DataView::create): + * runtime/DataView.h: + * runtime/DateInstanceCache.h: + (JSC::DateInstanceData::create): + * runtime/JSPromiseReaction.cpp: + (JSC::createExecutePromiseReactionMicrotask): + * runtime/JSPromiseReaction.h: + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArrayData::create): + * runtime/TypeSet.h: + (JSC::StructureShape::create): + (JSC::TypeSet::create): + * runtime/TypedArrayBase.h: + (JSC::TypedArrayBase::create): + (JSC::TypedArrayBase::createUninitialized): + (JSC::TypedArrayBase::subarrayImpl): + * runtime/VM.cpp: + (JSC::VM::createContextGroup): + (JSC::VM::create): + (JSC::VM::createLeaked): + * runtime/VM.h: + * yarr/RegularExpression.cpp: + (JSC::Yarr::RegularExpression::Private::create): + +2015-06-08 Filip Pizlo <fpizlo@apple.com> + + It should be possible to hoist all constants in DFG SSA + https://bugs.webkit.org/show_bug.cgi?id=145769 + + Reviewed by Geoffrey Garen. + + It's sometimes somewhat more efficient, and convenient, to have all constants at the + top of the root block. We don't require this as an IR invariant because too many phases + want to be able to insert constants in weird places. But, this phase will be great for + preparing for https://bugs.webkit.org/show_bug.cgi?id=145768. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGConstantHoistingPhase.cpp: Added. + (JSC::DFG::performConstantHoisting): + * dfg/DFGConstantHoistingPhase.h: Added. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + +2015-06-07 Filip Pizlo <fpizlo@apple.com> + + The tiny set magic in StructureSet should be available in WTF + https://bugs.webkit.org/show_bug.cgi?id=145722 + + Reviewed by Geoffrey Garen. + + I moved the generic logic of small sets of pointers and moved it into WTF. Now, + StructureSet is a subclass of TinyPtrSet<Structure*>. There shouldn't be any functional + change. + + * bytecode/StructureSet.cpp: + (JSC::StructureSet::filter): + (JSC::StructureSet::filterArrayModes): + (JSC::StructureSet::speculationFromStructures): + (JSC::StructureSet::arrayModesFromStructures): + (JSC::StructureSet::dumpInContext): + (JSC::StructureSet::dump): + (JSC::StructureSet::clear): Deleted. + (JSC::StructureSet::add): Deleted. + (JSC::StructureSet::remove): Deleted. + (JSC::StructureSet::contains): Deleted. + (JSC::StructureSet::merge): Deleted. + (JSC::StructureSet::exclude): Deleted. + (JSC::StructureSet::isSubsetOf): Deleted. + (JSC::StructureSet::overlaps): Deleted. + (JSC::StructureSet::operator==): Deleted. + (JSC::StructureSet::addOutOfLine): Deleted. + (JSC::StructureSet::containsOutOfLine): Deleted. + (JSC::StructureSet::copyFromOutOfLine): Deleted. + (JSC::StructureSet::OutOfLineList::create): Deleted. + (JSC::StructureSet::OutOfLineList::destroy): Deleted. + * bytecode/StructureSet.h: + (JSC::StructureSet::onlyStructure): + (JSC::StructureSet::StructureSet): Deleted. + (JSC::StructureSet::operator=): Deleted. + (JSC::StructureSet::~StructureSet): Deleted. + (JSC::StructureSet::isEmpty): Deleted. + (JSC::StructureSet::genericFilter): Deleted. + (JSC::StructureSet::isSupersetOf): Deleted. + (JSC::StructureSet::size): Deleted. + (JSC::StructureSet::at): Deleted. + (JSC::StructureSet::operator[]): Deleted. + (JSC::StructureSet::last): Deleted. + (JSC::StructureSet::iterator::iterator): Deleted. + (JSC::StructureSet::iterator::operator*): Deleted. + (JSC::StructureSet::iterator::operator++): Deleted. + (JSC::StructureSet::iterator::operator==): Deleted. + (JSC::StructureSet::iterator::operator!=): Deleted. + (JSC::StructureSet::begin): Deleted. + (JSC::StructureSet::end): Deleted. + (JSC::StructureSet::ContainsOutOfLine::ContainsOutOfLine): Deleted. + (JSC::StructureSet::ContainsOutOfLine::operator()): Deleted. + (JSC::StructureSet::copyFrom): Deleted. + (JSC::StructureSet::OutOfLineList::list): Deleted. + (JSC::StructureSet::OutOfLineList::OutOfLineList): Deleted. + (JSC::StructureSet::deleteStructureListIfNecessary): Deleted. + (JSC::StructureSet::isThin): Deleted. + (JSC::StructureSet::pointer): Deleted. + (JSC::StructureSet::singleStructure): Deleted. + (JSC::StructureSet::structureList): Deleted. + (JSC::StructureSet::set): Deleted. + (JSC::StructureSet::setEmpty): Deleted. + (JSC::StructureSet::getReservedFlag): Deleted. + (JSC::StructureSet::setReservedFlag): Deleted. + * dfg/DFGStructureAbstractValue.cpp: + (JSC::DFG::StructureAbstractValue::clobber): + (JSC::DFG::StructureAbstractValue::filter): + (JSC::DFG::StructureAbstractValue::filterSlow): + (JSC::DFG::StructureAbstractValue::contains): + * dfg/DFGStructureAbstractValue.h: + (JSC::DFG::StructureAbstractValue::makeTop): + +2015-06-08 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Add the missing setupArgumentsWithExecState functions after r185240 + https://bugs.webkit.org/show_bug.cgi?id=145754 + + Reviewed by Benjamin Poulain. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2015-06-08 Brady Eidson <beidson@apple.com> + + Completely remove all IDB properties/constructors when it is disabled at runtime. + rdar://problem/18429374 and https://bugs.webkit.org/show_bug.cgi?id=137034 + + Reviewed by Geoffrey Garen. + + * runtime/CommonIdentifiers.h: + +2015-06-06 Mark Lam <mark.lam@apple.com> + + Returned Exception* values need to be initialized to nullptr when no exceptions are thrown. + https://bugs.webkit.org/show_bug.cgi?id=145720 + + Reviewed by Dan Bernstein. + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + +2015-06-05 Mark Lam <mark.lam@apple.com> + + Subclasses of JSNonFinalObject with gc'able children need to implement visitChildren(). + https://bugs.webkit.org/show_bug.cgi?id=145709 + + Reviewed by Geoffrey Garen. + + * jsc.cpp: + (functionSetElementRoot): + - The Element class has a member of type Root which extends JSDestructibleObject. + It should be stored in a WriteBarrier, and visited by visitChildren(). + + * runtime/ClonedArguments.cpp: + (JSC::ClonedArguments::materializeSpecialsIfNecessary): + (JSC::ClonedArguments::visitChildren): + * runtime/ClonedArguments.h: + - Add missing visitChildren(). + + * tests/stress/cloned-arguments-should-visit-callee-during-gc.js: Added. + (makeTransientFunction.transientFunc): + (makeTransientFunction): + +2015-06-05 Geoffrey Garen <ggaren@apple.com> + + DropAllLocks RELEASE_ASSERT on iOS + https://bugs.webkit.org/show_bug.cgi?id=139654 + + Reviewed by Mark Lam. + + * runtime/JSLock.cpp: + (JSC::JSLock::dropAllLocks): Removed a comment because it duplicated + the code beneath it. Removed a FIXME because we can't ASSERT that + we're holding the lock. WebKit1 on iOS drops the lock before calling to + delegates, not knowing whether it holds the lock or not. + + (JSC::JSLock::DropAllLocks::DropAllLocks): Only ASSERT that we are not + GC'ing if we hold the lock. If we do not hold the lock, it is perfectly + valid for some other thread, which does hold the lock, to be GC'ing. + What is not valid is to drop the lock in the middle of GC, since GC + must be atomic. + +2015-06-05 Filip Pizlo <fpizlo@apple.com> + + speculateRealNumber() should early exit if you're already a real number, not if you're already a real double. + + Rubber stamped by Mark Lam. + + This was causing: https://build.webkit.org/results/Apple%20Yosemite%20Debug%20WK1%20(Tests)/r185261%20(5180)/webaudio/note-grain-on-timing-crash-log.txt + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::speculateRealNumber): + +2015-06-05 Mark Lam <mark.lam@apple.com> + + finally blocks should not set the exception stack trace when re-throwing the exception. + https://bugs.webkit.org/show_bug.cgi?id=145525 + + Reviewed by Geoffrey Garen. + + How exceptions presently work: + ============================= + 1. op_throw can throw any JSValue. + 2. the VM tries to capture the stack at the throw point and propagate that as needed. + 3. finally blocks are implemented using op_catch to catch the thrown value, and throws it again using op_throw. + + What's wrong with how it presently works: + ======================================== + 1. finally's makes for bad exception throw line numbers in the Inspector console. + + The op_throw in finally will throw the value anew i.e. it captures a stack from the re-throw point. + As a result, the Inspector sees the finally block as the throw point. The original stack is lost. + + 2. finally's breaks the Inspector's "Breaks on Uncaught Exception" + + This is because finally blocks are indistinguishable from catch blocks. As a result, a try-finally, + which should break in the Inspector on the throw, does not because the Inspector thought the + exception was "caught". + + 3. finally's yields confusing break points when the Inspector "Breaks on All Exceptions" + + a. In a try-finally scenario, the Inspector breaks 2 times: 1 at the throw, 1 at the finally. + b. In a for-of loop (which has synthesized finallys), the Inspector will do another break. + Similarly for other cases of JS code which synthesize finallys. + c. At VM re-entry boundaries (e.g. js throws & returns to native code, which returns to js), + the Inspector will do another break if there's an uncaught exception. + + How this patch fixes the issues: + =============================== + 1. We introduce an Exception object that wraps the thrown value and the exception stack. + + When throwing an exception, the VM will check if the thrown value is an Exception + object or not. If it is not an Exception object, then we must be throwing a new + exception. The VM will create an Exception object to wrap the thrown value and + capture the current stack for it. + + If the thrown value is already an Exception object, then the requested throw operation + must be a re-throw. The VM will not capture a new stack for it. + + 2. op_catch will now populate 2 locals: 1 for the Exception, 1 for the thrown JSValue. + + The VM is aware of the Exception object and uses it for rethrows in finally blocks. + JS source code is never aware of the Exception object. + + JS code is aware of the thrown value. If it throws the caught thrown value, that + constitutes a new throw, and a new Exception object will be created for it. + + 3. The VM no longer tracks the thrown JSValue and the exception stack. It will only + track a m_exception field which is an Exception*. + + 4. The BytecodeGenerator has already been updated in a prior patch to distinguish + between Catch, Finally, and SynthesizedFinally blocks. The interpreter runtime will + now report to the debugger whether we have a Catch handler, not just any handlers. + + The debugger will use this detail to determine whether to break or not. "Break on + uncaught exceptions" will only break if no Catch handler was found. + + This solves the issue of the debugger breaking at finally blocks, and for-of statements. + + 5. The Exception object will also have a flag to indicate whether the debugger has been + notified of the Exception being thrown. Once the Interpreter notifies the debugger + of the Exception object, it will mark this flag and not repeat the notify the debugger + again of the same Exception. + + This solves the issue of the debugger breaking at VM re-entry points due to uncaught + exceptions. + + 6. The life-cycle of the captured exception stack trace will now follow the life-cycle + of the Exception object. + + Other changes: + 7. Change all clients of the VM::exception() to expect an Exception* instead of JSValue. + + 8. Fixed a few bugs where thrown exceptions are not cleared before exiting the VM. + + 9. Also renamed some variables and classes to better describe what they are. + + * API/JSBase.cpp: + (JSEvaluateScript): + (JSCheckScriptSyntax): + + * API/JSObjectRef.cpp: + (handleExceptionIfNeeded): + - The functions below all do the same exception check. Added this helper + to simplify the code. + (JSClassCreate): + (JSObjectMakeFunction): + (JSObjectMakeArray): + (JSObjectMakeDate): + (JSObjectMakeError): + (JSObjectMakeRegExp): + (JSObjectGetProperty): + (JSObjectSetProperty): + (JSObjectGetPropertyAtIndex): + (JSObjectSetPropertyAtIndex): + (JSObjectDeleteProperty): + (JSObjectCallAsFunction): + (JSObjectCallAsConstructor): + + * API/JSScriptRef.cpp: + * API/JSValue.mm: + (JSContainerConvertor::take): + (reportExceptionToInspector): + + * API/JSValueRef.cpp: + (handleExceptionIfNeeded): + - The functions below all do the same exception check. Added this helper + to simplify the code. + (evernoteHackNeeded): + (JSValueIsEqual): + (JSValueIsInstanceOfConstructor): + (JSValueCreateJSONString): + (JSValueToNumber): + (JSValueToStringCopy): + (JSValueToObject): + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + - Added new files Exception.h and Exception.cpp. + + * bindings/ScriptFunctionCall.cpp: + (Deprecated::ScriptFunctionCall::call): + * bindings/ScriptFunctionCall.h: + + * bytecode/BytecodeList.json: + - op_catch now had 2 operands: the exception register, and the thrown value register. + + * bytecode/BytecodeUseDef.h: + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::handlerForBytecodeOffset): + * bytecode/CodeBlock.h: + - handlerForBytecodeOffset() now can look for just Catch handlers only. + + * bytecode/HandlerInfo.h: + - Cleaned up some white space I accidentally added in a previous patch. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::pushTry): + (JSC::BytecodeGenerator::popTryAndEmitCatch): + (JSC::BytecodeGenerator::emitThrowReferenceError): + (JSC::BytecodeGenerator::emitEnumeration): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitThrow): + * bytecompiler/NodesCodegen.cpp: + (JSC::TryNode::emitBytecode): + - Adding support for op_catch's 2 operands. + + * debugger/Debugger.cpp: + (JSC::Debugger::hasBreakpoint): + (JSC::Debugger::pauseIfNeeded): + (JSC::Debugger::exception): + * debugger/Debugger.h: + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::thisValue): + (JSC::DebuggerCallFrame::evaluate): + * debugger/DebuggerCallFrame.h: + (JSC::DebuggerCallFrame::isValid): + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::createInjectedScript): + * inspector/InspectorEnvironment.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectScriptDebugServer.h: + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::evaluate): + * inspector/JavaScriptCallFrame.h: + (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): + (Inspector::JavaScriptCallFrame::thisValue): + (Inspector::JavaScriptCallFrame::evaluate): + * inspector/ScriptCallStackFactory.cpp: + (Inspector::extractSourceInformationFromException): + (Inspector::createScriptCallStackFromException): + * inspector/ScriptCallStackFactory.h: + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::evaluateBreakpointAction): + (Inspector::ScriptDebugServer::handleBreakpointHit): + (Inspector::ScriptDebugServer::handleExceptionInBreakpointCondition): + * inspector/ScriptDebugServer.h: + * interpreter/CallFrame.h: + (JSC::ExecState::clearException): + (JSC::ExecState::exception): + (JSC::ExecState::hadException): + (JSC::ExecState::atomicStringTable): + (JSC::ExecState::propertyNames): + (JSC::ExecState::clearSupplementaryExceptionInfo): Deleted. + + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + (JSC::Interpreter::stackTraceAsString): + (JSC::GetCatchHandlerFunctor::GetCatchHandlerFunctor): + (JSC::GetCatchHandlerFunctor::operator()): + (JSC::Interpreter::unwind): + - Added a check for didNotifyInspectorOfThrow() here to prevent duplicate reports + of the same Exception to the debugger. + + (JSC::GetExceptionHandlerFunctor::GetExceptionHandlerFunctor): Deleted. + (JSC::GetExceptionHandlerFunctor::operator()): Deleted. + - Renamed GetExceptionHandlerFunctor to GetCatchHandlerFunctor since the debugger + is only interested in knowing whether we have Catch handlers. + + * interpreter/Interpreter.h: + (JSC::SuspendExceptionScope::SuspendExceptionScope): + (JSC::SuspendExceptionScope::~SuspendExceptionScope): + (JSC::Interpreter::sampler): + (JSC::ClearExceptionScope::ClearExceptionScope): Deleted. + (JSC::ClearExceptionScope::~ClearExceptionScope): Deleted. + - Renamed ClearExceptionScope to SuspendExceptionScope because "clear" implies that + we're purging the exception. Instead, we're merely suspending any handling of + that exception for a period defined by the scope. + + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::emitExceptionCheck): + + * jit/JITExceptions.cpp: + (JSC::genericUnwind): + - Removed the exception argument. It is always the value in VM::exception() anyway. + genericUnwind() can just get it from the VM, and save everyone some work. + + * jit/JITExceptions.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_catch): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTINativeCall): + (JSC::JIT::emit_op_catch): + - Add support for the new op_catch operands. + + * jit/JITOperations.cpp: + * jit/ThunkGenerators.cpp: + (JSC::nativeForGenerator): + * jsc.cpp: + (functionRun): + (functionLoad): + (runWithScripts): + (runInteractive): + * llint/LLIntOffsetsExtractor.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + - Add support for the new op_catch operands. Also update the code to handle + VM::m_exception being an Exception pointer, not a JSValue. + + * parser/NodeConstructors.h: + (JSC::TryNode::TryNode): + * parser/Nodes.h: + * runtime/CallData.cpp: + (JSC::call): + * runtime/CallData.h: + + * runtime/Completion.cpp: + (JSC::evaluate): + * runtime/Completion.h: + (JSC::evaluate): + - Change evaluate() to take a reference to the returned exception value instead + of a pointer. In all but 2 or 3 cases, we want the returned exception anyway. + Might as well simplify the code by requiring the reference. + + * runtime/Error.h: + (JSC::throwVMError): + (JSC::throwVMTypeError): + + * runtime/Exception.cpp: Added. + (JSC::Exception::create): + (JSC::Exception::destroy): + (JSC::Exception::createStructure): + (JSC::Exception::visitChildren): + (JSC::Exception::Exception): + (JSC::Exception::~Exception): + * runtime/Exception.h: Added. + (JSC::Exception::valueOffset): + (JSC::Exception::cast): + (JSC::Exception::value): + (JSC::Exception::stack): + (JSC::Exception::didNotifyInspectorOfThrow): + (JSC::Exception::setDidNotifyInspectorOfThrow): + + * runtime/ExceptionHelpers.cpp: + (JSC::createTerminatedExecutionException): + (JSC::isTerminatedExecutionException): + (JSC::createStackOverflowError): + * runtime/ExceptionHelpers.h: + * runtime/GetterSetter.cpp: + (JSC::callGetter): + * runtime/IteratorOperations.cpp: + (JSC::iteratorClose): + * runtime/JSObject.cpp: + * runtime/JSPromiseConstructor.cpp: + (JSC::constructPromise): + * runtime/JSPromiseDeferred.cpp: + (JSC::updateDeferredFromPotentialThenable): + (JSC::abruptRejection): + * runtime/JSPromiseReaction.cpp: + (JSC::ExecutePromiseReactionMicrotask::run): + + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::releaseExecutableMemory): + (JSC::VM::throwException): + (JSC::VM::setStackPointerAtVMEntry): + (JSC::VM::getExceptionInfo): Deleted. + (JSC::VM::setExceptionInfo): Deleted. + (JSC::VM::clearException): Deleted. + (JSC::clearExceptionStack): Deleted. + * runtime/VM.h: + (JSC::VM::targetMachinePCForThrowOffset): + (JSC::VM::clearException): + (JSC::VM::setException): + (JSC::VM::exception): + (JSC::VM::addressOfException): + (JSC::VM::exceptionStack): Deleted. + * runtime/VMEntryScope.cpp: + (JSC::VMEntryScope::VMEntryScope): + (JSC::VMEntryScope::setEntryScopeDidPopListener): + +2015-06-04 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case + https://bugs.webkit.org/show_bug.cgi?id=145673 + + Reviewed by Geoffrey Garen. + + Previously, we were deciding to use out-of-bounds speculation based on two informations: + -Explicitly detected out-of-bounds accesses tracked on ArrayProfile. + -The number of time we took the slow cases in the baseline JIT. + + The heuristic based on slow cases was a little too fragile. + + In some cases, we were running into that limit just because the indexing type changes between + two values (typically Int32Array and DoubleArray). Sometimes we were just unlucky on what + we used for the inline cache. + + In Kraken, this was hurting us on "audio-beat-detection" and "audio-fft". The array types we see + change between Int32 and Double. We run into the slow path a bit but never hit + out-of-bounds. + + By the time we compile in DFG, we have stable Double Arrays but we speculate out-of-bounds based + on the number of slow cases we took. Because of that, we start boxing the double on GetByVal, + using DoubleRep, etc. adding a ton of overhead over otherwise very simple operations. + + WebXPRT was also suffering from this problem but the other way arround: we were missing + the out-of-bounds accesses due to changes in indexing types, we were below the threshold + of slow-path access, thus we predicted in-bounds accesses for code that was doing plenty + of out-of-bands. + + + This patch fixes the problem by tracking the out-of-bounds access explicitly any time we go + into the slow path in baseline JIT. Since we no longer miss any out-of-bounds, we can remove + the slow-path heuristic. + + There is new additional special case in the C code regarding out-of-bounds: Arguments access. + Mispredicting out-of-bounds accesses on arguments is a disaster for performance, so those are + tracked in the way DFG expect it. + + + There are a few important cases that are still not covered optimally: + -PutByVal on Arguments. + -Get/Put ByVal on TypedArray. + Those are simply not used by DFG in any way. TypedArrays should probably be looked at in the future. + + * bytecode/ArrayProfile.cpp: + (JSC::ArrayProfile::computeUpdatedPrediction): + The inline-cache repatch cases now update the ArrayProfile information. This has no value in baseline + JIT but it helps avoiding one recompile in DFG for the missing ArrayProfile information. + + * bytecode/ArrayProfile.h: + (JSC::ArrayProfile::setOutOfBounds): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getArrayMode): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): Deleted. + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_has_indexed_property): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emitSlow_op_has_indexed_property): + * jit/JITOperations.cpp: + (JSC::canUseFastArgumentAccess): + This is not my favorite part of this patch. + + I tried having JSObject::canGetIndexQuickly() handle arguments which would put everything + on the generic path. Unfortunately, that code is very performance sensitive and some benchmarks were + impacted by over 10% + + I left JSObject::canGetIndexQuickly() alone, and I added the canUseFastArgumentAccess() mirroring + how DFG uses out-of-bounds for Arguments. + + (JSC::getByVal): + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emitSlow_op_put_by_val): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emitSlow_op_put_by_val): + * runtime/JSPromiseFunctions.cpp: + * tests/stress/get-by-val-out-of-bounds-basics.js: Added. + (opaqueGetByValOnInt32ArrayEarlyOutOfBounds): + (testInt32ArrayEarlyOutOfBounds): + (testIndexingTypeChangesOnInt32Array): + (opaqueGetByValOnStringArrayHotOutOfBounds): + (testStringArrayHotOutOfBounds): + (testIndexingTypeChangesOnStringArray): + (opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds): + (testStringAndInt32ArrayHotOutOfBounds): + (opaqueGetByValOnDoubleArrayHotOutOfBounds): + * tests/stress/put-by-val-out-of-bounds-basics.js: Added. + (opaquePutByValOnInt32ArrayEarlyOutOfBounds): + (testInt32ArrayEarlyOutOfBounds): + (opaquePutByValOnStringArrayHotOutOfBounds): + (testStringArrayHotOutOfBounds): + +2015-06-03 Filip Pizlo <fpizlo@apple.com> + + Simplify unboxing of double JSValues known to be not NaN and not Int32 + https://bugs.webkit.org/show_bug.cgi?id=145618 + + Reviewed by Geoffrey Garen. + + In many cases we know that we most likely loaded a non-NaN double value from the heap. + Prior to this patch, we would do two branches before unboxing the double. This patch + reduces this to one branch in the common case. Before: + + if (is int32) + unbox int32 and convert to double + else if (is number) + unbox double + else + exit + + After: + + tmp = unbox double + if (tmp == tmp) + done + else if (is int32) + unbox int32 and convert to double + else + exit + + We only use the new style if we have profiling that tells us that we are unlikely to see + either Int32 or NaN - since we will now exit on NaN and int32 requires an extra branch. + + This is a 8% speed-up on Octane/box2d. On one microbenchmark this is a 25% speed-up. + + Rolling this back in after I made DFG::SpeculativeJIT call a new version of unboxDouble() + that doesn't assert that the JSValue is a double, since we are intentionally using it + before doing the "is a double" test. This wasn't a problem on 32-bit since unboxDouble() + does no such assertion on 32-bit. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::observeUseKindOnNode): + (JSC::DFG::FixupPhase::fixEdgeRepresentation): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateDouble): + (JSC::DFG::Node::shouldSpeculateDoubleReal): + (JSC::DFG::Node::shouldSpeculateNumber): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileDoubleRep): + (JSC::DFG::SpeculativeJIT::speculateNumber): + (JSC::DFG::SpeculativeJIT::speculateRealNumber): + (JSC::DFG::SpeculativeJIT::speculateDoubleRepReal): + (JSC::DFG::SpeculativeJIT::speculate): + (JSC::DFG::SpeculativeJIT::speculateDoubleReal): Deleted. + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + (JSC::DFG::isNumerical): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::boxDouble): + (JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateNumber): + (JSC::FTL::LowerDFGToLLVM::speculateRealNumber): + (JSC::FTL::LowerDFGToLLVM::speculateDoubleRepReal): + (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): Deleted. + (JSC::FTL::LowerDFGToLLVM::speculateDoubleReal): Deleted. + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::branchIfNotOther): + (JSC::AssemblyHelpers::branchIfInt32): + (JSC::AssemblyHelpers::branchIfNotInt32): + (JSC::AssemblyHelpers::branchIfNumber): + +2015-06-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Class constructor appearing as Object Tree property does not include parameters + https://bugs.webkit.org/show_bug.cgi?id=145661 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.prototype._classPreview): + (InjectedScript.RemoteObject.prototype._appendPropertyPreviews): + The string we will return for previews of class constructor functions. + + (InjectedScript.RemoteObject): + (InjectedScript.RemoteObject.prototype._describe): + No longer return the class name as the description string. + Instead return the class name for the RemoteObject.className. + +2015-06-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r185216. + https://bugs.webkit.org/show_bug.cgi?id=145666 + + it caused a bunch of debug crashes (Requested by pizlo on + #webkit). + + Reverted changeset: + + "Simplify unboxing of double JSValues known to be not NaN and + not Int32" + https://bugs.webkit.org/show_bug.cgi?id=145618 + http://trac.webkit.org/changeset/185216 + +2015-06-03 Filip Pizlo <fpizlo@apple.com> + + Simplify unboxing of double JSValues known to be not NaN and not Int32 + https://bugs.webkit.org/show_bug.cgi?id=145618 + + Reviewed by Geoffrey Garen. + + In many cases we know that we most likely loaded a non-NaN double value from the heap. + Prior to this patch, we would do two branches before unboxing the double. This patch + reduces this to one branch in the common case. Before: + + if (is int32) + unbox int32 and convert to double + else if (is number) + unbox double + else + exit + + After: + + tmp = unbox double + if (tmp == tmp) + done + else if (is int32) + unbox int32 and convert to double + else + exit + + We only use the new style if we have profiling that tells us that we are unlikely to see + either Int32 or NaN - since we will now exit on NaN and int32 requires an extra branch. + + This is a 8% speed-up on Octane/box2d. On one microbenchmark this is a 25% speed-up. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::observeUseKindOnNode): + (JSC::DFG::FixupPhase::fixEdgeRepresentation): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGNode.h: + (JSC::DFG::Node::shouldSpeculateDouble): + (JSC::DFG::Node::shouldSpeculateDoubleReal): + (JSC::DFG::Node::shouldSpeculateNumber): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileDoubleRep): + (JSC::DFG::SpeculativeJIT::speculateNumber): + (JSC::DFG::SpeculativeJIT::speculateRealNumber): + (JSC::DFG::SpeculativeJIT::speculateDoubleRepReal): + (JSC::DFG::SpeculativeJIT::speculate): + (JSC::DFG::SpeculativeJIT::speculateDoubleReal): Deleted. + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + (JSC::DFG::isNumerical): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::boxDouble): + (JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::speculateNumber): + (JSC::FTL::LowerDFGToLLVM::speculateRealNumber): + (JSC::FTL::LowerDFGToLLVM::speculateDoubleRepReal): + (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): Deleted. + (JSC::FTL::LowerDFGToLLVM::speculateDoubleReal): Deleted. + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::branchIfNotOther): + (JSC::AssemblyHelpers::branchIfInt32): + (JSC::AssemblyHelpers::branchIfNotInt32): + (JSC::AssemblyHelpers::branchIfNumber): + +2015-06-04 Filip Pizlo <fpizlo@apple.com> + + SideState should be a distinct abstract heap from Heap and Stack + https://bugs.webkit.org/show_bug.cgi?id=145653 + + Reviewed by Geoffrey Garen. + + Before, SideState fit into the hierarchy like so: + + World + | + +-- Stack + | + +-- Heap + | + +-- SideState + + Now we will have: + + World + | + +-- Stack + | + +-- Heap + | + +-- SideState + + This makes it easy to ask if a writing operation wrote to anything that is observable even + if we don't exit. SideState is only observable if we exit. + + * dfg/DFGAbstractHeap.h: + (JSC::DFG::AbstractHeap::AbstractHeap): + (JSC::DFG::AbstractHeap::supertype): + +2015-06-04 Chris Dumez <cdumez@apple.com> + + [WK2] Prune more resources from the MemoryCache before process suspension + https://bugs.webkit.org/show_bug.cgi?id=145633 + + Reviewed by Andreas Kling. + + No longer move protect IncrementalSweeper::fullSweep() behind + USE(CF) so we don't need #ifdefs at call sites, similarly to what is + done for the rest of the IncrementalSweeper API. + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::fullSweep): + * heap/IncrementalSweeper.h: + +2015-06-01 Filip Pizlo <fpizlo@apple.com> + + CallLinkStatus should return takesSlowPath if the GC often cleared the IC + https://bugs.webkit.org/show_bug.cgi?id=145502 + + Reviewed by Geoffrey Garen. + + CallLinkInfo now remembers when it has been cleared by GC. This has some safeguards for when + a call gets cleared by GC only because we hadn't converted it into a closure call; in that + case the GC will just tell us that it should be a closure call. The DFG will not optimize + a call that was cleared by GC, and the DFG will always prefer a closure call if the GC told + us that the specific callee was dead but the executable wasn't. + + This guards us from some scenarios that came up in Speedometer. It's neutral on the pure JS + benchmarks, most likely just because those benchmarks aren't real enough to have interesting + GC of code. + + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::visitWeak): + (JSC::CallLinkInfo::dummy): + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::CallLinkInfo): + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFromCallLinkInfo): + +2015-06-02 Filip Pizlo <fpizlo@apple.com> + + GetById and PutById profiling should be more precise about it takes slow path + https://bugs.webkit.org/show_bug.cgi?id=145590 + + Reviewed by Geoffrey Garen. + + If a ById access ever takes slow path, we want the DFG and FTL to know this. Previously we + were relying on slow path counts, which conflate slow paths taken due to a megamorphic + access and slow paths taken due to IC building. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/StructureStubInfo.h: + (JSC::StructureStubInfo::StructureStubInfo): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetById): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + +2015-06-03 Michael Saboff <msaboff@apple.com> + + Improve test coverage for changes made in 145527 + https://bugs.webkit.org/show_bug.cgi?id=145578 + + Reviewed by Geoffrey Garen. + + Added more complexity to poly-setter-combo.js stress test to create more turmoil in the + polymorphic get-by-id / put-by-id with getters and setters to exercise the code change in + https://bugs.webkit.org/show_bug.cgi?id=145527. By changing the objects that the main test + function sees, we are able to test those paths. Verified with temporary logging code. + + * tests/stress/poly-setter-combo.js: + (Cons2): + (Cons3): + (Cons4): + (foo): + (test): + (runTestWithConstructors): + +2015-06-02 Mark Lam <mark.lam@apple.com> + + Gardening: fix broken CLoop build. + + Not reviewed. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeExitSiteData): + +2015-06-02 Keith Miller <keith_miller@apple.com> + + JavaScriptCore: JSExport protocol with an NSInteger property converts negative values to 18446744073709552000 + https://bugs.webkit.org/show_bug.cgi?id=145563 + + Reviewed by Darin Adler. + + The Objective-C bindings were improperly converting negative + long long/NSIntegers to 18446744073709552000 because they + were converted to unsigned numbers. + + * API/ObjcRuntimeExtras.h: + (parseObjCType): + * API/tests/testapi.mm: + (testObjectiveCAPIMain): + (checkNegativeNSIntegers): + (testObjectiveCAPI): + +2015-06-02 Yusuke Suzuki <utatane.tea@gmail.com> + + Heap-use-after-free read of size 4 in JavaScriptCore: WTF::StringImpl::isSymbol() (StringImpl.h:496) + https://bugs.webkit.org/show_bug.cgi?id=145532 + + Reviewed by Geoffrey Garen. + + AtomicStringImpl::lookUp returns AtomicStringImpl*, + it doesn't give any ownership to the caller. + Originally, this is ok because the ownership is taken + by AtomicStringImpl's table (& the register side). + + But if we would like to use this returned AtomicStringImpl*, + we should take its ownership immediately. + Because if the register side releases its ownership (ref count), + it will be destroyed. + + In JSString::toExistingAtomicString, it returns AtomicStringImpl*. + But it's not appropriate. + If the owner of AtomicStringImpl* is always JSString*, it is ok. + But it looks up the table-registered AtomicStringImpl* from + the AtomicStringImpl table. So JSString* may not have the ownership + of the returned AtomicStringImpl*. + + The failure situation is the following. + + 1. A creates AtomicStringImpl. A has its ownership. + And A registers it to AtomicStringImpl table. + 2. JSString looks up the AtomicStringImpl from the table. + It gets AtomicStringImpl*. And JSString doesn't have its ownership. + It returns the raw pointer immediately to the users + 3. A is released. There's no owner for AtomicStringImpl*. + So it's also destroyed. + 4. Use looked up AtomicStringImpl in (2). It becomes use-after-free. + + This patch fixes it by the following changes. + + 1. Change the signature of `AtomicStringImpl* AtomicStringImpl::lookUp(...)` + to `RefPtr<AtomicStringImpl> AtomicStringImpl::lookUp(..)`. + Use `RefPtr` because it may return `nullptr`. + 2. Change the signature of `AtomicStringImpl* JSString::toExistingAtomicString(...)` + to `RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(...)`. + Using `RefPtr` is the same reason. + 3. Receive the result with `RefPtr<AtomicStringImpl>` in the caller side. + + * dfg/DFGOperations.cpp: + * jit/JITOperations.cpp: + (JSC::getByVal): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getByVal): + * runtime/JSString.cpp: + (JSC::JSRopeString::resolveRopeToExistingAtomicString): + * runtime/JSString.h: + (JSC::JSString::toExistingAtomicString): + +2015-05-30 Filip Pizlo <fpizlo@apple.com> + + Any exit from any JIT due to profiling for an inline cache should force all future compilations to be wary + https://bugs.webkit.org/show_bug.cgi?id=145496 + + Reviewed by Geoffrey Garen. + + This pessimizes compilation a bit, but it reduces the likelihood of exiting from FTL. I + couldn't find any convincing reason not to do this, and we know from Speedometer that this + change is necessary for weirder code. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeExitSiteData): + (JSC::CallLinkStatus::computeDFGStatuses): + * bytecode/CallLinkStatus.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::appendVariant): + (JSC::GetByIdStatus::hasExitSite): + (JSC::GetByIdStatus::computeFor): + * bytecode/GetByIdStatus.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::appendVariant): + (JSC::PutByIdStatus::hasExitSite): + (JSC::PutByIdStatus::computeFor): + * bytecode/PutByIdStatus.h: + +2015-05-31 Filip Pizlo <fpizlo@apple.com> + + If a call has ever taken the virtual slow path, make sure that the DFG knows this + https://bugs.webkit.org/show_bug.cgi?id=145501 + + Reviewed by Geoffrey Garen. + + Now now return higher fidelity information in the case of no polymorphic call stub. If the + virtual slow path was ever taken, we note this, and we note either zero or one call variant + based on the IC's last callee. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFromCallLinkInfo): + (JSC::CallLinkStatus::computeFor): + +2015-06-01 Michael Saboff <msaboff@apple.com> + + Crash in com.apple.WebKit.WebContent at com.apple.JavaScriptCore: JSC::revertCall + 24 + https://bugs.webkit.org/show_bug.cgi?id=145527 + + Reviewed by Filip Pizlo. + + If a CallLinkInfo is GC'ed, we need to notify any PolymorphicCallNode's that reference it. + Added plumbling to clear the m_callLinkInfo of a PolymorphicCallNode when that CallLinkInfo + is going away. + + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::~CallLinkInfo): + * jit/PolymorphicCallStubRoutine.cpp: + (JSC::PolymorphicCallNode::unlink): + (JSC::PolymorphicCallNode::clearCallLinkInfo): + (JSC::PolymorphicCallCase::dump): + (JSC::PolymorphicCallStubRoutine::edges): + (JSC::PolymorphicCallStubRoutine::clearCallNodesFor): + (JSC::PolymorphicCallStubRoutine::visitWeak): + * jit/PolymorphicCallStubRoutine.h: + (JSC::PolymorphicCallNode::hasCallLinkInfo): + +2015-06-01 Mark Lam <mark.lam@apple.com> + + Add the ability to tell between Catch and Finally blocks. + https://bugs.webkit.org/show_bug.cgi?id=145524 + + Reviewed by Michael Saboff. + + ... and also SynthesizedFinally blocks too. A SynthesizedFinally block + is a finally block that is synthesized by the bytecode generator but + does not actually correspond to any exception handling construct at the + JS source code level. An example of this is the "for ... of" statement + where it needs to do some "final" clean up before passing on the + exception. + + Manually tested by inspecting the bytecode dump of functions with + try-catch-finally blocks as well as for of statements which have + synthesized finally blocks. The bytecode dumps contains the exception + handlers table which has these blocks labelled with their newly added + types. No automatic test because this type info is not visible to JS + code. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecode/HandlerInfo.h: + (JSC::HandlerInfoBase::type): + (JSC::HandlerInfoBase::setType): + (JSC::HandlerInfoBase::typeName): + (JSC::HandlerInfoBase::isCatchHandler): + (JSC::UnlinkedHandlerInfo::UnlinkedHandlerInfo): + (JSC::HandlerInfo::initialize): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::pushTry): + (JSC::BytecodeGenerator::popTryAndEmitCatch): + (JSC::BytecodeGenerator::emitEnumeration): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitThrow): + * bytecompiler/NodesCodegen.cpp: + (JSC::TryNode::emitBytecode): + +2015-05-29 Geoffrey Garen <ggaren@apple.com> + + REGRESSION: These sorting idioms used by Peacekeeper and Browsermark are ~20X slower + https://bugs.webkit.org/show_bug.cgi?id=145412 + + Reviewed by Darin Adler. + + Moar speedup. + + Added a bucket sort for string sorting. + + * builtins/Array.prototype.js: + (sort.compactSparse): + (sort.compactSlow): + (sort.compact): Split out a compaction fast path for dense arrays. Without + it, compaction can increase sort time by 2X for simple sorts. + + (sort.bucketSort): + (sort.stringSort): Use a bucket sorting algorithm if we know we're sorting + strings. This makes average case string sorting O(N) with O(N) additional + memory use. + + The worst case bucket sort can require O(M * N) additional + space. We avoid this by falling back to merge sort when things are + simple or overly duplicative. These are the two cases that accumulate + excessive -- and potentially pathological -- bucketing overhead. + +2015-06-01 Mark Lam <mark.lam@apple.com> + + HandlerInfo::initialize() should not assume that CodeLocationLabel is available. + https://bugs.webkit.org/show_bug.cgi?id=145515 + + Reviewed by Csaba Osztrogonác. + + CodeLocationLabel is only defined for ENABLE(ASSEMBLER) builds. r185022's + attempt at simplifying code to increase readability failed to take this into + account. This patch fixes it. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/HandlerInfo.h: + (JSC::HandlerInfo::initialize): + +2015-05-31 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, add a FIXME referencing https://bugs.webkit.org/show_bug.cgi?id=145503. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::inliningCost): + +2015-05-31 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Drop WeakMap#clear + https://bugs.webkit.org/show_bug.cgi?id=145489 + + Reviewed by Mark Lam. + + ES6 spec intentionally drops the WeakMap#clear + to allow engine to implement WeakMap as a per-object table. + + This patch drops WeakMap.prototype.clear. + + * runtime/WeakMapPrototype.cpp: + (JSC::WeakMapPrototype::finishCreation): Deleted. + (JSC::protoFuncWeakMapClear): Deleted. + +2015-05-31 Jordan Harband <ljharb@gmail.com> + + Array#reduce and reduceRight don't follow ToLength + https://bugs.webkit.org/show_bug.cgi?id=145364 + Per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + + Reviewed by Yusuke Suzuki. + + * builtins/Array.prototype.js: + (reduce): + (reduceRight): + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + (JSC::arrayProtoFuncReduce): Deleted. + (JSC::arrayProtoFuncReduceRight): Deleted. + +2015-05-29 Filip Pizlo <fpizlo@apple.com> + + FTL codegen for MultiGetByOffset and MultiPutByOffset where the structure set is already proved should have an unreachable default case instead of an exit + https://bugs.webkit.org/show_bug.cgi?id=145469 + + Reviewed by Geoffrey Garen. + + Omitting the speculation on the fail path when the speculation is guaranteed not to be + taken hints to LLVM that the default case is impossible. This enables some useful + optimizations. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset): + (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset): + +2015-05-29 Mark Lam <mark.lam@apple.com> + + Refactoring HandlerInfo and UnlinkedHandlerInfo. + https://bugs.webkit.org/show_bug.cgi?id=145480 + + Reviewed by Benjamin Poulain. + + HandlerInfo and UnlinkedHandlerInfo have common parts, but are not currently + expressed as 2 unrelated structs that happen to have near identical fields. + We can refactor them to better express their relationship. We can also add + some convenience functions to make the code that uses them a little more + readable. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::handlerForBytecodeOffset): + * bytecode/HandlerInfo.h: + (JSC::UnlinkedHandlerInfo::UnlinkedHandlerInfo): + (JSC::HandlerInfo::initialize): + - I chose to include CodeLocationLabel arg even though it is unused by + by non-JIT builds. This makes the call site cleaner to read. + + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedSimpleJumpTable::add): + (JSC::UnlinkedInstruction::UnlinkedInstruction): + (JSC::UnlinkedCodeBlock::numberOfExceptionHandlers): + (JSC::UnlinkedCodeBlock::addExceptionHandler): + (JSC::UnlinkedCodeBlock::exceptionHandler): + (JSC::UnlinkedCodeBlock::symbolTable): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + +2015-05-28 Filip Pizlo <fpizlo@apple.com> + + Non-speculative Branch should be fast in the FTL + https://bugs.webkit.org/show_bug.cgi?id=145452 + + Reviewed by Andreas Kling. + + Inlines the code for convertJSValueToBoolean into the FTL. This also includes some other + clean-ups that I found along the way. + + I found this by looking at the hottest functions in DeltaBlue. Despite having so many + Branch specializations, apparently there was still a hot one that we missed that was going + down the untyped path. It was either Int32 or Other. Maybe we could specialize for that + combo, but it makes so much sense to just make all of this nonsense fast. + + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): Need to watch the masquerades watchpoint on UntypedUse: forms of Branch now. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::boolify): The actual fix. + (JSC::FTL::LowerDFGToLLVM::int52ToStrictInt52): + (JSC::FTL::LowerDFGToLLVM::isInt32): + (JSC::FTL::LowerDFGToLLVM::isNotInt32): + (JSC::FTL::LowerDFGToLLVM::unboxInt32): + * runtime/JSCellInlines.h: + (JSC::JSCell::toBoolean): Symbol is always true. + (JSC::JSCell::pureToBoolean): Symbol is always true. + * runtime/JSString.cpp: + (JSC::JSString::getPrimitiveNumber): + (JSC::JSString::toNumber): + (JSC::JSString::toBoolean): Deleted. This is a tiny method. It doesn't need to be out-of-line. + * runtime/JSString.h: + (JSC::JSString::length): + (JSC::JSString::toBoolean): This method shouldbe inline. + * runtime/Symbol.cpp: + (JSC::Symbol::toPrimitive): + (JSC::Symbol::getPrimitiveNumber): + (JSC::Symbol::toBoolean): Deleted. A Symbol is always true, so we don't need a method for this. + * runtime/Symbol.h: + +2015-05-29 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r184860. + https://bugs.webkit.org/show_bug.cgi?id=145456 + + May have caused ~1% Octane regression (Requested by kling on + #webkit). + + Reverted changeset: + + "Try to use StringView when comparing JSStrings for equality." + https://bugs.webkit.org/show_bug.cgi?id=145379 + http://trac.webkit.org/changeset/184860 + +2015-05-28 Michael Saboff <msaboff@apple.com> + + mozilla/js1_5/Array/regress-154338.js test causes ARM 32 bit iOS devices to run out of memory + https://bugs.webkit.org/show_bug.cgi?id=145444 + + Reviewed by Geoffrey Garen. + + Disabled mozilla/js1_5/Array/regress-154338.js when run on iOS ARM 32 bit devices and + the --memory-limited option is passed to run-jsc-stress-tests. + + * tests/mozilla/mozilla-tests.yaml: + +2015-05-28 Benjamin Poulain <benjamin@webkit.org> + + [iOS8][ARMv7(s)] Optimized Object.create in 'use strict' context sometimes breaks. + https://bugs.webkit.org/show_bug.cgi?id=138038 + + Reviewed by Michael Saboff. + + TL;DR: sometimes the baseline JIT could accidentally nuke the tag before calling + to C++, making put_by_id behave erratically. + + The bug was that put_by_id would randomly not work correctly in 32bits. It happened + in the baseline JIT if we were unlucky enough: + -The code get hot enough and the structure is stable so we get a fast path for + put_by_id. + -We repatch the fast-path branch with a stub generated by + emitPutTransitionStubAndGetOldStructure(). + -In emitPutTransitionStubAndGetOldStructure(), we only preserve the payload of the base + register, the tag register is ignored. + -emitPutTransitionStubAndGetOldStructure() allocate 2 to 3 registers. Any of those + could be the one used for the base's tag before the fast path and the value is trashed. + -If we hit one of the failure case, we fallback to the slow path, but we destroyed + the tag pointer. + -We now have unrelated bits in the tag, the most likely value type is now "double" + and we fail the put_by_id because we try to set a property on a number. + + The most obvious solution would be to change emitPutTransitionStubAndGetOldStructure() + to preserve the tag register in addition to the value register. + I decided against that option because of the added complexity. The DFG does not need + that case, so I would have to add branches everywhere to distinguish the cases + were we need to preserve the tag or not. + + Instead, I just load the tag back from memory in the slow path. The function in the slow + path is several order of magnitude slower than a load, it is not worth eliminating it, + especially in baseline JIT. + + I also discovered 4 useless loads in the fast path, so even with my extra load, this patch + makes the baseline faster :) + + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitSlow_op_put_by_id): + (JSC::JIT::emit_op_put_by_id): Deleted. + * tests/stress/put-by-id-on-new-object-after-prototype-transition-non-strict.js: Added. + (opaqueNewObject): + (putValueOnNewObject): + * tests/stress/put-by-id-on-new-object-after-prototype-transition-strict.js: Added. + (string_appeared_here.opaqueNewObject): + (putValueOnNewObject): + +2015-05-28 Benjamin Poulain <benjamin@webkit.org> + + [JSC] reduction the iteration count of the DoubleRep stress tests + + Once again, I used big numbers for manual testing and I forgot to fix them before landing. + + * tests/stress/double-rep-with-non-cell.js: + * tests/stress/double-rep-with-null.js: + * tests/stress/double-rep-with-undefined.js: + +2015-05-28 Basile Clement <basile_clement@apple.com> + + Add debug mode assertions for accessors casting JSC::DFG::Node.m_opInfo + https://bugs.webkit.org/show_bug.cgi?id=145441 + + Reviewed by Filip Pizlo. + + Most accessor functions casting m_opInfo in JSC::DFG::Node are + performing debug checks that they are only accessed for node types that + should have them. This patch adds similar checks for the accessors that + were missing them. + + * dfg/DFGNode.h: + (JSC::DFG::Node::watchpointSet): + (JSC::DFG::Node::storagePointer): + (JSC::DFG::Node::multiGetByOffsetData): + (JSC::DFG::Node::multiPutByOffsetData): + (JSC::DFG::Node::hasTypeLocation): + (JSC::DFG::Node::typeLocation): + (JSC::DFG::Node::hasBasicBlockLocation): + (JSC::DFG::Node::basicBlockLocation): + +2015-05-28 Matt Rajca <mrajca@apple.com> + + Add ENABLE_MEDIA_SESSION feature flag (which is off by default). + https://bugs.webkit.org/show_bug.cgi?id=145415 + + Reviewed by Eric Carlson. + + * Configurations/FeatureDefines.xcconfig: + +2015-05-27 Jordan Harband <ljharb@gmail.com> + + Array.of should work with other constructors + https://bugs.webkit.org/show_bug.cgi?id=145365 + Per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.of + step 4 + + Reviewed by Yusuke Suzuki. + + * builtins/ArrayConstructor.js: + (of): + * runtime/ArrayConstructor.cpp: + (JSC::arrayConstructorOf): Deleted. + +2015-05-27 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Add undefined->double conversion to DoubleRep + https://bugs.webkit.org/show_bug.cgi?id=145293 + + Reviewed by Filip Pizlo. + + This patch adds undefined to double conversion to the DoubleRep + node for the cases were we speculate "undefined" as part of the types + processed. + + The use case is doing math with accidental out-of-bounds access. For example, + something like: + for (var i = 0; i <= length; ++i) + ouptput += array[i]; + + would cause us to OSR exit every time i === length. + + When hitting one of those cases, we would already speculate double math, + but the DoubleRep node was unable to convert the undefined and would exit. + + With this patch the use kind NotCellUse cover this conversion for DoubleRep. + I have been quite conservative so in general we will not find "undefined" + until a few recompile but being optimistic seems better since this is a corner case. + + This patch is a 80% progression on WebXPRT's DNA Sequencing test. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + * dfg/DFGNode.h: + (JSC::DFG::Node::sawUndefined): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::SafeToExecuteEdge::operator()): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileDoubleRep): + * dfg/DFGUseKind.cpp: + (WTF::printInternal): + * dfg/DFGUseKind.h: + (JSC::DFG::typeFilterFor): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): + * tests/stress/double-rep-with-undefined.js: Added. + (addArgsNumberAndUndefined): + (addArgsInt32AndUndefined): + (testFallbackWithDouble): + (addArgsDoubleAndUndefined): + (testFallbackWithObject.): + (testFallbackWithObject): + (addArgsOnlyUndefined): + (testFallbackWithString): + +2015-05-27 Dean Jackson <dino@apple.com> + + img.currentSrc problem in strict mode with old picturefill + https://bugs.webkit.org/show_bug.cgi?id=144095 + <rdar://problem/21087013> + + Reviewed by Simon Fraser. + + Add a PICTURE_SIZES flag. + + * Configurations/FeatureDefines.xcconfig: + +2015-05-27 Basile Clement <basile_clement@apple.com> + + LazyNode comparison can return incorrect results when comparing an empty value + https://bugs.webkit.org/show_bug.cgi?id=145421 + + Reviewed by Geoffrey Garen. + + When comparing a LazyNode to another, we compare the value pointers if + we have one, and otherwise compare the nodes. + We should be comparing value pointers if the other LazyNode has one as + well, otherwise we risk an incoherency when we are a empty LazyNode + being compared to a FrozenValue without node. + + Note that this is not a problem in any other case because if we don't + have a FrozenValue and we are not an empty LazyNode, we are a + non-constant node, and comparing the node pointers is correct. + + * dfg/DFGLazyNode.h: + (JSC::DFG::LazyNode::operator==): + +2015-05-27 Geoffrey Garen <ggaren@apple.com> + + REGRESSION: These sorting idioms used by Peacekeeper and Browsermark are ~20X slower + https://bugs.webkit.org/show_bug.cgi?id=145412 + + Reviewed by Benjamin Poulain. + + Cache strings when doing a string-converting sort. + + This is a 21% speedup. + + * builtins/Array.prototype.js: + (sort.stringComparator): Use subtraction instead of branching because + it's slightly faster. + + (sort.comparatorSort): + (sort.stringSort): + (sort): Add a special case for string sorting to avoid redundant string + conversion. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::createBindingPattern): Names can be empty if + they are private names. + +2015-05-26 Filip Pizlo <fpizlo@apple.com> + + JIT-generated store barrier code should assume the buffer pointer and capacity to be compile-time constants + https://bugs.webkit.org/show_bug.cgi?id=145404 + + Reviewed by Andreas Kling. + + We never change the capacity of a write barrier buffer. We never repoint the buffer + pointer. So, the JIT shouldn't load those from memory; it should take advantage of the + fact that these are compile-time constants. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::storeToWriteBarrierBuffer): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + * heap/WriteBarrierBuffer.h: + (JSC::WriteBarrierBuffer::currentIndexAddress): + (JSC::WriteBarrierBuffer::capacity): + (JSC::WriteBarrierBuffer::buffer): + (JSC::WriteBarrierBuffer::currentIndexOffset): Deleted. + (JSC::WriteBarrierBuffer::capacityOffset): Deleted. + (JSC::WriteBarrierBuffer::bufferOffset): Deleted. + * jit/Repatch.cpp: + (JSC::emitPutTransitionStubAndGetOldStructure): + +2015-05-27 Geoffrey Garen <ggaren@apple.com> + + REGRESSION: These sorting idioms used by Peacekeeper and Browsermark are ~20X slower + https://bugs.webkit.org/show_bug.cgi?id=145412 + + Reviewed by Darin Adler. + + Use @toString instead of the String constructor because calls to the + String constructor are never optimized. (See + https://bugs.webkit.org/show_bug.cgi?id=144458.) + + This is a ~2X speedup. + + * builtins/Array.prototype.js: + (sort.stringComparator): + +2015-05-27 Dan Bernstein <mitz@apple.com> + + Remove JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 + https://bugs.webkit.org/show_bug.cgi?id=145403 + + Reviewed by Anders Carlsson. + + JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 was used to enable the JavaScriptCore Objective-C API + for WebKit and Safari projects building with JavaScriptCore targeting OS X 10.8. We donât + need it anymore. + + * API/JSBase.h: + * API/JSContext.h: + * API/JSManagedValue.h: + * API/JSValue.h: + * API/JSVirtualMachine.h: + * Configurations/Base.xcconfig: + * postprocess-headers.sh: + +2015-05-26 Geoffrey Garen <ggaren@apple.com> + + Photo Booth hangs under JSC::MachineThreads::tryCopyOtherThreadStacks + https://bugs.webkit.org/show_bug.cgi?id=145395 + + Reviewed by Mark Hahnenberg. + + No test case because we already have --threaded mode, which runs lots of + parallel GC, but it (and the original in-app test case) can't reproduce + this bug. + + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::tryCopyOtherThreadStacks): Use a lock to prevent + two threads from mutually suspending each other. + +2015-05-26 Yusuke Suzuki <utatane.tea@gmail.com> + + Add Array.prototype.copyWithin to JSC features.json + https://bugs.webkit.org/show_bug.cgi?id=145387 + + Reviewed by Darin Adler. + + * features.json: + +2015-05-26 Yusuke Suzuki <utatane.tea@gmail.com> + + Reflect nits for r184863 + https://bugs.webkit.org/show_bug.cgi?id=145107 + + Reviewed by Darin Adler. + + 1. Added the copyright line. + 2. Added an optional argument (/*, end */). To do so, fixed generate-js-builtins. + 3. Dropped the unnecessary variable `thisValue`. + 4. Fix the type error messages. This is also found in StringIterator.prototype.js. + 5. Added tests for 0 arguments. + + * builtins/Array.prototype.js: + (copyWithin): + * builtins/StringIterator.prototype.js: + (next): + * generate-js-builtins: + * tests/stress/array-copywithin.js: + * tests/stress/string-iterators.js: + +2015-05-26 Yusuke Suzuki <utatane.tea@gmail.com> + + Inline @Array / @Object callsites + https://bugs.webkit.org/show_bug.cgi?id=145382 + + Reviewed by Geoffrey Garen. + + As the same to Array/Object callsite inlining, @Array/@Object also + should be inlined in bytecode level. + While `new @Object` style is not encouraged in the builtins, + `@Array(len)` is already used at least in Array.from code. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::expectedFunctionForIdentifier): + +2015-05-26 Andreas Kling <akling@apple.com> + + String.prototype.charCodeAt() should use StringView. + <https://webkit.org/b/145353> + + Reviewed by Darin Adler. + + Use JSString::view() in charCodeAt() to avoid reifying the JSString if it's + a substring. This avoids StringImpl allocation in some cases and ref churn + in all cases. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncCharCodeAt): + +2015-05-26 Andreas Kling <akling@apple.com> + + String.prototype.charAt() should use StringView. + <https://webkit.org/b/145352> + + Reviewed by Darin Adler. + + Remove the jsSingleCharacterSubstring() function since it's actually completely + counter-productive: it could create a single-character string that would retain + a much larger string for the duration of its lifetime. + + This made sense before StringImpl learned to put its characters at the tail end + of its own allocation. Now that it does, it's far better to just create a new + single-character StringImpl. + + With that out of the way, we can make String.prototype.charAt() use StringView + to avoid reifying substring JSStrings (and avoid some ref churn too.) + + * runtime/JSString.cpp: + (JSC::JSRopeString::getIndexSlowCase): + * runtime/JSString.h: + (JSC::JSString::getIndex): + (JSC::jsSingleCharacterSubstring): Deleted. + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncCharAt): + (JSC::stringProtoFuncSplit): + +2015-05-26 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement Array.prototype.copyWithin + https://bugs.webkit.org/show_bug.cgi?id=145107 + + Reviewed by Darin Adler. + + This patch implements ES6 Array.prototype.copyWithin. + It is intended to be used for copying the region to the other region + in the callee array itself safely (like memmove, not memcpy). + This function is proposed in the context of WebGL. + + * builtins/Array.prototype.js: + (.maxWithPositives): + (.minWithMaybeNegativeZeroAndPositive): + (copyWithin): + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + * tests/stress/array-copywithin.js: Added. + (shouldBe): + (shouldBeArray): + (shouldThrow): + (arrayToObject): + (valueOf): + +2015-05-26 Dan Bernstein <mitz@apple.com> + + <rdar://problem/21104551> Update build settings + + Reviewed by Anders Carlsson. + + * Configurations/DebugRelease.xcconfig: + * Configurations/FeatureDefines.xcconfig: + * Configurations/Version.xcconfig: + +2015-05-26 Andreas Kling <akling@apple.com> + + Try to use StringView when comparing JSStrings for equality. + <https://webkit.org/b/145379> + + Reviewed by Darin Adler. + + Use JSString::view() when sending two JSStrings to WTF::equal() + for comparison. This avoids creating new objects in the case where + the strings are actually substrings. + + * jit/JITOperations.cpp: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::equalSlowCaseInline): + (JSC::JSValue::strictEqualSlowCaseInline): + +2015-05-26 Yusuke Suzuki <utatane.tea@gmail.com> + + [JSC] Generate put_by_val_direct for indexed identifiers instead of put_by_id with direct postfix + https://bugs.webkit.org/show_bug.cgi?id=145360 + + Reviewed by Darin Adler. + + JSObject::putDirect only accepts non-indexed properties. + So when generating put_by_id (with direct postfix) for indexed property, + we should generate put_by_val_direct instead. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitDirectPutById): + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitPutConstantProperty): + * tests/stress/put-by-id-direct-should-be-done-for-non-index-property.js: Added. + +2015-05-24 Jordan Harband <ljharb@gmail.com> + + Array#findIndex/find should not skip holes + https://bugs.webkit.org/show_bug.cgi?id=145361 + per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.findindex + and https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.find + + Reviewed by Yusuke Suzuki. + + * builtins/Array.prototype.js: + (find): Deleted. + (findIndex): Deleted. + +2015-05-24 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: Uncaught exception when using Inspect tool on SVG elements + https://bugs.webkit.org/show_bug.cgi?id=145363 + + Reviewed by Joseph Pecoraro. + + The injected script failed by chaining a call to String.prototype.trim to the result of + SVG*Element.className, which is an SVGAnimatedString and lacks useful methods. So, obtain + the class name using Node.getAttribute, which always returns a DOMString. + + * inspector/InjectedScriptSource.js: + (InjectedScriptSource.prototype._getDescription): use getAttribute instead of className. + +2015-05-23 Dan Bernstein <mitz@apple.com> + + Remove unused definitions of WEBKIT_VERSION_MIN_REQUIRED + https://bugs.webkit.org/show_bug.cgi?id=145345 + + Reviewed by Sam Weinig. + + * Configurations/Base.xcconfig: Also changed to use $(inherited). + +2015-05-23 Yusuke Suzuki <utatane.tea@gmail.com> + + Introduce UniquedStringImpl and SymbolImpl to separate symbolic strings from AtomicStringImpl + https://bugs.webkit.org/show_bug.cgi?id=144848 + + Reviewed by Darin Adler. + + Use UniquedStringImpl, SymbolImpl and AtomicStringImpl. + + * API/JSCallbackObject.h: + * builtins/BuiltinNames.h: + (JSC::BuiltinNames::isPrivateName): + * bytecode/BytecodeIntrinsicRegistry.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/ComplexGetStatus.cpp: + (JSC::ComplexGetStatus::computeFor): + * bytecode/ComplexGetStatus.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + (JSC::GetByIdStatus::computeFor): + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdStatus.h: + * bytecode/Instruction.h: + (JSC::Instruction::Instruction): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::visibleNameForParameter): + (JSC::BytecodeGenerator::hasConstant): + (JSC::BytecodeGenerator::addConstant): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitBytecode): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGDesiredIdentifiers.cpp: + (JSC::DFG::DesiredIdentifiers::addLazily): + (JSC::DFG::DesiredIdentifiers::at): + (JSC::DFG::DesiredIdentifiers::reallyAdd): + * dfg/DFGDesiredIdentifiers.h: + (JSC::DFG::DesiredIdentifiers::operator[]): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::isStringPrototypeMethodSane): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIn): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::identifierUID): + (JSC::DFG::SpeculativeJIT::callOperation): + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLInlineCacheDescriptor.h: + (JSC::FTL::InlineCacheDescriptor::InlineCacheDescriptor): + (JSC::FTL::InlineCacheDescriptor::uid): + (JSC::FTL::GetByIdDescriptor::GetByIdDescriptor): + (JSC::FTL::PutByIdDescriptor::PutByIdDescriptor): + (JSC::FTL::CheckInDescriptor::CheckInDescriptor): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compilePutById): + (JSC::FTL::LowerDFGToLLVM::compileIn): + (JSC::FTL::LowerDFGToLLVM::compileMaterializeCreateActivation): + (JSC::FTL::LowerDFGToLLVM::getById): + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): + * ftl/FTLSlowPathCall.cpp: + (JSC::FTL::callOperation): + * ftl/FTLSlowPathCall.h: + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * parser/Nodes.cpp: + (JSC::ProgramNode::setClosedVariables): + * parser/Nodes.h: + (JSC::ScopeNode::captures): + (JSC::ScopeNode::setClosedVariables): + (JSC::ProgramNode::closedVariables): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): + (JSC::Parser<LexerType>::didFinishParsing): + (JSC::Parser<LexerType>::parseContinueStatement): + * parser/Parser.h: + (JSC::Scope::Scope): + (JSC::Scope::pushLabel): + (JSC::Scope::getLabel): + (JSC::Scope::declareCallee): + (JSC::Scope::declareVariable): + (JSC::Scope::declareParameter): + (JSC::Scope::declareBoundParameter): + (JSC::Scope::useVariable): + (JSC::Scope::copyCapturedVariablesToVector): + (JSC::Parser::closedVariables): + (JSC::ScopeLabelInfo::ScopeLabelInfo): Deleted. + * parser/SourceProviderCacheItem.h: + (JSC::SourceProviderCacheItem::usedVariables): + (JSC::SourceProviderCacheItem::writtenVariables): + (JSC::SourceProviderCacheItem::create): + * runtime/CommonIdentifiers.cpp: + (JSC::CommonIdentifiers::isPrivateName): + * runtime/CommonIdentifiers.h: + * runtime/Identifier.h: + (JSC::Identifier::impl): + (JSC::Identifier::Identifier): + (JSC::parseIndex): + (JSC::IdentifierRepHash::hash): + * runtime/IdentifierInlines.h: + (JSC::Identifier::fromUid): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::mayInterceptStoreTo): + * runtime/IntendedStructureChain.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/Lookup.h: + (JSC::HashTable::entry): + * runtime/MapData.h: + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertySymbols): + * runtime/PrivateName.h: + (JSC::PrivateName::PrivateName): + (JSC::PrivateName::uid): + * runtime/PropertyMapHashTable.h: + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + (JSC::PropertyName::uid): + (JSC::PropertyName::publicName): + (JSC::parseIndex): + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArray::addKnownUnique): + (JSC::PropertyNameArray::add): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::StructureTransitionTable::add): + (JSC::Structure::addPropertyTransitionToExistingStructureImpl): + (JSC::Structure::addPropertyTransitionToExistingStructureConcurrently): + (JSC::Structure::getConcurrently): + (JSC::Structure::add): + (JSC::Structure::remove): + (JSC::Structure::toStructureShape): + * runtime/Structure.h: + (JSC::PropertyMapEntry::PropertyMapEntry): + * runtime/StructureInlines.h: + (JSC::Structure::getConcurrently): + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTable::Hash::hash): + * runtime/Symbol.cpp: + (JSC::Symbol::Symbol): + * runtime/Symbol.h: + * runtime/SymbolConstructor.cpp: + (JSC::symbolConstructorFor): + (JSC::symbolConstructorKeyFor): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::uniqueIDForVariable): + (JSC::SymbolTable::globalTypeSetForVariable): + * runtime/SymbolTable.h: + * runtime/TypeSet.cpp: + (JSC::StructureShape::addProperty): + (JSC::StructureShape::propertyHash): + * runtime/TypeSet.h: + +2015-05-21 Filip Pizlo <fpizlo@apple.com> + + Arguments elimination phase mishandles arity check failure in its reduction of LoadVarargs to GetStack/PutStacks + https://bugs.webkit.org/show_bug.cgi?id=145298 + + Reviewed by Geoffrey Garen. + + * dfg/DFGArgumentsEliminationPhase.cpp: Fix the bug. I restructured the loop to make it more obvious that we're initializing everything that we're supposed to initialize. + * dfg/DFGNode.h: Add a comment to clarify something I was confused about while writing this code. + * dfg/DFGPutStackSinkingPhase.cpp: Hacking on PutStacks made me think deep thoughts, and I added some FIXMEs. + * tests/stress/fold-load-varargs-arity-check-fail-barely.js: Added. This test crashes or fails before this patch. + * tests/stress/fold-load-varargs-arity-check-fail.js: Added. This is even more sure to crash or fail. + * tests/stress/simplify-varargs-mandatory-minimum-smaller-than-limit.js: Added. Not sure if we had coverage for this case before. + +2015-05-22 Basile Clement <basile_clement@apple.com> + + Allow DFGClobberize to return non-node constants that must be later created + https://bugs.webkit.org/show_bug.cgi?id=145272 + + Reviewed by Filip Pizlo. + + This adds a new LazyNode class in DFG that represents either a Node*, + or a FrozenValue* with a way to convert it to a Node* provided a block + to insert it into. DFGClobberize is converted to use LazyNode instead + of Node* when def()'ing values, which allows to now define the array's + length as well as the value of its various fields in NewArray and + NewArrayBuffer nodes. + + We also introduce a Vector<uint32_t> in DFG::Graph to collect all the + values that can be used as index, in order to avoid def()'ing too many + values at once for big NewArrayBuffers. + + HeapLocation had to be updated to use a LazyNode as its index to be + able to define array values. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGCSEPhase.cpp: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + (JSC::DFG::DefMethodClobberize::operator()): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::freezeFragile): + * dfg/DFGGraph.h: + * dfg/DFGHeapLocation.h: + (JSC::DFG::HeapLocation::HeapLocation): + (JSC::DFG::HeapLocation::index): + (JSC::DFG::HeapLocation::hash): + * dfg/DFGLazyNode.cpp: Added. + (JSC::DFG::LazyNode::dump): + * dfg/DFGLazyNode.h: Added. + (JSC::DFG::LazyNode::LazyNode): + (JSC::DFG::LazyNode::setNode): + (JSC::DFG::LazyNode::isHashTableDeletedValue): + (JSC::DFG::LazyNode::isNode): + (JSC::DFG::LazyNode::op): + (JSC::DFG::LazyNode::asNode): + (JSC::DFG::LazyNode::asValue): + (JSC::DFG::LazyNode::hash): + (JSC::DFG::LazyNode::operator==): + (JSC::DFG::LazyNode::operator!=): + (JSC::DFG::LazyNode::ensureIsNode): + (JSC::DFG::LazyNode::operator->): + (JSC::DFG::LazyNode::operator*): + (JSC::DFG::LazyNode::operator!): + (JSC::DFG::LazyNode::operator UnspecifiedBoolType*): + (JSC::DFG::LazyNode::setFrozenValue): + * dfg/DFGPreciseLocalClobberize.h: + (JSC::DFG::PreciseLocalClobberizeAdaptor::def): + * dfg/DFGPutStackSinkingPhase.cpp: + +2015-05-22 Andreas Kling <akling@apple.com> + + [JSC] Speed up new array construction in Array.prototype.splice(). + <https://webkit.org/b/145303> + + Reviewed by Benjamin Poulain. + + Give splice() a fast path just like slice(), for indexing types where the backing + store can be memcpy'd. I generalized JSArray::fastSlice() a little bit so it works + for this optimization as well. + + 7% progression on Kraken/stanford-crypto-pbkdf2. + + * runtime/JSArray.h: + * runtime/JSArray.cpp: + (JSC::JSArray::fastSlice): Tweak this to return JSArray*, and don't bother throwing + out-of-memory exceptions. Let the caller worry about that. + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSlice): Update for fastSlice() changes. + (JSC::arrayProtoFuncSplice): If the object we're splicing out of is a bona fide + JSArray, use fastSlice() to create the returned array instead of doing a generic + get/put loop. + +2015-05-21 Filip Pizlo <fpizlo@apple.com> + + CPS rethreading should really get rid of GetLocals + https://bugs.webkit.org/show_bug.cgi?id=145290 + + Reviewed by Benjamin Poulain. + + CPS rethreading is intended to get rid of redundant GetLocals. CSE can also do it, but + the idea is that you should be able to disable CSE and everything would still work. This + fixes a bug in CPS rethreading's GetLocal elimination: we should be calling replaceWith + rather than setReplacement, since setReplacement still leaves the original node. + + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::canonicalizeGetLocalFor): Fix the bug. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): Eliminating GetLocals means that they turn into Check. We should handle Checks that have zero inputs. + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): Add a validation for what a GetLocal should look like in ThreadedCPS. + * tests/stress/get-local-elimination.js: Added. + (foo): + +2015-05-21 Saam Barati <saambarati1@gmail.com> + + Object allocation sinking phase should explicitly create bottom values for CreateActivation sink candidates and CreateActivation should have SymbolTable as a child node + https://bugs.webkit.org/show_bug.cgi?id=145192 + + Reviewed by Filip Pizlo. + + When we sink CreateActivation and generate MaterializeCreateActivation + in the object allocation sinking phase, we now explictly add PutHints for + all variables on the activation setting those variables to their default value + (undefined for Function activations and soon to be JS Empty Value for block scope activations). + This allows us to remove code that fills FTL fast activation allocations with Undefined. + + This patch also adds the constant SymbolTable as an OpInfo of CreateActivation and MaterializeCreateActivation + nodes. This is in preparation for ES6 block scoping which will introduce a new + op code that gets lowered to CreateActivation. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasCellOperand): + (JSC::DFG::Node::cellOperand): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize): + (JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize): + * dfg/DFGPromotedHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGPromotedHeapLocation.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCreateActivation): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCreateActivation): + (JSC::FTL::LowerDFGToLLVM::compileMaterializeCreateActivation): + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): + * tests/stress/activation-sink-default-value.js: Added. + (bar): + * tests/stress/activation-sink-osrexit-default-value.js: Added. + (foo.set result): + +2015-05-21 Per Arne Vollan <peavo@outlook.com> + + MSVC internal compiler error when compiling TemplateRegistryKey class. + https://bugs.webkit.org/show_bug.cgi?id=145259 + + Reviewed by Alex Christensen. + + MSVC is not able to handle the brace initialization of a class member in this case. + + * runtime/TemplateRegistryKey.h: + +2015-05-21 Csaba Osztrogonác <ossy@webkit.org> + + Fix the !ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) build after r184337 + https://bugs.webkit.org/show_bug.cgi?id=145248 + + Reviewed by Yusuke Suzuki. + + * bytecompiler/BytecodeGenerator.cpp: + * bytecompiler/BytecodeGenerator.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseMemberExpression): + +2015-05-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: array previews should have a much smaller cap on values + https://bugs.webkit.org/show_bug.cgi?id=145195 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.RemoteObject.prototype._generatePreview): + Reduce the indexes threshold for previews. + +2015-05-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Use native Arguments detection instead of using toString + https://bugs.webkit.org/show_bug.cgi?id=145235 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.prototype._subtype): + Deleted the old string code. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + Replaced with a stricter, more accurate check. + +2015-05-20 Andreas Kling <akling@apple.com> + + Remove unused MarkedBlock::m_rememberedSet. + <https://webkit.org/b/145224> + + Reviewed by Mark Hahnenberg. + + The MarkedBlock had a copy of the remembered bit for each of its cells, + and we were maintaining that bitmap despite no one actually ever consulting it. + + This patch removes MarkedBlock::m_rememberedSet, freeing up 128 bytes in each + block and making write barriers a little faster. + + * heap/Heap.cpp: + (JSC::Heap::clearRememberedSet): + (JSC::Heap::addToRememberedSet): + * heap/HeapInlines.h: + (JSC::Heap::isRemembered): + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::clearRememberedSet): Deleted. + (JSC::MarkedBlock::clearMarksWithCollectionType): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::setRemembered): Deleted. + (JSC::MarkedBlock::clearRemembered): Deleted. + (JSC::MarkedBlock::atomicClearRemembered): Deleted. + (JSC::MarkedBlock::isRemembered): Deleted. + * heap/MarkedSpace.h: + (JSC::ClearRememberedSet::operator()): Deleted. + (JSC::MarkedSpace::clearRememberedSet): Deleted. + +2015-05-20 Andreas Kling <akling@apple.com> + + Eden collections should extend the IncrementalSweeper work list, not replace it. + <https://webkit.org/b/145213> + <rdar://problem/21002666> + + Reviewed by Geoffrey Garen. + + After an eden collection, the garbage collector was adding all MarkedBlocks containing + new objects to the IncrementalSweeper's work list, to make sure they didn't have to + wait until the next full collection before getting swept. + + Or at least, that's what it thought it was doing. It turns out that IncrementalSweeper's + internal work list is really just a reference to Heap::m_blockSnapshot. I didn't realize + this when writing the post-eden sweep code, and instead made eden collections cancel + all pending sweeps and *replace* them with the list of blocks with new objects. + + This made it so that rapidly occurring eden collections could prevent large numbers of + heap blocks from ever getting swept. This would manifest as accumulation of MarkedBlocks + when a system under heavy load was also allocating short lived objects at a high rate. + Things would eventually get cleaned up when there was a lull and a full collection was + allowed to run its heap sweep to completion. + + Fix this by moving all management of the block snapshot to Heap. snapshotMarkedSpace() + now handles eden collections by merging the list of blocks with new objects into the + existing block snapshot. + + * heap/Heap.cpp: + (JSC::Heap::snapshotMarkedSpace): + (JSC::Heap::notifyIncrementalSweeper): + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::startSweeping): + (JSC::IncrementalSweeper::addBlocksAndContinueSweeping): Deleted. + * heap/IncrementalSweeper.h: + +2015-05-20 Youenn Fablet <youenn.fablet@crf.canon.fr> + + AudioContext resume/close/suspend should reject promises with a DOM exception in lieu of throwing exceptions + https://bugs.webkit.org/show_bug.cgi?id=145064 + + Reviewed by Darin Adler. + + Added default message for TypeError. + + * runtime/Error.cpp: + (JSC::throwTypeError): + * runtime/Error.h: + +2015-05-20 Joseph Pecoraro <pecoraro@apple.com> + + No LLInt Test Failure: jsc-layout-tests.yaml/js/script-tests/object-literal-duplicate-properties.js.layout-no-llint + https://bugs.webkit.org/show_bug.cgi?id=145219 + + Reviewed by Mark Lam. + + * jit/JITOperations.cpp: + Throw the error we just got, instead of a stack overflow exception. + This matches other error handling for callers of prepareForExecution. + +2015-05-19 Filip Pizlo <fpizlo@apple.com> + + Add some assertions about the CFG in the loop pre-header creation phase + https://bugs.webkit.org/show_bug.cgi?id=145205 + + Reviewed by Geoffrey Garen. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::currentNodeOrigin): Add a FIXME. + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::run): Add a FIXME. + * dfg/DFGLoopPreHeaderCreationPhase.cpp: + (JSC::DFG::LoopPreHeaderCreationPhase::run): Add the assertions. + +2015-05-20 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Implement Object.setPrototypeOf + https://bugs.webkit.org/show_bug.cgi?id=145202 + + Reviewed by Darin Adler. + + * runtime/JSGlobalObjectFunctions.h: + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncProtoSetter): + (JSC::checkProtoSetterAccessAllowed): + Extract a helper to share this code between __proto__ setter and setPrototypeOf. + + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorSetPrototypeOf): + Implementation is very similiar to __proto__ setter. + +2015-05-20 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Should not allow duplicate basic __proto__ properties in Object Literals + https://bugs.webkit.org/show_bug.cgi?id=145138 + + Reviewed by Darin Adler. + + Implement ES6 Annex B.3.1, which disallows duplicate basic __proto__ + properties in object literals. This doesn't affect computed properties, + shorthand properties, or getters/setters all of which avoid setting + the actual prototype of the object anyway. + + * interpreter/Interpreter.cpp: + (JSC::eval): + Remove out of date comment. Duplicate property names are allowed + now in ES6, they were not in ES5 strict mode. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::getName): + (JSC::ASTBuilder::getType): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::getName): + Add back getName to get the property name depending on the tree builder. + Also tighten up the parameter types. + + * runtime/LiteralParser.cpp: + (JSC::LiteralParser<CharType>::parse): + In quick JSON literal parsing for eval, we actually need to evaluate + the __proto__ property assignment, instead of just building up a list + of direct properties. Only do this when not doing a strict JSON parse. + + * parser/Nodes.h: + Add "Shorthand" to the list of PropertyNode types to allow it to + be distinguished without relying on other information. + + * parser/Parser.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseProperty): + Add the Shorthand type when parsing a shorthand property. + + (JSC::Parser<LexerType>::shouldCheckPropertyForUnderscoreProtoDuplicate): + (JSC::Parser<LexerType>::parseObjectLiteral): + (JSC::Parser<LexerType>::parseStrictObjectLiteral): + Check for duplicate __proto__ properties, and throw a SyntaxError + if that was the case. + +2015-05-20 Csaba Osztrogonác <ossy@webkit.org> + + [JSC] Add missing copyrights and licenses for some scripts + https://bugs.webkit.org/show_bug.cgi?id=145044 + + Reviewed by Darin Adler. + + * build-symbol-table-index.py: + * create-llvm-ir-from-source-file.py: + * create-symbol-table-index.py: + +2015-05-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Slightly better node previews in arrays + https://bugs.webkit.org/show_bug.cgi?id=145188 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.prototype._nodeDescription): + (InjectedScript.prototype._nodePreview): + Different stringified representations for a basic object description or in a preview. + + (InjectedScript.RemoteObject.prototype._appendPropertyPreviews): + Use the node preview string representation inside previews. + +2015-05-19 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r184613 and r184614. + https://bugs.webkit.org/show_bug.cgi?id=145206 + + Broke 10 tests :| (Requested by kling on #webkit). + + Reverted changesets: + + "[JSC] Speed up URL encode/decode by using bitmaps instead of + strchr()." + https://bugs.webkit.org/show_bug.cgi?id=145115 + http://trac.webkit.org/changeset/184613 + + "[JSC] Speed up URL encode/decode by using bitmaps instead of + strchr()." + https://bugs.webkit.org/show_bug.cgi?id=145115 + http://trac.webkit.org/changeset/184614 + +2015-05-19 Andreas Kling <akling@apple.com> + + Give StringView a utf8() API. + <https://webkit.org/b/145201> + + Reviewed by Anders Carlsson. + + Use JSString::view() in a few places where we couldn't before due to StringView + lacking a utf8() API. This is a minor speed-up on Kraken's crypto subtests, + which like to call encode() with substring JSStrings. + + * jsc.cpp: + (functionPrint): + (functionDebug): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::encode): + +2015-05-19 Andreas Kling <akling@apple.com> + + [JSC] Speed up URL encode/decode by using bitmaps instead of strchr(). + <https://webkit.org/b/145115> + + Incorporate review feedback from Darin, removing some unnecessary zero checks. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::encode): + (JSC::decode): + (JSC::globalFuncEscape): + +2015-05-19 Yusuke Suzuki <utatane.tea@gmail.com> + + Move AtomicStringImpl table related operations from AtomicString to AtomicStringImpl + https://bugs.webkit.org/show_bug.cgi?id=145109 + + Reviewed by Darin Adler. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::nameForRegister): + * runtime/Identifier.cpp: + (JSC::Identifier::add): + (JSC::Identifier::add8): + * runtime/Identifier.h: + (JSC::Identifier::add): + * runtime/IdentifierInlines.h: + (JSC::Identifier::Identifier): + (JSC::Identifier::add): + * runtime/JSString.cpp: + (JSC::JSRopeString::resolveRopeToExistingAtomicString): + * runtime/JSString.h: + (JSC::JSString::toExistingAtomicString): + * runtime/SmallStrings.cpp: + (JSC::SmallStringsStorage::SmallStringsStorage): + * runtime/TypeSet.cpp: + (JSC::StructureShape::propertyHash): + +2015-05-19 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Improve Preview for NodeList / array like collections + https://bugs.webkit.org/show_bug.cgi?id=145177 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + (InjectedScript.RemoteObject.prototype._appendPropertyPreviews): + For "array" like object previews skip over non-index properties. + We are not marking the object as lossless by choice, but we + may return to this decision later. + +2015-05-19 Michael Saboff <msaboff@apple.com> + + REGRESSION(183787): JIT is enabled for all builds + https://bugs.webkit.org/show_bug.cgi?id=145179 + + Reviewed by Geoffrey Garen. + + Eliminated the setting of ENABLE_JIT, as wtf/Platform.h has appropriate logic to + set it depending on OS and CPU type. + + * Configurations/FeatureDefines.xcconfig: + +2015-05-19 Youenn Fablet <youenn.fablet@crf.canon.fr> + + Rename createIterResultObject as createIteratorResultObject + https://bugs.webkit.org/show_bug.cgi?id=145116 + + Reviewed by Darin Adler. + + Renamed createIterResultObject as createIteratorResultObject. + Made this function exportable for future use by streams API. + + * runtime/IteratorOperations.cpp: + (JSC::createIteratorResultObject): + * runtime/IteratorOperations.h: + * runtime/MapIteratorPrototype.cpp: + (JSC::MapIteratorPrototypeFuncNext): + * runtime/SetIteratorPrototype.cpp: + (JSC::SetIteratorPrototypeFuncNext): + +2015-05-19 Yusuke Suzuki <utatane.tea@gmail.com> + + Array.prototype methods must use ToLength + https://bugs.webkit.org/show_bug.cgi?id=144128 + + Reviewed by Oliver Hunt. + + Patch by Jordan Harband <ljharb@gmail.com> and Yusuke Suzuki <utatane.tea@gmail.com> + + Per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + + This patch introduces ToLength and ToInteger JS implementation to encourage the DFG/FTL's inlining. + These implementations are located in GlobalObject.js. + And set to the JSGlobalObject with the private symbols @ToLength and @ToInteger manually. + + * builtins/Array.prototype.js: + (every): + (forEach): + (filter): + (map): + (some): + (fill): + (find): + (findIndex): + (includes): + * builtins/ArrayConstructor.js: + (from): + * builtins/GlobalObject.js: Copied from Source/JavaScriptCore/builtins/StringConstructor.js. + (ToInteger): + (ToLength): + * builtins/StringConstructor.js: + (raw): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObjectFunctions.h: + +2015-05-19 Mark Lam <mark.lam@apple.com> + + Fix the build of a universal binary with ARMv7k of JavaScriptCore. + https://bugs.webkit.org/show_bug.cgi?id=145143 + + Reviewed by Geoffrey Garen. + + The offlineasm works in 3 phases: + + Phase 1: + Parse the llint asm files for config options and desired offsets. + Let's say the offlineasm discovers C unique options and O unique offsets. + The offlineasm will then generate a LLIntDesiredOffsets.h file with + C x C build configurations, each with a set of O offsets. + + Each of these build configurations is given a unique configuration index number. + + Phase 2: + Compile the LLIntDesiredOffsets.h file into a JSCLLIntOffsetsExtractor binary. + + If we're building a fat binary with 2 configurations: armv7, and armv7k, + then the fat binary will contain 2 blobs of offsets, one for each of these + build configurations. + + Phase 3: + Parse the llint asm files and emit asm code using the offsets that are + extracted from the JSCLLIntOffsetsExtractor binary for the corresponding + configuration index number. + + In the pre-existing code, there are no "if ARMv7k" statements in the llint asm + source. As a result, OFFLINE_ASM_ARMv7k is not one of the config options in + the set of C unique options. + + For armv7k builds, OFFLINE_ASM_ARMv7 is also true. As a result, for an armv7k + target, we will end up building armv7 source. In general, this is fine except: + + 1. armv7k has different alignment requirements from armv7. Hence, their offset + values (in JSCLLIntOffsetsExtractor) will be different. + + 2. The offlineasm was never told that it needed to make a different configuration + for armv7k builds. Hence, the armv7k build of LLIntDesiredOffsets.h will + build the armv7 configuration, and consequently, the armv7k blob of offsets in + JSCLLIntOffsetsExtractor will have the same configuration index number as + the armv7 blob of offsets. + + In phase 3, when the offlineasm parses the JSCLLIntOffsetsExtractor fat binary + looking for the armv7 build's configuration index number, it discovers the + armv7k blob which has the same configuration number. As a result, it + erroneously thinks the armv7k offsets are appropriate for emitting armv7 code. + Needless to say, armv7 code using armv7k offsets will lead to incorrect behavior + and all round badness. + + The fix is to add a simple "if ARMv7k" statement to the llint asm files. While + the if statement has no body, it does make the offlineasm aware of the need for + ARMv7k as a configuration option. As a result, it will generate an armv7k + variant configuration in the LLIntDesiredOffsets.h file with its own unique + configuration index number. With that, the JSCLLIntOffsetsExtractor fat binary + will no longer have duplicate configuration index numbers for the armv7 and + armv7k blobs of offsets, and the issue is resolved. + + * llint/LLIntOfflineAsmConfig.h: + * llint/LowLevelInterpreter.asm: + +2015-05-19 Andreas Kling <akling@apple.com> + + Give JSString a StringView getter and start using it. + <https://webkit.org/b/145131> + + Reviewed by Anders Carlsson. + + When JSString is a substring internally, calling value(ExecState*) on it + will reify the baseString/start/length tuple into a new StringImpl. + + For clients that only want to look at the characters of a JSString, but + don't actually need a reffable StringImpl, adding a light-weight StringView + getter lets them avoid constructing anything. + + This patch adds JSString::view(ExecState*) and uses it in a few places. + There are many more opportunities to use this API, but let's do a few things + at a time. + + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::decode): + (JSC::parseInt): + (JSC::jsToNumber): + (JSC::parseFloat): + (JSC::globalFuncParseInt): + (JSC::globalFuncParseFloat): + (JSC::globalFuncEscape): + (JSC::globalFuncUnescape): + * runtime/JSGlobalObjectFunctions.h: + * runtime/JSONObject.cpp: + (JSC::JSONProtoFuncParse): + * runtime/JSString.cpp: + (JSC::JSString::getPrimitiveNumber): + (JSC::JSString::toNumber): + * runtime/JSString.h: + (JSC::JSRopeString::view): + (JSC::JSString::view): + +2015-05-18 Filip Pizlo <fpizlo@apple.com> + + Better optimize 'if' with ternaries conditional tests. + https://bugs.webkit.org/show_bug.cgi?id=144136 + + Reviewed by Benjamin Poulain. + + This is the last fix I'll do for this for now. BooleanToNumber(Untyped:) where the input + is proved to be either BoolInt32 or Boolean should be optimized to just masking the + lowest bit. + + This is another 37% speed-up on JSRegress/slow-ternaries. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber): + +2015-05-18 Benjamin Poulain <bpoulain@apple.com> + + <rdar://problem/21003555> cloberrize() is wrong for ArithRound because it doesn't account for the arith mode + https://bugs.webkit.org/show_bug.cgi?id=145147 + + Reviewed by Filip Pizlo. + + Really stupid bug: ArithRound nodes with different rounding modes + were not distinguished and CSE would happily unify with a node of + a different rounding mode. + + DFG::clobberize() already support additional data but I was not using it. + + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * tests/stress/math-round-arith-rounding-mode.js: Added. + (firstCareAboutZeroSecondDoesNot): + (firstDoNotCareAboutZeroSecondDoes): + (warmup): + (verifyNegativeZeroIsPreserved): + +2015-05-18 Filip Pizlo <fpizlo@apple.com> + + Add SpecBoolInt32 type that means "I'm an int and I'm either 0 or 1" + https://bugs.webkit.org/show_bug.cgi?id=145137 + + Reviewed by Benjamin Poulain. + + It's super useful to know if an integer value could be either zero or one. We have an + immediate need for this because of Int32|Boolean uses, where knowing that the Int32 is + either 0 or 1 means that there is no actual polymorphism if you just look at the low bit + (1 behaves like true, 0 behaves like false, and the low bit of 1|true is 1, and the low + bit of 0|false is 0). + + We do this by splitting the SpecInt32 type into SpecBoolInt32 and SpecNonBoolInt32. This + change doesn't have any effect on behavior, yet. But it does give us the ability to + predict and prove when values are SpecBoolInt32; it's just we don't leverage this yet. + + This is perf-neutral. + + * bytecode/SpeculatedType.cpp: + (JSC::dumpSpeculation): + (JSC::speculationToAbbreviatedString): + (JSC::speculationFromValue): + * bytecode/SpeculatedType.h: + (JSC::isStringOrStringObjectSpeculation): + (JSC::isBoolInt32Speculation): + (JSC::isInt32Speculation): + (JSC::isInt32OrBooleanSpeculation): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + +2015-05-18 Michael Catanzaro <mcatanzaro@igalia.com> + + [CMake] Ignore warnings in system headers + https://bugs.webkit.org/show_bug.cgi?id=144747 + + Reviewed by Darin Adler. + + Separate include directories into WebKit project includes and system includes. Suppress all + warnings from headers in system include directories using the SYSTEM argument to + the include_directories command. + + * CMakeLists.txt: + * PlatformGTK.cmake: + +2015-05-18 Skachkov Alexandr <gskachkov@gmail.com> + + [ES6] Arrow function syntax. Feature flag for arrow function + https://bugs.webkit.org/show_bug.cgi?id=145108 + + Reviewed by Ryosuke Niwa. + + Added feature flag ENABLE_ES6_ARROWFUNCTION_SYNTAX for arrow function + + * Configurations/FeatureDefines.xcconfig: + +2015-05-18 Benjamin Poulain <benjamin@webkit.org> + + [JSC] When entering a CheckTierUp without OSREntry, force the CheckTierUp for the outer loops with OSR Entry + https://bugs.webkit.org/show_bug.cgi?id=145092 + + Reviewed by Filip Pizlo. + + When we have a hot loop without OSR Entry inside a slower loop that support OSR Entry, + we get the inside loop driving the tierUpCounter and we have very little chance of + doing a CheckTierUp on the outer loop. In turn, this give almost no opportunity to tier + up in the outer loop and OSR Enter there. + + This patches changes CheckTierUp to force its outer loops to do a CheckTierUp themselves. + + To do that, CheckTierUp sets a flag "nestedTriggerIsSet" to force the outer loop to + enter their CheckTierUp regardless of the tier-up counter. + + * bytecode/ExecutionCounter.cpp: + (JSC::ExecutionCounter<countingVariant>::setThreshold): + This is somewhat unrelated. This assertion is incorrect because it relies on + m_counter, which changes on an other thread. + + I have hit it a couple of times with this patch because we are a bit more aggressive + on CheckTierUp. What happens is: + 1) ExecutionCounter<countingVariant>::checkIfThresholdCrossedAndSet() first checks + hasCrossedThreshold(), and it is false. + 2) On the main thread, the hot loops keeps running and the counter becomes large + enough to cross the threshold. + 3) ExecutionCounter<countingVariant>::checkIfThresholdCrossedAndSet() runs the next + test, setThreshold(), where the assertion is. Since the counter is now large enough, + the assertion fails. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + + * dfg/DFGJITCode.h: + I used a uint8_t instead of a boolean to make the code generation clearer + in DFGSpeculativeJIT64. + + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + This is a bit annoying: we have the NaturalLoops analysis that provides us + everything we need to know about loops, but the TierUpCheck are conservative + and set on LoopHint. + + To make the two work together, we first find all the CheckTierUp that cannot + OSR enter and we keep a list of all the natural loops containing them. + + Then we do a second pass over the LoopHints, get their NaturalLoop, and check + if it contains a loop that cannot OSR enter. + + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTierUpCheckInjectionPhase.cpp: + (JSC::DFG::TierUpCheckInjectionPhase::run): + (JSC::DFG::TierUpCheckInjectionPhase::canOSREnterAtLoopHint): + +2015-05-18 Filip Pizlo <fpizlo@apple.com> + + Add a Int-or-Boolean speculation to Branch + https://bugs.webkit.org/show_bug.cgi?id=145134 + + Reviewed by Benjamin Poulain. + + After https://bugs.webkit.org/show_bug.cgi?id=126778 we no longer have a reason not to do the + int-or-boolean optimization that we already do everywhere else. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + +2015-05-18 Andreas Kling <akling@apple.com> + + [JSC] Speed up URL encode/decode by using bitmaps instead of strchr(). + <https://webkit.org/b/145115> + + Reviewed by Anders Carlsson. + + We were calling strchr() for every character when doing URL encoding/decoding and it stood out + like a sore O(n) thumb in Instruments. Optimize this by using a Bitmap<256> instead. + + 5.5% progression on Kraken/stanford-crypto-sha256-iterative. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::makeCharacterBitmap): + (JSC::encode): + (JSC::decode): + (JSC::globalFuncDecodeURI): + (JSC::globalFuncDecodeURIComponent): + (JSC::globalFuncEncodeURI): + (JSC::globalFuncEncodeURIComponent): + (JSC::globalFuncEscape): + +2015-05-17 Benjamin Poulain <benjamin@webkit.org> + + Do not use fastMallocGoodSize anywhere + https://bugs.webkit.org/show_bug.cgi?id=145103 + + Reviewed by Michael Saboff. + + * assembler/AssemblerBuffer.h: + (JSC::AssemblerData::AssemblerData): + (JSC::AssemblerData::grow): + +2015-05-17 Benjamin Poulain <benjamin@webkit.org> + + [JSC] Make StringRecursionChecker faster in the simple cases without any recursion + https://bugs.webkit.org/show_bug.cgi?id=145102 + + Reviewed by Darin Adler. + + In general, the array targeted by Array.toString() or Array.join() are pretty + simple. In those simple cases, we spend as much time in StringRecursionChecker + as we do on the actual operation. + + The reason for this is the HashSet stringRecursionCheckVisitedObjects used + to detect recursion. We are constantly adding and removing objects which + dirty buckets and force constant rehash. + + This patch adds a simple shortcut for those simple case: in addition to the HashSet, + we keep a pointer to the root object of the recursion. + In the vast majority of cases, we no longer touch the HashSet at all. + + This patch is a 12% progression on the overall score of ArrayWeighted. + + * runtime/StringRecursionChecker.h: + (JSC::StringRecursionChecker::performCheck): + (JSC::StringRecursionChecker::~StringRecursionChecker): + * runtime/VM.h: + +2015-05-17 Filip Pizlo <fpizlo@apple.com> + + Insert store barriers late so that IR transformations don't have to worry about them + https://bugs.webkit.org/show_bug.cgi?id=145015 + + Reviewed by Geoffrey Garen. + + We have had three kinds of bugs with store barriers. For the sake of discussion we say + that a store barrier is needed when we have something like: + + base.field = value + + - We sometimes fail to realize that we could remove a barrier when value is a non-cell. + This might happen if we prove value to be a non-cell even though in the FixupPhase it + wasn't predicted non-cell. + + - We sometimes have a barrier in the wrong place after object allocation sinking. We + might sink an allocation to just above the store, but that puts it just after the + StoreBarrier that FixupPhase inserted. + + - We don't remove redundant barriers across basic blocks. + + This comprehensively fixes these issues by doing store barrier insertion late, and + removing the store barrier elision phase. Store barrier insertion uses an epoch-based + algorithm to determine when stores need barriers. Briefly, a barrier is not needed if + base is in the current GC epoch (i.e. was the last object that we allocated or had a + barrier since last GC) or if base has a newer GC epoch than value (i.e. value would have + always been allocated before base). We do conservative things when merging epoch state + between basic blocks, and we only do such inter-block removal in the FTL. FTL also + queries AI to determine what type we've proved about value, and avoids barriers when + value is not a cell. FixupPhase still inserts type checks on some stores, to maximize + the likelihood that this AI-based removal is effective. + + Rolling back in after fixing some debug build test failures. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBlockMap.h: + (JSC::DFG::BlockMap::at): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGEpoch.h: + (JSC::DFG::Epoch::operator<): + (JSC::DFG::Epoch::operator>): + (JSC::DFG::Epoch::operator<=): + (JSC::DFG::Epoch::operator>=): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::speculateForBarrier): + (JSC::DFG::FixupPhase::insertStoreBarrier): Deleted. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGStoreBarrierElisionPhase.cpp: Removed. + * dfg/DFGStoreBarrierElisionPhase.h: Removed. + * dfg/DFGStoreBarrierInsertionPhase.cpp: Added. + (JSC::DFG::performFastStoreBarrierInsertion): + (JSC::DFG::performGlobalStoreBarrierInsertion): + * dfg/DFGStoreBarrierInsertionPhase.h: Added. + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): Fix an unrelated debug-only bug. + * tests/stress/load-varargs-then-inlined-call-and-exit.js: Test for that debug-only bug. + * tests/stress/load-varargs-then-inlined-call-and-exit-strict.js: Strict version of that test. + +2015-05-16 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r184415. + https://bugs.webkit.org/show_bug.cgi?id=145096 + + Broke several tests (Requested by msaboff on #webkit). + + Reverted changeset: + + "Insert store barriers late so that IR transformations don't + have to worry about them" + https://bugs.webkit.org/show_bug.cgi?id=145015 + http://trac.webkit.org/changeset/184415 + +2015-05-14 Filip Pizlo <fpizlo@apple.com> + + Insert store barriers late so that IR transformations don't have to worry about them + https://bugs.webkit.org/show_bug.cgi?id=145015 + + Reviewed by Geoffrey Garen. + + We have had three kinds of bugs with store barriers. For the sake of discussion we say + that a store barrier is needed when we have something like: + + base.field = value + + - We sometimes fail to realize that we could remove a barrier when value is a non-cell. + This might happen if we prove value to be a non-cell even though in the FixupPhase it + wasn't predicted non-cell. + + - We sometimes have a barrier in the wrong place after object allocation sinking. We + might sink an allocation to just above the store, but that puts it just after the + StoreBarrier that FixupPhase inserted. + + - We don't remove redundant barriers across basic blocks. + + This comprehensively fixes these issues by doing store barrier insertion late, and + removing the store barrier elision phase. Store barrier insertion uses an epoch-based + algorithm to determine when stores need barriers. Briefly, a barrier is not needed if + base is in the current GC epoch (i.e. was the last object that we allocated or had a + barrier since last GC) or if base has a newer GC epoch than value (i.e. value would have + always been allocated before base). We do conservative things when merging epoch state + between basic blocks, and we only do such inter-block removal in the FTL. FTL also + queries AI to determine what type we've proved about value, and avoids barriers when + value is not a cell. FixupPhase still inserts type checks on some stores, to maximize + the likelihood that this AI-based removal is effective. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBlockMap.h: + (JSC::DFG::BlockMap::at): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGEpoch.h: + (JSC::DFG::Epoch::operator<): + (JSC::DFG::Epoch::operator>): + (JSC::DFG::Epoch::operator<=): + (JSC::DFG::Epoch::operator>=): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::speculateForBarrier): + (JSC::DFG::FixupPhase::insertStoreBarrier): Deleted. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGStoreBarrierElisionPhase.cpp: Removed. + * dfg/DFGStoreBarrierElisionPhase.h: Removed. + * dfg/DFGStoreBarrierInsertionPhase.cpp: Added. + (JSC::DFG::performFastStoreBarrierInsertion): + (JSC::DFG::performGlobalStoreBarrierInsertion): + * dfg/DFGStoreBarrierInsertionPhase.h: Added. + +2015-05-15 Benjamin Poulain <bpoulain@apple.com> + + [ARM64] Do not fail branchConvertDoubleToInt32 when the result is zero and not negative zero + https://bugs.webkit.org/show_bug.cgi?id=144976 + + Reviewed by Michael Saboff. + + Failing the conversion on zero is pretty dangerous as we discovered on x86. + + This patch does not really impact performance significantly because + r184220 removed the zero checks from Kraken. This patch is just to be + on the safe side for cases not covered by existing benchmarks. + + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::branchConvertDoubleToInt32): + +2015-05-15 Sungmann Cho <sungmann.cho@navercorp.com> + + Remove unnecessary forward declarations in PropertyNameArray.h. + https://bugs.webkit.org/show_bug.cgi?id=145058 + + Reviewed by Andreas Kling. + + No new tests, no behavior change. + + * runtime/PropertyNameArray.h: + +2015-05-15 Mark Lam <mark.lam@apple.com> + + JSArray::setLength() should reallocate instead of zero-filling if the reallocation would be small enough. + https://bugs.webkit.org/show_bug.cgi?id=144622 + + Reviewed by Geoffrey Garen. + + When setting the array to a new length that is shorter, we now check if it is worth + just making a new butterfly instead of clearing out the slots in the old butterfly + that resides beyond the new length. If so, we will make a new butterfly instead. + + There is no perf differences in the benchmark results. However, this does benefit + the perf of pathological cases where we need to shorten the length of a very large + array, as is the case in tests/mozilla/js1_5/Array/regress-101964.js. With this + patch, we can expect that test to complete in a short time again. + + * runtime/JSArray.cpp: + (JSC::JSArray::setLength): + * runtime/JSObject.cpp: + (JSC::JSObject::reallocateAndShrinkButterfly): + - makes a new butterfly with a new shorter length. + * runtime/JSObject.h: + * tests/mozilla/js1_5/Array/regress-101964.js: + - Undo this test change since this patch will prevent us from spending a lot of time + clearing a large butterfly. + +2015-05-15 Basile Clement <basile_clement@apple.com> + + DFGLICMPhase shouldn't create NodeOrigins with forExit but without semantic + https://bugs.webkit.org/show_bug.cgi?id=145062 + + Reviewed by Filip Pizlo. + + We assert in various places (including NodeOrigin::isSet()) that a + NodeOrigin's semantic and forExit must be either both set, or both + unset. However, LICM'ing a node with unset NodeOrigin would only set + forExit, and leave semantic unset. This can for instance happen when a + Phi node is constant-folded into a JSConstant, which in turn gets + LICM'd. + + This patch changes DFGLICMPhase to set the NodeOrigin's semantic in + addition to its forExit if semantic was previously unset. + + It also adds two validators to DFGValidate.cpp: + - In both SSA and CPS form, a NodeOrigin semantic and forExit must be either both set or both unset + - In CPS form, all nodes must have a set NodeOrigin forExit (this is + the CPS counterpart to the SSA validator that checks that all nodes + must have a set NodeOrigin except possibly for a continuous chunk of + nodes at the top of a block) + + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + (JSC::DFG::Validate::validateCPS): + +2015-05-15 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, remove an unused declaration. + + * dfg/DFGSpeculativeJIT.h: + +2015-05-14 Filip Pizlo <fpizlo@apple.com> + + Remove unused constant-base and constant-value store barrier code in the DFG + https://bugs.webkit.org/show_bug.cgi?id=145039 + + Reviewed by Andreas Kling. + + Just killing dead code. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::storeToWriteBarrierBuffer): Deleted. + (JSC::DFG::SpeculativeJIT::writeBarrier): Deleted. + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + +2015-05-15 Alexandr Skachkov <gskachkov@gmail.com> + + Fix typo in function name parseFunctionParamters -> parseFunctionParameters + https://bugs.webkit.org/show_bug.cgi?id=145040 + + Reviewed by Mark Lam. + + * parser/Parser.h: + * parser/Parser.cpp: + +2015-05-14 Filip Pizlo <fpizlo@apple.com> + + Remove StoreBarrierWithNullCheck, nobody ever generates this. + + Rubber stamped by Benjamin Poulain and Michael Saboff. + + If we did bring something like this back in the future, we would just use UntypedUse instead + of CellUse to indicate that this is what we want. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::isStoreBarrier): + * dfg/DFGNodeType.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileStoreBarrier): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileStoreBarrierWithNullCheck): Deleted. + +2015-05-14 Filip Pizlo <fpizlo@apple.com> + + PutGlobalVar should reference the global object it's storing into + https://bugs.webkit.org/show_bug.cgi?id=145036 + + Reviewed by Michael Saboff. + + This makes it easier to reason about store barrier insertion and elimination. This changes + the format of PutGlobalVar so that child1 is the global object and child2 is the value. + Previously it just had child1, and that was the value. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compilePutGlobalVar): + +2015-05-14 Michael Catanzaro <mcatanzaro@igalia.com> + + [CMake] Error out when ruby is too old + https://bugs.webkit.org/show_bug.cgi?id=145014 + + Reviewed by Martin Robinson. + + Don't enforce the check for the Ruby executable here; it's now enforced in the top-level + CMakeLists.txt instead. + + * CMakeLists.txt: + +2015-05-12 Basile Clement <basile_clement@apple.com> + + Enforce options coherency + https://bugs.webkit.org/show_bug.cgi?id=144921 + + Reviewed by Mark Lam. + + JavaScriptCore should be failing early when the options are set in such + a way that we don't have a meaningful way to execute JavaScript, rather + than failing for obscure reasons at some point during execution. + + This patch adds a new function that checks whether the options are set + in a coherent way, and makes JSC::Options::initialize() crash when the + environment enforces incoherent options. + Client applications able to add or change additional options are + responsible to check for coherency again before starting to actually + execute JavaScript, if any additional options have been set. This is + implemented for the jsc executable in this patch. + + * jsc.cpp: + (CommandLine::parseArguments): + * runtime/Options.cpp: + (JSC::Options::initialize): + (JSC::Options::ensureOptionsAreCoherent): Added. + * runtime/Options.h: + (JSC::Options::ensureOptionsAreCoherent): Added. + +2015-05-14 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION (r184337): [EFL] unresolved reference errors in ARM builds + https://bugs.webkit.org/show_bug.cgi?id=145019 + + Reviewed by Ryosuke Niwa. + + Attempt to fix compile errors in EFL ARM buildbots. + By executing `nm`, found JSTemplateRegistryKey.cpp.o and TemplateRegistry.cpp.o have + unresolved reference to Structure::get. That is inlined function in StructureInlines.h. + + * runtime/JSTemplateRegistryKey.cpp: + * runtime/TemplateRegistry.cpp: + +2015-05-14 Alexandr Skachkov <gskachkov@gmail.com> + + Small refactoring before implementation of the ES6 arrow function. + https://bugs.webkit.org/show_bug.cgi?id=144954 + + Reviewed by Ryosuke Niwa. + + * parser/Parser.h: + * parser/Parser.cpp: + +2015-05-14 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION (r184337): ASSERT failed in debug builds for tagged templates + https://bugs.webkit.org/show_bug.cgi?id=145013 + + Reviewed by Filip Pizlo. + + Fix the regression introduced by r184337. + + 1. JSTemporaryRegistryKey::s_info should inherit the Base::s_info, + JSDestructibleObject::s_info. + + 2. The first register argument of BytecodeGenerator::emitNode + should be a referenced register if it is a temporary register. + + * bytecompiler/NodesCodegen.cpp: + (JSC::TaggedTemplateNode::emitBytecode): + * runtime/JSTemplateRegistryKey.cpp: + +2015-05-14 Andreas Kling <akling@apple.com> + + String.prototype.split() should create efficient substrings. + <https://webkit.org/b/144985> + <rdar://problem/20949344> + + Reviewed by Geoffrey Garen. + + Teach split() how to make substring JSStrings instead of relying on StringImpl's + substring sharing mechanism. The optimization works by deferring the construction + of a StringImpl until the substring's value is actually needed. + + This knocks ~2MB off of theverge.com by avoiding the extra StringImpl allocations. + Out of ~70000 substrings created by split(), only ~2000 of them get reified. + + * runtime/StringPrototype.cpp: + (JSC::jsSubstring): + (JSC::splitStringByOneCharacterImpl): + (JSC::stringProtoFuncSplit): + +2015-05-14 Yusuke Suzuki <utatane.tea@gmail.com> + + Change the status of ES6 tagged templates to Done in features.json + https://bugs.webkit.org/show_bug.cgi?id=145003 + + Reviewed by Benjamin Poulain. + + Now it's implemented in r184337. + + * features.json: + +2015-05-14 Yusuke Suzuki <utatane.tea@gmail.com> + + Introduce SymbolType into SpeculativeTypes + https://bugs.webkit.org/show_bug.cgi?id=142651 + + Reviewed by Filip Pizlo. + + Introduce SpecSymbol type into speculative types. + Previously symbol type is categorized into SpecCellOther. + But SpecCellOther is not intended to be used for such cells. + + This patch just introduces SpecSymbol. + It represents the type of target value is definitely the symbol type. + It is the part of SpecCell. + + In this patch, we do not introduce SymbolUse tracking. + It will be added in the separate patch. + + * bytecode/SpeculatedType.cpp: + (JSC::dumpSpeculation): + (JSC::speculationFromStructure): + * bytecode/SpeculatedType.h: + (JSC::isSymbolSpeculation): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::setType): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * tests/stress/typeof-symbol.js: Added. + +2015-05-14 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement tagged templates + https://bugs.webkit.org/show_bug.cgi?id=143183 + + Reviewed by Oliver Hunt. + + This patch implements ES6 tagged templates. + In tagged templates, the function takes the template object. + + The template object contains the raw and cooked template strings, + so when parsing the tagged templates, we need to tokenize the raw and cooked strings. + While tagged templates require the both strings, the template literal only requires + the cooked strings. So when tokenizing under the template literal context, + we only builds the cooked strings. + + As per ES6 spec, the template objects for the same raw strings are shared in the same realm. + The template objects is cached. And every time we evaluate the same tagged templates, + the same (cached) template objects are used. + Since the spec freezes this template objects completely, + we cannot attach some properties to it. + So we can say that it behaves as if the template objects are the primitive values (like JSString). + Since we cannot attach properties, the only way to test the identity of the template object is comparing. (===) + As the result, when there is no reference to the template object, we can garbage collect it + because the user has no way to test that the newly created template object does not equal + to the already collected template object. + + So, to implement tagged templates, we implement the following components. + + 1. JSTemplateRegistryKey + It holds the template registry key and it does not exposed to users. + TemplateRegistryKey holds the vector of raw and cooked strings with the pre-computed hash value. + When obtaining the template object for the (statically, a.k.a. at the parsing time) given raw string vectors, + we use this JSTemplateRegistryKey as a key to the map and look up the template object from + TemplateRegistry. + JSTemplateRegistryKey is created at the bytecode compiling time and + stored in the CodeBlock as like as JSString content values. + + 2. TemplateRegistry + This manages the cached template objects. + It holds the weak map (JSTemplateRegistryKey -> the template object). + The template object is weakly referenced. + So if there is no reference to the template object, + the template object is automatically GC-ed. + When looking up the template object, it searches the cached template object. + If it is found, it is returned to the users. + If there is no cached template objects, it creates the new template object and + stores it with the given template registry key. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::addTemplateRegistryKeyConstant): + (JSC::BytecodeGenerator::emitGetTemplateObject): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::TaggedTemplateNode::emitBytecode): + (JSC::TemplateLiteralNode::emitBytecode): Deleted. + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createTaggedTemplate): + (JSC::ASTBuilder::createTemplateLiteral): Deleted. + * parser/Lexer.cpp: + (JSC::Lexer<T>::setCode): + (JSC::Lexer<T>::parseTemplateLiteral): + (JSC::Lexer<T>::lex): + (JSC::Lexer<T>::scanTrailingTemplateString): + (JSC::Lexer<T>::clear): + * parser/Lexer.h: + (JSC::Lexer<T>::makeEmptyIdentifier): + * parser/NodeConstructors.h: + (JSC::TaggedTemplateNode::TaggedTemplateNode): + (JSC::TemplateLiteralNode::TemplateLiteralNode): Deleted. + * parser/Nodes.h: + (JSC::TemplateLiteralNode::templateStrings): + (JSC::TemplateLiteralNode::templateExpressions): + (JSC::TaggedTemplateNode::templateLiteral): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseTemplateString): + (JSC::Parser<LexerType>::parseTemplateLiteral): + (JSC::Parser<LexerType>::parsePrimaryExpression): + (JSC::Parser<LexerType>::parseMemberExpression): + * parser/Parser.h: + * parser/ParserArena.h: + (JSC::IdentifierArena::makeEmptyIdentifier): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createTaggedTemplate): + (JSC::SyntaxChecker::createTemplateLiteral): Deleted. + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::getTemplateObject): + (JSC::JSGlobalObject::JSGlobalObject): + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::templateRegistry): + * runtime/JSTemplateRegistryKey.cpp: Added. + (JSC::JSTemplateRegistryKey::JSTemplateRegistryKey): + (JSC::JSTemplateRegistryKey::create): + (JSC::JSTemplateRegistryKey::destroy): + * runtime/JSTemplateRegistryKey.h: Added. + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorFreeze): + * runtime/ObjectConstructor.h: + * runtime/TemplateRegistry.cpp: Added. + (JSC::TemplateRegistry::TemplateRegistry): + (JSC::TemplateRegistry::getTemplateObject): + * runtime/TemplateRegistry.h: Added. + * runtime/TemplateRegistryKey.h: Added. + (JSC::TemplateRegistryKey::isDeletedValue): + (JSC::TemplateRegistryKey::isEmptyValue): + (JSC::TemplateRegistryKey::hash): + (JSC::TemplateRegistryKey::rawStrings): + (JSC::TemplateRegistryKey::cookedStrings): + (JSC::TemplateRegistryKey::operator==): + (JSC::TemplateRegistryKey::operator!=): + (JSC::TemplateRegistryKey::Hasher::hash): + (JSC::TemplateRegistryKey::Hasher::equal): + (JSC::TemplateRegistryKey::TemplateRegistryKey): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + * tests/stress/tagged-templates-identity.js: Added. + (shouldBe): + * tests/stress/tagged-templates-raw-strings.js: Added. + (shouldBe): + (tag): + (testEval): + * tests/stress/tagged-templates-syntax.js: Added. + (tag): + (testSyntax): + (testSyntaxError): + * tests/stress/tagged-templates-template-object.js: Added. + (shouldBe): + (tag): + * tests/stress/tagged-templates-this.js: Added. + (shouldBe): + (tag): + * tests/stress/tagged-templates.js: Added. + (shouldBe): + (raw): + (cooked): + (Counter): + +2015-05-13 Ryosuke Niwa <rniwa@webkit.org> + + REGRESSION(r180595): same-callee profiling no longer works + https://bugs.webkit.org/show_bug.cgi?id=144787 + + Reviewed by Filip Pizlo. + + This patch introduces a DFG optimization to use NewObject node when the callee of op_create_this is + always the same JSFunction. This condition doesn't hold when the byte code creates multiple + JSFunction objects at runtime as in: function y() { return function () {} }; new y(); new y(); + + To enable this optimization, LLint and baseline JIT now store the last callee we saw in the newly + added fourth operand of op_create_this. We use this JSFunction's structure in DFG after verifying + our speculation that the callee is the same. To avoid recompiling the same code for different callee + objects in the polymorphic case, the special value of seenMultipleCalleeObjects() is set in + LLint and baseline JIT when multiple callees are observed. + + Tests: stress/create-this-with-callee-variants.js + + * bytecode/BytecodeList.json: Increased the number of operands to 5. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Dump the newly added callee cache. + (JSC::CodeBlock::finalizeUnconditionally): Clear the callee cache if the callee is no longer alive. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCreateThis): Add the instruction to propertyAccessInstructions so that + we can clear the callee cache in CodeBlock::finalizeUnconditionally. Also initialize the newly added + operand. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): Implement the optimization. Speculate the actual callee to + match the cache. Use the cached callee's structure if the speculation succeeds. Otherwise, OSR exit. + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_this): Go to the slow path to update the cache unless it's already marked + as seenMultipleCalleeObjects() to indicate the polymorphic behavior and/or we've OSR exited here. + (JSC::JIT::emitSlow_op_create_this): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_this): Ditto. + (JSC::JIT::emitSlow_op_create_this): + * llint/LowLevelInterpreter32_64.asm: + (_llint_op_create_this): Ditto. + * llint/LowLevelInterpreter64.asm: + (_llint_op_create_this): Ditto. + * runtime/CommonSlowPaths.cpp: + (slow_path_create_this): Set the callee cache to the actual callee if it's not set. If the cache has + been set to a JSFunction* different from the actual callee, set it to seenMultipleCalleeObjects(). + * runtime/JSCell.h: + (JSC::JSCell::seenMultipleCalleeObjects): Added. + * runtime/WriteBarrier.h: + (JSC::WriteBarrierBase::unvalidatedGet): Removed the compile guard around it. + * tests/stress/create-this-with-callee-variants.js: Added. + +2015-05-13 Joseph Pecoraro <pecoraro@apple.com> + + Clean up some possible RefPtr to PassRefPtr churn + https://bugs.webkit.org/show_bug.cgi?id=144779 + + Reviewed by Darin Adler. + + * runtime/GenericTypedArrayViewInlines.h: + (JSC::GenericTypedArrayView<Adaptor>::create): + (JSC::GenericTypedArrayView<Adaptor>::createUninitialized): + * runtime/JSArrayBufferConstructor.cpp: + (JSC::constructArrayBuffer): + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + * runtime/TypedArrayBase.h: + (JSC::TypedArrayBase::create): + (JSC::TypedArrayBase::createUninitialized): + * tools/FunctionOverrides.cpp: + (JSC::initializeOverrideInfo): + Release the last use of a RefPtr as it is passed on. + +2015-05-13 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Allow duplicate property names + https://bugs.webkit.org/show_bug.cgi?id=142895 + + Reviewed by Geoffrey Garen. + + Introduce new `op_put_getter_by_id` and `op_put_setter_by_id` opcodes + that will define a single getter or setter property on an object. + + The existing `op_put_getter_setter` opcode is still preferred for + putting both a getter and setter at the same time but cannot be used + for putting an individual getter or setter which is needed in + some cases. + + Add a new slow path when generating bytecodes for a property list + with computed properties, as computed properties are the only time + the list of properties cannot be determined statically. + + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitBytecode): + - fast path for all constant properties + - slow but paired getter/setter path if there are no computed properties + - slow path, individual put operation for every property, if there are computed properties + + * parser/Nodes.h: + Distinguish a Computed property from a Constant property. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseProperty): + (JSC::Parser<LexerType>::parsePropertyMethod): + Distingish Computed and Constant properties. + + (JSC::Parser<LexerType>::parseObjectLiteral): + When we drop into strict mode it is because we saw a getter + or setter, so be more explicit. + + (JSC::Parser<LexerType>::parseStrictObjectLiteral): + Eliminate duplicate property syntax error exception. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::getName): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::getName): Deleted. + No longer used. + + * runtime/JSObject.h: + (JSC::JSObject::putDirectInternal): + When updating a property. If the Accessor attribute changed + update the Structure. + + * runtime/JSObject.cpp: + (JSC::JSObject::putGetter): + (JSC::JSObject::putSetter): + Called by the opcodes, just perform the same operation that + __defineGetter__ or __defineSetter__ would do. + + (JSC::JSObject::putDirectNonIndexAccessor): + This transition is now handled in putDirectInternal. + + * runtime/Structure.h: + Add needed export. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitPutGetterById): + (JSC::BytecodeGenerator::emitPutSetterById): + * bytecompiler/BytecodeGenerator.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_put_getter_by_id): + (JSC::JIT::emit_op_put_setter_by_id): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_put_getter_by_id): + (JSC::JIT::emit_op_put_setter_by_id): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LLIntSlowPaths.h: + * llint/LowLevelInterpreter.asm: + New bytecodes. Modelled after existing op_put_getter_setter. + +2015-05-13 Filip Pizlo <fpizlo@apple.com> + + Creating a new blank document in icloud pages causes an AI error: Abstract value (CellBytecodedoubleBoolOther, TOP, TOP) for double node has type outside SpecFullDouble. + https://bugs.webkit.org/show_bug.cgi?id=144856 + + Reviewed by Benjamin Poulain. + + First I made fixTypeForRepresentation() print out better diagnostics when it dies. + + Then I fixed the bug: Node::convertToIdentityOn(Node*) needs to make sure that when it + converts to a representation-changing node, it needs to use one of the UseKinds that such + a node expects. For example, DoubleRep(UntypedUse:) doesn't make sense; it needs to be + something like DoubleRep(NumberUse:) since it will speculate that the input is a number. + + * dfg/DFGAbstractInterpreter.h: + (JSC::DFG::AbstractInterpreter::setBuiltInConstant): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::fixTypeForRepresentation): + * dfg/DFGAbstractValue.h: + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::convertToIdentityOn): + * tests/stress/cloned-arguments-get-by-val-double-array.js: Added. + (foo): + +2015-05-13 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r184313. + https://bugs.webkit.org/show_bug.cgi?id=144974 + + Introduced an assertion failure in class-syntax- + declaration.js, class-syntax-expression.js, and object- + literal-syntax.js (Requested by rniwa on #webkit). + + Reverted changeset: + + "Small refactoring before ES6 Arrow function implementation." + https://bugs.webkit.org/show_bug.cgi?id=144954 + http://trac.webkit.org/changeset/184313 + +2015-05-13 Oliver Hunt <oliver@apple.com> + Ensure that all the smart pointer types in WTF clear their pointer before deref + https://bugs.webkit.org/show_bug.cgi?id=143789 + + Reviewed by Ryosuke Niwa. + + One of the simpler cases of this in JavaScriptCore. There + are other cases where we need to guard the derefs but they + are more complex cases. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::releaseImpl): + * inspector/JSJavaScriptCallFrame.cpp: + (Inspector::JSJavaScriptCallFrame::releaseImpl): + +2015-05-13 Alexandr Skachkov <gskachkov@gmail.com> + + Small refactoring before ES6 Arrow function implementation. + https://bugs.webkit.org/show_bug.cgi?id=144954 + + Reviewed by Filip Pizlo. + + * parser/Parser.h: + * parser/Parser.cpp: + +2015-05-13 Filip Pizlo <fpizlo@apple.com> + + The liveness pruning done by ObjectAllocationSinkingPhase ignores the possibility of an object's bytecode liveness being longer than its DFG liveness + https://bugs.webkit.org/show_bug.cgi?id=144945 + + Reviewed by Michael Saboff. + + We were making the mistake of using DFG liveness for object allocation sinking decisions. + This is wrong. In fact we almost never want to use DFG liveness directly. The only place + where that makes sense is pruning in DFG AI. + + So, I created a CombinedLiveness class that combines the DFG liveness with bytecode + liveness. + + In the process of doing this, I realized that the DFGForAllKills definition of combined + liveness at block tail was not strictly right; it was using the bytecode liveness at the + block terminal instead of the union of the bytecode live-at-heads of successor blocks. So, + I changed DFGForAllKills to work in terms of CombinedLiveness. + + This allows me to unskip the test I added in r184260. I also added a new test that tries to + trigger this bug more directly. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGCombinedLiveness.cpp: Added. + (JSC::DFG::liveNodesAtHead): + (JSC::DFG::CombinedLiveness::CombinedLiveness): + * dfg/DFGCombinedLiveness.h: Added. + (JSC::DFG::CombinedLiveness::CombinedLiveness): + * dfg/DFGForAllKills.h: + (JSC::DFG::forAllKillsInBlock): + (JSC::DFG::forAllLiveNodesAtTail): Deleted. + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::performSinking): + (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + * tests/stress/escape-object-in-diamond-then-exit.js: Added. + * tests/stress/sink-object-past-invalid-check-sneaky.js: + +2015-05-13 Ryosuke Niwa <rniwa@webkit.org> + + I skipped a wrong test in r184270. Fix that. + The failure is tracked by webkit.org/b/144947. + + * tests/stress/arith-modulo-node-behaviors.js: + * tests/stress/arith-mul-with-constants.js: + +2015-05-13 Joseph Pecoraro <pecoraro@apple.com> + + Avoid always running some debug code in type profiling + https://bugs.webkit.org/show_bug.cgi?id=144775 + + Reviewed by Daniel Bates. + + * runtime/TypeProfilerLog.cpp: + (JSC::TypeProfilerLog::processLogEntries): + +2015-05-13 Joseph Pecoraro <pecoraro@apple.com> + + Pass String as reference in more places + https://bugs.webkit.org/show_bug.cgi?id=144769 + + Reviewed by Daniel Bates. + + * debugger/Breakpoint.h: + (JSC::Breakpoint::Breakpoint): + * parser/Parser.h: + (JSC::Parser::setErrorMessage): + (JSC::Parser::updateErrorWithNameAndMessage): + * parser/ParserError.h: + (JSC::ParserError::ParserError): + * runtime/RegExp.cpp: + (JSC::RegExpFunctionalTestCollector::outputOneTest): + * runtime/RegExpObject.cpp: + (JSC::regExpObjectSourceInternal): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::typeInformationForExpressionAtOffset): + * runtime/TypeProfilerLog.cpp: + (JSC::TypeProfilerLog::processLogEntries): + * runtime/TypeProfilerLog.h: + * tools/FunctionOverrides.cpp: + (JSC::initializeOverrideInfo): + * inspector/scripts/codegen/generate_objc_conversion_helpers.py: + (ObjCConversionHelpersGenerator._generate_enum_from_protocol_string): + + * inspector/scripts/codegen/objc_generator_templates.py: + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + Rebaseline tests after updating the generator. + +2015-05-13 Michael Saboff <msaboff@apple.com> + + com.apple.WebKit.WebContent crashed at JavaScriptCore: JSC::CodeBlock::finalizeUnconditionally + https://bugs.webkit.org/show_bug.cgi?id=144933 + + Changed the RELEASE_ASSERT_NOT_REACHED into an ASSERT. Added some diagnostic messages to + help determine the cause for any crash. + + Reviewed by Geoffrey Garen. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::finalizeUnconditionally): + +2015-05-13 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(r184260): arguments elimination has stopped working because of Check(UntypedUse:) from SSAConversionPhase + https://bugs.webkit.org/show_bug.cgi?id=144951 + + Reviewed by Michael Saboff. + + There were two issues here: + + - In r184260 we expected a small number of possible use kinds in Check nodes, and + UntypedUse was not one of them. That seemed like a sensible assumption because we don't + create Check nodes unless it's to have a check. But, SSAConversionPhase was creating a + Check that could have UntypedUse. I fixed this. It's cleaner for SSAConversionPhase to + follow the same idiom as everyone else and not create tautological checks. + + - It's clearly not very robust to assume that Checks will not be used tautologically. So, + this changes how we validate Checks in the escape analyses. We now use willHaveCheck, + which catches cases that AI would have already marked as unnecessary. It then also uses + a new helper called alreadyChecked(), which allows us to just ask if the check is + unnecessary for objects. That's a good fall-back in case AI hadn't run yet. + + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGMayExit.cpp: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGUseKind.h: + (JSC::DFG::alreadyChecked): + * dfg/DFGVarargsForwardingPhase.cpp: + +k +2015-05-13 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement String.raw + https://bugs.webkit.org/show_bug.cgi?id=144330 + + Reviewed by Filip Pizlo. + + Implement String.raw. It is intended to be used with tagged-templates syntax. + To implement ToString abstract operation efficiently, + we introduce @toString bytecode intrinsic. It emits op_to_string directly. + + * CMakeLists.txt: + * builtins/StringConstructor.js: Added. + (raw): + * bytecompiler/NodesCodegen.cpp: + (JSC::BytecodeIntrinsicNode::emit_intrinsic_toString): + * runtime/CommonIdentifiers.h: + * runtime/StringConstructor.cpp: + * tests/stress/string-raw.js: Added. + (shouldBe): + (.get shouldBe): + (Counter): + +2015-05-12 Ryosuke Niwa <rniwa@webkit.org> + + Temporarily disable the test on Windows. The failure is tracked in webkit.org/b/144897. + + * tests/stress/arith-mul-with-constants.js: + +2015-05-12 Filip Pizlo <fpizlo@apple.com> + + js/dom/stack-trace.html fails with eager compilation + https://bugs.webkit.org/show_bug.cgi?id=144853 + + Reviewed by Benjamin Poulain. + + All of our escape analyses were mishandling Check(). They were assuming that this is a + non-escaping operation. But, if we do for example a Check(Int32:@x) and @x is an escape + candidate, then we need to do something: if we eliminate or sink @x, then the check no + longer makes any sense since a phantom allocation has no type. This will make us forget + that this operation would have exited. This was causing us to not call a valueOf method in + js/dom/stack-trace.html with eager compilation enabled, because it was doing something like + +o where o had a valueOf method, and o was otherwise sinkable. + + This changes our escape analyses to basically pretend that any Check() that isn't obviously + unnecessary is an escape. We don't have to be super careful here. Most checks will be + completely eliminated by constant-folding. If that doesn't run in time, then the most + common check we will see is CellUse. So, we just recognize some very obvious check kinds + that we know would have passed, and for all of the rest we just assume that it's an escape. + + This was super tricky to test. The obvious way to test it is to use +o like + stack-trace.html, except that doing so relies on the fact that we still haven't implemented + the optimal behavior for op_to_number. So, I take four approaches in testing this patch: + + 1) Use +o. These will test what we want it to test for now, but at some point in the future + these tests will just be a good sanity-check that our op_to_number implementation is + right. + + 2) Do fancy control flow tricks to fool the profiling into thinking that some arithmetic + operation always sees integers even though we eventually feed it an object and that + object is a sink candidate. + + 3) Introduce a new jsc.cpp intrinsic called isInt32() which returns true if the incoming + value is an int32. This intrinsic is required to be implemented by DFG by + unconditionally speculating that the input is int32. This allows us to write much more + targetted tests of the underlying issue. + + 4) I made a version of stack-trace.html that runs in run-jsc-stress-tests, so that we can + get regression test coverage of this test in eager mode. + + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGVarargsForwardingPhase.cpp: + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::dumpInContext): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileFTLOSRExit): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionIsInt32): + * runtime/Intrinsic.h: + * tests/stress/sink-arguments-past-invalid-check-dfg.js: Added. + * tests/stress/sink-arguments-past-invalid-check-int32-dfg.js: Added. + * tests/stress/sink-arguments-past-invalid-check-int32.js: Added. + * tests/stress/sink-arguments-past-invalid-check-sneakier.js: Added. + * tests/stress/sink-arguments-past-invalid-check.js: Added. + * tests/stress/sink-function-past-invalid-check-sneakier.js: Added. + * tests/stress/sink-function-past-invalid-check-sneaky.js: Added. + * tests/stress/sink-object-past-invalid-check-int32.js: Added. + * tests/stress/sink-object-past-invalid-check-sneakier.js: Added. + * tests/stress/sink-object-past-invalid-check-sneaky.js: Added. + * tests/stress/sink-object-past-invalid-check.js: Added. + +2015-05-12 Benjamin Poulain <benjamin@webkit.org> + + Fix the iteration count of arith-modulo-node-behaviors.js + + * tests/stress/arith-modulo-node-behaviors.js: + No need for big numbers for the real testing. + +2015-05-12 Mark Lam <mark.lam@apple.com> + + Windows: Cannot use HANDLE from GetCurrentThread() to get the CONTEXT of another thread. + https://bugs.webkit.org/show_bug.cgi?id=144924 + + Reviewed by Alex Christensen. + + The present stack scanning code in the Windows port is expecting that the + GetCurrentThread() API will provide a unique HANDLE for each thread. The code + then saves and later uses that HANDLE with GetThreadContext() to get the + runtime state of the target thread from the GC thread. According to + https://msdn.microsoft.com/en-us/library/windows/desktop/ms683182(v=vs.85).aspx, + GetCurrentThread() does not provide this unique HANDLE that we expect: + + "The function cannot be used by one thread to create a handle that can + be used by other threads to refer to the first thread. The handle is + always interpreted as referring to the thread that is using it. A + thread can create a "real" handle to itself that can be used by other + threads, or inherited by other processes, by specifying the pseudo + handle as the source handle in a call to the DuplicateHandle function." + + As a result of this, GetCurrentThread() always returns the same HANDLE value, and + we end up never scanning the stacks of other threads because we wrongly think that + they are all equal (in identity) to the scanning thread. This, in turn, results + in crashes due to objects that are incorrectly collected. + + The fix is to call DuplicateHandle() to create a HANDLE that we can use. The + MachineThreads::Thread class already accurately tracks the period of time when + we need that HANDLE for the VM. Hence, the life-cycle of the HANDLE can be tied + to the life-cycle of the MachineThreads::Thread object for the corresponding thread. + + * heap/MachineStackMarker.cpp: + (JSC::getCurrentPlatformThread): + (JSC::MachineThreads::Thread::Thread): + (JSC::MachineThreads::Thread::~Thread): + (JSC::MachineThreads::Thread::suspend): + (JSC::MachineThreads::Thread::resume): + (JSC::MachineThreads::Thread::getRegisters): + +2015-05-12 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Make the NegZero backward propagated flags of ArithMod stricter + https://bugs.webkit.org/show_bug.cgi?id=144897 + + Reviewed by Geoffrey Garen. + + The NegZero flags of ArithMod were the same as ArithDiv: both children were + marked as needing to handle NegativeZero. + + Lucky for us, ArithMod is quite a bit different than ArithDiv. + + First, the sign of the result is completely independent from + the sign of the divisor. A zero on the divisor always produces a NaN. + That's great, we can remove the NodeBytecodeNeedsNegZero + from the flags propagated to child2. + + Second, the sign of the result is always the same as the sign of + the dividend. A dividend of zero produces a zero of same sign + unless the divisor is zero (in which case the result is NaN). + This is great too: we can just pass the flags we got into + ArithMod. + + With those two out of the way, we can make a faster version of ArithRound + for Kraken's oscillator. Since we no longer care about negative zero, + rounding becomes cast<int32>(value + 0.5). This gives ~3% faster runtime + on the benchmark. + + Unfortunatelly, most of the time is spent in FTL and the same optimization + does not apply well just yet: rdar://problem/20904149. + + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + Never add NodeBytecodeNeedsNegZero unless needed by the users of this node. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithRound): + Faster Math.round() when negative zero is not important. + + * tests/stress/arith-modulo-node-behaviors.js: Added. + (moduloWithNegativeZeroDividend): + (moduloWithUnusedNegativeZeroDividend): + (moduloWithNegativeZeroDivisor): + +2015-05-12 Mark Lam <mark.lam@apple.com> + + Refactor MachineStackMarker.cpp so that it's easier to reason about MachineThreads::Thread. + https://bugs.webkit.org/show_bug.cgi?id=144925 + + Reviewed by Michael Saboff. + + Currently, the code in MachineStackMarker.cpp is written as a bunch of functions that + operate on the platformThread value in the MachineThreads::Thread struct. Instead, we + can apply better OO encapsulation and convert all these functions into methods of the + MachineThreads::Thread struct. + + This will also make it easier to reason about the fix for + https://bugs.webkit.org/show_bug.cgi?id=144924 later. + + * heap/MachineStackMarker.cpp: + (JSC::getCurrentPlatformThread): + (JSC::MachineThreads::Thread::createForCurrentThread): + (JSC::MachineThreads::Thread::operator!=): + (JSC::MachineThreads::Thread::operator==): + (JSC::MachineThreads::addCurrentThread): + (JSC::MachineThreads::removeThreadIfFound): + (JSC::MachineThreads::Thread::suspend): + (JSC::MachineThreads::Thread::resume): + (JSC::MachineThreads::Thread::getRegisters): + (JSC::MachineThreads::Thread::Registers::stackPointer): + (JSC::MachineThreads::Thread::freeRegisters): + (JSC::MachineThreads::Thread::captureStack): + (JSC::MachineThreads::tryCopyOtherThreadStack): + (JSC::MachineThreads::tryCopyOtherThreadStacks): + (JSC::equalThread): Deleted. + (JSC::suspendThread): Deleted. + (JSC::resumeThread): Deleted. + (JSC::getPlatformThreadRegisters): Deleted. + (JSC::otherThreadStackPointer): Deleted. + (JSC::freePlatformThreadRegisters): Deleted. + (JSC::otherThreadStack): Deleted. + +2015-05-12 Ryosuke Niwa <rniwa@webkit.org> + + Array.slice should have a fast path like Array.splice + https://bugs.webkit.org/show_bug.cgi?id=144901 + + Reviewed by Geoffrey Garen. + + Add a fast memcpy path to Array.prototype.slice as done for Array.prototype.splice. + In Kraken, this appears to be 30% win on stanford-crypto-ccm and 10% win on stanford-crypto-pbkdf2. + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSlice): + * runtime/JSArray.cpp: + (JSC::JSArray::fastSlice): Added. + * runtime/JSArray.h: + +2015-05-11 Filip Pizlo <fpizlo@apple.com> + + OSR availability analysis would be more scalable (and correct) if it did more liveness pruning + https://bugs.webkit.org/show_bug.cgi?id=143078 + + Reviewed by Andreas Kling. + + In https://bugs.webkit.org/show_bug.cgi?id=144883, we found an example of where liveness + pruning is actually necessary. Well, not quite: we just need to prune out keys from the + heap availability map where the base node doesn't dominate the point where we are asking + for availability. If we don't do this, then eventually the IR gets corrupt because we'll + insert PutHints that reference the base node in places where the base node doesn't + dominate. But if we're going to do any pruning, then it makes sense to prune by bytecode + liveness. This is the strongest possible pruning we can do, and it should be sound. We + shouldn't have a node available for a virtual register if that register is live and the + node doesn't dominate. + + Making this work meant reusing the prune-to-liveness algorithm from the FTL backend. So, I + abstracted this a bit better. You can now availabilityMap.pruneByLiveness(graph, origin). + + * dfg/DFGAvailabilityMap.cpp: + (JSC::DFG::AvailabilityMap::pruneHeap): + (JSC::DFG::AvailabilityMap::pruneByLiveness): + (JSC::DFG::AvailabilityMap::prune): Deleted. + * dfg/DFGAvailabilityMap.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::OSRAvailabilityAnalysisPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + * tests/stress/liveness-pruning-needed-for-osr-availability.js: Added. This is a proper regression test. + * tests/stress/liveness-pruning-needed-for-osr-availability-eager.js: Added. This is the original reduced test case, requires eager-no-cjit to fail prior to this changeset. + +2015-05-12 Gabor Loki <loki@webkit.org> + + Workaround for Cortex-A53 erratum 843419 + https://bugs.webkit.org/show_bug.cgi?id=144680 + + Reviewed by Michael Saboff. + + This patch is about to give simple workaround for Cortex-A53 erratum 843419. + It inserts nops after ADRP instruction to avoid wrong address accesses. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::adrp): + (JSC::ARM64Assembler::nopCortexA53Fix843419): + +2015-05-11 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r184009. + https://bugs.webkit.org/show_bug.cgi?id=144900 + + Caused crashes on inspector tests (Requested by ap on + #webkit). + + Reverted changeset: + + "MapDataImpl::add() shouldn't do the same hash lookup twice." + https://bugs.webkit.org/show_bug.cgi?id=144759 + http://trac.webkit.org/changeset/184009 + +2015-05-11 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r184123. + https://bugs.webkit.org/show_bug.cgi?id=144899 + + Seems to have introduced flaky crashes in many JS tests + (Requested by rniwa on #webkit). + + Reverted changeset: + + "REGRESSION(r180595): same-callee profiling no longer works" + https://bugs.webkit.org/show_bug.cgi?id=144787 + http://trac.webkit.org/changeset/184123 + +2015-05-11 Brent Fulgham <bfulgham@apple.com> + + [Win] Move Windows build target to Windows 7 (or newer) + https://bugs.webkit.org/show_bug.cgi?id=144890 + <rdar://problem/20707307> + + Reviewed by Anders Carlsson. + + Update linked SDK and minimal Windows level to be compatible with + Windows 7 or newer. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj: + * JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj: + * JavaScriptCore.vcxproj/jsc/jsc.vcxproj: + * JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj: + * JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj: + * JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj: + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj: + * config.h: + +2015-05-08 Filip Pizlo <fpizlo@apple.com> + + CPS rethreading phase's flush detector flushes way too many SetLocals + https://bugs.webkit.org/show_bug.cgi?id=144819 + + Reviewed by Geoffrey Garen. + + After probably unrelated changes, this eventually caused some arguments elimination to stop + working because it would cause more SetLocals to turn into PutStacks. But it was a bug for + a long time. Basically, we don't want the children of a SetLocal to be flushed. Flushing is + meant to only affect the SetLocal itself. + + This is a speed-up on Octane/earley. + + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::computeIsFlushed): + +2015-05-11 Filip Pizlo <fpizlo@apple.com> + + gmail and google maps fail to load with eager compilation: Failed to insert inline cache for varargs call (specifically, CallForwardVarargs) because we thought the size would be 250 but it ended up being 262 prior to compaction. + https://bugs.webkit.org/show_bug.cgi?id=144854 + + Reviewed by Oliver Hunt. + + This is easy: just lift the threshold. Also remove the need for some duplicate thresholds. + It used to be that Construct required less code, but that's not the case for now. + + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCallForwardVarargs): + (JSC::FTL::sizeOfConstructVarargs): + (JSC::FTL::sizeOfConstructForwardVarargs): + +2015-05-11 Ryosuke Niwa <rniwa@webkit.org> + + REGRESSION(r180595): same-callee profiling no longer works + https://bugs.webkit.org/show_bug.cgi?id=144787 + + Reviewed by Michael Saboff. + + This patch introduces a DFG optimization to use NewObject node when the callee of op_create_this is + always the same JSFunction. This condition doesn't hold when the byte code creates multiple + JSFunction objects at runtime as in: function y() { return function () {} }; new y(); new y(); + + To enable this optimization, LLint and baseline JIT now store the last callee we saw in the newly + added fourth operand of op_create_this. We use this JSFunction's structure in DFG after verifying + our speculation that the callee is the same. To avoid recompiling the same code for different callee + objects in the polymorphic case, the special value of seenMultipleCalleeObjects() is set in + LLint and baseline JIT when multiple callees are observed. + + Tests: stress/create-this-with-callee-variants.js + + * bytecode/BytecodeList.json: Increased the number of operands to 5. + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): op_create_this uses 2nd (constructor) and 4th (callee cache) + operands. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Dump the newly added callee cache. + (JSC::CodeBlock::finalizeUnconditionally): Clear the callee cache if the callee is no longer alive. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCreateThis): Add the instruction to propertyAccessInstructions so that + we can clear the callee cache in CodeBlock::finalizeUnconditionally. Also initialize the newly added + operand. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): Implement the optimization. Speculate the actual callee to + match the cache. Use the cached callee's structure if the speculation succeeds. Otherwise, OSR exit. + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_this): Go to the slow path to update the cache unless it's already marked + as seenMultipleCalleeObjects() to indicate the polymorphic behavior. + (JSC::JIT::emitSlow_op_create_this): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_this): Ditto. + (JSC::JIT::emitSlow_op_create_this): + * llint/LowLevelInterpreter32_64.asm: + (_llint_op_create_this): Ditto. + * llint/LowLevelInterpreter64.asm: + (_llint_op_create_this): Ditto. + * runtime/CommonSlowPaths.cpp: + (slow_path_create_this): Set the callee cache to the actual callee if it's not set. If the cache has + been set to a JSFunction* different from the actual callee, set it to seenMultipleCalleeObjects(). + * runtime/JSCell.h: + (JSC::JSCell::seenMultipleCalleeObjects): Added. + * runtime/WriteBarrier.h: + (JSC::WriteBarrierBase::unvalidatedGet): Removed the compile guard around it. + * tests/stress/create-this-with-callee-variants.js: Added. + +2015-05-11 Andreas Kling <akling@apple.com> + + PropertyNameArray should use a Vector when there are few entries. + <https://webkit.org/b/144874> + + Reviewed by Geoffrey Garen. + + Bring back an optimization that was lost in the for-in refactoring. + PropertyNameArray now holds a Vector<AtomicStringImpl*> until there are + enough (20) entries to justify converting to a HashSet for contains(). + + Also inlined the code while we're here, since it has so few clients and + the call overhead adds up. + + ~5% progression on Kraken/json-stringify-tinderbox. + + * runtime/PropertyNameArray.cpp: Removed. + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArray::canAddKnownUniqueForStructure): + (JSC::PropertyNameArray::add): + (JSC::PropertyNameArray::addKnownUnique): + +2015-05-11 Matt Baker <mattbaker@apple.com> + + Web Inspector: REGRESSION (r175203): No profile information is shown in Inspector + https://bugs.webkit.org/show_bug.cgi?id=144808 + + Reviewed by Darin Adler. + + Since a profile can be started after a timeline recording has already begun, we can't assume a zero start time. + The start time for the root node's call entry should be based on the stopwatch used by the ProfileGenerator. + + * profiler/Profile.cpp: + (JSC::Profile::create): + (JSC::Profile::Profile): + * profiler/Profile.h: + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::AddParentForConsoleStartFunctor::operator()): + +2015-05-11 Basile Clement <basile_clement@apple.com> + + Unreviewed, remove unintended change. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + +2015-05-11 Filip Pizlo <fpizlo@apple.com> + + Make it easy to enable eager/non-concurrent JIT compilation + https://bugs.webkit.org/show_bug.cgi?id=144877 + + Reviewed by Michael Saboff. + + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + * runtime/Options.h: + +2015-05-10 Filip Pizlo <fpizlo@apple.com> + + We shouldn't promote LoadVarargs to a sequence of GetStacks and PutStacks if doing so would exceed the LoadVarargs' limit + https://bugs.webkit.org/show_bug.cgi?id=144851 + + Reviewed by Michael Saboff. + + LoadVarargs loads arguments from some object and puts them on the stack. The region of + stack is controlled by a bunch of meta-data, including InlineCallFrame. InlineCallFrame + shouldn't really be edited after ByteCodeParser, so we cannot convert LoadVarargs to + something that uses more stack than the LoadVarargs wanted to. + + This check was missing in the ArgumentsEliminationPhase's LoadVarargs->GetStack+PutStack + promoter. This is an important promotion rule for performance, and in cases where we are + compiling truly hot code, the LoadVarargs limit will be at least as big as the length of + the phantom arguments array that this phase sees. The LoadVarargs limit is based on + profiling and the phantom arguments array is a proof; in most cases the profiling is more + conservative. + + But, you could write some crazy code where the statically obvious arguments array value is + bigger than what the profiling would have told you. When this happens, this promotion + effectively removes a bounds check. This either results in us clobbering a bunch of stack, + or it means that we never initialize a region of the stack that a later operation will read + (the uninitialization happens because PutStackSinkingPhase removes PutStacks that appear + unnecessary, and a GetMyArgumentByVal will claim not to use the region of the stack outside + the original LoadVarargs limit). + + * dfg/DFGArgumentsEliminationPhase.cpp: + * tests/stress/load-varargs-elimination-bounds-check-barely.js: Added. + (foo): + (bar): + (baz): + * tests/stress/load-varargs-elimination-bounds-check.js: Added. + (foo): + (bar): + (baz): + +2015-05-11 Andreas Kling <akling@apple.com> + + JSON.stringify shouldn't use generic get() to access Array.length + <https://webkit.org/b/144847> + + Reviewed by Geoffrey Garen. + + If the value being serialized is a JSArray object, we can downcast and call its + length() directly instead of doing a generic property lookup. + + 0.5% progression on Kraken/json-stringify-tinderbox. + + * runtime/JSONObject.cpp: + (JSC::Stringifier::Holder::appendNextProperty): + +2015-05-10 Andreas Kling <akling@apple.com> + + Remove unnecessary AtomicStringImpl* hash specification in PropertyNameArray. + + Follow up to r184050 suggested by Darin. + + * runtime/PropertyNameArray.h: + +2015-05-10 Andreas Kling <akling@apple.com> + + Remove unused things from PropertyNameArray. + <https://webkit.org/b/144834> + + Reviewed by Filip Pizlo. + + PropertyNameArray had a bunch of bells and whistles added to it when for-in iteration + was refactored and optimized last year. Then more refactoring happened and this class + doesn't need to ring and toot anymore. + + The RefCountedIdentifierSet class disappears since the JSPropertyNameEnumerator wasn't + actually using it for anything and we were just wasting time creating these. + + Also made the member functions take AtomicStringImpl* instead of plain StringImpl*. + + * runtime/JSObject.cpp: + (JSC::JSObject::getPropertyNames): + * runtime/JSPropertyNameEnumerator.cpp: + (JSC::JSPropertyNameEnumerator::create): + (JSC::JSPropertyNameEnumerator::JSPropertyNameEnumerator): + * runtime/JSPropertyNameEnumerator.h: + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + (JSC::PropertyNameArray::setPreviouslyEnumeratedProperties): Deleted. + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArray::PropertyNameArray): + (JSC::PropertyNameArray::add): + (JSC::PropertyNameArray::addKnownUnique): + (JSC::PropertyNameArray::canAddKnownUniqueForStructure): + (JSC::RefCountedIdentifierSet::contains): Deleted. + (JSC::RefCountedIdentifierSet::size): Deleted. + (JSC::RefCountedIdentifierSet::add): Deleted. + (JSC::PropertyNameArray::identifierSet): Deleted. + (JSC::PropertyNameArray::numCacheableSlots): Deleted. + (JSC::PropertyNameArray::setNumCacheableSlotsForObject): Deleted. + (JSC::PropertyNameArray::setBaseObject): Deleted. + (JSC::PropertyNameArray::setPreviouslyEnumeratedLength): Deleted. + +2015-05-09 Yoav Weiss <yoav@yoav.ws> + + Remove the PICTURE_SIZES build flag + https://bugs.webkit.org/show_bug.cgi?id=144679 + + Reviewed by Benjamin Poulain. + + Removed the PICTURE_SIZES build time flag. + + * Configurations/FeatureDefines.xcconfig: + +2015-05-08 Filip Pizlo <fpizlo@apple.com> + + Extend the SaneChain optimization to Contiguous arrays + https://bugs.webkit.org/show_bug.cgi?id=144664 + + Reviewed by Mark Lam. + + Previously if you loaded from a hole, you'd either have to take slow path for the array + load (which means C++ calls and prototype chain walks) or you'd exit (if you hadn't + gathered the necessary profiling yet). But that's unnecessary if we know that the + prototype chain is sane - i.e. has no indexed properties. Then we can just return + Undefined for the hole. + + Making this change requires setting more watchpoints on the array prototype chain. But + that hit a horrible bug: ArrayPrototype still uses the static lookup tables and builds + itself up lazily. This means that this increased the number of recompilations we'd get + due to the array prototype chain being built up. + + So, this change also removes the laziness and static tables from ArrayPrototype. + + But to make that change, I also had to add a helper for eagerly building up a prototype + that has builtin functions. + + * CMakeLists.txt: + * DerivedSources.make: + * dfg/DFGArrayMode.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + (JSC::ArrayPrototype::getOwnPropertySlot): Deleted. + * runtime/ArrayPrototype.h: + * runtime/JSObject.h: + +2015-05-08 Michael Saboff <msaboff@apple.com> + + Creating a large MarkedBlock sometimes results in more than one cell in the block + https://bugs.webkit.org/show_bug.cgi?id=144815 + + Reviewed by Mark Lam. + + Large MarkedBlocks should have one and only one cell. Changed the calculation of + m_endAtom for large blocks to use the location of the first cell + 1. This + assures that large blocks only have one cell. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::MarkedBlock): + +2015-05-08 Oliver Hunt <oliver@apple.com> + + MapDataImpl::add() shouldn't do the same hash lookup twice. + https://bugs.webkit.org/show_bug.cgi?id=144759 + + Reviewed by Gavin Barraclough. + + We don't actually need to do a double lookup here, all we need to + do is update the index to point to the correct m_size. + + * runtime/MapDataInlines.h: + (JSC::JSIterator>::add): + +2015-05-08 Andreas Kling <akling@apple.com> + + Micro-optimize JSON serialization of string primitives. + <https://webkit.org/b/144800> + + Reviewed by Sam Weinig. + + Don't use the out-of-line JSValue::getString() to grab at string primitives + in serialization. Just check if it's a JSString and then downcast to grab at + the WTF::String inside. + + 2% progression on Kraken/json-stringify-tinderbox. + + * runtime/JSONObject.cpp: + (JSC::Stringifier::appendStringifiedValue): + +2015-05-08 Andreas Kling <akling@apple.com> + + Optimize serialization of quoted JSON strings. + <https://webkit.org/b/144754> + + Reviewed by Darin Adler. + + Optimized the serialization of quoted strings into JSON by moving the logic into + StringBuilder so it can make smarter decisions about buffering. + + 12% progression on Kraken/json-stringify-tinderbox (on my Mac Pro.) + + * bytecompiler/NodesCodegen.cpp: + (JSC::ObjectPatternNode::toString): Use the new StringBuilder API. + + * runtime/JSONObject.h: + * runtime/JSONObject.cpp: + (JSC::Stringifier::Holder::appendNextProperty): + (JSC::appendStringToStringBuilder): Deleted. + (JSC::appendQuotedJSONStringToBuilder): Deleted. + (JSC::Stringifier::appendQuotedString): Deleted. + (JSC::Stringifier::appendStringifiedValue): Moved the bulk of this logic + to StringBuilder and call that from here. + +2015-05-07 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r183961. + https://bugs.webkit.org/show_bug.cgi?id=144784 + + Broke js/dom/JSON-stringify.html (Requested by kling on + #webkit). + + Reverted changeset: + + "Optimize serialization of quoted JSON strings." + https://bugs.webkit.org/show_bug.cgi?id=144754 + http://trac.webkit.org/changeset/183961 + +2015-05-07 Filip Pizlo <fpizlo@apple.com> + + GC has trouble with pathologically large array allocations + https://bugs.webkit.org/show_bug.cgi?id=144609 + + Reviewed by Geoffrey Garen. + + The bug was that SlotVisitor::copyLater() would return early for oversize blocks (right + after pinning them), and would skip the accounting. The GC calculates the size of the heap + in tandem with the scan to save time, and that accounting was part of how the GC would + know how big the heap was. The GC would then think that oversize copied blocks use no + memory, and would then mess up its scheduling of the next GC. + + Fixing this bug is harder than it seems. When running an eden GC, we figure out the heap + size by summing the size from the last collection and the size by walking the eden heap. + But this breaks when we eagerly delete objects that the last collection touched. We can do + that in one corner case: copied block reallocation. The old block will be deleted from old + space during the realloc and a new block will be allocated in new space. In order for the + GC to know that the size of old space actually shrank, we need a field to tell us how much + such shrinkage could occur. Since this is a very dirty corner case and it only works for + very particular reasons arising from the special properties of copied space (single owner, + and the realloc is used in places where the compiler already knows that it cannot register + allocate a pointer to the old block), I opted for an equally dirty shrinkage counter + devoted just to this case. It's called bytesRemovedFromOldSpaceDueToReallocation. + + To test this, I needed to add an Option to force a particular RAM size in the GC. This + allows us to write tests that assert that the GC heap size is some value X, without + worrying about machine-to-machine variations due to GC heuristics changing based on RAM + size. + + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::CopiedSpace): Initialize the dirty shrinkage counter. + (JSC::CopiedSpace::tryReallocateOversize): Bump the dirty shrinkage counter. + * heap/CopiedSpace.h: + (JSC::CopiedSpace::takeBytesRemovedFromOldSpaceDueToReallocation): Swap out the counter. Used by the GC when it does its accounting. + * heap/Heap.cpp: + (JSC::Heap::Heap): Allow the user to force the RAM size. + (JSC::Heap::updateObjectCounts): Use the dirty shrinkage counter to good effect. Also, make this code less confusing. + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::copyLater): The early return for isOversize() was the bug. We still need to report these bytes as live. Otherwise the GC doesn't know that it owns this memory. + * jsc.cpp: Add size measuring hooks to write the largeish test. + (GlobalObject::finishCreation): + (functionGCAndSweep): + (functionFullGC): + (functionEdenGC): + (functionHeapSize): + * runtime/Options.h: + * tests/stress/new-array-storage-array-with-size.js: Fix this so that it actually allocates ArrayStorage arrays and tests the thing it was supposed to test. + * tests/stress/new-largeish-contiguous-array-with-size.js: Added. This tests what the other test accidentally started testing, but does so without running your system out of memory. + (foo): + (test): + +2015-05-07 Saam Barati <saambarati1@gmail.com> + + Global functions should be initialized as JSFunctions in byte code + https://bugs.webkit.org/show_bug.cgi?id=144178 + + Reviewed by Geoffrey Garen. + + This patch makes the initialization of global functions more explicit by + moving initialization into bytecode. It also prepares JSC for having ES6 + style lexical scoping because initializing global functions in bytecode + easily allows global functions to be initialized with the proper scope that + will have access to global lexical variables. Global lexical variables + should be visible to global functions but don't live on the global object. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedProgramCodeBlock::visitChildren): + * bytecode/UnlinkedCodeBlock.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::BytecodeGenerator): + * bytecompiler/BytecodeGenerator.h: + * runtime/Executable.cpp: + (JSC::ProgramExecutable::initializeGlobalProperties): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + * runtime/JSGlobalObject.h: + +2015-05-07 Benjamin Poulain <bpoulain@apple.com> + + Fix the x86 32bits build + + * assembler/X86Assembler.h: + +2015-05-07 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Add basic DFG/FTL support for Math.round + https://bugs.webkit.org/show_bug.cgi?id=144725 + + Reviewed by Filip Pizlo. + + This patch adds two optimizations targeting Math.round(): + -Add a DFGNode ArithRound corresponding to the intrinsic RoundIntrinsic. + -Change the MacroAssembler to be stricter on how we fail to convert a double + to ingeter. Previously, any number valued zero would fail, now we only + fail for -0. + + Since ArithRound speculate it produces int32, the MacroAssembler assembler + part became necessary because zero is a pretty common output of Math.round() + and we would OSR exit a lot (and eventually recompile for doubles). + + The implementation itself of the inline Math.round() is exactly the same + as the C function that exists for Math.round(). We can very likely do better + but it is a good start known to be valid and inlining alone alread provides + significant speedups. + + * assembler/X86Assembler.h: + (JSC::X86Assembler::movmskpd_rr): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): + When we have a zero, get the sign bit out of the double and check if is one. + + I'll look into doing the same improvement for ARM. + + * bytecode/SpeculatedType.cpp: + (JSC::typeOfDoubleRounding): + (JSC::typeOfDoubleFRound): Deleted. + * bytecode/SpeculatedType.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::roundShouldSpeculateInt32): + (JSC::DFG::Graph::negateShouldSpeculateMachineInt): Deleted. + * dfg/DFGNode.h: + (JSC::DFG::Node::arithNodeFlags): + (JSC::DFG::Node::hasHeapPrediction): + (JSC::DFG::Node::hasArithMode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithRound): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::convertDoubleToInt32): + (JSC::FTL::LowerDFGToLLVM::compileDoubleAsInt32): + (JSC::FTL::LowerDFGToLLVM::compileArithRound): + * ftl/FTLOutput.h: + (JSC::FTL::Output::ceil64): + * jit/ThunkGenerators.cpp: + * runtime/MathCommon.cpp: + * runtime/MathCommon.h: + * runtime/MathObject.cpp: + (JSC::mathProtoFuncRound): + * tests/stress/math-round-basics.js: Added. + (mathRoundOnIntegers): + (mathRoundOnDoubles): + (mathRoundOnBooleans): + (uselessMathRound): + (mathRoundWithOverflow): + (mathRoundConsumedAsDouble): + (mathRoundDoesNotCareAboutMinusZero): + (mathRoundNoArguments): + (mathRoundTooManyArguments): + (testMathRoundOnConstants): + (mathRoundStructTransition): + (Math.round): + +2015-05-07 Saam Barati <saambarati1@gmail.com> + + exceptionFuzz tests should explicitly initialize the exceptionFuzz boolean in JavaScript code through a function in jsc.cpp + https://bugs.webkit.org/show_bug.cgi?id=144753 + + Reviewed by Mark Lam. + + This allows the BytecodeGenerator to freely emit startup code that "may" + throw exceptions without worrying that this startup code will trigger + the exceptionFuzz exception. The exceptionFuzz counter will only begin + ticking when the 'enableExceptionFuzz' function is explicitly called in + the exceptionFuzz tests. + + * jsc.cpp: + (GlobalObject::finishCreation): + (functionEnableExceptionFuzz): + * tests/exceptionFuzz/3d-cube.js: + * tests/exceptionFuzz/date-format-xparb.js: + * tests/exceptionFuzz/earley-boyer.js: + +2015-05-07 Andreas Kling <akling@apple.com> + + Optimize serialization of quoted JSON strings. + <https://webkit.org/b/144754> + + Reviewed by Darin Adler. + + Optimized the serialization of quoted strings into JSON by moving the logic into + StringBuilder so it can make smarter decisions about buffering. + + 12% progression on Kraken/json-stringify-tinderbox (on my Mac Pro.) + + * bytecompiler/NodesCodegen.cpp: + (JSC::ObjectPatternNode::toString): Use the new StringBuilder API. + + * runtime/JSONObject.h: + * runtime/JSONObject.cpp: + (JSC::Stringifier::Holder::appendNextProperty): + (JSC::appendStringToStringBuilder): Deleted. + (JSC::appendQuotedJSONStringToBuilder): Deleted. + (JSC::Stringifier::appendQuotedString): Deleted. + (JSC::Stringifier::appendStringifiedValue): Moved the bulk of this logic + to StringBuilder and call that from here. + +2015-05-07 Yusuke Suzuki <utatane.tea@gmail.com> + + FunctionCallBracketNode should store the base value to the temporary when subscript has assignment + https://bugs.webkit.org/show_bug.cgi?id=144678 + + Reviewed by Geoffrey Garen. + + Currently, FunctionCallBracketNode directly use the RegisterID returned by emitNode. + But if the base part is the local register and the subscript part has assignment to it, the base result is accidentally rewritten. + + function t() { var ok = {null: function () { } }; ok[ok = null](); } + t(); // Should not throw error. + + This patch takes care about `subscriptHasAssignment`. + By using `emitNodeForLeftHandSide`, when there's assignment to local variables in RHS, + it correctly moves the LHS value to a temporary register. + + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionCallBracketNode::emitBytecode): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::makeFunctionCallNode): + * parser/NodeConstructors.h: + (JSC::FunctionCallBracketNode::FunctionCallBracketNode): + * parser/Nodes.h: + * tests/stress/assignment-in-function-call-bracket-node.js: Added. + (shouldBe): + (shouldBe.): + +2015-05-07 Basile Clement <basile_clement@apple.com> + + Unreviewed, add missing braces on a single-line if that got expanded in r183939 + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + +2015-05-05 Myles C. Maxfield <mmaxfield@apple.com> + + Revert "Introducing the Platform Abstraction Layer (PAL)" + https://bugs.webkit.org/show_bug.cgi?id=144751 + + Unreviewed. + + PAL should be a new target inside WebCore, rather than a top-level folder. + + * Configurations/FeatureDefines.xcconfig: Updated + +2015-05-07 Basile Clement <basile_clement@apple.com> + + Dumping OSR ExitValue should expand materializations only once + https://bugs.webkit.org/show_bug.cgi?id=144694 + + Reviewed by Filip Pizlo. + + Currently, dumping OSR exit values will print the full materialization + information each time it is encountered. We change it to print only a + brief description (only the materialization's address), and print the + whole set of materializations later on. + + This makes the dump less confusing (less likely to think that two + instances of the same materialization are different), and will be a + necessary change if/when we support materialization cycles. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::dumpInContext): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + +2015-05-07 Andreas Kling <akling@apple.com> + + Worker threads leak WeakBlocks (as seen on leaks bot) + <https://webkit.org/b/144721> + <rdar://problem/20848288> + + Reviewed by Darin Adler. + + Nuke any remaining empty WeakBlocks when the Heap is being torn down. + Trying to peek into these blocks after the VM is dead would be a bug anyway. + + This fixes a ~750 KB leak seen on the leaks bot. + + * heap/Heap.cpp: + (JSC::Heap::~Heap): + +2015-05-05 Geoffrey Garen <ggaren@apple.com> + + Don't branch when accessing the callee + https://bugs.webkit.org/show_bug.cgi?id=144645 + + Reviewed by Michael Saboff. + + The branch was added in <http://trac.webkit.org/changeset/81040> without + explanation. + + kling found it to be a performance problem. See <https://webkit.org/b/144586>. + + Our theory of access to Registers is that it's up to the client to access + them in the right way. So, let's do that. + + * interpreter/CallFrame.h: + (JSC::ExecState::callee): + (JSC::ExecState::setCallee): Call the field object instead of function + because nothing guarantees that it's a function. + * interpreter/ProtoCallFrame.h: + (JSC::ProtoCallFrame::callee): + (JSC::ProtoCallFrame::setCallee): + * interpreter/Register.h: + * runtime/JSObject.h: + (JSC::Register::object): Just do a cast like our other accessors do. + (JSC::Register::operator=): + (JSC::Register::function): Deleted. + (JSC::Register::withCallee): Deleted. + +2015-05-07 Dan Bernstein <mitz@apple.com> + + <rdar://problem/19317140> [Xcode] Remove usage of AspenFamily.xcconfig in Source/ + https://bugs.webkit.org/show_bug.cgi?id=144727 + + Reviewed by Darin Adler. + + * Configurations/Base.xcconfig: Donât include AspenFamily.xcconfig, and define + INSTALL_PATH_PREFIX and LD_DYLIB_INSTALL_NAME for the iOS 8.x Simulator. + +2015-05-07 Andreas Kling <akling@apple.com> + + Special-case Int32 values in JSON.stringify(). + <https://webkit.org/b/144731> + + Reviewed by Michael Saboff. + + Add a fast path for serializing Int32 values to JSON. This is far faster than dragging + simple integers through the full-blown dtoa() machinery. + + ~50% speedup on Kraken/json-stringify-tinderbox. + + * runtime/JSONObject.cpp: + (JSC::Stringifier::appendStringifiedValue): + +2015-05-06 Ryosuke Niwa <rniwa@webkit.org> + + ToT WebKit crashes while loading ES6 compatibility table + https://bugs.webkit.org/show_bug.cgi?id=144726 + + Reviewed by Filip Pizlo. + + The bug was caused by parseClass superfluously avoiding to build up the string after seeing {. + + Always build the identifier here as it could be a method name. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + +2015-05-05 Filip Pizlo <fpizlo@apple.com> + + Sane chain and string watchpoints should be set in FixupPhase or the backend rather than WatchpointCollectionPhase + https://bugs.webkit.org/show_bug.cgi?id=144665 + + Reviewed by Michael Saboff. + + This is a step towards getting rid of WatchpointCollectionPhase. It's also a step towards + extending SaneChain to all indexing shapes. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): Set the watchpoints here so that we don't need a case in WatchpointCollectionPhase. + (JSC::DFG::FixupPhase::checkArray): Clarify the need for checking the structure. We often forget why we do this instead of always using CheckArray. + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileGetByValOnString): Set the watchpoints here so that we don't need a case in WatchpointCollectionPhase. + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): Remove some code. + (JSC::DFG::WatchpointCollectionPhase::handleStringGetByVal): Deleted. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileStringCharAt): Set the watchpoints here so that we don't need a case in WatchpointCollectionPhase. + +2015-04-02 Myles C. Maxfield <mmaxfield@apple.com> + + Introducing the Platform Abstraction Layer (PAL) + https://bugs.webkit.org/show_bug.cgi?id=143358 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: Updated + +2015-05-06 Andreas Kling <akling@apple.com> + + Don't allocate a StringImpl for every Number JSValue in JSON.stringify(). + <https://webkit.org/b/144676> + + Reviewed by Darin Adler. + + We were creating a new String for every number JSValue passing through the JSON stringifier. + These StringImpl allocations were dominating one of the Kraken JSON benchmarks. + Optimize this by using StringBuilder::appendECMAScriptNumber() which uses a stack buffer + for the conversion instead. + + 13% progression on Kraken/json-stringify-tinderbox. + + * runtime/JSONObject.cpp: + (JSC::Stringifier::appendStringifiedValue): + +2015-05-06 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r183847. + https://bugs.webkit.org/show_bug.cgi?id=144691 + + Caused many assertion failures (Requested by ap on #webkit). + + Reverted changeset: + + "GC has trouble with pathologically large array allocations" + https://bugs.webkit.org/show_bug.cgi?id=144609 + http://trac.webkit.org/changeset/183847 + +2015-05-05 Filip Pizlo <fpizlo@apple.com> + + PutGlobalVar shouldn't have an unconditional store barrier + https://bugs.webkit.org/show_bug.cgi?id=133104 + + Reviewed by Benjamin Poulain. + + We don't need a store barrier on PutGlobalVar if the value being stored can be + speculated to not be a cell. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + +2015-05-05 Filip Pizlo <fpizlo@apple.com> + + CopiedBlock::reportLiveBytes() should be totally cool with oversize blocks + https://bugs.webkit.org/show_bug.cgi?id=144667 + + Reviewed by Andreas Kling. + + We are now calling this method for oversize blocks. It had an assertion that indirectly + implied that the block is not oversize, because it was claiming that the number of live + bytes should be smaller than the non-oversize-block size. + + * heap/CopiedBlockInlines.h: + (JSC::CopiedBlock::reportLiveBytes): + +2015-05-05 Filip Pizlo <fpizlo@apple.com> + + GC has trouble with pathologically large array allocations + https://bugs.webkit.org/show_bug.cgi?id=144609 + + Reviewed by Mark Lam. + + * heap/Heap.cpp: + (JSC::Heap::updateObjectCounts): Make this code less confusing. + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::copyLater): The early return for isOversize() was the bug. We still need to report these bytes as live. Otherwise the GC doesn't know that it owns this memory. + * jsc.cpp: Add size measuring hooks to write the largeish test. + (GlobalObject::finishCreation): + (functionGCAndSweep): + (functionFullGC): + (functionEdenGC): + (functionHeapSize): + * tests/stress/new-array-storage-array-with-size.js: Fix this so that it actually allocates ArrayStorage arrays and tests the thing it was supposed to test. + * tests/stress/new-largeish-contiguous-array-with-size.js: Added. This tests what the other test accidentally started testing, but does so without running your system out of memory. + (foo): + (test): + +2015-05-05 Filip Pizlo <fpizlo@apple.com> + + FTL SwitchString slow case creates duplicate switch cases + https://bugs.webkit.org/show_bug.cgi?id=144634 + + Reviewed by Geoffrey Garen. + + The problem of duplicate switches is sufficiently annoying that I fixed the issue and also + added mostly-debug-only asserts to catch such issues earlier. + + * bytecode/CallVariant.cpp: + (JSC::variantListWithVariant): Assertion to prevent similar bugs. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::switchStringRecurse): Assertion to prevent similar bugs. + (JSC::FTL::LowerDFGToLLVM::switchStringSlow): This is the bug. + * jit/BinarySwitch.cpp: + (JSC::BinarySwitch::BinarySwitch): Assertion to prevent similar bugs. + * jit/Repatch.cpp: + (JSC::linkPolymorphicCall): Assertion to prevent similar bugs. + * tests/stress/ftl-switch-string-slow-duplicate-cases.js: Added. This tests the FTL SwitchString bug. It was previously crashing every time. + (foo): + (cat): + +2015-05-05 Basile Clement <basile_clement@apple.com> + + Fix debug builds after r183812 + https://bugs.webkit.org/show_bug.cgi?id=144300 + + Rubber stamped by Andreas Kling and Filip Pizlo. + + hasObjectMaterializationData() didn't treat MaterializeCreateActivation + as having materialization data, which was causing an assertion failure when + sinking CreateActivations on debug builds. + + * dfg/DFGNode.h: + (JSC::DFG::Node::hasObjectMaterializationData): + +2015-05-04 Basile Clement <basile_clement@apple.com> + + Allow CreateActivation sinking + https://bugs.webkit.org/show_bug.cgi?id=144300 + + Reviewed by Filip Pizlo. + + This pursues the work started in + https://bugs.webkit.org/show_bug.cgi?id=144016 to expand the set of + allocations we are able to sink by allowing sinking of CreateActivation + node. + + This is achieved by following closely the way NewObject is currently + sunk: we add a new PhantomCreateActivation node to record the initial + position of the CreateActivation node, new ClosureVarPLoc promoted heap + locations to keep track of the variables put in the activation, and a + new MaterializeCreateActivation node to allocate and populate the sunk + activation. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::convertToPutClosureVarHint): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPhantomCreateActivation): + (JSC::DFG::Node::isActivationAllocation): + (JSC::DFG::Node::isPhantomActivationAllocation): + (JSC::DFG::Node::isPhantomAllocation): + * dfg/DFGNodeType.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize): + (JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGPromotedHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGPromotedHeapLocation.h: + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileMaterializeCreateActivation): + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): + * tests/stress/activation-sink-osrexit.js: Added. + (bar): + (foo.set result): + * tests/stress/activation-sink.js: Added. + (bar): + +2015-05-04 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix stale comment. + + * tests/mozilla/js1_5/Array/regress-101964.js: + +2015-05-04 Filip Pizlo <fpizlo@apple.com> + + Large array shouldn't be slow + https://bugs.webkit.org/show_bug.cgi?id=144617 + + Rubber stamped by Mark Lam. + + * tests/mozilla/js1_5/Array/regress-101964.js: 500ms isn't enough in debug mode. We don't care how long this takes so long as we run it to completion. I've raised the limit much higher. + +2015-05-04 Filip Pizlo <fpizlo@apple.com> + + Large array shouldn't be slow + https://bugs.webkit.org/show_bug.cgi?id=144617 + + Rubber stamped by Mark Lam. + + * tests/mozilla/js1_5/Array/regress-101964.js: Mozilla may have cared about this being fast a decade ago (or more), but we don't care. We've consistently found that an array implementation that punishes this case to get speed on common-case array accesses is better. This should fix some test failures on the bots. + +2015-05-04 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r183789. + https://bugs.webkit.org/show_bug.cgi?id=144620 + + Causing flakiness on exceptionFuzz tests locally on 32-bit + build (Requested by saamyjoon on #webkit). + + Reverted changeset: + + "Global functions should be initialized as JSFunctions in byte + code" + https://bugs.webkit.org/show_bug.cgi?id=144178 + http://trac.webkit.org/changeset/183789 + +2015-05-04 Saam Barati <saambarati1@gmail.com> + + Global functions should be initialized as JSFunctions in byte code + https://bugs.webkit.org/show_bug.cgi?id=144178 + + Reviewed by Geoffrey Garen. + + This patch makes the initialization of global functions more explicit by + moving initialization into bytecode. It also prepares JSC for having ES6 + style lexical scoping because initializing global functions in bytecode + easily allows global functions to be initialized with the proper scope that + will have access to global lexical variables. Global lexical variables + should be visible to global functions but don't live on the global object. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedProgramCodeBlock::visitChildren): + * bytecode/UnlinkedCodeBlock.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::BytecodeGenerator): + * bytecompiler/BytecodeGenerator.h: + * runtime/Executable.cpp: + (JSC::ProgramExecutable::initializeGlobalProperties): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + * runtime/JSGlobalObject.h: + +2015-05-04 Filip Pizlo <fpizlo@apple.com> + + Large array shouldn't be slow + https://bugs.webkit.org/show_bug.cgi?id=144617 + + Reviewed by Geoffrey Garen. + + Decouple MIN_SPARSE_ARRAY_INDEX, which is the threshold for storing to the sparse map when + you're already using ArrayStorage mode, from the minimul array length required to use + ArrayStorage in a new Array(length) allocation. + + Lift the array allocation length threshold to something very high. If this works, we'll + probably remove that threshold entirely. + + This is a 27% speed-up on JetStream/hash-map. Because run-jsc-benchmarks still can't run + JetStream as a discrete suite, this adds hash-map to LongSpider so that we run it somewhere + for now. + + * dfg/DFGCallArrayAllocatorSlowPathGenerator.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNewArrayWithSize): + * runtime/ArrayConventions.h: + * runtime/JSArray.h: + (JSC::JSArray::create): + * runtime/JSGlobalObject.h: + (JSC::constructEmptyArray): + * tests/stress/new-array-storage-array-with-size.js: Skip this test until we fix https://bugs.webkit.org/show_bug.cgi?id=144609. + +2015-05-03 Yusuke Suzuki <utatane.tea@gmail.com> + + Add backed intrinsics to private functions exposed with private symbols in global object + https://bugs.webkit.org/show_bug.cgi?id=144545 + + Reviewed by Darin Adler. + + Math.abs and Math.floor have ASM intrinsics And it is further accelerated in DFG/FTL layers. + This patch adds intrinsic to private functions exposed with private symbols in global object, + @floor and @abs. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalPrivateFuncAbs): Deleted. + (JSC::globalPrivateFuncFloor): Deleted. + * runtime/MathObject.cpp: + * runtime/MathObject.h: + * tests/stress/array-from-abs-and-floor.js: Added. + (target1): + (target2): + (target3): + +2015-05-04 Csaba Osztrogonác <ossy@webkit.org> + + [cmake] ARM related build system cleanup + https://bugs.webkit.org/show_bug.cgi?id=144566 + + Reviewed by Darin Adler. + + * CMakeLists.txt: + +2015-05-04 Andreas Kling <akling@apple.com> + + Optimize WeakBlock's "reap" and "visit" operations. + <https://webkit.org/b/144585> + + Reviewed by Geoffrey Garen. + + WeakBlock was using Heap::isLive(void*) to determine the liveness of weak pointees. + That function was really written with conservative roots marking in mind, and will do a bunch + of sanity and bounds checks. + + For weaks, we know that the pointer will have been a valid cell pointer into a block + of appropriate cell size, so we can skip a lot of the checks. + + We now keep a pointer to the MarkedBlock in each WeakBlock. That way we no longer have to do + MarkedBlock::blockFor() for every single cell when iterating. + + Note that a WeakBlock's MarkedBlock pointer becomes null when we detach a logically empty + WeakBlock from its WeakSet and transfer ownership to Heap. At that point, the block will never + be pointing to any live cells, and the only operation that will run on the block is sweep(). + + Finally, MarkedBlock allows liveness queries in three states: Marked, Retired, and Allocated. + In Allocated state, all cells are reported as live. This state will reset to Marked on next GC. + This patch uses that knowledge to avoid branching on the MarkedBlock's state for every cell. + + This is a ~3x speedup of visit() and a ~2x speedup of reap() on Dromaeo/dom-modify, netting + what looks like a 1% speedup locally. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::MarkedBlock): Pass *this to the WeakSet's ctor. + + * heap/MarkedBlock.h: + (JSC::MarkedBlock::isMarkedOrNewlyAllocated): Added, stripped-down version of isLive() when the + block's state is known to be either Marked or Retired. + + (JSC::MarkedBlock::isAllocated): Added, tells WeakBlock it's okay to skip reap/visit since isLive() + would report that all cells are live anyway. + + * heap/WeakBlock.cpp: + (JSC::WeakBlock::create): + (JSC::WeakBlock::WeakBlock): Stash a MarkedBlock* on each WeakBlock. + + (JSC::WeakBlock::visit): + (JSC::WeakBlock::reap): Optimized these two to avoid a bunch of pointer arithmetic and branches. + + * heap/WeakBlock.h: + (JSC::WeakBlock::disconnectMarkedBlock): Added. + * heap/WeakSet.cpp: + (JSC::WeakSet::sweep): Call the above when removing a WeakBlock from WeakSet and transferring + ownership to Heap until it can die peacefully. + + (JSC::WeakSet::addAllocator): + * heap/WeakSet.h: + (JSC::WeakSet::WeakSet): Give WeakSet a MarkedBlock& for passing on to WeakBlocks. + +2015-05-04 Basile Clement <basile_clement@apple.com> + + Allocation sinking is prohibiting the creation of phis between a Phantom object and its materialization + https://bugs.webkit.org/show_bug.cgi?id=144587 + + Rubber stamped by Filip Pizlo. + + When sinking object allocations, we ensure in + determineMaterializationPoints that whenever an allocation is + materialized on a path to a block, it is materialized in all such + paths. Thus when running the SSA calculator to place Phis in + placeMaterializationPoints, we can't encounter a situation where some + Upsilons are referring to a materialization while others are referring + to the phantom object. + + This replaces the code that was adding a materialization late in + placeMaterializationPoints to handle that case by an assertion that it + does not happen, which will make + https://bugs.webkit.org/show_bug.cgi?id=143073 easier to implement. + + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + +2015-05-04 Ryosuke Niwa <rniwa@webkit.org> + + Extending undefined in class syntax should throw a TypeError + https://bugs.webkit.org/show_bug.cgi?id=144284 + + Reviewed by Darin Adler. + + The bug was caused by op_eq_null evaluating to true when compared to undefined. + Explicitly check op_eq_undefined first to detect the case where we're extending undefined. + + We also had bogus test cases checked in class-syntax-extends.html. This patch also fixes them. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ClassExprNode::emitBytecode): + +2015-05-04 Ryosuke Niwa <rniwa@webkit.org> + + new super should be a syntax error + https://bugs.webkit.org/show_bug.cgi?id=144282 + + Reviewed by Joseph Pecoraro. + + Disallow "new super" as ES6 spec doesn't allow this. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseMemberExpression): + +2015-05-04 Saam Barati <saambarati1@gmail.com> + + JSCallbackObject does not maintain symmetry between accesses for getOwnPropertySlot and put + https://bugs.webkit.org/show_bug.cgi?id=144265 + + Reviewed by Geoffrey Garen. + + JSCallbackObject will defer to a parent's implementation of getOwnPropertySlot + for a static function if the parent has that property slot. JSCallbackObject::put + did not maintain this symmetry of also calling ::put on the parent if the parent + has the property. We should ensure that this symmetry exists. + + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::put): + * API/tests/testapi.c: + * API/tests/testapi.js: + (globalStaticFunction2): + (this.globalStaticFunction2): + (iAmNotAStaticFunction): + (this.iAmNotAStaticFunction): + +2015-05-04 Andreas Kling <akling@apple.com> + + Make ExecState::vm() branchless in release builds. + <https://webkit.org/b/144586> + + Reviewed by Geoffrey Garen. + + Avoid null checking the ExecState's callee() before getting the + VM from it. The code was already dereferencing it anyway, since we + know it's not gonna be null. + + * runtime/JSCellInlines.h: + (JSC::ExecState::vm): + +2015-05-04 Basile Clement <basile_clement@apple.com> + + Object allocation not sinking properly through CheckStructure + https://bugs.webkit.org/show_bug.cgi?id=144465 + + Reviewed by Filip Pizlo. + + Currently, sinking an allocation through a CheckStructure will + completely ignore all structure checking, which is obviously wrong. + + A CheckStructureImmediate node type was present for that purpose, but + the CheckStructures were not properly replaced. This ensures that + CheckStructure nodes are replaced by CheckStructureImmediate nodes when + sunk through, and that structure checking happens correctly. + + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToCheckStructureImmediate): Added. + (JSC::DFG::Node::hasStructureSet): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCheckStructure): + (JSC::FTL::LowerDFGToLLVM::compileCheckStructureImmediate): + (JSC::FTL::LowerDFGToLLVM::checkStructure): + * tests/stress/sink_checkstructure.js: Added. + (foo): + +2015-05-01 Geoffrey Garen <ggaren@apple.com> + + REGRESSION(r183570): jslib-traverse-jquery is 22% slower + https://bugs.webkit.org/show_bug.cgi?id=144476 + + Reviewed by Sam Weinig. + + jslib-traverse-jquery is now 31% faster than its unregressed baseline. + + The jQuery algorithm for sorting DOM nodes is so pathologically slow that, + to my knowledge, the topic of how to optimize it is not covered in any + literature about sorting. + + On the slowest jQuery sorting test -- prevAll -- our new + Array.prototype.sort, compared to its predecessor, performed 12% fewer + comparisons and requireed 10X less overhead per comparison. Yet, it was + slower. + + It was slower because it inadvertantly increased the average cost of the + comparison function by 2X. jQuery uses compareDocumentPosition to compare + DOM nodes, and compareDocumentPosition(a, b) is O(N) in the distance + required to traverse backwards from b to a. In prevAll, we encounter the + worst case for merge sort of compareDocumentPosition: A long list of DOM + nodes in mostly reverse order. In this case, merge sort will sequentially + compareDocumentPosition(a, b), where a is not reachable backwards from + b, and therefore compareDocumentPosition will traverse the whole sibling + list. + + The solution is simple enough: Call compareDocumentPosition(b, a) instead. + + This is a pretty silly thing to do, but it is harmless, and jQuery is + popular, so let's do it. + + We do not risk suffering the same problem in reverse when sorting a long + list of DOM nodes in forward order. (We still have a 37% speedup on the + nextAll benchmark.) The reason is that merge sort performs 2X fewer + comparisons when the list is already sorted, so we can worry less about + the cost of each comparison. + + A fully principled soultion to this problem would probably do something + like Python's timsort, which special-cases ordered ranges to perform + only O(n) comparisons. But that would contradict our original + goal of just having something simple that works. + + Another option is for elements to keep a compareDocumentPosition cache, + like a node list cache, which allows you to determine the absolute + position of a node using a hash lookup. I will leave this as an exercise + for kling. + + * builtins/Array.prototype.js: + (sort.merge): Compare in an order that is favorable to a comparator + that calls compareDocumentPosition. + +2015-05-04 Csaba Osztrogonác <ossy@webkit.org> + + [cmake] Fix generate-js-builtins related incremental build issue + https://bugs.webkit.org/show_bug.cgi?id=144094 + + Reviewed by Michael Saboff. + + * CMakeLists.txt: Generated JSCBuiltins.<cpp|h> should depend on Source/JavaScriptCore/builtins directory. + Pass input directory to generate-js-builtins instead of Source/JavaScriptCore/builtins/*.js. + * DerivedSources.make: + Pass input directory to generate-js-builtins instead of Source/JavaScriptCore/builtins/*.js. + * generate-js-builtins: Accept input files and input directory too. + +2015-05-03 Simon Fraser <simon.fraser@apple.com> + + Make some static data const + https://bugs.webkit.org/show_bug.cgi?id=144552 + + Reviewed by Andreas Kling. + + Turn characterSetInfo into const data. + + * yarr/YarrCanonicalizeUCS2.cpp: + * yarr/YarrCanonicalizeUCS2.h: + +2015-05-01 Filip Pizlo <fpizlo@apple.com> + + TypeOf should be fast + https://bugs.webkit.org/show_bug.cgi?id=144396 + + Reviewed by Geoffrey Garen. + + Adds comprehensive support for fast typeof to the optimizing JITs. Calls into the runtime + are only used for very exotic objects - they must have either the MasqueradesAsUndefined or + TypeOfShouldCallGetCallData type flags set. All other cases are handled inline. + + This means optimizing IsObjectOrNull, IsFunction, and TypeOf - all node types that used to + rely heavily on C++ calls to fulfill their function. + + Because TypeOf is now so fast, we no longer need to do any speculations on this node. + + In the FTL, we take this further by querying AI for each branch in the TypeOf decision tree. + This means that if the TypeOf is dominated by any type checks, we will automatically prune + out cases that are redundant. + + This patch anticipates the addition of SwitchTypeOf or something like that. So, the TypeOf + code generation is designed to be reusable. + + This is a speed-up on most typeof benchmarks. But, it is a slow-down on benchmarks that take + the exotic call trap hook. That hook is now in a deeper slow path than before. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): TypeOf was pure all along, but we failed to realize this. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileIsObjectOrNull): + (JSC::DFG::SpeculativeJIT::compileIsFunction): + (JSC::DFG::SpeculativeJIT::compileTypeOf): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::blessedBooleanResult): + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileIsObjectOrNull): + (JSC::FTL::LowerDFGToLLVM::compileIsFunction): + (JSC::FTL::LowerDFGToLLVM::compileTypeOf): + (JSC::FTL::LowerDFGToLLVM::buildTypeOf): Reusable TypeOf building for the FTL. + (JSC::FTL::LowerDFGToLLVM::isExoticForTypeof): + * ftl/FTLSwitchCase.h: + (JSC::FTL::SwitchCase::SwitchCase): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::branchIfNotEqual): + (JSC::AssemblyHelpers::branchIfEqual): + (JSC::AssemblyHelpers::branchIfNumber): + (JSC::AssemblyHelpers::branchIfNotNumber): + (JSC::AssemblyHelpers::branchIfBoolean): + (JSC::AssemblyHelpers::branchIfNotBoolean): + (JSC::AssemblyHelpers::boxBooleanPayload): + (JSC::AssemblyHelpers::boxBoolean): + (JSC::AssemblyHelpers::emitTypeOf): Reusable TypeOf building for assembly JITs. + * jit/JITOperations.h: + * runtime/SmallStrings.h: + (JSC::SmallStrings::typeString): + * runtime/TypeofType.cpp: Added. + (WTF::printInternal): + * runtime/TypeofType.h: Added. + * tests/stress/type-of-functions-and-objects.js: Modified this test to give more comprehensive feedback. + +2015-05-02 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, add a FIXME referencing https://bugs.webkit.org/show_bug.cgi?id=144527. + + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::attemptHoist): + +2015-05-02 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, add FIXMEs referencing https://bugs.webkit.org/show_bug.cgi?id=144524 and + https://bugs.webkit.org/show_bug.cgi?id=144525. + + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGPhantomInsertionPhase.cpp: + +2015-05-02 Yusuke Suzuki <utatane.tea@gmail.com> + + Static property hashtable should only lookup with non-symbol key + https://bugs.webkit.org/show_bug.cgi?id=144438 + + Reviewed by Darin Adler. + + Static property hashtable compares the Identifier's uid + with the normal C string without interning it. + So this comparison is performed in their contents. + As the result, in this comparison, symbol-ness is not considered. + + So if accidentally the hash collision occur with the symbol and the string + and they have the same contents, the hash table entry is looked up incorrectly. + + * runtime/Lookup.h: + (JSC::HashTable::entry): + +2015-05-01 Ryosuke Niwa <rniwa@webkit.org> + + Class syntax should allow string and numeric identifiers for method names + https://bugs.webkit.org/show_bug.cgi?id=144254 + + Reviewed by Darin Adler. + + Added the support for string and numeric identifiers in class syntax. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): Instead of using ConstructorKind to indicate whether we're + inside a class or not, use the newly added SuperBinding argument instead. ConstructorKind is now None + outside a class constructor as it should be. + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseClass): No longer expects an identifier at the beginning of every class + element to allow numeric and string method names. For both of those method names, parse it here instead + of parseFunctionInfo since it doesn't support either type. Also pass in SuperBinding::Needed. + (JSC::Parser<LexerType>::parsePropertyMethod): Call parseFunctionInfo with SuperBinding::NotNeeded since + this function is never used to parse a class method. + (JSC::Parser<LexerType>::parseGetterSetter): Pass in superBinding argument to parseFunctionInfo. + (JSC::Parser<LexerType>::parsePrimaryExpression): Call parseFunctionInfo with SuperBinding::NotNeeded. + * parser/Parser.h: + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createProperty): + +2015-05-01 Filip Pizlo <fpizlo@apple.com> + + FTL should use AI more + https://bugs.webkit.org/show_bug.cgi?id=144500 + + Reviewed by Oliver Hunt. + + This makes our type check folding even more comprehensive by ensuring that even if the FTL + decides to emit some checks, it will still do another query to the abstract interpreter to + see if the check is necessary. This helps with cases where we decided early on to speculate + one way, but later proved a more specific type of the value in question, and the constant + folder didn't catch it. + + This also makes it more natural to query the abstract interpreter. For example, if you just + want the proven type, you can now say provenType(node) or provenType(edge). + + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::alreadyChecked): + * dfg/DFGArrayMode.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber): + (JSC::FTL::LowerDFGToLLVM::compileToThis): + (JSC::FTL::LowerDFGToLLVM::compileValueAdd): + (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): + (JSC::FTL::LowerDFGToLLVM::compileArithPow): + (JSC::FTL::LowerDFGToLLVM::compileArithNegate): + (JSC::FTL::LowerDFGToLLVM::compileGetById): + (JSC::FTL::LowerDFGToLLVM::compileCheckArray): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileToStringOrCallStringConstructor): + (JSC::FTL::LowerDFGToLLVM::compileToPrimitive): + (JSC::FTL::LowerDFGToLLVM::compileStringCharAt): + (JSC::FTL::LowerDFGToLLVM::compileStringCharCodeAt): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::compileIsBoolean): + (JSC::FTL::LowerDFGToLLVM::compileIsNumber): + (JSC::FTL::LowerDFGToLLVM::compileIsString): + (JSC::FTL::LowerDFGToLLVM::compileIsObject): + (JSC::FTL::LowerDFGToLLVM::compileInstanceOf): + (JSC::FTL::LowerDFGToLLVM::numberOrNotCellToInt32): + (JSC::FTL::LowerDFGToLLVM::baseIndex): + (JSC::FTL::LowerDFGToLLVM::compareEqObjectOrOtherToObject): + (JSC::FTL::LowerDFGToLLVM::typedArrayLength): + (JSC::FTL::LowerDFGToLLVM::boolify): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::lowInt32): + (JSC::FTL::LowerDFGToLLVM::lowInt52): + (JSC::FTL::LowerDFGToLLVM::lowCell): + (JSC::FTL::LowerDFGToLLVM::lowBoolean): + (JSC::FTL::LowerDFGToLLVM::lowDouble): + (JSC::FTL::LowerDFGToLLVM::isCellOrMisc): + (JSC::FTL::LowerDFGToLLVM::isNotCellOrMisc): + (JSC::FTL::LowerDFGToLLVM::isNumber): + (JSC::FTL::LowerDFGToLLVM::isNotNumber): + (JSC::FTL::LowerDFGToLLVM::isNotCell): + (JSC::FTL::LowerDFGToLLVM::isCell): + (JSC::FTL::LowerDFGToLLVM::isNotMisc): + (JSC::FTL::LowerDFGToLLVM::isMisc): + (JSC::FTL::LowerDFGToLLVM::isNotBoolean): + (JSC::FTL::LowerDFGToLLVM::isBoolean): + (JSC::FTL::LowerDFGToLLVM::isNotOther): + (JSC::FTL::LowerDFGToLLVM::isOther): + (JSC::FTL::LowerDFGToLLVM::isProvenValue): + (JSC::FTL::LowerDFGToLLVM::isObject): + (JSC::FTL::LowerDFGToLLVM::isNotObject): + (JSC::FTL::LowerDFGToLLVM::isNotString): + (JSC::FTL::LowerDFGToLLVM::isString): + (JSC::FTL::LowerDFGToLLVM::isFunction): + (JSC::FTL::LowerDFGToLLVM::isNotFunction): + (JSC::FTL::LowerDFGToLLVM::speculateObjectOrOther): + (JSC::FTL::LowerDFGToLLVM::speculateStringObjectForStructureID): + (JSC::FTL::LowerDFGToLLVM::speculateNotStringVar): + (JSC::FTL::LowerDFGToLLVM::abstractValue): + (JSC::FTL::LowerDFGToLLVM::provenType): + (JSC::FTL::LowerDFGToLLVM::provenValue): + (JSC::FTL::LowerDFGToLLVM::abstractStructure): + +2015-05-01 Martin Robinson <mrobinson@igalia.com> + + USE(...) macro should expect unprefixed variables + https://bugs.webkit.org/show_bug.cgi?id=144454 + + Reviewed by Daniel Bates. + + * CMakeLists.txt: Replace all occurrences WTF_USE with USE. + +2015-05-01 Jordan Harband <ljharb@gmail.com> + + String#startsWith/endsWith/includes don't handle Infinity position/endPosition args correctly + https://bugs.webkit.org/show_bug.cgi?id=144314 + + Reviewed by Darin Adler. + + Fixing handling of Infinity position args, per + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.startswith + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.endswith + + * runtime/StringPrototype.cpp: + (JSC::clampInt32): + (JSC::stringProtoFuncStartsWith): + (JSC::stringProtoFuncEndsWith): + (JSC::stringProtoFuncIncludes): + +2015-05-01 Basile Clement <basile_clement@apple.com> + + Math.abs() returns negative + https://bugs.webkit.org/show_bug.cgi?id=137827 + + Reviewed by Michael Saboff. + + Math.abs() on doubles was mistakenly assumed by the DFG AI to be the + identity function. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * tests/stress/math-abs-positive.js: Added, was previously failing. + (foo): + +2015-05-01 Basile Clement <basile_clement@apple.com> + + Function allocation sinking shouldn't be performed on singleton functions + https://bugs.webkit.org/show_bug.cgi?id=144166 + + Reviewed by Geoffrey Garen. + + Function allocations usually are free of any other side effects, but + this is not the case for allocations performed while the underlying + FunctionExecutable is still a singleton (as this allogation will fire + watchpoints invalidating code that depends on it being a singleton). + As the object allocation sinking phase assumes object allocation is + free of side-effects, sinking these allocations is not correct. + + This also means that when materializing a function allocation on OSR + exit, that function's executable will never be a singleton, and we don't have + to worry about its watchpoint, allowing us to use + JSFunction::createWithInvalidatedRellocationWatchpoint instead of + JSFunction::create. + + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): + +2015-04-30 Jon Davis <jond@apple.com> + + Web Inspector: console should show an icon for console.info() messages + https://bugs.webkit.org/show_bug.cgi?id=18530 + + Reviewed by Timothy Hatcher. + + * inspector/ConsoleMessage.cpp: + (Inspector::messageLevelValue): + * inspector/protocol/Console.json: + * runtime/ConsoleClient.cpp: + (JSC::appendMessagePrefix): + * runtime/ConsolePrototype.cpp: + (JSC::ConsolePrototype::finishCreation): + (JSC::consoleProtoFuncInfo): + * runtime/ConsoleTypes.h: + +2015-04-30 Filip Pizlo <fpizlo@apple.com> + + Move all of the branchIs<type> helpers from SpeculativeJIT into AssemblyHelpers + https://bugs.webkit.org/show_bug.cgi?id=144462 + + Reviewed by Geoffrey Garen and Mark Lam. + + At some point we started adding representation-agnostic helpers for doing common type tests. + We added some in SpeculativeJIT, and then some in AssemblyHelpers. Prior to this change, + they had overlapping powers, though SpeculativeJIT was a bit better. + + This removes SpeculativeJIT's helpers and strengthens AssemblyHelpers' helpers. This is + better because now all of these helpers can be used in all of the assembly-based JITs, not + just the DFG. It also settles on what I find to be a slightly better naming convention. + For example where we previously would have said branchIsString, now we say + branchIfString. Similarly, branchNotString becomes branchIfNotString. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): + (JSC::DFG::SpeculativeJIT::compileValueToInt32): + (JSC::DFG::SpeculativeJIT::compileInstanceOfForObject): + (JSC::DFG::SpeculativeJIT::compileInstanceOf): + (JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality): + (JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality): + (JSC::DFG::SpeculativeJIT::compileGetByValOnScopedArguments): + (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructorOnCell): + (JSC::DFG::SpeculativeJIT::speculateObject): + (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): + (JSC::DFG::SpeculativeJIT::speculateString): + (JSC::DFG::SpeculativeJIT::speculateNotStringVar): + (JSC::DFG::SpeculativeJIT::speculateNotCell): + (JSC::DFG::SpeculativeJIT::speculateOther): + (JSC::DFG::SpeculativeJIT::emitSwitchChar): + (JSC::DFG::SpeculativeJIT::emitSwitchString): + (JSC::DFG::SpeculativeJIT::branchIsObject): Deleted. + (JSC::DFG::SpeculativeJIT::branchNotObject): Deleted. + (JSC::DFG::SpeculativeJIT::branchIsString): Deleted. + (JSC::DFG::SpeculativeJIT::branchNotString): Deleted. + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::branchIsCell): Deleted. + (JSC::DFG::SpeculativeJIT::branchNotCell): Deleted. + (JSC::DFG::SpeculativeJIT::branchIsOther): Deleted. + (JSC::DFG::SpeculativeJIT::branchNotOther): Deleted. + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull): + (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + (JSC::DFG::SpeculativeJIT::writeBarrier): + (JSC::DFG::SpeculativeJIT::branchIsCell): Deleted. + (JSC::DFG::SpeculativeJIT::branchNotCell): Deleted. + (JSC::DFG::SpeculativeJIT::branchIsOther): Deleted. + (JSC::DFG::SpeculativeJIT::branchNotOther): Deleted. + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::branchIfCell): + (JSC::AssemblyHelpers::branchIfOther): + (JSC::AssemblyHelpers::branchIfNotOther): + (JSC::AssemblyHelpers::branchIfObject): + (JSC::AssemblyHelpers::branchIfNotObject): + (JSC::AssemblyHelpers::branchIfType): + (JSC::AssemblyHelpers::branchIfNotType): + (JSC::AssemblyHelpers::branchIfString): + (JSC::AssemblyHelpers::branchIfNotString): + (JSC::AssemblyHelpers::branchIfSymbol): + (JSC::AssemblyHelpers::branchIfNotSymbol): + (JSC::AssemblyHelpers::branchIfFunction): + (JSC::AssemblyHelpers::branchIfNotFunction): + (JSC::AssemblyHelpers::branchIfEmpty): + (JSC::AssemblyHelpers::branchIsEmpty): Deleted. + (JSC::AssemblyHelpers::branchIfCellNotObject): Deleted. + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitScopedArgumentsGetByVal): + +2015-04-30 Filip Pizlo <fpizlo@apple.com> + + js/regress/is-string-fold-tricky.html and js/regress/is-string-fold.html are crashing + https://bugs.webkit.org/show_bug.cgi?id=144463 + + Reviewed by Benjamin Poulain. + + Fixup phase was super cleverly folding an IsString(@x) when @x is predicted SpecString + into a Check(String:@x) followed by JSConstant(true). Then in these tests the + ValueAdd(IsString(@x), @stuff) would try to turn this into an integer add by cleverly + converting the boolean into an integer. But as part of doing that, it would try to + short-circuit any profiling by leveraging the fact that the IsString is now a constant, + and it would try to figure out if the addition might overflow. Part of that logic + involved checking if the immediate is either a boolean or a sufficiently small integer. + But: it would check if it's a sufficiently small integer before checking if it was a + boolean, so it would try to call asNumber() on the boolean. + + All of this cleverness was very deliberate, but apparently the @stuff + booleanConstant + case was previously never hit until I wrote these tests, and so we never knew that + calling asNumber() on a boolean was wrong. + + The fix is super simple: the expression should just check for boolean first. + + This bug was benign in release builds. JSValue::asNumber() on a boolean would return + garbage, and that's OK, since we'd take the boolean case anyway. + + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addImmediateShouldSpeculateInt32): + +2015-04-30 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, add a FIXME comment referencing https://bugs.webkit.org/show_bug.cgi?id=144458. + + * jit/JITOperations.cpp: + +2015-04-30 Filip Pizlo <fpizlo@apple.com> + + Add a comment clarifying the behavior and semantics of getCallData/getConstructData, in + particular that they cannot change their minds and may be called from compiler threads. + + Rubber stamped by Geoffrey Garen. + + * runtime/JSCell.h: + +2015-04-29 Filip Pizlo <fpizlo@apple.com> + + DFG Is<Blah> versions of TypeOf should fold based on proven input type + https://bugs.webkit.org/show_bug.cgi?id=144409 + + Reviewed by Geoffrey Garen. + + We were missing some obvious folding opportunities here. I don't know how this affects real + code, but in general, we like to ensure that our constant folding is comprehensive. So this + is more about placating my static analysis OCD than anything else. + + I added a bunch of speed/correctness tests for this in LayoutTests/js/regress. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + +2015-04-30 Yusuke Suzuki <utatane.tea@gmail.com> + + Use the default hash value for Symbolized StringImpl + https://bugs.webkit.org/show_bug.cgi?id=144347 + + Reviewed by Darin Adler. + + Before this patch, symbolized StringImpl* has a special hash value + to avoid the hash collision with the other normal StringImpl*. + I guess that it is introduced when private symbols are introduced. + However, it prevents using symbolized StringImpl* in the other place + For example, using it as WTFString cause a problem because of its special hash value. + + When only using private symbols, they are not exposed to the outside of JSC, + so we can handle it carefully. But now, it's extended to symbols. + So I think storing a special hash value in StringImpl* causes an error. + + To avoid this, I propose using the usual hash value in symbolized StringImpl*. + And to provide significantly different hash value when using it as symbol, + store the additional hash value in symbolized StringImpl*. It is used when + the hash value is required by IdentifierRepHash. + + * runtime/Identifier.h: + (JSC::IdentifierRepHash::hash): + * runtime/Lookup.h: + (JSC::HashTable::entry): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::find): + (JSC::PropertyTable::get): + * runtime/Structure.cpp: + (JSC::PropertyTable::checkConsistency): + +2015-04-29 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Remove RageConvert array conversion + https://bugs.webkit.org/show_bug.cgi?id=144433 + + Reviewed by Filip Pizlo. + + RageConvert was causing a subtle bug that was hitting the Kraken crypto tests + pretty hard: + -The indexing types shows that the array access varies between Int32 and DoubleArray. + -ArrayMode::fromObserved() decided to use the most generic type: DoubleArray. + An Arrayify node would convert the Int32 to that type. + -Somewhere, a GetByVal or PutByVal would have the flag NodeBytecodeUsesAsInt. That + node would use RageConvert instead of Convert. + -The Arrayify for that GetByVal with RageConvert would not convert the array to + Contiguous. + -All the following array access that do not have the flag NodeBytecodeUsesAsInt would + now expect a DoubleArray and always get a Contiguous Array. The CheckStructure + fail systematically and we never get to run the later code. + + Getting rid of RageConvert fixes the problem and does not seems to have any + negative side effect on other benchmarks. + + The improvments on Kraken are: + -stanford-crypto-aes: definitely 1.0915x faster. + -stanford-crypto-pbkdf2: definitely 1.2446x faster. + -stanford-crypto-sha256-iterative: definitely 1.0544x faster. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::refine): + (JSC::DFG::arrayConversionToString): + * dfg/DFGArrayMode.h: + * dfg/DFGArrayifySlowPathGenerator.h: + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + * runtime/JSObject.cpp: + (JSC::JSObject::convertDoubleToContiguous): + (JSC::JSObject::ensureContiguousSlow): + (JSC::JSObject::genericConvertDoubleToContiguous): Deleted. + (JSC::JSObject::rageConvertDoubleToContiguous): Deleted. + (JSC::JSObject::rageEnsureContiguousSlow): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::rageEnsureContiguous): Deleted. + +2015-04-29 Joseph Pecoraro <pecoraro@apple.com> + + Gracefully handle missing auto pause key on remote inspector setup + https://bugs.webkit.org/show_bug.cgi?id=144411 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::receivedSetupMessage): + +2015-04-29 Joseph Pecoraro <pecoraro@apple.com> + + NodeList has issues with Symbol and empty string + https://bugs.webkit.org/show_bug.cgi?id=144310 + + Reviewed by Darin Adler. + + * runtime/PropertyName.h: + (JSC::PropertyName::isSymbol): + Helper to check if the PropertyName is a string or symbol property. + +2015-04-29 Alex Christensen <achristensen@webkit.org> + + Fix non-cygwin incremental builds on Windows. + https://bugs.webkit.org/show_bug.cgi?id=143264 + + Reviewed by Brent Fulgham. + + * generate-js-builtins: + Remove stale headers before calling os.rename to replace them. + +2015-04-29 Filip Pizlo <fpizlo@apple.com> + + JSTypeInfo should have an inline type flag to indicate of getCallData() has been overridden + https://bugs.webkit.org/show_bug.cgi?id=144397 + + Reviewed by Andreas Kling. + + Add the flag to JSTypeInfo. It's an inline flag so that it's fast to query. Slap the flag on + callback objects and internal functions. Modify the TypeOf operation to use this flag to avoid + making a getCallData() call if it isn't necessary. + + * API/JSCallbackObject.h: + * runtime/InternalFunction.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::typeOfShouldCallGetCallData): + * runtime/Operations.cpp: + (JSC::jsTypeStringForValue): + * tests/stress/type-of-functions-and-objects.js: Added. + (foo): + (bar): + (baz): + (fuzz): + (expect): + (test): + +2015-04-28 Geoffrey Garen <ggaren@apple.com> + + It shouldn't take 1846 lines of code and 5 FIXMEs to sort an array. + https://bugs.webkit.org/show_bug.cgi?id=144013 + + Reviewed by Mark Lam. + + This patch implements Array.prototype.sort in JavaScript, removing the + C++ implementations. It is simpler and less error-prone to express our + operations in JavaScript, which provides memory safety, exception safety, + and recursion safety. + + The performance result is mixed, but net positive in my opinion. It's + difficult to enumerate all the results, since we used to have so many + different sorting modes, and there are lots of different data patterns + across which you might want to measure sorting. Suffice it to say: + + (*) The benchmarks we track are faster or unchanged. + + (*) Sorting random input using a comparator -- which we think is + common -- is 3X faster. + + (*) Sorting random input in a non-array object -- which jQuery does + -- is 4X faster. + + (*) Sorting random input in a compact array of integers using a + trivial pattern-matchable comparator is 2X *slower*. + + * builtins/Array.prototype.js: + (sort.min): + (sort.stringComparator): + (sort.compactSparse): Special case compaction for sparse arrays because + we don't want to hang when sorting new Array(BIG). + + (sort.compact): + (sort.merge): + (sort.mergeSort): Use merge sort because it's a reasonably efficient + stable sort. We have evidence that some sites depend on stable sort, + even though the ES6 spec does not mandate it. (See + <http://trac.webkit.org/changeset/33967>.) + + This is a textbook implementation of merge sort with three optimizations: + + (1) Use iteration instead of recursion; + + (2) Use array subscripting instead of array copying in order to + create logical sub-lists without creating physical sub-lists; + + (3) Swap src and dst at each iteration instead of copying src into + dst, and only copy src into the subject array at the end if src is + not the subject array. + + (sort.inflate): + (sort.comparatorSort): + (sort): Sort in JavaScript for the win. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createExecutableInternal): Allow non-private + names so we can use helper functions. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::isNumericCompareFunction): Deleted. + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::setIsNumericCompareFunction): Deleted. + (JSC::UnlinkedCodeBlock::isNumericCompareFunction): Deleted. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::setIsNumericCompareFunction): Deleted. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionNode::emitBytecode): We don't do this special casing based + on pattern matching anymore. This was mainly an optimization to avoid + the overhead of calling from C++ to JS, which we now avoid by + sorting in JS. + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::pushTempSortVector): Deleted. + (JSC::Heap::popTempSortVector): Deleted. + (JSC::Heap::visitTempSortVectors): Deleted. + * heap/Heap.h: We don't have temp sort vectors anymore because we sort + in JavaScript using a normal JavaScript array for our temporary storage. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): Allow capturing so we can use + helper functions. + + * runtime/ArrayPrototype.cpp: + (JSC::isNumericCompareFunction): Deleted. + (JSC::attemptFastSort): Deleted. + (JSC::performSlowSort): Deleted. + (JSC::arrayProtoFuncSort): Deleted. + + * runtime/CommonIdentifiers.h: New strings used by sort. + + * runtime/JSArray.cpp: + (JSC::compareNumbersForQSortWithInt32): Deleted. + (JSC::compareNumbersForQSortWithDouble): Deleted. + (JSC::compareNumbersForQSort): Deleted. + (JSC::compareByStringPairForQSort): Deleted. + (JSC::JSArray::sortNumericVector): Deleted. + (JSC::JSArray::sortNumeric): Deleted. + (JSC::ContiguousTypeAccessor::getAsValue): Deleted. + (JSC::ContiguousTypeAccessor::setWithValue): Deleted. + (JSC::ContiguousTypeAccessor::replaceDataReference): Deleted. + (JSC::ContiguousTypeAccessor<ArrayWithDouble>::getAsValue): Deleted. + (JSC::ContiguousTypeAccessor<ArrayWithDouble>::setWithValue): Deleted. + (JSC::ContiguousTypeAccessor<ArrayWithDouble>::replaceDataReference): Deleted. + (JSC::JSArray::sortCompactedVector): Deleted. + (JSC::JSArray::sort): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::get_less): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::set_less): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::get_greater): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::set_greater): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::get_balance_factor): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::set_balance_factor): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_key): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_node): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::compare_node_node): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::null): Deleted. + (JSC::JSArray::sortVector): Deleted. + (JSC::JSArray::compactForSorting): Deleted. + * runtime/JSArray.h: + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::finishCreation): Provide some builtins used + by sort. + +2015-04-29 Mark Lam <mark.lam@apple.com> + + Safari WebKit crash when loading Google Spreadsheet. + https://bugs.webkit.org/show_bug.cgi?id=144020 + + Reviewed by Filip Pizlo. + + The bug is that the object allocation sinking phase did not account for a case + where a property of a sunken object is only initialized on one path and not + another. As a result, on the path where the property is not initialized, we'll + encounter an Upsilon with a BottomValue (which is not allowed by definition). + + The fix is to use a JSConstant(undefined) as the bottom value instead (of + BottomValue). If the property is uninitialized, it should still be accessible + and have the value undefined. + + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + * tests/stress/object-allocation-sinking-with-uninitialized-property-on-one-path.js: Added. + (foo): + (foo2): + +2015-04-29 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION (r183373): ASSERT failed in wtf/SHA1.h + https://bugs.webkit.org/show_bug.cgi?id=144257 + + Reviewed by Darin Adler. + + SHA1 is used to calculate CodeBlockHash. + To calculate hash value, we pass the source code UTF-8 CString to SHA1::addBytes. + However, the source code can contain null character. + So when performing `strlen` on the source code's CString, it returns the incorrect length. + In SHA1::addBytes, there's assertion `input.length() == strlen(string)` and it fails. + + In the template-literal-syntax.js, we perform `eval` with the script contains "\0". + As the result, `strlen(string)` accidentally shortened by the contained "\0", and assertion fails. + + CString will be changed not to contain a null-character[1]. However, inserting the assertion here + is not correct. Because + + 1. If CString should not contain a null character, this should be asserted in CString side instead of SHA1::addBytes. + 2. If CString can contain a null character, this assertion becomes incorrect. + + So this patch just drops the assertion. + + In the current implementation, we once convert the entire source code to the newly allocated + UTF-8 string and pass it to the SHA1 processing. However, this is memory consuming. + Ideally, we should stream the decoded bytes into the SHA1 processing iteratively. + We'll implement it in the separate patch[2]. + + [1]: https://bugs.webkit.org/show_bug.cgi?id=144339 + [2]: https://bugs.webkit.org/show_bug.cgi?id=144263 + + * tests/stress/eval-script-contains-null-character.js: Added. + (shouldBe): + (test): + * tests/stress/template-literal-line-terminators.js: + * tests/stress/template-literal-syntax.js: + * tests/stress/template-literal.js: + +2015-04-29 Filip Pizlo <fpizlo@apple.com> + + Evict IsEnvironmentRecord from inline type flags + https://bugs.webkit.org/show_bug.cgi?id=144398 + + Reviewed by Mark Lam and Michael Saboff. + + In https://bugs.webkit.org/show_bug.cgi?id=144397, we'll need an extra bit in the inline + type flags. This change picks the least important inline type flag - IsEnvironmentRecord - + and evicts it into the out-of-line type flags. This change has no performance implications + because we never even accessed IsEnvironmentRecord via the StructureIDBlob. The only place + where we access it at all is in String.prototype.repeat, and there we already load the + structure anyway. + + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::implementsHasInstance): + (JSC::TypeInfo::structureIsImmortal): + (JSC::TypeInfo::isEnvironmentRecord): + +2015-04-29 Darin Adler <darin@apple.com> + + [ES6] Implement Unicode code point escapes + https://bugs.webkit.org/show_bug.cgi?id=144377 + + Reviewed by Antti Koivisto. + + * parser/Lexer.cpp: Moved the UnicodeHexValue class in here from + the header. Made it a non-member class so it doesn't need to be part + of a template. Made it use UChar32 instead of int for the value to + make it clearer what goes into this class. + (JSC::ParsedUnicodeEscapeValue::isIncomplete): Added. Replaces the + old type() function. + (JSC::Lexer<CharacterType>::parseUnicodeEscape): Renamed from + parseFourDigitUnicodeHex and added support for code point escapes. + (JSC::isLatin1): Added an overload for UChar32. + (JSC::isIdentStart): Changed this to take UChar32; no caller tries + to call it with a UChar, so no need to overload for that type for now. + (JSC::isNonLatin1IdentPart): Changed argument type to UChar32 for clarity. + Also added FIXME about a subtle ES6 change that we might want to make later. + (JSC::isIdentPart): Changed this to take UChar32; no caller tries + to call it with a UChar, so no need to overload for that type for now. + (JSC::isIdentPartIncludingEscapeTemplate): Made this a template so that we + don't need to repeat the code twice. Added code to handle code point escapes. + (JSC::isIdentPartIncludingEscape): Call the template instead of having the + code in line. + (JSC::Lexer<CharacterType>::recordUnicodeCodePoint): Added. + (JSC::Lexer<CharacterType>::parseIdentifierSlowCase): Made small tweaks and + updated to call parseUnicodeEscape instead of parseFourDigitUnicodeHex. + (JSC::Lexer<CharacterType>::parseComplexEscape): Call parseUnicodeEscape + instead of parseFourDigitUnicodeHex. Move the code to handle "\u" before + the code that handles the escapes, since the code point escape code now + consumes characters while parsing rather than peeking ahead. Test case + covers this: Symptom would be that "\u{" would evaluate to "u" instead of + giving a syntax error. + + * parser/Lexer.h: Updated for above changes. + + * runtime/StringConstructor.cpp: + (JSC::stringFromCodePoint): Use ICU's UCHAR_MAX_VALUE instead of writing + out 0x10FFFF; clearer this way. + +2015-04-29 Martin Robinson <mrobinson@igalia.com> + + [CMake] [GTK] Organize and clean up unused CMake variables + https://bugs.webkit.org/show_bug.cgi?id=144364 + + Reviewed by Gyuyoung Kim. + + * PlatformGTK.cmake: Add variables specific to this project. + +2015-04-28 Filip Pizlo <fpizlo@apple.com> + + TypeOf should return SpecStringIdent and the DFG should know this + https://bugs.webkit.org/show_bug.cgi?id=144376 + + Reviewed by Andreas Kling. + + Make TypeOf return atomic strings. That's a simple change in SmallStrings. + + Make the DFG know this and use it for optimization. This makes Switch(TypeOf) a bit less + bad. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGAbstractValue.cpp: + (JSC::DFG::AbstractValue::setType): + * dfg/DFGAbstractValue.h: + (JSC::DFG::AbstractValue::setType): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * runtime/SmallStrings.cpp: + (JSC::SmallStrings::initialize): + * tests/stress/switch-typeof-indirect.js: Added. + (bar): + (foo): + (test): + * tests/stress/switch-typeof-slightly-indirect.js: Added. + (foo): + (test): + * tests/stress/switch-typeof.js: Added. + (foo): + (test): + +2015-04-29 Joseph Pecoraro <pecoraro@apple.com> + + REGRESSION(181868): Windows Live SkyDrive cannot open an excel file + https://bugs.webkit.org/show_bug.cgi?id=144373 + + Reviewed by Darin Adler. + + Revert r181868 as it caused a failure on live.com. We can try + re-enabling this exception after we make idl attributes configurable, + which may have prevented this particular failure. + + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + +2015-04-28 Joseph Pecoraro <pecoraro@apple.com> + + Deadlock on applications using JSContext on non-main thread + https://bugs.webkit.org/show_bug.cgi?id=144370 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::singleton): + Prevent a possible deadlock by assuming we can synchronously + run something on the main queue at this time. + +2015-04-28 Filip Pizlo <fpizlo@apple.com> + + FTL should fully support Switch (it currently lacks the SwitchString variant) + https://bugs.webkit.org/show_bug.cgi?id=144348 + + Reviewed by Benjamin Poulain. + + This adds SwitchString support to the FTL. This is already tested by switch microbenchmarks + in LayoutTests/js/regress. + + * dfg/DFGCommon.cpp: + (JSC::DFG::stringLessThan): + * dfg/DFGCommon.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::StringSwitchCase::operator<): Deleted. + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::StringSwitchCase::operator<): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::switchString): + (JSC::FTL::LowerDFGToLLVM::StringSwitchCase::StringSwitchCase): + (JSC::FTL::LowerDFGToLLVM::StringSwitchCase::operator<): + (JSC::FTL::LowerDFGToLLVM::CharacterCase::CharacterCase): + (JSC::FTL::LowerDFGToLLVM::CharacterCase::operator<): + (JSC::FTL::LowerDFGToLLVM::switchStringRecurse): + (JSC::FTL::LowerDFGToLLVM::switchStringSlow): + (JSC::FTL::LowerDFGToLLVM::appendOSRExit): + * ftl/FTLOutput.cpp: + (JSC::FTL::Output::check): + * ftl/FTLOutput.h: + * ftl/FTLWeight.h: + (JSC::FTL::Weight::inverse): + * jit/JITOperations.h: + +2015-04-28 Michael Catanzaro <mcatanzaro@igalia.com> + + Fully replace ENABLE_LLINT_C_LOOP with ENABLE_JIT + https://bugs.webkit.org/show_bug.cgi?id=144304 + + Reviewed by Geoffrey Garen. + + * Configurations/FeatureDefines.xcconfig: Define ENABLE_JIT, enabled by default, instead of + ENABLE_LLINT_C_LOOP, disabled by default. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): Check ENABLE_JIT instead of ENABLE_LLINT_C_LOOP. + +2015-04-28 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r183514. + https://bugs.webkit.org/show_bug.cgi?id=144359 + + It broke cloop test bots (Requested by mcatanzaro on #webkit). + + Reverted changeset: + + "Fully replace ENABLE_LLINT_C_LOOP with ENABLE_JIT" + https://bugs.webkit.org/show_bug.cgi?id=144304 + http://trac.webkit.org/changeset/183514 + +2015-04-28 Michael Catanzaro <mcatanzaro@igalia.com> + + Fully replace ENABLE_LLINT_C_LOOP with ENABLE_JIT + https://bugs.webkit.org/show_bug.cgi?id=144304 + + Reviewed by Geoffrey Garen. + + * Configurations/FeatureDefines.xcconfig: Define ENABLE_JIT, enabled by default, instead of + ENABLE_LLINT_C_LOOP, disabled by default. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): Check ENABLE_JIT instead of ENABLE_LLINT_C_LOOP. + +2015-04-28 Joseph Pecoraro <pecoraro@apple.com> + + Fix common typo "targetting" => "targeting" + https://bugs.webkit.org/show_bug.cgi?id=144349 + + Reviewed by Daniel Bates. + + * bytecode/ExecutionCounter.h: + +2015-04-28 Yusuke Suzuki <utatane.tea@gmail.com> + + Update the features.json for WeakSet, WeakMap, Template literals, Tagged templates + https://bugs.webkit.org/show_bug.cgi?id=144328 + + Reviewed by Andreas Kling. + + Update the status of ES6 features. + + * features.json: + +2015-04-28 Filip Pizlo <fpizlo@apple.com> + + DFG should not use or preserve Phantoms during transformations + https://bugs.webkit.org/show_bug.cgi?id=143736 + + Reviewed by Geoffrey Garen. + + Since http://trac.webkit.org/changeset/183207 and http://trac.webkit.org/changeset/183406, it is + no longer necessary to preserve Phantoms during transformations. They are still useful just + before FixupPhase to support backwards propagation analyses. They are still inserted late in the + game in the DFG backend. But transformations don't need to worry about them. Inside a basic + block, we can be sure that so long as the IR pinpoints the place where the value becomes + available in a bytecode register (using MovHint) and so long as there is a SetLocal anytime some + other block would need the value (either for OSR or for DFG execution), then we don't need any + liveness markers. + + So, this removes any places where we inserted Phantoms just for liveness during transformation + and it replaces convertToPhantom() with remove(), which just converts the node to a Check. A + Check node only keeps its children so long as those children have checks. + + The fact that we no longer convertToPhantom() means that we have to be more careful when + constant-folding GetLocal. Previously we would convertToPhantom() and use the fact that + Phantom(Phi) was a valid construct. It's not valid anymore. So, when constant folding encounters + a GetLocal it needs to insert a PhantomLocal directly. This allows us to simplify + Graph::convertToConstant() a bit. Luckily, none of the other users of this method would see + GetLocals. + + The only Phantom-like cruft left over after this patch is: + + - Phantoms before FixupPhase. I kind of like these. It means that before FixupPhase, we can do + backwards analyses and rely on the fact that the users of a node in DFG IR are a superset of + the users of the original local's live range in bytecode. This is essential for supporting our + BackwardsPropagationPhase, which is an important optimization for things like asm.js. + + - PhantomLocals and GetLocals being NodeMustGenerate. See discussion in + https://bugs.webkit.org/show_bug.cgi?id=144086. It appears that this is not as evil as the + alternatives. The best long-term plan is to simply ditch the ThreadedCPS IR entirely and have + the DFG use SSA. For now, so long as any new DFG optimizations we add are block-local and + treat GetLocal/SetLocal conservatively, this should all be sound. + + This change should be perf-neutral although it does reduce the total work that the compiler + does. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAdjacencyList.h: + (JSC::DFG::AdjacencyList::justChecks): + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::replaceTerminal): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::findTerminal): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::keepOperandAlive): + (JSC::DFG::CFGSimplificationPhase::mergeBlocks): + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::CPSRethreadingPhase): + (JSC::DFG::CPSRethreadingPhase::clearVariables): + (JSC::DFG::CPSRethreadingPhase::canonicalizeFlushOrPhantomLocalFor): + (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock): + * dfg/DFGCSEPhase.cpp: + * dfg/DFGCleanUpPhase.cpp: Copied from Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp. + (JSC::DFG::CleanUpPhase::CleanUpPhase): + (JSC::DFG::CleanUpPhase::run): + (JSC::DFG::performCleanUp): + (JSC::DFG::PhantomRemovalPhase::PhantomRemovalPhase): Deleted. + (JSC::DFG::PhantomRemovalPhase::run): Deleted. + (JSC::DFG::performPhantomRemoval): Deleted. + * dfg/DFGCleanUpPhase.h: Copied from Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.h. + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + (JSC::DFG::ConstantFoldingPhase::addBaseCheck): + (JSC::DFG::ConstantFoldingPhase::fixUpsilons): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + (JSC::DFG::DCEPhase::fixupBlock): + (JSC::DFG::DCEPhase::cleanVariables): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupBlock): + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::convertStringAddUse): + (JSC::DFG::FixupPhase::attemptToMakeFastStringAdd): + (JSC::DFG::FixupPhase::checkArray): + (JSC::DFG::FixupPhase::fixIntConvertingEdge): + (JSC::DFG::FixupPhase::fixIntOrBooleanEdge): + (JSC::DFG::FixupPhase::fixDoubleOrBooleanEdge): + (JSC::DFG::FixupPhase::injectTypeConversionsInBlock): + (JSC::DFG::FixupPhase::tryToRelaxRepresentation): + (JSC::DFG::FixupPhase::injectTypeConversionsForEdge): + (JSC::DFG::FixupPhase::addRequiredPhantom): Deleted. + (JSC::DFG::FixupPhase::addPhantomsIfNecessary): Deleted. + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::convertToConstant): + (JSC::DFG::Graph::mergeRelevantToOSR): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertCheck): + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::handleBlock): + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::remove): + * dfg/DFGNode.h: + (JSC::DFG::Node::replaceWith): + (JSC::DFG::Node::convertToPhantom): Deleted. + (JSC::DFG::Node::convertToCheck): Deleted. + (JSC::DFG::Node::willHaveCodeGenOrOSR): Deleted. + * dfg/DFGNodeFlags.h: + * dfg/DFGNodeType.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPhantomCanonicalizationPhase.cpp: Removed. + * dfg/DFGPhantomCanonicalizationPhase.h: Removed. + * dfg/DFGPhantomRemovalPhase.cpp: Removed. + * dfg/DFGPhantomRemovalPhase.h: Removed. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPutStackSinkingPhase.cpp: + * dfg/DFGResurrectionForValidationPhase.cpp: Removed. + * dfg/DFGResurrectionForValidationPhase.h: Removed. + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateDouble): + * dfg/DFGStoreBarrierElisionPhase.cpp: + (JSC::DFG::StoreBarrierElisionPhase::elideBarrier): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + (JSC::DFG::StrengthReductionPhase::convertToIdentityOverChild): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + (JSC::DFG::Validate::validateCPS): + (JSC::DFG::Validate::validateSSA): + * dfg/DFGVarargsForwardingPhase.cpp: + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileNoOp): + (JSC::FTL::LowerDFGToLLVM::compilePhantom): Deleted. + +2015-04-28 Andreas Kling <akling@apple.com> + + DFG+FTL should generate efficient code for branching on a string's boolean value. + <https://webkit.org/b/144317> + + Reviewed by Geoff Garen & Filip Pizlo + + Teach Branch nodes about StringUse and have them generate an efficient zero-length string check + instead of dropping out to C++ whenever we branch on a string. + + The FTL JIT already handled Branch nodes with StringUse through its use of boolify(), so only + the DFG JIT gets some new codegen logic in this patch. + + Test: js/regress/branch-on-string-as-boolean.js (~4.5x speedup) + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitStringBranch): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitBranch): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitBranch): + +2015-04-28 Filip Pizlo <fpizlo@apple.com> + + VarargsForwardingPhase should only consider MovHints that have the candidate as a child + https://bugs.webkit.org/show_bug.cgi?id=144340 + + Reviewed by Michael Saboff and Mark Lam. + + Since we were considering all MovHints, we'd assume that the CreateDirectArguments or + CreateClosedArguments node was live so long as any MovHinted bytecode variable was alive. + Basically, we'd keep it alive until the end of the block. This maximized the chances of + there being an interfering operation, which would prevent elimination. + + The fix is to only consider MovHints that have the arguments candidate as a child. We only + care to track the liveness of those bytecode locals that would need an arguments object + recovery on OSR exit. + + This is a speed-up on V8Spider/raytrace and Octane/raytrace because it undoes the regression + introduced in http://trac.webkit.org/changeset/183406. + + * dfg/DFGVarargsForwardingPhase.cpp: + +2015-04-28 Csaba Osztrogonác <ossy@webkit.org> + + Remove WinCE cruft from cmake build system + https://bugs.webkit.org/show_bug.cgi?id=144325 + + Reviewed by Gyuyoung Kim. + + * CMakeLists.txt: + * create_jit_stubs: Removed. + +2015-04-27 Andreas Kling <akling@apple.com> + + RegExp matches arrays should use contiguous indexing. + <https://webkit.org/b/144286> + + Reviewed by Geoffrey Garen. + + We had a custom Structure being used for RegExp matches arrays that would + put the arrays into SlowPutArrayStorageShape mode. This was just left + from when matches arrays were custom, lazily initialized objects. + + This change removes that Structure and switches the matches arrays to + using the default ContiguousShape Structure. This allows the FTL JIT + to compile the inner loop of the Octane/regexp benchmark. + + Also made a version of initializeIndex() [inline] that takes the indexing + type in an argument, allowing createRegExpMatchesArray() to initialize + the entire array without branching on the indexing type for each entry. + + ~3% progression on Octane/regexp. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::mapStructure): + (JSC::JSGlobalObject::regExpMatchesArrayStructure): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::initializeIndex): + * runtime/RegExpMatchesArray.cpp: + (JSC::createRegExpMatchesArray): + +2015-04-27 Filip Pizlo <fpizlo@apple.com> + + FTL failed to initialize arguments.callee on the slow path as well as the fast path + https://bugs.webkit.org/show_bug.cgi?id=144293 + + Reviewed by Mark Lam. + + The slow path doesn't fully initialize DirectArguments - it leaves callee blank. So, we need + to initialize the callee on the common path after the fast and slow path. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCreateDirectArguments): + * tests/stress/arguments-callee-uninitialized.js: Added. + (foo): + +2015-04-27 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Add support for typed arrays to the Array profiling + https://bugs.webkit.org/show_bug.cgi?id=143913 + + Reviewed by Filip Pizlo. + + This patch adds ArrayModes for every typed arrays. Having that information + let us generate better GetByVal and PutByVal when the type speculation + are not good enough. + + A typical case where this is useful is any basic block for which the type + of the object is always more restrictive than the speculation (for example, + a basic block gated by a branch only taken for on type). + + * bytecode/ArrayProfile.cpp: + (JSC::dumpArrayModes): + * bytecode/ArrayProfile.h: + (JSC::arrayModeFromStructure): + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::fromObserved): + (JSC::DFG::ArrayMode::refine): + Maintain the refine() semantic. We do not support OutOfBounds access + for GetByVal on typed array. + + * runtime/IndexingType.h: + * tests/stress/typed-array-get-by-val-profiling.js: Added. + (testArray.testCode): + (testArray): + * tests/stress/typed-array-put-by-val-profiling.js: Added. + (testArray.testCode): + (testArray): + +2015-04-27 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, roll out r183438 "RegExp matches arrays should use contiguous indexing". It + causes many debug test failures. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::regExpMatchesArrayStructure): + * runtime/JSObject.h: + (JSC::JSObject::initializeIndex): + * runtime/RegExpMatchesArray.cpp: + (JSC::createRegExpMatchesArray): + +2015-04-27 Andreas Kling <akling@apple.com> + + RegExp matches arrays should use contiguous indexing. + <https://webkit.org/b/144286> + + Reviewed by Geoffrey Garen. + + We had a custom Structure being used for RegExp matches arrays that would + put the arrays into SlowPutArrayStorageShape mode. This was just left + from when matches arrays were custom, lazily initialized objects. + + This change removes that Structure and switches the matches arrays to + using the default ContiguousShape Structure. This allows the FTL JIT + to compile the inner loop of the Octane/regexp benchmark. + + Also made a version of initializeIndex() [inline] that takes the indexing + type in an argument, allowing createRegExpMatchesArray() to initialize + the entire array without branching on the indexing type for each entry. + + ~3% progression on Octane/regexp. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::mapStructure): + (JSC::JSGlobalObject::regExpMatchesArrayStructure): Deleted. + * runtime/JSObject.h: + (JSC::JSObject::initializeIndex): + * runtime/RegExpMatchesArray.cpp: + (JSC::createRegExpMatchesArray): + +2015-04-27 Ryosuke Niwa <rniwa@webkit.org> + + REGRESSION (r183373): ASSERT failed in wtf/SHA1.h + https://bugs.webkit.org/show_bug.cgi?id=144257 + + Temporarily disable skip these tests. + + * tests/stress/template-literal-line-terminators.js: + * tests/stress/template-literal-syntax.js: + * tests/stress/template-literal.js: + +2015-04-27 Basile Clement <basile_clement@apple.com> + + Function allocations shouldn't sink through Put operations + https://bugs.webkit.org/show_bug.cgi?id=144176 + + Reviewed by Filip Pizlo. + + By design, we don't support function allocation sinking through any + related operation ; however object allocation can sink through PutByOffset et + al. + + Currently, the checks to prevent function allocation to sink through + these are misguided and do not prevent anything ; function allocation sinking + through these operations is prevented as a side effect of requiring an + AllocatePropertyStorage through which the function allocation is seen as + escaping. + + This changes it so that ObjectAllocationSinkingPhase::handleNode() + checks properly that only object allocations sink through related write + operations. + + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + +2015-04-25 Filip Pizlo <fpizlo@apple.com> + + VarargsForwardingPhase should use bytecode liveness in addition to other uses to determine the last point that a candidate is used + https://bugs.webkit.org/show_bug.cgi?id=143843 + + Reviewed by Geoffrey Garen. + + It will soon come to pass that Phantom isn't available at the time that + VarargsForwardingPhase runs. So, it needs to use some other mechanism for discovering when + a value dies for OSR. + + This is simplified by two things: + + 1) The bytecode kill analysis is now reusable. This patch makes it even more reusable than + before by polishing the API. + + 2) This phase already operates on one node at a time and allows itself to do a full search + of the enclosing basic block for that node. This is fine because CreateDirectArguments + and friends is a rarely occurring node. The fact that it operates on one node at a time + makes it even easier to reason about OSR liveness - we just track the list of locals in + which it is live. + + This change has no effect right now but it is a necessary prerequisite to implementing + https://bugs.webkit.org/show_bug.cgi?id=143736. + + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::tryAt): + * dfg/DFGForAllKills.h: + (JSC::DFG::forAllKilledOperands): + * dfg/DFGPhantomInsertionPhase.cpp: + * dfg/DFGVarargsForwardingPhase.cpp: + +2015-04-27 Jordan Harband <ljharb@gmail.com> + + Map#entries and Map#keys error for non-Maps is swapped + https://bugs.webkit.org/show_bug.cgi?id=144253 + + Reviewed by Simon Fraser. + + Correcting error messages on Set/Map methods when called on + incompatible objects. + + * runtime/MapPrototype.cpp: + (JSC::mapProtoFuncEntries): + (JSC::mapProtoFuncKeys): + * runtime/SetPrototype.cpp: + (JSC::setProtoFuncEntries): + +2015-04-24 Filip Pizlo <fpizlo@apple.com> + + Rationalize DFG DCE handling of nodes that perform checks that propagate through AI + https://bugs.webkit.org/show_bug.cgi?id=144186 + + Reviewed by Geoffrey Garen. + + If I do ArithAdd(Int32Use, Int32Use, CheckOverflow) then AI will prove that this returns + Int32. We may later perform code simplifications based on the proof that this is Int32, and + we may kill all DFG users of this ArithAdd. Then we may prove that there is no exit site at + which the ArithAdd is live. This seems like it is sufficient to then kill the ArithAdd, + except that we still need the overflow check! + + Previously we mishandled this: + + - In places where we want the overflow check we need to use MustGenerate(@ArithAdd) as a hack + to keep it alive. That's dirty and it's just indicative of a deeper issue. + + - Our MovHint removal doesn't do Phantom canonicalization which essentially makes it + powerless. This was sort of hiding the bug. + + - Nodes that have checks that AI leverages should always be NodeMustGenerate. You can't kill + something that you are relying on for subsequent simplifications. + + This fixes MovHint removal to also canonicalize Phantoms. This also adds ModeMustGenerate to + nodes that may perform checks that are used by AI to guarantee the result type. As a result, + we no longer need the weird MustGenerate node. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::tryToRelaxRepresentation): + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::handleBlock): + (JSC::DFG::IntegerCheckCombiningPhase::insertMustAdd): Deleted. + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGNode.h: + (JSC::DFG::Node::willHaveCodeGenOrOSR): + * dfg/DFGNodeType.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPhantomCanonicalizationPhase.cpp: + (JSC::DFG::PhantomCanonicalizationPhase::run): + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): + * dfg/DFGVarargsForwardingPhase.cpp: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * tests/stress/fold-based-on-int32-proof-mul-branch.js: Added. + (foo): + * tests/stress/fold-based-on-int32-proof-mul.js: Added. + (foo): + * tests/stress/fold-based-on-int32-proof-or-zero.js: Added. + (foo): + * tests/stress/fold-based-on-int32-proof.js: Added. + (foo): + +2015-04-26 Ryosuke Niwa <rniwa@webkit.org> + + Class body ending with a semicolon throws a SyntaxError + https://bugs.webkit.org/show_bug.cgi?id=144244 + + Reviewed by Darin Adler. + + The bug was caused by parseClass's inner loop for method definitions not moving onto the next iteration + it encounters a semicolon. As a result, we always expected a method to appear after a semicolon. Fixed + it by continue'ing when it encounters a semicolon. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + +2015-04-26 Ryosuke Niwa <rniwa@webkit.org> + + Getter or setter method named "prototype" or "constrcutor" should throw SyntaxError + https://bugs.webkit.org/show_bug.cgi?id=144243 + + Reviewed by Darin Adler. + + Fixed the bug by adding explicit checks in parseGetterSetter when we're parsing class methods. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseGetterSetter): + +2015-04-26 Jordan Harband <ljharb@gmail.com> + + Map#forEach does not pass "map" argument to callback. + https://bugs.webkit.org/show_bug.cgi?id=144187 + + Reviewed by Darin Adler. + + Per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map.prototype.foreach + step 7.a.i., the callback should be called with three arguments. + + * runtime/MapPrototype.cpp: + (JSC::mapProtoFuncForEach): + +2015-04-26 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement ES6 template literals + https://bugs.webkit.org/show_bug.cgi?id=142691 + + Reviewed by Darin Adler. + + This patch implements TemplateLiteral. + Since TaggedTemplate requires some global states and + primitive operations like GetTemplateObject, + we separate the patch. It will be implemented in a subsequent patch. + + Template Literal Syntax is guarded by ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX compile time flag. + By disabling it, we can disable Template Literal support. + + To implement template literals, in this patch, + we newly introduces bytecode op_to_string. + In template literals, we alternately evaluate the expression and + perform ToString onto the result of evaluation. + For example, + + `${f1()} ${f2()}` + + In this template literal, execution order is the following, + 1. calling f1() + 2. ToString(the result of f1()) + 3. calling f2() + 4. ToString(the result of f2()) + + op_strcat also performs ToString. However, performing ToString + onto expressions are batched in op_strcat, it's not the same to the + template literal spec. In the above example, + ToString(f1()) should be called before calling f2(). + + * Configurations/FeatureDefines.xcconfig: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitToString): + (JSC::BytecodeGenerator::emitToNumber): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::TemplateStringNode::emitBytecode): + (JSC::TemplateLiteralNode::emitBytecode): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_to_string): + (JSC::JIT::emitSlow_op_to_string): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_to_string): + (JSC::JIT::emitSlow_op_to_string): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createTemplateString): + (JSC::ASTBuilder::createTemplateStringList): + (JSC::ASTBuilder::createTemplateExpressionList): + (JSC::ASTBuilder::createTemplateLiteral): + * parser/Lexer.cpp: + (JSC::Lexer<T>::Lexer): + (JSC::Lexer<T>::parseIdentifierSlowCase): + (JSC::Lexer<T>::parseString): + (JSC::LineNumberAdder::LineNumberAdder): + (JSC::LineNumberAdder::clear): + (JSC::LineNumberAdder::add): + (JSC::Lexer<T>::parseTemplateLiteral): + (JSC::Lexer<T>::lex): + (JSC::Lexer<T>::scanRegExp): + (JSC::Lexer<T>::scanTrailingTemplateString): + (JSC::Lexer<T>::parseStringSlowCase): Deleted. + * parser/Lexer.h: + * parser/NodeConstructors.h: + (JSC::TemplateExpressionListNode::TemplateExpressionListNode): + (JSC::TemplateStringNode::TemplateStringNode): + (JSC::TemplateStringListNode::TemplateStringListNode): + (JSC::TemplateLiteralNode::TemplateLiteralNode): + * parser/Nodes.h: + (JSC::TemplateExpressionListNode::value): + (JSC::TemplateExpressionListNode::next): + (JSC::TemplateStringNode::cooked): + (JSC::TemplateStringNode::raw): + (JSC::TemplateStringListNode::value): + (JSC::TemplateStringListNode::next): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseTemplateString): + (JSC::Parser<LexerType>::parseTemplateLiteral): + (JSC::Parser<LexerType>::parsePrimaryExpression): + * parser/Parser.h: + * parser/ParserTokens.h: + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createTemplateString): + (JSC::SyntaxChecker::createTemplateStringList): + (JSC::SyntaxChecker::createTemplateExpressionList): + (JSC::SyntaxChecker::createTemplateLiteral): + (JSC::SyntaxChecker::createSpreadExpression): Deleted. + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * tests/stress/template-literal-line-terminators.js: Added. + (test): + (testEval): + (testEvalLineNumber): + * tests/stress/template-literal-syntax.js: Added. + (testSyntax): + (testSyntaxError): + * tests/stress/template-literal.js: Added. + (test): + (testEval): + (testEmbedded): + +2015-04-26 Jordan Harband <ljharb@gmail.com> + + Set#forEach does not pass "key" or "set" arguments to callback. + https://bugs.webkit.org/show_bug.cgi?id=144188 + + Reviewed by Darin Adler. + + Per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-set.prototype.foreach + Set#forEach should pass 3 arguments to the callback. + + * runtime/SetPrototype.cpp: + (JSC::setProtoFuncForEach): + +2015-04-26 Benjamin Poulain <benjamin@webkit.org> + + [JSC] Implement Math.clz32(), remove Number.clz() + https://bugs.webkit.org/show_bug.cgi?id=144205 + + Reviewed by Michael Saboff. + + This patch adds the ES6 function Math.clz32(), and remove the non-standard + Number.clz(). Number.clz() probably came from an older draft. + + The new function has a corresponding instrinsic: Clz32Intrinsic, + and a corresponding DFG node: ArithClz32, optimized all the way to LLVM. + + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::countLeadingZeros32): + * assembler/X86Assembler.h: + (JSC::X86Assembler::bsr_rr): + The x86 assembler did not have countLeadingZeros32() because there is + no native CLZ instruction on that architecture. + + I have added the version with bsr + branches for the case of zero. + An other popular version uses cmov to handle the case of zero. I kept + it simple since the Assembler has no support for cmov. + + It is unlikely to matter much. If the code is hot enough, LLVM picks + something good based on the surrounding code. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + Constant handling + effect propagation. The node only produces integer (between 0 and 32). + + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + Thanks to the definition of toUint32(), we can ignore plenty of details + from doubles. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithClz32): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileArithClz32): + * ftl/FTLOutput.h: + (JSC::FTL::Output::ctlz32): + * jit/ThunkGenerators.cpp: + (JSC::clz32ThunkGenerator): + * jit/ThunkGenerators.h: + * runtime/Intrinsic.h: + * runtime/MathCommon.h: + (JSC::clz32): + Fun fact: InstCombine does not recognize this pattern to eliminate + the branch which makes our FTL version better than the C version. + + * runtime/MathObject.cpp: + (JSC::MathObject::finishCreation): + (JSC::mathProtoFuncClz32): + * runtime/NumberPrototype.cpp: + (JSC::clz): Deleted. + (JSC::numberProtoFuncClz): Deleted. + * runtime/VM.cpp: + (JSC::thunkGeneratorForIntrinsic): + * tests/stress/math-clz32-basics.js: Added. + (mathClz32OnInteger): + (testMathClz32OnIntegers): + (verifyMathClz32OnIntegerWithOtherTypes): + (mathClz32OnDouble): + (testMathClz32OnDoubles): + (verifyMathClz32OnDoublesWithOtherTypes): + (mathClz32NoArguments): + (mathClz32TooManyArguments): + (testMathClz32OnConstants): + (mathClz32StructTransition): + (Math.clz32): + +2015-04-26 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Array.from need to accept iterables + https://bugs.webkit.org/show_bug.cgi?id=141055 + + Reviewed by Darin Adler. + + ES6 spec requires that Array.from accepts iterable objects. + This patch introduces this functionality, Array.from accepting iterable objects. + + Currently, `isConstructor` is not used. Instead of it, `typeof thiObj === "function"` is used. + However, it doesn't conform to the spec. While `isConstructor` queries the given object has `[[Construct]]`, + `typeof thisObj === "function"` queries the given object has `[[Call]]`. + This will be fixed in the subsequent patch[1]. + + [1]: https://bugs.webkit.org/show_bug.cgi?id=144093 + + * builtins/ArrayConstructor.js: + (from): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * tests/stress/array-from-with-iterable.js: Added. + (shouldBe): + (.set for): + (.set var): + (.get var): + (argumentsGenerators): + (.set shouldBe): + (.set new): + * tests/stress/array-from-with-iterator.js: Added. + (shouldBe): + (shouldThrow): + (createIterator.iterator.return): + (createIterator): + (.): + +2015-04-25 Jordan Harband <ljharb@gmail.com> + + Set#keys !== Set#values + https://bugs.webkit.org/show_bug.cgi?id=144190 + + Reviewed by Darin Adler. + + per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-set.prototype.keys + Set#keys should === Set#values + + * runtime/SetPrototype.cpp: + (JSC::SetPrototype::finishCreation): + (JSC::setProtoFuncValues): + (JSC::setProtoFuncEntries): + (JSC::setProtoFuncKeys): Deleted. + +2015-04-25 Joseph Pecoraro <pecoraro@apple.com> + + Allow for pausing a JSContext when opening a Web Inspector + <rdar://problem/20564788> + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::receivedSetupMessage): + * inspector/remote/RemoteInspectorConstants.h: + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + On any incoming setup message, we may want to automatically + pause the debuggable. If requested, pause the debuggable + after we have setup the frontend connection. + + * runtime/JSGlobalObjectDebuggable.h: + * runtime/JSGlobalObjectDebuggable.cpp: + (JSC::JSGlobalObjectDebuggable::pause): + Pass through to the inspector controller. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::pause): + Enable pause on next statement. + +2015-04-23 Ryosuke Niwa <rniwa@webkit.org> + + class methods should be non-enumerable + https://bugs.webkit.org/show_bug.cgi?id=143181 + + Reviewed by Darin Adler. + + Fixed the bug by using Object.defineProperty to define methods. + + This patch adds the concept of link time constants and uses it to resolve Object.defineProperty + inside CodeBlock's constructor since bytecode can be linked against multiple global objects. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): Resolve link time constants that are used. Ignore ones with register + index of zero. + * bytecode/SpecialPointer.h: Added a new enum for link time constants. It currently contains + exactly one entry for Object.defineProperty. + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::addConstant): Added. Like addConstant that takes JSValue, allocate a new + constant register for the link time constant we're adding. + (JSC::UnlinkedCodeBlock::registerIndexForLinkTimeConstant): Added. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitMoveLinkTimeConstant): Added. Like addConstantValue, allocate a new + register for the specified link time constant and notify UnlinkedCodeBlock about it. + (JSC::BytecodeGenerator::emitCallDefineProperty): Added. Create a new property descriptor and call + Object.defineProperty with it. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitBytecode): Make static and non-static getters and setters for classes + non-enumerable by using emitCallDefineProperty to define them. + (JSC::PropertyListNode::emitPutConstantProperty): Ditto for a non-accessor properties. + (JSC::ClassExprNode::emitBytecode): Make prototype.constructor non-enumerable and make prototype + property on the class non-writable, non-configurable, and non-enumerable by using defineProperty. + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): Set m_definePropertyFunction. + (JSC::JSGlobalObject::visitChildren): Visit m_definePropertyFunction. + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::definePropertyFunction): Added. + (JSC::JSGlobalObject::actualPointerFor): Added a variant that takes LinkTimeConstant. + (JSC::JSGlobalObject::jsCellForLinkTimeConstant): Like actualPointerFor, takes LinkTimeConstant and + returns a JSCell; e.g. Object.defineProperty. + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::addDefineProperty): Added. Returns Object.defineProperty. + * runtime/ObjectConstructor.h: + +2015-04-25 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement String.fromCodePoint + https://bugs.webkit.org/show_bug.cgi?id=144160 + + Reviewed by Darin Adler. + + This patch implements String.fromCodePoint. + It accepts multiple code points and generates a string that consists of given code points. + The range [0x0000 - 0x10FFFF] is valid for code points. + If the given value is out of range, throw a range error. + + When a 0xFFFF <= valid code point is given, + String.fromCodePoint generates a string that contains surrogate pairs. + + * runtime/StringConstructor.cpp: + (JSC::stringFromCodePoint): + (JSC::constructWithStringConstructor): + * tests/stress/string-from-code-point.js: Added. + (shouldBe): + (shouldThrow): + (toCodePoints): + (passThrough): + +2015-04-25 Martin Robinson <mrobinson@igalia.com> + + Rename ENABLE_3D_RENDERING to ENABLE_3D_TRANSFORMS + https://bugs.webkit.org/show_bug.cgi?id=144182 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: Replace all instances of 3D_RENDERING with 3D_TRANSFORMS. + +2015-04-25 Mark Lam <mark.lam@apple.com> + + mayExit() is wrong about Branch nodes with ObjectOrOtherUse: they can exit. + https://bugs.webkit.org/show_bug.cgi?id=144152 + + Reviewed by Filip Pizlo. + + Changed the EdgeMayExit functor to recognize ObjectUse, ObjectOrOtherUse, + StringObjectUse, and StringOrStringObjectUse kinds as potentially triggering + OSR exits. This was overlooked in the original code. + + While only the ObjectOrOtherUse kind is relevant for manifesting this bug with + the Branch node, the other 3 may also trigger the same bug for other nodes. + To prevent this bug from manifesting with other nodes (and future ones that + are yet to be added to mayExits()'s "potential won't exit" set), we fix the + EdgeMayExit functor to handle all 4 use kinds (instead of just ObjectOrOtherUse). + + Also added a test to exercise a code path that will trigger this bug with + the Branch node before the fix is applied. + + * dfg/DFGMayExit.cpp: + * tests/stress/branch-may-exit-due-to-object-or-other-use-kind.js: Added. + (inlinedFunction): + (foo): + +2015-04-24 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r183288. + https://bugs.webkit.org/show_bug.cgi?id=144189 + + Made js/sort-with-side-effecting-comparisons.html time out in + debug builds (Requested by ap on #webkit). + + Reverted changeset: + + "It shouldn't take 1846 lines of code and 5 FIXMEs to sort an + array." + https://bugs.webkit.org/show_bug.cgi?id=144013 + http://trac.webkit.org/changeset/183288 + +2015-04-24 Filip Pizlo <fpizlo@apple.com> + + CRASH in operationCreateDirectArgumentsDuringExit() + https://bugs.webkit.org/show_bug.cgi?id=143962 + + Reviewed by Geoffrey Garen. + + We shouldn't assume that constant-like OSR exit values are always recoverable. They are only + recoverable so long as they are live. Therefore, OSR exit should track liveness of + constants instead of assuming that they are always live. + + * dfg/DFGGenerationInfo.h: + (JSC::DFG::GenerationInfo::noticeOSRBirth): + (JSC::DFG::GenerationInfo::appendBirth): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + * dfg/DFGVariableEvent.cpp: + (JSC::DFG::VariableEvent::dump): + * dfg/DFGVariableEvent.h: + (JSC::DFG::VariableEvent::birth): + (JSC::DFG::VariableEvent::id): + (JSC::DFG::VariableEvent::dataFormat): + * dfg/DFGVariableEventStream.cpp: + (JSC::DFG::VariableEventStream::reconstruct): + * tests/stress/phantom-direct-arguments-clobber-argument-count.js: Added. + (foo): + (bar): + * tests/stress/phantom-direct-arguments-clobber-callee.js: Added. + (foo): + (bar): + +2015-04-24 Benjamin Poulain <bpoulain@apple.com> + + [JSC] When inserting a NaN into a Int32 array, we convert it to DoubleArray then to ContiguousArray + https://bugs.webkit.org/show_bug.cgi?id=144169 + + Reviewed by Geoffrey Garen. + + * runtime/JSObject.cpp: + (JSC::JSObject::convertInt32ForValue): + DoubleArray do not store NaN, they are used for holes. + What happened was: + 1) We fail to insert the NaN in the Int32 array because it is a double. + 2) We were converting the array to DoubleArray. + 3) We were trying to insert the value again. We would fail again because + DoubleArray does not store NaN. + 4) We would convert the DoubleArrayt to Contiguous Array, converting the values + to boxed values. + + * tests/stress/int32array-transition-on-nan.js: Added. + The behavior is not really observable. This only test nothing crashes in those + cases. + + (insertNaNWhileFilling): + (testInsertNaNWhileFilling): + (insertNaNAfterFilling): + (testInsertNaNAfterFilling): + (pushNaNWhileFilling): + (testPushNaNWhileFilling): + +2015-04-21 Geoffrey Garen <ggaren@apple.com> + + It shouldn't take 1846 lines of code and 5 FIXMEs to sort an array. + https://bugs.webkit.org/show_bug.cgi?id=144013 + + Reviewed by Mark Lam. + + This patch implements Array.prototype.sort in JavaScript, removing the + C++ implementations. It is simpler and less error-prone to express our + operations in JavaScript, which provides memory safety, exception safety, + and recursion safety. + + The performance result is mixed, but net positive in my opinion. It's + difficult to enumerate all the results, since we used to have so many + different sorting modes, and there are lots of different data patterns + across which you might want to measure sorting. Suffice it to say: + + (*) The benchmarks we track are faster or unchanged. + + (*) Sorting random input using a comparator -- which we think is + common -- is 3X faster. + + (*) Sorting random input in a non-array object -- which jQuery does + -- is 4X faster. + + (*) Sorting random input in a compact array of integers using a + trivial pattern-matchable comparator is 2X *slower*. + + * builtins/Array.prototype.js: + (sort.min): + (sort.stringComparator): + (sort.compactSparse): Special case compaction for sparse arrays because + we don't want to hang when sorting new Array(BIG). + + (sort.compact): + (sort.merge): + (sort.mergeSort): Use merge sort because it's a reasonably efficient + stable sort. We have evidence that some sites depend on stable sort, + even though the ES6 spec does not mandate it. (See + <http://trac.webkit.org/changeset/33967>.) + + This is a textbook implementation of merge sort with three optimizations: + + (1) Use iteration instead of recursion; + + (2) Use array subscripting instead of array copying in order to + create logical sub-lists without creating physical sub-lists; + + (3) Swap src and dst at each iteration instead of copying src into + dst, and only copy src into the subject array at the end if src is + not the subject array. + + (sort.inflate): + (sort.comparatorSort): + (sort): Sort in JavaScript for the win. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createExecutableInternal): Allow non-private + names so we can use helper functions. + + * bytecode/CodeBlock.h: + (JSC::CodeBlock::isNumericCompareFunction): Deleted. + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::setIsNumericCompareFunction): Deleted. + (JSC::UnlinkedCodeBlock::isNumericCompareFunction): Deleted. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::setIsNumericCompareFunction): Deleted. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionNode::emitBytecode): We don't do this special casing based + on pattern matching anymore. This was mainly an optimization to avoid + the overhead of calling from C++ to JS, which we now avoid by + sorting in JS. + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::pushTempSortVector): Deleted. + (JSC::Heap::popTempSortVector): Deleted. + (JSC::Heap::visitTempSortVectors): Deleted. + * heap/Heap.h: We don't have temp sort vectors anymore because we sort + in JavaScript using a normal JavaScript array for our temporary storage. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): Allow capturing so we can use + helper functions. + + * runtime/ArrayPrototype.cpp: + (JSC::isNumericCompareFunction): Deleted. + (JSC::attemptFastSort): Deleted. + (JSC::performSlowSort): Deleted. + (JSC::arrayProtoFuncSort): Deleted. + + * runtime/CommonIdentifiers.h: New strings used by sort. + + * runtime/JSArray.cpp: + (JSC::compareNumbersForQSortWithInt32): Deleted. + (JSC::compareNumbersForQSortWithDouble): Deleted. + (JSC::compareNumbersForQSort): Deleted. + (JSC::compareByStringPairForQSort): Deleted. + (JSC::JSArray::sortNumericVector): Deleted. + (JSC::JSArray::sortNumeric): Deleted. + (JSC::ContiguousTypeAccessor::getAsValue): Deleted. + (JSC::ContiguousTypeAccessor::setWithValue): Deleted. + (JSC::ContiguousTypeAccessor::replaceDataReference): Deleted. + (JSC::ContiguousTypeAccessor<ArrayWithDouble>::getAsValue): Deleted. + (JSC::ContiguousTypeAccessor<ArrayWithDouble>::setWithValue): Deleted. + (JSC::ContiguousTypeAccessor<ArrayWithDouble>::replaceDataReference): Deleted. + (JSC::JSArray::sortCompactedVector): Deleted. + (JSC::JSArray::sort): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::get_less): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::set_less): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::get_greater): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::set_greater): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::get_balance_factor): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::set_balance_factor): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_key): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_node): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::compare_node_node): Deleted. + (JSC::AVLTreeAbstractorForArrayCompare::null): Deleted. + (JSC::JSArray::sortVector): Deleted. + (JSC::JSArray::compactForSorting): Deleted. + * runtime/JSArray.h: + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::finishCreation): Provide some builtins used + by sort. + +2015-04-24 Matthew Mirman <mmirman@apple.com> + + Made Object.prototype.__proto__ native getter and setter check that this object not null or undefined + https://bugs.webkit.org/show_bug.cgi?id=141865 + rdar://problem/19927273 + + Reviewed by Filip Pizlo. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncProtoGetter): + (JSC::globalFuncProtoSetter): + +2015-04-23 Benjamin Poulain <bpoulain@apple.com> + + Remove a useless branch on DFGGraph::addShouldSpeculateMachineInt() + https://bugs.webkit.org/show_bug.cgi?id=144118 + + Reviewed by Geoffrey Garen. + + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addShouldSpeculateMachineInt): + Both block do the same thing. + +2015-04-23 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Speculative fix for non-main thread auto-attach failures + https://bugs.webkit.org/show_bug.cgi?id=144134 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::singleton): + +2015-04-23 Basile Clement <basile_clement@apple.com> + + Allow function allocation sinking + https://bugs.webkit.org/show_bug.cgi?id=144016 + + Reviewed by Filip Pizlo. + + This adds the ability to sink function allocations in the + DFGObjectAllocationSinkingPhase. + + In order to enable this, we add a new PhantomNewFunction node that is + used similarily to the PhantomNewObject node, i.e. as a placeholder to replace + a sunk NewFunction and keep track of the allocations that have to be performed + in case of OSR exit after the sunk allocation but before the real one. + The FunctionExecutable and JSLexicalEnvironment (activation) of the function + are stored onto the PhantomNewFunction through PutHints in order for them + to be recovered on OSR exit. + + Contrary to sunk object allocations, sunk function allocations do not + support any kind of operations (e.g. storing into a field) ; any such operation + will mark the function allocation as escaping and trigger materialization. As + such, function allocations can only be sunk to places where it would have been + correct to syntactically move them, and we don't need a special + MaterializeNewFunction node to recover possible operations on the function. A + sunk NewFunction node will simply create new NewFunction nodes, then replace + itself with a PhantomNewFunction node. + + In itself, this change is not expected to have a significant impact on + performances other than in degenerate cases (see e.g. + JSRegress/sink-function), but it is a step towards being able to sink recursive + closures onces we support CreateActivation sinking as well as allocation cycles + sinking. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPhantomNewFunction): + (JSC::DFG::Node::isPhantomAllocation): + * dfg/DFGNodeType.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize): + (JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGPromotedHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGPromotedHeapLocation.h: + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): + * tests/stress/function-sinking-no-double-allocate.js: Added. + (call): + (.f): + (sink): + * tests/stress/function-sinking-osrexit.js: Added. + (.g): + (sink): + * tests/stress/function-sinking-put.js: Added. + (.g): + (sink): + +2015-04-23 Basile Clement <basile_clement@apple.com> + + Make FunctionRareData allocation thread-safe + https://bugs.webkit.org/show_bug.cgi?id=144001 + + Reviewed by Mark Lam. + + The two things we want to prevent are: + + 1. A thread seeing a pointer to a not-yet-fully-created rare data from + a JSFunction + 2. A thread seeing a pointer to a not-yet-fully-created Structure from + an ObjectAllocationProfile + + For 1., only the JS thread can be creating the rare data (in + runtime/CommonSlowPaths.cpp or in dfg/DFGOperations.cpp), so we don't need to + worry about concurrent writes, and we don't need any fences when *reading* the + rare data from the JS thread. Thus we only need a storeStoreFence between the + rare data creation and assignment to m_rareData in + JSFunction::createAndInitializeRareData() to ensure that when the store to + m_rareData is issued, the rare data has been properly created. + + For the DFG compilation threads, the only place they can access the + rare data is through JSFunction::rareData(), and so we only need a + loadLoadFence there to ensure that when we see a non-null pointer in + m_rareData, the pointed object will be seen as a fully created + FunctionRareData. + + + For 2., the structure is created in + ObjectAllocationProfile::initialize() (which appears to be called only by the + JS thread as well, in bytecode/CodeBlock.cpp and on rare data initialization, + which always happen in the JS thread), and read through + ObjectAllocationProfile::structure() and + ObjectAllocationProfile::inlineCapacity(), so following the same reasoning we + put a storeStoreFence in ObjectAllocationProfile::initialize() and a + loadLoadFence in ObjectAllocationProfile::structure() (and change + ObjectAllocationProfile::inlineCapacity() to go through + ObjectAllocationProfile::structure()). + + We don't need a fence in ObjectAllocationProfile::clear() because + clearing the structure is already as atomic as it gets. + + Finally, notice that we don't care about the ObjectAllocationProfile's + m_allocator as that is only used by ObjectAllocationProfile::initialize() and + ObjectAllocationProfile::clear() that are always run in the JS thread. + ObjectAllocationProfile::isNull() could cause some trouble, but it is + currently only used in the ObjectAllocationProfile::clear()'s ASSERT in the JS + thread. Doing isNull()-style pre-checks would be wrong in any other concurrent + thread anyway. + + * bytecode/ObjectAllocationProfile.h: + (JSC::ObjectAllocationProfile::initialize): + (JSC::ObjectAllocationProfile::structure): + (JSC::ObjectAllocationProfile::inlineCapacity): + * runtime/JSFunction.cpp: + (JSC::JSFunction::allocateAndInitializeRareData): + * runtime/JSFunction.h: + (JSC::JSFunction::rareData): + (JSC::JSFunction::allocationStructure): Deleted. + This is no longer used, as all the accesses to the ObjectAllocationProfile go through the rare data. + +2015-04-22 Filip Pizlo <fpizlo@apple.com> + + DFG should insert Phantoms late using BytecodeKills and block-local OSR availability + https://bugs.webkit.org/show_bug.cgi?id=143735 + + Reviewed by Geoffrey Garen. + + We've always had bugs arising from the fact that we would MovHint something into a local, + and then fail to keep it alive. We would then try to keep things alive by putting Phantoms + on those Nodes that were MovHinted. But this became increasingly tricky. Given the + sophistication of the transformations we are doing today, this approach is just not sound + anymore. + + This comprehensively fixes these bugs by having the DFG backend automatically insert + Phantoms just before codegen based on bytecode liveness. To make this practical, this also + makes it much faster to query bytecode liveness. + + It's about as perf-neutral as it gets for a change that increases compiler work without + actually optimizing anything. Later changes will remove the old Phantom-preserving logic, + which should then speed us up. I can't really report concrete slow-down numbers because + they are low enough to basically be in the noise. For example, a 20-iteration run of + SunSpider yields "maybe 0.8% slower", whatever that means. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeLivenessAnalysis.cpp: + (JSC::BytecodeLivenessAnalysis::computeFullLiveness): + * bytecode/FullBytecodeLiveness.h: + (JSC::FullBytecodeLiveness::getLiveness): + * bytecode/VirtualRegister.h: + (JSC::VirtualRegister::operator+): + (JSC::VirtualRegister::operator-): + * dfg/DFGForAllKills.h: + (JSC::DFG::forAllLiveNodesAtTail): + (JSC::DFG::forAllKilledOperands): + (JSC::DFG::forAllKilledNodesAtNodeIndex): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::isLiveInBytecode): + (JSC::DFG::Graph::localsLiveInBytecode): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::forAllLocalsLiveInBytecode): + (JSC::DFG::Graph::forAllLiveInBytecode): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGMovHintRemovalPhase.cpp: + * dfg/DFGNodeType.h: + * dfg/DFGPhantomInsertionPhase.cpp: Added. + (JSC::DFG::performPhantomInsertion): + * dfg/DFGPhantomInsertionPhase.h: Added. + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGScoreBoard.h: + (JSC::DFG::ScoreBoard::sortFree): + (JSC::DFG::ScoreBoard::assertClear): + * dfg/DFGVirtualRegisterAllocationPhase.cpp: + (JSC::DFG::VirtualRegisterAllocationPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + * tests/stress/phantom-inadequacy.js: Added. + (bar): + (baz): + (foo): + +2015-04-23 Filip Pizlo <fpizlo@apple.com> + + Rename HardPhantom to MustGenerate. + + Rubber stamped by Geoffrey Garen. + + We are steadily moving towards Phantom just being a backend hack in the DFG. HardPhantom + is more than that; it's a utility for forcing the execution of otherwise killable nodes. + NodeMustGenerate is the flag we use to indicate that something isn't killable. So this + node should just be called MustGenerate. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::tryToRelaxRepresentation): + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::insertMustAdd): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGNode.h: + (JSC::DFG::Node::willHaveCodeGenOrOSR): + * dfg/DFGNodeType.h: + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPhantomCanonicalizationPhase.cpp: + (JSC::DFG::PhantomCanonicalizationPhase::run): + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): + (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): + * dfg/DFGVarargsForwardingPhase.cpp: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + +2015-04-23 Jordan Harband <ljharb@gmail.com> + + Implement `Object.assign` + https://bugs.webkit.org/show_bug.cgi?id=143980 + + Reviewed by Filip Pizlo. + + per https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign + + * builtins/ObjectConstructor.js: Added. + (assign): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/ObjectConstructor.cpp: + * runtime/ObjectConstructor.h: + +2015-04-22 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix debug build. + + * dfg/DFGGraph.h: + (JSC::DFG::Graph::performSubstitutionForEdge): + +2015-04-22 Filip Pizlo <fpizlo@apple.com> + + Nodes should have an optional epoch field + https://bugs.webkit.org/show_bug.cgi?id=144084 + + Reviewed by Ryosuke Niwa and Mark Lam. + + This makes it easier to do epoch-based analyses on nodes. I plan to do just that in + https://bugs.webkit.org/show_bug.cgi?id=143735. Currently the epoch field is not yet + used. + + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::canonicalizeGetLocalFor): + * dfg/DFGCSEPhase.cpp: + * dfg/DFGEpoch.h: + (JSC::DFG::Epoch::fromUnsigned): + (JSC::DFG::Epoch::toUnsigned): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::clearReplacements): + (JSC::DFG::Graph::clearEpochs): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::performSubstitutionForEdge): + * dfg/DFGNode.h: + (JSC::DFG::Node::Node): + (JSC::DFG::Node::replaceWith): + (JSC::DFG::Node::replacement): + (JSC::DFG::Node::setReplacement): + (JSC::DFG::Node::epoch): + (JSC::DFG::Node::setEpoch): + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + +2015-04-22 Mark Lam <mark.lam@apple.com> + + Fix assertion failure and race condition in Options::dumpSourceAtDFGTime(). + https://bugs.webkit.org/show_bug.cgi?id=143898 + + Reviewed by Filip Pizlo. + + CodeBlock::dumpSource() will access SourceCode strings in a way that requires + ref'ing of the underlying StringImpls. This is unsafe to do from arbitrary + compilation threads because StringImpls are not thread safe. As a result, we get + an assertion failure when we run with JSC_dumpSourceAtDFGTime=true on a debug + build. + + This patch fixes the issue by only collecting the CodeBlock (and associated info) + into a DeferredSourceDump record while compiling, and stashing it away in a + deferredSourceDump list in the DeferredCompilationCallback object to be dumped + later. + + When compilation is done, the callback object will be notified that + compilationDidComplete(). We will dump the SourceCode strings from there. + Since compilationDidComplete() is guaranteed to only be called on the thread + doing JS execution, it is safe to access the SourceCode strings there and ref + their underlying StringImpls as needed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/DeferredCompilationCallback.cpp: + (JSC::DeferredCompilationCallback::compilationDidComplete): + (JSC::DeferredCompilationCallback::sourceDumpInfo): + (JSC::DeferredCompilationCallback::dumpCompiledSources): + * bytecode/DeferredCompilationCallback.h: + * bytecode/DeferredSourceDump.cpp: Added. + (JSC::DeferredSourceDump::DeferredSourceDump): + (JSC::DeferredSourceDump::dump): + * bytecode/DeferredSourceDump.h: Added. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + +2015-04-22 Benjamin Poulain <benjamin@webkit.org> + + Implement String.codePointAt() + https://bugs.webkit.org/show_bug.cgi?id=143934 + + Reviewed by Darin Adler. + + This patch adds String.codePointAt() as defined by ES6. + I opted for a C++ implementation for now. + + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + (JSC::codePointAt): + (JSC::stringProtoFuncCodePointAt): + +2015-04-22 Mark Lam <mark.lam@apple.com> + + SparseArrayEntry's write barrier owner should be the SparseArrayValueMap. + https://bugs.webkit.org/show_bug.cgi?id=144067 + + Reviewed by Michael Saboff. + + Currently, there are a few places where the JSObject that owns the + SparseArrayValueMap is designated as the owner of the SparseArrayEntry + write barrier. This is a bug and can result in the GC collecting the + SparseArrayEntry even though it is being referenced by the + SparseArrayValueMap. This patch fixes the bug. + + * runtime/JSObject.cpp: + (JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists): + (JSC::JSObject::putIndexedDescriptor): + * tests/stress/sparse-array-entry-update-144067.js: Added. + (useMemoryToTriggerGCs): + (foo): + +2015-04-22 Mark Lam <mark.lam@apple.com> + + Give the heap object iterators the ability to return early. + https://bugs.webkit.org/show_bug.cgi?id=144011 + + Reviewed by Michael Saboff. + + JSDollarVMPrototype::isValidCell() uses a heap object iterator to validate + candidate cell pointers, and, when in use, is called a lot more often than + the normal way those iterators are used. As a result, I see my instrumented + VM killed with a SIGXCPU (CPU time limit exceeded). This patch gives the + callback functor the ability to tell the iterators to return early when the + functor no longer needs to continue iterating. With this, my instrumented + VM is useful again for debugging. + + Since heap iteration is not something that we do in a typical fast path, + I don't expect this to have any noticeable impact on performance. + + I also renamed ObjectAddressCheckFunctor to CellAddressCheckFunctor since + it checks JSCell addresses, not just JSObjects. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * debugger/Debugger.cpp: + * heap/GCLogging.cpp: + (JSC::LoggingFunctor::operator()): + * heap/Heap.cpp: + (JSC::Zombify::visit): + (JSC::Zombify::operator()): + * heap/HeapStatistics.cpp: + (JSC::StorageStatistics::visit): + (JSC::StorageStatistics::operator()): + * heap/HeapVerifier.cpp: + (JSC::GatherLiveObjFunctor::visit): + (JSC::GatherLiveObjFunctor::operator()): + * heap/MarkedBlock.cpp: + (JSC::SetNewlyAllocatedFunctor::operator()): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::forEachCell): + (JSC::MarkedBlock::forEachLiveCell): + (JSC::MarkedBlock::forEachDeadCell): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::forEachLiveCell): + (JSC::MarkedSpace::forEachDeadCell): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::TypeRecompiler::visit): + (Inspector::TypeRecompiler::operator()): + * runtime/IterationStatus.h: Added. + * runtime/JSGlobalObject.cpp: + * runtime/VM.cpp: + (JSC::StackPreservingRecompiler::visit): + (JSC::StackPreservingRecompiler::operator()): + * tools/JSDollarVMPrototype.cpp: + (JSC::CellAddressCheckFunctor::CellAddressCheckFunctor): + (JSC::CellAddressCheckFunctor::operator()): + (JSC::JSDollarVMPrototype::isValidCell): + (JSC::ObjectAddressCheckFunctor::ObjectAddressCheckFunctor): Deleted. + (JSC::ObjectAddressCheckFunctor::operator()): Deleted. + +2015-04-22 Yusuke Suzuki <utatane.tea@gmail.com> + + [[Set]] should be properly executed in JS builtins + https://bugs.webkit.org/show_bug.cgi?id=143996 + + Reviewed by Geoffrey Garen. + + Currently, all assignments in builtins JS code is compiled into put_by_val_direct. + However, + + 1. Some functions (like Array.from) needs [[Set]]. (but it is now compiled into put_by_val_direct, [[DefineOwnProperty]]). + 2. It's different from the default JS behavior. + + In this patch, we implement the bytecode intrinsic emitting put_by_val_direct and use it explicitly. + And dropping the current hack for builtins. + + * builtins/Array.prototype.js: + (filter): + (map): + (find): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitPutByVal): + * tests/stress/array-fill-put-by-val.js: Added. + (shouldThrow): + (.set get array): + * tests/stress/array-filter-put-by-val-direct.js: Added. + (shouldBe): + (.set get var): + * tests/stress/array-find-does-not-lookup-twice.js: Added. + (shouldBe): + (shouldThrow): + (.get shouldBe): + * tests/stress/array-from-put-by-val-direct.js: Added. + (shouldBe): + (.set get var): + * tests/stress/array-from-set-length.js: Added. + (shouldBe): + (ArrayLike): + (ArrayLike.prototype.set length): + (ArrayLike.prototype.get length): + * tests/stress/array-map-put-by-val-direct.js: Added. + (shouldBe): + (.set get var): + +2015-04-22 Basile Clement <basile_clement@apple.com> + + Don't de-allocate FunctionRareData + https://bugs.webkit.org/show_bug.cgi?id=144000 + + Reviewed by Michael Saboff. + + A function rare data (containing most notably its allocation profile) is currently + freed and re-allocated each time the function's prototype is cleared. + This is not optimal as it means we are invalidating the watchpoint and recompiling the + scope each time the prototype is cleared. + + This makes it so that a single rare data is reused, clearing the underlying + ObjectAllocationProfile instead of throwing away the whole rare data on + .prototype updates. + + * runtime/FunctionRareData.cpp: + (JSC::FunctionRareData::create): + (JSC::FunctionRareData::finishCreation): + * runtime/FunctionRareData.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::allocateAndInitializeRareData): + (JSC::JSFunction::initializeRareData): + +2015-04-21 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix 32-bit. Forgot to make this simple change to 32_64 as well. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2015-04-21 Filip Pizlo <fpizlo@apple.com> + + DFG should allow Phantoms after terminals + https://bugs.webkit.org/show_bug.cgi?id=126778 + + Reviewed by Mark Lam. + + It's important for us to be able to place liveness-marking nodes after nodes that do + things. These liveness-marking nodes are nops. Previously, we disallowed such nodes after + terminals. That made things awkward, especially for Switch and Branch, which may do + things that necessitate liveness markers (for example they might want to use a converted + version of a value rather than the value that was MovHinted). We previously made this + work by disallowing certain optimizations on Switch and Branch, which was probably a bad + thing. + + This changes our IR to allow for the terminal to not be the last node in a block. Asking + for the terminal involves a search. DFG::validate() checks that the nodes after the + terminal are liveness markers that have no effects or checks. + + This is perf-neutral but will allow more optimizations in the future. It will also make + it cleaner to fix https://bugs.webkit.org/show_bug.cgi?id=143735. + + * dfg/DFGBasicBlock.cpp: + (JSC::DFG::BasicBlock::replaceTerminal): + * dfg/DFGBasicBlock.h: + (JSC::DFG::BasicBlock::findTerminal): + (JSC::DFG::BasicBlock::terminal): + (JSC::DFG::BasicBlock::insertBeforeTerminal): + (JSC::DFG::BasicBlock::numSuccessors): + (JSC::DFG::BasicBlock::successor): + (JSC::DFG::BasicBlock::successorForCondition): + (JSC::DFG::BasicBlock::successors): + (JSC::DFG::BasicBlock::last): Deleted. + (JSC::DFG::BasicBlock::takeLast): Deleted. + (JSC::DFG::BasicBlock::insertBeforeLast): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::SuccessorsIterable): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::iterator): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator*): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator++): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator==): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator!=): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::begin): Deleted. + (JSC::DFG::BasicBlock::SuccessorsIterable::end): Deleted. + * dfg/DFGBasicBlockInlines.h: + (JSC::DFG::BasicBlock::appendNonTerminal): + (JSC::DFG::BasicBlock::replaceTerminal): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addToGraph): + (JSC::DFG::ByteCodeParser::inlineCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::linkBlock): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGCFGSimplificationPhase.cpp: + (JSC::DFG::CFGSimplificationPhase::run): + (JSC::DFG::CFGSimplificationPhase::convertToJump): + (JSC::DFG::CFGSimplificationPhase::mergeBlocks): + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock): + * dfg/DFGCommon.h: + (JSC::DFG::NodeAndIndex::NodeAndIndex): + (JSC::DFG::NodeAndIndex::operator!): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupBlock): + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::injectTypeConversionsInBlock): + (JSC::DFG::FixupPhase::clearPhantomsAtEnd): Deleted. + * dfg/DFGForAllKills.h: + (JSC::DFG::forAllLiveNodesAtTail): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::terminalsAreValid): + (JSC::DFG::Graph::dumpBlockHeader): + * dfg/DFGGraph.h: + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::mergeToSuccessors): + * dfg/DFGLICMPhase.cpp: + (JSC::DFG::LICMPhase::run): + (JSC::DFG::LICMPhase::attemptHoist): + * dfg/DFGMovHintRemovalPhase.cpp: + * dfg/DFGNode.h: + (JSC::DFG::Node::SuccessorsIterable::SuccessorsIterable): + (JSC::DFG::Node::SuccessorsIterable::iterator::iterator): + (JSC::DFG::Node::SuccessorsIterable::iterator::operator*): + (JSC::DFG::Node::SuccessorsIterable::iterator::operator++): + (JSC::DFG::Node::SuccessorsIterable::iterator::operator==): + (JSC::DFG::Node::SuccessorsIterable::iterator::operator!=): + (JSC::DFG::Node::SuccessorsIterable::begin): + (JSC::DFG::Node::SuccessorsIterable::end): + (JSC::DFG::Node::successors): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints): + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + * dfg/DFGPhantomRemovalPhase.cpp: + (JSC::DFG::PhantomRemovalPhase::run): + * dfg/DFGPutStackSinkingPhase.cpp: + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStaticExecutionCountEstimationPhase.cpp: + (JSC::DFG::StaticExecutionCountEstimationPhase::run): + * dfg/DFGTierUpCheckInjectionPhase.cpp: + (JSC::DFG::TierUpCheckInjectionPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * tests/stress/closure-call-exit.js: Added. + (foo): + +2015-04-21 Basile Clement <basile_clement@apple.com> + + PhantomNewObject should be marked NodeMustGenerate + https://bugs.webkit.org/show_bug.cgi?id=143974 + + Reviewed by Filip Pizlo. + + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToPhantomNewObject): + Was not properly marking NodeMustGenerate when converting. + +2015-04-21 Filip Pizlo <fpizlo@apple.com> + + DFG Call/ConstructForwardVarargs fails to restore the stack pointer + https://bugs.webkit.org/show_bug.cgi?id=144007 + + Reviewed by Mark Lam. + + We were conditioning the stack pointer restoration on isVarargs, but we also need to do it + if isForwardVarargs. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * tests/stress/varargs-then-slow-call.js: Added. + (foo): + (bar): + (fuzz): + (baz): + +2015-04-21 Basile Clement <basile_clement@apple.com> + + Remove AllocationProfileWatchpoint node + https://bugs.webkit.org/show_bug.cgi?id=143999 + + Reviewed by Filip Pizlo. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::hasCellOperand): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + * runtime/JSFunction.h: + (JSC::JSFunction::rareData): + (JSC::JSFunction::allocationProfileWatchpointSet): Deleted. + +2015-04-19 Filip Pizlo <fpizlo@apple.com> + + MovHint should be a strong use + https://bugs.webkit.org/show_bug.cgi?id=143734 + + Reviewed by Geoffrey Garen. + + This disables any DCE that assumes equivalence between DFG IR uses and bytecode uses. Doing + so is a major step towards allowing more fancy DFG transformations and also probably fixing + some bugs. + + Just making MovHint a strong use would also completely disable DCE. So we mitigate this by + introducing a MovHint removal phase that runs in FTL. + + This is a slight slowdown on Octane/gbemu, but it's basically neutral on suite averages. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeOrigin.cpp: + (JSC::InlineCallFrame::dumpInContext): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::fixupBlock): + * dfg/DFGDisassembler.cpp: + (JSC::DFG::Disassembler::createDumpList): + * dfg/DFGEpoch.cpp: Added. + (JSC::DFG::Epoch::dump): + * dfg/DFGEpoch.h: Added. + (JSC::DFG::Epoch::Epoch): + (JSC::DFG::Epoch::first): + (JSC::DFG::Epoch::operator!): + (JSC::DFG::Epoch::next): + (JSC::DFG::Epoch::bump): + (JSC::DFG::Epoch::operator==): + (JSC::DFG::Epoch::operator!=): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGMovHintRemovalPhase.cpp: Added. + (JSC::DFG::performMovHintRemoval): + * dfg/DFGMovHintRemovalPhase.h: Added. + * dfg/DFGNodeType.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileCurrentBlock): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * runtime/Options.h: + +2015-04-21 Basile Clement <basile_clement@apple.com> + + REGRESSION (r182899): icloud.com crashes + https://bugs.webkit.org/show_bug.cgi?id=143960 + + Reviewed by Filip Pizlo. + + * runtime/JSFunction.h: + (JSC::JSFunction::allocationStructure): + * tests/stress/dfg-rare-data.js: Added. + (F): Regression test + +2015-04-21 Michael Saboff <msaboff@apple.com> + + Crash in JSC::Interpreter::execute + https://bugs.webkit.org/show_bug.cgi?id=142625 + + Reviewed by Filip Pizlo. + + We need to keep the FunctionExecutables in the code block for the eval flavor of + Interpreter::execute() in order to create the scope used to eval. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::jettisonFunctionDeclsAndExprs): Deleted. + * bytecode/CodeBlock.h: + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::registerFrozenValues): + +2015-04-21 Chris Dumez <cdumez@apple.com> + + Make Vector(const Vector<T, otherCapacity, otherOverflowBehaviour>&) constructor explicit + https://bugs.webkit.org/show_bug.cgi?id=143970 + + Reviewed by Darin Adler. + + Make Vector(const Vector<T, otherCapacity, otherOverflowBehaviour>&) + constructor explicit as it copies the vector and it is easy to call it + by mistake. + + * bytecode/UnlinkedInstructionStream.cpp: + (JSC::UnlinkedInstructionStream::UnlinkedInstructionStream): + * bytecode/UnlinkedInstructionStream.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + +2015-04-20 Basile Clement <basile_clement@apple.com> + + PhantomNewObject should be marked NodeMustGenerate + https://bugs.webkit.org/show_bug.cgi?id=143974 + + Reviewed by Filip Pizlo. + + * dfg/DFGNodeType.h: Mark PhantomNewObject as NodeMustGenerate + +2015-04-20 Joseph Pecoraro <pecoraro@apple.com> + + Cleanup some StringBuilder use + https://bugs.webkit.org/show_bug.cgi?id=143550 + + Reviewed by Darin Adler. + + * runtime/Symbol.cpp: + (JSC::Symbol::descriptiveString): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::typeInformationForExpressionAtOffset): + * runtime/TypeSet.cpp: + (JSC::TypeSet::toJSONString): + (JSC::StructureShape::propertyHash): + (JSC::StructureShape::stringRepresentation): + (JSC::StructureShape::toJSONString): + +2015-04-20 Mark Lam <mark.lam@apple.com> + + Add debugging tools to test if a given pointer is a valid object and in the heap. + https://bugs.webkit.org/show_bug.cgi?id=143910 + + Reviewed by Geoffrey Garen. + + When doing debugging from lldb, sometimes, it is useful to be able to tell if a + purported JSObject is really a valid object in the heap or not. We can add the + following utility functions to help: + isValidCell(heap, candidate) - returns true if the candidate is a "live" cell in the heap. + isInHeap(heap, candidate) - returns true if the candidate is the heap's Object space or Storage space. + isInObjectSpace(heap, candidate) - returns true if the candidate is the heap's Object space. + isInStorageSpace(heap, candidate) - returns true if the candidate is the heap's Storage space. + + Also moved lldb callable debug utility function prototypes from + JSDollarVMPrototype.cpp to JSDollarVMPrototype.h as static members of the + JSDollarVMPrototype class. This is so that we can conveniently #include that + file to get the prototypes when we need to call them programmatically from + instrumentation that we add while debugging an issue. + + * heap/Heap.h: + (JSC::Heap::storageSpace): + * tools/JSDollarVMPrototype.cpp: + (JSC::JSDollarVMPrototype::currentThreadOwnsJSLock): + (JSC::ensureCurrentThreadOwnsJSLock): + (JSC::JSDollarVMPrototype::gc): + (JSC::functionGC): + (JSC::JSDollarVMPrototype::edenGC): + (JSC::functionEdenGC): + (JSC::JSDollarVMPrototype::isInHeap): + (JSC::JSDollarVMPrototype::isInObjectSpace): + (JSC::JSDollarVMPrototype::isInStorageSpace): + (JSC::ObjectAddressCheckFunctor::ObjectAddressCheckFunctor): + (JSC::ObjectAddressCheckFunctor::operator()): + (JSC::JSDollarVMPrototype::isValidCell): + (JSC::JSDollarVMPrototype::isValidCodeBlock): + (JSC::JSDollarVMPrototype::codeBlockForFrame): + (JSC::functionCodeBlockForFrame): + (JSC::codeBlockFromArg): + (JSC::JSDollarVMPrototype::printCallFrame): + (JSC::JSDollarVMPrototype::printStack): + (JSC::JSDollarVMPrototype::printValue): + (JSC::currentThreadOwnsJSLock): Deleted. + (JSC::gc): Deleted. + (JSC::edenGC): Deleted. + (JSC::isValidCodeBlock): Deleted. + (JSC::codeBlockForFrame): Deleted. + (JSC::printCallFrame): Deleted. + (JSC::printStack): Deleted. + (JSC::printValue): Deleted. + * tools/JSDollarVMPrototype.h: + +2015-04-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Improve Support for WeakSet in Console + https://bugs.webkit.org/show_bug.cgi?id=143951 + + Reviewed by Darin Adler. + + * inspector/InjectedScriptSource.js: + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + (Inspector::JSInjectedScriptHost::weakSetSize): + (Inspector::JSInjectedScriptHost::weakSetEntries): + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + (Inspector::jsInjectedScriptHostPrototypeFunctionWeakSetSize): + (Inspector::jsInjectedScriptHostPrototypeFunctionWeakSetEntries): + Treat WeakSets like special sets. + + * inspector/protocol/Runtime.json: + Add a new object subtype, "weakset". + +2015-04-20 Yusuke Suzuki <utatane.tea@gmail.com> + + HashMap storing PropertyKey StringImpl* need to use IdentifierRepHash to handle Symbols + https://bugs.webkit.org/show_bug.cgi?id=143947 + + Reviewed by Darin Adler. + + Type profiler has map between PropertyKey (StringImpl*) and offset. + StringImpl* is also used for Symbol PropertyKey. + So equality of hash tables is considered by interned StringImpl*'s pointer value. + To do so, use IdentifierRepHash instead of StringHash. + + * runtime/SymbolTable.h: + +2015-04-20 Jordan Harband <ljharb@gmail.com> + + Implement `Object.is` + https://bugs.webkit.org/show_bug.cgi?id=143865 + + Reviewed by Darin Adler. + + Expose sameValue to JS, via Object.is + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.is + + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorIs): + * runtime/PropertyDescriptor.cpp: + (JSC::sameValue): + +2015-04-19 Darin Adler <darin@apple.com> + + Remove all the remaining uses of OwnPtr and PassOwnPtr in JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=143941 + + Reviewed by Gyuyoung Kim. + + * API/JSCallbackObject.h: Use unique_ptr for m_callbackObjectData. + * API/JSCallbackObjectFunctions.h: Ditto. + + * API/ObjCCallbackFunction.h: Use unique_ptr for the arguments to the + create function and the constructor and for m_impl. + * API/ObjCCallbackFunction.mm: + (CallbackArgumentOfClass::CallbackArgumentOfClass): Streamline this + class by using RetainPtr<Class>. + (ArgumentTypeDelegate::typeInteger): Use make_unique. + (ArgumentTypeDelegate::typeDouble): Ditto. + (ArgumentTypeDelegate::typeBool): Ditto. + (ArgumentTypeDelegate::typeVoid): Ditto. + (ArgumentTypeDelegate::typeId): Ditto. + (ArgumentTypeDelegate::typeOfClass): Ditto. + (ArgumentTypeDelegate::typeBlock): Ditto. + (ArgumentTypeDelegate::typeStruct): Ditto. + (ResultTypeDelegate::typeInteger): Ditto. + (ResultTypeDelegate::typeDouble): Ditto. + (ResultTypeDelegate::typeBool): Ditto. + (ResultTypeDelegate::typeVoid): Ditto. + (ResultTypeDelegate::typeId): Ditto. + (ResultTypeDelegate::typeOfClass): Ditto. + (ResultTypeDelegate::typeBlock): Ditto. + (ResultTypeDelegate::typeStruct): Ditto. + (JSC::ObjCCallbackFunctionImpl::ObjCCallbackFunctionImpl): Use + unique_ptr for the arguments to the constructor, m_arguments, and m_result. + Use RetainPtr<Class> for m_instanceClass. + (JSC::objCCallbackFunctionCallAsConstructor): Use nullptr instead of nil or 0 + for non-Objective-C object pointer null. + (JSC::ObjCCallbackFunction::ObjCCallbackFunction): Use unique_ptr for + the arguments to the constructor and for m_impl. + (JSC::ObjCCallbackFunction::create): Use unique_ptr for arguments. + (skipNumber): Mark this static since it's local to this source file. + (objCCallbackFunctionForInvocation): Call parseObjCType without doing any + explicit adoptPtr since the types in the traits are now unique_ptr. Also use + nullptr instead of nil for JSObjectRef values. + (objCCallbackFunctionForMethod): Tweaked comment. + (objCCallbackFunctionForBlock): Use nullptr instead of 0 for JSObjectRef. + + * bytecode/CallLinkInfo.h: Removed unneeded include of OwnPtr.h. + + * heap/GCThread.cpp: + (JSC::GCThread::GCThread): Use unique_ptr. + * heap/GCThread.h: Use unique_ptr for arguments to the constructor and for + m_slotVisitor and m_copyVisitor. + * heap/GCThreadSharedData.cpp: + (JSC::GCThreadSharedData::GCThreadSharedData): Ditto. + + * parser/SourceProvider.h: Removed unneeded include of PassOwnPtr.h. + +2015-04-19 Benjamin Poulain <benjamin@webkit.org> + + Improve the feature.json files + + * features.json: + +2015-04-19 Yusuke Suzuki <utatane.tea@gmail.com> + + Introduce bytecode intrinsics + https://bugs.webkit.org/show_bug.cgi?id=143926 + + Reviewed by Filip Pizlo. + + This patch introduces bytecode level intrinsics into builtins/*.js JS code. + When implementing functions in builtins/*.js, + sometimes we require lower level functionality. + + For example, in the current Array.from, we use `result[k] = value`. + The spec requires `[[DefineOwnProperty]]` operation here. + However, usual `result[k] = value` is evaluated as `[[Set]]`. (`PutValue` => `[[Set]]`) + So if we implement `Array.prototype[k]` getter/setter, the difference is observable. + + Ideally, reaching here, we would like to use put_by_val_direct bytecode. + However, there's no syntax to generate it directly. + + This patch introduces bytecode level intrinsics into JSC BytecodeCompiler. + Like @call, @apply, we introduce a new node, Intrinsic. + These are generated when calling appropriate private symbols in privileged code. + AST parser detects them and generates Intrinsic nodes and + BytecodeCompiler detects them and generate required bytecodes. + + Currently, Array.from implementation works fine without this patch. + This is because when the target code is builtin JS, + BytecodeGenerator emits put_by_val_direct instead of put_by_val. + This solves the above issue. However, instead of solving this issue, + it raises another issue; There's no way to emit `[[Set]]` operation. + `[[Set]]` operation is actually used in the spec (Array.from's "length" is set by `[[Set]]`). + So to implement it precisely, introducing bytecode level intrinsics is necessary. + + In the subsequent fixes, we'll remove that special path emitting put_by_val_direct + for `result[k] = value` under builtin JS environment. Instead of that special handling, + use bytecode intrinsics instead. It solves problems and it is more intuitive + because written JS code in builtin works as the same to the usual JS code. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/ArrayConstructor.js: + (from): + * bytecode/BytecodeIntrinsicRegistry.cpp: Added. + (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry): + (JSC::BytecodeIntrinsicRegistry::lookup): + * bytecode/BytecodeIntrinsicRegistry.h: Added. + * bytecompiler/NodesCodegen.cpp: + (JSC::BytecodeIntrinsicNode::emitBytecode): + (JSC::BytecodeIntrinsicNode::emit_intrinsic_putByValDirect): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::makeFunctionCallNode): + * parser/NodeConstructors.h: + (JSC::BytecodeIntrinsicNode::BytecodeIntrinsicNode): + * parser/Nodes.h: + (JSC::BytecodeIntrinsicNode::identifier): + * runtime/CommonIdentifiers.cpp: + (JSC::CommonIdentifiers::CommonIdentifiers): + * runtime/CommonIdentifiers.h: + (JSC::CommonIdentifiers::bytecodeIntrinsicRegistry): + * tests/stress/array-from-with-accessors.js: Added. + (shouldBe): + +2015-04-19 Yusuke Suzuki <utatane.tea@gmail.com> + + Make Builtin functions non constructible + https://bugs.webkit.org/show_bug.cgi?id=143923 + + Reviewed by Darin Adler. + + Builtin functions defined by builtins/*.js accidentally have [[Construct]]. + According to the spec, these functions except for explicitly defined as a constructor do not have [[Construct]]. + This patch fixes it. When the JS function used for a construction is builtin function, throw not a constructor error. + + Ideally, returning ConstructTypeNone in JSFunction::getConstructData is enough. + However, to avoid calling getConstructData (it involves indirect call of function pointer of getConstructData), some places do not check ConstructType. + In these places, they only check the target function is JSFunction because previously JSFunction always has [[Construct]]. + So in this patch, we check `isBuiltinFunction()` in those places. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::inliningCost): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::setUpCall): + * runtime/JSFunction.cpp: + (JSC::JSFunction::getConstructData): + * tests/stress/builtin-function-is-construct-type-none.js: Added. + (shouldThrow): + +2015-04-19 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement WeakSet + https://bugs.webkit.org/show_bug.cgi?id=142408 + + Reviewed by Darin Adler. + + This patch implements ES6 WeakSet. + Current implementation simply leverages WeakMapData with undefined value. + This WeakMapData should be optimized in the same manner as MapData/SetData in the subsequent patch[1]. + + And in this patch, we also fix WeakMap/WeakSet behavior to conform the ES6 spec. + Except for adders (WeakMap.prototype.set/WeakSet.prototype.add), + methods return false (or undefined for WeakMap.prototype.get) + when a key is not Object instead of throwing a type error. + + [1]: https://bugs.webkit.org/show_bug.cgi?id=143919 + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + * runtime/JSGlobalObject.h: + * runtime/JSWeakSet.cpp: Added. + (JSC::JSWeakSet::finishCreation): + (JSC::JSWeakSet::visitChildren): + * runtime/JSWeakSet.h: Added. + (JSC::JSWeakSet::createStructure): + (JSC::JSWeakSet::create): + (JSC::JSWeakSet::weakMapData): + (JSC::JSWeakSet::JSWeakSet): + * runtime/WeakMapPrototype.cpp: + (JSC::getWeakMapData): + (JSC::protoFuncWeakMapDelete): + (JSC::protoFuncWeakMapGet): + (JSC::protoFuncWeakMapHas): + * runtime/WeakSetConstructor.cpp: Added. + (JSC::WeakSetConstructor::finishCreation): + (JSC::callWeakSet): + (JSC::constructWeakSet): + (JSC::WeakSetConstructor::getConstructData): + (JSC::WeakSetConstructor::getCallData): + * runtime/WeakSetConstructor.h: Added. + (JSC::WeakSetConstructor::create): + (JSC::WeakSetConstructor::createStructure): + (JSC::WeakSetConstructor::WeakSetConstructor): + * runtime/WeakSetPrototype.cpp: Added. + (JSC::WeakSetPrototype::finishCreation): + (JSC::getWeakMapData): + (JSC::protoFuncWeakSetDelete): + (JSC::protoFuncWeakSetHas): + (JSC::protoFuncWeakSetAdd): + * runtime/WeakSetPrototype.h: Added. + (JSC::WeakSetPrototype::create): + (JSC::WeakSetPrototype::createStructure): + (JSC::WeakSetPrototype::WeakSetPrototype): + * tests/stress/weak-set-constructor-adder.js: Added. + (WeakSet.prototype.add): + * tests/stress/weak-set-constructor.js: Added. + +2015-04-17 Alexey Proskuryakov <ap@apple.com> + + Remove unused BoundsCheckedPointer + https://bugs.webkit.org/show_bug.cgi?id=143896 + + Reviewed by Geoffrey Garen. + + * bytecode/SpeculatedType.cpp: The header was included here. + +2015-04-17 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Fix name enumeration of static functions for Symbol constructor + https://bugs.webkit.org/show_bug.cgi?id=143891 + + Reviewed by Geoffrey Garen. + + Fix missing symbolPrototypeTable registration to the js class object. + This patch fixes name enumeration of static functions (Symbol.key, Symbol.keyFor) for Symbol constructor. + + * runtime/SymbolConstructor.cpp: + +2015-04-17 Basile Clement <basile_clement@apple.com> + + Inline JSFunction allocation in DFG + https://bugs.webkit.org/show_bug.cgi?id=143858 + + Reviewed by Filip Pizlo. + + Followup to my previous patch which inlines JSFunction allocation when + using FTL, now also enabled in DFG. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileNewFunction): + +2015-04-16 Jordan Harband <ljharb@gmail.com> + + Number.parseInt is not === global parseInt in nightly r182673 + https://bugs.webkit.org/show_bug.cgi?id=143799 + + Reviewed by Darin Adler. + + Ensuring parseInt === Number.parseInt, per spec + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.parseint + + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::parseIntFunction): + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::finishCreation): + +2015-04-16 Mark Lam <mark.lam@apple.com> + + Gardening: fix CLOOP build after r182927. + + Not reviewed. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::print): + +2015-04-16 Basile Clement <basile_clement@apple.com> + + Inline JSFunction allocation in FTL + https://bugs.webkit.org/show_bug.cgi?id=143851 + + Reviewed by Filip Pizlo. + + JSFunction allocation is a simple operation that should be inlined when possible. + + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNewFunction): + * runtime/JSFunction.h: + (JSC::JSFunction::allocationSize): + +2015-04-16 Mark Lam <mark.lam@apple.com> + + Add $vm debugging tool. + https://bugs.webkit.org/show_bug.cgi?id=143809 + + Reviewed by Geoffrey Garen. + + For debugging VM bugs, it would be useful to be able to dump VM data structures + from JS code that we instrument. To this end, let's introduce a + JS_enableDollarVM option that, if true, installs an $vm property into each JS + global object at creation time. The $vm property refers to an object that + provides a collection of useful utility functions. For this initial + implementation, $vm will have the following: + + crash() - trigger an intentional crash. + + dfgTrue() - returns true if the current function is DFG compiled, else returns false. + jitTrue() - returns true if the current function is compiled by the baseline JIT, else returns false. + llintTrue() - returns true if the current function is interpreted by the LLINT, else returns false. + + gc() - runs a full GC. + edenGC() - runs an eden GC. + + codeBlockForFrame(frameNumber) - gets the codeBlock at the specified frame (0 = current, 1 = caller, etc). + printSourceFor(codeBlock) - prints the source code for the codeBlock. + printByteCodeFor(codeBlock) - prints the bytecode for the codeBlock. + + print(str) - prints a string to dataLog output. + printCallFrame() - prints the current CallFrame. + printStack() - prints the JS stack. + printInternal(value) - prints the JSC internal info for the specified value. + + With JS_enableDollarVM=true, JS code can use the above functions like so: + + $vm.print("Using $vm features\n"); + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::printCallOp): + - FTL compiled functions don't like it when we try to compute the CallLinkStatus. + Hence, we skip this step if we're dumping an FTL codeBlock. + + * heap/Heap.cpp: + (JSC::Heap::collectAndSweep): + (JSC::Heap::collectAllGarbage): Deleted. + * heap/Heap.h: + (JSC::Heap::collectAllGarbage): + - Add ability to do an Eden collection and sweep. + + * interpreter/StackVisitor.cpp: + (JSC::printIndents): + (JSC::log): + (JSC::logF): + (JSC::StackVisitor::Frame::print): + (JSC::jitTypeName): Deleted. + (JSC::printif): Deleted. + - Modernize the implementation of StackVisitor::Frame::print(), and remove some + now redundant code. + - Also fix it so that it downgrades gracefully when encountering inlined DFG + and compiled FTL functions. + + (DebugPrintFrameFunctor::DebugPrintFrameFunctor): Deleted. + (DebugPrintFrameFunctor::operator()): Deleted. + (debugPrintCallFrame): Deleted. + (debugPrintStack): Deleted. + - these have been moved into JSDollarVMPrototype.cpp. + + * interpreter/StackVisitor.h: + - StackVisitor::Frame::print() is now enabled for release builds as well so that + we can call it from $vm. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + - Added the $vm instance to global objects conditional on the JSC_enableDollarVM + option. + + * runtime/Options.h: + - Added the JSC_enableDollarVM option. + + * tools/JSDollarVM.cpp: Added. + * tools/JSDollarVM.h: Added. + (JSC::JSDollarVM::createStructure): + (JSC::JSDollarVM::create): + (JSC::JSDollarVM::JSDollarVM): + + * tools/JSDollarVMPrototype.cpp: Added. + - This file contains 2 sets of functions: + + a. a C++ implementation of debugging utility functions that are callable when + doing debugging from lldb. To the extent possible, these functions try to + be cautious and not cause unintended crashes should the user call them with + the wrong info. Hence, they are designed to be robust rather than speedy. + + b. the native implementations of JS functions in the $vm object. Where there + is overlapping functionality, these are built on top of the C++ functions + above to do the work. + + Note: it does not make sense for all of the $vm functions to have a C++ + counterpart for lldb debugging. For example, the $vm.dfgTrue() function is + only useful for JS code, and works via the DFG intrinsics mechanism. + When doing debugging via lldb, the optimization level of the currently + executing JS function can be gotten by dumping the current CallFrame instead. + + (JSC::currentThreadOwnsJSLock): + (JSC::ensureCurrentThreadOwnsJSLock): + (JSC::JSDollarVMPrototype::addFunction): + (JSC::functionCrash): - $vm.crash() + (JSC::functionDFGTrue): - $vm.dfgTrue() + (JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor): + (JSC::CallerFrameJITTypeFunctor::operator()): + (JSC::CallerFrameJITTypeFunctor::jitType): + (JSC::functionLLintTrue): - $vm.llintTrue() + (JSC::functionJITTrue): - $vm.jitTrue() + (JSC::gc): + (JSC::functionGC): - $vm.gc() + (JSC::edenGC): + (JSC::functionEdenGC): - $vm.edenGC() + (JSC::isValidCodeBlock): + (JSC::codeBlockForFrame): + (JSC::functionCodeBlockForFrame): - $vm.codeBlockForFrame(frameNumber) + (JSC::codeBlockFromArg): + (JSC::functionPrintSourceFor): - $vm.printSourceFor(codeBlock) + (JSC::functionPrintByteCodeFor): - $vm.printBytecodeFor(codeBlock) + (JSC::functionPrint): - $vm.print(str) + (JSC::PrintFrameFunctor::PrintFrameFunctor): + (JSC::PrintFrameFunctor::operator()): + (JSC::printCallFrame): + (JSC::printStack): + (JSC::functionPrintCallFrame): - $vm.printCallFrame() + (JSC::functionPrintStack): - $vm.printStack() + (JSC::printValue): + (JSC::functionPrintValue): - $vm.printValue() + (JSC::JSDollarVMPrototype::finishCreation): + * tools/JSDollarVMPrototype.h: Added. + (JSC::JSDollarVMPrototype::create): + (JSC::JSDollarVMPrototype::createStructure): + (JSC::JSDollarVMPrototype::JSDollarVMPrototype): + +2015-04-16 Geoffrey Garen <ggaren@apple.com> + + Speculative fix after r182915 + https://bugs.webkit.org/show_bug.cgi?id=143404 + + Reviewed by Alexey Proskuryakov. + + * runtime/SymbolConstructor.h: + +2015-04-16 Mark Lam <mark.lam@apple.com> + + Fixed some typos in a comment. + + Not reviewed. + + * dfg/DFGGenerationInfo.h: + +2015-04-16 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement Symbol.for and Symbol.keyFor + https://bugs.webkit.org/show_bug.cgi?id=143404 + + Reviewed by Geoffrey Garen. + + This patch implements Symbol.for and Symbol.keyFor. + SymbolRegistry maintains registered StringImpl* symbols. + And to make this mapping enabled over realms, + VM owns this mapping (not JSGlobalObject). + + While there's Default AtomicStringTable per thread, + SymbolRegistry should not exist over VMs. + So everytime VM is created, SymbolRegistry is also created. + + In SymbolRegistry implementation, we don't leverage WeakGCMap (or weak reference design). + Theres are several reasons. + 1. StringImpl* which represents identity of Symbols is not GC-managed object. + So we cannot use WeakGCMap directly. + While Symbol* is GC-managed object, holding weak reference to Symbol* doesn't maintain JS symbols (exposed primitive values to users) liveness, + because distinct Symbol* can exist. + Distinct Symbol* means the Symbol* object that pointer value (Symbol*) is different from weakly referenced Symbol* but held StringImpl* is the same. + + 2. We don't use WTF::WeakPtr. If we add WeakPtrFactory into StringImpl's member, we can track StringImpl*'s liveness by WeakPtr. + However there's problem about when we prune staled entries in SymbolRegistry. + Since the memory allocated for the Symbol is typically occupied by allocated symbolized StringImpl*'s content, + and it is not in GC-heap. + While heavily registering Symbols and storing StringImpl* into SymbolRegistry, Heap's EdenSpace is not so occupied. + So GC typically attempt to perform EdenCollection, and it doesn't call WeakGCMap's pruleStaleEntries callback. + As a result, before pruning staled entries in SymbolRegistry, fast malloc-ed memory fills up the system memory. + + So instead of using Weak reference, we take relatively easy design. + When we register symbolized StringImpl* into SymbolRegistry, symbolized StringImpl* is aware of that. + And when destructing it, it removes its reference from SymbolRegistry as if atomic StringImpl do so with AtomicStringTable. + + * CMakeLists.txt: + * DerivedSources.make: + * runtime/SymbolConstructor.cpp: + (JSC::SymbolConstructor::getOwnPropertySlot): + (JSC::symbolConstructorFor): + (JSC::symbolConstructorKeyFor): + * runtime/SymbolConstructor.h: + * runtime/VM.cpp: + * runtime/VM.h: + (JSC::VM::symbolRegistry): + * tests/stress/symbol-registry.js: Added. + (test): + +2015-04-16 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Use specific functions for @@iterator functions + https://bugs.webkit.org/show_bug.cgi?id=143838 + + Reviewed by Geoffrey Garen. + + In ES6, some methods are defined with the different names. + + For example, + + Map.prototype[Symbol.iterator] === Map.prototype.entries + Set.prototype[Symbol.iterator] === Set.prototype.values + Array.prototype[Symbol.iterator] === Array.prototype.values + %Arguments%[Symbol.iterator] === Array.prototype.values + + However, current implementation creates different function objects per name. + This patch fixes it by setting the object that is used for the other method to @@iterator. + e.g. Setting Array.prototype.values function object to Array.prototype[Symbol.iterator]. + + And we drop Arguments' iterator implementation and replace Argument[@@iterator] implementation + with Array.prototype.values to conform to the spec. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + (Inspector::JSInjectedScriptHost::getInternalProperties): + (Inspector::JSInjectedScriptHost::iteratorEntries): + * runtime/ArgumentsIteratorConstructor.cpp: Removed. + * runtime/ArgumentsIteratorConstructor.h: Removed. + * runtime/ArgumentsIteratorPrototype.cpp: Removed. + * runtime/ArgumentsIteratorPrototype.h: Removed. + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + * runtime/ArrayPrototype.h: + * runtime/ClonedArguments.cpp: + (JSC::ClonedArguments::getOwnPropertySlot): + (JSC::ClonedArguments::put): + (JSC::ClonedArguments::deleteProperty): + (JSC::ClonedArguments::defineOwnProperty): + (JSC::ClonedArguments::materializeSpecials): + * runtime/ClonedArguments.h: + * runtime/CommonIdentifiers.h: + * runtime/DirectArguments.cpp: + (JSC::DirectArguments::overrideThings): + * runtime/GenericArgumentsInlines.h: + (JSC::GenericArguments<Type>::getOwnPropertySlot): + (JSC::GenericArguments<Type>::getOwnPropertyNames): + (JSC::GenericArguments<Type>::put): + (JSC::GenericArguments<Type>::deleteProperty): + (JSC::GenericArguments<Type>::defineOwnProperty): + * runtime/JSArgumentsIterator.cpp: Removed. + * runtime/JSArgumentsIterator.h: Removed. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::arrayProtoValuesFunction): + * runtime/MapPrototype.cpp: + (JSC::MapPrototype::finishCreation): + * runtime/ScopedArguments.cpp: + (JSC::ScopedArguments::overrideThings): + * runtime/SetPrototype.cpp: + (JSC::SetPrototype::finishCreation): + * tests/stress/arguments-iterator.js: Added. + (test): + (testArguments): + * tests/stress/iterator-functions.js: Added. + (test): + (argumentsTests): + +2015-04-14 Mark Lam <mark.lam@apple.com> + + Add JSC_functionOverrides=<overrides file> debugging tool. + https://bugs.webkit.org/show_bug.cgi?id=143717 + + Reviewed by Geoffrey Garen. + + This tool allows us to do runtime replacement of function bodies with alternatives + for debugging purposes. For example, this is useful when we need to debug VM bugs + which manifest in scripts executing in webpages downloaded from remote servers + that we don't control. The tool allows us to augment those scripts with logging + or test code to help isolate the bugs. + + This tool works by substituting the SourceCode at FunctionExecutable creation + time. It identifies which SourceCode to substitute by comparing the source + string against keys in a set of key value pairs. + + The keys are function body strings defined by 'override' clauses in the overrides + file specified by in the JSC_functionOverrides option. The values are function + body strings defines by 'with' clauses in the overrides file. + See comment blob at top of FunctionOverrides.cpp on the formatting + of the overrides file. + + At FunctionExecutable creation time, if the SourceCode string matches one of the + 'override' keys from the overrides file, the tool will replace the SourceCode with + a new one based on the corresponding 'with' value string. The FunctionExecutable + will then be created with the new SourceCode instead. + + Some design decisions: + 1. We opted to require that the 'with' clause appear on a separate line than the + 'override' clause because this makes it easier to read and write when the + 'override' clause's function body is single lined and long. + + 2. The user can use any sequence of characters for the delimiter (except for '{', + '}' and white space characters) because this ensures that there can always be + some delimiter pattern that does not appear in the function body in the clause + e.g. in the body of strings in the JS code. + + '{' and '}' are disallowed because they are used to mark the boundaries of the + function body string. White space characters are disallowed because they can + be error prone (the user may not be able to tell between spaces and tabs). + + 3. The start and end delimiter must be an identical sequence of characters. + + I had considered allowing the use of complementary characters like <>, [], and + () for making delimiter pairs like: + [[[[ ... ]]]] + <[([( ... )])]> + + But in the end, decided against it because: + a. These sequences of complementary characters can exists in JS code. + In contrast, a repeating delimiter like %%%% is unlikely to appear in JS + code. + b. It can be error prone for the user to have to type the exact complement + character for the end delimiter in reverse order. + In contrast, a repeating delimiter like %%%% is much easier to type and + less error prone. Even a sequence like @#$%^ is less error prone than + a complementary sequence because it can be copy-pasted, and need not be + typed in reverse order. + c. It is easier to parse for the same delimiter string for both start and end. + + 4. The tool does a lot of checks for syntax errors in the overrides file because + we don't want any overrides to fail silently. If a syntax error is detected, + the tool will print an error message and call exit(). This avoids the user + wasting time doing debugging only to be surprised later that their specified + overrides did not take effect because of some unnoticed typo. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::link): + * runtime/Executable.h: + * runtime/Options.h: + * tools/FunctionOverrides.cpp: Added. + (JSC::FunctionOverrides::overrides): + (JSC::FunctionOverrides::FunctionOverrides): + (JSC::initializeOverrideInfo): + (JSC::FunctionOverrides::initializeOverrideFor): + (JSC::hasDisallowedCharacters): + (JSC::parseClause): + (JSC::FunctionOverrides::parseOverridesInFile): + * tools/FunctionOverrides.h: Added. + +2015-04-16 Basile Clement <basile_clement@apple.com> + + Extract the allocation profile from JSFunction into a rare object + https://bugs.webkit.org/show_bug.cgi?id=143807 + + Reviewed by Filip Pizlo. + + The allocation profile is only needed for those functions that are used + to create objects with [new]. + Extracting it into its own JSCell removes the need for JSFunction and + JSCallee to be JSDestructibleObjects, which should improve performances in most + cases at the cost of an extra pointer dereference when the allocation profile + is actually needed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGOperations.cpp: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_this): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_this): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/FunctionRareData.cpp: Added. + (JSC::FunctionRareData::create): + (JSC::FunctionRareData::destroy): + (JSC::FunctionRareData::createStructure): + (JSC::FunctionRareData::visitChildren): + (JSC::FunctionRareData::FunctionRareData): + (JSC::FunctionRareData::~FunctionRareData): + (JSC::FunctionRareData::finishCreation): + * runtime/FunctionRareData.h: Added. + (JSC::FunctionRareData::offsetOfAllocationProfile): + (JSC::FunctionRareData::allocationProfile): + (JSC::FunctionRareData::allocationStructure): + (JSC::FunctionRareData::allocationProfileWatchpointSet): + * runtime/JSBoundFunction.cpp: + (JSC::JSBoundFunction::destroy): Deleted. + * runtime/JSBoundFunction.h: + * runtime/JSCallee.cpp: + (JSC::JSCallee::destroy): Deleted. + * runtime/JSCallee.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + (JSC::JSFunction::createRareData): + (JSC::JSFunction::visitChildren): + (JSC::JSFunction::put): + (JSC::JSFunction::defineOwnProperty): + (JSC::JSFunction::destroy): Deleted. + (JSC::JSFunction::createAllocationProfile): Deleted. + * runtime/JSFunction.h: + (JSC::JSFunction::offsetOfRareData): + (JSC::JSFunction::rareData): + (JSC::JSFunction::allocationStructure): + (JSC::JSFunction::allocationProfileWatchpointSet): + (JSC::JSFunction::offsetOfAllocationProfile): Deleted. + (JSC::JSFunction::allocationProfile): Deleted. + * runtime/JSFunctionInlines.h: + (JSC::JSFunction::JSFunction): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2015-04-16 Csaba Osztrogonác <ossy@webkit.org> + + Remove the unnecessary WTF_CHANGES define + https://bugs.webkit.org/show_bug.cgi?id=143825 + + Reviewed by Andreas Kling. + + * config.h: + +2015-04-15 Andreas Kling <akling@apple.com> + + Make MarkedBlock and WeakBlock 4x smaller. + <https://webkit.org/b/143802> + + Reviewed by Mark Hahnenberg. + + To reduce GC heap fragmentation and generally use less memory, reduce the size of MarkedBlock + and its buddy WeakBlock by 4x, bringing them from 64kB+4kB to 16kB+1kB. + + In a sampling of cool web sites, I'm seeing ~8% average reduction in overall GC heap size. + Some examples: + + apple.com: 6.3MB -> 5.5MB (14.5% smaller) + reddit.com: 4.5MB -> 4.1MB ( 9.7% smaller) + twitter.com: 23.2MB -> 21.4MB ( 8.4% smaller) + cuteoverload.com: 24.5MB -> 23.6MB ( 3.8% smaller) + + Benchmarks look mostly neutral. + Some small slowdowns on Octane, some slightly bigger speedups on Kraken and SunSpider. + + * heap/MarkedBlock.h: + * heap/WeakBlock.h: + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LowLevelInterpreter.asm: + +2015-04-15 Jordan Harband <ljharb@gmail.com> + + String.prototype.startsWith/endsWith/includes have wrong length in r182673 + https://bugs.webkit.org/show_bug.cgi?id=143659 + + Reviewed by Benjamin Poulain. + + Fix lengths of String.prototype.{includes,startsWith,endsWith} per spec + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.startswith + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.endswith + + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + +2015-04-15 Mark Lam <mark.lam@apple.com> + + Remove obsolete VMInspector debugging tool. + https://bugs.webkit.org/show_bug.cgi?id=143798 + + Reviewed by Michael Saboff. + + I added the VMInspector tool 3 years ago to aid in VM hacking work. Some of it + has bit rotted, and now the VM also has better ways to achieve its functionality. + Hence this code is now obsolete and should be removed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * interpreter/CallFrame.h: + * interpreter/VMInspector.cpp: Removed. + * interpreter/VMInspector.h: Removed. + * llint/LowLevelInterpreter.cpp: + +2015-04-15 Jordan Harband <ljharb@gmail.com> + + Math.imul has wrong length in Safari 8.0.4 + https://bugs.webkit.org/show_bug.cgi?id=143658 + + Reviewed by Benjamin Poulain. + + Correcting function length from 1, to 2, to match spec + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.imul + + * runtime/MathObject.cpp: + (JSC::MathObject::finishCreation): + +2015-04-15 Jordan Harband <ljharb@gmail.com> + + Number.parseInt in nightly r182673 has wrong length + https://bugs.webkit.org/show_bug.cgi?id=143657 + + Reviewed by Benjamin Poulain. + + Correcting function length from 1, to 2, to match spec + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.parseint + + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::finishCreation): + +2015-04-15 Filip Pizlo <fpizlo@apple.com> + + Harden DFGForAllKills + https://bugs.webkit.org/show_bug.cgi?id=143792 + + Reviewed by Geoffrey Garen. + + Unfortunately, we don't have a good way to test this yet - but it will be needed to prevent + bugs in https://bugs.webkit.org/show_bug.cgi?id=143734. + + Previously ForAllKills used the bytecode kill analysis. That seemed like a good idea because + that analysis is cheaper than the full liveness analysis. Unfortunately, it's probably wrong: + + - It looks for kill sites at forExit origin boundaries. But, something might have been killed + by an operation that was logically in between the forExit origins at the boundary, but was + removed from the DFG for whatever reason. The DFG is allowed to have bytecode instruction + gaps. + + - It overlooked the fact that a MovHint that addresses a local that is always live kills that + local. For example, storing to an argument means that the prior value of the argument is + killed. + + This fixes the analysis by making it handle MovHints directly, and making it define kills in + the most conservative way possible: it asks if you were live before but dead after. If we + have the compile time budget to afford this more direct approach, then it's definitel a good + idea since it's so fool-proof. + + * dfg/DFGArgumentsEliminationPhase.cpp: + * dfg/DFGForAllKills.h: + (JSC::DFG::forAllKilledOperands): + (JSC::DFG::forAllKilledNodesAtNodeIndex): + (JSC::DFG::forAllDirectlyKilledOperands): Deleted. + +2015-04-15 Joseph Pecoraro <pecoraro@apple.com> + + Provide SPI to allow changing whether JSContexts are remote debuggable by default + https://bugs.webkit.org/show_bug.cgi?id=143681 + + Reviewed by Darin Adler. + + * API/JSRemoteInspector.h: + * API/JSRemoteInspector.cpp: + (JSRemoteInspectorGetInspectionEnabledByDefault): + (JSRemoteInspectorSetInspectionEnabledByDefault): + Provide SPI to toggle the default enabled inspection state of debuggables. + + * API/JSContextRef.cpp: + (JSGlobalContextCreateInGroup): + Respect the default setting. + +2015-04-15 Joseph Pecoraro <pecoraro@apple.com> + + JavaScriptCore: Use kCFAllocatorDefault where possible + https://bugs.webkit.org/show_bug.cgi?id=143747 + + Reviewed by Darin Adler. + + * heap/HeapTimer.cpp: + (JSC::HeapTimer::HeapTimer): + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorInitializeGlobalQueue): + (Inspector::RemoteInspectorDebuggableConnection::setupRunLoop): + For consistency and readability use the constant instead of + different representations of null. + +2015-04-14 Michael Saboff <msaboff@apple.com> + + Remove JavaScriptCoreUseJIT default from JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=143746 + + Reviewed by Mark Lam. + + * runtime/VM.cpp: + (JSC::enableAssembler): + +2015-04-14 Chris Dumez <cdumez@apple.com> + + Regression(r180020): Web Inspector crashes on pages that have a stylesheet with an invalid MIME type + https://bugs.webkit.org/show_bug.cgi?id=143745 + <rdar://problem/20243916> + + Reviewed by Joseph Pecoraro. + + Add assertion in ContentSearchUtilities::findMagicComment() to make + sure the content String is not null or we would crash in + JSC::Yarr::interpret() later. + + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::findMagicComment): + +2015-04-14 Michael Saboff <msaboff@apple.com> + + DFG register fillSpeculate*() functions should validate incoming spill format is compatible with requested fill format + https://bugs.webkit.org/show_bug.cgi?id=143727 + + Reviewed by Geoffrey Garen. + + Used the result of AbstractInterpreter<>::filter() to check that the current spill format is compatible + with the requested fill format. If filter() reports a contradiction, then we force an OSR exit. + Removed individual checks made redundant by the new check. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + (JSC::DFG::SpeculativeJIT::fillSpeculateInt52): + (JSC::DFG::SpeculativeJIT::fillSpeculateCell): + (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean): + +2015-04-14 Joseph Pecoraro <pecoraro@apple.com> + + Replace JavaScriptCoreOutputConsoleMessagesToSystemConsole default with an SPI + https://bugs.webkit.org/show_bug.cgi?id=143691 + + Reviewed by Geoffrey Garen. + + * API/JSRemoteInspector.h: + * API/JSRemoteInspector.cpp: + (JSRemoteInspectorSetLogToSystemConsole): + Add SPI to enable/disable logging to the system console. + This only affects JSContext `console` logs and warnings. + + * inspector/JSGlobalObjectConsoleClient.h: + * inspector/JSGlobalObjectConsoleClient.cpp: + (Inspector::JSGlobalObjectConsoleClient::logToSystemConsole): + (Inspector::JSGlobalObjectConsoleClient::setLogToSystemConsole): + (Inspector::JSGlobalObjectConsoleClient::messageWithTypeAndLevel): + (Inspector::JSGlobalObjectConsoleClient::initializeLogToSystemConsole): Deleted. + Simplify access to the setting now that it doesn't need to + initialize its value from preferences. + +2015-04-14 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Auto-attach fails after r179562, initialization too late after dispatch + https://bugs.webkit.org/show_bug.cgi?id=143682 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::singleton): + If we are on the main thread, run the initialization immediately. + Otherwise dispatch to the main thread. This way if the first JSContext + was created on the main thread it can get auto-attached if applicable. + +2015-04-14 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed build fix for Mavericks. + + Mavericks includes this file but does not enable ENABLE_REMOTE_INSPECTOR + so the Inspector namespace is not available when compiling this file. + + * API/JSRemoteInspector.cpp: + +2015-04-14 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Expose private APIs to interact with RemoteInspector instead of going through WebKit + https://bugs.webkit.org/show_bug.cgi?id=143729 + + Reviewed by Timothy Hatcher. + + * API/JSRemoteInspector.h: Added. + * API/JSRemoteInspector.cpp: Added. + (JSRemoteInspectorDisableAutoStart): + (JSRemoteInspectorStart): + (JSRemoteInspectorSetParentProcessInformation): + Add the new SPIs for basic remote inspection behavior. + + * JavaScriptCore.xcodeproj/project.pbxproj: + Add the new files to Mac only, since remote inspection is only + enabled there anyways. + +2015-04-14 Mark Lam <mark.lam@apple.com> + + Rename JSC_dfgFunctionWhitelistFile to JSC_dfgWhitelist. + https://bugs.webkit.org/show_bug.cgi?id=143722 + + Reviewed by Michael Saboff. + + Renaming JSC_dfgFunctionWhitelistFile to JSC_dfgWhitelist so that it is + shorter, and easier to remember (without having to look it up) and to + type. JSC options now support descriptions, and one can always look up + the description if the option's purpose is not already obvious. + + * dfg/DFGFunctionWhitelist.cpp: + (JSC::DFG::FunctionWhitelist::ensureGlobalWhitelist): + (JSC::DFG::FunctionWhitelist::contains): + * runtime/Options.h: + +2015-04-13 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix Windows build. Windows doesn't take kindly to private classes that use FAST_ALLOCATED. + + * runtime/InferredValue.h: + +2015-04-13 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix build. I introduced a new cell type at the same time as kling changed how new cell types are written. + + * runtime/InferredValue.h: + +2015-04-08 Filip Pizlo <fpizlo@apple.com> + + JSC should detect singleton functions + https://bugs.webkit.org/show_bug.cgi?id=143232 + + Reviewed by Geoffrey Garen. + + This started out as an attempt to make constructors faster by detecting when a constructor is a + singleton. The idea is that each FunctionExecutable has a VariableWatchpointSet - a watchpoint + along with an inferred value - that detects if only one JSFunction has been allocated for that + executable, and if so, what that JSFunction is. Then, inside the code for the FunctionExecutable, + if the watchpoint set has an inferred value (i.e. it's been initialized and it is still valid), + we can constant-fold GetCallee. + + Unfortunately, constructors don't use GetCallee anymore, so that didn't pan out. But in the + process I realized a bunch of things: + + - This allows us to completely eliminate the GetCallee/GetScope sequence that we still sometimes + had even in code where our singleton-closure detection worked. That's because singleton-closure + inference worked at the op_resolve_scope, and that op_resolve_scope still needed to keep alive + the incoming scope in case we OSR exit. But by constant-folding GetCallee, that sequence + disappears. OSR exit can rematerialize the callee or the scope by just knowing their constant + values. + + - Singleton detection should be a reusable thing. So, I got rid of VariableWatchpointSet and + created InferredValue. InferredValue is a cell, so it can handle its own GC magic. + FunctionExecutable uses an InferredValue to tell you about singleton JSFunctions. + + - The old singleton-scope detection in op_resolve_scope is better abstracted as a SymbolTable + detecting a singleton JSSymbolTableObject. So, SymbolTable uses an InferredValue to tell you + about singleton JSSymbolTableObjects. It's curious that we want to have singleton detection in + SymbolTable if we already have it in FunctionExecutable. This comes into play in two ways. + First, it means that the DFG can realize sooner that a resolve_scope resolves to a constant + scope. Ths saves compile times and it allows prediction propagation to benefit from the + constant folding. Second, it means that we will detect a singleton scope even if it is + referenced from a non-singleton scope that is nearer to us in the scope chain. This refactoring + allows us to eliminate the function reentry watchpoint. + + - This allows us to use a normal WatchpointSet, instead of a VariableWatchpointSet, for inferring + constant values in scopes. Previously when the DFG inferred that a closure variable was + constant, it wouldn't know which closure that variable was in and so it couldn't just load that + value. But now we are first inferring that the function is a singleton, which means that we + know exactly what scope it points to, and we can load the value from the scope. Using a + WatchpointSet instead of a VariableWatchpointSet saves some memory and simplifies a bunch of + code. This also means that now, the only user of VariableWatchpointSet is FunctionExecutable. + I've tweaked the code of VariableWatchpointSet to reduce its power to just be what + FunctionExecutable wants. + + This also has the effect of simplifying the implementation of block scoping. Prior to this + change, block scoping would have needed to have some story for the function reentry watchpoint on + any nested symbol table. That's totally weird to think about; it's not really a function reentry + but a scope reentry. Now we don't have to think about this. Constant inference on nested scopes + will "just work": if we prove that we know the constant value of the scope then the machinery + kicks in, otherwise it doesn't. + + This is a small Octane and AsmBench speed-up. AsmBench sees 1% while Octane sees sub-1%. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + (JSC::CodeBlock::valueProfileForBytecodeOffset): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::valueProfileForBytecodeOffset): Deleted. + * bytecode/CodeOrigin.cpp: + (JSC::InlineCallFrame::calleeConstant): + (JSC::InlineCallFrame::visitAggregate): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::calleeConstant): Deleted. + (JSC::InlineCallFrame::visitAggregate): Deleted. + * bytecode/Instruction.h: + * bytecode/VariableWatchpointSet.cpp: Removed. + * bytecode/VariableWatchpointSet.h: Removed. + * bytecode/VariableWatchpointSetInlines.h: Removed. + * bytecode/VariableWriteFireDetail.cpp: Added. + (JSC::VariableWriteFireDetail::dump): + (JSC::VariableWriteFireDetail::touch): + * bytecode/VariableWriteFireDetail.h: Added. + (JSC::VariableWriteFireDetail::VariableWriteFireDetail): + * bytecode/Watchpoint.h: + (JSC::WatchpointSet::stateOnJSThread): + (JSC::WatchpointSet::startWatching): + (JSC::WatchpointSet::fireAll): + (JSC::WatchpointSet::touch): + (JSC::WatchpointSet::invalidate): + (JSC::InlineWatchpointSet::stateOnJSThread): + (JSC::InlineWatchpointSet::state): + (JSC::InlineWatchpointSet::hasBeenInvalidated): + (JSC::InlineWatchpointSet::invalidate): + (JSC::InlineWatchpointSet::touch): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::get): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::getScope): Deleted. + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDesiredWatchpoints.cpp: + (JSC::DFG::InferredValueAdaptor::add): + (JSC::DFG::DesiredWatchpoints::addLazily): + (JSC::DFG::DesiredWatchpoints::reallyAdd): + (JSC::DFG::DesiredWatchpoints::areStillValid): + * dfg/DFGDesiredWatchpoints.h: + (JSC::DFG::InferredValueAdaptor::hasBeenInvalidated): + (JSC::DFG::DesiredWatchpoints::isWatched): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::tryGetConstantClosureVar): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasWatchpointSet): + (JSC::DFG::Node::watchpointSet): + (JSC::DFG::Node::hasVariableWatchpointSet): Deleted. + (JSC::DFG::Node::variableWatchpointSet): Deleted. + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileNewFunction): + (JSC::DFG::SpeculativeJIT::compileCreateActivation): + (JSC::DFG::SpeculativeJIT::compileNotifyWrite): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGVarargsForwardingPhase.cpp: + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCreateActivation): + (JSC::FTL::LowerDFGToLLVM::compileNewFunction): + (JSC::FTL::LowerDFGToLLVM::compileNotifyWrite): + * interpreter/Interpreter.cpp: + (JSC::StackFrame::friendlySourceURL): + (JSC::StackFrame::friendlyFunctionName): + * interpreter/Interpreter.h: + (JSC::StackFrame::friendlySourceURL): Deleted. + (JSC::StackFrame::friendlyFunctionName): Deleted. + * jit/JIT.cpp: + (JSC::JIT::emitNotifyWrite): + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_touch_entry): Deleted. + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitPutGlobalVar): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emitNotifyWrite): Deleted. + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitPutGlobalVar): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emitNotifyWrite): Deleted. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): Deleted. + * runtime/CommonSlowPaths.h: + * runtime/Executable.cpp: + (JSC::FunctionExecutable::finishCreation): + (JSC::FunctionExecutable::visitChildren): + * runtime/Executable.h: + (JSC::FunctionExecutable::singletonFunction): + * runtime/InferredValue.cpp: Added. + (JSC::InferredValue::create): + (JSC::InferredValue::destroy): + (JSC::InferredValue::createStructure): + (JSC::InferredValue::visitChildren): + (JSC::InferredValue::InferredValue): + (JSC::InferredValue::~InferredValue): + (JSC::InferredValue::notifyWriteSlow): + (JSC::InferredValue::ValueCleanup::ValueCleanup): + (JSC::InferredValue::ValueCleanup::~ValueCleanup): + (JSC::InferredValue::ValueCleanup::finalizeUnconditionally): + * runtime/InferredValue.h: Added. + (JSC::InferredValue::inferredValue): + (JSC::InferredValue::state): + (JSC::InferredValue::isStillValid): + (JSC::InferredValue::hasBeenInvalidated): + (JSC::InferredValue::add): + (JSC::InferredValue::notifyWrite): + (JSC::InferredValue::invalidate): + * runtime/JSEnvironmentRecord.cpp: + (JSC::JSEnvironmentRecord::visitChildren): + * runtime/JSEnvironmentRecord.h: + (JSC::JSEnvironmentRecord::isValid): + (JSC::JSEnvironmentRecord::finishCreation): + * runtime/JSFunction.cpp: + (JSC::JSFunction::create): + * runtime/JSFunction.h: + (JSC::JSFunction::createWithInvalidatedReallocationWatchpoint): + (JSC::JSFunction::createImpl): + (JSC::JSFunction::create): Deleted. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + * runtime/JSGlobalObject.h: + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::symbolTablePut): + * runtime/JSScope.h: + (JSC::ResolveOp::ResolveOp): + * runtime/JSSegmentedVariableObject.h: + (JSC::JSSegmentedVariableObject::finishCreation): + * runtime/JSSymbolTableObject.h: + (JSC::JSSymbolTableObject::JSSymbolTableObject): + (JSC::JSSymbolTableObject::setSymbolTable): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/PutPropertySlot.h: + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::prepareToWatch): + (JSC::SymbolTable::SymbolTable): + (JSC::SymbolTable::finishCreation): + (JSC::SymbolTable::visitChildren): + (JSC::SymbolTableEntry::inferredValue): Deleted. + (JSC::SymbolTableEntry::notifyWriteSlow): Deleted. + (JSC::SymbolTable::WatchpointCleanup::WatchpointCleanup): Deleted. + (JSC::SymbolTable::WatchpointCleanup::~WatchpointCleanup): Deleted. + (JSC::SymbolTable::WatchpointCleanup::finalizeUnconditionally): Deleted. + * runtime/SymbolTable.h: + (JSC::SymbolTableEntry::disableWatching): + (JSC::SymbolTableEntry::watchpointSet): + (JSC::SymbolTable::singletonScope): + (JSC::SymbolTableEntry::notifyWrite): Deleted. + * runtime/TypeProfiler.cpp: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + * tests/stress/infer-uninitialized-closure-var.js: Added. + (foo.f): + (foo): + * tests/stress/singleton-scope-then-overwrite.js: Added. + (foo.f): + (foo): + * tests/stress/singleton-scope-then-realloc-and-overwrite.js: Added. + (foo): + * tests/stress/singleton-scope-then-realloc.js: Added. + (foo): + +2015-04-13 Andreas Kling <akling@apple.com> + + Don't segregate heap objects based on Structure immortality. + <https://webkit.org/b/143638> + + Reviewed by Darin Adler. + + Put all objects that need a destructor call into the same MarkedBlock. + This reduces memory consumption in many situations, while improving locality, + since much more of the MarkedBlock space can be shared. + + Instead of branching on the MarkedBlock type, we now check a bit in the + JSCell's inline type flags (StructureIsImmortal) to see whether it's safe + to access the cell's Structure during destruction or not. + + Performance benchmarks look mostly neutral. Maybe a small regression on + SunSpider's date objects. + + On the amazon.com landing page, this saves us 50 MarkedBlocks (3200kB) along + with a bunch of WeakBlocks that were hanging off of them. That's on the higher + end of savings we can get from this, but still a very real improvement. + + Most of this patch is removing the "hasImmortalStructure" constant from JSCell + derived classes and passing that responsibility to the StructureIsImmortal flag. + StructureFlags is made public so that it's accessible from non-member functions. + I made sure to declare it everywhere and make classes final to try to make it + explicit what each class is doing to its inherited flags. + + * API/JSCallbackConstructor.h: + * API/JSCallbackObject.h: + * bytecode/UnlinkedCodeBlock.h: + * debugger/DebuggerScope.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileMakeRope): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileMakeRope): + * heap/Heap.h: + (JSC::Heap::subspaceForObjectDestructor): + (JSC::Heap::allocatorForObjectWithDestructor): + (JSC::Heap::subspaceForObjectNormalDestructor): Deleted. + (JSC::Heap::subspaceForObjectsWithImmortalStructure): Deleted. + (JSC::Heap::allocatorForObjectWithNormalDestructor): Deleted. + (JSC::Heap::allocatorForObjectWithImmortalStructureDestructor): Deleted. + * heap/HeapInlines.h: + (JSC::Heap::allocateWithDestructor): + (JSC::Heap::allocateObjectOfType): + (JSC::Heap::subspaceForObjectOfType): + (JSC::Heap::allocatorForObjectOfType): + (JSC::Heap::allocateWithNormalDestructor): Deleted. + (JSC::Heap::allocateWithImmortalStructureDestructor): Deleted. + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::allocateBlock): + * heap/MarkedAllocator.h: + (JSC::MarkedAllocator::needsDestruction): + (JSC::MarkedAllocator::MarkedAllocator): + (JSC::MarkedAllocator::init): + (JSC::MarkedAllocator::destructorType): Deleted. + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::create): + (JSC::MarkedBlock::MarkedBlock): + (JSC::MarkedBlock::callDestructor): + (JSC::MarkedBlock::specializedSweep): + (JSC::MarkedBlock::sweep): + (JSC::MarkedBlock::sweepHelper): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::needsDestruction): + (JSC::MarkedBlock::destructorType): Deleted. + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::MarkedSpace): + (JSC::MarkedSpace::resetAllocators): + (JSC::MarkedSpace::forEachAllocator): + (JSC::MarkedSpace::isPagedOut): + (JSC::MarkedSpace::clearNewlyAllocated): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::subspaceForObjectsWithDestructor): + (JSC::MarkedSpace::destructorAllocatorFor): + (JSC::MarkedSpace::allocateWithDestructor): + (JSC::MarkedSpace::forEachBlock): + (JSC::MarkedSpace::subspaceForObjectsWithNormalDestructor): Deleted. + (JSC::MarkedSpace::subspaceForObjectsWithImmortalStructure): Deleted. + (JSC::MarkedSpace::immortalStructureDestructorAllocatorFor): Deleted. + (JSC::MarkedSpace::normalDestructorAllocatorFor): Deleted. + (JSC::MarkedSpace::allocateWithImmortalStructureDestructor): Deleted. + (JSC::MarkedSpace::allocateWithNormalDestructor): Deleted. + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.h: + * inspector/JSJavaScriptCallFrame.h: + * inspector/JSJavaScriptCallFramePrototype.h: + * jsc.cpp: + * runtime/ArrayBufferNeuteringWatchpoint.h: + * runtime/ArrayConstructor.h: + * runtime/ArrayIteratorPrototype.h: + * runtime/BooleanPrototype.h: + * runtime/ClonedArguments.h: + * runtime/CustomGetterSetter.h: + * runtime/DateConstructor.h: + * runtime/DatePrototype.h: + * runtime/ErrorPrototype.h: + * runtime/ExceptionHelpers.h: + * runtime/Executable.h: + * runtime/GenericArguments.h: + * runtime/GetterSetter.h: + * runtime/InternalFunction.h: + * runtime/JSAPIValueWrapper.h: + * runtime/JSArgumentsIterator.h: + * runtime/JSArray.h: + * runtime/JSArrayBuffer.h: + * runtime/JSArrayBufferView.h: + * runtime/JSBoundFunction.h: + * runtime/JSCallee.h: + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::classInfo): + * runtime/JSDataViewPrototype.h: + * runtime/JSEnvironmentRecord.h: + * runtime/JSFunction.h: + * runtime/JSGenericTypedArrayView.h: + * runtime/JSGlobalObject.h: + * runtime/JSLexicalEnvironment.h: + * runtime/JSNameScope.h: + * runtime/JSNotAnObject.h: + * runtime/JSONObject.h: + * runtime/JSObject.h: + (JSC::JSFinalObject::JSFinalObject): + * runtime/JSPromiseConstructor.h: + * runtime/JSPromiseDeferred.h: + * runtime/JSPromisePrototype.h: + * runtime/JSPromiseReaction.h: + * runtime/JSPropertyNameEnumerator.h: + * runtime/JSProxy.h: + * runtime/JSScope.h: + * runtime/JSString.h: + * runtime/JSSymbolTableObject.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::structureIsImmortal): + * runtime/MathObject.h: + * runtime/NumberConstructor.h: + * runtime/NumberPrototype.h: + * runtime/ObjectConstructor.h: + * runtime/PropertyMapHashTable.h: + * runtime/RegExp.h: + * runtime/RegExpConstructor.h: + * runtime/RegExpObject.h: + * runtime/RegExpPrototype.h: + * runtime/ScopedArgumentsTable.h: + * runtime/SparseArrayValueMap.h: + * runtime/StrictEvalActivation.h: + * runtime/StringConstructor.h: + * runtime/StringIteratorPrototype.h: + * runtime/StringObject.h: + * runtime/StringPrototype.h: + * runtime/Structure.cpp: + (JSC::Structure::Structure): + * runtime/Structure.h: + * runtime/StructureChain.h: + * runtime/StructureRareData.h: + * runtime/Symbol.h: + * runtime/SymbolPrototype.h: + * runtime/SymbolTable.h: + * runtime/WeakMapData.h: + +2015-04-13 Mark Lam <mark.lam@apple.com> + + DFG inlining of op_call_varargs should keep the callee alive in case of OSR exit. + https://bugs.webkit.org/show_bug.cgi?id=143407 + + Reviewed by Filip Pizlo. + + DFG inlining of a varargs call / construct needs to keep the local + containing the callee alive with a Phantom node because the LoadVarargs + node may OSR exit. After the OSR exit, the baseline JIT executes the + op_call_varargs with that callee in the local. + + Previously, because that callee local was not explicitly kept alive, + the op_call_varargs case can OSR exit a DFG function and leave an + undefined value in that local. As a result, the baseline observes the + side effect of an op_call_varargs on an undefined value instead of the + function it expected. + + Note: this issue does not manifest with op_construct_varargs because + the inlined constructor will have an op_create_this which operates on + the incoming callee value, thereby keeping it alive. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleInlining): + * tests/stress/call-varargs-with-different-arguments-length-after-warmup.js: Added. + (foo): + (Foo): + (doTest): + +2015-04-12 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement Array.prototype.values + https://bugs.webkit.org/show_bug.cgi?id=143633 + + Reviewed by Darin Adler. + + Symbol.unscopables is implemented, so we can implement Array.prototype.values + without largely breaking the web. The following script passes. + + var array = []; + var values = 42; + with (array) { + assert(values, 42); + } + + * runtime/ArrayPrototype.cpp: + * tests/stress/array-iterators-next.js: + * tests/stress/map-iterators-next.js: + * tests/stress/set-iterators-next.js: + * tests/stress/values-unscopables.js: Added. + (test): + +2015-04-11 Yusuke Suzuki <utatane.tea@gmail.com> + + Run flaky conservative GC related test first before polluting stack and registers + https://bugs.webkit.org/show_bug.cgi?id=143634 + + Reviewed by Ryosuke Niwa. + + After r182653, JSC API tests fail. However, it's not related to the change. + After investigating the cause of this failure, I've found that the failed test is flaky + because JSC's GC is conservative. If previously allocated JSGlobalObject is accidentally alive + due to conservative roots in C stack and registers, this test fails. + + Since GC marks C stack and registers as roots conservatively, + objects not referenced logically can be accidentally marked and alive. + To avoid this situation as possible as we can, + 1. run this test first before stack is polluted, + 2. extract this test as a function to suppress stack height. + + * API/tests/testapi.mm: + (testWeakValue): + (testObjectiveCAPIMain): + (testObjectiveCAPI): + +2015-04-11 Matt Baker <mattbaker@apple.com> + + Web Inspector: create content view and details sidebar for Frames timeline + https://bugs.webkit.org/show_bug.cgi?id=143533 + + Reviewed by Timothy Hatcher. + + Refactoring: RunLoop prefix changed to RenderingFrame. + + * inspector/protocol/Timeline.json: + +2015-04-11 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Enable Symbol in web pages + https://bugs.webkit.org/show_bug.cgi?id=143375 + + Reviewed by Ryosuke Niwa. + + Expose Symbol to web pages. + Symbol was exposed, but it was hidden since it breaks Facebook comments. + This is because at that time Symbol is implemented, + but methods for Symbol.iterator and Object.getOwnPropertySymbols are not implemented yet + and it breaks React.js and immutable.js. + + Now methods for Symbol.iterator and Object.getOwnPropertySymbols are implemented + and make sure that Facebook comment input functionality is not broken with exposed Symbol. + + So this patch replaces runtime flags SymbolEnabled to SymbolDisabled + and makes enabling symbols by default. + + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::finishCreation): + * runtime/RuntimeFlags.h: + +2015-04-10 Yusuke Suzuki <utatane.tea@gmail.com> + + ES6: Iterator toString names should be consistent + https://bugs.webkit.org/show_bug.cgi?id=142424 + + Reviewed by Geoffrey Garen. + + Iterator Object Names in the spec right now have spaces. + In our implementation some do and some don't. + This patch aligns JSC to the spec. + + * runtime/JSArrayIterator.cpp: + * runtime/JSStringIterator.cpp: + * tests/stress/iterator-names.js: Added. + (test): + (iter): + (check): + +2015-04-10 Michael Saboff <msaboff@apple.com> + + REGRESSION (182567): regress/script-tests/sorting-benchmark.js fails on 32 bit dfg-eager tests + https://bugs.webkit.org/show_bug.cgi?id=143582 + + Reviewed by Mark Lam. + + For 32 bit builds, we favor spilling unboxed values. The ASSERT at the root of this bug doesn't + fire for 64 bit builds, because we spill an "Other" value as a full JS value (DataFormatJS). + For 32 bit builds however, if we are able, we spill Other values as JSCell* (DataFormatCell). + The fix is to add a check in fillSpeculateInt32Internal() before the ASSERT that always OSR exits + if the spillFormat is DataFormatCell. Had we spilled in DataFormatJS and the value was a JSCell*, + we would still OSR exit after the speculation check. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): Fixed an error in a comment while debugging. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal): + +2015-04-10 Milan Crha <mcrha@redhat.com> + + Disable Linux-specific code in a Windows build + https://bugs.webkit.org/show_bug.cgi?id=137973 + + Reviewed by Joseph Pecoraro. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::appendAPIBacktrace): + +2015-04-10 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Fix calleeSaveRegisters() on non iOS platforms after r180516 + https://bugs.webkit.org/show_bug.cgi?id=143368 + + Reviewed by Michael Saboff. + + * jit/RegisterSet.cpp: + (JSC::RegisterSet::calleeSaveRegisters): + +2015-04-08 Joseph Pecoraro <pecoraro@apple.com> + + Use jsNontrivialString in more places if the string is guaranteed to be 2 or more characters + https://bugs.webkit.org/show_bug.cgi?id=143430 + + Reviewed by Darin Adler. + + * runtime/ExceptionHelpers.cpp: + (JSC::errorDescriptionForValue): + * runtime/NumberPrototype.cpp: + (JSC::numberProtoFuncToExponential): + (JSC::numberProtoFuncToPrecision): + (JSC::numberProtoFuncToString): + * runtime/SymbolPrototype.cpp: + (JSC::symbolProtoFuncToString): + +2015-04-08 Filip Pizlo <fpizlo@apple.com> + + JSArray::sortNumeric should handle ArrayWithUndecided + https://bugs.webkit.org/show_bug.cgi?id=143535 + + Reviewed by Geoffrey Garen. + + ArrayWithUndecided is what you get if you haven't stored anything into the array yet. We need to handle it. + + * runtime/JSArray.cpp: + (JSC::JSArray::sortNumeric): + * tests/stress/sort-array-with-undecided.js: Added. + +2015-04-08 Filip Pizlo <fpizlo@apple.com> + + DFG::IntegerCheckCombiningPhase's wrap-around check shouldn't trigger C++ undef behavior on wrap-around + https://bugs.webkit.org/show_bug.cgi?id=143532 + + Reviewed by Gavin Barraclough. + + Oh the irony! We were protecting an optimization that only worked if there was no wrap-around in JavaScript. + But the C++ code had wrap-around, which is undef in C++. So, if the compiler was smart enough, our compiler + would think that there never was wrap-around. + + This fixes a failure in stress/tricky-array-boiunds-checks.js when JSC is compiled with bleeding-edge clang. + + * dfg/DFGIntegerCheckCombiningPhase.cpp: + (JSC::DFG::IntegerCheckCombiningPhase::isValid): + +2015-04-07 Michael Saboff <msaboff@apple.com> + + Lazily initialize LogToSystemConsole flag to reduce memory usage + https://bugs.webkit.org/show_bug.cgi?id=143506 + + Reviewed by Mark Lam. + + Only call into CF preferences code when we need to in order to reduce memory usage. + + * inspector/JSGlobalObjectConsoleClient.cpp: + (Inspector::JSGlobalObjectConsoleClient::logToSystemConsole): + (Inspector::JSGlobalObjectConsoleClient::setLogToSystemConsole): + (Inspector::JSGlobalObjectConsoleClient::initializeLogToSystemConsole): + (Inspector::JSGlobalObjectConsoleClient::JSGlobalObjectConsoleClient): + +2015-04-07 Benjamin Poulain <benjamin@webkit.org> + + Get the features.json files ready for open contributions + https://bugs.webkit.org/show_bug.cgi?id=143436 + + Reviewed by Darin Adler. + + * features.json: + +2015-04-07 Filip Pizlo <fpizlo@apple.com> + + Constant folding of typed array properties should be handled by AI rather than strength reduction + https://bugs.webkit.org/show_bug.cgi?id=143496 + + Reviewed by Geoffrey Garen. + + Handling constant folding in AI is better because it precludes us from having to fixpoint the CFA + phase and whatever other phase did the folding in order to find all constants. + + This also removes the TypedArrayWatchpoint node type because we can just set the watchpoint + directly. + + This also fixes a bug in FTL lowering of GetTypedArrayByteOffset. The bug was previously not + found because all of the tests for it involved the property getting constant folded. I found that + the codegen was bad because an earlier version of the patch broke that constant folding. This + adds a new test for that node type, which makes constant folding impossible by allocating a new + typed array every type. The lesson here is: if you write a test for something, run the test with + full IR dumps to make sure it's actually testing the thing you want it to test. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::tryGetFoldableView): + (JSC::DFG::Graph::tryGetFoldableViewForChild1): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::hasTypedArray): Deleted. + (JSC::DFG::Node::typedArray): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + (JSC::DFG::StrengthReductionPhase::foldTypedArrayPropertyToConstant): Deleted. + (JSC::DFG::StrengthReductionPhase::prepareToFoldTypedArray): Deleted. + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + (JSC::DFG::WatchpointCollectionPhase::addLazily): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetTypedArrayByteOffset): + (JSC::FTL::LowerDFGToLLVM::typedArrayLength): + * tests/stress/fold-typed-array-properties.js: + (foo): + * tests/stress/typed-array-byte-offset.js: Added. + (foo): + +2015-04-07 Matthew Mirman <mmirman@apple.com> + + Source and stack information should get appended only to native errors + and should be added directly after construction rather than when thrown. + This fixes frozen objects being unfrozen when thrown while conforming to + ecma script standard and other browser behavior. + rdar://problem/19927293 + https://bugs.webkit.org/show_bug.cgi?id=141871 + + Reviewed by Geoffrey Garen. + + Appending stack, source, line, and column information to an object whenever that object is thrown + is incorrect because it violates the ecma script standard for the behavior of throw. Suppose for example + that the object being thrown already has one of these properties or is frozen. Adding the properties + would then violate the frozen contract or overwrite those properties. Other browsers do not do this, + and doing this causes unnecessary performance hits in code with heavy use of the throw construct as + a control flow construct rather than just an error reporting mechanism. + + Because WebCore adds "native" errors which do not inherit from any JSC native error, + appending the error properties as a seperate call after construction of the error is required + to avoid having to manually truncate the stack and gather local source information due to + the stack being extended by a nested call to construct one of the native jsc error. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * interpreter/Interpreter.h: + * parser/ParserError.h: + (JSC::ParserError::toErrorObject): + * runtime/CommonIdentifiers.h: + * runtime/Error.cpp: + (JSC::createError): + (JSC::createEvalError): + (JSC::createRangeError): + (JSC::createReferenceError): + (JSC::createSyntaxError): + (JSC::createTypeError): + (JSC::createNotEnoughArgumentsError): + (JSC::createURIError): + (JSC::createOutOfMemoryError): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::index): + (JSC::addErrorInfoAndGetBytecodeOffset): Added. + (JSC::addErrorInfo): Added special case for appending complete error info + to a newly constructed error object. + * runtime/Error.h: + * runtime/ErrorConstructor.cpp: + (JSC::Interpreter::constructWithErrorConstructor): + (JSC::Interpreter::callErrorConstructor): + * runtime/ErrorInstance.cpp: + (JSC::appendSourceToError): Moved from VM.cpp + (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame): + (JSC::FindFirstCallerFrameWithCodeblockFunctor::index): + (JSC::addErrorInfoAndGetBytecodeOffset): + (JSC::ErrorInstance::finishCreation): + * runtime/ErrorInstance.h: + (JSC::ErrorInstance::create): + * runtime/ErrorPrototype.cpp: + (JSC::ErrorPrototype::finishCreation): + * runtime/ExceptionFuzz.cpp: + (JSC::doExceptionFuzzing): + * runtime/ExceptionHelpers.cpp: + (JSC::createError): + (JSC::createInvalidFunctionApplyParameterError): + (JSC::createInvalidInParameterError): + (JSC::createInvalidInstanceofParameterError): + (JSC::createNotAConstructorError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + (JSC::throwOutOfMemoryError): + (JSC::createStackOverflowError): Deleted. + (JSC::createOutOfMemoryError): Deleted. + * runtime/ExceptionHelpers.h: + * runtime/JSArrayBufferConstructor.cpp: + (JSC::constructArrayBuffer): + * runtime/JSArrayBufferPrototype.cpp: + (JSC::arrayBufferProtoFuncSlice): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::create): + (JSC::JSGenericTypedArrayView<Adaptor>::createUninitialized): + * runtime/NativeErrorConstructor.cpp: + (JSC::Interpreter::constructWithNativeErrorConstructor): + (JSC::Interpreter::callNativeErrorConstructor): + * runtime/VM.cpp: + (JSC::VM::throwException): + (JSC::appendSourceToError): Moved to Error.cpp + (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor): Deleted. + (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()): Deleted. + (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame): Deleted. + (JSC::FindFirstCallerFrameWithCodeblockFunctor::index): Deleted. + * tests/stress/freeze_leek.js: Added. + +2015-04-07 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ES6: Show Symbol properties on Objects + https://bugs.webkit.org/show_bug.cgi?id=141279 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Runtime.json: + Give PropertyDescriptor a reference to the Symbol RemoteObject + if the property is a symbol property. + + * inspector/InjectedScriptSource.js: + Enumerate symbol properties on objects. + +2015-04-07 Filip Pizlo <fpizlo@apple.com> + + Make it possible to enable LLVM FastISel + https://bugs.webkit.org/show_bug.cgi?id=143489 + + Reviewed by Michael Saboff. + + The decision to enable FastISel is made by Options.h|cpp, but the LLVM library can disable it if it finds that it is built + against a version of LLVM that doesn't support it. Thereafter, JSC::enableLLVMFastISel is the flag that tells the system + if we should enable it. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * llvm/InitializeLLVM.cpp: + (JSC::initializeLLVMImpl): + * llvm/InitializeLLVM.h: + * llvm/InitializeLLVMLinux.cpp: + (JSC::getLLVMInitializerFunction): + (JSC::initializeLLVMImpl): Deleted. + * llvm/InitializeLLVMMac.cpp: + (JSC::getLLVMInitializerFunction): + (JSC::initializeLLVMImpl): Deleted. + * llvm/InitializeLLVMPOSIX.cpp: + (JSC::getLLVMInitializerFunctionPOSIX): + (JSC::initializeLLVMPOSIX): Deleted. + * llvm/InitializeLLVMPOSIX.h: + * llvm/InitializeLLVMWin.cpp: + (JSC::getLLVMInitializerFunction): + (JSC::initializeLLVMImpl): Deleted. + * llvm/LLVMAPI.cpp: + * llvm/LLVMAPI.h: + * llvm/library/LLVMExports.cpp: + (initCommandLine): + (initializeAndGetJSCLLVMAPI): + * runtime/Options.cpp: + (JSC::Options::initialize): + +2015-04-06 Yusuke Suzuki <utatane.tea@gmail.com> + + put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex + https://bugs.webkit.org/show_bug.cgi?id=140426 + + Reviewed by Darin Adler. + + In the put_by_val_direct operation, we use JSObject::putDirect. + However, it only accepts non-index property. For index property, we need to use JSObject::putDirectIndex. + This patch checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex. + + * dfg/DFGOperations.cpp: + (JSC::DFG::putByVal): + (JSC::DFG::operationPutByValInternal): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Identifier.h: + (JSC::isIndex): + (JSC::parseIndex): + * tests/stress/dfg-put-by-val-direct-with-edge-numbers.js: Added. + (lookupWithKey): + (toStringThrowsError.toString): + +2015-04-06 Alberto Garcia <berto@igalia.com> + + [GTK] Fix HPPA build + https://bugs.webkit.org/show_bug.cgi?id=143453 + + Reviewed by Darin Adler. + + Add HPPA to the list of supported CPUs. + + * CMakeLists.txt: + +2015-04-06 Mark Lam <mark.lam@apple.com> + + In the 64-bit DFG and FTL, Array::Double case for HasIndexedProperty should set its result to true when all is well. + <https://webkit.org/b/143396> + + Reviewed by Filip Pizlo. + + The DFG was neglecting to set the result boolean. The FTL was setting it with + an inverted value. Both of these are now resolved. + + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileHasIndexedProperty): + * tests/stress/for-in-array-mode.js: Added. + (.): + (test): + +2015-04-06 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] DFG and FTL should be aware of that StringConstructor behavior for symbols becomes different from ToString + https://bugs.webkit.org/show_bug.cgi?id=143424 + + Reviewed by Geoffrey Garen. + + In ES6, StringConstructor behavior becomes different from ToString abstract operations in the spec. (and JSValue::toString). + + ToString(symbol) throws a type error. + However, String(symbol) produces SymbolDescriptiveString(symbol). + + So, in DFG and FTL phase, they should not inline StringConstructor to ToString. + + Now, in the template literals patch, ToString DFG operation is planned to be used. + And current ToString behavior is aligned to the spec (and JSValue::toString) and it's better. + So intead of changing ToString behavior, this patch adds CallStringConstructor operation into DFG and FTL. + In CallStringConstructor, all behavior in DFG analysis is the same. + Only the difference from ToString is, when calling DFG operation functions, it calls + operationCallStringConstructorOnCell and operationCallStringConstructor instead of + operationToStringOnCell and operationToString. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::fixupToStringOrCallStringConstructor): + (JSC::DFG::FixupPhase::attemptToMakeFastStringAdd): + (JSC::DFG::FixupPhase::fixupToString): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructorOnCell): + (JSC::DFG::SpeculativeJIT::compileToStringOnCell): Deleted. + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStructureRegistrationPhase.cpp: + (JSC::DFG::StructureRegistrationPhase::run): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileToStringOrCallStringConstructor): + (JSC::FTL::LowerDFGToLLVM::compileToString): Deleted. + * runtime/StringConstructor.cpp: + (JSC::stringConstructor): + (JSC::callStringConstructor): + * runtime/StringConstructor.h: + * tests/stress/symbol-and-string-constructor.js: Added. + (performString): + +2015-04-06 Yusuke Suzuki <utatane.tea@gmail.com> + + Return Optional<uint32_t> from PropertyName::asIndex + https://bugs.webkit.org/show_bug.cgi?id=143422 + + Reviewed by Darin Adler. + + PropertyName::asIndex returns uint32_t and use UINT_MAX as NotAnIndex. + But it's not obvious to callers. + + This patch changes + 1. PropertyName::asIndex() to return Optional<uint32_t> and + 2. function name `asIndex()` to `parseIndex()`. + It forces callers to check the value is index or not explicitly. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitDirectPutById): + * jit/Repatch.cpp: + (JSC::emitPutTransitionStubAndGetOldStructure): + * jsc.cpp: + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSort): + * runtime/GenericArgumentsInlines.h: + (JSC::GenericArguments<Type>::getOwnPropertySlot): + (JSC::GenericArguments<Type>::put): + (JSC::GenericArguments<Type>::deleteProperty): + (JSC::GenericArguments<Type>::defineOwnProperty): + * runtime/Identifier.h: + (JSC::parseIndex): + (JSC::Identifier::isSymbol): + * runtime/JSArray.cpp: + (JSC::JSArray::defineOwnProperty): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitive): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot): + (JSC::JSGenericTypedArrayView<Adaptor>::put): + (JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty): + (JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty): + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::putDirectAccessor): + (JSC::JSObject::putDirectCustomAccessor): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::putDirectMayBeIndex): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + (JSC::JSObject::getOwnPropertySlot): + (JSC::JSObject::getPropertySlot): + (JSC::JSObject::putDirectInternal): + * runtime/JSString.cpp: + (JSC::JSString::getStringPropertyDescriptor): + * runtime/JSString.h: + (JSC::JSString::getStringPropertySlot): + * runtime/LiteralParser.cpp: + (JSC::LiteralParser<CharType>::parse): + * runtime/PropertyName.h: + (JSC::parseIndex): + (JSC::toUInt32FromCharacters): Deleted. + (JSC::toUInt32FromStringImpl): Deleted. + (JSC::PropertyName::asIndex): Deleted. + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + * runtime/StringObject.cpp: + (JSC::StringObject::deleteProperty): + * runtime/Structure.cpp: + (JSC::Structure::prototypeChainMayInterceptStoreTo): + +2015-04-05 Andreas Kling <akling@apple.com> + + URI encoding/escaping should use efficient string building instead of calling snprintf(). + <https://webkit.org/b/143426> + + Reviewed by Gavin Barraclough. + + I saw 0.5% of main thread time in snprintf() on <http://polymerlabs.github.io/benchmarks/> + which seemed pretty silly. This change gets that down to nothing in favor of using our + existing JSStringBuilder and HexNumber.h facilities. + + These APIs are well-exercised by our existing test suite. + + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::encode): + (JSC::globalFuncEscape): + +2015-04-05 Masataka Yakura <masataka.yakura@gmail.com> + + documentation for ES Promises points to the wrong one + https://bugs.webkit.org/show_bug.cgi?id=143263 + + Reviewed by Darin Adler. + + * features.json: + +2015-04-05 Simon Fraser <simon.fraser@apple.com> + + Remove "go ahead and" from comments + https://bugs.webkit.org/show_bug.cgi?id=143421 + + Reviewed by Darin Adler, Benjamin Poulain. + + Remove the phrase "go ahead and" from comments where it doesn't add + anything (which is almost all of them). + + * interpreter/JSStack.cpp: + (JSC::JSStack::growSlowCase): + +2015-04-04 Andreas Kling <akling@apple.com> + + Logically empty WeakBlocks should not pin down their MarkedBlocks indefinitely. + <https://webkit.org/b/143210> + + Reviewed by Geoffrey Garen. + + Since a MarkedBlock cannot be destroyed until all the WeakBlocks pointing into it are gone, + we had a little problem where WeakBlocks with only null pointers would still keep their + MarkedBlock alive. + + This patch fixes that by detaching WeakBlocks from their MarkedBlock once a sweep discovers + that the WeakBlock contains no pointers to live objects. Ownership of the WeakBlock is passed + to the Heap, which will sweep the list of these detached WeakBlocks as part of a full GC, + destroying them once they're fully dead. + + This allows the garbage collector to reclaim the 64kB MarkedBlocks much sooner, and resolves + a mysterious issue where doing two full garbage collections back-to-back would free additional + memory in the second collection. + + Management of detached WeakBlocks is implemented as a Vector<WeakBlock*> in Heap, along with + an index of the next block in that vector that needs to be swept. The IncrementalSweeper then + calls into Heap::sweepNextLogicallyEmptyWeakBlock() to sweep one block at a time. + + * heap/Heap.h: + * heap/Heap.cpp: + (JSC::Heap::collectAllGarbage): Add a final pass where we sweep the logically empty WeakBlocks + owned by Heap, after everything else has been swept. + + (JSC::Heap::notifyIncrementalSweeper): Set up an incremental sweep of logically empty WeakBlocks + after a full garbage collection ends. Note that we don't do this after Eden collections, since + they are unlikely to cause entire WeakBlocks to go empty. + + (JSC::Heap::addLogicallyEmptyWeakBlock): Added. Interface for passing ownership of a WeakBlock + to the Heap when it's detached from a WeakSet. + + (JSC::Heap::sweepAllLogicallyEmptyWeakBlocks): Helper for collectAllGarbage() that sweeps all + of the logically empty WeakBlocks owned by Heap. + + (JSC::Heap::sweepNextLogicallyEmptyWeakBlock): Sweeps one logically empty WeakBlock if needed + and updates the next-logically-empty-weak-block-to-sweep index. + + (JSC::Heap::lastChanceToFinalize): call sweepAllLogicallyEmptyWeakBlocks() here, since there + won't be another chance after this. + + * heap/IncrementalSweeper.h: + (JSC::IncrementalSweeper::hasWork): Deleted. + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::fullSweep): + (JSC::IncrementalSweeper::doSweep): + (JSC::IncrementalSweeper::sweepNextBlock): Restructured IncrementalSweeper a bit to simplify + adding a new sweeping stage for the Heap's logically empty WeakBlocks. sweepNextBlock() is + changed to return a bool (true if there's more work to be done.) + + * heap/WeakBlock.cpp: + (JSC::WeakBlock::sweep): This now figures out if the WeakBlock is logically empty, i.e doesn't + contain any pointers to live objects. The answer is stored in a new SweepResult member. + + * heap/WeakBlock.h: + (JSC::WeakBlock::isLogicallyEmptyButNotFree): Added. Can be queried after a sweep to determine + if the WeakBlock could be detached from the MarkedBlock. + + (JSC::WeakBlock::SweepResult::SweepResult): Deleted in favor of initializing member variables + when declaring them. + +2015-04-04 Yusuke Suzuki <utatane.tea@gmail.com> + + Implement ES6 Object.getOwnPropertySymbols + https://bugs.webkit.org/show_bug.cgi?id=141106 + + Reviewed by Geoffrey Garen. + + This patch implements `Object.getOwnPropertySymbols`. + One technical issue is that, since we use private symbols (such as `@Object`) in the + privileged JS code in `builtins/`, they should not be exposed. + To distinguish them from the usual symbols, check the target `StringImpl*` is a not private name + before adding it into PropertyNameArray. + + To check the target `StringImpl*` is a private name, we leverage privateToPublic map in `BuiltinNames` + since all private symbols are held in this map. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createExecutableInternal): + * builtins/BuiltinNames.h: + (JSC::BuiltinNames::isPrivateName): + * runtime/CommonIdentifiers.cpp: + (JSC::CommonIdentifiers::isPrivateName): + * runtime/CommonIdentifiers.h: + * runtime/EnumerationMode.h: + (JSC::EnumerationMode::EnumerationMode): + (JSC::EnumerationMode::includeSymbolProperties): + * runtime/ExceptionHelpers.cpp: + (JSC::createUndefinedVariableError): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames): + * runtime/JSSymbolTableObject.cpp: + (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::finishCreation): + (JSC::objectConstructorGetOwnPropertySymbols): + (JSC::defineProperties): + (JSC::objectConstructorSeal): + (JSC::objectConstructorFreeze): + (JSC::objectConstructorIsSealed): + (JSC::objectConstructorIsFrozen): + * runtime/ObjectConstructor.h: + (JSC::ObjectConstructor::create): + * runtime/Structure.cpp: + (JSC::Structure::getPropertyNamesFromStructure): + * tests/stress/object-get-own-property-symbols-perform-to-object.js: Added. + (compare): + * tests/stress/object-get-own-property-symbols.js: Added. + (forIn): + * tests/stress/symbol-define-property.js: Added. + (testSymbol): + * tests/stress/symbol-seal-and-freeze.js: Added. + * tests/stress/symbol-with-json.js: Added. + +2015-04-03 Mark Lam <mark.lam@apple.com> + + Add Options::jitPolicyScale() as a single knob to make all compilations happen sooner. + <https://webkit.org/b/143385> + + Reviewed by Geoffrey Garen. + + For debugging purposes, sometimes, we want to be able to make compilation happen + sooner to see if we can accelerate the manifestation of certain events / bugs. + Currently, in order to achieve this, we'll have to tweak multiple JIT thresholds + which make up the compilation policy. Let's add a single knob that can tune all + the thresholds up / down in one go proportionately so that we can easily tweak + how soon compilation occurs. + + * runtime/Options.cpp: + (JSC::scaleJITPolicy): + (JSC::recomputeDependentOptions): + * runtime/Options.h: + +2015-04-03 Geoffrey Garen <ggaren@apple.com> + + is* API methods should be @properties + https://bugs.webkit.org/show_bug.cgi?id=143388 + + Reviewed by Mark Lam. + + This appears to be the preferred idiom in WebKit, CA, AppKit, and + Foundation. + + * API/JSValue.h: Be @properties. + + * API/tests/testapi.mm: + (testObjectiveCAPI): Use the @properties. + +2015-04-03 Mark Lam <mark.lam@apple.com> + + Some JSC Options refactoring and enhancements. + <https://webkit.org/b/143384> + + Rubber stamped by Benjamin Poulain. + + Create a better encapsulated Option class to make working with options easier. This + is a building block towards a JIT policy scaling debugging option I will introduce later. + + This work entails: + 1. Convert Options::Option into a public class Option (who works closely with Options). + 2. Convert Options::EntryType into an enum class Options::Type and make it public. + 3. Renamed Options::OPT_<option name> to Options::<option name>ID because it reads better. + 4. Add misc methods to class Option to make it more useable. + + * runtime/Options.cpp: + (JSC::Options::dumpOption): + (JSC::Option::dump): + (JSC::Option::operator==): + (JSC::Options::Option::dump): Deleted. + (JSC::Options::Option::operator==): Deleted. + * runtime/Options.h: + (JSC::Option::Option): + (JSC::Option::operator!=): + (JSC::Option::name): + (JSC::Option::description): + (JSC::Option::type): + (JSC::Option::isOverridden): + (JSC::Option::defaultOption): + (JSC::Option::boolVal): + (JSC::Option::unsignedVal): + (JSC::Option::doubleVal): + (JSC::Option::int32Val): + (JSC::Option::optionRangeVal): + (JSC::Option::optionStringVal): + (JSC::Option::gcLogLevelVal): + (JSC::Options::Option::Option): Deleted. + (JSC::Options::Option::operator!=): Deleted. + +2015-04-03 Geoffrey Garen <ggaren@apple.com> + + JavaScriptCore API should support type checking for Array and Date + https://bugs.webkit.org/show_bug.cgi?id=143324 + + Follow-up to address a comment by Dan. + + * API/WebKitAvailability.h: __MAC_OS_X_VERSION_MIN_REQUIRED <= 101100 + is wrong, since this API is available when __MAC_OS_X_VERSION_MIN_REQUIRED + is equal to 101100. + +2015-04-03 Geoffrey Garen <ggaren@apple.com> + + JavaScriptCore API should support type checking for Array and Date + https://bugs.webkit.org/show_bug.cgi?id=143324 + + Follow-up to address a comment by Dan. + + * API/WebKitAvailability.h: Do use 10.0 because it was right all along. + Added a comment explaining why. + +2015-04-03 Csaba Osztrogonác <ossy@webkit.org> + + FTL JIT tests should fail if LLVM library isn't available + https://bugs.webkit.org/show_bug.cgi?id=143374 + + Reviewed by Mark Lam. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * runtime/Options.h: + +2015-04-03 Zan Dobersek <zdobersek@igalia.com> + + Fix the EFL and GTK build after r182243 + https://bugs.webkit.org/show_bug.cgi?id=143361 + + Reviewed by Csaba Osztrogonác. + + * CMakeLists.txt: InspectorBackendCommands.js is generated in the + DerivedSources/JavaScriptCore/inspector/ directory. + +2015-04-03 Zan Dobersek <zdobersek@igalia.com> + + Unreviewed, fixing Clang builds of the GTK port on Linux. + + * runtime/Options.cpp: + Include the <math.h> header for isnan(). + +2015-04-02 Mark Lam <mark.lam@apple.com> + + Enhance ability to dump JSC Options. + <https://webkit.org/b/143357> + + Reviewed by Benjamin Poulain. + + Some enhancements to how the JSC options work: + + 1. Add a JSC_showOptions option which take values: 0 = None, 1 = Overridden only, + 2 = All, 3 = Verbose. + + The default is 0 (None). This dumps nothing. + With the Overridden setting, at VM initialization time, we will dump all + option values that have been changed from their default. + With the All setting, at VM initialization time, we will dump all option values. + With the Verbose setting, at VM initialization time, we will dump all option + values along with their descriptions (if available). + + 2. We now store a copy of the default option values. + + We later use this for comparison to tell if an option has been overridden, and + print the default value for reference. As a result, we no longer need the + didOverride flag since we can compute whether the option is overridden at any time. + + 3. Added description strings to some options to be printed when JSC_showOptions=3 (Verbose). + + This will come in handy later when we want to rename some of the options to more sane + names that are easier to remember. For example, we can change + Options::dfgFunctionWhitelistFile() to Options::dfgWhiteList(), and + Options::slowPathAllocsBetweenGCs() to Options::forcedGcRate(). With the availability + of the description, we can afford to use shorter and less descriptive option names, + but they will be easier to remember and use for day to day debugging work. + + In this patch, I did not change the names of any of the options yet. I only added + description strings for options that I know about, and where I think the option name + isn't already descriptive enough. + + 4. Also deleted some unused code. + + * jsc.cpp: + (CommandLine::parseArguments): + * runtime/Options.cpp: + (JSC::Options::initialize): + (JSC::Options::setOption): + (JSC::Options::dumpAllOptions): + (JSC::Options::dumpOption): + (JSC::Options::Option::dump): + (JSC::Options::Option::operator==): + * runtime/Options.h: + (JSC::OptionRange::rangeString): + (JSC::Options::Option::Option): + (JSC::Options::Option::operator!=): + +2015-04-02 Geoffrey Garen <ggaren@apple.com> + + JavaScriptCore API should support type checking for Array and Date + https://bugs.webkit.org/show_bug.cgi?id=143324 + + Reviewed by Darin Adler, Sam Weinig, Dan Bernstein. + + * API/JSValue.h: + * API/JSValue.mm: + (-[JSValue isArray]): + (-[JSValue isDate]): Added an ObjC API. + + * API/JSValueRef.cpp: + (JSValueIsArray): + (JSValueIsDate): + * API/JSValueRef.h: Added a C API. + + * API/WebKitAvailability.h: Brought our availability macros up to date + and fixed a harmless bug where "10_10" translated to "10.0". + + * API/tests/testapi.c: + (main): Added a test and corrected a pre-existing leak. + + * API/tests/testapi.mm: + (testObjectiveCAPI): Added a test. + +2015-04-02 Mark Lam <mark.lam@apple.com> + + Add Options::dumpSourceAtDFGTime(). + <https://webkit.org/b/143349> + + Reviewed by Oliver Hunt, and Michael Saboff. + + Sometimes, we will want to see the JS source code that we're compiling, and it + would be nice to be able to do this without having to jump thru a lot of hoops. + So, let's add a Options::dumpSourceAtDFGTime() option just like we have a + Options::dumpBytecodeAtDFGTime() option. + + Also added versions of CodeBlock::dumpSource() and CodeBlock::dumpBytecode() + that explicitly take no arguments (instead of relying on the version that takes + the default argument). These versions are friendlier to use when we want to call + them from an interactive debugging session. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpSource): + (JSC::CodeBlock::dumpBytecode): + * bytecode/CodeBlock.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * runtime/Options.h: + +2015-04-02 Yusuke Suzuki <utatane.tea@gmail.com> + + Clean up EnumerationMode to easily extend + https://bugs.webkit.org/show_bug.cgi?id=143276 + + Reviewed by Geoffrey Garen. + + To make the followings easily, + 1. Adding new flag Include/ExcludeSymbols in the Object.getOwnPropertySymbols patch + 2. Make ExcludeSymbols implicitly default for the existing flags + we encapsulate EnumerationMode flags into EnumerationMode class. + + And this class manages 2 flags. Later it will be extended to 3. + 1. DontEnumPropertiesMode (default is Exclude) + 2. JSObjectPropertiesMode (default is Include) + 3. SymbolPropertiesMode (default is Exclude) + SymbolPropertiesMode will be added in Object.getOwnPropertySymbols patch. + + This patch replaces places using ExcludeDontEnumProperties + to EnumerationMode() value which represents default mode. + + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames): + * API/JSObjectRef.cpp: + (JSObjectCopyPropertyNames): + * bindings/ScriptValue.cpp: + (Deprecated::jsToInspectorValue): + * bytecode/ObjectAllocationProfile.h: + (JSC::ObjectAllocationProfile::possibleDefaultPropertyCount): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSort): + * runtime/EnumerationMode.h: + (JSC::EnumerationMode::EnumerationMode): + (JSC::EnumerationMode::includeDontEnumProperties): + (JSC::EnumerationMode::includeJSObjectProperties): + (JSC::shouldIncludeDontEnumProperties): Deleted. + (JSC::shouldExcludeDontEnumProperties): Deleted. + (JSC::shouldIncludeJSObjectPropertyNames): Deleted. + (JSC::modeThatSkipsJSObject): Deleted. + * runtime/GenericArgumentsInlines.h: + (JSC::GenericArguments<Type>::getOwnPropertyNames): + * runtime/JSArray.cpp: + (JSC::JSArray::getOwnNonIndexPropertyNames): + * runtime/JSArrayBuffer.cpp: + (JSC::JSArrayBuffer::getOwnNonIndexPropertyNames): + * runtime/JSArrayBufferView.cpp: + (JSC::JSArrayBufferView::getOwnNonIndexPropertyNames): + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnNonIndexPropertyNames): + * runtime/JSFunction.h: + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames): + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames): + * runtime/JSONObject.cpp: + (JSC::Stringifier::Holder::appendNextProperty): + (JSC::Walker::walk): + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + (JSC::JSObject::getOwnPropertyNames): + (JSC::JSObject::getOwnNonIndexPropertyNames): + (JSC::JSObject::getGenericPropertyNames): + * runtime/JSPropertyNameEnumerator.h: + (JSC::propertyNameEnumerator): + * runtime/JSSymbolTableObject.cpp: + (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames): + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyNames): + (JSC::objectConstructorKeys): + (JSC::defineProperties): + (JSC::objectConstructorSeal): + (JSC::objectConstructorFreeze): + (JSC::objectConstructorIsSealed): + (JSC::objectConstructorIsFrozen): + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::getOwnNonIndexPropertyNames): + (JSC::RegExpObject::getPropertyNames): + (JSC::RegExpObject::getGenericPropertyNames): + * runtime/StringObject.cpp: + (JSC::StringObject::getOwnPropertyNames): + * runtime/Structure.cpp: + (JSC::Structure::getPropertyNamesFromStructure): + +2015-04-01 Alex Christensen <achristensen@webkit.org> + + Progress towards CMake on Windows and Mac. + https://bugs.webkit.org/show_bug.cgi?id=143293 + + Reviewed by Filip Pizlo. + + * CMakeLists.txt: + Enabled using assembly on Windows. + Replaced unix commands with CMake commands. + * PlatformMac.cmake: + Tell open source builders where to find unicode headers. + +2015-04-01 Yusuke Suzuki <utatane.tea@gmail.com> + + IteratorClose should be called when jumping over the target for-of loop + https://bugs.webkit.org/show_bug.cgi?id=143140 + + Reviewed by Geoffrey Garen. + + This patch fixes labeled break/continue behaviors with for-of and iterators. + + 1. Support IteratorClose beyond multiple loop contexts + Previously, IteratorClose is only executed in for-of's breakTarget(). + However, this misses IteratorClose execution when statement roll-ups multiple control flow contexts. + For example, + outer: for (var e1 of outer) { + inner: for (var e2 of inner) { + break outer; + } + } + In this case, return method of inner should be called. + We leverage the existing system for `finally` to execute inner.return method correctly. + Leveraging `finally` system fixes `break`, `continue` and `return` cases. + `throw` case is already supported by emitting try-catch handlers in for-of. + + 2. Incorrect LabelScope creation is done in ForOfNode + ForOfNode creates duplicated LabelScope. + It causes infinite loop when executing the following program that contains + explicitly labeled for-of loop. + For example, + inner: for (var elm of array) { + continue inner; + } + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::pushFinallyContext): + (JSC::BytecodeGenerator::pushIteratorCloseContext): + (JSC::BytecodeGenerator::popFinallyContext): + (JSC::BytecodeGenerator::popIteratorCloseContext): + (JSC::BytecodeGenerator::emitComplexPopScopes): + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::emitIteratorClose): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ForOfNode::emitBytecode): + * tests/stress/iterator-return-beyond-multiple-iteration-scopes.js: Added. + (createIterator.iterator.return): + (createIterator): + * tests/stress/raise-error-in-iterator-close.js: Added. + (createIterator.iterator.return): + (createIterator): + +2015-04-01 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Implement Symbol.unscopables + https://bugs.webkit.org/show_bug.cgi?id=142829 + + Reviewed by Geoffrey Garen. + + This patch introduces Symbol.unscopables functionality. + In ES6, some generic names (like keys, values) are introduced + as Array's method name. And this breaks the web since some web sites + use like the following code. + + var values = ...; + with (array) { + values; // This values is trapped by array's method "values". + } + + To fix this, Symbol.unscopables introduces blacklist + for with scope's trapping. When resolving scope, + if name is found in the target scope and the target scope is with scope, + we check Symbol.unscopables object to filter generic names. + + This functionality is only active for with scopes. + Global scope does not have unscopables functionality. + + And since + 1) op_resolve_scope for with scope always return Dynamic resolve type, + 2) in that case, JSScope::resolve is always used in JIT and LLInt, + 3) the code which contains op_resolve_scope that returns Dynamic cannot be compiled with DFG and FTL, + to implement this functionality, we just change JSScope::resolve and no need to change JIT code. + So performance regression is only visible in Dynamic resolving case, and it is already much slow. + + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::runtimeFlags): + * runtime/JSScope.cpp: + (JSC::isUnscopable): + (JSC::JSScope::resolve): + * runtime/JSScope.h: + (JSC::ScopeChainIterator::scope): + * tests/stress/global-environment-does-not-trap-unscopables.js: Added. + (test): + * tests/stress/unscopables.js: Added. + (test): + (.): + +2015-03-31 Ryosuke Niwa <rniwa@webkit.org> + + ES6 class syntax should allow static setters and getters + https://bugs.webkit.org/show_bug.cgi?id=143180 + + Reviewed by Filip Pizlo + + Apparently I misread the spec when I initially implemented parseClass. + ES6 class syntax allows static getters and setters so just allow that. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + +2015-03-31 Filip Pizlo <fpizlo@apple.com> + + PutClosureVar CSE def() rule has a wrong base + https://bugs.webkit.org/show_bug.cgi?id=143280 + + Reviewed by Michael Saboff. + + I think that this code was incorrect in a benign way, since the base of a + PutClosureVar is not a JS-visible object. But it was preventing some optimizations. + + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + +2015-03-31 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r182200. + https://bugs.webkit.org/show_bug.cgi?id=143279 + + Probably causing assertion extravaganza on bots. (Requested by + kling on #webkit). + + Reverted changeset: + + "Logically empty WeakBlocks should not pin down their + MarkedBlocks indefinitely." + https://bugs.webkit.org/show_bug.cgi?id=143210 + http://trac.webkit.org/changeset/182200 + +2015-03-31 Yusuke Suzuki <utatane.tea@gmail.com> + + Clean up Identifier factories to clarify the meaning of StringImpl* + https://bugs.webkit.org/show_bug.cgi?id=143146 + + Reviewed by Filip Pizlo. + + In the a lot of places, `Identifier(VM*/ExecState*, StringImpl*)` constructor is used. + However, it's ambiguous because `StringImpl*` has 2 different meanings. + 1) normal string, it is replacable with `WTFString` and + 2) `uid`, which holds `isSymbol` information to represent Symbols. + So we dropped Identifier constructors for strings and instead, introduced 2 factory functions. + + `Identifier::fromString(VM*/ExecState*, const String&)`. + Just construct Identifier from strings. The symbol-ness of StringImpl* is not kept. + + `Identifier::fromUid(VM*/ExecState*, StringImpl*)`. + This function is used for 2) `uid`. So symbol-ness of `StringImpl*` is kept. + + And to clean up `StringImpl` which is used as uid, + we introduce `StringKind` into `StringImpl`. There's 3 kinds + 1. StringNormal (non-atomic, non-symbol) + 2. StringAtomic (atomic, non-symbol) + 3. StringSymbol (non-atomic, symbol) + They are mutually exclusive. And (atomic, symbol) case should not exist. + + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::getOwnNonIndexPropertyNames): + * API/JSObjectRef.cpp: + (JSObjectMakeFunction): + * API/OpaqueJSString.cpp: + (OpaqueJSString::identifier): + * bindings/ScriptFunctionCall.cpp: + (Deprecated::ScriptFunctionCall::call): + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createExecutableInternal): + * builtins/BuiltinNames.h: + (JSC::BuiltinNames::BuiltinNames): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitThrowReferenceError): + (JSC::BytecodeGenerator::emitThrowTypeError): + (JSC::BytecodeGenerator::emitReadOnlyExceptionIfNeeded): + (JSC::BytecodeGenerator::emitEnumeration): + * dfg/DFGDesiredIdentifiers.cpp: + (JSC::DFG::DesiredIdentifiers::reallyAdd): + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::functionDetails): + (Inspector::constructInternalProperty): + (Inspector::JSInjectedScriptHost::weakMapEntries): + (Inspector::JSInjectedScriptHost::iteratorEntries): + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + * inspector/JSJavaScriptCallFramePrototype.cpp: + * inspector/ScriptCallStackFactory.cpp: + (Inspector::extractSourceInformationFromException): + * jit/JITOperations.cpp: + * jsc.cpp: + (GlobalObject::finishCreation): + (GlobalObject::addFunction): + (GlobalObject::addConstructableFunction): + (functionRun): + (runWithScripts): + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LowLevelInterpreter.asm: + * parser/ASTBuilder.h: + (JSC::ASTBuilder::addVar): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): + (JSC::Parser<LexerType>::createBindingPattern): + * parser/ParserArena.h: + (JSC::IdentifierArena::makeIdentifier): + (JSC::IdentifierArena::makeIdentifierLCharFromUChar): + (JSC::IdentifierArena::makeNumericIdentifier): + * runtime/ArgumentsIteratorPrototype.cpp: + (JSC::ArgumentsIteratorPrototype::finishCreation): + * runtime/ArrayIteratorPrototype.cpp: + (JSC::ArrayIteratorPrototype::finishCreation): + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::finishCreation): + (JSC::arrayProtoFuncPush): + * runtime/ClonedArguments.cpp: + (JSC::ClonedArguments::getOwnPropertySlot): + * runtime/CommonIdentifiers.cpp: + (JSC::CommonIdentifiers::CommonIdentifiers): + * runtime/CommonIdentifiers.h: + * runtime/Error.cpp: + (JSC::addErrorInfo): + (JSC::hasErrorInfo): + * runtime/ExceptionHelpers.cpp: + (JSC::createUndefinedVariableError): + * runtime/GenericArgumentsInlines.h: + (JSC::GenericArguments<Type>::getOwnPropertySlot): + * runtime/Identifier.h: + (JSC::Identifier::isSymbol): + (JSC::Identifier::Identifier): + (JSC::Identifier::from): Deleted. + * runtime/IdentifierInlines.h: + (JSC::Identifier::Identifier): + (JSC::Identifier::fromUid): + (JSC::Identifier::fromString): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::dumpInContextAssumingStructure): + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::toPropertyKey): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames): + * runtime/JSObject.cpp: + (JSC::getClassPropertyNames): + (JSC::JSObject::reifyStaticFunctionsForDelete): + * runtime/JSObject.h: + (JSC::makeIdentifier): + * runtime/JSPromiseConstructor.cpp: + (JSC::JSPromiseConstructorFuncRace): + (JSC::JSPromiseConstructorFuncAll): + * runtime/JSString.h: + (JSC::JSString::toIdentifier): + * runtime/JSSymbolTableObject.cpp: + (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames): + * runtime/LiteralParser.cpp: + (JSC::LiteralParser<CharType>::tryJSONPParse): + (JSC::LiteralParser<CharType>::makeIdentifier): + * runtime/Lookup.h: + (JSC::reifyStaticProperties): + * runtime/MapConstructor.cpp: + (JSC::constructMap): + * runtime/MapIteratorPrototype.cpp: + (JSC::MapIteratorPrototype::finishCreation): + * runtime/MapPrototype.cpp: + (JSC::MapPrototype::finishCreation): + * runtime/MathObject.cpp: + (JSC::MathObject::finishCreation): + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::finishCreation): + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::finishCreation): + * runtime/PrivateName.h: + (JSC::PrivateName::PrivateName): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::find): + (JSC::PropertyTable::get): + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + (JSC::PropertyName::publicName): + (JSC::PropertyName::asIndex): + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArray::addKnownUnique): + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::finishCreation): + * runtime/SetConstructor.cpp: + (JSC::constructSet): + * runtime/SetIteratorPrototype.cpp: + (JSC::SetIteratorPrototype::finishCreation): + * runtime/SetPrototype.cpp: + (JSC::SetPrototype::finishCreation): + * runtime/StringIteratorPrototype.cpp: + (JSC::StringIteratorPrototype::finishCreation): + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + * runtime/Structure.cpp: + (JSC::Structure::getPropertyNamesFromStructure): + * runtime/SymbolConstructor.cpp: + * runtime/VM.cpp: + (JSC::VM::throwException): + * runtime/WeakMapConstructor.cpp: + (JSC::constructWeakMap): + +2015-03-31 Andreas Kling <akling@apple.com> + + Logically empty WeakBlocks should not pin down their MarkedBlocks indefinitely. + <https://webkit.org/b/143210> + + Reviewed by Geoffrey Garen. + + Since a MarkedBlock cannot be destroyed until all the WeakBlocks pointing into it are gone, + we had a little problem where WeakBlocks with only null pointers would still keep their + MarkedBlock alive. + + This patch fixes that by detaching WeakBlocks from their MarkedBlock once a sweep discovers + that the WeakBlock contains no pointers to live objects. Ownership of the WeakBlock is passed + to the Heap, which will sweep the list of these detached WeakBlocks as part of a full GC, + destroying them once they're fully dead. + + This allows the garbage collector to reclaim the 64kB MarkedBlocks much sooner, and resolves + a mysterious issue where doing two full garbage collections back-to-back would free additional + memory in the second collection. + + Management of detached WeakBlocks is implemented as a Vector<WeakBlock*> in Heap, along with + an index of the next block in that vector that needs to be swept. The IncrementalSweeper then + calls into Heap::sweepNextLogicallyEmptyWeakBlock() to sweep one block at a time. + + * heap/Heap.h: + * heap/Heap.cpp: + (JSC::Heap::collectAllGarbage): Add a final pass where we sweep the logically empty WeakBlocks + owned by Heap, after everything else has been swept. + + (JSC::Heap::notifyIncrementalSweeper): Set up an incremental sweep of logically empty WeakBlocks + after a full garbage collection ends. Note that we don't do this after Eden collections, since + they are unlikely to cause entire WeakBlocks to go empty. + + (JSC::Heap::addLogicallyEmptyWeakBlock): Added. Interface for passing ownership of a WeakBlock + to the Heap when it's detached from a WeakSet. + + (JSC::Heap::sweepAllLogicallyEmptyWeakBlocks): Helper for collectAllGarbage() that sweeps all + of the logically empty WeakBlocks owned by Heap. + + (JSC::Heap::sweepNextLogicallyEmptyWeakBlock): Sweeps one logically empty WeakBlock if needed + and updates the next-logically-empty-weak-block-to-sweep index. + + (JSC::Heap::lastChanceToFinalize): call sweepAllLogicallyEmptyWeakBlocks() here, since there + won't be another chance after this. + + * heap/IncrementalSweeper.h: + (JSC::IncrementalSweeper::hasWork): Deleted. + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::fullSweep): + (JSC::IncrementalSweeper::doSweep): + (JSC::IncrementalSweeper::sweepNextBlock): Restructured IncrementalSweeper a bit to simplify + adding a new sweeping stage for the Heap's logically empty WeakBlocks. sweepNextBlock() is + changed to return a bool (true if there's more work to be done.) + + * heap/WeakBlock.cpp: + (JSC::WeakBlock::sweep): This now figures out if the WeakBlock is logically empty, i.e doesn't + contain any pointers to live objects. The answer is stored in a new SweepResult member. + + * heap/WeakBlock.h: + (JSC::WeakBlock::isLogicallyEmptyButNotFree): Added. Can be queried after a sweep to determine + if the WeakBlock could be detached from the MarkedBlock. + + (JSC::WeakBlock::SweepResult::SweepResult): Deleted in favor of initializing member variables + when declaring them. + +2015-03-31 Ryosuke Niwa <rniwa@webkit.org> + + eval("this.foo") causes a crash if this had not been initialized in a derived class's constructor + https://bugs.webkit.org/show_bug.cgi?id=142883 + + Reviewed by Filip Pizlo. + + The crash was caused by eval inside the constructor of a derived class not checking TDZ. + + Fixed the bug by adding a parser flag that forces the TDZ check to be always emitted when accessing "this" + in eval inside a derived class' constructor. + + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::getSlow): + * bytecompiler/NodesCodegen.cpp: + (JSC::ThisNode::emitBytecode): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + * interpreter/Interpreter.cpp: + (JSC::eval): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::thisExpr): + * parser/NodeConstructors.h: + (JSC::ThisNode::ThisNode): + * parser/Nodes.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + (JSC::Parser<LexerType>::parsePrimaryExpression): + * parser/Parser.h: + (JSC::parse): + * parser/ParserModes.h: + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::thisExpr): + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getProgramCodeBlock): + (JSC::CodeCache::getEvalCodeBlock): + * runtime/CodeCache.h: + (JSC::SourceCodeKey::SourceCodeKey): + * runtime/Executable.cpp: + (JSC::EvalExecutable::create): + * runtime/Executable.h: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::createEvalCodeBlock): + * runtime/JSGlobalObject.h: + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncEval): + * tests/stress/class-syntax-no-tdz-in-eval.js: Added. + * tests/stress/class-syntax-tdz-in-eval.js: Added. + +2015-03-31 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r182186. + https://bugs.webkit.org/show_bug.cgi?id=143270 + + it crashes all the WebGL tests on the Debug bots (Requested by + dino on #webkit). + + Reverted changeset: + + "Web Inspector: add 2D/WebGL canvas instrumentation + infrastructure" + https://bugs.webkit.org/show_bug.cgi?id=137278 + http://trac.webkit.org/changeset/182186 + +2015-03-31 Yusuke Suzuki <utatane.tea@gmail.com> + + [ES6] Object type restrictions on a first parameter of several Object.* functions are relaxed + https://bugs.webkit.org/show_bug.cgi?id=142937 + + Reviewed by Darin Adler. + + In ES6, Object type restrictions on a first parameter of several Object.* functions are relaxed. + In ES5 or prior, when a first parameter is not object type, these functions raise TypeError. + But now, several functions perform ToObject onto a non-object parameter. + And others behaves as if a parameter is a non-extensible ordinary object with no own properties. + It is described in ES6 Annex E. + Functions different from ES5 are following. + + 1. An attempt is make to coerce the argument using ToObject. + Object.getOwnPropertyDescriptor + Object.getOwnPropertyNames + Object.getPrototypeOf + Object.keys + + 2. Treated as if it was a non-extensible ordinary object with no own properties. + Object.freeze + Object.isExtensible + Object.isFrozen + Object.isSealed + Object.preventExtensions + Object.seal + + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructorGetPrototypeOfFunctor::operator()): + (JSC::objectConstructorGetPrototypeOf): + (JSC::objectConstructorGetOwnPropertyDescriptor): + (JSC::objectConstructorGetOwnPropertyNames): + (JSC::objectConstructorKeys): + (JSC::objectConstructorSeal): + (JSC::objectConstructorFreeze): + (JSC::objectConstructorPreventExtensions): + (JSC::objectConstructorIsSealed): + (JSC::objectConstructorIsFrozen): + (JSC::objectConstructorIsExtensible): + * tests/stress/object-freeze-accept-non-object.js: Added. + * tests/stress/object-get-own-property-descriptor-perform-to-object.js: Added. + (canary): + * tests/stress/object-get-own-property-names-perform-to-object.js: Added. + (compare): + * tests/stress/object-get-prototype-of-perform-to-object.js: Added. + * tests/stress/object-is-extensible-accept-non-object.js: Added. + * tests/stress/object-is-frozen-accept-non-object.js: Added. + * tests/stress/object-is-sealed-accept-non-object.js: Added. + * tests/stress/object-keys-perform-to-object.js: Added. + (compare): + * tests/stress/object-prevent-extensions-accept-non-object.js: Added. + * tests/stress/object-seal-accept-non-object.js: Added. + +2015-03-31 Matt Baker <mattbaker@apple.com> + + Web Inspector: add 2D/WebGL canvas instrumentation infrastructure + https://bugs.webkit.org/show_bug.cgi?id=137278 + + Reviewed by Timothy Hatcher. + + Added Canvas protocol which defines types used by InspectorCanvasAgent. + + * CMakeLists.txt: + * DerivedSources.make: + * inspector/protocol/Canvas.json: Added. + + * inspector/scripts/codegen/generator.py: + (Generator.stylized_name_for_enum_value): + Added special handling for 2D (always uppercase) and WebGL (rename mapping) enum strings. + +2015-03-30 Ryosuke Niwa <rniwa@webkit.org> + + Extending null should set __proto__ to null + https://bugs.webkit.org/show_bug.cgi?id=142882 + + Reviewed by Geoffrey Garen and Benjamin Poulain. + + Set Derived.prototype.__proto__ to null when extending null. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ClassExprNode::emitBytecode): + +2015-03-30 Mark Lam <mark.lam@apple.com> + + REGRESSION (r181993): inspector-protocol/debugger/setBreakpoint-dfg-and-modify-local.html crashes. + <https://webkit.org/b/143105> + + Reviewed by Filip Pizlo. + + With r181993, the DFG and FTL may elide the storing of the scope register. As a result, + on OSR exits from DFG / FTL frames where this elision has take place, we may get baseline + JIT frames that may have its scope register not set. The Debugger's current implementation + which relies on the scope register is not happy about this. For example, this results in a + crash in the layout test inspector-protocol/debugger/setBreakpoint-dfg-and-modify-local.html. + + The fix is to disable inlining when the debugger is in use. Also, we add Flush nodes to + ensure that the scope register value is flushed to the register in the stack frame. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::ByteCodeParser): + (JSC::DFG::ByteCodeParser::setLocal): + (JSC::DFG::ByteCodeParser::flush): + - Add code to flush the scope register. + (JSC::DFG::ByteCodeParser::inliningCost): + - Pretend that all codeBlocks are too expensive to inline if the debugger is in use, thereby + disabling inlining whenever the debugger is in use. + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::hasDebuggerEnabled): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + - Update the DFG codeBlock's scopeRegister since it can be moved during stack layout. + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + - Update the FTL codeBlock's scopeRegister since it can be moved during stack layout. + +2015-03-30 Michael Saboff <msaboff@apple.com> + + Fix flakey float32-repeat-out-of-bounds.js and int8-repeat-out-of-bounds.js tests for ARM64 + https://bugs.webkit.org/show_bug.cgi?id=138391 + + Reviewed by Mark Lam. + + Re-enabling these tests as I can't get them to fail on local iOS test devices. + There have been many changes since these tests were disabled. + I'll watch automated test results for failures. If there are failures running automated + testing, it might be due to the device's relative CPU performance. + + * tests/stress/float32-repeat-out-of-bounds.js: + * tests/stress/int8-repeat-out-of-bounds.js: + +2015-03-30 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Regression: Preview for [[null]] shouldn't be [] + https://bugs.webkit.org/show_bug.cgi?id=143208 + + Reviewed by Mark Lam. + + * inspector/InjectedScriptSource.js: + Handle null when generating simple object previews. + +2015-03-30 Per Arne Vollan <peavo@outlook.com> + + Avoid using hardcoded values for JSValue::Int32Tag, if possible. + https://bugs.webkit.org/show_bug.cgi?id=143134 + + Reviewed by Geoffrey Garen. + + * jit/JSInterfaceJIT.h: + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + +2015-03-30 Filip Pizlo <fpizlo@apple.com> + + REGRESSION: js/regress/inline-arguments-local-escape.html is flaky + https://bugs.webkit.org/show_bug.cgi?id=143104 + + Reviewed by Geoffrey Garen. + + Created a test that is a 100% repro of the flaky failure. This test is called + get-my-argument-by-val-for-inlined-escaped-arguments.js. It fails all of the time because it + always causes the compiler to emit a GetMyArgumentByVal of the arguments object returned by + the inlined function. Other than that, it's the same as inline-arguments-local-escape. + + Also created three more tests for three similar, but not identical, failures. + + Then fixed the bug: PreciseLocalClobberize was assuming that if we read(Stack) then we are + only reading those parts of the stack that are relevant to the current semantic code origin. + That's false after ArgumentsEliminationPhase - we might have operations on phantom arguments, + like GetMyArgumentByVal, ForwardVarargs, CallForwardVarargs, and ConstructForwardVarargs, that + read parts of the stack associated with the inline call frame for the phantom arguments. This + may not be subsumed by the current semantic origin's stack area in cases that the arguments + were allowed to "locally" escape. + + The higher-order lesson here is that in DFG SSA IR, the current semantic origin's stack area + is not really a meaningful concept anymore. It is only meaningful for nodes that will read + the stack due to function.arguments, but there are a bunch of other ways that we could also + read the stack and those operations may read any stack slot. I believe that this change makes + PreciseLocalClobberize right: it will refine a read(Stack) from Clobberize correctly by casing + on node type. In future, if we add a read(Stack) to Clobberize, we'll have to make sure that + readTop() in PreciseLocalClobberize does the right thing. + + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGPreciseLocalClobberize.h: + (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): + * dfg/DFGPutStackSinkingPhase.cpp: + * tests/stress/call-forward-varargs-for-inlined-escaped-arguments.js: Added. + * tests/stress/construct-forward-varargs-for-inlined-escaped-arguments.js: Added. + * tests/stress/forward-varargs-for-inlined-escaped-arguments.js: Added. + * tests/stress/get-my-argument-by-val-for-inlined-escaped-arguments.js: Added. + * tests/stress/real-forward-varargs-for-inlined-escaped-arguments.js: Added. + +2015-03-30 Benjamin Poulain <benjamin@webkit.org> + + Start the features.json files + https://bugs.webkit.org/show_bug.cgi?id=143207 + + Reviewed by Darin Adler. + + Start the features.json files to have something to experiment + with for the UI. + + * features.json: Added. + +2015-03-29 Myles C. Maxfield <mmaxfield@apple.com> + + [Win] Addresing post-review comment after r182122 + https://bugs.webkit.org/show_bug.cgi?id=143189 + + Unreviewed. + +2015-03-29 Myles C. Maxfield <mmaxfield@apple.com> + + [Win] Allow building JavaScriptCore without Cygwin + https://bugs.webkit.org/show_bug.cgi?id=143189 + + Reviewed by Brent Fulgham. + + Paths like /usr/bin/ don't exist on Windows. + Hashbangs don't work on Windows. Instead we must explicitly call the executable. + Prefixing commands with environment variables doesn't work on Windows. + Windows doesn't have 'cmp' + Windows uses 'del' instead of 'rm' + Windows uses 'type NUL' intead of 'touch' + + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make: + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make: + * JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl: + * JavaScriptCore.vcxproj/build-generated-files.pl: + * UpdateContents.py: Copied from Source/JavaScriptCore/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl. + +2015-03-28 Joseph Pecoraro <pecoraro@apple.com> + + Clean up JavaScriptCore/builtins + https://bugs.webkit.org/show_bug.cgi?id=143177 + + Reviewed by Ryosuke Niwa. + + * builtins/ArrayConstructor.js: + (from): + - We can compare to undefined instead of using a typeof undefined check. + - Converge on double quoted strings everywhere. + + * builtins/ArrayIterator.prototype.js: + (next): + * builtins/StringIterator.prototype.js: + (next): + - Use shorthand object construction to avoid duplication. + - Improve grammar in error messages. + + * tests/stress/array-iterators-next-with-call.js: + * tests/stress/string-iterators.js: + - Update for new error message strings. + +2015-03-28 Saam Barati <saambarati1@gmail.com> + + Web Inspector: ES6: Better support for Symbol types in Type Profiler + https://bugs.webkit.org/show_bug.cgi?id=141257 + + Reviewed by Joseph Pecoraro. + + ES6 introduces the new primitive type Symbol. This patch makes JSC's + type profiler support this new primitive type. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * inspector/protocol/Runtime.json: + * runtime/RuntimeType.cpp: + (JSC::runtimeTypeForValue): + * runtime/RuntimeType.h: + (JSC::runtimeTypeIsPrimitive): + * runtime/TypeSet.cpp: + (JSC::TypeSet::addTypeInformation): + (JSC::TypeSet::dumpTypes): + (JSC::TypeSet::doesTypeConformTo): + (JSC::TypeSet::displayName): + (JSC::TypeSet::inspectorTypeSet): + (JSC::TypeSet::toJSONString): + * runtime/TypeSet.h: + (JSC::TypeSet::seenTypes): + * tests/typeProfiler/driver/driver.js: + * tests/typeProfiler/symbol.js: Added. + (wrapper.foo): + (wrapper.bar): + (wrapper.bar.bar.baz): + (wrapper): + +2015-03-27 Saam Barati <saambarati1@gmail.com> + + Deconstruction parameters are bound too late + https://bugs.webkit.org/show_bug.cgi?id=143148 + + Reviewed by Filip Pizlo. + + Currently, a deconstruction pattern named with the same + name as a function will shadow the function. This is + wrong. It should be the other way around. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + +2015-03-27 Ryosuke Niwa <rniwa@webkit.org> + + parse doesn't initialize the 16-bit version of the JSC parser with defaultConstructorKind + https://bugs.webkit.org/show_bug.cgi?id=143170 + + Reviewed by Benjamin Poulain. + + Assert that we never use 16-bit version of the parser to parse a default constructor + since both base and derived default constructors should be using a 8-bit string. + + * parser/Parser.h: + (JSC::parse): + +2015-03-27 Ryosuke Niwa <rniwa@webkit.org> + + ES6 Classes: Runtime error in JIT'd class calling super() with arguments and superclass has default constructor + https://bugs.webkit.org/show_bug.cgi?id=142862 + + Reviewed by Benjamin Poulain. + + Add a test that used to fail in DFG now that the bug has been fixed by r181993. + + * tests/stress/class-syntax-derived-default-constructor.js: Added. + +2015-03-27 Michael Saboff <msaboff@apple.com> + + load8Signed() and load16Signed() should be renamed to avoid confusion + https://bugs.webkit.org/show_bug.cgi?id=143168 + + Reviewed by Benjamin Poulain. + + Renamed load8Signed() to load8SignedExtendTo32() and load16Signed() to load16SignedExtendTo32(). + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::load8SignedExtendTo32): + (JSC::MacroAssemblerARM::load16SignedExtendTo32): + (JSC::MacroAssemblerARM::load8Signed): Deleted. + (JSC::MacroAssemblerARM::load16Signed): Deleted. + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::load16SignedExtendTo32): + (JSC::MacroAssemblerARM64::load8SignedExtendTo32): + (JSC::MacroAssemblerARM64::load16Signed): Deleted. + (JSC::MacroAssemblerARM64::load8Signed): Deleted. + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::load16SignedExtendTo32): + (JSC::MacroAssemblerARMv7::load8SignedExtendTo32): + (JSC::MacroAssemblerARMv7::load16Signed): Deleted. + (JSC::MacroAssemblerARMv7::load8Signed): Deleted. + * assembler/MacroAssemblerMIPS.h: + (JSC::MacroAssemblerMIPS::load8SignedExtendTo32): + (JSC::MacroAssemblerMIPS::load16SignedExtendTo32): + (JSC::MacroAssemblerMIPS::load8Signed): Deleted. + (JSC::MacroAssemblerMIPS::load16Signed): Deleted. + * assembler/MacroAssemblerSH4.h: + (JSC::MacroAssemblerSH4::load8SignedExtendTo32): + (JSC::MacroAssemblerSH4::load8): + (JSC::MacroAssemblerSH4::load16SignedExtendTo32): + (JSC::MacroAssemblerSH4::load16): + (JSC::MacroAssemblerSH4::load8Signed): Deleted. + (JSC::MacroAssemblerSH4::load16Signed): Deleted. + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::load8SignedExtendTo32): + (JSC::MacroAssemblerX86Common::load16SignedExtendTo32): + (JSC::MacroAssemblerX86Common::load8Signed): Deleted. + (JSC::MacroAssemblerX86Common::load16Signed): Deleted. + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitIntTypedArrayGetByVal): + +2015-03-27 Michael Saboff <msaboff@apple.com> + + Fix flakey dfg-int8array.js and dfg-int16array.js tests for ARM64 + https://bugs.webkit.org/show_bug.cgi?id=138390 + + Reviewed by Mark Lam. + + Changed load8Signed() and load16Signed() to only sign extend the loaded value to 32 bits + instead of 64 bits. This is what X86-64 does. + + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::load16Signed): + (JSC::MacroAssemblerARM64::load8Signed): + +2015-03-27 Saam Barati <saambarati1@gmail.com> + + Add back previously broken assert from bug 141869 + https://bugs.webkit.org/show_bug.cgi?id=143005 + + Reviewed by Michael Saboff. + + * runtime/ExceptionHelpers.cpp: + (JSC::invalidParameterInSourceAppender): + +2015-03-26 Geoffrey Garen <ggaren@apple.com> + + Make some more objects use FastMalloc + https://bugs.webkit.org/show_bug.cgi?id=143122 + + Reviewed by Csaba Osztrogonác. + + * API/JSCallbackObject.h: + * heap/IncrementalSweeper.h: + * jit/JITThunks.h: + * runtime/JSGlobalObjectDebuggable.h: + * runtime/RegExpCache.h: + +2015-03-27 Michael Saboff <msaboff@apple.com> + + Objects with numeric properties intermittently get a phantom 'length' property + https://bugs.webkit.org/show_bug.cgi?id=142792 + + Reviewed by Csaba Osztrogonác. + + Fixed a > (greater than) that should be a >> (right shift) in the code that disassembles + test and branch instructions. This function is used for linking tbz/tbnz branches between + two seperately JIT'ed sections of code. Sometime we'd create a bogus tbz instruction in + the failure case checks in the GetById array length stub created for "obj.length" access. + If the failure case code address was at a negative offset from the stub, we'd look for bit 1 + being set when we should have been looking for bit 0. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::disassembleTestAndBranchImmediate): + +2015-03-27 Yusuke Suzuki <utatane.tea@gmail.com> + + Insert exception check around toPropertyKey call + https://bugs.webkit.org/show_bug.cgi?id=142922 + + Reviewed by Geoffrey Garen. + + In some places, exception check is missing after/before toPropertyKey. + However, since it calls toString, it's observable to users, + + Missing exception checks in Object.prototype methods can be + observed since it would be overridden with toObject(null/undefined) errors. + We inserted exception checks after toPropertyKey. + + Missing exception checks in GetById related code can be + observed since it would be overridden with toObject(null/undefined) errors. + In this case, we need to insert exception checks before/after toPropertyKey + since RequireObjectCoercible followed by toPropertyKey can cause exceptions. + + JSValue::get checks null/undefined and raise an exception if |this| is null or undefined. + However, we need to check whether the baseValue is object coercible before executing JSValue::toPropertyKey. + According to the spec, we first perform RequireObjectCoercible and check the exception. + And second, we perform ToPropertyKey and check the exception. + Since JSValue::toPropertyKey can cause toString call, this is observable to users. + For example, if the target is not object coercible, + ToPropertyKey should not be executed, and toString should not be executed by ToPropertyKey. + So the order of observable actions (RequireObjectCoercible and ToPropertyKey) should be correct to the spec. + + This patch introduces JSValue::requireObjectCoercible and use it because of the following 2 reasons. + + 1. Using toObject instead of requireObjectCoercible produces unnecessary wrapper object. + + toObject converts primitive types into wrapper objects. + But it is not efficient since wrapper objects are not necessary + if we look up methods from primitive values's prototype. (using synthesizePrototype is better). + + 2. Using the result of toObject is not correct to the spec. + + To align to the spec correctly, we cannot use JSObject::get + by using the wrapper object produced by the toObject suggested in (1). + If we use JSObject that is converted by toObject, getter will be called by using this JSObject as |this|. + It is not correct since getter should be called with the original |this| value that may be primitive types. + + So in this patch, we use JSValue::requireObjectCoercible + to check the target is object coercible and raise an error if it's not. + + * dfg/DFGOperations.cpp: + * jit/JITOperations.cpp: + (JSC::getByVal): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getByVal): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::requireObjectCoercible): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncHasOwnProperty): + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + (JSC::objectProtoFuncPropertyIsEnumerable): + * tests/stress/exception-in-to-property-key-should-be-handled-early-in-object-methods.js: Added. + (shouldThrow): + (if): + * tests/stress/exception-in-to-property-key-should-be-handled-early.js: Added. + (shouldThrow): + (.): + +2015-03-26 Joseph Pecoraro <pecoraro@apple.com> + + WebContent Crash when instantiating class with Type Profiling enabled + https://bugs.webkit.org/show_bug.cgi?id=143037 + + Reviewed by Ryosuke Niwa. + + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitMoveEmptyValue): + We cannot profile the type of an uninitialized empty JSValue. + Nor do we expect this to be necessary, since it is effectively + an unseen undefined value. So add a way to put the empty value + without profiling. + + (JSC::BytecodeGenerator::emitMove): + Add an assert to try to catch this issue early on, and force + callers to explicitly use emitMoveEmptyValue instead. + + * tests/typeProfiler/classes.js: Added. + (wrapper.Base): + (wrapper.Derived): + (wrapper): + Add test coverage both for this case and classes in general. + +2015-03-26 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ES6: Provide a better view for Classes in the console + https://bugs.webkit.org/show_bug.cgi?id=142999 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Runtime.json: + Provide a new `subtype` enum "class". This is a subtype of `type` + "function", all other subtypes are subtypes of `object` types. + For a class, the frontend will immediately want to get the prototype + to enumerate its methods, so include the `classPrototype`. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + Denote class construction functions as "class" subtypes. + + * inspector/InjectedScriptSource.js: + Handling for the new "class" type. + + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::isClassConstructorFunction): + * runtime/Executable.h: + (JSC::FunctionExecutable::isClassConstructorFunction): + * runtime/JSFunction.h: + * runtime/JSFunctionInlines.h: + (JSC::JSFunction::isClassConstructorFunction): + Check if this function is a class constructor function. That information + is on the UnlinkedFunctionExecutable, so plumb it through to JSFunction. + +2015-03-26 Geoffrey Garen <ggaren@apple.com> + + Function.prototype.toString should not decompile the AST + https://bugs.webkit.org/show_bug.cgi?id=142853 + + Reviewed by Darin Adler. + + Following up on Darin's review comments. + + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + +2015-03-26 Geoffrey Garen <ggaren@apple.com> + + "lineNo" does not match WebKit coding style guidelines + https://bugs.webkit.org/show_bug.cgi?id=143119 + + Reviewed by Michael Saboff. + + We can afford to use whole words. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::lineNumberForBytecodeOffset): + (JSC::CodeBlock::expressionRangeForBytecodeOffset): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::link): + (JSC::UnlinkedFunctionExecutable::fromGlobalCode): + * bytecode/UnlinkedCodeBlock.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::WhileNode::emitBytecode): + * debugger/Debugger.cpp: + (JSC::Debugger::toggleBreakpoint): + * interpreter/Interpreter.cpp: + (JSC::StackFrame::computeLineAndColumn): + (JSC::GetStackTraceFunctor::operator()): + (JSC::Interpreter::execute): + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::computeLineAndColumn): + * parser/Nodes.h: + (JSC::Node::firstLine): + (JSC::Node::lineNo): Deleted. + (JSC::StatementNode::firstLine): Deleted. + * parser/ParserError.h: + (JSC::ParserError::toErrorObject): + * profiler/LegacyProfiler.cpp: + (JSC::createCallIdentifierFromFunctionImp): + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + * runtime/Executable.cpp: + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::ScriptExecutable::newCodeBlockFor): + (JSC::FunctionExecutable::fromGlobalCode): + * runtime/Executable.h: + (JSC::ScriptExecutable::firstLine): + (JSC::ScriptExecutable::setOverrideLineNumber): + (JSC::ScriptExecutable::hasOverrideLineNumber): + (JSC::ScriptExecutable::overrideLineNumber): + (JSC::ScriptExecutable::lineNo): Deleted. + (JSC::ScriptExecutable::setOverrideLineNo): Deleted. + (JSC::ScriptExecutable::hasOverrideLineNo): Deleted. + (JSC::ScriptExecutable::overrideLineNo): Deleted. + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + * runtime/FunctionConstructor.h: + * tools/CodeProfile.cpp: + (JSC::CodeProfile::report): + * tools/CodeProfile.h: + (JSC::CodeProfile::CodeProfile): + +2015-03-26 Geoffrey Garen <ggaren@apple.com> + + Assertion firing in JavaScriptCore/parser/parser.h for statesman.com site + https://bugs.webkit.org/show_bug.cgi?id=142974 + + Reviewed by Joseph Pecoraro. + + This patch does two things: + + (1) Restore JavaScriptCore's sanitization of line and column numbers to + one-based values. + + We need this because WebCore sometimes provides huge negative column + numbers. + + (2) Solve the attribute event listener line numbering problem a different + way: Rather than offseting all line numbers by -1 in an attribute event + listener in order to arrange for a custom result, instead use an explicit + feature for saying "all errors in this code should map to this line number". + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::link): + (JSC::UnlinkedFunctionExecutable::fromGlobalCode): + * bytecode/UnlinkedCodeBlock.h: + * interpreter/Interpreter.cpp: + (JSC::StackFrame::computeLineAndColumn): + (JSC::GetStackTraceFunctor::operator()): + * interpreter/Interpreter.h: + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::computeLineAndColumn): + * parser/ParserError.h: + (JSC::ParserError::toErrorObject): Plumb through an override line number. + When a function has an override line number, all syntax and runtime + errors in the function will map to it. This is useful for attribute event + listeners. + + * parser/SourceCode.h: + (JSC::SourceCode::SourceCode): Restore the old sanitization of line and + column numbers to one-based integers. It was kind of a hack to remove this. + + * runtime/Executable.cpp: + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::FunctionExecutable::fromGlobalCode): + * runtime/Executable.h: + (JSC::ScriptExecutable::setOverrideLineNo): + (JSC::ScriptExecutable::hasOverrideLineNo): + (JSC::ScriptExecutable::overrideLineNo): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + * runtime/FunctionConstructor.h: Plumb through an override line number. + +2015-03-26 Filip Pizlo <fpizlo@apple.com> + + If we're in code for accessing scoped arguments, we should probably check if the object is a scoped arguments rather than checking if it's a direct arguments. + + Reviewed by Michael Saboff. + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitScopedArgumentsGetByVal): + * tests/stress/scoped-then-direct-arguments-get-by-val-in-baseline.js: Added. + +2015-03-26 Filip Pizlo <fpizlo@apple.com> + + FTL ScopedArguments GetArrayLength generates incorrect code and crashes in LLVM + https://bugs.webkit.org/show_bug.cgi?id=143098 + + Reviewed by Csaba Osztrogonác. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength): Fix a typo. + * tests/stress/scoped-arguments-array-length.js: Added. This test previously always crashed in ftl-no-cjit mode. + +2015-03-26 Csaba Osztrogonác <ossy@webkit.org> + + Unreviewed gardening, skip failing tests on AArch64 Linux. + + * tests/mozilla/mozilla-tests.yaml: + * tests/stress/cached-prototype-setter.js: + +2015-03-26 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fixes to silly things. While landing fixes to r181993, I introduced crashes. This fixes them. + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): I landed a fix for a VS warning. It broke this. Now I'm fixing it. + * ftl/FTLCompile.cpp: + (JSC::FTL::compile): Make sure we pass the module when dumping. This makes FTL debugging possible again. + * ftl/FTLState.cpp: + (JSC::FTL::State::dumpState): New overload that takes a module, so that we can call this after FTL::compile() clears State's module. + * ftl/FTLState.h: + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix obvious goof that was causing 32-bit debug crashes. The 64-bit version did it + right, so this just makes 32-bit do the same. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Fix a typo that ggaren found but that I didn't fix before. + + * runtime/DirectArgumentsOffset.h: + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, VC found a bug. This fixes the bug. + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, try to fix Windows build. + + * runtime/ClonedArguments.cpp: + (JSC::ClonedArguments::createWithInlineFrame): + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix debug build. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ConstDeclNode::emitCodeSingle): + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix CLOOP build. + + * dfg/DFGMinifiedID.h: + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Heap variables shouldn't end up in the stack frame + https://bugs.webkit.org/show_bug.cgi?id=141174 + + Reviewed by Geoffrey Garen. + + This is a major change to how JavaScriptCore handles declared variables (i.e. "var"). It removes + any ambiguity about whether a variable should be in the heap or on the stack. A variable will no + longer move between heap and stack during its lifetime. This enables a bunch of optimizations and + simplifications: + + - Accesses to variables no longer need checks or indirections to determine where the variable is + at that moment in time. For example, loading a closure variable now takes just one load instead + of two. Loading an argument by index now takes a bounds check and a load in the fastest case + (when no arguments object allocation is required) while previously that same operation required + a "did I allocate arguments yet" check, a bounds check, and then the load. + + - Reasoning about the allocation of an activation or arguments object now follows the same simple + logic as the allocation of any other kind of object. Previously, those objects were lazily + allocated - so an allocation instruction wasn't the actual allocation site, since it might not + allocate anything at all. This made the implementation of traditional escape analyses really + awkward, and ultimately it meant that we missed important cases. Now, we can reason about the + arguments object using the usual SSA tricks which allows for more comprehensive removal. + + - The allocations of arguments objects, functions, and activations are now much faster. While + this patch generally expands our ability to eliminate arguments object allocations, an earlier + version of the patch - which lacked that functionality - was a progression on some arguments- + and closure-happy benchmarks because although no allocations were eliminated, all allocations + were faster. + + - There is no tear-off. The runtime no loner needs to know about where on the stack a frame keeps + its arguments objects or activations. The runtime doesn't have to do things to the arguments + objects and activations that a frame allocated, when the frame is unwound. We always had horrid + bugs in that code, so it's good to see it go. This removes *a ton* of machinery from the DFG, + FTL, CodeBlock, and other places. All of the things having to do with "captured variables" is + now gone. This also enables implementing block-scoping. Without this change, block-scope + support would require telling CodeBlock and all of the rest of the runtime about all of the + variables that store currently-live scopes. That would have been so disastrously hard that it + might as well be impossible. With this change, it's fair game for the bytecode generator to + simply allocate whatever activations it wants, wherever it wants, and to keep them live for + however long it wants. This all works, because after bytecode generation, an activation is just + an object and variables that refer to it are just normal variables. + + - SymbolTable can now tell you explicitly where a variable lives. The answer is in the form of a + VarOffset object, which has methods like isStack(), isScope(), etc. VirtualRegister is never + used for offsets of non-stack variables anymore. We now have shiny new objects for other kinds + of offsets - ScopeOffset for offsets into scopes, and DirectArgumentsOffset for offsets into + an arguments object. + + - Functions that create activations can now tier-up into the FTL. Previously they couldn't. Also, + using activations used to prevent inlining; now functions that use activations can be inlined + just fine. + + This is a >1% speed-up on Octane. This is a >2% speed-up on CompressionBench. This is a tiny + speed-up on AsmBench (~0.4% or something). This looks like it might be a speed-up on SunSpider. + It's only a slow-down on very short-running microbenchmarks we had previously written for our old + style of tear-off-based arguments optimization. Those benchmarks are not part of any major suite. + + The easiest way of understanding this change is to start by looking at the changes in runtime/, + and then the changes in bytecompiler/, and then sort of work your way up the compiler tiers. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/AbortReason.h: + * assembler/AbstractMacroAssembler.h: + (JSC::AbstractMacroAssembler::BaseIndex::withOffset): + * bytecode/ByValInfo.h: + (JSC::hasOptimizableIndexingForJSType): + (JSC::hasOptimizableIndexing): + (JSC::jitArrayModeForJSType): + (JSC::jitArrayModePermitsPut): + (JSC::jitArrayModeForStructure): + * bytecode/BytecodeKills.h: Added. + (JSC::BytecodeKills::BytecodeKills): + (JSC::BytecodeKills::operandIsKilled): + (JSC::BytecodeKills::forEachOperandKilledAt): + (JSC::BytecodeKills::KillSet::KillSet): + (JSC::BytecodeKills::KillSet::add): + (JSC::BytecodeKills::KillSet::forEachLocal): + (JSC::BytecodeKills::KillSet::contains): + * bytecode/BytecodeList.json: + * bytecode/BytecodeLivenessAnalysis.cpp: + (JSC::isValidRegisterForLiveness): + (JSC::stepOverInstruction): + (JSC::BytecodeLivenessAnalysis::runLivenessFixpoint): + (JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset): + (JSC::BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset): + (JSC::BytecodeLivenessAnalysis::computeFullLiveness): + (JSC::BytecodeLivenessAnalysis::computeKills): + (JSC::indexForOperand): Deleted. + (JSC::BytecodeLivenessAnalysis::getLivenessInfoForNonCapturedVarsAtBytecodeOffset): Deleted. + (JSC::getLivenessInfo): Deleted. + * bytecode/BytecodeLivenessAnalysis.h: + * bytecode/BytecodeLivenessAnalysisInlines.h: + (JSC::operandIsAlwaysLive): + (JSC::operandThatIsNotAlwaysLiveIsLive): + (JSC::operandIsLive): + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::nameForRegister): + (JSC::CodeBlock::validate): + (JSC::CodeBlock::isCaptured): Deleted. + (JSC::CodeBlock::framePointerOffsetToGetActivationRegisters): Deleted. + (JSC::CodeBlock::machineSlowArguments): Deleted. + * bytecode/CodeBlock.h: + (JSC::unmodifiedArgumentsRegister): Deleted. + (JSC::CodeBlock::setArgumentsRegister): Deleted. + (JSC::CodeBlock::argumentsRegister): Deleted. + (JSC::CodeBlock::uncheckedArgumentsRegister): Deleted. + (JSC::CodeBlock::usesArguments): Deleted. + (JSC::CodeBlock::captureCount): Deleted. + (JSC::CodeBlock::captureStart): Deleted. + (JSC::CodeBlock::captureEnd): Deleted. + (JSC::CodeBlock::argumentIndexAfterCapture): Deleted. + (JSC::CodeBlock::hasSlowArguments): Deleted. + (JSC::ExecState::argumentAfterCapture): Deleted. + * bytecode/CodeOrigin.h: + * bytecode/DataFormat.h: + (JSC::dataFormatToString): + * bytecode/FullBytecodeLiveness.h: + (JSC::FullBytecodeLiveness::getLiveness): + (JSC::FullBytecodeLiveness::operandIsLive): + (JSC::FullBytecodeLiveness::FullBytecodeLiveness): Deleted. + (JSC::FullBytecodeLiveness::getOut): Deleted. + * bytecode/Instruction.h: + (JSC::Instruction::Instruction): + * bytecode/Operands.h: + (JSC::Operands::virtualRegisterForIndex): + * bytecode/SpeculatedType.cpp: + (JSC::dumpSpeculation): + (JSC::speculationToAbbreviatedString): + (JSC::speculationFromClassInfo): + * bytecode/SpeculatedType.h: + (JSC::isDirectArgumentsSpeculation): + (JSC::isScopedArgumentsSpeculation): + (JSC::isActionableMutableArraySpeculation): + (JSC::isActionableArraySpeculation): + (JSC::isArgumentsSpeculation): Deleted. + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::setArgumentsRegister): Deleted. + (JSC::UnlinkedCodeBlock::usesArguments): Deleted. + (JSC::UnlinkedCodeBlock::argumentsRegister): Deleted. + * bytecode/ValueRecovery.cpp: + (JSC::ValueRecovery::dumpInContext): + * bytecode/ValueRecovery.h: + (JSC::ValueRecovery::directArgumentsThatWereNotCreated): + (JSC::ValueRecovery::outOfBandArgumentsThatWereNotCreated): + (JSC::ValueRecovery::nodeID): + (JSC::ValueRecovery::argumentsThatWereNotCreated): Deleted. + * bytecode/VirtualRegister.h: + (JSC::VirtualRegister::operator==): + (JSC::VirtualRegister::operator!=): + (JSC::VirtualRegister::operator<): + (JSC::VirtualRegister::operator>): + (JSC::VirtualRegister::operator<=): + (JSC::VirtualRegister::operator>=): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::initializeNextParameter): + (JSC::BytecodeGenerator::visibleNameForParameter): + (JSC::BytecodeGenerator::emitMove): + (JSC::BytecodeGenerator::variable): + (JSC::BytecodeGenerator::createVariable): + (JSC::BytecodeGenerator::emitResolveScope): + (JSC::BytecodeGenerator::emitGetFromScope): + (JSC::BytecodeGenerator::emitPutToScope): + (JSC::BytecodeGenerator::initializeVariable): + (JSC::BytecodeGenerator::emitInstanceOf): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionInternal): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitReturn): + (JSC::BytecodeGenerator::emitConstruct): + (JSC::BytecodeGenerator::isArgumentNumber): + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::addVar): Deleted. + (JSC::BytecodeGenerator::emitInitLazyRegister): Deleted. + (JSC::BytecodeGenerator::initializeCapturedVariable): Deleted. + (JSC::BytecodeGenerator::resolveCallee): Deleted. + (JSC::BytecodeGenerator::addCallee): Deleted. + (JSC::BytecodeGenerator::addParameter): Deleted. + (JSC::BytecodeGenerator::willResolveToArgumentsRegister): Deleted. + (JSC::BytecodeGenerator::uncheckedLocalArgumentsRegister): Deleted. + (JSC::BytecodeGenerator::createLazyRegisterIfNecessary): Deleted. + (JSC::BytecodeGenerator::isCaptured): Deleted. + (JSC::BytecodeGenerator::local): Deleted. + (JSC::BytecodeGenerator::constLocal): Deleted. + (JSC::BytecodeGenerator::emitResolveConstantLocal): Deleted. + (JSC::BytecodeGenerator::emitGetArgumentsLength): Deleted. + (JSC::BytecodeGenerator::emitGetArgumentByVal): Deleted. + (JSC::BytecodeGenerator::emitLazyNewFunction): Deleted. + (JSC::BytecodeGenerator::createArgumentsIfNecessary): Deleted. + * bytecompiler/BytecodeGenerator.h: + (JSC::Variable::Variable): + (JSC::Variable::isResolved): + (JSC::Variable::ident): + (JSC::Variable::offset): + (JSC::Variable::isLocal): + (JSC::Variable::local): + (JSC::Variable::isSpecial): + (JSC::BytecodeGenerator::argumentsRegister): + (JSC::BytecodeGenerator::emitNode): + (JSC::BytecodeGenerator::registerFor): + (JSC::Local::Local): Deleted. + (JSC::Local::operator bool): Deleted. + (JSC::Local::get): Deleted. + (JSC::Local::isSpecial): Deleted. + (JSC::ResolveScopeInfo::ResolveScopeInfo): Deleted. + (JSC::ResolveScopeInfo::isLocal): Deleted. + (JSC::ResolveScopeInfo::localIndex): Deleted. + (JSC::BytecodeGenerator::hasSafeLocalArgumentsRegister): Deleted. + (JSC::BytecodeGenerator::captureMode): Deleted. + (JSC::BytecodeGenerator::shouldTearOffArgumentsEagerly): Deleted. + (JSC::BytecodeGenerator::shouldCreateArgumentsEagerly): Deleted. + (JSC::BytecodeGenerator::hasWatchableVariable): Deleted. + (JSC::BytecodeGenerator::watchableVariableIdentifier): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ResolveNode::isPure): + (JSC::ResolveNode::emitBytecode): + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::EvalFunctionCallNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::DeleteResolveNode::emitBytecode): + (JSC::TypeOfResolveNode::emitBytecode): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::EmptyVarExpression::emitBytecode): + (JSC::ForInNode::tryGetBoundLocal): + (JSC::ForInNode::emitLoopHeader): + (JSC::ForOfNode::emitBytecode): + (JSC::ArrayPatternNode::emitDirectBinding): + (JSC::BindingNode::bindValue): + (JSC::getArgumentByVal): Deleted. + * dfg/DFGAbstractHeap.h: + * dfg/DFGAbstractInterpreter.h: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberWorld): + (JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberCapturedVars): Deleted. + * dfg/DFGAbstractValue.h: + * dfg/DFGArgumentPosition.h: + (JSC::DFG::ArgumentPosition::addVariable): + * dfg/DFGArgumentsEliminationPhase.cpp: Added. + (JSC::DFG::performArgumentsElimination): + * dfg/DFGArgumentsEliminationPhase.h: Added. + * dfg/DFGArgumentsSimplificationPhase.cpp: Removed. + * dfg/DFGArgumentsSimplificationPhase.h: Removed. + * dfg/DFGArgumentsUtilities.cpp: Added. + (JSC::DFG::argumentsInvolveStackSlot): + (JSC::DFG::emitCodeToGetArgumentsArrayLength): + * dfg/DFGArgumentsUtilities.h: Added. + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::refine): + (JSC::DFG::ArrayMode::alreadyChecked): + (JSC::DFG::arrayTypeToString): + * dfg/DFGArrayMode.h: + (JSC::DFG::ArrayMode::canCSEStorage): + (JSC::DFG::ArrayMode::modeForPut): + * dfg/DFGAvailabilityMap.cpp: + (JSC::DFG::AvailabilityMap::prune): + * dfg/DFGAvailabilityMap.h: + (JSC::DFG::AvailabilityMap::closeOverNodes): + (JSC::DFG::AvailabilityMap::closeStartingWithLocal): + * dfg/DFGBackwardsPropagationPhase.cpp: + (JSC::DFG::BackwardsPropagationPhase::propagate): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::newVariableAccessData): + (JSC::DFG::ByteCodeParser::getLocal): + (JSC::DFG::ByteCodeParser::setLocal): + (JSC::DFG::ByteCodeParser::getArgument): + (JSC::DFG::ByteCodeParser::setArgument): + (JSC::DFG::ByteCodeParser::flushDirect): + (JSC::DFG::ByteCodeParser::flush): + (JSC::DFG::ByteCodeParser::noticeArgumentsUse): + (JSC::DFG::ByteCodeParser::handleVarargsCall): + (JSC::DFG::ByteCodeParser::attemptToInlineCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + (JSC::DFG::ByteCodeParser::parseCodeBlock): + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::canonicalizeGetLocalFor): + (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock): + * dfg/DFGCSEPhase.cpp: + * dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h: Added. + (JSC::DFG::CallCreateDirectArgumentsSlowPathGenerator::CallCreateDirectArgumentsSlowPathGenerator): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::isSupportedForInlining): + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.h: + * dfg/DFGCommonData.h: + (JSC::DFG::CommonData::CommonData): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::cleanVariables): + * dfg/DFGDisassembler.h: + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGFlushFormat.cpp: + (WTF::printInternal): + * dfg/DFGFlushFormat.h: + (JSC::DFG::resultFor): + (JSC::DFG::useKindFor): + (JSC::DFG::dataFormatFor): + * dfg/DFGForAllKills.h: Added. + (JSC::DFG::forAllLiveNodesAtTail): + (JSC::DFG::forAllDirectlyKilledOperands): + (JSC::DFG::forAllKilledOperands): + (JSC::DFG::forAllKilledNodesAtNodeIndex): + (JSC::DFG::forAllKillsInBlock): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::Graph): + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::substituteGetLocal): + (JSC::DFG::Graph::livenessFor): + (JSC::DFG::Graph::killsFor): + (JSC::DFG::Graph::tryGetConstantClosureVar): + (JSC::DFG::Graph::tryGetRegisters): Deleted. + * dfg/DFGGraph.h: + (JSC::DFG::Graph::symbolTableFor): + (JSC::DFG::Graph::uses): + (JSC::DFG::Graph::bytecodeRegisterForArgument): Deleted. + (JSC::DFG::Graph::capturedVarsFor): Deleted. + (JSC::DFG::Graph::usesArguments): Deleted. + (JSC::DFG::Graph::argumentsRegisterFor): Deleted. + (JSC::DFG::Graph::machineArgumentsRegisterFor): Deleted. + (JSC::DFG::Graph::uncheckedArgumentsRegisterFor): Deleted. + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + (JSC::DFG::InPlaceAbstractState::mergeStateAtTail): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGMinifiedID.h: + * dfg/DFGMinifiedNode.cpp: + (JSC::DFG::MinifiedNode::fromNode): + * dfg/DFGMinifiedNode.h: + (JSC::DFG::belongsInMinifiedGraph): + (JSC::DFG::MinifiedNode::hasInlineCallFrame): + (JSC::DFG::MinifiedNode::inlineCallFrame): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::convertToIdentityOn): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasConstant): + (JSC::DFG::Node::constant): + (JSC::DFG::Node::hasScopeOffset): + (JSC::DFG::Node::scopeOffset): + (JSC::DFG::Node::hasDirectArgumentsOffset): + (JSC::DFG::Node::capturedArgumentsOffset): + (JSC::DFG::Node::variablePointer): + (JSC::DFG::Node::hasCallVarargsData): + (JSC::DFG::Node::hasLoadVarargsData): + (JSC::DFG::Node::hasHeapPrediction): + (JSC::DFG::Node::hasCellOperand): + (JSC::DFG::Node::objectMaterializationData): + (JSC::DFG::Node::isPhantomAllocation): + (JSC::DFG::Node::willHaveCodeGenOrOSR): + (JSC::DFG::Node::shouldSpeculateDirectArguments): + (JSC::DFG::Node::shouldSpeculateScopedArguments): + (JSC::DFG::Node::isPhantomArguments): Deleted. + (JSC::DFG::Node::hasVarNumber): Deleted. + (JSC::DFG::Node::varNumber): Deleted. + (JSC::DFG::Node::registerPointer): Deleted. + (JSC::DFG::Node::shouldSpeculateArguments): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::OSRAvailabilityAnalysisPhase::run): + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGOSRExitCompiler.cpp: + (JSC::DFG::OSRExitCompiler::emitRestoreArguments): + * dfg/DFGOSRExitCompiler.h: + (JSC::DFG::OSRExitCompiler::badIndex): Deleted. + (JSC::DFG::OSRExitCompiler::initializePoisoned): Deleted. + (JSC::DFG::OSRExitCompiler::poisonIndex): Deleted. + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + (JSC::DFG::ArgumentsRecoveryGenerator::ArgumentsRecoveryGenerator): Deleted. + (JSC::DFG::ArgumentsRecoveryGenerator::~ArgumentsRecoveryGenerator): Deleted. + (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): Deleted. + * dfg/DFGOSRExitCompilerCommon.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPreciseLocalClobberize.h: + (JSC::DFG::PreciseLocalClobberizeAdaptor::read): + (JSC::DFG::PreciseLocalClobberizeAdaptor::write): + (JSC::DFG::PreciseLocalClobberizeAdaptor::def): + (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): + (JSC::DFG::preciseLocalClobberize): + (JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop): Deleted. + (JSC::DFG::forEachLocalReadByUnwind): Deleted. + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::run): + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting): + (JSC::DFG::PredictionPropagationPhase::propagateThroughArgumentPositions): + * dfg/DFGPromoteHeapAccess.h: + (JSC::DFG::promoteHeapAccess): + * dfg/DFGPromotedHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGPromotedHeapLocation.h: + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateJSArray): + (JSC::DFG::SpeculativeJIT::emitGetLength): + (JSC::DFG::SpeculativeJIT::emitGetCallee): + (JSC::DFG::SpeculativeJIT::emitGetArgumentStart): + (JSC::DFG::SpeculativeJIT::checkArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments): + (JSC::DFG::SpeculativeJIT::compileGetByValOnScopedArguments): + (JSC::DFG::SpeculativeJIT::compileGetArrayLength): + (JSC::DFG::SpeculativeJIT::compileNewFunction): + (JSC::DFG::SpeculativeJIT::compileForwardVarargs): + (JSC::DFG::SpeculativeJIT::compileCreateActivation): + (JSC::DFG::SpeculativeJIT::compileCreateDirectArguments): + (JSC::DFG::SpeculativeJIT::compileGetFromArguments): + (JSC::DFG::SpeculativeJIT::compilePutToArguments): + (JSC::DFG::SpeculativeJIT::compileCreateScopedArguments): + (JSC::DFG::SpeculativeJIT::compileCreateClonedArguments): + (JSC::DFG::SpeculativeJIT::emitAllocateArguments): Deleted. + (JSC::DFG::SpeculativeJIT::compileGetByValOnArguments): Deleted. + (JSC::DFG::SpeculativeJIT::compileGetArgumentsLength): Deleted. + (JSC::DFG::SpeculativeJIT::compileNewFunctionNoCheck): Deleted. + (JSC::DFG::SpeculativeJIT::compileNewFunctionExpression): Deleted. + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + (JSC::DFG::SpeculativeJIT::emitAllocateJSObjectWithKnownSize): + (JSC::DFG::SpeculativeJIT::emitAllocateJSObject): + (JSC::DFG::SpeculativeJIT::framePointerOffsetToGetActivationRegisters): Deleted. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGStructureRegistrationPhase.cpp: + (JSC::DFG::StructureRegistrationPhase::run): + * dfg/DFGUnificationPhase.cpp: + (JSC::DFG::UnificationPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): + * dfg/DFGValueSource.cpp: + (JSC::DFG::ValueSource::dump): + * dfg/DFGValueSource.h: + (JSC::DFG::dataFormatToValueSourceKind): + (JSC::DFG::valueSourceKindToDataFormat): + (JSC::DFG::ValueSource::ValueSource): + (JSC::DFG::ValueSource::forFlushFormat): + (JSC::DFG::ValueSource::valueRecovery): + * dfg/DFGVarargsForwardingPhase.cpp: Added. + (JSC::DFG::performVarargsForwarding): + * dfg/DFGVarargsForwardingPhase.h: Added. + * dfg/DFGVariableAccessData.cpp: + (JSC::DFG::VariableAccessData::VariableAccessData): + (JSC::DFG::VariableAccessData::flushFormat): + (JSC::DFG::VariableAccessData::mergeIsCaptured): Deleted. + * dfg/DFGVariableAccessData.h: + (JSC::DFG::VariableAccessData::shouldNeverUnbox): + (JSC::DFG::VariableAccessData::shouldUseDoubleFormat): + (JSC::DFG::VariableAccessData::isCaptured): Deleted. + (JSC::DFG::VariableAccessData::mergeIsArgumentsAlias): Deleted. + (JSC::DFG::VariableAccessData::isArgumentsAlias): Deleted. + * dfg/DFGVariableAccessDataDump.cpp: + (JSC::DFG::VariableAccessDataDump::dump): + * dfg/DFGVariableAccessDataDump.h: + * dfg/DFGVariableEventStream.cpp: + (JSC::DFG::VariableEventStream::tryToSetConstantRecovery): + * dfg/DFGVariableEventStream.h: + * ftl/FTLAbstractHeap.cpp: + (JSC::FTL::AbstractHeap::dump): + (JSC::FTL::AbstractField::dump): + (JSC::FTL::IndexedAbstractHeap::dump): + (JSC::FTL::NumberedAbstractHeap::dump): + (JSC::FTL::AbsoluteAbstractHeap::dump): + * ftl/FTLAbstractHeap.h: + * ftl/FTLAbstractHeapRepository.cpp: + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLExitArgument.cpp: + (JSC::FTL::ExitArgument::dump): + * ftl/FTLExitPropertyValue.cpp: + (JSC::FTL::ExitPropertyValue::withLocalsOffset): + * ftl/FTLExitPropertyValue.h: + * ftl/FTLExitTimeObjectMaterialization.cpp: + (JSC::FTL::ExitTimeObjectMaterialization::ExitTimeObjectMaterialization): + (JSC::FTL::ExitTimeObjectMaterialization::accountForLocalsOffset): + * ftl/FTLExitTimeObjectMaterialization.h: + (JSC::FTL::ExitTimeObjectMaterialization::origin): + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::withLocalsOffset): + (JSC::FTL::ExitValue::valueFormat): + (JSC::FTL::ExitValue::dumpInContext): + * ftl/FTLExitValue.h: + (JSC::FTL::ExitValue::isArgument): + (JSC::FTL::ExitValue::argumentsObjectThatWasNotCreated): Deleted. + (JSC::FTL::ExitValue::isArgumentsObjectThatWasNotCreated): Deleted. + (JSC::FTL::ExitValue::valueFormat): Deleted. + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCallForwardVarargs): + (JSC::FTL::sizeOfConstructForwardVarargs): + (JSC::FTL::sizeOfICFor): + * ftl/FTLInlineCacheSize.h: + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLJSCallVarargs.cpp: + (JSC::FTL::JSCallVarargs::JSCallVarargs): + (JSC::FTL::JSCallVarargs::emit): + * ftl/FTLJSCallVarargs.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compilePutStack): + (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileArrayPush): + (JSC::FTL::LowerDFGToLLVM::compileArrayPop): + (JSC::FTL::LowerDFGToLLVM::compileCreateActivation): + (JSC::FTL::LowerDFGToLLVM::compileNewFunction): + (JSC::FTL::LowerDFGToLLVM::compileCreateDirectArguments): + (JSC::FTL::LowerDFGToLLVM::compileCreateScopedArguments): + (JSC::FTL::LowerDFGToLLVM::compileCreateClonedArguments): + (JSC::FTL::LowerDFGToLLVM::compileStringCharAt): + (JSC::FTL::LowerDFGToLLVM::compileStringCharCodeAt): + (JSC::FTL::LowerDFGToLLVM::compileGetGlobalVar): + (JSC::FTL::LowerDFGToLLVM::compilePutGlobalVar): + (JSC::FTL::LowerDFGToLLVM::compileGetArgumentCount): + (JSC::FTL::LowerDFGToLLVM::compileGetClosureVar): + (JSC::FTL::LowerDFGToLLVM::compilePutClosureVar): + (JSC::FTL::LowerDFGToLLVM::compileGetFromArguments): + (JSC::FTL::LowerDFGToLLVM::compilePutToArguments): + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstructVarargs): + (JSC::FTL::LowerDFGToLLVM::compileForwardVarargs): + (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname): + (JSC::FTL::LowerDFGToLLVM::ArgumentsLength::ArgumentsLength): + (JSC::FTL::LowerDFGToLLVM::getArgumentsLength): + (JSC::FTL::LowerDFGToLLVM::getCurrentCallee): + (JSC::FTL::LowerDFGToLLVM::getArgumentsStart): + (JSC::FTL::LowerDFGToLLVM::baseIndex): + (JSC::FTL::LowerDFGToLLVM::allocateObject): + (JSC::FTL::LowerDFGToLLVM::allocateVariableSizedObject): + (JSC::FTL::LowerDFGToLLVM::isArrayType): + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability): + (JSC::FTL::LowerDFGToLLVM::exitValueForNode): + (JSC::FTL::LowerDFGToLLVM::loadStructure): + (JSC::FTL::LowerDFGToLLVM::compilePhantomArguments): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileGetClosureRegisters): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileCheckArgumentsNotCreated): Deleted. + (JSC::FTL::LowerDFGToLLVM::checkArgumentsNotCreated): Deleted. + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileRecovery): + (JSC::FTL::compileStub): + * ftl/FTLOperations.cpp: + (JSC::FTL::operationMaterializeObjectInOSR): + * ftl/FTLOutput.h: + (JSC::FTL::Output::aShr): + (JSC::FTL::Output::lShr): + (JSC::FTL::Output::zeroExtPtr): + * heap/CopyToken.h: + * interpreter/CallFrame.h: + (JSC::ExecState::getArgumentUnsafe): + * interpreter/Interpreter.cpp: + (JSC::sizeOfVarargs): + (JSC::sizeFrameForVarargs): + (JSC::loadVarargs): + (JSC::unwindCallFrame): + * interpreter/Interpreter.h: + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::createArguments): + (JSC::StackVisitor::Frame::existingArguments): Deleted. + * interpreter/StackVisitor.h: + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::storeValue): + (JSC::AssemblyHelpers::loadValue): + (JSC::AssemblyHelpers::storeTrustedValue): + (JSC::AssemblyHelpers::branchIfNotCell): + (JSC::AssemblyHelpers::branchIsEmpty): + (JSC::AssemblyHelpers::argumentsStart): + (JSC::AssemblyHelpers::baselineArgumentsRegisterFor): Deleted. + (JSC::AssemblyHelpers::offsetOfLocals): Deleted. + (JSC::AssemblyHelpers::offsetOfArguments): Deleted. + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgument): + * jit/GPRInfo.h: + (JSC::JSValueRegs::withTwoAvailableRegs): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_lexical_environment): + (JSC::JIT::emit_op_new_func): + (JSC::JIT::emit_op_create_direct_arguments): + (JSC::JIT::emit_op_create_scoped_arguments): + (JSC::JIT::emit_op_create_out_of_band_arguments): + (JSC::JIT::emit_op_tear_off_arguments): Deleted. + (JSC::JIT::emit_op_create_arguments): Deleted. + (JSC::JIT::emit_op_init_lazy_reg): Deleted. + (JSC::JIT::emit_op_get_arguments_length): Deleted. + (JSC::JIT::emitSlow_op_get_arguments_length): Deleted. + (JSC::JIT::emit_op_get_argument_by_val): Deleted. + (JSC::JIT::emitSlow_op_get_argument_by_val): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_lexical_environment): + (JSC::JIT::emit_op_tear_off_arguments): Deleted. + (JSC::JIT::emit_op_create_arguments): Deleted. + (JSC::JIT::emit_op_init_lazy_reg): Deleted. + (JSC::JIT::emit_op_get_arguments_length): Deleted. + (JSC::JIT::emitSlow_op_get_arguments_length): Deleted. + (JSC::JIT::emit_op_get_argument_by_val): Deleted. + (JSC::JIT::emitSlow_op_get_argument_by_val): Deleted. + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitGetClosureVar): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emit_op_get_from_arguments): + (JSC::JIT::emit_op_put_to_arguments): + (JSC::JIT::emit_op_init_global_const): + (JSC::JIT::privateCompileGetByVal): + (JSC::JIT::emitDirectArgumentsGetByVal): + (JSC::JIT::emitScopedArgumentsGetByVal): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitGetClosureVar): + (JSC::JIT::emitPutClosureVar): + (JSC::JIT::emit_op_get_from_arguments): + (JSC::JIT::emit_op_put_to_arguments): + (JSC::JIT::emit_op_init_global_const): + * jit/SetupVarargsFrame.cpp: + (JSC::emitSetupVarargsFrameFastCase): + * llint/LLIntOffsetsExtractor.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * parser/Nodes.h: + (JSC::ScopeNode::captures): + * runtime/Arguments.cpp: Removed. + * runtime/Arguments.h: Removed. + * runtime/ArgumentsMode.h: Added. + * runtime/DirectArgumentsOffset.cpp: Added. + (JSC::DirectArgumentsOffset::dump): + * runtime/DirectArgumentsOffset.h: Added. + (JSC::DirectArgumentsOffset::DirectArgumentsOffset): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/ConstantMode.cpp: Added. + (WTF::printInternal): + * runtime/ConstantMode.h: + (JSC::modeForIsConstant): + * runtime/DirectArguments.cpp: Added. + (JSC::DirectArguments::DirectArguments): + (JSC::DirectArguments::createUninitialized): + (JSC::DirectArguments::create): + (JSC::DirectArguments::createByCopying): + (JSC::DirectArguments::visitChildren): + (JSC::DirectArguments::copyBackingStore): + (JSC::DirectArguments::createStructure): + (JSC::DirectArguments::overrideThings): + (JSC::DirectArguments::overrideThingsIfNecessary): + (JSC::DirectArguments::overrideArgument): + (JSC::DirectArguments::copyToArguments): + (JSC::DirectArguments::overridesSize): + * runtime/DirectArguments.h: Added. + (JSC::DirectArguments::internalLength): + (JSC::DirectArguments::length): + (JSC::DirectArguments::canAccessIndexQuickly): + (JSC::DirectArguments::getIndexQuickly): + (JSC::DirectArguments::setIndexQuickly): + (JSC::DirectArguments::callee): + (JSC::DirectArguments::argument): + (JSC::DirectArguments::overrodeThings): + (JSC::DirectArguments::offsetOfCallee): + (JSC::DirectArguments::offsetOfLength): + (JSC::DirectArguments::offsetOfMinCapacity): + (JSC::DirectArguments::offsetOfOverrides): + (JSC::DirectArguments::storageOffset): + (JSC::DirectArguments::offsetOfSlot): + (JSC::DirectArguments::allocationSize): + (JSC::DirectArguments::storage): + * runtime/FunctionPrototype.cpp: + * runtime/GenericArguments.h: Added. + (JSC::GenericArguments::GenericArguments): + * runtime/GenericArgumentsInlines.h: Added. + (JSC::GenericArguments<Type>::getOwnPropertySlot): + (JSC::GenericArguments<Type>::getOwnPropertySlotByIndex): + (JSC::GenericArguments<Type>::getOwnPropertyNames): + (JSC::GenericArguments<Type>::put): + (JSC::GenericArguments<Type>::putByIndex): + (JSC::GenericArguments<Type>::deleteProperty): + (JSC::GenericArguments<Type>::deletePropertyByIndex): + (JSC::GenericArguments<Type>::defineOwnProperty): + (JSC::GenericArguments<Type>::copyToArguments): + * runtime/GenericOffset.h: Added. + (JSC::GenericOffset::GenericOffset): + (JSC::GenericOffset::operator!): + (JSC::GenericOffset::offsetUnchecked): + (JSC::GenericOffset::offset): + (JSC::GenericOffset::operator==): + (JSC::GenericOffset::operator!=): + (JSC::GenericOffset::operator<): + (JSC::GenericOffset::operator>): + (JSC::GenericOffset::operator<=): + (JSC::GenericOffset::operator>=): + (JSC::GenericOffset::operator+): + (JSC::GenericOffset::operator-): + (JSC::GenericOffset::operator+=): + (JSC::GenericOffset::operator-=): + * runtime/JSArgumentsIterator.cpp: + (JSC::JSArgumentsIterator::finishCreation): + (JSC::argumentsFuncIterator): + * runtime/JSArgumentsIterator.h: + (JSC::JSArgumentsIterator::create): + (JSC::JSArgumentsIterator::next): + * runtime/JSEnvironmentRecord.cpp: + (JSC::JSEnvironmentRecord::visitChildren): + * runtime/JSEnvironmentRecord.h: + (JSC::JSEnvironmentRecord::variables): + (JSC::JSEnvironmentRecord::isValid): + (JSC::JSEnvironmentRecord::variableAt): + (JSC::JSEnvironmentRecord::offsetOfVariables): + (JSC::JSEnvironmentRecord::offsetOfVariable): + (JSC::JSEnvironmentRecord::allocationSizeForScopeSize): + (JSC::JSEnvironmentRecord::allocationSize): + (JSC::JSEnvironmentRecord::JSEnvironmentRecord): + (JSC::JSEnvironmentRecord::finishCreationUninitialized): + (JSC::JSEnvironmentRecord::finishCreation): + (JSC::JSEnvironmentRecord::registers): Deleted. + (JSC::JSEnvironmentRecord::registerAt): Deleted. + (JSC::JSEnvironmentRecord::addressOfRegisters): Deleted. + (JSC::JSEnvironmentRecord::offsetOfRegisters): Deleted. + * runtime/JSFunction.cpp: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::addGlobalVar): + (JSC::JSGlobalObject::addFunction): + (JSC::JSGlobalObject::visitChildren): + (JSC::JSGlobalObject::addStaticGlobals): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::directArgumentsStructure): + (JSC::JSGlobalObject::scopedArgumentsStructure): + (JSC::JSGlobalObject::outOfBandArgumentsStructure): + (JSC::JSGlobalObject::argumentsStructure): Deleted. + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::symbolTableGet): + (JSC::JSLexicalEnvironment::symbolTablePut): + (JSC::JSLexicalEnvironment::getOwnNonIndexPropertyNames): + (JSC::JSLexicalEnvironment::symbolTablePutWithAttributes): + (JSC::JSLexicalEnvironment::visitChildren): Deleted. + * runtime/JSLexicalEnvironment.h: + (JSC::JSLexicalEnvironment::create): + (JSC::JSLexicalEnvironment::JSLexicalEnvironment): + (JSC::JSLexicalEnvironment::registersOffset): Deleted. + (JSC::JSLexicalEnvironment::storageOffset): Deleted. + (JSC::JSLexicalEnvironment::storage): Deleted. + (JSC::JSLexicalEnvironment::allocationSize): Deleted. + (JSC::JSLexicalEnvironment::isValidIndex): Deleted. + (JSC::JSLexicalEnvironment::isValid): Deleted. + (JSC::JSLexicalEnvironment::registerAt): Deleted. + * runtime/JSNameScope.cpp: + (JSC::JSNameScope::visitChildren): Deleted. + * runtime/JSNameScope.h: + (JSC::JSNameScope::create): + (JSC::JSNameScope::value): + (JSC::JSNameScope::finishCreation): + (JSC::JSNameScope::JSNameScope): + * runtime/JSScope.cpp: + (JSC::abstractAccess): + * runtime/JSSegmentedVariableObject.cpp: + (JSC::JSSegmentedVariableObject::findVariableIndex): + (JSC::JSSegmentedVariableObject::addVariables): + (JSC::JSSegmentedVariableObject::visitChildren): + (JSC::JSSegmentedVariableObject::findRegisterIndex): Deleted. + (JSC::JSSegmentedVariableObject::addRegisters): Deleted. + * runtime/JSSegmentedVariableObject.h: + (JSC::JSSegmentedVariableObject::variableAt): + (JSC::JSSegmentedVariableObject::assertVariableIsInThisObject): + (JSC::JSSegmentedVariableObject::registerAt): Deleted. + (JSC::JSSegmentedVariableObject::assertRegisterIsInThisObject): Deleted. + * runtime/JSSymbolTableObject.h: + (JSC::JSSymbolTableObject::offsetOfSymbolTable): + (JSC::symbolTableGet): + (JSC::symbolTablePut): + (JSC::symbolTablePutWithAttributes): + * runtime/JSType.h: + * runtime/Options.h: + * runtime/ClonedArguments.cpp: Added. + (JSC::ClonedArguments::ClonedArguments): + (JSC::ClonedArguments::createEmpty): + (JSC::ClonedArguments::createWithInlineFrame): + (JSC::ClonedArguments::createWithMachineFrame): + (JSC::ClonedArguments::createByCopyingFrom): + (JSC::ClonedArguments::createStructure): + (JSC::ClonedArguments::getOwnPropertySlot): + (JSC::ClonedArguments::getOwnPropertyNames): + (JSC::ClonedArguments::put): + (JSC::ClonedArguments::deleteProperty): + (JSC::ClonedArguments::defineOwnProperty): + (JSC::ClonedArguments::materializeSpecials): + (JSC::ClonedArguments::materializeSpecialsIfNecessary): + * runtime/ClonedArguments.h: Added. + (JSC::ClonedArguments::specialsMaterialized): + * runtime/ScopeOffset.cpp: Added. + (JSC::ScopeOffset::dump): + * runtime/ScopeOffset.h: Added. + (JSC::ScopeOffset::ScopeOffset): + * runtime/ScopedArguments.cpp: Added. + (JSC::ScopedArguments::ScopedArguments): + (JSC::ScopedArguments::finishCreation): + (JSC::ScopedArguments::createUninitialized): + (JSC::ScopedArguments::create): + (JSC::ScopedArguments::createByCopying): + (JSC::ScopedArguments::createByCopyingFrom): + (JSC::ScopedArguments::visitChildren): + (JSC::ScopedArguments::createStructure): + (JSC::ScopedArguments::overrideThings): + (JSC::ScopedArguments::overrideThingsIfNecessary): + (JSC::ScopedArguments::overrideArgument): + (JSC::ScopedArguments::copyToArguments): + * runtime/ScopedArguments.h: Added. + (JSC::ScopedArguments::internalLength): + (JSC::ScopedArguments::length): + (JSC::ScopedArguments::canAccessIndexQuickly): + (JSC::ScopedArguments::getIndexQuickly): + (JSC::ScopedArguments::setIndexQuickly): + (JSC::ScopedArguments::callee): + (JSC::ScopedArguments::overrodeThings): + (JSC::ScopedArguments::offsetOfOverrodeThings): + (JSC::ScopedArguments::offsetOfTotalLength): + (JSC::ScopedArguments::offsetOfTable): + (JSC::ScopedArguments::offsetOfScope): + (JSC::ScopedArguments::overflowStorageOffset): + (JSC::ScopedArguments::allocationSize): + (JSC::ScopedArguments::overflowStorage): + * runtime/ScopedArgumentsTable.cpp: Added. + (JSC::ScopedArgumentsTable::ScopedArgumentsTable): + (JSC::ScopedArgumentsTable::~ScopedArgumentsTable): + (JSC::ScopedArgumentsTable::destroy): + (JSC::ScopedArgumentsTable::create): + (JSC::ScopedArgumentsTable::clone): + (JSC::ScopedArgumentsTable::setLength): + (JSC::ScopedArgumentsTable::set): + (JSC::ScopedArgumentsTable::createStructure): + * runtime/ScopedArgumentsTable.h: Added. + (JSC::ScopedArgumentsTable::length): + (JSC::ScopedArgumentsTable::get): + (JSC::ScopedArgumentsTable::lock): + (JSC::ScopedArgumentsTable::offsetOfLength): + (JSC::ScopedArgumentsTable::offsetOfArguments): + (JSC::ScopedArgumentsTable::at): + * runtime/SymbolTable.cpp: + (JSC::SymbolTableEntry::prepareToWatch): + (JSC::SymbolTable::SymbolTable): + (JSC::SymbolTable::visitChildren): + (JSC::SymbolTable::localToEntry): + (JSC::SymbolTable::entryFor): + (JSC::SymbolTable::cloneScopePart): + (JSC::SymbolTable::prepareForTypeProfiling): + (JSC::SymbolTable::uniqueIDForOffset): + (JSC::SymbolTable::globalTypeSetForOffset): + (JSC::SymbolTable::cloneCapturedNames): Deleted. + (JSC::SymbolTable::uniqueIDForRegister): Deleted. + (JSC::SymbolTable::globalTypeSetForRegister): Deleted. + * runtime/SymbolTable.h: + (JSC::SymbolTableEntry::varOffsetFromBits): + (JSC::SymbolTableEntry::scopeOffsetFromBits): + (JSC::SymbolTableEntry::Fast::varOffset): + (JSC::SymbolTableEntry::Fast::scopeOffset): + (JSC::SymbolTableEntry::Fast::isDontEnum): + (JSC::SymbolTableEntry::Fast::getAttributes): + (JSC::SymbolTableEntry::SymbolTableEntry): + (JSC::SymbolTableEntry::varOffset): + (JSC::SymbolTableEntry::isWatchable): + (JSC::SymbolTableEntry::scopeOffset): + (JSC::SymbolTableEntry::setAttributes): + (JSC::SymbolTableEntry::constantMode): + (JSC::SymbolTableEntry::isDontEnum): + (JSC::SymbolTableEntry::disableWatching): + (JSC::SymbolTableEntry::pack): + (JSC::SymbolTableEntry::isValidVarOffset): + (JSC::SymbolTable::createNameScopeTable): + (JSC::SymbolTable::maxScopeOffset): + (JSC::SymbolTable::didUseScopeOffset): + (JSC::SymbolTable::didUseVarOffset): + (JSC::SymbolTable::scopeSize): + (JSC::SymbolTable::nextScopeOffset): + (JSC::SymbolTable::takeNextScopeOffset): + (JSC::SymbolTable::add): + (JSC::SymbolTable::set): + (JSC::SymbolTable::argumentsLength): + (JSC::SymbolTable::setArgumentsLength): + (JSC::SymbolTable::argumentOffset): + (JSC::SymbolTable::setArgumentOffset): + (JSC::SymbolTable::arguments): + (JSC::SlowArgument::SlowArgument): Deleted. + (JSC::SymbolTableEntry::Fast::getIndex): Deleted. + (JSC::SymbolTableEntry::getIndex): Deleted. + (JSC::SymbolTableEntry::isValidIndex): Deleted. + (JSC::SymbolTable::captureStart): Deleted. + (JSC::SymbolTable::setCaptureStart): Deleted. + (JSC::SymbolTable::captureEnd): Deleted. + (JSC::SymbolTable::setCaptureEnd): Deleted. + (JSC::SymbolTable::captureCount): Deleted. + (JSC::SymbolTable::isCaptured): Deleted. + (JSC::SymbolTable::parameterCount): Deleted. + (JSC::SymbolTable::parameterCountIncludingThis): Deleted. + (JSC::SymbolTable::setParameterCountIncludingThis): Deleted. + (JSC::SymbolTable::slowArguments): Deleted. + (JSC::SymbolTable::setSlowArguments): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + * runtime/VarOffset.cpp: Added. + (JSC::VarOffset::dump): + (WTF::printInternal): + * runtime/VarOffset.h: Added. + (JSC::VarOffset::VarOffset): + (JSC::VarOffset::assemble): + (JSC::VarOffset::isValid): + (JSC::VarOffset::operator!): + (JSC::VarOffset::kind): + (JSC::VarOffset::isStack): + (JSC::VarOffset::isScope): + (JSC::VarOffset::isDirectArgument): + (JSC::VarOffset::stackOffsetUnchecked): + (JSC::VarOffset::scopeOffsetUnchecked): + (JSC::VarOffset::capturedArgumentsOffsetUnchecked): + (JSC::VarOffset::stackOffset): + (JSC::VarOffset::scopeOffset): + (JSC::VarOffset::capturedArgumentsOffset): + (JSC::VarOffset::rawOffset): + (JSC::VarOffset::checkSanity): + (JSC::VarOffset::operator==): + (JSC::VarOffset::operator!=): + (JSC::VarOffset::hash): + (JSC::VarOffset::isHashTableDeletedValue): + (JSC::VarOffsetHash::hash): + (JSC::VarOffsetHash::equal): + * tests/stress/arguments-exit-strict-mode.js: Added. + * tests/stress/arguments-exit.js: Added. + * tests/stress/arguments-inlined-exit-strict-mode-fixed.js: Added. + * tests/stress/arguments-inlined-exit-strict-mode.js: Added. + * tests/stress/arguments-inlined-exit.js: Added. + * tests/stress/arguments-interference.js: Added. + * tests/stress/arguments-interference-cfg.js: Added. + * tests/stress/dead-get-closure-var.js: Added. + * tests/stress/get-declared-unpassed-argument-in-direct-arguments.js: Added. + * tests/stress/get-declared-unpassed-argument-in-scoped-arguments.js: Added. + * tests/stress/varargs-closure-inlined-exit-strict-mode.js: Added. + * tests/stress/varargs-closure-inlined-exit.js: Added. + * tests/stress/varargs-exit.js: Added. + * tests/stress/varargs-inlined-exit.js: Added. + * tests/stress/varargs-inlined-simple-exit-aliasing-weird-reversed-args.js: Added. + * tests/stress/varargs-inlined-simple-exit-aliasing-weird.js: Added. + * tests/stress/varargs-inlined-simple-exit-aliasing.js: Added. + * tests/stress/varargs-inlined-simple-exit.js: Added. + * tests/stress/varargs-too-few-arguments.js: Added. + * tests/stress/varargs-varargs-closure-inlined-exit.js: Added. + * tests/stress/varargs-varargs-inlined-exit-strict-mode.js: Added. + * tests/stress/varargs-varargs-inlined-exit.js: Added. + +2015-03-25 Andy Estes <aestes@apple.com> + + [Cocoa] RemoteInspectorXPCConnection::deserializeMessage() leaks a NSDictionary under Objective-C GC + https://bugs.webkit.org/show_bug.cgi?id=143068 + + Reviewed by Dan Bernstein. + + * inspector/remote/RemoteInspectorXPCConnection.mm: + (Inspector::RemoteInspectorXPCConnection::deserializeMessage): Used RetainPtr::autorelease(), which does the right thing under GC. + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Use JITCompilationCanFail in more places, and make the fail path of JITCompilationMustSucceed a crash instead of attempting GC + https://bugs.webkit.org/show_bug.cgi?id=142993 + + Reviewed by Geoffrey Garen and Mark Lam. + + This changes the most commonly invoked paths that relied on JITCompilationMustSucceed + into using JITCompilationCanFail and having a legit fallback path. This mostly involves + having the FTL JIT do the same trick as the DFG JIT in case of any memory allocation + failure, but also involves adding the same kind of thing to the stub generators in + Repatch. + + Because of that change, there are relatively few uses of JITCompilationMustSucceed. Most + of those uses cannot handle a GC, and so cannot do releaseExecutableMemory(). Only a few, + like host call stub generation, could handle a GC, but those get invoked very rarely. So, + this patch changes the releaseExecutableMemory() call into a crash with some diagnostic + printout. + + Also add a way of inducing executable allocation failure, so that we can test this. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compile): + (JSC::DFG::JITCompiler::compileFunction): + (JSC::DFG::JITCompiler::link): Deleted. + (JSC::DFG::JITCompiler::linkFunction): Deleted. + * dfg/DFGJITCompiler.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateCodeSection): + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * ftl/FTLState.h: + * jit/ArityCheckFailReturnThunks.cpp: + (JSC::ArityCheckFailReturnThunks::returnPCsFor): + * jit/ExecutableAllocationFuzz.cpp: Added. + (JSC::numberOfExecutableAllocationFuzzChecks): + (JSC::doExecutableAllocationFuzzing): + * jit/ExecutableAllocationFuzz.h: Added. + (JSC::doExecutableAllocationFuzzingIfEnabled): + * jit/ExecutableAllocatorFixedVMPool.cpp: + (JSC::ExecutableAllocator::allocate): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITCompilationEffort.h: + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::emitPutReplaceStub): + (JSC::emitPutTransitionStubAndGetOldStructure): + (JSC::tryCachePutByID): + (JSC::tryBuildPutByIdList): + (JSC::tryRepatchIn): + (JSC::linkPolymorphicCall): + * jsc.cpp: + (jscmain): + * runtime/Options.h: + * runtime/TestRunnerUtils.h: + * runtime/VM.cpp: + * tests/executableAllocationFuzz: Added. + * tests/executableAllocationFuzz.yaml: Added. + * tests/executableAllocationFuzz/v8-raytrace.js: Added. + +2015-03-25 Mark Lam <mark.lam@apple.com> + + REGRESSION(169139): LLINT intermittently fails JSC testapi tests. + <https://webkit.org/b/135719> + + Reviewed by Geoffrey Garen. + + This is a regression introduced in http://trac.webkit.org/changeset/169139 which + changed VM::watchdog from an embedded field into a std::unique_ptr, but did not + update the LLINT to access it as such. + + The issue has only manifested so far on the CLoop tests because those are LLINT + only. In the non-CLoop cases, the JIT kicks in and does the right thing, thereby + hiding the bug in the LLINT. + + * API/JSContextRef.cpp: + (createWatchdogIfNeeded): + (JSContextGroupSetExecutionTimeLimit): + (JSContextGroupClearExecutionTimeLimit): + * llint/LowLevelInterpreter.asm: + +2015-03-25 Filip Pizlo <fpizlo@apple.com> + + Change Atomic methods from using the_wrong_naming_conventions to using theRightNamingConventions. Also make seq_cst the default. + + Rubber stamped by Geoffrey Garen. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::visitAggregate): + +2015-03-25 Joseph Pecoraro <pecoraro@apple.com> + + Fix formatting in BuiltinExecutables + https://bugs.webkit.org/show_bug.cgi?id=143061 + + Reviewed by Ryosuke Niwa. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createExecutableInternal): + +2015-03-25 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Classes: Program level class statement throws exception in strict mode + https://bugs.webkit.org/show_bug.cgi?id=143038 + + Reviewed by Ryosuke Niwa. + + Classes expose a name to the current lexical environment. This treats + "class X {}" like "var X = class X {}". Ideally it would be "let X = class X {}". + Also, improve error messages for class statements where the class is missing a name. + + * parser/Parser.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + Fill name in info parameter if needed. Better error message if name is needed and missing. + + (JSC::Parser<LexerType>::parseClassDeclaration): + Pass info parameter to get name, and expose the name as a variable name. + + (JSC::Parser<LexerType>::parsePrimaryExpression): + Pass info parameter that is ignored. + + * parser/ParserFunctionInfo.h: + Add a parser info for class, to extract the name. + +2015-03-25 Yusuke Suzuki <utatane.tea@gmail.com> + + New map and set modification tests in r181922 fails + https://bugs.webkit.org/show_bug.cgi?id=143031 + + Reviewed and tweaked by Geoffrey Garen. + + When packing Map/Set backing store, we need to decrement Map/Set iterator's m_index + to adjust for the packed backing store. + + Consider the following map data. + + x: deleted, o: exists + 0 1 2 3 4 + x x x x o + + And iterator with m_index 3. + + When packing the map data, map data will become, + + 0 + o + + At that time, we perfom didRemoveEntry 4 times on iterators. + times => m_index/index/result + 1 => 3/0/dec + 2 => 2/1/dec + 3 => 1/2/nothing + 4 => 1/3/nothing + + After iteration, iterator's m_index becomes 1. But we expected that becomes 0. + This is because if we use decremented m_index for comparison, + while provided deletedIndex is the index in old storage, m_index is the index in partially packed storage. + + In this patch, we compare against the packed index instead. + times => m_index/packedIndex/result + 1 => 3/0/dec + 2 => 2/0/dec + 3 => 1/0/dec + 4 => 0/0/nothing + + So m_index becomes 0 as expected. + + And according to the spec, once the iterator is closed (becomes done: true), + its internal [[Map]]/[[Set]] is set to undefined. + So after the iterator is finished, we don't revive the iterator (e.g. by clearing m_index = 0). + + In this patch, we change 2 things. + 1. + Compare an iterator's index against the packed index when removing an entry. + + 2. + If the iterator is closed (isFinished()), we don't apply adjustment to the iterator. + + * runtime/MapData.h: + (JSC::MapDataImpl::IteratorData::finish): + (JSC::MapDataImpl::IteratorData::isFinished): + (JSC::MapDataImpl::IteratorData::didRemoveEntry): + (JSC::MapDataImpl::IteratorData::didRemoveAllEntries): + (JSC::MapDataImpl::IteratorData::startPackBackingStore): + * runtime/MapDataInlines.h: + (JSC::JSIterator>::replaceAndPackBackingStore): + * tests/stress/modify-map-during-iteration.js: + * tests/stress/modify-set-during-iteration.js: + +2015-03-24 Joseph Pecoraro <pecoraro@apple.com> + + Setter should have a single formal parameter, Getter no parameters + https://bugs.webkit.org/show_bug.cgi?id=142903 + + Reviewed by Geoffrey Garen. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): + Enforce no parameters for getters and a single parameter + for setters, with informational error messages. + +2015-03-24 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Classes: Early return in sub-class constructor results in returning undefined instead of instance + https://bugs.webkit.org/show_bug.cgi?id=143012 + + Reviewed by Ryosuke Niwa. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitReturn): + Fix handling of "undefined" when returned from a Derived class. It was + returning "undefined" when it should have returned "this". + +2015-03-24 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION (r181458): Heap use-after-free in JSSetIterator destructor + https://bugs.webkit.org/show_bug.cgi?id=142696 + + Reviewed and tweaked by Geoffrey Garen. + + Before r142556, JSSetIterator::destroy was not defined. + So accidentally MapData::const_iterator in JSSet was never destroyed. + But it had non trivial destructor, decrementing MapData->m_iteratorCount. + + After r142556, JSSetIterator::destroy works. + It correctly destruct MapData::const_iterator and m_iteratorCount partially works. + But JSSetIterator::~JSSetIterator requires owned JSSet since it mutates MapData->m_iteratorCount. + + It is guaranteed that JSSet is live since JSSetIterator has a reference to JSSet + and marks it in visitChildren (WriteBarrier<Unknown>). + However, the order of destructions is not guaranteed in GC-ed system. + + Consider the following case, + allocate JSSet and subsequently allocate JSSetIterator. + And they resides in the separated MarkedBlock, <1> and <2>. + + JSSet<1> <- JSSetIterator<2> + + And after that, when performing GC, Marker decides that the above 2 objects are not marked. + And Marker also decides MarkedBlocks <1> and <2> can be sweeped. + + First Sweeper sweep <1>, destruct JSSet<1> and free MarkedBlock<1>. + Second Sweeper sweep <2>, attempt to destruct JSSetIterator<2>. + However, JSSetIterator<2>'s destructor, + JSSetIterator::~JSSetIterator requires live JSSet<1>, it causes use-after-free. + + In this patch, we introduce WeakGCMap into JSMap/JSSet to track live iterators. + When packing the removed elements in JSSet/JSMap, we apply the change to all live + iterators tracked by WeakGCMap. + + WeakGCMap can only track JSCell since they are managed by GC. + So we drop JSSet/JSMap C++ style iterators. Instead of C++ style iterator, this patch + introduces JS style iterator signatures into C++ class IteratorData. + If we need to iterate over JSMap/JSSet, use JSSetIterator/JSMapIterator instead of using + IteratorData directly. + + * runtime/JSMap.cpp: + (JSC::JSMap::destroy): + * runtime/JSMap.h: + (JSC::JSMap::JSMap): + (JSC::JSMap::begin): Deleted. + (JSC::JSMap::end): Deleted. + * runtime/JSMapIterator.cpp: + (JSC::JSMapIterator::destroy): + * runtime/JSMapIterator.h: + (JSC::JSMapIterator::next): + (JSC::JSMapIterator::nextKeyValue): + (JSC::JSMapIterator::iteratorData): + (JSC::JSMapIterator::JSMapIterator): + * runtime/JSSet.cpp: + (JSC::JSSet::destroy): + * runtime/JSSet.h: + (JSC::JSSet::JSSet): + (JSC::JSSet::begin): Deleted. + (JSC::JSSet::end): Deleted. + * runtime/JSSetIterator.cpp: + (JSC::JSSetIterator::destroy): + * runtime/JSSetIterator.h: + (JSC::JSSetIterator::next): + (JSC::JSSetIterator::iteratorData): + (JSC::JSSetIterator::JSSetIterator): + * runtime/MapData.h: + (JSC::MapDataImpl::IteratorData::finish): + (JSC::MapDataImpl::IteratorData::isFinished): + (JSC::MapDataImpl::shouldPack): + (JSC::JSIterator>::MapDataImpl): + (JSC::JSIterator>::KeyType::KeyType): + (JSC::JSIterator>::IteratorData::IteratorData): + (JSC::JSIterator>::IteratorData::next): + (JSC::JSIterator>::IteratorData::ensureSlot): + (JSC::JSIterator>::IteratorData::applyMapDataPatch): + (JSC::JSIterator>::IteratorData::refreshCursor): + (JSC::MapDataImpl::const_iterator::key): Deleted. + (JSC::MapDataImpl::const_iterator::value): Deleted. + (JSC::MapDataImpl::const_iterator::operator++): Deleted. + (JSC::MapDataImpl::const_iterator::finish): Deleted. + (JSC::MapDataImpl::const_iterator::atEnd): Deleted. + (JSC::MapDataImpl::begin): Deleted. + (JSC::MapDataImpl::end): Deleted. + (JSC::MapDataImpl<Entry>::MapDataImpl): Deleted. + (JSC::MapDataImpl<Entry>::clear): Deleted. + (JSC::MapDataImpl<Entry>::KeyType::KeyType): Deleted. + (JSC::MapDataImpl<Entry>::const_iterator::internalIncrement): Deleted. + (JSC::MapDataImpl<Entry>::const_iterator::ensureSlot): Deleted. + (JSC::MapDataImpl<Entry>::const_iterator::const_iterator): Deleted. + (JSC::MapDataImpl<Entry>::const_iterator::~const_iterator): Deleted. + (JSC::MapDataImpl<Entry>::const_iterator::operator): Deleted. + (JSC::=): Deleted. + * runtime/MapDataInlines.h: + (JSC::JSIterator>::clear): + (JSC::JSIterator>::find): + (JSC::JSIterator>::contains): + (JSC::JSIterator>::add): + (JSC::JSIterator>::set): + (JSC::JSIterator>::get): + (JSC::JSIterator>::remove): + (JSC::JSIterator>::replaceAndPackBackingStore): + (JSC::JSIterator>::replaceBackingStore): + (JSC::JSIterator>::ensureSpaceForAppend): + (JSC::JSIterator>::visitChildren): + (JSC::JSIterator>::copyBackingStore): + (JSC::JSIterator>::applyMapDataPatch): + (JSC::MapDataImpl<Entry>::find): Deleted. + (JSC::MapDataImpl<Entry>::contains): Deleted. + (JSC::MapDataImpl<Entry>::add): Deleted. + (JSC::MapDataImpl<Entry>::set): Deleted. + (JSC::MapDataImpl<Entry>::get): Deleted. + (JSC::MapDataImpl<Entry>::remove): Deleted. + (JSC::MapDataImpl<Entry>::replaceAndPackBackingStore): Deleted. + (JSC::MapDataImpl<Entry>::replaceBackingStore): Deleted. + (JSC::MapDataImpl<Entry>::ensureSpaceForAppend): Deleted. + (JSC::MapDataImpl<Entry>::visitChildren): Deleted. + (JSC::MapDataImpl<Entry>::copyBackingStore): Deleted. + * runtime/MapPrototype.cpp: + (JSC::mapProtoFuncForEach): + * runtime/SetPrototype.cpp: + (JSC::setProtoFuncForEach): + * runtime/WeakGCMap.h: + (JSC::WeakGCMap::forEach): + * tests/stress/modify-map-during-iteration.js: Added. + (testValue): + (identityPairs): + (.set if): + (var): + (set map): + * tests/stress/modify-set-during-iteration.js: Added. + (testValue): + (set forEach): + (set delete): + +2015-03-24 Mark Lam <mark.lam@apple.com> + + The ExecutionTimeLimit test should use its own JSGlobalContextRef. + <https://webkit.org/b/143024> + + Reviewed by Geoffrey Garen. + + Currently, the ExecutionTimeLimit test is using a JSGlobalContextRef + passed in from testapi.c. It should create its own for better + encapsulation of the test. + + * API/tests/ExecutionTimeLimitTest.cpp: + (currentCPUTimeAsJSFunctionCallback): + (testExecutionTimeLimit): + * API/tests/ExecutionTimeLimitTest.h: + * API/tests/testapi.c: + (main): + +2015-03-24 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Object Literal Methods toString is missing method name + https://bugs.webkit.org/show_bug.cgi?id=142992 + + Reviewed by Geoffrey Garen. + + Always stringify functions in the pattern: + + "function " + <function name> + <text from opening parenthesis to closing brace>. + + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): + Update the path that was not stringifying in this pattern. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::parametersStartOffset): + * parser/Nodes.h: + * runtime/Executable.cpp: + (JSC::FunctionExecutable::FunctionExecutable): + * runtime/Executable.h: + (JSC::FunctionExecutable::parametersStartOffset): + Pass the already known function parameter opening parenthesis + start offset through to the FunctionExecutable. + + * tests/mozilla/js1_5/Scope/regress-185485.js: + (with.g): + Add back original space in this test that was removed by r181810 + now that we have the space again in stringification. + +2015-03-24 Michael Saboff <msaboff@apple.com> + + REGRESSION (172175-172177): Change in for...in processing causes properties added in loop to be enumerated + https://bugs.webkit.org/show_bug.cgi?id=142856 + + Reviewed by Filip Pizlo. + + Refactored the way the for .. in enumeration over objects is done. We used to make three C++ calls to + get info for three loops to iterate over indexed properties, structure properties and other properties, + respectively. We still have the three loops, but now we make one C++ call to get all the info needed + for all loops before we exectue any enumeration. + + The JSPropertyEnumerator has a count of the indexed properties and a list of named properties. + The named properties are one list, with structured properties in the range [0,m_endStructurePropertyIndex) + and the generic properties in the range [m_endStructurePropertyIndex, m_endGenericPropertyIndex); + + Eliminated the bytecodes op_get_structure_property_enumerator, op_get_generic_property_enumerator and + op_next_enumerator_pname. + Added the bytecodes op_get_property_enumerator, op_enumerator_structure_pname and op_enumerator_generic_pname. + The bytecodes op_enumerator_structure_pname and op_enumerator_generic_pname are similar except for what + end value we stop iterating on. + + Made corresponding node changes to the DFG and FTL for the bytecode changes. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetPropertyEnumerator): + (JSC::BytecodeGenerator::emitEnumeratorStructurePropertyName): + (JSC::BytecodeGenerator::emitEnumeratorGenericPropertyName): + (JSC::BytecodeGenerator::emitGetStructurePropertyEnumerator): Deleted. + (JSC::BytecodeGenerator::emitGetGenericPropertyEnumerator): Deleted. + (JSC::BytecodeGenerator::emitNextEnumeratorPropertyName): Deleted. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitMultiLoopBytecode): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLAbstractHeapRepository.h: + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength): + (JSC::FTL::LowerDFGToLLVM::compileGetPropertyEnumerator): + (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorStructurePname): + (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorGenericPname): + (JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator): Deleted. + (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname): Deleted. + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_enumerator_structure_pname): + (JSC::JIT::emit_op_enumerator_generic_pname): + (JSC::JIT::emit_op_get_property_enumerator): + (JSC::JIT::emit_op_next_enumerator_pname): Deleted. + (JSC::JIT::emit_op_get_structure_property_enumerator): Deleted. + (JSC::JIT::emit_op_get_generic_property_enumerator): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_enumerator_structure_pname): + (JSC::JIT::emit_op_enumerator_generic_pname): + (JSC::JIT::emit_op_next_enumerator_pname): Deleted. + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LowLevelInterpreter.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/JSPropertyNameEnumerator.cpp: + (JSC::JSPropertyNameEnumerator::create): + (JSC::JSPropertyNameEnumerator::finishCreation): + * runtime/JSPropertyNameEnumerator.h: + (JSC::JSPropertyNameEnumerator::indexedLength): + (JSC::JSPropertyNameEnumerator::endStructurePropertyIndex): + (JSC::JSPropertyNameEnumerator::endGenericPropertyIndex): + (JSC::JSPropertyNameEnumerator::indexedLengthOffset): + (JSC::JSPropertyNameEnumerator::endStructurePropertyIndexOffset): + (JSC::JSPropertyNameEnumerator::endGenericPropertyIndexOffset): + (JSC::JSPropertyNameEnumerator::cachedInlineCapacityOffset): + (JSC::propertyNameEnumerator): + (JSC::JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset): Deleted. + (JSC::structurePropertyNameEnumerator): Deleted. + (JSC::genericPropertyNameEnumerator): Deleted. + * runtime/Structure.cpp: + (JSC::Structure::setCachedPropertyNameEnumerator): + (JSC::Structure::cachedPropertyNameEnumerator): + (JSC::Structure::canCachePropertyNameEnumerator): + (JSC::Structure::setCachedStructurePropertyNameEnumerator): Deleted. + (JSC::Structure::cachedStructurePropertyNameEnumerator): Deleted. + (JSC::Structure::setCachedGenericPropertyNameEnumerator): Deleted. + (JSC::Structure::cachedGenericPropertyNameEnumerator): Deleted. + (JSC::Structure::canCacheStructurePropertyNameEnumerator): Deleted. + (JSC::Structure::canCacheGenericPropertyNameEnumerator): Deleted. + * runtime/Structure.h: + * runtime/StructureRareData.cpp: + (JSC::StructureRareData::visitChildren): + (JSC::StructureRareData::cachedPropertyNameEnumerator): + (JSC::StructureRareData::setCachedPropertyNameEnumerator): + (JSC::StructureRareData::cachedStructurePropertyNameEnumerator): Deleted. + (JSC::StructureRareData::setCachedStructurePropertyNameEnumerator): Deleted. + (JSC::StructureRareData::cachedGenericPropertyNameEnumerator): Deleted. + (JSC::StructureRareData::setCachedGenericPropertyNameEnumerator): Deleted. + * runtime/StructureRareData.h: + * tests/stress/for-in-delete-during-iteration.js: + +2015-03-24 Michael Saboff <msaboff@apple.com> + + Unreviewed build fix for debug builds. + + * runtime/ExceptionHelpers.cpp: + (JSC::invalidParameterInSourceAppender): + +2015-03-24 Saam Barati <saambarati1@gmail.com> + + Improve error messages in JSC + https://bugs.webkit.org/show_bug.cgi?id=141869 + + Reviewed by Geoffrey Garen. + + JavaScriptCore has some unintuitive error messages associated + with certain common errors. This patch changes some specific + error messages to be more understandable and also creates a + mechanism that will allow for easy modification of error messages + in the future. The specific errors we change are not a function + errors and invalid parameter errors. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * interpreter/Interpreter.cpp: + (JSC::sizeOfVarargs): + * jit/JITOperations.cpp: + op_throw_static_error always has a JSString as its argument. + There is no need to dance around this, and we should assert + that this always holds. This JSString represents the error + message we want to display to the user, so there is no need + to pass it into errorDescriptionForValue which will now place + quotes around the string. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::opIn): + * runtime/ErrorInstance.cpp: + (JSC::ErrorInstance::ErrorInstance): + * runtime/ErrorInstance.h: + (JSC::ErrorInstance::hasSourceAppender): + (JSC::ErrorInstance::sourceAppender): + (JSC::ErrorInstance::setSourceAppender): + (JSC::ErrorInstance::clearSourceAppender): + (JSC::ErrorInstance::setRuntimeTypeForCause): + (JSC::ErrorInstance::runtimeTypeForCause): + (JSC::ErrorInstance::clearRuntimeTypeForCause): + (JSC::ErrorInstance::appendSourceToMessage): Deleted. + (JSC::ErrorInstance::setAppendSourceToMessage): Deleted. + (JSC::ErrorInstance::clearAppendSourceToMessage): Deleted. + * runtime/ExceptionHelpers.cpp: + (JSC::errorDescriptionForValue): + (JSC::defaultApproximateSourceError): + (JSC::defaultSourceAppender): + (JSC::functionCallBase): + (JSC::notAFunctionSourceAppender): + (JSC::invalidParameterInSourceAppender): + (JSC::invalidParameterInstanceofSourceAppender): + (JSC::createError): + (JSC::createInvalidFunctionApplyParameterError): + (JSC::createInvalidInParameterError): + (JSC::createInvalidInstanceofParameterError): + (JSC::createNotAConstructorError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + (JSC::createInvalidParameterError): Deleted. + * runtime/ExceptionHelpers.h: + * runtime/JSObject.cpp: + (JSC::JSObject::hasInstance): + * runtime/RuntimeType.cpp: Added. + (JSC::runtimeTypeForValue): + (JSC::runtimeTypeAsString): + * runtime/RuntimeType.h: Added. + * runtime/TypeProfilerLog.cpp: + (JSC::TypeProfilerLog::processLogEntries): + * runtime/TypeSet.cpp: + (JSC::TypeSet::getRuntimeTypeForValue): Deleted. + * runtime/TypeSet.h: + * runtime/VM.cpp: + (JSC::appendSourceToError): + (JSC::VM::throwException): + +2015-03-23 Filip Pizlo <fpizlo@apple.com> + + JSC should have a low-cost asynchronous disassembler + https://bugs.webkit.org/show_bug.cgi?id=142997 + + Reviewed by Mark Lam. + + This adds a JSC_asyncDisassembly option that disassembles on a thread. Disassembly + doesn't block execution. Some code will live a little longer because of this, since the + work tasks hold a ref to the code, but other than that there is basically no overhead. + + At present, this isn't really a replacement for JSC_showDisassembly, since it doesn't + provide contextual IR information for Baseline and DFG disassemblies, and it doesn't do + the separate IR dumps for FTL. Using JSC_showDisassembly and friends along with + JSC_asyncDisassembly has bizarre behavior - so just choose one. + + A simple way of understanding how great this is, is to run a small benchmark like + V8Spider/earley-boyer. + + Performance without any disassembly flags: 60ms + Performance with JSC_showDisassembly=true: 477ms + Performance with JSC_asyncDisassembly=true: 65ms + + So, the overhead of disassembly goes from 8x to 8%. + + Note that JSC_asyncDisassembly=true does make it incorrect to run "time" as a way of + measuring benchmark performance. This is because at VM exit, we wait for all async + disassembly requests to finish. For example, for earley-boyer, we spend an extra ~130ms + after the benchmark completely finishes to finish the disassemblies. This small weirdness + should be OK for the intended use-cases, since all you have to do to get around it is to + measure the execution time of the benchmark payload rather than the end-to-end time of + launching the VM. + + * assembler/LinkBuffer.cpp: + (JSC::LinkBuffer::finalizeCodeWithDisassembly): + * assembler/LinkBuffer.h: + (JSC::LinkBuffer::wasAlreadyDisassembled): + (JSC::LinkBuffer::didAlreadyDisassemble): + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::disassemble): + * dfg/DFGJITFinalizer.cpp: + (JSC::DFG::JITFinalizer::finalize): + (JSC::DFG::JITFinalizer::finalizeFunction): + * disassembler/Disassembler.cpp: + (JSC::disassembleAsynchronously): + (JSC::waitForAsynchronousDisassembly): + * disassembler/Disassembler.h: + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jsc.cpp: + * runtime/Options.h: + * runtime/VM.cpp: + (JSC::VM::~VM): + +2015-03-23 Dean Jackson <dino@apple.com> + + ES7: Implement Array.prototype.includes + https://bugs.webkit.org/show_bug.cgi?id=142707 + + Reviewed by Geoffrey Garen. + + Add support for the ES7 includes method on Arrays. + https://github.com/tc39/Array.prototype.includes + + * builtins/Array.prototype.js: + (includes): Implementation in JS. + * runtime/ArrayPrototype.cpp: Add 'includes' to the lookup table. + +2015-03-23 Joseph Pecoraro <pecoraro@apple.com> + + __defineGetter__/__defineSetter__ should throw exceptions + https://bugs.webkit.org/show_bug.cgi?id=142934 + + Reviewed by Geoffrey Garen. + + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + Throw exceptions when these functions are used directly. + +2015-03-23 Joseph Pecoraro <pecoraro@apple.com> + + Fix DO_PROPERTYMAP_CONSTENCY_CHECK enabled build + https://bugs.webkit.org/show_bug.cgi?id=142952 + + Reviewed by Geoffrey Garen. + + * runtime/Structure.cpp: + (JSC::PropertyTable::checkConsistency): + The check offset method doesn't exist in PropertyTable, it exists in Structure. + + (JSC::Structure::checkConsistency): + So move it here, and always put it at the start to match normal behavior. + +2015-03-22 Filip Pizlo <fpizlo@apple.com> + + Remove DFG::ValueRecoveryOverride; it's been dead since we removed forward speculations + https://bugs.webkit.org/show_bug.cgi?id=142956 + + Rubber stamped by Gyuyoung Kim. + + Just removing dead code. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGOSRExit.h: + * dfg/DFGOSRExitCompiler.cpp: + * dfg/DFGValueRecoveryOverride.h: Removed. + +2015-03-22 Filip Pizlo <fpizlo@apple.com> + + DFG OSR exit shouldn't assume that the frame count for exit is greater than the frame count in DFG + https://bugs.webkit.org/show_bug.cgi?id=142948 + + Reviewed by Sam Weinig. + + It's necessary to ensure that the stack pointer accounts for the extent of our stack usage + since a signal may clobber the area below the stack pointer. When the DFG is executing, + the stack pointer accounts for the DFG's worst-case stack usage. When we OSR exit back to + baseline, we will use a different amount of stack. This is because baseline is a different + compiler. It will make different decisions. So it will use a different amount of stack. + + This gets tricky when we are in the process of doing an OSR exit, because we are sort of + incrementally transforming the stack from how it looked in the DFG to how it will look in + baseline. The most conservative approach would be to set the stack pointer to the max of + DFG and baseline. + + When this code was written, a reckless assumption was made: that the stack usage in + baseline is always at least as large as the stack usage in DFG. Based on this incorrect + assumption, the code first adjusts the stack pointer to account for the baseline stack + usage. This sort of usually works, because usually baseline does happen to use more stack. + But that's not an invariant. Nobody guarantees this. We will never make any changes that + would make this be guaranteed, because that would be antithetical to how optimizing + compilers work. The DFG should be allowed to use however much stack it decides that it + should use in order to get good performance, and it shouldn't try to guarantee that it + always uses less stack than baseline. + + As such, we must always assume that the frame size for DFG execution (i.e. + frameRegisterCount) and the frame size in baseline once we exit (i.e. + requiredRegisterCountForExit) are two independent quantities and they have no + relationship. + + Fortunately, though, this code can be made correct by just moving the stack adjustment to + just before we do conversions. This is because we have since changed the OSR exit + algorithm to first lift up all state from the DFG state into a scratch buffer, and then to + drop it out of the scratch buffer and into the stack according to the baseline layout. The + point just before conversions is the point where we have finished reading the DFG frame + and will not read it anymore, and we haven't started writing the baseline frame. So, at + this point it is safe to set the stack pointer to account for the frame size at exit. + + This is benign because baseline happens to create larger frames than DFG. + + * dfg/DFGOSRExitCompiler32_64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompiler64.cpp: + (JSC::DFG::OSRExitCompiler::compileExit): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::adjustAndJumpToTarget): + +2015-03-22 Filip Pizlo <fpizlo@apple.com> + + Shorten the number of iterations to 10,000 since that's enough to test all tiers. + + Rubber stamped by Sam Weinig. + + * tests/stress/equals-masquerader.js: + +2015-03-22 Filip Pizlo <fpizlo@apple.com> + + tests/stress/*tdz* tests do 10x more iterations than necessary + https://bugs.webkit.org/show_bug.cgi?id=142946 + + Reviewed by Ryosuke Niwa. + + The stress test harness runs all of these tests in various configurations. This includes + no-cjit, which has tier-up heuristics locked in such a way that 10,000 iterations is + enough to get to the highest tier. The only exceptions are very large functions or + functions that have some reoptimizations. That happens rarely, and when it does happen, + usually 20,000 iterations is enough. + + Therefore, these tests use 10x too many iterations. This is bad, since these tests + allocate on each iteration, and so they run very slowly in debug mode. + + * tests/stress/class-syntax-no-loop-tdz.js: + * tests/stress/class-syntax-no-tdz-in-catch.js: + * tests/stress/class-syntax-no-tdz-in-conditional.js: + * tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js: + * tests/stress/class-syntax-no-tdz-in-loop.js: + * tests/stress/class-syntax-no-tdz.js: + * tests/stress/class-syntax-tdz-in-catch.js: + * tests/stress/class-syntax-tdz-in-conditional.js: + * tests/stress/class-syntax-tdz-in-loop.js: + * tests/stress/class-syntax-tdz.js: + +2015-03-21 Joseph Pecoraro <pecoraro@apple.com> + + Fix a typo in Parser error message + https://bugs.webkit.org/show_bug.cgi?id=142942 + + Reviewed by Alexey Proskuryakov. + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitSlow_op_resolve_scope): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitSlow_op_resolve_scope): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + Fix a common identifier typo. + +2015-03-21 Joseph Pecoraro <pecoraro@apple.com> + + Computed Property names should allow only AssignmentExpressions not any Expression + https://bugs.webkit.org/show_bug.cgi?id=142902 + + Reviewed by Ryosuke Niwa. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseProperty): + Limit computed expressions to just assignment expressions instead of + any expression (which allowed comma expressions). + +2015-03-21 Andreas Kling <akling@apple.com> + + Make UnlinkedFunctionExecutable fit in a 128-byte cell. + <https://webkit.org/b/142939> + + Reviewed by Mark Hahnenberg. + + Re-arrange the members of UnlinkedFunctionExecutable so it can fit inside + a 128-byte heap cell instead of requiring a 256-byte one. + + Threw in a static_assert to catch anyone pushing it over the limit again. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::functionMode): + +2015-03-20 Mark Hahnenberg <mhahnenb@gmail.com> + + GCTimer should know keep track of nested GC phases + https://bugs.webkit.org/show_bug.cgi?id=142675 + + Reviewed by Darin Adler. + + This improves the GC phase timing output in Heap.cpp by linking + phases nested inside other phases together, allowing tools + to compute how much time we're spending in various nested phases. + + * heap/Heap.cpp: + +2015-03-20 Geoffrey Garen <ggaren@apple.com> + + FunctionBodyNode should known where its parameters started + https://bugs.webkit.org/show_bug.cgi?id=142926 + + Reviewed by Ryosuke Niwa. + + This will allow us to re-parse parameters instead of keeping the + parameters piece of the AST around forever. + + I also took the opportunity to initialize most FunctionBodyNode data + members at construction time, to help clarify that they are set right. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createFunctionExpr): No need to pass + functionKeywordStart here; we now provide it at FunctionBodyNode + creation time. + + (JSC::ASTBuilder::createFunctionBody): Require everything we need at + construction time, including the start of our parameters. + + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createFuncDeclStatement): No need to pass + functionKeywordStart here; we now provide it at FunctionBodyNode + creation time. + + (JSC::ASTBuilder::setFunctionNameStart): Deleted. + + * parser/Nodes.cpp: + (JSC::FunctionBodyNode::FunctionBodyNode): Initialize everything at + construction time. + + * parser/Nodes.h: Added a field for the location of our parameters. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionBody): + (JSC::Parser<LexerType>::parseFunctionInfo): + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseClass): + (JSC::Parser<LexerType>::parsePropertyMethod): + (JSC::Parser<LexerType>::parseGetterSetter): + (JSC::Parser<LexerType>::parsePrimaryExpression): + * parser/Parser.h: Refactored to match above interface changes. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createFunctionExpr): + (JSC::SyntaxChecker::createFunctionBody): + (JSC::SyntaxChecker::createFuncDeclStatement): + (JSC::SyntaxChecker::createGetterOrSetterProperty): Refactored to match + above interface changes. + + (JSC::SyntaxChecker::setFunctionNameStart): Deleted. + +2015-03-20 Filip Pizlo <fpizlo@apple.com> + + Observably effectful nodes in DFG IR should come last in their bytecode instruction (i.e. forExit section), except for Hint nodes + https://bugs.webkit.org/show_bug.cgi?id=142920 + + Reviewed by Oliver Hunt, Geoffrey Garen, and Mark Lam. + + Observably effectful, n.: If we reexecute the bytecode instruction after this node has + executed, then something other than the bytecode instruction's specified outcome will + happen. + + We almost never had observably effectful nodes except at the end of the bytecode + instruction. The exception is a lowered transitioning PutById: + + PutStructure(@o, S1 -> S2) + PutByOffset(@o, @o, @v) + + The PutStructure is observably effectful: if you try to reexecute the bytecode after + doing the PutStructure, then we'll most likely crash. The generic PutById handling means + first checking what the old structure of the object is; but if we reexecute, the old + structure will seem to be the new structure. But the property ensured by the new + structure hasn't been stored yet, so any attempt to load it or scan it will crash. + + Intriguingly, however, none of the other operations involved in the PutById are + observably effectful. Consider this example: + + PutByOffset(@o, @o, @v) + PutStructure(@o, S1 -> S2) + + Note that the PutStructure node doesn't reallocate property storage; see further below + for an example that does that. Because no property storage is happening, we know that we + already had room for the new property. This means that the PutByOffset is no observable + until the PutStructure executes and "reveals" the property. Hence, PutByOffset is not + observably effectful. + + Now consider this: + + b: AllocatePropertyStorage(@o) + PutByOffset(@b, @o, @v) + PutStructure(@o, S1 -> S2) + + Surprisingly, this is also safe, because the AllocatePropertyStorage is not observably + effectful. It *does* reallocate the property storage and the new property storage pointer + is stored into the object. But until the PutStructure occurs, the world will just think + that the reallocation didn't happen, in the sense that we'll think that the property + storage is using less memory than what we just allocated. That's harmless. + + The AllocatePropertyStorage is safe in other ways, too. Even if we GC'd after the + AllocatePropertyStorage but before the PutByOffset (or before the PutStructure), + everything could be expected to be fine, so long as all of @o, @v and @b are on the + stack. If they are all on the stack, then the GC will leave the property storage alone + (so the extra memory we just allocated would be safe). The GC will not scan the part of + the property storage that contains @v, but that's fine, so long as @v is on the stack. + + The better long-term solution is probably bug 142921. + + But for now, this: + + - Fixes an object materialization bug, exemplified by the two tests, that previously + crashed 100% of the time with FTL enabled and concurrent JIT disabled. + + - Allows us to remove the workaround introduced in r174856. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handlePutById): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::insertCheck): + (JSC::DFG::FixupPhase::indexOfNode): Deleted. + (JSC::DFG::FixupPhase::indexOfFirstNodeOfExitOrigin): Deleted. + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertOutOfOrder): Deleted. + (JSC::DFG::InsertionSet::insertOutOfOrderNode): Deleted. + * tests/stress/materialize-past-butterfly-allocation.js: Added. + (bar): + (foo0): + (foo1): + (foo2): + (foo3): + (foo4): + * tests/stress/materialize-past-put-structure.js: Added. + (foo): + +2015-03-20 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION (r179429): Potential Use after free in JavaScriptCore`WTF::StringImpl::ref + 83 + https://bugs.webkit.org/show_bug.cgi?id=142410 + + Reviewed by Geoffrey Garen. + + Before this patch, added function JSValue::toPropertyKey returns PropertyName. + Since PropertyName doesn't have AtomicStringImpl ownership, + if Identifier is implicitly converted to PropertyName and Identifier is destructed, + PropertyName may refer freed AtomicStringImpl*. + + This patch changes the result type of JSValue::toPropertyName from PropertyName to Identifier, + to keep AtomicStringImpl* ownership after the toPropertyName call is done. + And receive the result value as Identifier type to keep ownership in the caller side. + + To catch the result of toPropertyKey as is, we catch the result of toPropertyName as auto. + + However, now we don't need to have both Identifier and PropertyName. + So we'll merge PropertyName to Identifier in the subsequent patch. + + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * jit/JITOperations.cpp: + (JSC::getByVal): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getByVal): + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::opIn): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::toPropertyKey): + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyDescriptor): + (JSC::objectConstructorDefineProperty): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncPropertyIsEnumerable): + +2015-03-18 Geoffrey Garen <ggaren@apple.com> + + Function.prototype.toString should not decompile the AST + https://bugs.webkit.org/show_bug.cgi?id=142853 + + Reviewed by Sam Weinig. + + To recover the function parameter string, Function.prototype.toString + decompiles the function parameters from the AST. This is bad for a few + reasons: + + (1) It requires us to keep pieces of the AST live forever. This is an + awkward design and a waste of memory. + + (2) It doesn't match Firefox or Chrome (because it changes whitespace + and ES6 destructuring expressions). + + (3) It doesn't scale to ES6 default argument parameters, which require + arbitrarily complex decompilation. + + (4) It can counterfeit all the line numbers in a function (because + whitespace can include newlines). + + (5) It's expensive, and we've seen cases where websites invoke + Function.prototype.toString a lot by accident. + + The fix is to do what we do for the rest of the function: Just quote the + original source text. + + Since this change inevitably changes some function stringification, I + took the opportunity to make our stringification match Firefox's and + Chrome's. + + * API/tests/testapi.c: + (assertEqualsAsUTF8String): Be more informative when this fails. + + (main): Updated to match new stringification rules. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::paramString): Deleted. Yay! + * bytecode/UnlinkedCodeBlock.h: + + * parser/Nodes.h: + (JSC::StatementNode::isFuncDeclNode): New helper for constructing + anonymous functions. + + * parser/SourceCode.h: + (JSC::SourceCode::SourceCode): Allow zero because WebCore wants it. + + * runtime/CodeCache.cpp: + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Updated for use + of function declaration over function expression. + + * runtime/Executable.cpp: + (JSC::FunctionExecutable::paramString): Deleted. Yay! + * runtime/Executable.h: + (JSC::FunctionExecutable::parameterCount): + + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): Added a newline after + the opening brace to match Firefox and Chrome, and a space after the comma + to match Firefox and WebKit coding style. Added the function name to + the text of the function so it would look right when stringify-ing. Switched + from parentheses to braces to produce a function declaration instead of + a function expression because we are required to exclude the function's + name from its scope, and that's what a function declaration does. + + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): Removed an old workaround because the + library it worked around doesn't really exist anymore, and the behavior + doesn't match Firefox or Chrome. Use type profiling offsets instead of + function body offsets because we want to include the function name and + the parameter string, rather than stitching them in manually by + decompiling the AST. + + (JSC::insertSemicolonIfNeeded): Deleted. + + * tests/mozilla/js1_2/function/tostring-1.js: + * tests/mozilla/js1_5/Scope/regress-185485.js: + (with.g): Updated these test results for formatting changes. + +2015-03-20 Joseph Pecoraro <pecoraro@apple.com> + + SyntaxChecker assertion is trapped with computed property name and getter + https://bugs.webkit.org/show_bug.cgi?id=142863 + + Reviewed by Ryosuke Niwa. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::getName): + Remove invalid assert. Computed properties will not have a name + and the calling code is checking for null expecting it. The + AST path (non-CheckingPath) already does this without the assert + so it is well tested. + +2015-03-19 Mark Lam <mark.lam@apple.com> + + JSCallbackObject<JSGlobalObject> should not destroy its JSCallbackObjectData before all its finalizers have been called. + <https://webkit.org/b/142846> + + Reviewed by Geoffrey Garen. + + Currently, JSCallbackObject<JSGlobalObject> registers weak finalizers via 2 mechanisms: + 1. JSCallbackObject<Parent>::init() registers a weak finalizer for all JSClassRef + that a JSCallbackObject references. + 2. JSCallbackObject<JSGlobalObject>::create() registers a finalizer via + vm.heap.addFinalizer() which destroys the JSCallbackObject. + + The first finalizer is implemented as a virtual function of a JSCallbackObjectData + instance that will be destructed if the 2nd finalizer is called. Hence, if the + 2nd finalizer if called first, the later invocation of the 1st finalizer will + result in a crash. + + This patch fixes the issue by eliminating the finalizer registration in init(). + Instead, we'll have the JSCallbackObject destructor call all the JSClassRef finalizers + if needed. This ensures that these finalizers are called before the JSCallbackObject + is destructor. + + Also added assertions to a few Heap functions because JSCell::classInfo() expects + all objects that are allocated from MarkedBlock::Normal blocks to be derived from + JSDestructibleObject. These assertions will help us catch violations of this + expectation earlier. + + * API/JSCallbackObject.cpp: + (JSC::JSCallbackObjectData::finalize): Deleted. + * API/JSCallbackObject.h: + (JSC::JSCallbackObjectData::~JSCallbackObjectData): + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::~JSCallbackObject): + (JSC::JSCallbackObject<Parent>::init): + * API/tests/GlobalContextWithFinalizerTest.cpp: Added. + (finalize): + (testGlobalContextWithFinalizer): + * API/tests/GlobalContextWithFinalizerTest.h: Added. + * API/tests/testapi.c: + (main): + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/HeapInlines.h: + (JSC::Heap::allocateObjectOfType): + (JSC::Heap::subspaceForObjectOfType): + (JSC::Heap::allocatorForObjectOfType): + +2015-03-19 Andreas Kling <akling@apple.com> + + JSCallee unnecessarily overrides a bunch of things in the method table. + <https://webkit.org/b/142855> + + Reviewed by Geoffrey Garen. + + Remove JSCallee method table overrides that simply call to base class. + This makes JSFunction property slot lookups slightly more efficient since + they can take the fast path when passing over JSCallee in the base class chain. + + * runtime/JSCallee.cpp: + (JSC::JSCallee::getOwnPropertySlot): Deleted. + (JSC::JSCallee::getOwnNonIndexPropertyNames): Deleted. + (JSC::JSCallee::put): Deleted. + (JSC::JSCallee::deleteProperty): Deleted. + (JSC::JSCallee::defineOwnProperty): Deleted. + * runtime/JSCallee.h: + +2015-03-19 Andreas Kling <akling@apple.com> + + DFGAllocator should use bmalloc's aligned allocator. + <https://webkit.org/b/142871> + + Reviewed by Geoffrey Garen. + + Switch DFGAllocator to using bmalloc through fastAlignedMalloc(). + + * dfg/DFGAllocator.h: + (JSC::DFG::Allocator<T>::allocateSlow): + (JSC::DFG::Allocator<T>::freeRegionsStartingAt): + * heap/CopiedSpace.h: + * heap/MarkedBlock.h: + * heap/MarkedSpace.h: + +2015-03-18 Joseph Pecoraro <pecoraro@apple.com> + + ES6 Classes: Extends should accept an expression without parenthesis + https://bugs.webkit.org/show_bug.cgi?id=142840 + + Reviewed by Ryosuke Niwa. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + "extends" allows a LeftHandExpression (new expression / call expression, + which includes a member expression), not a primary expression. Our + parseMemberExpression does all of these. + +2015-03-18 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Debugger Popovers and Probes should use FormattedValue/ObjectTreeView instead of Custom/ObjectPropertiesSection + https://bugs.webkit.org/show_bug.cgi?id=142830 + + Reviewed by Timothy Hatcher. + + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::breakpointActionProbe): + Give Probe Samples object previews. + +2015-03-17 Ryuan Choi <ryuan.choi@navercorp.com> + + [EFL] Expose JavaScript binding interface through ewk_extension + https://bugs.webkit.org/show_bug.cgi?id=142033 + + Reviewed by Gyuyoung Kim. + + * PlatformEfl.cmake: Install Javascript APIs. + +2015-03-17 Geoffrey Garen <ggaren@apple.com> + + Function bodies should always include braces + https://bugs.webkit.org/show_bug.cgi?id=142795 + + Reviewed by Michael Saboff. + + Having a mode for excluding the opening and closing braces from a function + body was unnecessary and confusing. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): Adopt the new one true linking function. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::link): + (JSC::UnlinkedFunctionExecutable::codeBlockFor): No need to pass through + a boolean: there is only one kind of function now. + + (JSC::UnlinkedFunctionExecutable::linkInsideExecutable): Deleted. + (JSC::UnlinkedFunctionExecutable::linkGlobalCode): Deleted. Let's only + have one way to do things. This removes the old mode that would pretend + that a function always started at column 1. That pretense was not true: + an attribute event listener does not necessarily start at column 1. + + * bytecode/UnlinkedCodeBlock.h: + * generate-js-builtins: Adopt the new one true linking function. + + * parser/Parser.h: + (JSC::Parser<LexerType>::parse): + (JSC::parse): needsReparsingAdjustment is always true now, so I removed it. + + * runtime/Executable.cpp: + (JSC::ScriptExecutable::newCodeBlockFor): + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::ProgramExecutable::initializeGlobalProperties): + (JSC::FunctionExecutable::fromGlobalCode): + * runtime/Executable.h: + (JSC::FunctionExecutable::create): + (JSC::FunctionExecutable::bodyIncludesBraces): Deleted. Removed unused stuff. + + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): Always provide a + leading space because that's what this function's comment says is required + for web compatibility. We used to fake this up after the fact when + stringifying, based on the bodyIncludesBraces flag, but that flag is gone now. + + * runtime/FunctionPrototype.cpp: + (JSC::insertSemicolonIfNeeded): + (JSC::functionProtoFuncToString): No need to add braces and/or a space + after the fact -- we always have them now. + +2015-03-17 Mark Lam <mark.lam@apple.com> + + Refactor execution time limit tests out of testapi.c. + <https://webkit.org/b/142798> + + Rubber stamped by Michael Saboff. + + These tests were sometimes failing to time out on C loop builds. Let's + refactor them out of the big monolith that is testapi.c so that we can + reason more easily about them and make adjustments if needed. + + * API/tests/ExecutionTimeLimitTest.cpp: Added. + (currentCPUTime): + (currentCPUTimeAsJSFunctionCallback): + (shouldTerminateCallback): + (cancelTerminateCallback): + (extendTerminateCallback): + (testExecutionTimeLimit): + * API/tests/ExecutionTimeLimitTest.h: Added. + * API/tests/testapi.c: + (main): + (currentCPUTime): Deleted. + (currentCPUTime_callAsFunction): Deleted. + (shouldTerminateCallback): Deleted. + (cancelTerminateCallback): Deleted. + (extendTerminateCallback): Deleted. + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-03-17 Geoffrey Garen <ggaren@apple.com> + + Built-in functions should know that they use strict mode + https://bugs.webkit.org/show_bug.cgi?id=142788 + + Reviewed by Mark Lam. + + Even though all of our builtin functions use strict mode, the parser + thinks that they don't. This is because Executable::toStrictness treats + builtin-ness and strict-ness as mutually exclusive. + + The fix is to disambiguate builtin-ness from strict-ness. + + This bug is currently unobservable because of some other parser bugs. But + it causes lots of test failures once those other bugs are fixed. + + * API/JSScriptRef.cpp: + (parseScript): + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): Adopt the new API + for a separate value to indicate builtin-ness vs strict-ness. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::codeBlockFor): Ditto. + + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::toStrictness): Deleted. This function + was misleading since it pretended that no builtin function was ever + strict, which is the opposite of true. + + * parser/Lexer.cpp: + (JSC::Lexer<T>::Lexer): + * parser/Lexer.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + * parser/Parser.h: + (JSC::parse): Adopt the new API. + + * parser/ParserModes.h: Added JSParserBuiltinMode, and tried to give + existing modes clearer names. + + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getProgramCodeBlock): + (JSC::CodeCache::getEvalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Adopt the new API. + + * runtime/CodeCache.h: + (JSC::SourceCodeKey::SourceCodeKey): Be sure to treat strict-ness and + bulitin-ness as separate pieces of the code cache key. We would not want + a user function to match a built-in function in the cache, even if they + agreed about strictness, since builtin functions have different lexing + rules. + + * runtime/Completion.cpp: + (JSC::checkSyntax): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::ProgramExecutable::checkSyntax): + * runtime/Executable.h: + (JSC::FunctionExecutable::create): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::createProgramCodeBlock): + (JSC::JSGlobalObject::createEvalCodeBlock): Adopt the new API. + +2015-03-16 Filip Pizlo <fpizlo@apple.com> + + DFG IR shouldn't have a separate node for every kind of put hint that could be described using PromotedLocationDescriptor + https://bugs.webkit.org/show_bug.cgi?id=142769 + + Reviewed by Michael Saboff. + + When we sink an object allocation, we need to have some way of tracking what stores would + have happened had the allocation not been sunk, so that we know how to rematerialize the + object on OSR exit. Prior to this change, trunk had two ways of describing such a "put + hint": + + - The PutStrutureHint and PutByOffsetHint node types. + - The PromotedLocationDescriptor class, which has an enum with cases StructurePLoc and + NamedPropertyPLoc. + + We also had ways of converting from a Node with those two node types to a + PromotedLocationDescriptor, and we had a way of converting a PromotedLocationDescriptor to + a Node. + + This change removes the redundancy. We now have just one node type that corresponds to a + put hint, and it's called PutHint. It has a PromotedLocationDescriptor as metadata. + Converting between a PutHint node and a PromotedLocationDescriptor and vice-versa is now + trivial. + + This means that if we add new kinds of sunken objects, we'll have less pro-forma to write + for the put hints to those objects. This is mainly to simplify the implementation of + arguments elimination in bug 141174. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::mergeRelevantToOSR): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::convertToPutHint): + (JSC::DFG::Node::convertToPutStructureHint): + (JSC::DFG::Node::convertToPutByOffsetHint): + (JSC::DFG::Node::promotedLocationDescriptor): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasIdentifier): + (JSC::DFG::Node::hasPromotedLocationDescriptor): + (JSC::DFG::Node::convertToPutByOffsetHint): Deleted. + (JSC::DFG::Node::convertToPutStructureHint): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::run): + (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations): + (JSC::DFG::ObjectAllocationSinkingPhase::handleNode): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGPromoteHeapAccess.h: + (JSC::DFG::promoteHeapAccess): + * dfg/DFGPromotedHeapLocation.cpp: + (JSC::DFG::PromotedHeapLocation::createHint): + * dfg/DFGPromotedHeapLocation.h: + (JSC::DFG::PromotedLocationDescriptor::imm1): + (JSC::DFG::PromotedLocationDescriptor::imm2): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + +2015-03-17 Michael Saboff <msaboff@apple.com> + + Windows X86-64 should use the fixed executable allocator + https://bugs.webkit.org/show_bug.cgi?id=142749 + + Reviewed by Filip Pizlo. + + Added jit/ExecutableAllocatorFixedVMPool.cpp to Windows build. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * jit/ExecutableAllocatorFixedVMPool.cpp: Don't include unistd.h on Windows. + +2015-03-17 Matt Baker <mattbaker@apple.com> + + Web Inspector: Show rendering frames (and FPS) in Layout and Rendering timeline + https://bugs.webkit.org/show_bug.cgi?id=142029 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Timeline.json: + Added new event type for runloop timeline records. + +2015-03-16 Ryosuke Niwa <rniwa@webkit.org> + + Enable ES6 classes by default + https://bugs.webkit.org/show_bug.cgi?id=142774 + + Reviewed by Gavin Barraclough. + + Enabled the feature and unskipped tests. + + * Configurations/FeatureDefines.xcconfig: + * tests/stress/class-syntax-no-loop-tdz.js: + * tests/stress/class-syntax-no-tdz-in-catch.js: + * tests/stress/class-syntax-no-tdz-in-conditional.js: + * tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js: + * tests/stress/class-syntax-no-tdz-in-loop.js: + * tests/stress/class-syntax-no-tdz.js: + * tests/stress/class-syntax-tdz-in-catch.js: + * tests/stress/class-syntax-tdz-in-conditional.js: + * tests/stress/class-syntax-tdz-in-loop.js: + * tests/stress/class-syntax-tdz.js: + +2015-03-16 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Better Console Previews for Arrays / Small Objects + https://bugs.webkit.org/show_bug.cgi?id=142322 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + Create deep valuePreviews for simple previewable objects, + such as arrays with 5 values, or basic objects with + 3 properties. + +2015-03-16 Ryosuke Niwa <rniwa@webkit.org> + + Add support for default constructor + https://bugs.webkit.org/show_bug.cgi?id=142388 + + Reviewed by Filip Pizlo. + + Added the support for default constructors. They're generated by ClassExprNode::emitBytecode + via BuiltinExecutables::createDefaultConstructor. + + UnlinkedFunctionExecutable now has the ability to override SourceCode provided by the owner + executable. We can't make store SourceCode in UnlinkedFunctionExecutable since CodeCache can use + the same UnlinkedFunctionExecutable to generate code blocks for multiple functions. + + Parser now has the ability to treat any function expression as a constructor of the kind specified + by m_defaultConstructorKind member variable. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createDefaultConstructor): Added. + (JSC::BuiltinExecutables::createExecutableInternal): Generalized from createBuiltinExecutable. + Parse default constructors as normal non-builtin functions. Override SourceCode in the unlinked + function executable since the Miranda function's code is definitely not in the owner executable's + source code. That's the whole point. + * builtins/BuiltinExecutables.h: + (UnlinkedFunctionExecutable::createBuiltinExecutable): Added. Wraps createExecutableInternal. + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + (JSC::UnlinkedFunctionExecutable::linkInsideExecutable): + (JSC::UnlinkedFunctionExecutable::linkGlobalCode): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedFunctionExecutable::create): + (JSC::UnlinkedFunctionExecutable::symbolTable): Deleted. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitNewDefaultConstructor): Added. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ClassExprNode::emitBytecode): Generate the default constructor if needed. + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + (JSC::Parser<LexerType>::parseFunctionInfo): Override ownerClassKind and assume the function as + a constructor if we're parsing a default constructor. + (JSC::Parser<LexerType>::parseClass): Allow omission of the class constructor. + * parser/Parser.h: + (JSC::parse): + +2015-03-16 Alex Christensen <achristensen@webkit.org> + + Progress towards CMake on Mac + https://bugs.webkit.org/show_bug.cgi?id=142747 + + Reviewed by Chris Dumez. + + * CMakeLists.txt: + Include AugmentableInspectorController.h in CMake build. + +2015-03-16 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Enable generating idiv instructions if it is supported + https://bugs.webkit.org/show_bug.cgi?id=142725 + + Reviewed by Michael Saboff. + + * assembler/ARMAssembler.h: Added sdiv and udiv implementation for ARM Traditional instruction set. + (JSC::ARMAssembler::sdiv): + (JSC::ARMAssembler::udiv): + * assembler/ARMv7Assembler.h: Use HAVE(ARM_IDIV_INSTRUCTIONS) instead of CPU(APPLE_ARMV7S). + * assembler/AbstractMacroAssembler.h: + (JSC::isARMv7IDIVSupported): + (JSC::optimizeForARMv7IDIVSupported): + (JSC::isARMv7s): Renamed to isARMv7IDIVSupported(). + (JSC::optimizeForARMv7s): Renamed to optimizeForARMv7IDIVSupported(). + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithDiv): + (JSC::DFG::SpeculativeJIT::compileArithMod): + +2015-03-15 Filip Pizlo <fpizlo@apple.com> + + DFG::PutStackSinkingPhase should eliminate GetStacks that have an obviously known source, and emit GetStacks when the stack's value is needed and none is deferred + https://bugs.webkit.org/show_bug.cgi?id=141624 + + Reviewed by Geoffrey Garen. + + Not eliminating GetStacks was an obvious omission from the original PutStackSinkingPhase. + Previously, we would treat GetStacks conservatively and assume that the stack slot + escaped. That's pretty dumb, since a GetStack is a local load of the stack. This change + makes GetStack a no-op from the standpoint of this phase's deferral analysis. At the end + we either keep the GetStack (if there was no concrete deferral) or we replace it with an + identity over the value that would have been stored by the deferred PutStack. Note that + this might be a Phi that the phase creates, so this is strictly stronger than what GCSE + could do. + + But this change revealed the fact that this phase never correctly handled side effects in + case that we had done a GetStack, then a side-effect, and then found ourselves wanting the + value on the stack due to (for example) a Phi on a deferred PutStack and that GetStack. + Basically, it's only correct to use the SSA converter's incoming value mapping if we have + a concrete deferral - since anything but a concrete deferral may imply that the value has + been clobbered. + + This has no performance change. I believe that the bug was previously benign because we + have so few operations that clobber the stack anymore, and most of those get used in a + very idiomatic way. The GetStack elimination will be very useful for the varargs + simplification that is part of bug 141174. + + This includes a test for the case that Speedometer hit, plus tests for the other cases I + thought of once I realized the deeper issue. + + * dfg/DFGPutStackSinkingPhase.cpp: + * tests/stress/get-stack-identity-due-to-sinking.js: Added. + (foo): + (bar): + * tests/stress/get-stack-mapping-with-dead-get-stack.js: Added. + (bar): + (foo): + * tests/stress/get-stack-mapping.js: Added. + (bar): + (foo): + * tests/stress/weird-put-stack-varargs.js: Added. + (baz): + (foo): + (fuzz): + (bar): + +2015-03-16 Joseph Pecoraro <pecoraro@apple.com> + + Update Map/Set to treat -0 and 0 as the same value + https://bugs.webkit.org/show_bug.cgi?id=142709 + + Reviewed by Csaba Osztrogonác. + + * runtime/MapData.h: + (JSC::MapDataImpl<Entry>::KeyType::KeyType): + No longer special case -0. It will be treated as the same as 0. + +2015-03-15 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Better handle displaying -0 + https://bugs.webkit.org/show_bug.cgi?id=142708 + + Reviewed by Timothy Hatcher. + + Modeled after a blink change: + + Patch by <aandrey@chromium.org> + DevTools: DevTools: Show -0 for negative zero in console + https://src.chromium.org/viewvc/blink?revision=162605&view=revision + + * inspector/InjectedScriptSource.js: + When creating a description string, or preview value string + for -0, be sure the string is "-0" and not "0". + +2015-03-14 Ryosuke Niwa <rniwa@webkit.org> + + parseClass should popScope after pushScope + https://bugs.webkit.org/show_bug.cgi?id=142689 + + Reviewed by Benjamin Poulain. + + Pop the parser scope as needed. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + +2015-03-14 Dean Jackson <dino@apple.com> + + Feature flag for Animations Level 2 + https://bugs.webkit.org/show_bug.cgi?id=142699 + <rdar://problem/20165097> + + Reviewed by Brent Fulgham. + + Add ENABLE_CSS_ANIMATIONS_LEVEL_2 and a runtime flag animationTriggersEnabled. + + * Configurations/FeatureDefines.xcconfig: + +2015-03-14 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r181487. + https://bugs.webkit.org/show_bug.cgi?id=142695 + + Caused Speedometer/Full.html to fail (Requested by smfr on + #webkit). + + Reverted changeset: + + "DFG::PutStackSinkingPhase should eliminate GetStacks that + have an obviously known source" + https://bugs.webkit.org/show_bug.cgi?id=141624 + http://trac.webkit.org/changeset/181487 + +2015-03-14 Michael Saboff <msaboff@apple.com> + + ES6: Add binary and octal literal support + https://bugs.webkit.org/show_bug.cgi?id=142681 + + Reviewed by Ryosuke Niwa. + + Added a binary literal parser function, parseBinary(), to Lexer patterned after the octal parser. + Refactored the parseBinary, parseOctal and parseDecimal to use a constant size for the number of + characters to try and handle directly. Factored out the shifting past any prefix to be handled by + the caller. Added binary and octal parsing to toDouble() via helper functions. + + * parser/Lexer.cpp: + (JSC::Lexer<T>::parseHex): + (JSC::Lexer<T>::parseBinary): + (JSC::Lexer<T>::parseOctal): + (JSC::Lexer<T>::parseDecimal): + (JSC::Lexer<T>::lex): + * parser/Lexer.h: + * parser/ParserTokens.h: + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::jsBinaryIntegerLiteral): + (JSC::jsOctalIntegerLiteral): + (JSC::toDouble): + +2015-03-13 Alex Christensen <achristensen@webkit.org> + + Progress towards CMake on Mac. + https://bugs.webkit.org/show_bug.cgi?id=142680 + + Reviewed by Gyuyoung Kim. + + * PlatformMac.cmake: + Generate TracingDtrace.h based on project.pbxproj. + +2015-03-13 Filip Pizlo <fpizlo@apple.com> + + Object allocation sinking phase shouldn't re-decorate previously sunken allocations on each fixpoint operation + https://bugs.webkit.org/show_bug.cgi?id=142686 + + Reviewed by Oliver Hunt. + + Just because promoteHeapAccess() notifies us of an effect to a heap location in a node doesn't + mean that we should handle it as if it was for one of our sinking candidates. Instead we should + prune based on m_sinkCandidates. + + This fixes a benign bug where we would generate a lot of repeated IR for some pathological + tests. + + * dfg/DFGObjectAllocationSinkingPhase.cpp: + (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields): + +2015-03-13 Eric Carlson <eric.carlson@apple.com> + + [Mac] Enable WIRELESS_PLAYBACK_TARGET + https://bugs.webkit.org/show_bug.cgi?id=142635 + + Reviewed by Darin Adler. + + * Configurations/FeatureDefines.xcconfig: + +2015-03-13 Ryosuke Niwa <rniwa@webkit.org> + + Class constructor should throw TypeError when "called" + https://bugs.webkit.org/show_bug.cgi?id=142566 + + Reviewed by Michael Saboff. + + Added ConstructorKind::None to denote code that doesn't belong to an ES6 class. + This allows BytecodeGenerator to emit code to throw TypeError when generating code block + to call ES6 class constructors. + + Most of changes are about increasing the number of bits to store ConstructorKind from one + bit to two bits. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): + * bytecode/UnlinkedCodeBlock.h: + (JSC::ExecutableInfo::ExecutableInfo): + (JSC::ExecutableInfo::needsActivation): + (JSC::ExecutableInfo::usesEval): + (JSC::ExecutableInfo::isStrictMode): + (JSC::ExecutableInfo::isConstructor): + (JSC::ExecutableInfo::isBuiltinFunction): + (JSC::ExecutableInfo::constructorKind): + (JSC::UnlinkedFunctionExecutable::constructorKind): + (JSC::UnlinkedCodeBlock::constructorKind): + (JSC::UnlinkedFunctionExecutable::constructorKindIsDerived): Deleted. + (JSC::UnlinkedCodeBlock::constructorKindIsDerived): Deleted. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::generate): Don't emit bytecode when we had already emitted code + to throw TypeError. + (JSC::BytecodeGenerator::BytecodeGenerator): Emit code to throw TypeError when generating + code to call. + (JSC::BytecodeGenerator::emitReturn): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::constructorKind): + (JSC::BytecodeGenerator::constructorKindIsDerived): Deleted. + * bytecompiler/NodesCodegen.cpp: + (JSC::ThisNode::emitBytecode): + (JSC::FunctionCallValueNode::emitBytecode): + * parser/Nodes.cpp: + (JSC::FunctionBodyNode::FunctionBodyNode): + * parser/Nodes.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): Renamed the incoming function argument to + ownerClassKind. Set constructorKind to Base or Derived only if we're parsing a constructor. + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseClass): Don't parse static methods using MethodMode since that + would result in BytecodeGenerator erroneously treating static method named "constructor" as + a class constructor. + (JSC::Parser<LexerType>::parsePropertyMethod): + (JSC::Parser<LexerType>::parsePrimaryExpression): + * parser/Parser.h: + * parser/ParserModes.h: + * runtime/Executable.h: + (JSC::EvalExecutable::executableInfo): + (JSC::ProgramExecutable::executableInfo): + +2015-03-13 Filip Pizlo <fpizlo@apple.com> + + DFG::PutStackSinkingPhase should eliminate GetStacks that have an obviously known source + https://bugs.webkit.org/show_bug.cgi?id=141624 + + Reviewed by Oliver Hunt. + + This was an obvious omission from the original PutStackSinkingPhase. Previously, we would treat + GetStacks conservatively and assume that the stack slot escaped. That's pretty dumb, since a + GetStack is a local load of the stack. This change makes GetStack a no-op from the standpoint of + this phase's deferral analysis. At the end we either keep the GetStack (if there was no concrete + deferral) or we replace it with an identity over the value that would have been stored by the + deferred PutStack. Note that this might be a Phi that the phase creates, so this is strictly + stronger than what GCSE could do. + + This is probably not a speed-up now, but it will be very useful for the varargs simplification + done in bug 141174. + + * dfg/DFGPutStackSinkingPhase.cpp: + +2015-03-12 Geoffrey Garen <ggaren@apple.com> + + Prohibit GC while sweeping + https://bugs.webkit.org/show_bug.cgi?id=142638 + + Reviewed by Andreas Kling. + + I noticed in https://bugs.webkit.org/show_bug.cgi?id=142636 that a GC + could trigger a sweep which could trigger another GC. Yo Dawg. + + I tried to figure out whether this could cause problems or not and it + made me cross-eyed. + + (Some clients like to report extra memory cost during deallocation as a + way to indicate that the GC now owns something exclusively. It's + arguably a bug to communicate with the GC in this way, but we shouldn't + do crazy when this happens.) + + This patch makes explicit the fact that we don't allow GC while sweeping. + + Usually, sweeping implicitly defers GC by virtue of happening during + allocation. But not always. + + * heap/Heap.cpp: + (JSC::Heap::collectAllGarbage): Defer GC while sweeping due to an + explicit GC request. + + (JSC::Heap::didFinishCollection): Make sure that zombifying sweep + defers GC by not returning to the non-GC state until we're all done. + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::sweepNextBlock): Defer GC while sweeping due + to a timer. + +2015-03-13 Mark Lam <mark.lam@apple.com> + + Replace TCSpinLock with a new WTF::SpinLock based on WTF::Atomic. + <https://webkit.org/b/142674> + + Reviewed by Filip Pizlo. + + * API/JSValue.mm: + (handerForStructTag): + * API/JSWrapperMap.mm: + * dfg/DFGCommon.cpp: + (JSC::DFG::startCrashing): + (JSC::DFG::isCrashing): + - Changed to use a StaticSpinLock since that's what this code was trying to do + anyway. + * heap/CopiedBlock.h: + (JSC::CopiedBlock::CopiedBlock): + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::CopiedSpace): + * heap/CopiedSpace.h: + * heap/GCThreadSharedData.cpp: + (JSC::GCThreadSharedData::GCThreadSharedData): + * heap/GCThreadSharedData.h: + * heap/ListableHandler.h: + (JSC::ListableHandler::List::List): + * parser/SourceProvider.cpp: + * profiler/ProfilerDatabase.cpp: + (JSC::Profiler::Database::addDatabaseToAtExit): + (JSC::Profiler::Database::removeDatabaseFromAtExit): + (JSC::Profiler::Database::removeFirstAtExitDatabase): + +2015-03-13 Ryosuke Niwa <rniwa@webkit.org> + + BytecodeGenerator needs to be re-entrant to support miranda functions + https://bugs.webkit.org/show_bug.cgi?id=142627 + + Reviewed by Filip Pizlo. + + Made CodeCache::getGlobalCodeBlock and CodeCache::getFunctionExecutableFromGlobalCode re-entrant + by not keeping AddResult while invoking BytecodeGenerator::generate. + + This is needed to support Miranda functions since they need to be lazily initialized. + + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + * runtime/CodeCache.h: + (JSC::CodeCacheMap::findCacheAndUpdateAge): Extracted from add. + (JSC::CodeCacheMap::addCache): Extracted from add. + (JSC::CodeCacheMap::add): Deleted. + +2015-03-13 Mark Lam <mark.lam@apple.com> + + Introduce WTF::Atomic to wrap std::atomic for a friendlier CAS. + <https://webkit.org/b/142661> + + Reviewed by Filip Pizlo. + + Changed CodeBlock, and the DFG's crashLock to use WTF::Atomic instead of + std::atomic. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::visitAggregate): + * bytecode/CodeBlock.h: + * dfg/DFGCommon.cpp: + (JSC::DFG::startCrashing): + +2015-03-12 Mark Lam <mark.lam@apple.com> + + Change the DFG crashLock to use std::atomic. + <https://webkit.org/b/142649> + + Reviewed by Filip Pizlo. + + * dfg/DFGCommon.cpp: + (JSC::DFG::startCrashing): + (JSC::DFG::isCrashing): + +2015-03-12 Filip Pizlo <fpizlo@apple.com> + + Bytecode liveness analysis should have more lambdas and fewer sets + https://bugs.webkit.org/show_bug.cgi?id=142647 + + Reviewed by Mark Lam. + + In bug 141174 I'll need to identify all of the bytecode kill sites. This requires hooking into + the bytecode analysis' stepOverFunction method, except in such a way that we observe uses that + are not in outs. This refactors stepOverFunction so that you can pass it use/def functors that + can either be used to propagate outs (as we do right now) or to additionally detect kills or + whatever else. + + In order to achieve this, the liveness analysis was moved off of maintaining uses/defs + bitvectors. This wasn't helping the abstraction and was probably inefficient. The new code + should be a bit faster since we don't have to clear uses/defs bitvectors on each instruction. On + the other hand, being able to intercept each use means that our code for exception handlers is + no longer a bitwise-merge; it requires finding set bits. Fortunately, this code only kicks in + for instructions inside a try, and its performance is O(live at catch), so that's probably not + bad. + + * bytecode/BytecodeLivenessAnalysis.cpp: + (JSC::indexForOperand): + (JSC::stepOverInstruction): + (JSC::computeLocalLivenessForBytecodeOffset): + (JSC::BytecodeLivenessAnalysis::computeFullLiveness): + (JSC::setForOperand): Deleted. + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + +2015-03-12 Ryosuke Niwa <rniwa@webkit.org> + + "this" should be in TDZ until super is called in the constructor of a derived class + https://bugs.webkit.org/show_bug.cgi?id=142527 + + Reviewed by Mark Hahnenberg. + + DFG and FTL implementations co-authored by Filip Pizlo. + + In ES6 class syntax, "this" register must be in the "temporal dead zone" (TDZ) and throw ReferenceError until + super() is called inside the constructor of a derived class. + + Added op_check_tdz, a new OP code, which throws a reference error when the first operand is an empty value + to all tiers of JIT and LLint. The op code throws in the slow path on the basis that a TDZ error should be + a programming error and not a part of the programs' normal control flow. In DFG, this op code is represented + by a no-op must-generate node CheckNotEmpty modeled after CheckCell. + + Also made the constructor of a derived class assign the empty value to "this" register rather than undefined + so that ThisNode can emit the op_check_tdz to check the initialized-ness of "this" in such a constructor. + + * bytecode/BytecodeList.json: Added op_check_tdz. + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): Ditto. + (JSC::computeDefsForBytecodeOffset): Ditto. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Ditto. + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): Added TDZFailure. + * bytecode/ExitKind.h: Ditto. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): Assign the empty value to "this" register to indicate it's in TDZ. + (JSC::BytecodeGenerator::emitTDZCheck): Added. + (JSC::BytecodeGenerator::emitReturn): Emit the TDZ check since "this" can still be in TDZ if super() was never + called. e.g. class B extends A { constructor() { } } + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ThisNode::emitBytecode): Always emit the TDZ check if we're inside the constructor of a derived class. + We can't omit this check even if the result was ignored per spec. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): Previously, empty value could never appear + in a local variable. This is no longer true so generalize this code. Also added the support for CheckNotEmpty. + Like CheckCell, we phantomize this DFG node in the constant folding phase if the type of the operand is already + found to be not empty. Otherwise filter out SpecEmpty. + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): Added op_check_tdz. + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): op_check_tdz can be compiled and inlined. + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): CheckNotEmpty doesn't read or write values. + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): Convert CheckNotEmpty to a phantom if non-emptiness had already + been proven for the operand prior to this node. + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): CheckNotEmpty does not trigger GC. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): CheckNotEmpty is a no-op in the fixup phase. + * dfg/DFGNodeType.h: CheckNotEmpty cannot be removed even if the result was ignored. See ThisNode::emitBytecode. + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): CheckNotEmpty doesn't return any value. + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): CheckNotEmpty doesn't load from heap so it's safe. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): Speculative the operand to be not empty. OSR exit if the speculation fails. + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): Ditto. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): CheckNotEmpty can be compiled in FTL. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): Calls compileCheckNotEmpty for CheckNotEmpty. + (JSC::FTL::LowerDFGToLLVM::compileCheckNotEmpty): OSR exit with "TDZFailure" if the operand is not empty. + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): Added op_check_tdz. + (JSC::JIT::privateCompileSlowCases): Ditto. + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_check_tdz): Implements op_check_tdz in Baseline JIT. + (JSC::JIT::emitSlow_op_check_tdz): Ditto. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_check_tdz): Ditto. + (JSC::JIT::emitSlow_op_check_tdz): Ditto. + * llint/LowLevelInterpreter32_64.asm: Implements op_check_tdz in LLint. + * llint/LowLevelInterpreter64.asm: Ditto. + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): Throws a reference error for op_check_tdz. Shared by LLint and Baseline JIT. + * runtime/CommonSlowPaths.h: + * tests/stress/class-syntax-no-loop-tdz.js: Added. + * tests/stress/class-syntax-no-tdz-in-catch.js: Added. + * tests/stress/class-syntax-no-tdz-in-conditional.js: Added. + * tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js: Added. + * tests/stress/class-syntax-no-tdz-in-loop.js: Added. + * tests/stress/class-syntax-no-tdz.js: Added. + * tests/stress/class-syntax-tdz-in-catch.js: Added. + * tests/stress/class-syntax-tdz-in-conditional.js: Added. + * tests/stress/class-syntax-tdz-in-loop.js: Added. + * tests/stress/class-syntax-tdz.js: Added. + +2015-03-12 Yusuke Suzuki <utatane.tea@gmail.com> + + Integrate MapData into JSMap and JSSet + https://bugs.webkit.org/show_bug.cgi?id=142556 + + Reviewed by Filip Pizlo. + + This patch integrates MapData into JSMap and JSSet. + This removes 2 object allocation per one JSMap / JSSet. + + MapDataImpl is specialized into MapData and SetData. + In the case of SetData, it does not have the dummy values + previously stored in the MapDataImpl. So the storage size of SetData + becomes the half of the previous implementation. + + And now MapData and SetData are completely integrated into JSMap and JSSet, + these structures are not exposed to the other code even in WebCore world. + + And at the same time, this patch fixes missing destroy functions + in JSMapIterator and JSSetIterator. + They are needed because MapData::const_iterator is a non-trivial destructor. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/JSMap.cpp: + (JSC::JSMap::destroy): + (JSC::JSMap::visitChildren): + (JSC::JSMap::copyBackingStore): + (JSC::JSMap::has): + (JSC::JSMap::size): + (JSC::JSMap::get): + (JSC::JSMap::set): + (JSC::JSMap::clear): + (JSC::JSMap::remove): + (JSC::JSMap::finishCreation): Deleted. + * runtime/JSMap.h: + (JSC::JSMap::Entry::key): + (JSC::JSMap::Entry::value): + (JSC::JSMap::Entry::visitChildren): + (JSC::JSMap::Entry::setKey): + (JSC::JSMap::Entry::setKeyWithoutWriteBarrier): + (JSC::JSMap::Entry::setValue): + (JSC::JSMap::Entry::clear): + (JSC::JSMap::begin): + (JSC::JSMap::end): + (JSC::JSMap::JSMap): + (JSC::JSMap::mapData): Deleted. + * runtime/JSMapIterator.cpp: + (JSC::JSMapIterator::finishCreation): + (JSC::JSMapIterator::destroy): + (JSC::JSMapIterator::visitChildren): + * runtime/JSMapIterator.h: + (JSC::JSMapIterator::JSMapIterator): + * runtime/JSSet.cpp: + (JSC::JSSet::destroy): + (JSC::JSSet::visitChildren): + (JSC::JSSet::copyBackingStore): + (JSC::JSSet::has): + (JSC::JSSet::size): + (JSC::JSSet::add): + (JSC::JSSet::clear): + (JSC::JSSet::remove): + (JSC::JSSet::finishCreation): Deleted. + * runtime/JSSet.h: + (JSC::JSSet::Entry::key): + (JSC::JSSet::Entry::value): + (JSC::JSSet::Entry::visitChildren): + (JSC::JSSet::Entry::setKey): + (JSC::JSSet::Entry::setKeyWithoutWriteBarrier): + (JSC::JSSet::Entry::setValue): + (JSC::JSSet::Entry::clear): + (JSC::JSSet::begin): + (JSC::JSSet::end): + (JSC::JSSet::JSSet): + (JSC::JSSet::mapData): Deleted. + * runtime/JSSetIterator.cpp: + (JSC::JSSetIterator::finishCreation): + (JSC::JSSetIterator::visitChildren): + (JSC::JSSetIterator::destroy): + * runtime/JSSetIterator.h: + (JSC::JSSetIterator::JSSetIterator): + * runtime/MapConstructor.cpp: + (JSC::constructMap): + * runtime/MapData.h: + (JSC::MapDataImpl::const_iterator::key): + (JSC::MapDataImpl::const_iterator::value): + (JSC::MapDataImpl::size): + (JSC::MapDataImpl<Entry>::MapDataImpl): + (JSC::MapDataImpl<Entry>::clear): + (JSC::MapDataImpl<Entry>::KeyType::KeyType): + (JSC::MapDataImpl<Entry>::const_iterator::internalIncrement): + (JSC::MapDataImpl<Entry>::const_iterator::ensureSlot): + (JSC::MapDataImpl<Entry>::const_iterator::const_iterator): + (JSC::MapDataImpl<Entry>::const_iterator::~const_iterator): + (JSC::MapDataImpl<Entry>::const_iterator::operator): + (JSC::=): + (JSC::MapData::const_iterator::key): Deleted. + (JSC::MapData::const_iterator::value): Deleted. + (JSC::MapData::create): Deleted. + (JSC::MapData::createStructure): Deleted. + (JSC::MapData::size): Deleted. + (JSC::MapData::clear): Deleted. + (JSC::MapData::KeyType::KeyType): Deleted. + (JSC::MapData::const_iterator::internalIncrement): Deleted. + (JSC::MapData::const_iterator::ensureSlot): Deleted. + (JSC::MapData::const_iterator::const_iterator): Deleted. + (JSC::MapData::const_iterator::~const_iterator): Deleted. + (JSC::MapData::const_iterator::operator*): Deleted. + (JSC::MapData::const_iterator::end): Deleted. + (JSC::MapData::const_iterator::operator!=): Deleted. + (JSC::MapData::const_iterator::operator==): Deleted. + * runtime/MapDataInlines.h: Renamed from Source/JavaScriptCore/runtime/MapData.cpp. + (JSC::MapDataImpl<Entry>::find): + (JSC::MapDataImpl<Entry>::contains): + (JSC::MapDataImpl<Entry>::add): + (JSC::MapDataImpl<Entry>::set): + (JSC::MapDataImpl<Entry>::get): + (JSC::MapDataImpl<Entry>::remove): + (JSC::MapDataImpl<Entry>::replaceAndPackBackingStore): + (JSC::MapDataImpl<Entry>::replaceBackingStore): + (JSC::MapDataImpl<Entry>::ensureSpaceForAppend): + (JSC::MapDataImpl<Entry>::visitChildren): + (JSC::MapDataImpl<Entry>::copyBackingStore): + * runtime/MapPrototype.cpp: + (JSC::getMap): + (JSC::mapProtoFuncClear): + (JSC::mapProtoFuncDelete): + (JSC::mapProtoFuncForEach): + (JSC::mapProtoFuncGet): + (JSC::mapProtoFuncHas): + (JSC::mapProtoFuncSet): + (JSC::mapProtoFuncSize): + (JSC::getMapData): Deleted. + * runtime/SetPrototype.cpp: + (JSC::getSet): + (JSC::setProtoFuncAdd): + (JSC::setProtoFuncClear): + (JSC::setProtoFuncDelete): + (JSC::setProtoFuncForEach): + (JSC::setProtoFuncHas): + (JSC::setProtoFuncSize): + (JSC::getMapData): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2015-03-12 Mark Lam <mark.lam@apple.com> + + Use std::atomic for CodeBlock::m_visitAggregateHasBeenCalled. + <https://webkit.org/b/142640> + + Reviewed by Mark Hahnenberg. + + We used to spin our own compare and swap on a uint8_t. Now that we can + use C++11, let's use std::atomic instead. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::visitAggregate): + - The CAS here needs std::memory_order_acquire ordering because it + requires lock acquisition semantics to visit the CodeBlock. + + * bytecode/CodeBlock.h: + (JSC::CodeBlockSet::mark): + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::clearMarksForFullCollection): + (JSC::CodeBlockSet::clearMarksForEdenCollection): + - These can go with relaxed ordering because they are all done before + the GC starts parallel marking. + +2015-03-12 Csaba Osztrogonác <ossy@webkit.org> + + [cmake] Fix the incremental build issue revealed by r181419 + https://bugs.webkit.org/show_bug.cgi?id=142613 + + Reviewed by Carlos Garcia Campos. + + * CMakeLists.txt: + +2015-03-11 Ryosuke Niwa <rniwa@webkit.org> + + "static" should not be a reserved keyword in non-strict mode even when ES6 class is enabled + https://bugs.webkit.org/show_bug.cgi?id=142600 + + Reviewed by Mark Lam. + + Make "static" RESERVED_IF_STRICT and manually detect it in parseClass. + + No new tests. This is already checked by js/reserved-words.html and js/keywords-and-reserved_words.html + + * parser/Keywords.table: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + * parser/ParserTokens.h: + +2015-03-11 Geoffrey Garen <ggaren@apple.com> + + Many users of Heap::reportExtraMemory* are wrong, causing lots of memory growth + https://bugs.webkit.org/show_bug.cgi?id=142593 + + Reviewed by Andreas Kling. + + Adopt deprecatedReportExtraMemory as a short-term fix for runaway + memory growth in these cases where we have not adopted + reportExtraMemoryVisited. + + Long-term, we should use reportExtraMemoryAllocated+reportExtraMemoryVisited. + That's tracked by https://bugs.webkit.org/show_bug.cgi?id=142595. + + * API/JSBase.cpp: + (JSReportExtraMemoryCost): + * runtime/SparseArrayValueMap.cpp: + (JSC::SparseArrayValueMap::add): + +2015-03-11 Geoffrey Garen <ggaren@apple.com> + + Refactored the JSC::Heap extra cost API for clarity and to make some known bugs more obvious + https://bugs.webkit.org/show_bug.cgi?id=142589 + + Reviewed by Andreas Kling. + + * API/JSBase.cpp: + (JSReportExtraMemoryCost): Added a FIXME to annotate a known bug. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::visitAggregate): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::setJITCode): Updated for rename. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::reportExtraMemoryAllocatedSlowCase): + (JSC::Heap::deprecatedReportExtraMemorySlowCase): Renamed our reporting + APIs to clarify their relationship to each other: One must report extra + memory at the time of allocation, and at the time the GC visits it. + + (JSC::Heap::extraMemorySize): + (JSC::Heap::size): + (JSC::Heap::capacity): + (JSC::Heap::sizeAfterCollect): + (JSC::Heap::willStartCollection): Updated for renames. Added explicit + API for deprecated users who can't use our best API. + + (JSC::Heap::reportExtraMemoryCostSlowCase): Deleted. + (JSC::Heap::extraSize): Deleted. + + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::reportExtraMemoryAllocated): + (JSC::Heap::reportExtraMemoryVisited): + (JSC::Heap::deprecatedReportExtraMemory): + (JSC::Heap::reportExtraMemoryCost): Deleted. Ditto. + + * heap/SlotVisitor.h: + * heap/SlotVisitorInlines.h: + (JSC::SlotVisitor::reportExtraMemoryVisited): + (JSC::SlotVisitor::reportExtraMemoryUsage): Deleted. Moved this + functionality into the Heap since it's pretty detailed in its access + to the heap. + + * runtime/JSArrayBufferView.cpp: + (JSC::JSArrayBufferView::ConstructionContext::ConstructionContext): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::visitChildren): Updated for + renames. + + * runtime/JSString.cpp: + (JSC::JSString::visitChildren): + (JSC::JSRopeString::resolveRopeToAtomicString): + (JSC::JSRopeString::resolveRope): + * runtime/JSString.h: + (JSC::JSString::finishCreation): Updated for renames. + + * runtime/SparseArrayValueMap.cpp: + (JSC::SparseArrayValueMap::add): Added FIXME. + + * runtime/WeakMapData.cpp: + (JSC::WeakMapData::visitChildren): Updated for rename. + +2015-03-11 Ryosuke Niwa <rniwa@webkit.org> + + Calling super() in a base class results in a crash + https://bugs.webkit.org/show_bug.cgi?id=142563 + + Reviewed by Filip Pizlo. + + The bug was caused by BytecodeGenerator trying to generate "super" expression inside the constructor of a base class. + Disallow that by keeping track of whether "super" has been used in the current scope or not (needsSuperBinding flag) + and then throwing a syntax error in parseFunctionInfo if it was used and the current scope wasn't the constructor of + a derived class. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): Don't allow super() or super.foo outside the constructor of a derived class. + (JSC::Parser<LexerType>::parseClass): Pass in the constructor kind to parseGetterSetter. + (JSC::Parser<LexerType>::parseGetterSetter): Ditto to parseFunctionInfo. + (JSC::Parser<LexerType>::parseMemberExpression): Set needsSuperBinding flag true on the containing scope. + * parser/Parser.h: + (JSC::Scope::Scope): + (JSC::Scope::needsSuperBinding): Added. + (JSC::Scope::setNeedsSuperBinding): Added. + +2015-03-10 Darin Adler <darin@apple.com> + + Some event handler fixes + https://bugs.webkit.org/show_bug.cgi?id=142474 + + Reviewed by Anders Carlsson. + + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::createInjectedScript): Call clearException. + I spotted the fact it was missing by auditing all the calls to JSC::call. + +2015-03-10 Matthew Mirman <mmirman@apple.com> + + Functions should have initialization precedence over arguments. + https://bugs.webkit.org/show_bug.cgi?id=142550 + rdar://problem/19702564 + + Reviewed by Geoffrey Garen. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::initializeCapturedVariable): + * tests/stress/initialize_functions_after_arguments.js: Added. + +2015-03-10 Andreas Kling <akling@apple.com> + + Eden collections should trigger sweep of MarkedBlocks containing new objects. + <https://webkit.org/b/142538> + + Reviewed by Geoffrey Garen. + + Take a snapshot of all MarkedBlocks with new objects as part of Eden collections, + and append that to the IncrementalSweeper's working set. + + This ensures that we run destructors for objects that were discovered to be garbage during + Eden collections, instead of delaying their teardown until the next full collection, + or the next allocation cycle for their block. + + * heap/Heap.cpp: + (JSC::Heap::snapshotMarkedSpace): For Eden collections, snapshot the list of MarkedBlocks + that contain new objects, since those are the only ones we're interested in. + Also use Vector::resizeToFit() to allocate the snapshot for full collections, since we know + the final size we need up front. + + (JSC::Heap::notifyIncrementalSweeper): For Eden collections, tell the IncrementalSweeper + to add the block snapshot (taken earlier) to its existing set of blocks instead of replacing + it entirely. This allows Eden collections and incremental sweeping to occur interleaved with + each other without missing destruction opportunities. + + * heap/IncrementalSweeper.h: + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::doSweep): + (JSC::IncrementalSweeper::sweepNextBlock): Change the way we iterate over the sweeper's + work list: instead of keeping an index for the next block, just pop from the end of the list. + This allows us to add new blocks and deduplicate the list without disturbing iteration. + + (JSC::IncrementalSweeper::startSweeping): Make this take a Vector<MarkedBlock>&& so we can + pass ownership of this Vector efficiently from Heap to IncrementalSweeper. + + (JSC::IncrementalSweeper::addBlocksAndContinueSweeping): Added. This is used by Eden + collections to add a set of MarkedBlocks with new objects to the sweeper's existing + working set and kick the timer. + + * heap/MarkedSpace.h: + (JSC::MarkedSpace::blocksWithNewObjects): Expose the list of MarkedBlocks with new objects. + +2015-03-10 Alex Christensen <achristensen@webkit.org> + + Use unsigned for HashSet size. + https://bugs.webkit.org/show_bug.cgi?id=142518 + + Reviewed by Benjamin Poulain. + + * dfg/DFGAvailabilityMap.cpp: + (JSC::DFG::AvailabilityMap::prune): + * ftl/FTLOSRExitCompiler.cpp: + (JSC::FTL::compileStub): + * heap/MarkedBlockSet.h: + (JSC::MarkedBlockSet::remove): + * runtime/WeakMapData.h: + +2015-03-10 Mark Lam <mark.lam@apple.com> + + Use std::numeric_limits<unsigned>::max() instead of (unsigned)-1. + <https://webkit.org/b/142539> + + Reviewed by Benjamin Poulain. + + * jit/JIT.cpp: + (JSC::JIT::JIT): + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + (JSC::JIT::privateCompile): + (JSC::JIT::privateCompileExceptionHandlers): + * jit/JITInlines.h: + (JSC::JIT::emitNakedCall): + (JSC::JIT::addSlowCase): + (JSC::JIT::addJump): + (JSC::JIT::emitJumpSlowToHot): + (JSC::JIT::emitGetVirtualRegister): + * jit/SlowPathCall.h: + (JSC::JITSlowPathCall::call): + * yarr/Yarr.h: + +2015-03-10 Mark Lam <mark.lam@apple.com> + + [Win] JSC Build Warnings Need to be Resolved. + <https://webkit.org/b/142366> + + Reviewed by Brent Fulgham. + + Applied some benign changes to make the MSVC compiler happy. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::fillJSValue): + * runtime/BasicBlockLocation.cpp: + (JSC::BasicBlockLocation::getExecutedRanges): + * runtime/ControlFlowProfiler.cpp: + (JSC::ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted): + +2015-03-10 Yusuke Suzuki <utatane.tea@gmail.com> + + Upgrade Map, Set and WeakMap constructor interface + https://bugs.webkit.org/show_bug.cgi?id=142348 + + Reviewed by Filip Pizlo. + + In the latest ES6 spec, Map and Set constructors take initialization data sets + as iterable value. And iterate it and add the values into the constructed one. + + This is breaking change because the old constructor interface is + already shipped in Safari 8. + + * runtime/MapConstructor.cpp: + (JSC::callMap): + (JSC::constructMap): + (JSC::MapConstructor::getCallData): + * runtime/SetConstructor.cpp: + (JSC::callSet): + (JSC::constructSet): + * runtime/WeakMapConstructor.cpp: + (JSC::callWeakMap): + (JSC::constructWeakMap): + (JSC::WeakMapConstructor::getCallData): + * tests/stress/map-constructor-adder.js: Added. + * tests/stress/map-constructor.js: Added. + (testCallTypeError): + (testTypeError): + (for): + * tests/stress/set-constructor-adder.js: Added. + (Set.prototype.add): + * tests/stress/set-constructor.js: Added. + (for): + * tests/stress/weak-map-constructor-adder.js: Added. + * tests/stress/weak-map-constructor.js: Added. + (testCallTypeError): + (testTypeError): + (for): + +2015-03-10 Michael Catanzaro <mcatanzaro@igalia.com> + + GCC: CRASH() should be annotated with NORETURN + https://bugs.webkit.org/show_bug.cgi?id=142524 + + Reviewed by Anders Carlsson. + + Don't return from a NORETURN function. This used to avoid a warning from GCC, but now it + causes one. + + * jsc.cpp: + +2015-03-10 Mark Lam <mark.lam@apple.com> + + Gardening: fix bleeding debug test bots. + https://webkit.org/b/142513> + + Not reviewed. + + The test needs to initialize WTF threading explicitly before using it. + + * API/tests/CompareAndSwapTest.cpp: + (testCompareAndSwap): + +2015-03-10 Alex Christensen <achristensen@webkit.org> + + [WinCairo] Unreviewed build fix. + + * JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props: + Added directory containing config.h, like r181304. + +2015-03-09 Mark Lam <mark.lam@apple.com> + + Yet another build fix for Windows. + https://webkit.org/b/142513> + + Reviewed by Alex Christensen. + + Looks like MSVC requires the function be explicitly declared in a header file + in order for it to be linkable from another file in the same project. This is + strange, but it seems to make MSVC happy. + + Also fixed a typo in testapi.vcxproj.filters. + + * API/tests/CompareAndSwapTest.cpp: + * API/tests/CompareAndSwapTest.h: Added. + * API/tests/testapi.c: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-03-09 Chris Dumez <cdumez@apple.com> + + [iOS] Sweep all collected objects on critical memory pressure + https://bugs.webkit.org/show_bug.cgi?id=142457 + <rdar://problem/20044440> + + Reviewed by Geoffrey Garen. + + All fullSweep() API to IncrementalSweeper so that we can call it in the + memory pressure handler. + + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::fullSweep): + * heap/IncrementalSweeper.h: + (JSC::IncrementalSweeper::hasWork): + +2015-03-09 Mark Lam <mark.lam@apple.com> + + Another build fix for Windows. + https://webkit.org/b/142513> + + Not reviewed. + + * API/tests/CompareAndSwapTest.cpp: + - Added JS_EXPORT_PRIVATE attribute. + +2015-03-09 Mark Lam <mark.lam@apple.com> + + Build fix for Windows after r181305. + https://webkit.org/b/142513> + + Reviewed by Alex Christensen. + + Windows doesn't like pthreads anymore. Changed test to use WTF threading. + + * API/tests/CompareAndSwapTest.cpp: + (setBitThreadFunc): + (testCompareAndSwap): + +2015-03-09 Mark Lam <mark.lam@apple.com> + + 8-bit version of weakCompareAndSwap() can cause an infinite loop. + https://webkit.org/b/142513> + + Reviewed by Filip Pizlo. + + Added a test that exercises the 8-bit CAS from multiple threads. The threads + will contend to set bits in a large array of bytes using the CAS function. + + * API/tests/CompareAndSwapTest.cpp: Added. + (Bitmap::Bitmap): + (Bitmap::numBits): + (Bitmap::clearAll): + (Bitmap::concurrentTestAndSet): + (setBitThreadFunc): + (testCompareAndSwap): + * API/tests/testapi.c: + (main): + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-03-09 Brent Fulgham <bfulgham@apple.com> + + [Win] testapi project is unable to find the 'config.h' file. + + Rubberstamped by Mark Lam. + + * JavaScriptCore.vcxproj/testapi/testapiCommon.props: Add JavaScriptCore source directory + to the include path. + +2015-03-09 Andreas Kling <akling@apple.com> + + Stale entries in WeakGCMaps are keeping tons of WeakBlocks alive unnecessarily. + <https://webkit.org/b/142115> + <rdar://problem/19992268> + + Reviewed by Geoffrey Garen. + + Prune stale entries from WeakGCMaps as part of every full garbage collection. + This frees up tons of previously-stuck WeakBlocks that were only sitting around + with finalized handles waiting to die. + + Note that WeakGCMaps register/unregister themselves with the GC heap in their + ctor/dtor, so creating one now requires passing the VM. + + Average time spent in the PruningStaleEntriesFromWeakGCMaps GC phase appears + to be between 0.01ms and 0.3ms, though I've seen a few longer ones at ~1.2ms. + It seems somewhat excessive to do this on every Eden collection, so it's only + doing work in full collections for now. + + Because the GC may now mutate WeakGCMap below object allocation, I've made it + so that the classic HashMap::add() optimization can't be used with WeakGCMap. + This caused intermittent test failures when originally landed due to having + an invalid iterator on the stack after add() inserted a new entry and we + proceeded to allocate the new object, triggering GC. + + * API/JSWeakObjectMapRefInternal.h: + (OpaqueJSWeakObjectMap::create): + (OpaqueJSWeakObjectMap::OpaqueJSWeakObjectMap): + * API/JSWeakObjectMapRefPrivate.cpp: + * API/JSWrapperMap.mm: + (-[JSWrapperMap initWithContext:]): + (-[JSWrapperMap jsWrapperForObject:]): Pass VM to WeakGCMap constructor. + + * JavaScriptCore.xcodeproj/project.pbxproj: Add WeakGCMapInlines.h and make + it project-private so WebCore clients can access it. + + * heap/Heap.cpp: + (JSC::Heap::collect): + (JSC::Heap::pruneStaleEntriesFromWeakGCMaps): Added a new GC phase for pruning + stale entries from WeakGCMaps. This is only executed during full collections. + + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::registerWeakGCMap): + (JSC::Heap::unregisterWeakGCMap): Added a mechanism for WeakGCMaps to register + themselves with the Heap and provide a pruning callback. + + * runtime/PrototypeMap.h: + (JSC::PrototypeMap::PrototypeMap): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::add): Pass VM to WeakGCMap constructor. + + * runtime/JSCInlines.h: Add "WeakGCMapInlines.h" + + * runtime/JSGlobalObject.cpp: Include "WeakGCMapInlines.h" so this builds. + + * runtime/JSString.cpp: + (JSC::jsStringWithCacheSlowCase): + * runtime/PrototypeMap.cpp: + (JSC::PrototypeMap::addPrototype): + (JSC::PrototypeMap::emptyObjectStructureForPrototype): Remove HashMap add() + optimization since it's not safe in the GC-managed WeakGCMap world. + + * runtime/VM.cpp: + (JSC::VM::VM): Pass VM to WeakGCMap constructor. + + * runtime/WeakGCMap.h: + (JSC::WeakGCMap::set): + (JSC::WeakGCMap::add): + (JSC::WeakGCMap::WeakGCMap): Deleted. + (JSC::WeakGCMap::gcMap): Deleted. + (JSC::WeakGCMap::gcMapIfNeeded): Deleted. + * runtime/WeakGCMapInlines.h: Added. + (JSC::WeakGCMap::WeakGCMap): + (JSC::WeakGCMap::~WeakGCMap): + (JSC::WeakGCMap::pruneStaleEntries): Moved ctor, dtor and pruning callback + to WeakGCMapInlines.h to fix interdependent header issues. Removed code that + prunes WeakGCMap at certain growth milestones and instead rely on the GC + callback for housekeeping. + +2015-03-09 Ryosuke Niwa <rniwa@webkit.org> + + Support extends and super keywords + https://bugs.webkit.org/show_bug.cgi?id=142200 + + Reviewed by Filip Pizlo. + + Added the support for ES6 class syntax inheritance. + + Added ConstructorKind as well as boolean flags indicating the constructor kind to + various classes in UnlinkedCodeBlock as well as AST nodes. + + Each method stores the associated class as its homeObjectPrivateName. This value is used to + make super calls. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): + + * bytecode/UnlinkedCodeBlock.h: + (JSC::ExecutableInfo::ExecutableInfo): + (JSC::UnlinkedFunctionExecutable::constructorKindIsDerived): Added. + (JSC::UnlinkedCodeBlock::constructorKindIsDerived): Added. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): Don't emit op_create_this in a derived class + as the object is allocated by the highest base class's constructor. Also set "this" to null + and store the original value in m_newTargetRegister. "this" is supposed to be in TDZ but + that will be implemented in a separate patch. + (JSC::BytecodeGenerator::emitReturn): Allow "undefined" to be returned from a derived class. + In a derived class's constructor, not returning "undefined" or an object results in a type + error instead of "this" being returned. + (JSC::BytecodeGenerator::emitThrowTypeError): Added. + + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::constructorKindIsDerived): Added. + (JSC::BytecodeGenerator::newTarget): Added. + + * bytecompiler/NodesCodegen.cpp: + (JSC::SuperNode::emitBytecode): Added. Emits the code to obtain the callee's parent class. + (JSC::emitSuperBaseForCallee): Added. Emits the code to obtain the parent class's prototype. + (JSC::emitPutHomeObject): Added. + (JSC::PropertyListNode::emitBytecode): Stores the home object when adding methods. + (JSC::PropertyListNode::emitPutConstantProperty): Ditto. + (JSC::BracketAccessorNode::emitBytecode): Added the support for super['foo']. + (JSC::DotAccessorNode::emitBytecode): Added the support for super.foo. + (JSC::FunctionCallValueNode::emitBytecode): Added the support for super(). + (JSC::FunctionCallBracketNode::emitBytecode): Added the support for super['foo'](). + (JSC::FunctionCallDotNode::emitBytecode): Added the support for super.foo(). + (JSC::DeleteBracketNode::emitBytecode): Forbid "delete super.foo". + (JSC::DeleteDotNode::emitBytecode): Forbid "delete super['foo']". + (JSC::ClassExprNode::emitBytecode): Added the support for "classHeritage". This is the main + logic for inheritance. When a class B inherits from a class A, set B.__proto__ to A and set + B.prototype.__proto__ to A.prototype. Throw exceptions when either A or A.__proto__ is not + an object. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::superExpr): Added. + + * parser/NodeConstructors.h: + (JSC::SuperNode::SuperNode): Added. + + * parser/Nodes.cpp: + (JSC::FunctionBodyNode::FunctionBodyNode): + + * parser/Nodes.h: + (JSC::ExpressionNode::isSuperNode): + (JSC::PropertyNode::type): + (JSC::PropertyNode::needsSuperBinding): + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionBody): + (JSC::Parser<LexerType>::parseFunctionInfo): Throw a parser error if super() is used outside + of class constructors. + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseClass): ConstructorKind is "derived" if and only if the parent + class is specified in the declaration / expression. + (JSC::Parser<LexerType>::parseGetterSetter): + (JSC::Parser<LexerType>::parsePrimaryExpression): + (JSC::Parser<LexerType>::parseMemberExpression): Added the support for "super()", "super.foo", + and "super['foo']". Throw a semantic error if "super" appears by itself. + + * parser/Parser.h: + (JSC::Scope::Scope): Added m_hasDirectSuper. This variable keeps track of the use of "super()" + so that parseFunctionInfo can spit an error if it's used outside of class constructors. + (JSC::Scope::hasDirectSuper): Added. + (JSC::Scope::setHasDirectSuper): Added. + + * parser/ParserModes.h: + (JSC::ConstructorKind): Added. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::superExpr): Added. + + * runtime/CommonIdentifiers.h: Added homeObjectPrivateName. + + * runtime/Executable.h: + (JSC::EvalExecutable::executableInfo): + (JSC::ProgramExecutable::executableInfo): + +2015-03-08 Andreas Kling <akling@apple.com> + + JITThunks keeps finalized Weaks around, pinning WeakBlocks. + <https://webkit.org/b/142454> + + Reviewed by Darin Adler. + + Make JITThunks a WeakHandleOwner so it can keep its host function map free of stale entries. + This fixes an issue I was seeing where a bunch of WeakBlocks stuck around with nothing but + finalized Weak<NativeExecutable> entries. + + * jit/JITThunks.h: + * jit/JITThunks.cpp: + (JSC::JITThunks::finalize): Make JITThunks inherit from WeakHandleOwner so it can receive + a callback when the NativeExecutables get garbage collected. + + (JSC::JITThunks::hostFunctionStub): Pass 'this' as the handle owner when creating Weaks. + +2015-03-08 Andreas Kling <akling@apple.com> + + BuiltinExecutables keeps finalized Weaks around, pinning WeakBlocks. + <https://webkit.org/b/142460> + + Reviewed by Geoffrey Garen. + + Make BuiltinExecutables a WeakHandleOwner so it can clear out its respective Weak members + if and when their pointees get garbage collected. + + This fixes an issue I've seen locally where a WeakBlock is pinned down by a single one of + these Weak<BuiltinExecutables>. + + * builtins/BuiltinExecutables.h: Make BuiltinExecutables inherit from WeakHandleOwner. + + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::finalize): Clear out the relevant member pointer when it's been + garbage collected. We use the WeakImpl's "context" field to pass the address of the member. + +2015-03-07 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the removal of BlockAllocator, which is now unused. + + * API/JSBase.cpp: + * CMakeLists.txt: + * JavaScriptCore.order: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/BlockAllocator.cpp: Removed. + * heap/BlockAllocator.h: Removed. + * heap/GCThreadSharedData.h: + * heap/HandleBlockInlines.h: + * heap/Heap.cpp: + (JSC::Heap::Heap): + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::blockAllocator): Deleted. + * heap/HeapTimer.cpp: + * heap/MarkedBlock.h: + * heap/MarkedSpace.h: + * heap/Region.h: Removed. + * heap/SuperRegion.cpp: Removed. + * heap/SuperRegion.h: Removed. + +2015-03-07 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r181010. + https://bugs.webkit.org/show_bug.cgi?id=142442 + + Broke media/video-src-invalid-poster.html (Requested by kling + on #webkit). + + Reverted changeset: + + "Stale entries in WeakGCMaps are keeping tons of WeakBlocks + alive unnecessarily." + https://bugs.webkit.org/show_bug.cgi?id=142115 + http://trac.webkit.org/changeset/181010 + +2015-03-07 Ryosuke Niwa <rniwa@webkit.org> + + The code to link FunctionExecutable is duplicated everywhere + https://bugs.webkit.org/show_bug.cgi?id=142436 + + Reviewed by Darin Adler. + + Reduced code duplication by factoring out linkInsideExecutable and linkGlobalCode. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): Calls linkInsideExecutable. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::linkInsideExecutable): Renamed from link. Now takes care of startOffset. + This change was needed to use this function in CodeBlock::CodeBlock. Also, this function no longer takes + lineOffset since this information is already stored in the source code. + (JSC::UnlinkedFunctionExecutable::linkGlobalCode): Extracted from FunctionExecutable::fromGlobalCode. + + * bytecode/UnlinkedCodeBlock.h: + + * generate-js-builtins: Calls linkGlobalCode. + + * runtime/Executable.cpp: + (JSC::ProgramExecutable::initializeGlobalProperties): Calls linkGlobalCode. + (JSC::FunctionExecutable::fromGlobalCode): Calls linkGlobalCode. + +2015-03-06 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the MarkedBlock piece of this patch. + + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::allocateBlock): + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::create): + (JSC::MarkedBlock::destroy): + (JSC::MarkedBlock::MarkedBlock): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::capacity): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::freeBlock): + +2015-03-07 Ryosuke Niwa <rniwa@webkit.org> + + fromGlobalCode has an unused Debugger* argument + https://bugs.webkit.org/show_bug.cgi?id=142430 + + Reviewed by Darin Adler. + + Removed the debugger argument from UnlinkedFunctionExecutable::fromGlobalCode and + FunctionExecutable::fromGlobalCode since it's not used in either function. + + Also use reference in other arguments. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::fromGlobalCode): + * bytecode/UnlinkedCodeBlock.h: + * runtime/Executable.cpp: + (JSC::FunctionExecutable::fromGlobalCode): + * runtime/Executable.h: + * runtime/FunctionConstructor.cpp: + (JSC::constructFunctionSkippingEvalEnabledCheck): + +2015-03-06 Brent Fulgham <bfulgham@apple.com> + + [Win] Turn off a warning on Windows. + + Reduce build logging noise on Windows. + + * JavaScriptCore.vcxproj/JavaScriptCoreCommon.props: + +2015-03-06 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ES6: Improved Support for Iterator Objects + https://bugs.webkit.org/show_bug.cgi?id=142420 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Runtime.json: + Add new object subtype "iterator" for built-in iterator objects. + + * inspector/InjectedScriptSource.js: + Return iterator values as Entry objects. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + Identify "iterator" typed objects. + + (Inspector::JSInjectedScriptHost::getInternalProperties): + Provide internal properties for the different Iterator objects. + + (Inspector::JSInjectedScriptHost::iteratorEntries): + Fetch the next few iterator entries of a built-in iterator object. + + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + (Inspector::jsInjectedScriptHostPrototypeFunctionIteratorEntries): + Call through to JSInjectedScriptHost. + + * runtime/JSArgumentsIterator.cpp: + (JSC::JSArgumentsIterator::clone): + * runtime/JSArgumentsIterator.h: + (JSC::JSArgumentsIterator::iteratedValue): + * runtime/JSArrayIterator.cpp: + (JSC::JSArrayIterator::kind): + (JSC::JSArrayIterator::iteratedValue): + (JSC::JSArrayIterator::clone): + * runtime/JSArrayIterator.h: + * runtime/JSMapIterator.cpp: + (JSC::JSMapIterator::finishCreation): + (JSC::JSMapIterator::clone): + * runtime/JSMapIterator.h: + (JSC::JSMapIterator::kind): + (JSC::JSMapIterator::iteratedValue): + * runtime/JSSetIterator.cpp: + (JSC::JSSetIterator::finishCreation): + (JSC::JSSetIterator::clone): + * runtime/JSSetIterator.h: + (JSC::JSSetIterator::kind): + (JSC::JSSetIterator::iteratedValue): + * runtime/JSStringIterator.cpp: + (JSC::JSStringIterator::iteratedValue): + (JSC::JSStringIterator::clone): + * runtime/JSStringIterator.h: + Add accessors for internal properties and provide a way to clone the + iterator so we can be at the same index and peek at the next few + objects without modifying the original iterator object. + +2015-03-06 Ryosuke Niwa <rniwa@webkit.org> + + REGRESSION(r180595): construct varargs fails in FTL + https://bugs.webkit.org/show_bug.cgi?id=142030 + + Reviewed by Michael Saboff. + + Increase sizeOfCallVarargs as done for sizeOfConstructVarargs in r180651. + + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCallVarargs): + +2015-03-06 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Adopt Object Literal Shorthand Property Construction Syntax + https://bugs.webkit.org/show_bug.cgi?id=142374 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + +2015-03-06 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Object Literal Extensions - Methods + https://bugs.webkit.org/show_bug.cgi?id=142390 + + Reviewed by Geoffrey Garen. + + Support method syntax in object literals. + + * parser/Parser.h: + * parser/Parser.cpp: + (JSC::stringForFunctionMode): + (JSC::Parser<LexerType>::parseProperty): + Methods are allowed for identifier, string, and numeric names, + and computed property names. + + (JSC::Parser<LexerType>::parsePropertyMethod): + Helper for parsing a property method. + +2015-03-05 Joseph Pecoraro <pecoraro@apple.com> + + __proto__ shorthand property should not modify prototype in Object Literal construction + https://bugs.webkit.org/show_bug.cgi?id=142382 + + Reviewed by Geoffrey Garen. + + When parsing shorthand property syntax we know we will do a + put direct, even if the property name is __proto__. Pass that + information through to bytecode generation. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitDirectPutById): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitPutConstantProperty): + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createProperty): + * parser/NodeConstructors.h: + (JSC::PropertyNode::PropertyNode): + * parser/Nodes.h: + (JSC::PropertyNode::putType): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseClass): + (JSC::Parser<LexerType>::parseProperty): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createProperty): + +2015-03-06 Geoffrey Garen <ggaren@apple.com> + + Fix crashes seen on the the 32-bit buildbots after my last patch. + + Unreviewed. + + * heap/CopiedBlock.h: + (JSC::CopiedBlock::payload): + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::tryAllocateOversize): Round up to the right alignment, + since the size of the CopiedBlock class is not guaranteed to be the + right alignment, and is in fact the wrong alignment on 32-bit. + +2015-03-05 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the CopiedBlock piece of this patch. + + * heap/CopiedBlock.h: + (JSC::CopiedBlock::createNoZeroFill): + (JSC::CopiedBlock::destroy): + (JSC::CopiedBlock::create): + (JSC::CopiedBlock::CopiedBlock): + (JSC::CopiedBlock::isOversize): + (JSC::CopiedBlock::payloadEnd): + (JSC::CopiedBlock::capacity): + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::~CopiedSpace): + (JSC::CopiedSpace::tryAllocateOversize): + (JSC::CopiedSpace::tryReallocateOversize): + * heap/CopiedSpaceInlines.h: + (JSC::CopiedSpace::recycleEvacuatedBlock): + (JSC::CopiedSpace::recycleBorrowedBlock): + (JSC::CopiedSpace::allocateBlockForCopyingPhase): + (JSC::CopiedSpace::allocateBlock): + (JSC::CopiedSpace::startedCopying): + * heap/CopyWorkList.h: + +2015-03-06 Myles C. Maxfield <mmaxfield@apple.com> + + [iOS] SVG fonts are garbled + https://bugs.webkit.org/show_bug.cgi?id=142377 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: + +2015-03-05 Joseph Pecoraro <pecoraro@apple.com> + + ES6: Object Literal Extensions - Shorthand Properties (Identifiers) + https://bugs.webkit.org/show_bug.cgi?id=142353 + + Reviewed by Geoffrey Garen. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseProperty): + Parsing an identifier property followed by a comma or end brace treat + as a shorthand property and create a property that has the same + property name as the identifier name and value of a variable with that + identifier. Otherwise, fall through to getter/setter parsing. + +2015-03-05 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed gardening. + + Confirmed with JSC that warning 4611 (interaction between '_setjmp' and C++ object + destruction is non-portable) should be ignored in the JavaScriptCore project. + + * JavaScriptCore.vcxproj/JavaScriptCoreCommon.props: Silence warning 4611. + +2015-03-05 Chris Dumez <cdumez@apple.com> + + Regression(r173761): ASSERTION FAILED: !is8Bit() in StringImpl::characters16() + https://bugs.webkit.org/show_bug.cgi?id=142350 + + Reviewed by Michael Saboff and Benjamin Poulain. + + Call WTFString::hasInfixStartingAt() / hasInfixEndingAt() now that these + methods have been renamed for clarity. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncStartsWith): + (JSC::stringProtoFuncEndsWith): + +2015-03-05 Yusuke Suzuki <utatane.tea@gmail.com> + + Implement ES6 StringIterator + https://bugs.webkit.org/show_bug.cgi?id=142080 + + Reviewed by Filip Pizlo. + + This patch introduces ES6 String Iterator. + It enumerates code points instead of elements in String. + So surrogate pairs should be handled correctly. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/StringIterator.prototype.js: Added. + (next): + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + * runtime/JSGlobalObject.h: + * runtime/JSStringIterator.cpp: Added. + (JSC::JSStringIterator::finishCreation): + * runtime/JSStringIterator.h: Added. + (JSC::JSStringIterator::createStructure): + (JSC::JSStringIterator::create): + (JSC::JSStringIterator::JSStringIterator): + * runtime/StringIteratorConstructor.cpp: Added. + (JSC::StringIteratorConstructor::finishCreation): + * runtime/StringIteratorConstructor.h: Added. + (JSC::StringIteratorConstructor::create): + (JSC::StringIteratorConstructor::createStructure): + (JSC::StringIteratorConstructor::StringIteratorConstructor): + * runtime/StringIteratorPrototype.cpp: Added. + (JSC::StringIteratorPrototype::finishCreation): + (JSC::StringIteratorPrototype::getOwnPropertySlot): + (JSC::stringIteratorPrototypeIterator): + * runtime/StringIteratorPrototype.h: Added. + (JSC::StringIteratorPrototype::create): + (JSC::StringIteratorPrototype::createStructure): + (JSC::StringIteratorPrototype::StringIteratorPrototype): + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + (JSC::stringProtoFuncIterator): + * tests/stress/string-iterators.js: Added. + (testSurrogatePair): + (increment): + (for): + +2015-03-05 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Fix the FTL build on Aarch64 Linux after r177421 + https://bugs.webkit.org/show_bug.cgi?id=142040 + + Reviewed by Mark Lam. + + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2015-03-05 Yusuke Suzuki <utatane.tea@gmail.com> + + Upgrade ES6 Iterator interfaces + https://bugs.webkit.org/show_bug.cgi?id=141351 + + Reviewed by Filip Pizlo. + + This patch upgrades the exising ES6 iterator to align the latest spec. + In the latest spec, + 1. `Iterator.next` returns object that implements IteratorResult interface { value: value, done, boolean }. + 2. `Iterator.return` is introduced. When the iteration is terminated by the abrupt completion, + it is called to close iterator state. + 3. Iterator.next of Array is moved from an iterator object to `%ArrayIteratorPrototype%`. + + To upgrade it, we changes the bytecode that represents for-of loops. + And to embody the efficient iteration with an iterator object, + we implemented %ArrayIteratorPrototype%.next in JavaScript and + it is located in builtins/ArrayIterator.prototype.js. + Implementing it in JavaScript encourages inlining and + utilizes escape analysis for an iterator result object in DFG JIT. + And we dropped the intrinsic version of %ArrayIteratorPrototype%.next. + + And we introduced IteratorOperations that is defined in the spec. + It aligns the iteration in the runtime to the latest spec. + Currently, Promise.all and Promise.race uses an iterable object. + However, Promise.all and Promise.race implementation is also based on the old spec. + Subsequent patches will upgrade it. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/ArrayIterator.prototype.js: Copied from Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h. + (next): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitReturn): + (JSC::BytecodeGenerator::emitThrowTypeError): + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::emitIsObject): + (JSC::BytecodeGenerator::emitIsUndefined): + * bytecompiler/BytecodeGenerator.h: + * jit/ThunkGenerators.cpp: + (JSC::arrayIteratorNextThunkGenerator): Deleted. + (JSC::arrayIteratorNextKeyThunkGenerator): Deleted. + (JSC::arrayIteratorNextValueThunkGenerator): Deleted. + * jit/ThunkGenerators.h: + * runtime/ArgumentsIteratorPrototype.cpp: + (JSC::ArgumentsIteratorPrototype::finishCreation): + (JSC::argumentsIteratorPrototypeFuncNext): + * runtime/ArrayIteratorPrototype.cpp: + (JSC::ArrayIteratorPrototype::finishCreation): + (JSC::ArrayIteratorPrototype::getOwnPropertySlot): + (JSC::arrayIteratorProtoFuncIterator): + (JSC::arrayIteratorPrototypeIterate): Deleted. + * runtime/ArrayIteratorPrototype.h: + * runtime/CommonIdentifiers.h: + * runtime/Intrinsic.h: + * runtime/IteratorOperations.cpp: Added. + (JSC::iteratorNext): + (JSC::iteratorValue): + (JSC::iteratorComplete): + (JSC::iteratorStep): + (JSC::iteratorClose): + (JSC::createIterResultObject): + * runtime/IteratorOperations.h: Copied from Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp. + * runtime/JSArrayIterator.cpp: + (JSC::JSArrayIterator::finishCreation): + (JSC::JSArrayIterator::visitChildren): Deleted. + (JSC::createIteratorResult): Deleted. + (JSC::arrayIteratorNext): Deleted. + (JSC::arrayIteratorNextKey): Deleted. + (JSC::arrayIteratorNextValue): Deleted. + (JSC::arrayIteratorNextGeneric): Deleted. + * runtime/JSArrayIterator.h: + (JSC::JSArrayIterator::JSArrayIterator): + (JSC::JSArrayIterator::iterationKind): Deleted. + (JSC::JSArrayIterator::iteratedObject): Deleted. + (JSC::JSArrayIterator::nextIndex): Deleted. + (JSC::JSArrayIterator::setNextIndex): Deleted. + (JSC::JSArrayIterator::finish): Deleted. + (JSC::JSArrayIterator::offsetOfIterationKind): Deleted. + (JSC::JSArrayIterator::offsetOfIteratedObject): Deleted. + (JSC::JSArrayIterator::offsetOfNextIndex): Deleted. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSPromiseConstructor.cpp: + (JSC::performPromiseRaceLoop): + (JSC::JSPromiseConstructorFuncRace): + (JSC::performPromiseAll): + (JSC::JSPromiseConstructorFuncAll): + * runtime/MapIteratorPrototype.cpp: + (JSC::MapIteratorPrototype::finishCreation): + (JSC::MapIteratorPrototypeFuncNext): + * runtime/SetIteratorPrototype.cpp: + (JSC::SetIteratorPrototype::finishCreation): + (JSC::SetIteratorPrototypeFuncNext): + * runtime/VM.cpp: + (JSC::thunkGeneratorForIntrinsic): + * tests/stress/array-iterators-next-with-call.js: Added. + (increment): + (for): + * tests/stress/array-iterators-next.js: Added. + + Revive the older Array iterator tests that manually call 'next' method. + + * tests/stress/custom-iterators.js: Added. + (iter.next): + (iter.Symbol.iterator): + (iter.return): + (iter.get next): + (iter.get return): + (iteratorInterfaceErrorTest.iter.next): + (iteratorInterfaceErrorTest.iter.Symbol.iterator): + (iteratorInterfaceErrorTest.iter.return): + (iteratorInterfaceErrorTest): + (iteratorInterfaceErrorTestReturn.iter.next): + (iteratorInterfaceErrorTestReturn.iter.Symbol.iterator): + (iteratorInterfaceErrorTestReturn.iter.return): + (iteratorInterfaceErrorTestReturn): + (iteratorInterfaceBreakTestReturn.iter.next): + (iteratorInterfaceBreakTestReturn.iter.Symbol.iterator): + (iteratorInterfaceBreakTestReturn.iter.return): + (iteratorInterfaceBreakTestReturn): + + This tests the behavior of custom iterators. + 'next' and 'return' of iterator work with for-of. + + * tests/stress/iterators-shape.js: Added. + (iteratorShape): + (sameNextMethods): + (set var): + + This tests the shape of iterators; iterators of Array have 'next' method in %ArrayIteratorPrototype%. + + * tests/stress/map-iterators-next.js: Added. + (set var): + (.get if): + (otherKey): + * tests/stress/set-iterators-next.js: Added. + (otherKey): + +2015-03-04 Yusuke Suzuki <utatane.tea@gmail.com> + + Hide Promise with runtime flags under Cocoa JSContext API + https://bugs.webkit.org/show_bug.cgi?id=141965 + + Reviewed by Filip Pizlo. + + Since there's no run loop in JavaScriptCore APIs, Promises don't work currently. + So until they work, we hide Promise from a global object. + Introduce new JSC runtime flag, PromiseDisabled. When `isPromiseDisabled` is true, + Promise constructor is not attached to JSGlobalObject. + + To make 0 as default runtime flags, we choose PromiseDisabled flag + instead of PromiseEnabled flag. So by default, Promise is enabled. + + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject<Parent>::JSCallbackObject): + * API/JSContextRef.cpp: + (javaScriptRuntimeFlags): + (JSGlobalContextCreateInGroup): + * API/tests/testapi.c: + (main): + * API/tests/testapi.mm: + (testObjectiveCAPI): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::create): + * runtime/RuntimeFlags.h: + (JSC::RuntimeFlags::createAllEnabled): + +2015-03-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Array/Collection Sizes should be visible and distinct + https://bugs.webkit.org/show_bug.cgi?id=142254 + + Reviewed by Timothy Hatcher. + + * runtime/WeakMapData.h: + (JSC::WeakMapData::size): + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::weakMapSize): + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + (Inspector::jsInjectedScriptHostPrototypeFunctionWeakMapSize): + Add a way to get a WeakMap's size. + + * inspector/protocol/Runtime.json: + Include size in RemoteObject and ObjectPreview. + + * inspector/InjectedScriptSource.js: + Set the size of RemoteObjects and previews if they + are array/collection types. + +2015-03-04 Andreas Kling <akling@apple.com> + + GC should compute stack bounds and dump registers at the earliest opportunity. + <https://webkit.org/b/142310> + <rdar://problem/20045624> + + Reviewed by Geoffrey Garen. + + Make Heap::collect() a wrapper function around a collectImpl() where the work is actually done. + The wrapper function that grabs a snapshot of the current stack boundaries and register values + on entry, and sanitizes the stack on exit. + + This is a speculative fix for what appears to be overly conservative behavior in the garbage + collector following r178364 which caused a measurable regression in memory usage on Membuster. + The theory being that we were putting pointers to dead things on the stack before scanning it, + and by doing that ended up marking things that we'd otherwise discover to be garbage. + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::gatherStackRoots): + (JSC::Heap::collect): + (JSC::Heap::collectImpl): + * heap/Heap.h: + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::gatherFromCurrentThread): + (JSC::MachineThreads::gatherConservativeRoots): + * heap/MachineStackMarker.h: + +2015-03-04 Debarshi Ray <debarshir@gnome.org> + + Silence GCC's -Wstrict-prototypes + https://bugs.webkit.org/show_bug.cgi?id=142278 + + Reviewed by Alexey Proskuryakov. + + * API/JSContextRef.h: + +2015-03-04 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Add a node for Math.log() + https://bugs.webkit.org/show_bug.cgi?id=142126 + + Reviewed by Geoffrey Garen. + + This patch adds the DFG node ArithLog for LogIntrinsic. + + Having a direct call to log has very little value by itself, the implementation + in DFG and FTL is a simple function call. + + What is useful in ArithLog is that we know the operation is pure. + This allow us to hoist it out of loops when the argument is independent + is an invariant of the loop. + + Perf wise, this patch gives: + -Kraken's imaging-darkroom: definitely 1.2372x faster. + -AsmBench's Towers.c: definitely 1.0261x faster. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithLog): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileArithLog): + * ftl/FTLOutput.h: + (JSC::FTL::Output::doubleLog): + * tests/stress/math-log-basics.js: Added. + * tests/stress/math-log-with-constants.js: Added. + +2015-03-04 Filip Pizlo <fpizlo@apple.com> + + Only Heap should be in charge of deciding how to select a subspace for a type + https://bugs.webkit.org/show_bug.cgi?id=142304 + + Reviewed by Mark Lam. + + This slightly reduces the code duplication for selecting subspace based on type, and what + duplication is left is at least localized in HeapInlines.h. The immediate effect is that + the DFG and FTL don't have to duplicate this pattern. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateJSObject): + (JSC::DFG::SpeculativeJIT::emitAllocateVariableSizedJSObject): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::allocateObject): + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::allocateObjectOfType): + (JSC::Heap::subspaceForObjectOfType): + (JSC::Heap::allocatorForObjectOfType): + * runtime/JSCellInlines.h: + (JSC::allocateCell): + +2015-03-04 Andreas Kling <akling@apple.com> + + Stale entries in WeakGCMaps are keeping tons of WeakBlocks alive unnecessarily. + <https://webkit.org/b/142115> + <rdar://problem/19992268> + + Reviewed by Geoffrey Garen. + + Prune stale entries from WeakGCMaps as part of every full garbage collection. + This frees up tons of previously-stuck WeakBlocks that were only sitting around + with finalized handles waiting to die. + + Note that WeakGCMaps register/unregister themselves with the GC heap in their + ctor/dtor, so creating one now requires passing the VM. + + Average time spent in the PruningStaleEntriesFromWeakGCMaps GC phase appears + to be between 0.01ms and 0.3ms, though I've seen a few longer ones at ~1.2ms. + It seems somewhat excessive to do this on every Eden collection, so it's only + doing work in full collections for now. + + * API/JSWeakObjectMapRefInternal.h: + (OpaqueJSWeakObjectMap::create): + (OpaqueJSWeakObjectMap::OpaqueJSWeakObjectMap): + * API/JSWeakObjectMapRefPrivate.cpp: + * API/JSWrapperMap.mm: + (-[JSWrapperMap initWithContext:]): + (-[JSWrapperMap jsWrapperForObject:]): Pass VM to WeakGCMap constructor. + + * JavaScriptCore.xcodeproj/project.pbxproj: Add WeakGCMapInlines.h and make + it project-private so WebCore clients can access it. + + * heap/Heap.cpp: + (JSC::Heap::collect): + (JSC::Heap::pruneStaleEntriesFromWeakGCMaps): Added a new GC phase for pruning + stale entries from WeakGCMaps. This is only executed during full collections. + + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::registerWeakGCMap): + (JSC::Heap::unregisterWeakGCMap): Added a mechanism for WeakGCMaps to register + themselves with the Heap and provide a pruning callback. + + * runtime/PrototypeMap.h: + (JSC::PrototypeMap::PrototypeMap): + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::add): Pass VM to WeakGCMap constructor. + + * runtime/JSCInlines.h: Add "WeakGCMapInlines.h" + + * runtime/JSGlobalObject.cpp: Include "WeakGCMapInlines.h" so this builds. + + * runtime/VM.cpp: + (JSC::VM::VM): Pass VM to WeakGCMap constructor. + + * runtime/WeakGCMap.h: + (JSC::WeakGCMap::set): + (JSC::WeakGCMap::add): + (JSC::WeakGCMap::WeakGCMap): Deleted. + (JSC::WeakGCMap::gcMap): Deleted. + (JSC::WeakGCMap::gcMapIfNeeded): Deleted. + * runtime/WeakGCMapInlines.h: Added. + (JSC::WeakGCMap::WeakGCMap): + (JSC::WeakGCMap::~WeakGCMap): + (JSC::WeakGCMap::pruneStaleEntries): Moved ctor, dtor and pruning callback + to WeakGCMapInlines.h to fix interdependent header issues. Removed code that + prunes WeakGCMap at certain growth milestones and instead rely on the GC + callback for housekeeping. + +2015-03-03 Filip Pizlo <fpizlo@apple.com> + + DFG IR should refer to FunctionExecutables directly and not via the CodeBlock + https://bugs.webkit.org/show_bug.cgi?id=142229 + + Reviewed by Mark Lam and Benjamin Poulain. + + Anytime a DFG IR node refers to something in CodeBlock, it has three effects: + + - Cumbersome API for accessing the thing that the node refers to. + + - Not obvious how to create a new such node after bytecode parsing, especially if the + thing it refers to isn't already in the CodeBlock. We have done this in the past, but + it usually involves subtle changes to CodeBlock. + + - Not obvious how to inline code that ends up using such nodes. Again, when we have done + this, it involved subtle changes to CodeBlock. + + Prior to this change, the NewFunction* node types used an index into tables in CodeBlock. + For this reason, those operations were not inlineable. But the functin tables in CodeBlock + just point to FunctionExecutables, which are cells; this means that we can just abstract + these operands in DFG IR as cellOperands. cellOperands use DFG::FrozenValue, which means + that GC registration happens automagically. Even better, our dumping for cellOperand + already did FunctionExecutable dumping - so that functionality gets to be deduplicated. + + Because this change increases the number of users of cellOperand, it also adds some + convenience methods for using it. For example, whereas before you'd say things like: + + jsCast<Foo*>(node->cellOperand()->value()) + + you can now just say: + + node->castOperand<Foo*>() + + This change also changes existing cellOperand users to use the new conveniance API when + applicable. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::jettisonFunctionDeclsAndExprs): + * bytecode/CodeBlock.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGFrozenValue.h: + (JSC::DFG::FrozenValue::cell): + (JSC::DFG::FrozenValue::dynamicCast): + (JSC::DFG::FrozenValue::cast): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::registerFrozenValues): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasCellOperand): + (JSC::DFG::Node::castOperand): + (JSC::DFG::Node::hasFunctionDeclIndex): Deleted. + (JSC::DFG::Node::functionDeclIndex): Deleted. + (JSC::DFG::Node::hasFunctionExprIndex): Deleted. + (JSC::DFG::Node::functionExprIndex): Deleted. + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileNewFunctionNoCheck): + (JSC::DFG::SpeculativeJIT::compileNewFunctionExpression): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileCheckCell): + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): + +2015-03-03 Michael Saboff <msaboff@apple.com> + + DelayedReleaseScope drops locks during GC which can cause a thread switch and code reentry + https://bugs.webkit.org/show_bug.cgi?id=141275 + + Reviewed by Geoffrey Garen. + + The original issue is that the CodeCache uses an unsafe method to add new UnlinkedCodeBlocks. + It basically adds a null UnlinkedCodeBlock if there isn't a cached entry and then later + updates the null entry to the result of the compilation. If during that compilation and + related processing we need to garbage collect, the DelayedReleaseScope would drop locks + possibly allowing another thread to try to get the same source out of the CodeCache. + This second thread would find the null entry and crash. The fix is to move the processing of + DelayedReleaseScope to when we drop locks and not drop locks during GC. That was done in + the original patch with the new function releaseDelayedReleasedObjects(). + + Updated releaseDelayedReleasedObjects() so that objects are released with all locks + dropped. Now its processing follows these steps + Increment recursion counter and do recursion check and exit if recursing + While there are objects to release + ASSERT that lock is held by current thread + Take all items from delayed release Vector and put into temporary Vector + Release API lock + Release and clear items from temporary vector + Reaquire API lock + This meets the requirement that we release while the API lock is released and it is + safer processing of the delayed release Vector. + + Added new regression test to testapi. + + Also added comment describing how recursion into releaseDelayedReleasedObjects() is + prevented. + + * API/tests/Regress141275.h: Added. + * API/tests/Regress141275.mm: Added. + (+[JSTEvaluatorTask evaluatorTaskWithEvaluateBlock:completionHandler:]): + (-[JSTEvaluator init]): + (-[JSTEvaluator initWithScript:]): + (-[JSTEvaluator _accessPendingTasksWithBlock:]): + (-[JSTEvaluator insertSignPostWithCompletion:]): + (-[JSTEvaluator evaluateScript:completion:]): + (-[JSTEvaluator evaluateBlock:completion:]): + (-[JSTEvaluator waitForTasksDoneAndReportResults]): + (__JSTRunLoopSourceScheduleCallBack): + (__JSTRunLoopSourcePerformCallBack): + (__JSTRunLoopSourceCancelCallBack): + (-[JSTEvaluator _jsThreadMain]): + (-[JSTEvaluator _sourceScheduledOnRunLoop:]): + (-[JSTEvaluator _setupEvaluatorThreadContextIfNeeded]): + (-[JSTEvaluator _callCompletionHandler:ifNeededWithError:]): + (-[JSTEvaluator _sourcePerform]): + (-[JSTEvaluator _sourceCanceledOnRunLoop:]): + (runRegress141275): + * API/tests/testapi.mm: + (testObjectiveCAPI): + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/Heap.cpp: + (JSC::Heap::releaseDelayedReleasedObjects): + * runtime/JSLock.cpp: + (JSC::JSLock::unlock): + +2015-03-03 Filip Pizlo <fpizlo@apple.com> + + DFG should constant fold GetScope, and accesses to the scope register in the ByteCodeParser should not pretend that it's a constant as that breaks OSR exit liveness tracking + https://bugs.webkit.org/show_bug.cgi?id=106202 + + Rubber stamped by Benjamin Poulain. + + This fixes a bug discovered by working on https://bugs.webkit.org/show_bug.cgi?id=142229, + which was in turn discovered by working on https://bugs.webkit.org/show_bug.cgi?id=141174. + Our way of dealing with scopes known to be constant is very sketchy, and only really works + when a function is inlined. When it is, we pretend that every load of the scopeRegister sees + a constant. But this breaks the DFG's tracking of the liveness of the scopeRegister. The way + this worked made us miss oppportunities for optimizing based on a constant scope, and it also + meant that in some cases - particularly like when we inline code that uses NewFuction and + friends, as I do in bug 142229 - it makes OSR exit think that the scope is dead even though + it's most definitely alive and it's a constant. + + The problem here is that we were doing too many optimizations in the ByteCodeParser, and not + later. Later optimization phases know how to preserve OSR exit liveness. They're actually + really good at it. Also, later phases know how to infer that any variable is a constant no + matter how that constant arose - rather than the inlining-specific thing in ByteCodeParser. + + This changes the ByteCodeParser to largely avoid doing constant folding on the scope, except + making the GetScope operation itself a constant. This is a compilation-time hack for small + functions, and it doesn't break the loads of local variables - so OSR exit liveness still + sees that the scopeRegister is in use. This then adds a vastly more powerful GetScope and + GetClosureVar constant folder in the AbstractInterpreter. This handles most general cases + including those that arise in complex control flow. This will catch cases where the scope + is constant for any number of reasons. Basically anytime that the callee is inferred constant + this will give us a constant scope. Also, we still have the parse-time constant folding of + ResolveScope based on the reentry watchpoint, which luckily did the right thing with respect + to OSR exit liveness (it splats a Phantom on its inputs, and it produces a constant result + which is then set() normally). + + This appears to be a broad speed-up, albeit a small one. But mainly it unblocks bug 142229, + which then should unblock bug 141174. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::get): + (JSC::DFG::ByteCodeParser::getLocal): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::parse): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetConstantClosureVar): + (JSC::DFG::Graph::tryGetRegisters): + (JSC::DFG::Graph::tryGetActivation): Deleted. + * dfg/DFGGraph.h: + * dfg/DFGNode.h: + (JSC::DFG::Node::hasVariableWatchpointSet): + (JSC::DFG::Node::hasSymbolTable): Deleted. + (JSC::DFG::Node::symbolTable): Deleted. + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetClosureVar): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::visitChildren): + (JSC::SymbolTable::localToEntry): + (JSC::SymbolTable::entryFor): + * runtime/SymbolTable.h: + (JSC::SymbolTable::add): + (JSC::SymbolTable::set): + * tests/stress/function-expression-exit.js: Added. + * tests/stress/function-reentry-infer-on-self.js: Added. + (thingy): + * tests/stress/goofy-function-reentry-incorrect-inference.js: Added. + +2015-03-03 Anders Carlsson <andersca@apple.com> + + Remove unused compression code + https://bugs.webkit.org/show_bug.cgi?id=142237 + + Reviewed by Geoffrey Garen. + + * bytecode/UnlinkedCodeBlock.h: + +2015-03-03 Filip Pizlo <fpizlo@apple.com> + + JIT debugging features that selectively disable the JITs for code blocks need to stay out of the way of the critical path of JIT management + https://bugs.webkit.org/show_bug.cgi?id=142234 + + Reviewed by Mark Lam and Benjamin Poulain. + + Long ago, we used to selectively disable compilation of CodeBlocks for debugging purposes by + adding hacks to DFGDriver.cpp. This was all well and good. It used the existing + CompilationFailed mode of the DFG driver to signal failure of CodeBlocks that we didn't want + to compile. That's great because CompilationFailed is a well-supported return value on the + critical path, usually used for when we run out of JIT memory. + + Later, this was moved into DFGCapabilities. This was basically incorrect. It introduced a bug + where disabling compiling of a CodeBlock meant that we stopped inlining it as well. So if + you had a compiler bug that arose if foo was inlined into bar, and you bisected down to bar, + then foo would no longer get inlined and you wouldn't see the bug. That's busted. + + So then we changed the code in DFGCapabilities to mark bar as CanCompile and foo as + CanInline. Now, foo wouldn't get compiled alone but it would get inlined. + + But then we removed CanCompile because that capability mode only existed for the purpose of + our old varargs hacks. After that removal, "CanInline" became CannotCompile. This means + that if you bisect down on bar in the "foo inlined into bar" case, you'll crash in the DFG + because the baseline JIT wouldn't have known to insert profiling on foo. + + We could fix this by bringing back CanInline. + + But this is all a pile of nonsense. The debug support to selectively disable compilation of + some CodeBlocks shouldn't cross-cut our entire engine and should most certainly never involve + adding new capability modes. This support is a hack at best and is for use by JSC hackers + only. It should be as unintrusive as possible. + + So, as in the ancient times, the only proper place to put this hack is in DFGDriver.cpp, and + return CompilationFailed. This is correct not just because it takes capability modes out of + the picture (and obviates the need to introduce new ones), but also because it means that + disabling compilation doesn't change the profiling mode of other CodeBlocks in the Baseline + JIT. Capability mode influences profiling mode which in turn influences code generation in + the Baseline JIT, sometimes in very significant ways - like, we sometimes do additional + double-to-int conversions in Baseline if we know that we might tier-up into the DFG, since + this buys us more precise profiling. + + This change reduces the intrusiveness of debugging hacks by making them use the very simple + CompilationFailed mechanism rather than trying to influence capability modes. Capability + modes have very subtle effects on the whole engine, while CompilationFailed just makes the + engine pretend like the DFG compilation will happen at timelike infinity. That makes these + hacks much more likely to continue working as we make other changes to the system. + + This brings back the ability to bisect down onto a function bar when bar inlines foo. Prior + to this change, we would crash in that case. + + * dfg/DFGCapabilities.cpp: + (JSC::DFG::isSupported): + (JSC::DFG::mightCompileEval): + (JSC::DFG::mightCompileProgram): + (JSC::DFG::mightCompileFunctionForCall): + (JSC::DFG::mightCompileFunctionForConstruct): + * dfg/DFGCapabilities.h: + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + +2015-03-03 peavo@outlook.com <peavo@outlook.com> + + [Win64] JSC compile error. + https://bugs.webkit.org/show_bug.cgi?id=142216 + + Reviewed by Mark Lam. + + There is missing a version of setupArgumentsWithExecState when NUMBER_OF_ARGUMENT_REGISTERS == 4. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2015-03-02 Filip Pizlo <fpizlo@apple.com> + + DFG compile time measurements should really report milliseconds + https://bugs.webkit.org/show_bug.cgi?id=142209 + + Reviewed by Benjamin Poulain. + + Fix this to record milliseconds instead of seconds. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThread): + (JSC::DFG::Plan::compileInThreadImpl): + +2015-03-02 Filip Pizlo <fpizlo@apple.com> + + Remove op_get_callee, it's unused + https://bugs.webkit.org/show_bug.cgi?id=142206 + + Reviewed by Andreas Kling. + + It's a bit of a shame that we stopped using this opcode since it gives us same-callee + profiling. But, if we were to add this functionality back in, we would almost certainly do + it by adding a JSFunction allocation watchpoint on FunctionExecutable. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::finalizeUnconditionally): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_callee): Deleted. + (JSC::JIT::emitSlow_op_get_callee): Deleted. + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_callee): Deleted. + (JSC::JIT::emitSlow_op_get_callee): Deleted. + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): Deleted. + +2015-03-02 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Context Menu to Log a Particular Object + https://bugs.webkit.org/show_bug.cgi?id=142198 + + Reviewed by Timothy Hatcher. + + Add a protocol method to assign a $n index to a value. For an object + use the injected script context for that object. For a value, use + the execution context to know where to save the value. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::saveResult): + * inspector/InjectedScript.h: + * inspector/InjectedScriptSource.js: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::saveResult): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Debugger.json: + * inspector/protocol/Runtime.json: + +2015-03-02 Filip Pizlo <fpizlo@apple.com> + + SpeculativeJIT::emitAllocateArguments() should be a bit faster, and shouldn't do destructor initialization + https://bugs.webkit.org/show_bug.cgi?id=142197 + + Reviewed by Geoffrey Garen. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateArguments): Use shift instead of mul, since mul doesn't automatically strength-reduce to shift. Also pass the structure as a TrustedImmPtr. + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateVariableSizedJSObject): Rationalize this a bit. The other emitAllocate... methods take a templated structure so that it can be either a TrustedImmPtr or a register. Also don't do destructor initialization, since its one client doesn't need it, and it's actually probably wrong. + +2015-03-02 Mark Lam <mark.lam@apple.com> + + Exception stack unwinding in JSC hangs while the Timeline Profiler is enabled. + <https://webkit.org/b/142191> + + Reviewed by Geoffrey Garen. + + Imagine a scenario where the Inspector is paused / suspended at a breakpoint or + while the user is stepping through JS code. The user then tries to evaluate an + expression in the console, and that evaluation results in an exception being + thrown. Currently, if the Timeline Profiler is enabled while this exception is + being thrown, the WebProcess will hang while trying to handle that exception. + + The issue is that the Timeline Profiler's ProfileGenerator::didExecute() will + return early and decline to process ProfileNodes if the Inspector is paused. + This is proper because it does not want to count work done for injected scripts + (e.g. from the console) towards the timeline profile of the webpage being run. + However, this is in conflict with ProfileGenerator::exceptionUnwind()'s + expectation that didExecute() will process ProfileNodes in order to do the stack + unwinding for the exception handling. As a result, + ProfileGenerator::exceptionUnwind() hangs. + + ProfileGenerator::exceptionUnwind() is in error. While the Inspector is paused, + there will not be any ProfileNodes that it needs to "unwind". Hence, the fix is + simply to return early also in ProfileGenerator::exceptionUnwind() if the + Inspector is paused. + + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::exceptionUnwind): + +2015-03-02 Filip Pizlo <fpizlo@apple.com> + + FTL should correctly document where it puts the argument count for inlined varargs frames + https://bugs.webkit.org/show_bug.cgi?id=142187 + + Reviewed by Geoffrey Garn. + + After LLVM tells us where the captured variables alloca landed in the frame, we need to + tell all of our meta-data about it. We were forgetting to do so for the argument count + register, which is used by inlined varargs calls. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * tests/stress/inline-varargs-get-arguments.js: Added. + (foo): + (bar): + (baz): + +2015-03-02 Filip Pizlo <fpizlo@apple.com> + + Deduplicate slow path calling code in JITOpcodes.cpp/JITOpcodes32_64.cpp + https://bugs.webkit.org/show_bug.cgi?id=142184 + + Reviewed by Michael Saboff. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_enumerable_length): + (JSC::JIT::emitSlow_op_has_structure_property): + (JSC::JIT::emit_op_has_generic_property): + (JSC::JIT::emit_op_get_structure_property_enumerator): + (JSC::JIT::emit_op_get_generic_property_enumerator): + (JSC::JIT::emit_op_to_index_string): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_enumerable_length): Deleted. + (JSC::JIT::emitSlow_op_has_structure_property): Deleted. + (JSC::JIT::emit_op_has_generic_property): Deleted. + (JSC::JIT::emit_op_get_structure_property_enumerator): Deleted. + (JSC::JIT::emit_op_get_generic_property_enumerator): Deleted. + (JSC::JIT::emit_op_to_index_string): Deleted. + (JSC::JIT::emit_op_profile_control_flow): Deleted. + +2015-03-02 Antti Koivisto <antti@apple.com> + + Add way to dump cache meta data to file + https://bugs.webkit.org/show_bug.cgi?id=142183 + + Reviewed by Andreas Kling. + + Export appendQuotedJSONStringToBuilder. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ObjectPatternNode::toString): + * runtime/JSONObject.cpp: + (JSC::appendQuotedJSONStringToBuilder): + (JSC::Stringifier::appendQuotedString): + (JSC::escapeStringToBuilder): Deleted. + * runtime/JSONObject.h: + +2015-03-02 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Add Context Menus to Object Tree properties + https://bugs.webkit.org/show_bug.cgi?id=142125 + + Reviewed by Timothy Hatcher. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::functionDetails): + Update to include columnNumber. + +2015-03-01 Filip Pizlo <fpizlo@apple.com> + + BytecodeGenerator shouldn't emit op_resolve_scope as a roundabout way of returning the scopeRegister + https://bugs.webkit.org/show_bug.cgi?id=142153 + + Reviewed by Michael Saboff. + + We don't need a op_resolve_scope if we know that it will simply return the scope register. + This changes the BytecodeGenerator to use the scope register directly in those cases where + we know statically that we would just have returned that from op_resolve_scope. + + This doesn't appear to have a significant impact on performance. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitResolveScope): + (JSC::BytecodeGenerator::emitReturn): + (JSC::BytecodeGenerator::emitGetOwnScope): Deleted. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ResolveNode::emitBytecode): + (JSC::EvalFunctionCallNode::emitBytecode): + (JSC::FunctionCallResolveNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::DeleteResolveNode::emitBytecode): + (JSC::TypeOfResolveNode::emitBytecode): + (JSC::PrefixNode::emitResolve): + (JSC::ReadModifyResolveNode::emitBytecode): + (JSC::AssignResolveNode::emitBytecode): + (JSC::ConstDeclNode::emitCodeSingle): + (JSC::EmptyVarExpression::emitBytecode): + (JSC::ForInNode::emitLoopHeader): + (JSC::ForOfNode::emitBytecode): + (JSC::BindingNode::bindValue): + +2015-02-27 Benjamin Poulain <bpoulain@apple.com> + + [JSC] Use the way number constants are written to help type speculation + https://bugs.webkit.org/show_bug.cgi?id=142072 + + Reviewed by Filip Pizlo. + + This patch changes how we interpret numeric constant based on how they appear + in the source. + + Constants that are integers but written with a decimal point now carry that information + to the optimizating tiers. From there, we use that to be more aggressive about typing + math operations toward double operations. + + For example, in: + var a = x + 1.0; + var b = y + 1; + The Add for a would be biased toward doubles, the Add for b would speculate + integer as usual. + + + The gains are tiny but this is a prerequisite to make my next patch useful: + -SunSpider's access-fannkuch: definitely 1.0661x faster + -SunSpider's math-cordic: definitely 1.0266x slower + overal: might be 1.0066x slower. + -Kraken's imaging-darkroom: definitely 1.0333x faster. + + * parser/Lexer.cpp: + (JSC::tokenTypeForIntegerLikeToken): + (JSC::Lexer<T>::lex): + The lexer now create two types of tokens for number: INTEGER and DOUBLE. + Those token types only carry information about how the values were + entered, an INTEGER does not have to be an integer, it is only written like one. + Large integer still end up represented as double in memory. + + One trap I fell into was typing numbers like 12e3 as double. This kind of literal + is frequently used in integer-typed code, while 12.e3 would appear in double-typed + code. + Because of that, the only signals for double are: decimal point, negative zero, + and ridiculously large values. + + * parser/NodeConstructors.h: + (JSC::DoubleNode::DoubleNode): + (JSC::IntegerNode::IntegerNode): + * parser/Nodes.h: + (JSC::NumberNode::value): + (JSC::NumberNode::setValue): Deleted. + Number get specialized in two new kind of nodes in the AST: IntegerNode and DoubleNode. + + * bytecompiler/NodesCodegen.cpp: + (JSC::NumberNode::emitBytecode): + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createDoubleExpr): + (JSC::ASTBuilder::createIntegerExpr): + (JSC::ASTBuilder::createIntegerLikeNumber): + (JSC::ASTBuilder::createDoubleLikeNumber): + (JSC::ASTBuilder::createNumberFromBinaryOperation): + (JSC::ASTBuilder::createNumberFromUnaryOperation): + (JSC::ASTBuilder::makeNegateNode): + (JSC::ASTBuilder::makeBitwiseNotNode): + (JSC::ASTBuilder::makeMultNode): + (JSC::ASTBuilder::makeDivNode): + (JSC::ASTBuilder::makeModNode): + (JSC::ASTBuilder::makeAddNode): + (JSC::ASTBuilder::makeSubNode): + (JSC::ASTBuilder::makeLeftShiftNode): + (JSC::ASTBuilder::makeRightShiftNode): + (JSC::ASTBuilder::makeURightShiftNode): + (JSC::ASTBuilder::makeBitOrNode): + (JSC::ASTBuilder::makeBitAndNode): + (JSC::ASTBuilder::makeBitXOrNode): + (JSC::ASTBuilder::createNumberExpr): Deleted. + (JSC::ASTBuilder::createNumber): Deleted. + The AST has some optimization to resolve constants before emitting bytecode. + In the new code, the intger representation is kept if both operands where + also represented as integers. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseDeconstructionPattern): + (JSC::Parser<LexerType>::parseProperty): + (JSC::Parser<LexerType>::parseGetterSetter): + (JSC::Parser<LexerType>::parsePrimaryExpression): + (JSC::Parser<LexerType>::printUnexpectedTokenText): + * parser/ParserTokens.h: + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createDoubleExpr): + (JSC::SyntaxChecker::createIntegerExpr): + (JSC::SyntaxChecker::createNumberExpr): Deleted. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::registerName): + (JSC::CodeBlock::constantName): + Change constantName(r, getConstant(r)) -> constantName(r) to simplify + the dump code. + + (JSC::CodeBlock::dumpBytecode): + Dump thre soure representation information we have with each constant. + + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::shrinkToFit): + (JSC::constantName): Deleted. + * bytecode/CodeBlock.h: + (JSC::CodeBlock::constantsSourceCodeRepresentation): + (JSC::CodeBlock::addConstant): + (JSC::CodeBlock::addConstantLazily): + (JSC::CodeBlock::constantSourceCodeRepresentation): + (JSC::CodeBlock::setConstantRegisters): + + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::addConstant): + (JSC::UnlinkedCodeBlock::constantsSourceCodeRepresentation): + (JSC::UnlinkedCodeBlock::shrinkToFit): + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::addConstantValue): + (JSC::BytecodeGenerator::emitLoad): + * bytecompiler/BytecodeGenerator.h: + We have to differentiate between constants that have the same values but are + represented differently in the source. Values like 1.0 and 1 now end up + as different constants. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::get): + (JSC::DFG::ByteCodeParser::addConstantToGraph): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::registerFrozenValues): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::addSpeculationMode): + (JSC::DFG::Graph::addImmediateShouldSpeculateInt32): + ArithAdd is very aggressive toward using Int52, which is quite useful + in many benchmarks. + + Here we need to specialize to make sure we don't force our literals + to Int52 if there were represented as double. + + There is one exception to that rule: when the other operand is guaranteed + to come from a NodeResultInt32. This is because there is some weird code + doing stuff like: + var b = a|0; + var c = b*2.0; + + * dfg/DFGNode.h: + (JSC::DFG::Node::Node): + (JSC::DFG::Node::setOpAndDefaultFlags): + (JSC::DFG::Node::sourceCodeRepresentation): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * runtime/JSCJSValue.h: + (JSC::EncodedJSValueWithRepresentationHashTraits::emptyValue): + (JSC::EncodedJSValueWithRepresentationHashTraits::constructDeletedValue): + (JSC::EncodedJSValueWithRepresentationHashTraits::isDeletedValue): + (JSC::EncodedJSValueWithRepresentationHash::hash): + (JSC::EncodedJSValueWithRepresentationHash::equal): + * tests/stress/arith-add-with-constants.js: Added. + * tests/stress/arith-mul-with-constants.js: Added. + +2015-02-26 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, roll out r180723. It broke a bunch of tests. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::constLocal): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ConstDeclNode::emitCodeSingle): + * tests/stress/const-arguments.js: Removed. + +2015-02-26 Mark Lam <mark.lam@apple.com> + + Assertion fix for r180711: The bool returning form of BytecodeGenerator::addVar() can be removed. + <https://webkit.org/b/142064> + + Reviewed by Joseph Pecoraro. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::addVar): + +2015-02-26 Mark Lam <mark.lam@apple.com> + + MachineThreads::Thread clean up has a use after free race condition. + <https://webkit.org/b/141990> + + Reviewed by Filip Pizlo. + + MachineThreads::Thread clean up relies on the clean up mechanism + implemented in _pthread_tsd_cleanup_key(), which looks like this: + + void _pthread_tsd_cleanup_key(pthread_t self, pthread_key_t key) + { + void (*destructor)(void *); + if (_pthread_key_get_destructor(key, &destructor)) { + void **ptr = &self->tsd[key]; + void *value = *ptr; + + // === Start of window for the bug to manifest ================= + + // At this point, this thread has cached "destructor" and "value" + // (which is a MachineThreads*). If the VM gets destructed (along + // with its MachineThreads registry) by another thread, then this + // thread will have no way of knowing that the MachineThreads* is + // now pointing to freed memory. Calling the destructor below will + // therefore result in a use after free scenario when it tries to + // access the MachineThreads' data members. + + if (value) { + *ptr = NULL; + if (destructor) { + + // === End of window for the bug to manifest ================== + + destructor(value); + } + } + } + } + + The fix is to add each active MachineThreads to an ActiveMachineThreadsManager, + and always check if the manager still contains that MachineThreads object + before we call removeCurrentThread() on it. When MachineThreads is destructed, + it will remove itself from the manager. The add, remove, and checking + operations are all synchronized on the manager's lock, thereby ensuring that + the MachineThreads object, if found in the manager, will remain alive for the + duration of time we call removeCurrentThread() on it. + + There's also possible for the MachineThreads object to already be destructed + and another one happened to have been instantiated at the same address. + Hence, we should only remove the exiting thread if it is found in the + MachineThreads object. + + There is no test for this issue because this bug requires a race condition + between 2 threads where: + 1. Thread B, which had previously used the VM, exiting and + getting to the bug window shown in _pthread_tsd_cleanup_key() above. + 2. Thread A destructing the VM (and its MachineThreads object) + within that window of time before Thread B calls the destructor. + + It is not possible to get a reliable test case without invasively + instrumenting _pthread_tsd_cleanup_key() or MachineThreads::removeCurrentThread() + to significantly increase that window of opportunity. + + * heap/MachineStackMarker.cpp: + (JSC::ActiveMachineThreadsManager::Locker::Locker): + (JSC::ActiveMachineThreadsManager::add): + (JSC::ActiveMachineThreadsManager::remove): + (JSC::ActiveMachineThreadsManager::contains): + (JSC::ActiveMachineThreadsManager::ActiveMachineThreadsManager): + (JSC::activeMachineThreadsManager): + (JSC::MachineThreads::MachineThreads): + (JSC::MachineThreads::~MachineThreads): + (JSC::MachineThreads::removeThread): + (JSC::MachineThreads::removeThreadIfFound): + (JSC::MachineThreads::removeCurrentThread): Deleted. + * heap/MachineStackMarker.h: + +2015-02-26 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Save Console Evaluations into Command Line variables $1-$99 ($n) + https://bugs.webkit.org/show_bug.cgi?id=142061 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Debugger.json: + * inspector/protocol/Runtime.json: + Input flag "saveResult" on whether we should try to save a result. + Output int "savedResultIndex" to tell the frontend the saved state. + + * inspector/InjectedScriptSource.js: + Handle saving and clearing $1-$99 values. + Include in BasicCommandLineAPI for JSContext inspection. + + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::makeEvalCall): + * inspector/InjectedScriptBase.h: + Allow an optional "savedResultIndex" out value on evals. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::evaluate): + (Inspector::InjectedScript::evaluateOnCallFrame): + * inspector/InjectedScript.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::evaluateOnCallFrame): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::evaluate): + * inspector/agents/InspectorRuntimeAgent.h: + Plumbing for new in and out parameters. + +2015-02-26 Filip Pizlo <fpizlo@apple.com> + + The bool returning form of BytecodeGenerator::addVar() can be removed + https://bugs.webkit.org/show_bug.cgi?id=142064 + + Reviewed by Mark Lam. + + It's easier to implement addVar() when you don't have to return whether it's a new + variable or not. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::addVar): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::addVar): Deleted. + +2015-02-26 Filip Pizlo <fpizlo@apple.com> + + Various array access corner cases should take OSR exit feedback + https://bugs.webkit.org/show_bug.cgi?id=142056 + + Reviewed by Geoffrey Garen. + + Two major changes here: + + - Don't keep converting GetById into GetArrayLength if we exited due to any kind of array + type check. + + - Use a generic form of GetByVal/PutByVal if we exited due to any kind of exotic checks, + like the Arguments safety checks. We use the "ExoticObjectMode" for out-of-bounds on + arguments for now, since it's a convenient way of forcing out-of-bounds to be handled by + the Generic array mode. + + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): + * bytecode/ExitKind.h: + * dfg/DFGArrayMode.cpp: + (JSC::DFG::ArrayMode::refine): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileGetByValOnArguments): + (JSC::DFG::SpeculativeJIT::compileGetArgumentsLength): + * tests/stress/array-length-array-storage-plain-object.js: Added. + (foo): + * tests/stress/array-length-plain-object.js: Added. + (foo): + +2015-02-25 Filip Pizlo <fpizlo@apple.com> + + DFG SSA stack accesses shouldn't speak of VariableAccessDatas + https://bugs.webkit.org/show_bug.cgi?id=142036 + + Reviewed by Michael Saboff. + + VariableAccessData is a useful thing in LoadStore and ThreadedCPS, but it's purely harmful in + SSA because you can't cook up new VariableAccessDatas. So, if you know that you want to load + or store to the stack, and you know what format to use as well as the location, then prior to + this patch you couldn't do it unless you found some existing VariableAccessData that matched + your requirements. That can be a hard task. + + It's better if SSA doesn't speak of VariableAccessDatas but instead just has stack accesses + that speak of the things that a stack access needs: local, machineLocal, and format. This + patch changes the SSA way of accessing the stack to do just that. + + Also add more IR validation. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGFlushFormat.h: + (JSC::DFG::isConcrete): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::hasVariableAccessData): + * dfg/DFGNode.h: + (JSC::DFG::StackAccessData::StackAccessData): + (JSC::DFG::StackAccessData::flushedAt): + (JSC::DFG::Node::convertToPutStack): + (JSC::DFG::Node::convertToGetStack): + (JSC::DFG::Node::hasUnlinkedLocal): + (JSC::DFG::Node::hasStackAccessData): + (JSC::DFG::Node::stackAccessData): + (JSC::DFG::Node::willHaveCodeGenOrOSR): + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGPutLocalSinkingPhase.cpp: Removed. + * dfg/DFGPutLocalSinkingPhase.h: Removed. + * dfg/DFGPutStackSinkingPhase.cpp: Copied from Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp. + (JSC::DFG::performPutStackSinking): + (JSC::DFG::performPutLocalSinking): Deleted. + * dfg/DFGPutStackSinkingPhase.h: Copied from Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h. + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + (JSC::DFG::Validate::validateCPS): + (JSC::DFG::Validate::validateSSA): + * dfg/DFGVirtualRegisterAllocationPhase.cpp: + (JSC::DFG::VirtualRegisterAllocationPhase::run): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetStack): + (JSC::FTL::LowerDFGToLLVM::compilePutStack): + (JSC::FTL::LowerDFGToLLVM::compileGetLocal): Deleted. + (JSC::FTL::LowerDFGToLLVM::compilePutLocal): Deleted. + * ftl/FTLOSRExit.h: + * tests/stress/many-sunken-locals.js: Added. This failure mode was caught by some miscellaneous test, so I figured I should write an explicit test for it. + (foo): + (bar): + (baz): + (fuzz): + (buzz): + +2015-02-26 Mark Lam <mark.lam@apple.com> + + Rolling out r180602, r180608, r180613, r180617, r180671. + <https://webkit.org/b/141990> + + Not reviewed. + + The r180602 solution does result in more work for GC when worker + threads are in use. Filip is uncomfortable with that. + The EFL and GTK ports also seem to be unhappy with this change. + Rolling out while we investigate. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::gatherStackRoots): + (JSC::Heap::machineThreads): Deleted. + * heap/Heap.h: + (JSC::Heap::machineThreads): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::MachineThreads): + (JSC::MachineThreads::~MachineThreads): + (JSC::MachineThreads::addCurrentThread): + * heap/MachineStackMarker.h: + * runtime/JSLock.cpp: + (JSC::JSLock::didAcquireLock): + +2015-02-26 Myles C. Maxfield <mmaxfield@apple.com> + + [Mac] [iOS] Parsing support for -apple-trailing-word + https://bugs.webkit.org/show_bug.cgi?id=141939 + + Reviewed by Andreas Kling. + + * Configurations/FeatureDefines.xcconfig: + +2015-02-26 Michael Saboff <msaboff@apple.com> + + [Win] Debug-only JavaScriptCore failures + https://bugs.webkit.org/show_bug.cgi?id=142045 + + Rubber stamped by Filip Pizlo. + + Reduced loop count to a more reasonable value of 10,000. This still gets us to tier up + to the FTL, but doesn't take too long to run. + + * tests/stress/repeated-arity-check-fail.js: + +2015-02-26 Brent Fulgham <bfulgham@apple.com> + + [Win] Make build logs more legible by reducing noise + https://bugs.webkit.org/show_bug.cgi?id=142034 + + Reviewed by Alexey Proskuryakov. + + Modify batch files, makefiles, and DOS commands to remove + uninteresting/unhelpful output. + + * JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make: + * JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.vcxproj/jsc/jscLauncherPreBuild.cmd: + * JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd: + * JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreBuild.cmd: + * JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd: + * JavaScriptCore.vcxproj/testapi/testapiLauncherPostBuild.cmd: + * JavaScriptCore.vcxproj/testapi/testapiLauncherPreBuild.cmd: + * JavaScriptCore.vcxproj/testapi/testapiPostBuild.cmd: + * JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd: + +2015-02-26 Csaba Osztrogonác <ossy@webkit.org> + + Add calleeSaveRegisters() implementation for ARM Traditional + https://bugs.webkit.org/show_bug.cgi?id=141903 + + Reviewed by Darin Adler. + + * jit/RegisterSet.cpp: + (JSC::RegisterSet::calleeSaveRegisters): + +2015-02-25 Michael Saboff <msaboff@apple.com> + + Web Inspector: CRASH when debugger pauses inside a Promise handler + https://bugs.webkit.org/show_bug.cgi?id=141396 + + Reviewed by Mark Lam. + + For frames that don't have a scope, typically native frames, use the lexicalGlobalObject to + create the DebuggerScope for that frame. + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::scope): + +2015-02-25 Filip Pizlo <fpizlo@apple.com> + + DFG abstract heaps should respect the difference between heap and stack + https://bugs.webkit.org/show_bug.cgi?id=142022 + + Reviewed by Geoffrey Garen. + + We will soon (https://bugs.webkit.org/show_bug.cgi?id=141174) be in a world where a "world + clobbering" operation cannot write to our stack, but may be able to read from it. This + means that we need to change the DFG abstract heap hierarchy to have a notion of Heap that + subsumes all that World previously subsumed, and a new notion of Stack that is a subtype + of World and a sibling of Heap. + + So, henceforth "clobbering the world" means reading World and writing Heap. + + This makes a bunch of changes to make this work, including changing the implementation of + disjointness in AbstractHeap to make it support a more general hierarchy. I was expecting + a slow-down, but I measured the heck out of this and found no perf difference. + + * dfg/DFGAbstractHeap.cpp: + (JSC::DFG::AbstractHeap::dump): + * dfg/DFGAbstractHeap.h: + (JSC::DFG::AbstractHeap::supertype): + (JSC::DFG::AbstractHeap::isStrictSubtypeOf): + (JSC::DFG::AbstractHeap::isSubtypeOf): + (JSC::DFG::AbstractHeap::overlaps): + (JSC::DFG::AbstractHeap::isDisjoint): + * dfg/DFGClobberize.cpp: + (JSC::DFG::clobbersHeap): + (JSC::DFG::clobbersWorld): Deleted. + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + +2015-02-25 Ryosuke Niwa <rniwa@webkit.org> + + REGRESSION(r180595): construct varargs fails in FTL + https://bugs.webkit.org/show_bug.cgi?id=142030 + + Reviewed by Geoffrey Garen. + + The bug was caused by IC size being too small for construct_varargs even though we've added a new argument. + Fixed the bug by increasing the IC size to match call_varargs. + + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfConstructVarargs): + +2015-02-25 Mark Lam <mark.lam@apple.com> + + ASan does not like JSC::MachineThreads::tryCopyOtherThreadStack. + <https://webkit.org/b/141672> + + Reviewed by Alexey Proskuryakov. + + ASan does not like the fact that we memcpy the stack for GC scans. So, + we're working around this by using our own memcpy (asanUnsafeMemcpy) + implementation that we can tell ASan to ignore. + + * heap/MachineStackMarker.cpp: + (JSC::asanUnsafeMemcpy): + +2015-02-25 Benjamin Poulain <bpoulain@apple.com> + + CodeBlock crashes when dumping op_push_name_scope + https://bugs.webkit.org/show_bug.cgi?id=141953 + + Reviewed by Filip Pizlo and Csaba Osztrogonác. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * tests/stress/op-push-name-scope-crashes-profiler.js: Added. + +2015-02-25 Benjamin Poulain <benjamin@webkit.org> + + Make ParserError immutable by design + https://bugs.webkit.org/show_bug.cgi?id=141955 + + Reviewed by Geoffrey Garen. + + This patch enforce that no field of ParserError can + be modified after the constructor. + + * parser/ParserError.h: + Move the attributes to pack the integer + 2 bytes together. + This is irrelevant for memory impact, it is to remve a load-store + when copying by value. + + Also move the attributes to be private. + + (JSC::ParserError::isValid): + To client of the interface cared about the type of the error, + the only information needed was: is there an error. + + (JSC::ParserError::ParserError): + (JSC::ParserError::syntaxErrorType): + (JSC::ParserError::token): + (JSC::ParserError::message): + (JSC::ParserError::line): + (JSC::ParserError::toErrorObject): + * API/JSScriptRef.cpp: + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + (JSC::UnlinkedFunctionExecutable::fromGlobalCode): + (JSC::UnlinkedFunctionExecutable::codeBlockFor): + * bytecode/UnlinkedCodeBlock.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::parse): + * jsc.cpp: + (runInteractive): + * parser/Parser.h: + (JSC::parse): + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + * runtime/CodeCache.h: + * runtime/Completion.h: + * runtime/Executable.cpp: + (JSC::ProgramExecutable::checkSyntax): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::createProgramCodeBlock): + (JSC::JSGlobalObject::createEvalCodeBlock): + +2015-02-25 Filip Pizlo <fpizlo@apple.com> + + Need to pass RTLD_DEEPBIND to dlopen() to ensure that our LLVMOverrides take effect on Linux + https://bugs.webkit.org/show_bug.cgi?id=142006 + + Reviewed by Csaba Osztrogonác. + + This fixes hard-to-reproduce concurrency-related crashes when running stress tests with FTL and + concurrent JIT enabled. + + * llvm/InitializeLLVMPOSIX.cpp: + (JSC::initializeLLVMPOSIX): + +2015-02-24 Filip Pizlo <fpizlo@apple.com> + + CMake build of libllvmForJSC.so should limit its export list like the Xcode build does + https://bugs.webkit.org/show_bug.cgi?id=141989 + + Reviewed by Gyuyoung Kim. + + * CMakeLists.txt: + * llvm/library/libllvmForJSC.version: Added. + +2015-02-24 Alexey Proskuryakov <ap@apple.com> + + More iOS build fix after r180602. + + * heap/Heap.h: Export Heap::machineThreads(). + +2015-02-24 Brent Fulgham <bfulgham@apple.com> + + Unreviewed build fix after r180602. + + * heap/MachineStackMarker.h: Add missing 'no return' + declaration for Windows. + +2015-02-24 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r180599. + https://bugs.webkit.org/show_bug.cgi?id=141998 + + Lots of new test failures (Requested by smfr on #webkit). + + Reverted changeset: + + "Parsing support for -webkit-trailing-word" + https://bugs.webkit.org/show_bug.cgi?id=141939 + http://trac.webkit.org/changeset/180599 + +2015-02-24 Mark Lam <mark.lam@apple.com> + + MachineThreads::Thread clean up has a use after free race condition. + <https://webkit.org/b/141990> + + Reviewed by Michael Saboff. + + MachineThreads::Thread clean up relies on the clean up mechanism + implemented in _pthread_tsd_cleanup_key(), which looks like this: + + void _pthread_tsd_cleanup_key(pthread_t self, pthread_key_t key) + { + void (*destructor)(void *); + if (_pthread_key_get_destructor(key, &destructor)) { + void **ptr = &self->tsd[key]; + void *value = *ptr; + + // At this point, this thread has cached "destructor" and "value" + // (which is a MachineThreads*). If the VM gets destructed (along + // with its MachineThreads registry) by another thread, then this + // thread will have no way of knowing that the MachineThreads* is + // now pointing to freed memory. Calling the destructor below will + // therefore result in a use after free scenario when it tries to + // access the MachineThreads' data members. + + if (value) { + *ptr = NULL; + if (destructor) { + destructor(value); + } + } + } + } + + The solution is simply to change MachineThreads from a per VM thread + registry to a process global singleton thread registry i.e. the + MachineThreads registry is now immortal and we cannot have a use after + free scenario since we never free it. + + The cost of this change is that all VM instances will have to scan + stacks of all threads ever touched by a VM, and not just those that + touched a specific VM. However, stacks tend to be shallow. Hence, + those additional scans will tend to be cheap. + + Secondly, it is not common for there to be multiple JSC VMs in use + concurrently on multiple threads. Hence, this cost should rarely + manifest in real world applications. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::machineThreads): + (JSC::Heap::gatherStackRoots): + * heap/Heap.h: + (JSC::Heap::machineThreads): Deleted. + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::MachineThreads): + (JSC::MachineThreads::~MachineThreads): + (JSC::MachineThreads::addCurrentThread): + * heap/MachineStackMarker.h: + * runtime/JSLock.cpp: + (JSC::JSLock::didAcquireLock): + +2015-02-24 Myles C. Maxfield <mmaxfield@apple.com> + + [Mac] [iOS] Parsing support for -apple-trailing-word + https://bugs.webkit.org/show_bug.cgi?id=141939 + + Reviewed by Andreas Kling. + + * Configurations/FeatureDefines.xcconfig: + +2015-02-24 Ryosuke Niwa <rniwa@webkit.org> + + Use "this" instead of "callee" to get the constructor + https://bugs.webkit.org/show_bug.cgi?id=141019 + + Reviewed by Filip Pizlo. + + This patch uses "this" register to pass the constructor (newTarget) to op_create_this from + op_construct or op_construct_varargs. This will allow future patches that implement ES6 class + to pass in the most derived class' constructor through "this" argument. + + BytecodeGenerator's emitConstruct and emitConstructVarargs now passes thisRegister like + regular calls and emitCreateThis passes in this register to op_create_this as constructor. + + The rest of the code change removes the code for special casing "this" register not being used + in call to construct. + + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitCreateThis): + (JSC::BytecodeGenerator::emitConstructVarargs): + (JSC::BytecodeGenerator::emitConstruct): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::NewExprNode::emitBytecode): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): + (JSC::DFG::ByteCodeParser::handleVarargsCall): + (JSC::DFG::ByteCodeParser::emitArgumentPhantoms): + (JSC::DFG::ByteCodeParser::attemptToInlineCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGJITCode.cpp: + (JSC::DFG::JITCode::reconstruct): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * ftl/FTLJSCallVarargs.cpp: + (JSC::FTL::JSCallVarargs::emit): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstructVarargs): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::executeConstruct): + * jit/JITOperations.cpp: + +2015-02-24 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Make Getter/Setter RemoteObject property and ObjectPreview handling consistent + https://bugs.webkit.org/show_bug.cgi?id=141587 + + Reviewed by Timothy Hatcher. + + Convert getProperties(ownAndGetterProperties) to getDisplayableProperties(). + Mark PropertyDescriptors that are presumed to be native getters / bindings + separately so that the frontend may display them differently. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getDisplayableProperties): + * inspector/InjectedScript.h: + * inspector/InjectedScriptSource.js: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getProperties): + (Inspector::InspectorRuntimeAgent::getDisplayableProperties): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + +2015-02-24 Mark Lam <mark.lam@apple.com> + + Rolling out r179753. The fix was invalid. + <https://webkit.org/b/141990> + + Not reviewed. + + * API/tests/testapi.mm: + (threadMain): + (useVMFromOtherThread): Deleted. + (useVMFromOtherThreadAndOutliveVM): Deleted. + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::~Heap): + (JSC::Heap::gatherStackRoots): + * heap/Heap.h: + (JSC::Heap::machineThreads): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::Thread::Thread): + (JSC::MachineThreads::MachineThreads): + (JSC::MachineThreads::~MachineThreads): + (JSC::MachineThreads::addCurrentThread): + (JSC::MachineThreads::removeThread): + (JSC::MachineThreads::removeCurrentThread): + * heap/MachineStackMarker.h: + +2015-02-24 Yusuke Suzuki <utatane.tea@gmail.com> + + Constructor returning null should construct an object instead of null + https://bugs.webkit.org/show_bug.cgi?id=141640 + + Reviewed by Filip Pizlo. + + When constructor code doesn't return object, constructor should return `this` object instead. + Since we used `op_is_object` for this check and `op_is_object` is intended to be used for `typeof`, + it allows `null` as an object. + This patch fixes it by introducing an new bytecode `op_is_object_or_null` for `typeof` use cases. + Instead, constructor uses simplified `is_object`. + + As a result, `op_is_object` becomes fairly simple. So we introduce optimization for `op_is_object`. + + 1. LLInt and baseline JIT support `op_is_object` as a fast path. + 2. DFG abstract interpreter support `op_is_object`. And recognize its speculated type and read-write effects. + 3. DFG introduces inlined asm for `op_is_object` rather than calling a C++ function. + 4. FTL lowers DFG's IsObject into LLVM IR. + + And at the same time, this patch fixes isString / isObject predicate used for `op_is_object` and others + in LLInt, JIT, DFG and FTL. + Before introducing ES6 Symbol, JSCell is only used for object and string in user observable area. + So in many places, when the cell is not object, we recognize it as a string, and vice versa. + However, now ES6 Symbol is implemented as a JSCell, this assumption is broken. + So this patch stop using !isString as isObject. + To check whether a cell is an object, instead of seeing that structure ID of a cell is not stringStructure, + we examine typeInfo in JSCell. + + * JavaScriptCore.order: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitEqualityOp): + (JSC::BytecodeGenerator::emitReturn): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + + IsObject operation only touches JSCell typeInfoType. + And this value would be changed through structure transition. + As a result, IsObject can report that it doesn't read any information. + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + + Just like IsString, IsObject is also fixed up. + + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): + (JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality): + (JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality): + (JSC::DFG::SpeculativeJIT::compileToStringOnCell): + (JSC::DFG::SpeculativeJIT::speculateObject): + (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): + (JSC::DFG::SpeculativeJIT::speculateString): + (JSC::DFG::SpeculativeJIT::speculateNotStringVar): + (JSC::DFG::SpeculativeJIT::emitSwitchChar): + (JSC::DFG::SpeculativeJIT::emitSwitchString): + (JSC::DFG::SpeculativeJIT::branchIsObject): + (JSC::DFG::SpeculativeJIT::branchNotObject): + (JSC::DFG::SpeculativeJIT::branchIsString): + (JSC::DFG::SpeculativeJIT::branchNotString): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileToString): + (JSC::FTL::LowerDFGToLLVM::compileIsObject): + (JSC::FTL::LowerDFGToLLVM::compileIsObjectOrNull): + (JSC::FTL::LowerDFGToLLVM::speculateTruthyObject): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::isObject): + (JSC::FTL::LowerDFGToLLVM::isNotObject): + (JSC::FTL::LowerDFGToLLVM::isNotString): + (JSC::FTL::LowerDFGToLLVM::speculateNonNullObject): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::emitJumpIfCellObject): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_is_object): + (JSC::JIT::emit_op_to_primitive): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_is_object): + (JSC::JIT::emit_op_to_primitive): + (JSC::JIT::compileOpStrictEq): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/Operations.cpp: + (JSC::jsIsObjectTypeOrNull): + (JSC::jsIsObjectType): Deleted. + * runtime/Operations.h: + * tests/stress/constructor-with-return.js: Added. + (Test): + + When constructor doesn't return an object, `this` should be returned instead. + In this test, we check all primitives. And test object, array and wrappers. + + * tests/stress/dfg-to-primitive-pass-symbol.js: Added. + (toPrimitiveTarget): + (doToPrimitive): + + op_to_primitive operation passes Symbol in fast path. + +2015-02-24 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION(r179429): Can't type comments in Facebook + https://bugs.webkit.org/show_bug.cgi?id=141859 + + Reviewed by Brent Fulgham. + + When window.Symbol is exposed to user-space pages, + Facebook's JavaScript use it (maybe, for immutable-js and React.js's unique key). + However, to work with Symbols completely, it also requires + 1) Object.getOwnPropertySymbols (for mixin including Symbols) + 2) the latest ES6 Iterator interface that uses Iterator.next and it returns { done: boolean, value: value }. + Since they are not landed yet, comments in Facebook don't work. + + This patch introduces RuntimeFlags for JavaScriptCore. + Specifying SymbolEnabled flag under test runner and inspector to continue to work with Symbol. + And drop JavaScriptExperimentsEnabled flag + because it is no longer used and use case of this is duplicated to runtime flags. + + * JavaScriptCore.order: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * jsc.cpp: + (GlobalObject::javaScriptRuntimeFlags): + (GlobalObject::javaScriptExperimentsEnabled): Deleted. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::finishCreation): + (JSC::JSGlobalObject::javaScriptRuntimeFlags): + (JSC::JSGlobalObject::javaScriptExperimentsEnabled): Deleted. + * runtime/RuntimeFlags.h: Added. + (JSC::RuntimeFlags::RuntimeFlags): + (JSC::RuntimeFlags::createAllEnabled): + +2015-02-23 Filip Pizlo <fpizlo@apple.com> + + Our bizarre behavior on Arguments::defineOwnProperty should be deliberate rather than a spaghetti incident + https://bugs.webkit.org/show_bug.cgi?id=141951 + + Reviewed by Benjamin Poulain. + + This patch has no behavioral change, but it simplifies a bunch of wrong code. The code is + still wrong in exactly the same way, but at least it's obvious what's going on. The wrongness + is covered by this bug: https://bugs.webkit.org/show_bug.cgi?id=141952. + + * runtime/Arguments.cpp: + (JSC::Arguments::copyBackingStore): We should only see the arguments token; assert otherwise. This works because if the GC sees the butterfly token it calls the JSObject::copyBackingStore method directly. + (JSC::Arguments::defineOwnProperty): Make our bizarre behavior deliberate rather than an accident of a decade of patches. + * tests/stress/arguments-bizarre-behavior.js: Added. + (foo): + * tests/stress/arguments-bizarre-behaviour-disable-enumerability.js: Added. My choice of spellings of the word "behavio[u]r" is almost as consistent as our implementation of arguments. + (foo): + * tests/stress/arguments-custom-properties-gc.js: Added. I added this test because at first I was unsure if we GCd arguments correctly. + (makeBaseArguments): + (makeArray): + (cons): + +2015-02-23 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r180547 and r180550. + https://bugs.webkit.org/show_bug.cgi?id=141957 + + Broke 10 Windows tests. (Requested by bfulgham_ on #webkit). + + Reverted changesets: + + "REGRESSION(r179429): Can't type comments in Facebook" + https://bugs.webkit.org/show_bug.cgi?id=141859 + http://trac.webkit.org/changeset/180547 + + "Constructor returning null should construct an object instead + of null" + https://bugs.webkit.org/show_bug.cgi?id=141640 + http://trac.webkit.org/changeset/180550 + +2015-02-23 Yusuke Suzuki <utatane.tea@gmail.com> + + Constructor returning null should construct an object instead of null + https://bugs.webkit.org/show_bug.cgi?id=141640 + + Reviewed by Geoffrey Garen. + + When constructor code doesn't return object, constructor should return `this` object instead. + Since we used `op_is_object` for this check and `op_is_object` is intended to be used for `typeof`, + it allows `null` as an object. + This patch fixes it by introducing an new bytecode `op_is_object_or_null` for `typeof` use cases. + Instead, constructor uses simplified `is_object`. + + As a result, `op_is_object` becomes fairly simple. So we introduce optimization for `op_is_object`. + + 1. LLInt and baseline JIT support `op_is_object` as a fast path. + 2. DFG abstract interpreter support `op_is_object`. And recognize its speculated type and read-write effects. + 3. DFG introduces inlined asm for `op_is_object` rather than calling a C++ function. + 4. FTL lowers DFG's IsObject into LLVM IR. + + And at the same time, this patch fixes isString / isObject predicate used for `op_is_object` and others + in LLInt, JIT, DFG and FTL. + Before introducing ES6 Symbol, JSCell is only used for object and string in user observable area. + So in many places, when the cell is not object, we recognize it as a string, and vice versa. + However, now ES6 Symbol is implemented as a JSCell, this assumption is broken. + So this patch stop using !isString as isObject. + To check whether a cell is an object, instead of seeing that structure ID of a cell is not stringStructure, + we examine typeInfo in JSCell. + + * JavaScriptCore.order: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitEqualityOp): + (JSC::BytecodeGenerator::emitReturn): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + + IsObject operation only touches JSCell typeInfoType. + And this value would not be changed through structure transition. + As a result, IsObject can report that it doesn't read any information. + + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + + Just like IsString, IsObject is also fixed up. + + * dfg/DFGHeapLocation.cpp: + (WTF::printInternal): + * dfg/DFGHeapLocation.h: + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): + (JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality): + (JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality): + (JSC::DFG::SpeculativeJIT::compileToStringOnCell): + (JSC::DFG::SpeculativeJIT::speculateObject): + (JSC::DFG::SpeculativeJIT::speculateObjectOrOther): + (JSC::DFG::SpeculativeJIT::speculateString): + (JSC::DFG::SpeculativeJIT::speculateNotStringVar): + (JSC::DFG::SpeculativeJIT::emitSwitchChar): + (JSC::DFG::SpeculativeJIT::emitSwitchString): + (JSC::DFG::SpeculativeJIT::branchIsObject): + (JSC::DFG::SpeculativeJIT::branchNotObject): + (JSC::DFG::SpeculativeJIT::branchIsString): + (JSC::DFG::SpeculativeJIT::branchNotString): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compileObjectEquality): + (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality): + (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): + (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch): + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileToString): + (JSC::FTL::LowerDFGToLLVM::compileIsObject): + (JSC::FTL::LowerDFGToLLVM::compileIsObjectOrNull): + (JSC::FTL::LowerDFGToLLVM::speculateTruthyObject): + (JSC::FTL::LowerDFGToLLVM::equalNullOrUndefined): + (JSC::FTL::LowerDFGToLLVM::isObject): + (JSC::FTL::LowerDFGToLLVM::isNotObject): + (JSC::FTL::LowerDFGToLLVM::isNotString): + (JSC::FTL::LowerDFGToLLVM::speculateNonNullObject): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::emitJumpIfCellObject): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_is_object): + (JSC::JIT::emit_op_to_primitive): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_is_object): + (JSC::JIT::emit_op_to_primitive): + (JSC::JIT::compileOpStrictEq): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/Operations.cpp: + (JSC::jsIsObjectTypeOrNull): + (JSC::jsIsObjectType): Deleted. + * runtime/Operations.h: + +2015-02-23 Ryosuke Niwa <rniwa@webkit.org> + + Disable font loading events until our implementation gets updated to match the latest spec + https://bugs.webkit.org/show_bug.cgi?id=141938 + + Reviewed by Andreas Kling. + + * Configurations/FeatureDefines.xcconfig: + +2015-02-23 Yusuke Suzuki <utatane.tea@gmail.com> + + REGRESSION(r179429): Can't type comments in Facebook + https://bugs.webkit.org/show_bug.cgi?id=141859 + + Reviewed by Geoffrey Garen. + + When window.Symbol is exposed to user-space pages, + Facebook's JavaScript use it (maybe, for immutable-js and React.js's unique key). + However, to work with Symbols completely, it also requires + 1) Object.getOwnPropertySymbols (for mixin including Symbols) + 2) the latest ES6 Iterator interface that uses Iterator.next and it returns { done: boolean, value: value }. + Since they are not landed yet, comments in Facebook don't work. + + This patch introduces RuntimeFlags for JavaScriptCore. + Specifying SymbolEnabled flag under test runner and inspector to continue to work with Symbol. + And drop JavaScriptExperimentsEnabled flag + because it is no longer used and use case of this is duplicated to runtime flags. + + * JavaScriptCore.order: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * jsc.cpp: + (GlobalObject::javaScriptRuntimeFlags): + (GlobalObject::javaScriptExperimentsEnabled): Deleted. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::JSGlobalObject): + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::finishCreation): + (JSC::JSGlobalObject::javaScriptRuntimeFlags): + (JSC::JSGlobalObject::javaScriptExperimentsEnabled): Deleted. + * runtime/RuntimeFlags.h: Added. + (JSC::RuntimeFlags::RuntimeFlags): + (JSC::RuntimeFlags::createAllEnabled): + +2015-02-23 Benjamin Poulain <bpoulain@apple.com> + + Set the semantic origin of delayed SetLocal to the Bytecode that originated it + https://bugs.webkit.org/show_bug.cgi?id=141727 + + Reviewed by Filip Pizlo. + + Previously, delayed SetLocals would have the NodeOrigin of the next + bytecode. This was because delayed SetLocal are...delayed... and + currentCodeOrigin() is the one where the node is emitted. + + This made debugging a little awkward since the OSR exits on SetLocal + were reported for the next bytecode. This patch changes the semantic + origin to keep the original bytecode. + + From benchmarks, this looks like it could be a tiny bit faster + but it likely just noise. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::setDirect): + (JSC::DFG::ByteCodeParser::setLocal): + (JSC::DFG::ByteCodeParser::setArgument): + (JSC::DFG::ByteCodeParser::currentNodeOrigin): + (JSC::DFG::ByteCodeParser::addToGraph): + (JSC::DFG::ByteCodeParser::DelayedSetLocal::DelayedSetLocal): + (JSC::DFG::ByteCodeParser::DelayedSetLocal::execute): + +2015-02-23 Benjamin Poulain <bpoulain@apple.com> + + Remove DFGNode::predictHeap() + https://bugs.webkit.org/show_bug.cgi?id=141864 + + Reviewed by Geoffrey Garen. + + * dfg/DFGNode.h: + (JSC::DFG::Node::predictHeap): Deleted. + Unused code. + +2015-02-23 Filip Pizlo <fpizlo@apple.com> + + Get rid of JSLexicalEnvironment::argumentsGetter + https://bugs.webkit.org/show_bug.cgi?id=141930 + + Reviewed by Mark Lam. + + This function is unused, and the way it's written is bizarre - it's a return statement that + dominates a bunch of dead code. + + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::argumentsGetter): Deleted. + * runtime/JSLexicalEnvironment.h: + +2015-02-23 Filip Pizlo <fpizlo@apple.com> + + Remove unused activationCount and allTheThingsCount variable declarations. + + Rubber stamped by Mark Lam and Michael Saboff. + + * runtime/JSLexicalEnvironment.h: + +2015-02-23 Saam Barati <saambarati1@gmail.com> + + Adjust the ranges of basic block statements in JSC's control flow profiler to be mutually exclusive + https://bugs.webkit.org/show_bug.cgi?id=141095 + + Reviewed by Mark Lam. + + Suppose the control flow of a program forms basic block A with successor block + B. A's end offset will be the *same* as B's start offset in the current architecture + of the control flow profiler. This makes reasoning about the text offsets of + the control flow profiler unsound. To make reasoning about offsets sound, all + basic block ranges should be mutually exclusive. All calls to emitProfileControlFlow + now pass in the *start* of a basic block as the text offset argument. This simplifies + all calls to emitProfileControlFlow because the previous implementation had a + lot of edge cases for getting the desired basic block text boundaries. + + This patch also ensures that the basic block boundary of a block statement + is the exactly the block's open and close brace offsets (inclusive). For example, + in if/for/while statements. This also has the consequence that for statements + like "if (cond) foo();", the whitespace preceding "foo()" is not part of + the "foo()" basic block, but instead is part of the "if (cond) " basic block. + This is okay because these text offsets aren't meant to be human readable. + Instead, they reflect the text offsets of JSC's AST nodes. The Web Inspector + is the only client of this API and user of these text offsets and it is + not negatively effected by this new behavior. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler): + When computing basic block boundaries in CodeBlock, we ensure that every + block's end offset is one less than its successor's start offset to + maintain that boundaries' ranges should be mutually exclusive. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + Because the control flow profiler needs to know which functions + have executed, we can't lazily create functions. This was a bug + from before that was hidden because the Type Profiler was always + enabled when the control flow profiler was enabled when profiling + was turned on from the Web Inspector. But, JSC allows for Control + Flow profiling to be turned on without Type Profiling, so we need + to ensure the Control Flow profiler has all the data it needs. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ConditionalNode::emitBytecode): + (JSC::IfElseNode::emitBytecode): + (JSC::WhileNode::emitBytecode): + (JSC::ForNode::emitBytecode): + (JSC::ForInNode::emitMultiLoopBytecode): + (JSC::ForOfNode::emitBytecode): + (JSC::TryNode::emitBytecode): + * jsc.cpp: + (functionHasBasicBlockExecuted): + We now assert that the substring argument is indeed a substring + of the function argument's text because subtle bugs could be + introduced otherwise. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::setStartOffset): + * parser/Nodes.h: + (JSC::Node::setStartOffset): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseBlockStatement): + (JSC::Parser<LexerType>::parseStatement): + (JSC::Parser<LexerType>::parseMemberExpression): + For the various function call AST nodes, their m_position member + variable is now the start of the entire function call expression + and not at the start of the open paren of the arguments list. + + * runtime/BasicBlockLocation.cpp: + (JSC::BasicBlockLocation::getExecutedRanges): + * runtime/ControlFlowProfiler.cpp: + (JSC::ControlFlowProfiler::getBasicBlocksForSourceID): + Function ranges inserted as gaps should follow the same criteria + that the bytecode generator uses to ensure that basic blocks + start and end offsets are mutually exclusive. + + * tests/controlFlowProfiler/brace-location.js: Added. + (foo): + (bar): + (baz): + (testIf): + (testForRegular): + (testForIn): + (testForOf): + (testWhile): + (testIfNoBraces): + (testForRegularNoBraces): + (testForInNoBraces): + (testForOfNoBraces): + (testWhileNoBraces): + * tests/controlFlowProfiler/conditional-expression.js: Added. + (foo): + (bar): + (baz): + (testConditionalBasic): + (testConditionalFunctionCall): + * tests/controlFlowProfiler/driver/driver.js: + (checkBasicBlock): + +2015-02-23 Matthew Mirman <mmirman@apple.com> + + r9 is volatile on ARMv7 for iOS 3 and up. + https://bugs.webkit.org/show_bug.cgi?id=141489 + rdar://problem/19432916 + + Reviewed by Michael Saboff. + + * jit/RegisterSet.cpp: + (JSC::RegisterSet::calleeSaveRegisters): removed r9 from the list of ARMv7 callee save registers. + * tests/stress/regress-141489.js: Added. + (foo): + +2015-02-23 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Add the necessary setupArgumentsWithExecState after bug141915 + https://bugs.webkit.org/show_bug.cgi?id=141921 + + Reviewed by Michael Saboff. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2015-02-23 Filip Pizlo <fpizlo@apple.com> + + Scopes should always be created with a previously-created symbol table rather than creating one on the fly + https://bugs.webkit.org/show_bug.cgi?id=141915 + + Reviewed by Mark Lam. + + The main effect of this change is that pushing name scopes no longer requires creating symbol + tables on the fly. + + This also makes it so that JSEnvironmentRecords must always have an a priori symbol table. + + JSSegmentedVariableObject still does a hack where it creates a blank symbol table on-demand. + This is needed because that's what JSGlobalObject and all of its many subclasses want. That's + harmless; I mainly needed a prior symbol tables for JSEnvironmentRecords anyway. + + * bytecode/BytecodeList.json: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitPushFunctionNameScope): + (JSC::BytecodeGenerator::emitPushCatchScope): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOperations.cpp: + (JSC::pushNameScope): + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * runtime/Executable.cpp: + (JSC::ScriptExecutable::newCodeBlockFor): + * runtime/JSCatchScope.h: + (JSC::JSCatchScope::JSCatchScope): + (JSC::JSCatchScope::create): + * runtime/JSEnvironmentRecord.h: + (JSC::JSEnvironmentRecord::JSEnvironmentRecord): + * runtime/JSFunctionNameScope.h: + (JSC::JSFunctionNameScope::JSFunctionNameScope): + (JSC::JSFunctionNameScope::create): + * runtime/JSNameScope.cpp: + (JSC::JSNameScope::create): + * runtime/JSNameScope.h: + (JSC::JSNameScope::create): + (JSC::JSNameScope::finishCreation): + (JSC::JSNameScope::JSNameScope): + * runtime/JSSegmentedVariableObject.h: + (JSC::JSSegmentedVariableObject::finishCreation): + * runtime/JSSymbolTableObject.h: + (JSC::JSSymbolTableObject::JSSymbolTableObject): + (JSC::JSSymbolTableObject::finishCreation): Deleted. + * runtime/SymbolTable.h: + (JSC::SymbolTable::createNameScopeTable): + +2015-02-23 Filip Pizlo <fpizlo@apple.com> + + Add a comment to clarify that the test was taken from the bug report, in response to + feedback from Michael Saboff and Benjamin Poulain. + + * tests/stress/regress-141883.js: + +2015-02-22 Filip Pizlo <fpizlo@apple.com> + + Function name scope is only created on the function instance that triggered parsing rather than on every function instance that needs it + https://bugs.webkit.org/show_bug.cgi?id=141881 + + Reviewed by Michael Saboff. + + Previously we only created the function name scope in a way that made it visible to the + function that triggered parsing/linking of the executable/codeBlock, and to the linker for + that code block. This was sort of the bare minimum for the feature to appear to work right to + synthetic tests. + + There are two valid "times" to create the function name scope. Either it's created for each + JSFunction instance that needs a name scope, or it's created for each execution of such a + JSFunction. This change chooses the latter, because it happens to be the easiest to implement + with what we have right now. I opened a bug for optimizing this if we ever need to: + https://bugs.webkit.org/show_bug.cgi?id=141887. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::prepareForRepeatCall): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::setUpCall): + * runtime/ArrayPrototype.cpp: + (JSC::isNumericCompareFunction): + * runtime/Executable.cpp: + (JSC::ScriptExecutable::newCodeBlockFor): + (JSC::ScriptExecutable::prepareForExecutionImpl): + (JSC::FunctionExecutable::FunctionExecutable): + * runtime/Executable.h: + (JSC::ScriptExecutable::prepareForExecution): + * runtime/JSFunction.cpp: + (JSC::JSFunction::addNameScopeIfNeeded): Deleted. + * runtime/JSFunction.h: + * tests/stress/function-name-scope.js: Added. + (check.verify): + (check): + +2015-02-22 Filip Pizlo <fpizlo@apple.com> + + Crash in DFGFrozenValue + https://bugs.webkit.org/show_bug.cgi?id=141883 + + Reviewed by Benjamin Poulain. + + If a value might be a cell, then we have to have Graph freeze it rather than trying to + create the FrozenValue directly. Creating it directly is just an optimization for when you + know for sure that it cannot be a cell. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * tests/stress/regress-141883.js: Added. Hacked the original test to be faster while still crashing before this fix. + +2015-02-21 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Generate Previews more often for RemoteObject interaction + https://bugs.webkit.org/show_bug.cgi?id=141875 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Runtime.json: + Add generatePreview to getProperties. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getInternalProperties): + * inspector/InjectedScript.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getProperties): + * inspector/agents/InspectorRuntimeAgent.h: + Plumb the generatePreview boolean through to the injected script. + + * inspector/InjectedScriptSource.js: + Add generatePreview for getProperties. + Fix callFunctionOn to generatePreviews if asked. + +2015-02-20 Mark Lam <mark.lam@apple.com> + + Refactor JSWrapperMap.mm to defer creation of the ObjC JSValue until the latest possible moment. + <https://webkit.org/b/141856> + + Reviewed by Geoffrey Garen. + + 1. Make JSObjCClassInfo's -constructor and -wrapperForObject return a + JSC::JSObject* just like -prototype. + 2. Defer the creation of the ObjC JSValue from JSC::JSObject* until + the latest moment when it is needed. This allows us to not have to + keep converting back to a JSC::JSObject* in intermediate code. + + * API/JSWrapperMap.mm: + (makeWrapper): + (objectWithCustomBrand): + (constructorWithCustomBrand): + (allocateConstructorForCustomClass): + (-[JSObjCClassInfo allocateConstructorAndPrototype]): + (-[JSObjCClassInfo wrapperForObject:]): + (-[JSObjCClassInfo constructor]): + (-[JSWrapperMap jsWrapperForObject:]): + +2015-02-20 Filip Pizlo <fpizlo@apple.com> + + Build fix for gcc. + + * runtime/JSNameScope.cpp: + (JSC::JSNameScope::create): + +2015-02-20 Filip Pizlo <fpizlo@apple.com> + + Get rid of JSNameScope::m_type + https://bugs.webkit.org/show_bug.cgi?id=141851 + + Reviewed by Geoffrey Garen. + + This is a big step towards getting rid of JSEnvironmentRecord::m_registers. To do it we need + to ensure that subclasses of JSEnvironmentRecord never have additional C++ fields, so that + JSEnvironmentRecord can always place "registers" right after the end of itself. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::isCatchScope): + (JSC::DebuggerScope::isFunctionNameScope): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/JSCatchScope.cpp: Added. + * runtime/JSCatchScope.h: Added. + (JSC::JSCatchScope::JSCatchScope): + (JSC::JSCatchScope::create): + (JSC::JSCatchScope::createStructure): + * runtime/JSFunction.cpp: + (JSC::JSFunction::addNameScopeIfNeeded): + * runtime/JSFunctionNameScope.cpp: Added. + * runtime/JSFunctionNameScope.h: Added. + (JSC::JSFunctionNameScope::JSFunctionNameScope): + (JSC::JSFunctionNameScope::create): + (JSC::JSFunctionNameScope::createStructure): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::catchScopeStructure): + (JSC::JSGlobalObject::functionNameScopeStructure): + (JSC::JSGlobalObject::nameScopeStructure): Deleted. + * runtime/JSNameScope.cpp: + (JSC::JSNameScope::create): + * runtime/JSNameScope.h: + (JSC::JSNameScope::create): + (JSC::JSNameScope::JSNameScope): + (JSC::JSNameScope::createStructure): Deleted. + (JSC::JSNameScope::isFunctionNameScope): Deleted. + (JSC::JSNameScope::isCatchScope): Deleted. + * runtime/JSObject.cpp: + (JSC::JSObject::isCatchScopeObject): + (JSC::JSObject::isFunctionNameScopeObject): + * runtime/JSObject.h: + +2015-02-20 Mark Lam <mark.lam@apple.com> + + [JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate super class prototype chain. + <https://webkit.org/b/141809> + + Reviewed by Geoffrey Garen. + + A ObjC class that implement the JSExport protocol will have a JS prototype + chain and constructor automatically synthesized for its JS wrapper object. + However, if there are no more instances of that ObjC class reachable by a + JS GC root scan, then its synthesized prototype chain and constructors may + be released by the GC. If a new instance of that ObjC class is subsequently + instantiated, then [JSObjCClassInfo reallocateConstructorAndOrPrototype] + should re-construct the prototype chain and constructor (if they were + previously released). However, the current implementation only + re-constructs the immediate prototype, but not every other prototype + object upstream in the prototype chain. + + To fix this, we do the following: + 1. We no longer allocate the JSObjCClassInfo's prototype and constructor + eagerly. Hence, -initWithContext:forClass: will no longer call + -allocateConstructorAndPrototypeWithSuperClassInfo:. + 2. Instead, we'll always access the prototype and constructor thru + accessor methods. The accessor methods will call + -allocateConstructorAndPrototype: if needed. + 3. -allocateConstructorAndPrototype: will fetch the needed superClassInfo + from the JSWrapperMap itself. This makes it so that we no longer + need to pass the superClassInfo all over. + 4. -allocateConstructorAndPrototype: will get the super class prototype + by invoking -prototype: on the superClassInfo, thereby allowing the + super class to allocate its prototype and constructor if needed and + fixing the issue in this bug. + + 5. Also removed the GC warning comments, and ensured that needed JS + objects are kept alive by having a local var pointing to it from the + stack (which makes a GC root). + + * API/JSWrapperMap.mm: + (-[JSObjCClassInfo initWithContext:forClass:]): + (-[JSObjCClassInfo allocateConstructorAndPrototype]): + (-[JSObjCClassInfo wrapperForObject:]): + (-[JSObjCClassInfo constructor]): + (-[JSObjCClassInfo prototype]): + (-[JSWrapperMap classInfoForClass:]): + (-[JSObjCClassInfo initWithContext:forClass:superClassInfo:]): Deleted. + (-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): Deleted. + (-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): Deleted. + * API/tests/Regress141809.h: Added. + * API/tests/Regress141809.mm: Added. + (-[TestClassB name]): + (-[TestClassC name]): + (runRegress141809): + * API/tests/testapi.mm: + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-02-20 Alexey Proskuryakov <ap@apple.com> + + Remove svn:keywords property. + + As far as I can tell, the property had no effect on any of these files, but also, + when it has effect it's likely harmful. + + * builtins/ArrayConstructor.js: Removed property svn:keywords. + +2015-02-20 Michael Saboff <msaboff@apple.com> + + DFG JIT needs to check for stack overflow at the start of Program and Eval execution + https://bugs.webkit.org/show_bug.cgi?id=141676 + + Reviewed by Filip Pizlo. + + Added stack check to the beginning of the code the DFG copmiler emits for Program and Eval nodes. + To aid in testing the code, I replaced the EvalCodeCache::maxCacheableSourceLength const + a options in runtime/Options.h. The test script, run-jsc-stress-tests, sets that option + to a huge value when running with the "Eager" options. This allows the updated test to + reliably exercise the code in questions. + + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compile): + Added stack check. + + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::tryGet): + (JSC::EvalCodeCache::getSlow): + * runtime/Options.h: + Replaced EvalCodeCache::imaxCacheableSourceLength with Options::maximumEvalCacheableSourceLength + so that it can be configured when running the related test. + +2015-02-20 Eric Carlson <eric.carlson@apple.com> + + [iOS] cleanup AirPlay code + https://bugs.webkit.org/show_bug.cgi?id=141811 + + Reviewed by Jer Noble. + + * Configurations/FeatureDefines.xcconfig: IOS_AIRPLAY -> WIRELESS_PLAYBACK_TARGET. + +2015-02-19 Dean Jackson <dino@apple.com> + + ES6: Implement Array.from() + https://bugs.webkit.org/show_bug.cgi?id=141054 + <rdar://problem/19654521> + + Reviewed by Filip Pizlo. + + Implement the Array.from() ES6 method + as defined in Section 22.1.2.1 of the specification. + + Given that we can't rely on the built-in + global functions or objects to be untainted, + I had to expose a few of them directly to + the function via private names. In particular: + - Math.floor -> @floor + - Math.abs -> @abs + - Number -> @Number + - Array -> @Array + - isFinite -> @isFinite + + * builtins/ArrayConstructor.js: Added. + (from): Implementation of Array.from in JavaScript. + * runtime/ArrayConstructor.cpp: Add "from" to the lookup + table for the constructor object. + * runtime/CommonIdentifiers.h: Add the private versions + of the identifiers listed above. + * runtime/JSGlobalObject.cpp: Add the implementations of + those identifiers to the global object (using their + private names). + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalPrivateFuncAbs): Implementation of the abs function. + (JSC::globalPrivateFuncFloor): Implementation of the floor function. + * runtime/JSGlobalObjectFunctions.h: + +2015-02-19 Benjamin Poulain <bpoulain@apple.com> + + Refine the FTL part of ArithPow + https://bugs.webkit.org/show_bug.cgi?id=141792 + + Reviewed by Filip Pizlo. + + This patch refines the FTL lowering of ArithPow. This was left out + of the original patch to keep it simpler. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileArithPow): + Two improvements here: + 1) Do not generate the NaN check unless we know the exponent might be a NaN. + 2) Use one BasicBlock per check with the appropriate weight. Now that we have + one branch per test, move the Infinity check before the check for 1 since + it is the less common case. + + * tests/stress/math-pow-becomes-custom-function.js: Added. + Test for changing the Math.pow() function after it has been optimized. + + * tests/stress/math-pow-nan-behaviors.js: + The previous tests were only going as far as the DFGAbstractInterpreter + were the operations were replaced by the equivalent constant. + + I duplicated the test functions to also test the dynamic behavior of DFG + and FTL. + + * tests/stress/math-pow-with-constants.js: + Add cases covering exponent constants. LLVM removes many value + checks for those. + + * tests/stress/math-pow-with-never-NaN-exponent.js: Added. + Test for the new optimization removing the NaN check. + +2015-02-19 Csaba Osztrogonác <ossy@webkit.org> + + REGRESSION(r180279): It broke 20 tests on ARM Linux + https://bugs.webkit.org/show_bug.cgi?id=141771 + + Reviewed by Filip Pizlo. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): Align 64-bit values to respect ARM EABI. + +2015-02-18 Benjamin Poulain <bpoulain@apple.com> + + Remove BytecodeGenerator's numberMap, it is dead code + https://bugs.webkit.org/show_bug.cgi?id=141779 + + Reviewed by Filip Pizlo. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitLoad): Deleted. + * bytecompiler/BytecodeGenerator.h: + The JSValueMap seems better in every way. + + The emitLoad() taking a double was the only way to use numberMap + and that code has no caller. + +2015-02-18 Michael Saboff <msaboff@apple.com> + + Rollout r180247 & r180249 from trunk + https://bugs.webkit.org/show_bug.cgi?id=141773 + + Reviewed by Filip Pizlo. + + Theses changes makes sense to fix the crash reported in https://bugs.webkit.org/show_bug.cgi?id=141730 + only for branches. The change to fail the FTL compile but continue running is not comprehensive + enough for general use on trunk. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM): + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::createPhiVariables): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileUpsilon): + (JSC::FTL::LowerDFGToLLVM::compilePhi): + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::compileValueRep): + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::compilePutLocal): + (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): + (JSC::FTL::LowerDFGToLLVM::compileArithMul): + (JSC::FTL::LowerDFGToLLVM::compileArithDiv): + (JSC::FTL::LowerDFGToLLVM::compileArithMod): + (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): + (JSC::FTL::LowerDFGToLLVM::compileArithAbs): + (JSC::FTL::LowerDFGToLLVM::compileArithNegate): + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + (JSC::FTL::LowerDFGToLLVM::compileGetById): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileArrayPush): + (JSC::FTL::LowerDFGToLLVM::compileArrayPop): + (JSC::FTL::LowerDFGToLLVM::compileNewArray): + (JSC::FTL::LowerDFGToLLVM::compileToString): + (JSC::FTL::LowerDFGToLLVM::compileMakeRope): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::compare): + (JSC::FTL::LowerDFGToLLVM::boolify): + (JSC::FTL::LowerDFGToLLVM::opposite): + (JSC::FTL::LowerDFGToLLVM::lowJSValue): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::isArrayType): + (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability): + (JSC::FTL::LowerDFGToLLVM::exitValueForNode): + (JSC::FTL::LowerDFGToLLVM::setInt52): + (JSC::FTL::lowerDFGToLLVM): + (JSC::FTL::LowerDFGToLLVM::loweringFailed): Deleted. + * ftl/FTLLowerDFGToLLVM.h: + +2015-02-18 Filip Pizlo <fpizlo@apple.com> + + DFG should really support varargs + https://bugs.webkit.org/show_bug.cgi?id=141332 + + Reviewed by Oliver Hunt. + + This adds comprehensive vararg call support to the DFG and FTL compilers. Previously, if a + function had a varargs call, then it could only be compiled if that varargs call was just + forwarding arguments and we were inlining the function rather than compiling it directly. Also, + only varargs calls were dealt with; varargs constructs were not. + + This lifts all of those restrictions. Every varargs call or construct can now be compiled by both + the DFG and the FTL. Those calls can also be inlined, too - provided that profiling gives us a + sensible bound on arguments list length. When we inline a varargs call, the act of loading the + varargs is now made explicit in IR. I believe that we have enough IR machinery in place that we + would be able to do the arguments forwarding optimization as an IR transformation. This patch + doesn't implement that yet, and keeps the old bytecode-based varargs argument forwarding + optimization for now. + + There are three major IR features introduced in this patch: + + CallVarargs/ConstructVarargs: these are like Call/Construct except that they take an arguments + array rather than a list of arguments. Currently, they splat this arguments array onto the stack + using the same basic technique as the baseline JIT has always done. Except, these nodes indicate + that we are not interested in doing the non-escaping "arguments" optimization. + + CallForwardVarargs: this is a form of CallVarargs that just does the non-escaping "arguments" + optimization, aka forwarding arguments. It's somewhat lazy that this doesn't include + ConstructForwardVarargs, but the reason is that once we eliminate the lazy tear-off for + arguments, this whole thing will have to be tweaked - and for now forwarding on construct is just + not important in benchmarks. ConstructVarargs will still do forwarding, just not inlined. + + LoadVarargs: loads all elements out of an array onto the stack in a manner suitable for a varargs + call. This is used only when a varargs call (or construct) was inlined. The bytecode parser will + make room on the stack for the arguments, and will use LoadVarars to put those arguments into + place. + + In the future, we can consider adding strength reductions like: + + - If CallVarargs/ConstructVarargs see an array of known size with known elements, turn them into + Call/Construct. + + - If CallVarargs/ConstructVarargs are passed an unmodified, unescaped Arguments object, then + turn them into CallForwardVarargs/ConstructForwardVarargs. + + - If LoadVarargs sees an array of known size, then turn it into a sequence of GetByVals and + PutLocals. + + - If LoadVarargs sees an unmodified, unescaped Arguments object, then turn it into something like + LoadForwardVarargs. + + - If CallVarargs/ConstructVarargs/LoadVarargs see the result of a splice (or other Array + prototype function), then do the splice and varargs loading in one go (maybe via a new node + type). + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/MacroAssembler.h: + (JSC::MacroAssembler::rshiftPtr): + (JSC::MacroAssembler::urshiftPtr): + * assembler/MacroAssemblerARM64.h: + (JSC::MacroAssemblerARM64::urshift64): + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::urshift64): + * assembler/X86Assembler.h: + (JSC::X86Assembler::shrq_i8r): + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::CallLinkInfo): + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::setProvenConstantCallee): + (JSC::CallLinkStatus::dump): + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::maxNumArguments): + (JSC::CallLinkStatus::setIsProved): Deleted. + * bytecode/CodeOrigin.cpp: + (WTF::printInternal): + * bytecode/CodeOrigin.h: + (JSC::InlineCallFrame::varargsKindFor): + (JSC::InlineCallFrame::specializationKindFor): + (JSC::InlineCallFrame::isVarargs): + (JSC::InlineCallFrame::isNormalCall): Deleted. + * bytecode/ExitKind.cpp: + (JSC::exitKindToString): + * bytecode/ExitKind.h: + * bytecode/ValueRecovery.cpp: + (JSC::ValueRecovery::dumpInContext): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGArgumentsSimplificationPhase.cpp: + (JSC::DFG::ArgumentsSimplificationPhase::run): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::flush): + (JSC::DFG::ByteCodeParser::addCall): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleVarargsCall): + (JSC::DFG::ByteCodeParser::emitFunctionChecks): + (JSC::DFG::ByteCodeParser::inliningCost): + (JSC::DFG::ByteCodeParser::inlineCall): + (JSC::DFG::ByteCodeParser::attemptToInlineCall): + (JSC::DFG::ByteCodeParser::handleInlining): + (JSC::DFG::ByteCodeParser::handleMinMax): + (JSC::DFG::ByteCodeParser::handleIntrinsic): + (JSC::DFG::ByteCodeParser::handleTypedArrayConstructor): + (JSC::DFG::ByteCodeParser::handleConstantInternalFunction): + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::removeLastNodeFromGraph): Deleted. + (JSC::DFG::ByteCodeParser::undoFunctionChecks): Deleted. + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGCapabilities.h: + (JSC::DFG::functionCapabilityLevel): + (JSC::DFG::mightCompileFunctionFor): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGCommon.cpp: + (WTF::printInternal): + * dfg/DFGCommon.h: + (JSC::DFG::canInline): + (JSC::DFG::leastUpperBound): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + (JSC::DFG::Graph::dumpBlockHeader): + (JSC::DFG::Graph::isLiveInBytecode): + (JSC::DFG::Graph::valueProfileFor): + (JSC::DFG::Graph::methodOfGettingAValueProfileFor): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::valueProfileFor): Deleted. + (JSC::DFG::Graph::methodOfGettingAValueProfileFor): Deleted. + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::compileExceptionHandlers): + (JSC::DFG::JITCompiler::link): + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasCallVarargsData): + (JSC::DFG::Node::callVarargsData): + (JSC::DFG::Node::hasLoadVarargsData): + (JSC::DFG::Node::loadVarargsData): + (JSC::DFG::Node::hasHeapPrediction): + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + * dfg/DFGOperations.cpp: + * dfg/DFGOperations.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::dumpAndVerifyGraph): + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPreciseLocalClobberize.h: + (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): + (JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSSAConversionPhase.cpp: + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::isFlushed): + (JSC::DFG::SpeculativeJIT::callOperation): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + (JSC::DFG::StackLayoutPhase::assign): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGTypeCheckHoistingPhase.cpp: + (JSC::DFG::TypeCheckHoistingPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validateCPS): + * ftl/FTLAbbreviations.h: + (JSC::FTL::functionType): + (JSC::FTL::buildCall): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLInlineCacheSize.cpp: + (JSC::FTL::sizeOfCall): + (JSC::FTL::sizeOfCallVarargs): + (JSC::FTL::sizeOfCallForwardVarargs): + (JSC::FTL::sizeOfConstructVarargs): + (JSC::FTL::sizeOfIn): + (JSC::FTL::sizeOfICFor): + (JSC::FTL::sizeOfCheckIn): Deleted. + * ftl/FTLInlineCacheSize.h: + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLJSCall.cpp: + (JSC::FTL::JSCall::JSCall): + * ftl/FTLJSCallBase.cpp: + * ftl/FTLJSCallBase.h: + * ftl/FTLJSCallVarargs.cpp: Added. + (JSC::FTL::JSCallVarargs::JSCallVarargs): + (JSC::FTL::JSCallVarargs::numSpillSlotsNeeded): + (JSC::FTL::JSCallVarargs::emit): + (JSC::FTL::JSCallVarargs::link): + * ftl/FTLJSCallVarargs.h: Added. + (JSC::FTL::JSCallVarargs::node): + (JSC::FTL::JSCallVarargs::stackmapID): + (JSC::FTL::JSCallVarargs::operator<): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentsLength): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstructVarargs): + (JSC::FTL::LowerDFGToLLVM::compileLoadVarargs): + (JSC::FTL::LowerDFGToLLVM::compileIn): + (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier): + (JSC::FTL::LowerDFGToLLVM::vmCall): + (JSC::FTL::LowerDFGToLLVM::vmCallNoExceptions): + (JSC::FTL::LowerDFGToLLVM::callCheck): + * ftl/FTLOutput.h: + (JSC::FTL::Output::call): + * ftl/FTLState.cpp: + (JSC::FTL::State::State): + * ftl/FTLState.h: + * interpreter/Interpreter.cpp: + (JSC::sizeOfVarargs): + (JSC::sizeFrameForVarargs): + * interpreter/Interpreter.h: + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::readInlinedFrame): + * jit/AssemblyHelpers.cpp: + (JSC::AssemblyHelpers::emitExceptionCheck): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::addressFor): + (JSC::AssemblyHelpers::calleeFrameSlot): + (JSC::AssemblyHelpers::calleeArgumentSlot): + (JSC::AssemblyHelpers::calleeFrameTagSlot): + (JSC::AssemblyHelpers::calleeFramePayloadSlot): + (JSC::AssemblyHelpers::calleeArgumentTagSlot): + (JSC::AssemblyHelpers::calleeArgumentPayloadSlot): + (JSC::AssemblyHelpers::calleeFrameCallerFrame): + (JSC::AssemblyHelpers::selectScratchGPR): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/GPRInfo.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileSetupVarargsFrame): + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileSetupVarargsFrame): + (JSC::JIT::compileOpCall): + * jit/JITOperations.h: + * jit/SetupVarargsFrame.cpp: + (JSC::emitSetupVarargsFrameFastCase): + * jit/SetupVarargsFrame.h: + * runtime/Arguments.h: + (JSC::Arguments::create): + (JSC::Arguments::registerArraySizeInBytes): + (JSC::Arguments::finishCreation): + * runtime/Options.h: + * tests/stress/construct-varargs-inline-smaller-Foo.js: Added. + (Foo): + (bar): + (checkEqual): + (test): + * tests/stress/construct-varargs-inline.js: Added. + (Foo): + (bar): + (checkEqual): + (test): + * tests/stress/construct-varargs-no-inline.js: Added. + (Foo): + (bar): + (checkEqual): + (test): + * tests/stress/get-argument-by-val-in-inlined-varargs-call-out-of-bounds.js: Added. + (foo): + (bar): + * tests/stress/get-argument-by-val-safe-in-inlined-varargs-call-out-of-bounds.js: Added. + (foo): + (bar): + * tests/stress/get-my-argument-by-val-creates-arguments.js: Added. + (blah): + (foo): + (bar): + (checkEqual): + (test): + * tests/stress/load-varargs-then-inlined-call-exit-in-foo.js: Added. + (foo): + (bar): + (checkEqual): + * tests/stress/load-varargs-then-inlined-call-inlined.js: Added. + (foo): + (bar): + (baz): + (checkEqual): + (test): + * tests/stress/load-varargs-then-inlined-call.js: Added. + (foo): + (bar): + (checkEqual): + (test): + +2015-02-17 Michael Saboff <msaboff@apple.com> + + Unreviewed, Restoring the C LOOP insta-crash fix in r180184. + + Fixed a typo that only affected the C Loop in the prologue() macro in LowLevelInterpreter.asm. + After the stackHeightOKGetCodeBlock label, codeBlockSetter(t1) should be codeBlockGetter(t1). + + * llint/LowLevelInterpreter.asm: Fixed a typo. + +2015-02-18 Csaba Osztrogonác <ossy@webkit.org> + + URTBF after r180258 to fix Windows build. + + * runtime/MathCommon.cpp: + (JSC::mathPowInternal): + +2015-02-18 Joseph Pecoraro <pecoraro@apple.com> + + REGRESSION(r180235): It broke the !ENABLE(PROMISES) build + https://bugs.webkit.org/show_bug.cgi?id=141746 + + Unreviewed build fix. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::getInternalProperties): + Wrap JSPromise related code in ENABLE(PROMISES) guard. + +2015-02-18 Benjamin Poulain <benjamin@webkit.org> + + Fix the C-Loop LLInt build + https://bugs.webkit.org/show_bug.cgi?id=141618 + + Reviewed by Filip Pizlo. + + I broke C-Loop when moving the common code of pow() + to JITOperations because that file is #ifdefed out + when the JITs are disabled. + + It would be weird to move it back to MathObject since + the function needs to know about the calling conventions. + + To avoid making a mess, I just gave the function its own file + that is used by both the runtime and the JIT. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGAbstractInterpreterInlines.h: + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * runtime/MathCommon.cpp: Added. + (JSC::fdlibmScalbn): + (JSC::fdlibmPow): + (JSC::isDenormal): + (JSC::isEdgeCase): + (JSC::mathPowInternal): + (JSC::operationMathPow): + * runtime/MathCommon.h: Added. + * runtime/MathObject.cpp: + +2015-02-17 Benjamin Poulain <bpoulain@apple.com> + + Clean up OSRExit's considerAddingAsFrequentExitSite() + https://bugs.webkit.org/show_bug.cgi?id=141690 + + Reviewed by Anders Carlsson. + + Looks like some code was removed from CodeBlock::tallyFrequentExitSites() + and the OSRExit were left untouched. + + This patch cleans up the two loops and remove the boolean return + on considerAddingAsFrequentExitSite(). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::tallyFrequentExitSites): + * dfg/DFGOSRExit.h: + (JSC::DFG::OSRExit::considerAddingAsFrequentExitSite): + * dfg/DFGOSRExitBase.cpp: + (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSiteSlow): + * dfg/DFGOSRExitBase.h: + (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite): + * ftl/FTLOSRExit.h: + (JSC::FTL::OSRExit::considerAddingAsFrequentExitSite): + +2015-02-17 Alexey Proskuryakov <ap@apple.com> + + Debug build fix after r180247. + + * ftl/FTLLowerDFGToLLVM.cpp: (JSC::FTL::LowerDFGToLLVM::loweringFailed): + +2015-02-17 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r180184. + https://bugs.webkit.org/show_bug.cgi?id=141733 + + Caused infinite recursion on js/function-apply-aliased.html + (Requested by ap_ on #webkit). + + Reverted changeset: + + "REGRESSION(r180060): C Loop crashes" + https://bugs.webkit.org/show_bug.cgi?id=141671 + http://trac.webkit.org/changeset/180184 + +2015-02-17 Michael Saboff <msaboff@apple.com> + + CrashTracer: DFG_CRASH beneath JSC::FTL::LowerDFGToLLVM::compileNode + https://bugs.webkit.org/show_bug.cgi?id=141730 + + Reviewed by Geoffrey Garen. + + Added a new failure handler, loweringFailed(), to LowerDFGToLLVM that reports failures + while processing DFG lowering. For debug builds, the failures are logged identical + to the way the DFG_CRASH() reports them. For release builds, the failures are reported + and that FTL compilation is terminated, but the process is allowed to continue. + Wrapped calls to loweringFailed() in a macro LOWERING_FAILED so the function and + line number are reported at the point of the inconsistancy. + + Converted instances of DFG_CRASH to LOWERING_FAILED. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): Added lowerDFGToLLVM() failure check that + will fail the FTL compile. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM): + Added new member variable, m_loweringSucceeded, to stop compilation on the first + reported failure. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + * ftl/FTLLowerDFGToLLVM.h: + Added check for compilation failures and now report those failures via a boolean + return value. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::createPhiVariables): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileUpsilon): + (JSC::FTL::LowerDFGToLLVM::compilePhi): + (JSC::FTL::LowerDFGToLLVM::compileDoubleRep): + (JSC::FTL::LowerDFGToLLVM::compileValueRep): + (JSC::FTL::LowerDFGToLLVM::compileValueToInt32): + (JSC::FTL::LowerDFGToLLVM::compilePutLocal): + (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub): + (JSC::FTL::LowerDFGToLLVM::compileArithMul): + (JSC::FTL::LowerDFGToLLVM::compileArithDiv): + (JSC::FTL::LowerDFGToLLVM::compileArithMod): + (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax): + (JSC::FTL::LowerDFGToLLVM::compileArithAbs): + (JSC::FTL::LowerDFGToLLVM::compileArithNegate): + (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure): + (JSC::FTL::LowerDFGToLLVM::compileGetById): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::compileArrayPush): + (JSC::FTL::LowerDFGToLLVM::compileArrayPop): + (JSC::FTL::LowerDFGToLLVM::compileNewArray): + (JSC::FTL::LowerDFGToLLVM::compileToString): + (JSC::FTL::LowerDFGToLLVM::compileMakeRope): + (JSC::FTL::LowerDFGToLLVM::compileCompareEq): + (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq): + (JSC::FTL::LowerDFGToLLVM::compileSwitch): + (JSC::FTL::LowerDFGToLLVM::compare): + (JSC::FTL::LowerDFGToLLVM::boolify): + (JSC::FTL::LowerDFGToLLVM::opposite): + (JSC::FTL::LowerDFGToLLVM::lowJSValue): + (JSC::FTL::LowerDFGToLLVM::speculate): + (JSC::FTL::LowerDFGToLLVM::isArrayType): + (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability): + (JSC::FTL::LowerDFGToLLVM::exitValueForNode): + (JSC::FTL::LowerDFGToLLVM::setInt52): + Changed DFG_CRASH() to LOWERING_FAILED(). Updated related control flow as appropriate. + + (JSC::FTL::LowerDFGToLLVM::loweringFailed): New error reporting member function. + +2015-02-17 Filip Pizlo <fpizlo@apple.com> + + StackLayoutPhase should use CodeBlock::usesArguments rather than FunctionExecutable::usesArguments + https://bugs.webkit.org/show_bug.cgi?id=141721 + rdar://problem/17198633 + + Reviewed by Michael Saboff. + + I've seen cases where the two are out of sync. We know we can trust the CodeBlock::usesArguments because + we use it everywhere else. + + No test because I could never reproduce the crash. + + * dfg/DFGGraph.h: + (JSC::DFG::Graph::usesArguments): + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + +2015-02-16 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Improved Console Support for Bound Functions + https://bugs.webkit.org/show_bug.cgi?id=141635 + + Reviewed by Timothy Hatcher. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::getInternalProperties): + Expose internal properties of a JSBoundFunction. + +2015-02-16 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ES6: Improved Console Support for Promise Objects + https://bugs.webkit.org/show_bug.cgi?id=141634 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getInternalProperties): + * inspector/InjectedScriptSource.js: + Include internal properties in previews. Share code + with normal internal property handling. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::constructInternalProperty): + (Inspector::JSInjectedScriptHost::getInternalProperties): + Provide internal state of Promises. + + * inspector/protocol/Runtime.json: + Provide an optional field to distinguish if a PropertyPreview + is for an Internal property or not. + +2015-02-17 Filip Pizlo <fpizlo@apple.com> + + Throwing from an FTL call IC slow path may result in tag registers being clobbered on 64-bit CPUs + https://bugs.webkit.org/show_bug.cgi?id=141717 + rdar://problem/19863382 + + Reviewed by Geoffrey Garen. + + The best solution is to ensure that the engine catching an exception restores tag registers. + + Each of these new test cases reliably crashed prior to this patch and they don't crash at all now. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_catch): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter64.asm: + * tests/stress/throw-from-ftl-call-ic-slow-path-cells.js: Added. + * tests/stress/throw-from-ftl-call-ic-slow-path-undefined.js: Added. + * tests/stress/throw-from-ftl-call-ic-slow-path.js: Added. + +2015-02-17 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Add the necessary setupArgumentsWithExecState after bug141332 + https://bugs.webkit.org/show_bug.cgi?id=141714 + + Reviewed by Michael Saboff. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2015-02-15 Sam Weinig <sam@webkit.org> + + Add experimental <attachment> element support + https://bugs.webkit.org/show_bug.cgi?id=141626 + + Reviewed by Tim Horton. + + * Configurations/FeatureDefines.xcconfig: + +2015-02-16 Michael Saboff <msaboff@apple.com> + + REGRESSION(r180060): C Loop crashes + https://bugs.webkit.org/show_bug.cgi?id=141671 + + Reviewed by Geoffrey Garen. + + Fixed a typo that only affected the C Loop in the prologue() macro in LowLevelInterpreter.asm. + After the stackHeightOKGetCodeBlock label, codeBlockSetter(t1) should be codeBlockGetter(t1). + Fixed the processing of an out of stack exception in llint_stack_check to not get the caller's + frame. This isn't needed, since this helper is only called to check the stack on entry. Any + exception will be handled by a call ancestor. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::llint_stack_check): Changed to use the current frame for processing an exception. + * llint/LowLevelInterpreter.asm: Fixed a typo. + +2015-02-16 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Scope details sidebar should label objects with constructor names + https://bugs.webkit.org/show_bug.cgi?id=139449 + + Reviewed by Timothy Hatcher. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::internalConstructorName): + * runtime/Structure.cpp: + (JSC::Structure::toStructureShape): + Share calculatedClassName. + + * runtime/JSObject.h: + * runtime/JSObject.cpp: + (JSC::JSObject::calculatedClassName): + Elaborate on a way to get an Object's class name. + +2015-02-16 Filip Pizlo <fpizlo@apple.com> + + DFG SSA should use GetLocal for arguments, and the GetArgument node type should be removed + https://bugs.webkit.org/show_bug.cgi?id=141623 + + Reviewed by Oliver Hunt. + + During development of https://bugs.webkit.org/show_bug.cgi?id=141332, I realized that I + needed to use GetArgument for loading something that has magically already appeared on the + stack, so currently trunk sort of allows this. But then I realized three things: + + - A GetArgument with a non-JSValue flush format means speculating that the value on the + stack obeys that format, rather than just assuming that that it already has that format. + In bug 141332, I want it to assume rather than speculate. That also happens to be more + intuitive; I don't think I was wrong to expect that. + + - The node I really want is GetLocal. I'm just getting the value of the local and I don't + want to do anything else. + + - Maybe it would be easier if we just used GetLocal for all of the cases where we currently + use GetArgument. + + This changes the FTL to do argument speculations in the prologue just like the DFG does. + This brings some consistency to our system, and allows us to get rid of the GetArgument + node. The speculations that the FTL must do are now made explicit in the m_argumentFormats + vector in DFG::Graph. This has natural DCE behavior: even if all uses of the argument are + dead we will still speculate. We already have safeguards to ensure we only speculate if + there are uses that benefit from speculation (which is a much more conservative criterion + than DCE). + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDCEPhase.cpp: + (JSC::DFG::DCEPhase::run): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGFlushFormat.h: + (JSC::DFG::typeFilterFor): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::valueProfileFor): + (JSC::DFG::Graph::methodOfGettingAValueProfileFor): + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::initialize): + * dfg/DFGNode.cpp: + (JSC::DFG::Node::hasVariableAccessData): + * dfg/DFGNodeType.h: + * dfg/DFGOSRAvailabilityAnalysisPhase.cpp: + (JSC::DFG::OSRAvailabilityAnalysisPhase::run): + (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode): + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGPutLocalSinkingPhase.cpp: + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetLocal): + (JSC::FTL::LowerDFGToLLVM::compileGetArgument): Deleted. + * tests/stress/dead-speculating-argument-use.js: Added. + (foo): + (o.valueOf): + +2015-02-15 Filip Pizlo <fpizlo@apple.com> + + Rare case profiling should actually work + https://bugs.webkit.org/show_bug.cgi?id=141632 + + Reviewed by Michael Saboff. + + This simple adjustment appears to be a 2% speed-up on Octane. Over time, the slow case + heuristic has essentially stopped working because the typical execution count threshold for a + bytecode instruction is around 66 while the slow case threshold is 100: virtually + guaranteeing that the DFG will never think that a bytecode instruction has taken the slow + case even if it took it every single time. So, this changes the slow case threshold to 20. + + I checked if we could lower this down further, like to 10. That is worse than 20, and about + as bad as 100. + + * runtime/Options.h: + +2015-02-15 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: remove unused XHR replay code + https://bugs.webkit.org/show_bug.cgi?id=141622 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Network.json: remove XHR replay methods. + +2015-02-15 David Kilzer <ddkilzer@apple.com> + + REGRESSION (r180082): WebCore Debug builds fail on Mavericks due to weak export symbols + <http://webkit.org/b/141607> + + More work towards fixing the Mavericks Debug build. + + * inspector/ScriptDebugServer.h: + (Inspector::ScriptDebugServer::Task): + * inspector/agents/InspectorDebuggerAgent.h: + (Inspector::InspectorDebuggerAgent::Listener): + - Remove subclass exports. They did not help. + + * runtime/JSCJSValue.h: + (JSC::JSValue::toFloat): Do not mark inline method for export. + +2015-02-09 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: remove some unnecessary Inspector prefixes from class names in Inspector namespace + https://bugs.webkit.org/show_bug.cgi?id=141372 + + Reviewed by Joseph Pecoraro. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::addToFrontend): + (Inspector::ConsoleMessage::updateRepeatCountInConsole): + * inspector/ConsoleMessage.h: + * inspector/InspectorAgentBase.h: + * inspector/InspectorAgentRegistry.cpp: + (Inspector::AgentRegistry::AgentRegistry): + (Inspector::AgentRegistry::append): + (Inspector::AgentRegistry::appendExtraAgent): + (Inspector::AgentRegistry::didCreateFrontendAndBackend): + (Inspector::AgentRegistry::willDestroyFrontendAndBackend): + (Inspector::AgentRegistry::discardAgents): + (Inspector::InspectorAgentRegistry::InspectorAgentRegistry): Deleted. + (Inspector::InspectorAgentRegistry::append): Deleted. + (Inspector::InspectorAgentRegistry::appendExtraAgent): Deleted. + (Inspector::InspectorAgentRegistry::didCreateFrontendAndBackend): Deleted. + (Inspector::InspectorAgentRegistry::willDestroyFrontendAndBackend): Deleted. + (Inspector::InspectorAgentRegistry::discardAgents): Deleted. + * inspector/InspectorAgentRegistry.h: + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::BackendDispatcher::CallbackBase::CallbackBase): + (Inspector::BackendDispatcher::CallbackBase::isActive): + (Inspector::BackendDispatcher::CallbackBase::sendFailure): + (Inspector::BackendDispatcher::CallbackBase::sendIfActive): + (Inspector::BackendDispatcher::create): + (Inspector::BackendDispatcher::registerDispatcherForDomain): + (Inspector::BackendDispatcher::dispatch): + (Inspector::BackendDispatcher::sendResponse): + (Inspector::BackendDispatcher::reportProtocolError): + (Inspector::BackendDispatcher::getInteger): + (Inspector::BackendDispatcher::getDouble): + (Inspector::BackendDispatcher::getString): + (Inspector::BackendDispatcher::getBoolean): + (Inspector::BackendDispatcher::getObject): + (Inspector::BackendDispatcher::getArray): + (Inspector::BackendDispatcher::getValue): + (Inspector::InspectorBackendDispatcher::CallbackBase::CallbackBase): Deleted. + (Inspector::InspectorBackendDispatcher::CallbackBase::isActive): Deleted. + (Inspector::InspectorBackendDispatcher::CallbackBase::sendFailure): Deleted. + (Inspector::InspectorBackendDispatcher::CallbackBase::sendIfActive): Deleted. + (Inspector::InspectorBackendDispatcher::create): Deleted. + (Inspector::InspectorBackendDispatcher::registerDispatcherForDomain): Deleted. + (Inspector::InspectorBackendDispatcher::dispatch): Deleted. + (Inspector::InspectorBackendDispatcher::sendResponse): Deleted. + (Inspector::InspectorBackendDispatcher::reportProtocolError): Deleted. + (Inspector::InspectorBackendDispatcher::getInteger): Deleted. + (Inspector::InspectorBackendDispatcher::getDouble): Deleted. + (Inspector::InspectorBackendDispatcher::getString): Deleted. + (Inspector::InspectorBackendDispatcher::getBoolean): Deleted. + (Inspector::InspectorBackendDispatcher::getObject): Deleted. + (Inspector::InspectorBackendDispatcher::getArray): Deleted. + (Inspector::InspectorBackendDispatcher::getValue): Deleted. + * inspector/InspectorBackendDispatcher.h: + (Inspector::SupplementalBackendDispatcher::SupplementalBackendDispatcher): + (Inspector::SupplementalBackendDispatcher::~SupplementalBackendDispatcher): + (Inspector::InspectorSupplementalBackendDispatcher::InspectorSupplementalBackendDispatcher): Deleted. + (Inspector::InspectorSupplementalBackendDispatcher::~InspectorSupplementalBackendDispatcher): Deleted. + * inspector/InspectorFrontendChannel.h: + (Inspector::FrontendChannel::~FrontendChannel): + (Inspector::InspectorFrontendChannel::~InspectorFrontendChannel): Deleted. + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::globalObjectDestroyed): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + (Inspector::JSGlobalObjectInspectorController::disconnectFrontend): + (Inspector::JSGlobalObjectInspectorController::dispatchMessageFromFrontend): + (Inspector::JSGlobalObjectInspectorController::appendExtraAgent): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::didCreateFrontendAndBackend): + (Inspector::InspectorAgent::willDestroyFrontendAndBackend): + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::didCreateFrontendAndBackend): + (Inspector::InspectorConsoleAgent::willDestroyFrontendAndBackend): + * inspector/agents/InspectorConsoleAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::didCreateFrontendAndBackend): + (Inspector::InspectorDebuggerAgent::willDestroyFrontendAndBackend): + (Inspector::InspectorDebuggerAgent::handleConsoleAssert): + (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): + (Inspector::InspectorDebuggerAgent::pause): + (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP): + (Inspector::InspectorDebuggerAgent::didPause): + (Inspector::InspectorDebuggerAgent::breakProgram): + (Inspector::InspectorDebuggerAgent::clearBreakDetails): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::willDestroyFrontendAndBackend): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/agents/JSGlobalObjectRuntimeAgent.cpp: + (Inspector::JSGlobalObjectRuntimeAgent::didCreateFrontendAndBackend): + (Inspector::JSGlobalObjectRuntimeAgent::willDestroyFrontendAndBackend): + * inspector/agents/JSGlobalObjectRuntimeAgent.h: + * inspector/augmentable/AlternateDispatchableAgent.h: + * inspector/augmentable/AugmentableInspectorController.h: + * inspector/remote/RemoteInspectorDebuggable.h: + * inspector/remote/RemoteInspectorDebuggableConnection.h: + * inspector/scripts/codegen/cpp_generator.py: + (CppGenerator.cpp_type_for_formal_out_parameter): + (CppGenerator.cpp_type_for_stack_out_parameter): + * inspector/scripts/codegen/cpp_generator_templates.py: + (AlternateBackendDispatcher): + (Alternate): + (void): + (AlternateInspectorBackendDispatcher): Deleted. + (AlternateInspector): Deleted. + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py: + (CppBackendDispatcherHeaderGenerator._generate_alternate_handler_forward_declarations_for_domains.Alternate): + (CppBackendDispatcherHeaderGenerator._generate_dispatcher_declaration_for_command): + (CppBackendDispatcherHeaderGenerator._generate_alternate_handler_forward_declarations_for_domains.AlternateInspector): Deleted. + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py: + (CppBackendDispatcherImplementationGenerator._generate_handler_class_destructor_for_domain): + (CppBackendDispatcherImplementationGenerator._generate_large_dispatcher_switch_implementation_for_domain): + (CppBackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py: + (CppFrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py: + (ObjCFrontendDispatcherImplementationGenerator._generate_event): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * runtime/JSGlobalObjectDebuggable.cpp: + (JSC::JSGlobalObjectDebuggable::connect): + (JSC::JSGlobalObjectDebuggable::disconnect): + * runtime/JSGlobalObjectDebuggable.h: + +2015-02-14 David Kilzer <ddkilzer@apple.com> + + REGRESSION (r180082): WebCore Debug builds fail on Mavericks due to weak export symbols + <http://webkit.org/b/141607> + + Work towards fixing the Mavericks Debug build. + + * inspector/ScriptDebugServer.h: + (Inspector::ScriptDebugServer::Task): Export class. + * inspector/agents/InspectorDebuggerAgent.h: + (Inspector::InspectorDebuggerAgent::Listener): Export class. + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::setConsoleClient): Do not mark inline + method for export. + +2015-02-14 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Symbol RemoteObject should not send sub-type + https://bugs.webkit.org/show_bug.cgi?id=141604 + + Reviewed by Brian Burg. + + * inspector/InjectedScriptSource.js: + +2015-02-13 Benjamin Poulain <bpoulain@apple.com> + + Attempt to fix 32bits build after r180098 + + * jit/JITOperations.cpp: + * jit/JITOperations.h: + I copied the attribute from the MathObject version of that function when I moved + it over. DFG has no version of a function call taking those attributes. + +2015-02-13 Joseph Pecoraro <pecoraro@apple.com> + + JSContext Inspector: Do not stash console messages for non-debuggable JSContext + https://bugs.webkit.org/show_bug.cgi?id=141589 + + Reviewed by Timothy Hatcher. + + Consider developer extras disabled for JSContext inspection if the + RemoteInspector server is not enabled (typically a non-debuggable + process rejected by webinspectord) or if remote debugging on the + JSContext was explicitly disabled via SPI. + + When developer extras are disabled, console message will not be stashed. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::developerExtrasEnabled): + * inspector/JSGlobalObjectInspectorController.h: + +2015-02-13 Benjamin Poulain <bpoulain@apple.com> + + Add a DFG node for the Pow Intrinsics + https://bugs.webkit.org/show_bug.cgi?id=141540 + + Reviewed by Filip Pizlo. + + Add a DFG Node for PowIntrinsic. This patch covers the basic cases + need to avoid massive regression. I will iterate over the node to cover + the missing types. + + With this patch I get the following progressions on benchmarks: + -LongSpider's math-partial-sums: +5%. + -Kraken's imaging-darkroom: +17% + -AsmBench's cray.c: +6.6% + -CompressionBench: +2.2% globally. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + Cover a couple of trivial cases: + -If the exponent is zero, the result is always one, regardless of the base. + -If both arguments are constants, compute the result at compile time. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + We only support 2 basic cases at this time: + -Math.pow(double, int) + -Math.pow(double, double). + + I'll cover Math.pow(int, int) in a follow up. + + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToArithSqrt): + (JSC::DFG::Node::arithNodeFlags): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + (JSC::DFG::PredictionPropagationPhase::doDoubleVoting): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::compileArithPowIntegerFastPath): + (JSC::DFG::SpeculativeJIT::compileArithPow): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::validate): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLIntrinsicRepository.h: + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileArithPow): + * ftl/FTLOutput.h: + (JSC::FTL::Output::doublePow): + (JSC::FTL::Output::doublePowi): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * runtime/MathObject.cpp: + (JSC::mathProtoFuncPow): + (JSC::isDenormal): Deleted. + (JSC::isEdgeCase): Deleted. + (JSC::mathPow): Deleted. + + * tests/stress/math-pow-basics.js: Added. + * tests/stress/math-pow-integer-exponent-fastpath.js: Added. + * tests/stress/math-pow-nan-behaviors.js: Added. + * tests/stress/math-pow-with-constants.js: Added. + Start some basic testing of Math.pow(). + Due to the various transform, the value change when the code tiers up, + I covered this by checking for approximate values. + +2015-02-13 Benjamin Poulain <bpoulain@apple.com> + + ArithSqrt should not be conditional on supportsFloatingPointSqrt + https://bugs.webkit.org/show_bug.cgi?id=141546 + + Reviewed by Geoffrey Garen and Filip Pizlo. + + Just fallback to the function call in the DFG codegen. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleIntrinsic): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileArithSqrt): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * tests/stress/math-sqrt-basics.js: Added. + Basic coverage. + + * tests/stress/math-sqrt-basics-disable-architecture-specific-optimizations.js: Added. + Same tests but forcing the function call. + +2015-02-13 Michael Saboff <msaboff@apple.com> + + REGRESSION(r180060) New js/regress-141098 test crashes when LLInt is disabled. + https://bugs.webkit.org/show_bug.cgi?id=141577 + + Reviewed by Benjamin Poulain. + + Changed the prologue of the baseline JIT to check for stack space for all + types of code blocks. Previously, it was only checking Function. Now + it checks Program and Eval as well. + + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + +2015-02-13 Benjamin Poulain <bpoulain@apple.com> + + Generate incq instead of addq when the immediate value is one + https://bugs.webkit.org/show_bug.cgi?id=141548 + + Reviewed by Gavin Barraclough. + + JSC emits "addq #1 (rXX)" *a lot*. + This patch replace that by incq, which is one byte shorter + and is the adviced form. + + Sunspider: +0.47% + Octane: +0.28% + Kraken: +0.44% + AsmBench, CompressionBench: neutral. + + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::add64): + * assembler/X86Assembler.h: + (JSC::X86Assembler::incq_m): + +2015-02-13 Benjamin Poulain <benjamin@webkit.org> + + Little clean up of Bytecode Generator's Label + https://bugs.webkit.org/show_bug.cgi?id=141557 + + Reviewed by Michael Saboff. + + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/BytecodeGenerator.cpp: + Label was a friend of BytecodeGenerator in order to access + m_instructions. There is no need for that, BytecodeGenerator + has a public getter. + + * bytecompiler/Label.h: + (JSC::Label::Label): + (JSC::Label::setLocation): + (JSC::BytecodeGenerator::newLabel): + Make it explicit that the generator must exist. + +2015-02-13 Michael Saboff <msaboff@apple.com> + + Google doc spreadsheet reproducibly crashes when sorting + https://bugs.webkit.org/show_bug.cgi?id=141098 + + Reviewed by Oliver Hunt. + + Moved the stack check to before the callee registers are allocated in the + prologue() by movving it from the functionInitialization() macro. This + way we can check the stack before moving the stack pointer, avoiding a + crash during a "call" instruction. Before this change, we weren't even + checking the stack for program and eval execution. + + Made a couple of supporting changes. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::llint_stack_check): We can't just go up one frame as we + may be processing an exception to an entry frame. + + * llint/LowLevelInterpreter.asm: + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + (llint_throw_from_slow_path_trampoline): Changed method to get the vm + from the code block to not use the codeBlock, since we may need to + continue from an exception in a native function. + +2015-02-12 Benjamin Poulain <benjamin@webkit.org> + + Simplify the initialization of BytecodeGenerator a bit + https://bugs.webkit.org/show_bug.cgi?id=141505 + + Reviewed by Anders Carlsson. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * bytecompiler/BytecodeGenerator.h: + Setup the default initialization at the declaration level + instead of the constructor. + + Also made m_scopeNode and m_codeType const to make it explicit + that they are invariant after construction. + + * parser/Nodes.cpp: + * runtime/Executable.cpp: + Remove 2 useless #includes. + +2015-02-12 Benjamin Poulain <benjamin@webkit.org> + + Move the generators for GetScope and SkipScope to the common core in DFGSpeculativeJIT + https://bugs.webkit.org/show_bug.cgi?id=141506 + + Reviewed by Michael Saboff. + + The generators for the nodes GetScope and SkipScope were + completely identical between 32 and 64bits. + + This patch moves the duplicated code to DFGSpeculativeJIT. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileGetScope): + (JSC::DFG::SpeculativeJIT::compileSkipScope): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2015-02-11 Brent Fulgham <bfulgham@apple.com> + + [Win] [64-bit] Work around MSVC2013 Runtime Bug + https://bugs.webkit.org/show_bug.cgi?id=141498 + <rdar://problem/19803642> + + Reviewed by Anders Carlsson. + + Disable FMA3 instruction use in the MSVC math library to + work around a VS2013 runtime crash. We can remove this + workaround when we switch to VS2015. + + * API/tests/testapi.c: Call _set_FMA3_enable(0) to disable + FMA3 support. + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: Add new files. + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: Ditto. + * JavaScriptCore.vcxproj/JavaScriptCoreDLL.cpp: Added. + * JavaScriptCore.vcxproj/jsc/DLLLauncherMain.cpp: Call _set_FMA3_enable(0) + to disable FMA3 support. + * jsc.cpp: Ditto. + * testRegExp.cpp: Ditto. + +2015-02-11 Filip Pizlo <fpizlo@apple.com> + + The callee frame helpers in DFG::SpeculativeJIT should be available to other JITs + https://bugs.webkit.org/show_bug.cgi?id=141493 + + Reviewed by Michael Saboff. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::calleeFrameSlot): Deleted. + (JSC::DFG::SpeculativeJIT::calleeArgumentSlot): Deleted. + (JSC::DFG::SpeculativeJIT::calleeFrameTagSlot): Deleted. + (JSC::DFG::SpeculativeJIT::calleeFramePayloadSlot): Deleted. + (JSC::DFG::SpeculativeJIT::calleeArgumentTagSlot): Deleted. + (JSC::DFG::SpeculativeJIT::calleeArgumentPayloadSlot): Deleted. + (JSC::DFG::SpeculativeJIT::calleeFrameCallerFrame): Deleted. + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::calleeFrameSlot): + (JSC::AssemblyHelpers::calleeArgumentSlot): + (JSC::AssemblyHelpers::calleeFrameTagSlot): + (JSC::AssemblyHelpers::calleeFramePayloadSlot): + (JSC::AssemblyHelpers::calleeArgumentTagSlot): + (JSC::AssemblyHelpers::calleeArgumentPayloadSlot): + (JSC::AssemblyHelpers::calleeFrameCallerFrame): + +2015-02-11 Filip Pizlo <fpizlo@apple.com> + + SetupVarargsFrame should not assume that an inline stack frame would have identical layout to a normal stack frame + https://bugs.webkit.org/show_bug.cgi?id=141485 + + Reviewed by Oliver Hunt. + + The inlineStackOffset argument was meant to make it easy for the DFG to use this helper for + vararg calls from inlined code, but that doesn't work since the DFG inline call frame + doesn't actually put the argument count at the JSStack::ArgumentCount offset. In fact there + is really no such thing as an inlineStackOffset except when we OSR exit; while the code is + running the stack layout is compacted so that the stackOffset is not meaningful. + + * jit/JITCall.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/SetupVarargsFrame.cpp: + (JSC::emitSetupVarargsFrameFastCase): + * jit/SetupVarargsFrame.h: + +2015-02-10 Filip Pizlo <fpizlo@apple.com> + + Split FTL::JSCall into the part that knows about call inline caching and the part that interacts with LLVM patchpoints + https://bugs.webkit.org/show_bug.cgi?id=141455 + + Reviewed by Mark Lam. + + The newly introduced FTL::JSCallBase can be used to build other things, like the FTL portion + of https://bugs.webkit.org/show_bug.cgi?id=141332. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CallLinkInfo.h: + (JSC::CallLinkInfo::specializationKindFor): + (JSC::CallLinkInfo::specializationKind): + * ftl/FTLJSCall.cpp: + (JSC::FTL::JSCall::JSCall): + (JSC::FTL::JSCall::emit): Deleted. + (JSC::FTL::JSCall::link): Deleted. + * ftl/FTLJSCall.h: + * ftl/FTLJSCallBase.cpp: Added. + (JSC::FTL::JSCallBase::JSCallBase): + (JSC::FTL::JSCallBase::emit): + (JSC::FTL::JSCallBase::link): + * ftl/FTLJSCallBase.h: Added. + +2015-02-10 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix build. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + +2015-02-10 Filip Pizlo <fpizlo@apple.com> + + op_call_varargs should only load the length once + https://bugs.webkit.org/show_bug.cgi?id=141440 + rdar://problem/19761683 + + Reviewed by Michael Saboff. + + Refactors the pair of calls that set up the varargs frame so that the first call returns the + length, and the second call uses the length returned by the first one. It turns out that this + gave me an opportunity to shorten a lot of the code. + + * interpreter/Interpreter.cpp: + (JSC::sizeFrameForVarargs): + (JSC::loadVarargs): + (JSC::setupVarargsFrame): + (JSC::setupVarargsFrameAndSetThis): + * interpreter/Interpreter.h: + (JSC::calleeFrameForVarargs): + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/SetupVarargsFrame.cpp: + (JSC::emitSetVarargsFrame): + (JSC::emitSetupVarargsFrameFastCase): + * jit/SetupVarargsFrame.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::copyToArguments): + * runtime/Arguments.h: + * runtime/JSArray.cpp: + (JSC::JSArray::copyToArguments): + * runtime/JSArray.h: + * runtime/VM.h: + * tests/stress/call-varargs-length-effects.js: Added. + (foo): + (bar): + +2015-02-10 Michael Saboff <msaboff@apple.com> + + Crash in JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq + https://bugs.webkit.org/show_bug.cgi?id=139398 + + Reviewed by Filip Pizlo. + + Due to CFA analysis, the CompareStrictEq node was determined to be unreachable, but later + was determined to be reachable. When we go to lower to LLVM, the edges for the CompareStrictEq + node are UntypedUse which we can't compile. Fixed this by checking that the IR before + lowering can still be handled by the FTL. + + Had to add GetArgument as a node that the FTL can compile as the SSA conversion phase converts + a SetArgument to a GetArgument. Before this change FTL::canCompile() would never see a GetArgument + node. With the check right before lowering, we see this node. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): Added a final FTL::canCompile() check before lowering + to verify that after all the transformations we still have valid IR for the FTL. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): Added GetArgument as a node the FTL can compile. + +2015-02-10 Filip Pizlo <fpizlo@apple.com> + + Remove unused DFG::SpeculativeJIT::calleeFrameOffset(). + + Rubber stamped by Michael Saboff. + + Not only was this not used, I believe that the math was wrong. The callee frame doesn't + actually land past m_nextMachineLocal; instead it lands just below wherever we put SP and + that decision is made elsewhere. Also, it makes no sense to subtract 1 from + m_nextMachineLocal when trying to deduce the number of in-use stack slots. + + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::calleeFrameOffset): Deleted. + +2015-02-10 Saam Barati <saambarati1@gmail.com> + + Parser::parseVarDeclarationList gets the wrong JSToken for the last identifier + https://bugs.webkit.org/show_bug.cgi?id=141272 + + Reviewed by Oliver Hunt. + + This patch fixes a bug where the wrong text location would be + assigned to a variable declaration inside a ForIn/ForOf loop. + It also fixes a bug in the type profiler where the type profiler + emits the wrong text offset for a ForIn loop's variable declarator + when it's not a pattern node. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitLoopHeader): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclarationList): + * tests/typeProfiler/loop.js: + (testForIn): + (testForOf): + +2015-02-09 Saam Barati <saambarati1@gmail.com> + + JSC's Type Profiler doesn't profile the type of the looping variable in ForOf/ForIn loops + https://bugs.webkit.org/show_bug.cgi?id=141241 + + Reviewed by Filip Pizlo. + + Type information is now recorded for ForIn and ForOf statements. + It was an oversight to not have these statements profiled before. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitLoopHeader): + (JSC::ForOfNode::emitBytecode): + * tests/typeProfiler/loop.js: Added. + (testForIn): + (testForOf): + +2015-02-09 Filip Pizlo <fpizlo@apple.com> + + DFG::StackLayoutPhase should always set the scopeRegister to VirtualRegister() because the DFG doesn't do anything to make its value valid + https://bugs.webkit.org/show_bug.cgi?id=141412 + + Reviewed by Michael Saboff. + + StackLayoutPhase was attempting to ensure that the register that + CodeBlock::scopeRegister() points to is the right one for the DFG. But the DFG did nothing + else to maintain the validity of the scopeRegister(). It wasn't captured as far as I can + tell. StackLayoutPhase didn't explicitly mark it live. PreciseLocalClobberize didn't mark + it as being live. So, by the time we got here the register referred to by + CodeBlock::scopeRegister() would have been junk. Moreover, CodeBlock::scopeRegister() was + not used for DFG code blocks, and was hardly ever used outside of bytecode generation. + + So, this patch just removes the code to manipulate this field and replaces it with an + unconditional setScopeRegister(VirtualRegister()). Setting it to the invalid register + ensures that any attempst to read the scopeRegister in a DFG or FTL frame immediately + punts. + + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + +2015-02-09 Filip Pizlo <fpizlo@apple.com> + + Varargs frame set-up should be factored out for use by other JITs + https://bugs.webkit.org/show_bug.cgi?id=141388 + + Reviewed by Michael Saboff. + + Previously the code that dealt with varargs always assumed that we were setting up a varargs call + frame by literally following the execution semantics of op_call_varargs. This isn't how it'll + happen once the DFG and FTL do varargs calls, or when varargs calls get inlined. The DFG and FTL + don't literally execute bytecode; for example their stack frame layout has absolutely nothing in + common with what the bytecode says, and that will never change. + + This patch makes two changes: + + Setting up the varargs callee frame can be done in smaller steps: particularly in the case of a + varargs call that gets inlined, we aren't going to actually want to set up a callee frame in + full - we just want to put the arguments somewhere, and that place will not have much (if + anything) in common with the call frame format. This patch factors that out into something called + a loadVarargs. The thing we used to call loadVarargs is now called setupVarargsFrame. This patch + also separates loading varargs from setting this, since the fact that those two things are done + together is a detail made explicit in bytecode but it's not at all required in the higher-tier + engines. In the process of factoring this code out, I found a bunch of off-by-one errors in the + various calculations. I fixed them. The distance from the caller's frame pointer to the callee + frame pointer is always: + + numUsedCallerSlots + argCount + 1 + CallFrameSize + + where numUsedCallerSlots is toLocal(firstFreeRegister) - 1, which simplifies down to just + -firstFreeRegister. The code now speaks of numUsedCallerSlots rather than firstFreeRegister, + since the latter is a bytecode peculiarity that doesn't apply in the DFG or FTL. In the DFG, the + internally-computed frame size, minus the parameter slots, will be used for numUsedCallerSlots. + In the FTL, we will essentially compute numUsedCallerSlots dynamically by subtracting SP from FP. + Eventually, LLVM might give us some cleaner way of doing this, but it probably doesn't matter + very much. + + The arguments forwarding optimization is factored out of the Baseline JIT: the DFG and FTL will + want to do this optimization as well, but it involves quite a bit of code. So, this code is now + factored out into SetupVarargsFrame.h|cpp, so that other JITs can use it. In the process of factoring + this code out I noticed that the 32-bit and 64-bit code is nearly identical, so I combined them. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.h: + (JSC::ExecState::r): + (JSC::ExecState::uncheckedR): + * bytecode/VirtualRegister.h: + (JSC::VirtualRegister::operator+): + (JSC::VirtualRegister::operator-): + (JSC::VirtualRegister::operator+=): + (JSC::VirtualRegister::operator-=): + * interpreter/CallFrame.h: + * interpreter/Interpreter.cpp: + (JSC::sizeFrameForVarargs): + (JSC::loadVarargs): + (JSC::setupVarargsFrame): + (JSC::setupVarargsFrameAndSetThis): + * interpreter/Interpreter.h: + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::emitGetFromCallFrameHeaderPtr): + (JSC::AssemblyHelpers::emitGetFromCallFrameHeader32): + (JSC::AssemblyHelpers::emitGetFromCallFrameHeader64): + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileSetupVarargsFrame): + * jit/JITInlines.h: + (JSC::JIT::callOperation): + (JSC::JIT::emitGetFromCallFrameHeaderPtr): Deleted. + (JSC::JIT::emitGetFromCallFrameHeader32): Deleted. + (JSC::JIT::emitGetFromCallFrameHeader64): Deleted. + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * jit/SetupVarargsFrame.cpp: Added. + (JSC::emitSetupVarargsFrameFastCase): + * jit/SetupVarargsFrame.h: Added. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::copyToArguments): + * runtime/Arguments.h: + * runtime/JSArray.cpp: + (JSC::JSArray::copyToArguments): + * runtime/JSArray.h: + +2015-02-09 Filip Pizlo <fpizlo@apple.com> + + DFG call codegen should resolve the callee operand as late as possible + https://bugs.webkit.org/show_bug.cgi?id=141398 + + Reviewed by Mark Lam. + + This is mostly a benign restructuring to help with the implementation of + https://bugs.webkit.org/show_bug.cgi?id=141332. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + +2015-02-08 Filip Pizlo <fpizlo@apple.com> + + DFG should only have two mechanisms for describing effectfulness of nodes; previously there were three + https://bugs.webkit.org/show_bug.cgi?id=141369 + + Reviewed by Michael Saboff. + + We previously used the NodeMightClobber and NodeClobbersWorld NodeFlags to describe + effectfulness. Starting over a year ago, we introduced a more powerful mechanism - the + DFG::clobberize() function. Now we only have one remaining client of the old NodeFlags, + and everyone else uses DFG::clobberize(). We should get rid of those NodeFlags and + finally switch everyone over to DFG::clobberize(). + + Unfortunately there is still another place where effectfulness of nodes is described: the + AbstractInterpreter. This is because the AbstractInterpreter has special tuning both for + compile time performance and there are places where the AI is more precise than + clobberize() because of its flow-sensitivity. + + This means that after this change there will be only two places, rather than three, where + the effectfulness of a node has to be described: + + - DFG::clobberize() + - DFG::AbstractInterpreter + + * dfg/DFGClobberize.cpp: + (JSC::DFG::clobbersWorld): + * dfg/DFGClobberize.h: + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteLength): + (JSC::DFG::FixupPhase::convertToGetArrayLength): + (JSC::DFG::FixupPhase::attemptToMakeGetTypedArrayByteOffset): + * dfg/DFGGraph.h: + (JSC::DFG::Graph::isPredictedNumerical): Deleted. + (JSC::DFG::Graph::byValIsPure): Deleted. + (JSC::DFG::Graph::clobbersWorld): Deleted. + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToConstant): + (JSC::DFG::Node::convertToGetLocalUnlinked): + (JSC::DFG::Node::convertToGetByOffset): + (JSC::DFG::Node::convertToMultiGetByOffset): + (JSC::DFG::Node::convertToPutByOffset): + (JSC::DFG::Node::convertToMultiPutByOffset): + * dfg/DFGNodeFlags.cpp: + (JSC::DFG::dumpNodeFlags): + * dfg/DFGNodeFlags.h: + * dfg/DFGNodeType.h: + +2015-02-09 Csaba Osztrogonác <ossy@webkit.org> + + Fix the !ENABLE(DFG_JIT) build + https://bugs.webkit.org/show_bug.cgi?id=141387 + + Reviewed by Darin Adler. + + * jit/Repatch.cpp: + +2015-02-08 Benjamin Poulain <benjamin@webkit.org> + + Remove a few duplicate propagation steps from the DFG's PredictionPropagation phase + https://bugs.webkit.org/show_bug.cgi?id=141363 + + Reviewed by Darin Adler. + + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + Some blocks were duplicated, they probably evolved separately + to the same state. + +2015-02-08 Benjamin Poulain <benjamin@webkit.org> + + Remove useless declarations and a stale comment from DFGByteCodeParser.h + https://bugs.webkit.org/show_bug.cgi?id=141361 + + Reviewed by Darin Adler. + + The comment refers to the original form of the ByteCodeParser: + parse(Graph&, JSGlobalData*, CodeBlock*, unsigned startIndex); + + That form is long dead, the comment is more misleading than anything. + + * dfg/DFGByteCodeParser.cpp: + * dfg/DFGByteCodeParser.h: + +2015-02-08 Benjamin Poulain <benjamin@webkit.org> + + Encapsulate DFG::Plan's beforeFTL timestamp + https://bugs.webkit.org/show_bug.cgi?id=141360 + + Reviewed by Darin Adler. + + Make the attribute private, it is an internal state. + + Rename beforeFTL->timeBeforeFTL for readability. + + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThread): + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGPlan.h: + +2015-02-08 Benjamin Poulain <bpoulain@apple.com> + + Remove DFGNode::hasArithNodeFlags() + https://bugs.webkit.org/show_bug.cgi?id=141319 + + Reviewed by Michael Saboff. + + * dfg/DFGNode.h: + (JSC::DFG::Node::hasArithNodeFlags): Deleted. + Unused code is unused. + +2015-02-07 Chris Dumez <cdumez@apple.com> + + Add Vector::removeFirstMatching() / removeAllMatching() methods taking lambda functions + https://bugs.webkit.org/show_bug.cgi?id=141321 + + Reviewed by Darin Adler. + + Use new Vector::removeFirstMatching() / removeAllMatching() methods. + +2015-02-06 Filip Pizlo <fpizlo@apple.com> + + DFG SSA shouldn't have SetArgument nodes + https://bugs.webkit.org/show_bug.cgi?id=141342 + + Reviewed by Mark Lam. + + I was wondering why we kept the SetArgument around for captured + variables. It turns out we did so because we thought we had to, even + though we didn't have to. The node is meaningless in SSA. + + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + +2015-02-06 Filip Pizlo <fpizlo@apple.com> + + It should be possible to use the DFG SetArgument node to indicate that someone set the value of a local out-of-band + https://bugs.webkit.org/show_bug.cgi?id=141337 + + Reviewed by Mark Lam. + + This mainly involved ensuring that SetArgument behaves just like SetLocal from a CPS standpoint, but with a special case for those SetArguments that + are associated with the prologue. + + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::run): + (JSC::DFG::CPSRethreadingPhase::canonicalizeSet): + (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock): + (JSC::DFG::CPSRethreadingPhase::specialCaseArguments): + (JSC::DFG::CPSRethreadingPhase::canonicalizeSetLocal): Deleted. + (JSC::DFG::CPSRethreadingPhase::canonicalizeSetArgument): Deleted. + +2015-02-06 Mark Lam <mark.lam@apple.com> + + MachineThreads should be ref counted. + <https://webkit.org/b/141317> + + Reviewed by Filip Pizlo. + + The VM's MachineThreads registry object is being referenced from other + threads as a raw pointer. In a scenario where the VM is destructed on + the main thread, there is no guarantee that another thread isn't still + holding a reference to the registry and will eventually invoke + removeThread() on it on thread exit. Hence, there's a possible use + after free scenario here. + + The fix is to make MachineThreads ThreadSafeRefCounted, and have all + threads that references keep a RefPtr to it to ensure that it stays + alive until the very last thread is done with it. + + * API/tests/testapi.mm: + (useVMFromOtherThread): - Renamed to be more descriptive. + (useVMFromOtherThreadAndOutliveVM): + - Added a test that has another thread which uses the VM outlive the + VM to confirm that there is no crash. + + However, I was not actually able to get the VM to crash without this + patch because I wasn't always able to the thread destructor to be + called. With this patch applied, I did verify with some logging that + the MachineThreads registry is only destructed after all threads + have removed themselves from it. + + (threadMain): Deleted. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::~Heap): + (JSC::Heap::gatherStackRoots): + * heap/Heap.h: + (JSC::Heap::machineThreads): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::Thread::Thread): + (JSC::MachineThreads::addCurrentThread): + (JSC::MachineThreads::removeCurrentThread): + * heap/MachineStackMarker.h: + +2015-02-06 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r179743. + https://bugs.webkit.org/show_bug.cgi?id=141335 + + caused missing symbols in non-WebKit clients of WTF::Vector + (Requested by kling on #webkit). + + Reverted changeset: + + "Remove WTF::fastMallocGoodSize()." + https://bugs.webkit.org/show_bug.cgi?id=141020 + http://trac.webkit.org/changeset/179743 + +2015-02-04 Filip Pizlo <fpizlo@apple.com> + + Remove BytecodeGenerator::preserveLastVar() and replace it with a more robust mechanism for preserving non-temporary registers + https://bugs.webkit.org/show_bug.cgi?id=141211 + + Reviewed by Mark Lam. + + Previously, the way non-temporary registers were preserved (i.e. not reclaimed anytime + we did newTemporary()) by calling preserveLastVar() after all non-temps are created. It + would raise the refcount on the last (highest-numbered) variable created, and rely on + the fact that register reclamation started at higher-numbered registers and worked its + way down. So any retained register would block any lower-numbered registers from being + reclaimed. + + Also, preserveLastVar() sets a thing called m_firstConstantIndex. It's unused. + + This removes preserveLastVar() and makes addVar() retain each register it creates. This + is more explicit, since addVar() is the mechanism for creating non-temporary registers. + + To make this work I had to remove an assertion that Register::setIndex() can only be + called when the refcount is zero. This method might be called after a var is created to + change its index. This previously worked because preserveLastVar() would be called after + we had already made all index changes, so the vars would still have refcount zero. Now + they have refcount 1. I think it's OK to lose this assertion; I can't remember this + assertion ever firing in a way that alerted me to a serious issue. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::preserveLastVar): Deleted. + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::addVar): + * bytecompiler/RegisterID.h: + (JSC::RegisterID::setIndex): + +2015-02-06 Andreas Kling <akling@apple.com> + + Remove WTF::fastMallocGoodSize(). + <https://webkit.org/b/141020> + + Reviewed by Anders Carlsson. + + * assembler/AssemblerBuffer.h: + (JSC::AssemblerData::AssemblerData): + (JSC::AssemblerData::grow): + +2015-02-05 Michael Saboff <msaboff@apple.com> + + CodeCache is not thread safe when adding the same source from two different threads + https://bugs.webkit.org/show_bug.cgi?id=141275 + + Reviewed by Mark Lam. + + The issue for this bug is that one thread, takes a cache miss in CodeCache::getGlobalCodeBlock, + but in the process creates a cache entry with a nullptr UnlinkedCodeBlockType* which it + will fill in later in the function. During the body of that function, it allocates + objects that may garbage collect. During that garbage collection, we drop the all locks. + While the locks are released by the first thread, another thread can enter the VM and might + have exactly the same source and enter CodeCache::getGlobalCodeBlock() itself. When it + looks up the code block, it sees it as a cache it and uses the nullptr UnlinkedCodeBlockType* + and crashes. This fixes the problem by not dropping the locks during garbage collection. + There are other likely scenarios where we have a data structure like this code cache in an + unsafe state for arbitrary reentrance. + + Moved the functionality of DelayedReleaseScope directly into Heap. Changed it into + a simple list that is cleared with the new function Heap::releaseDelayedReleasedObjects. + Now we accumulate objects to be released and release them when all locks are dropped or + when destroying the Heap. This eliminated the dropping and reaquiring of locks associated + with the old scope form of this list. + + Given that all functionality of DelayedReleaseScope is now used and referenced by Heap + and the lock management no longer needs to be done, just made the list a member of Heap. + We do need to guard against the case that releasing an object can create more objects + by calling into JS. That is why releaseDelayedReleasedObjects() is written to remove + an object to release so that we aren't recursively in Vector code. The other thing we + do in releaseDelayedReleasedObjects() is to guard against recursive calls to itself using + the m_delayedReleaseRecursionCount. We only release at the first entry into the function. + This case is already tested by testapi.mm. + + * heap/DelayedReleaseScope.h: Removed file + + * API/JSAPIWrapperObject.mm: + * API/ObjCCallbackFunction.mm: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::doSweep): + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::tryAllocateHelper): + (JSC::MarkedAllocator::tryAllocate): + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::sweep): + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::MarkedSpace): + (JSC::MarkedSpace::lastChanceToFinalize): + (JSC::MarkedSpace::didFinishIterating): + * heap/MarkedSpace.h: + * heap/Heap.cpp: + (JSC::Heap::collectAllGarbage): + (JSC::Heap::zombifyDeadObjects): + Removed references to DelayedReleaseScope and DelayedReleaseScope.h. + + * heap/Heap.cpp: + (JSC::Heap::Heap): Initialized m_delayedReleaseRecursionCount. + (JSC::Heap::lastChanceToFinalize): Call releaseDelayedObjectsNow() as the VM is going away. + (JSC::Heap::releaseDelayedReleasedObjects): New function that released the accumulated + delayed release objects. + + * heap/Heap.h: + (JSC::Heap::m_delayedReleaseObjects): List of objects to be released later. + (JSC::Heap::m_delayedReleaseRecursionCount): Counter to indicate that + releaseDelayedReleasedObjects is being called recursively. + * heap/HeapInlines.h: + (JSC::Heap::releaseSoon): Changed location of list to add delayed release objects. + + * runtime/JSLock.cpp: + (JSC::JSLock::willReleaseLock): + Call Heap::releaseDelayedObjectsNow() when releasing the lock. + +2015-02-05 Youenn Fablet <youenn.fablet@crf.canon.fr> and Xabier Rodriguez Calvar <calvaris@igalia.com> + + [Streams API] Implement a barebone ReadableStream interface + https://bugs.webkit.org/show_bug.cgi?id=141045 + + Reviewed by Benjamin Poulain. + + * Configurations/FeatureDefines.xcconfig: + +2015-02-05 Saam Barati <saambarati1@gmail.com> + + Crash in uninitialized deconstructing variable. + https://bugs.webkit.org/show_bug.cgi?id=141070 + + Reviewed by Michael Saboff. + + According to the ES6 spec, when a destructuring pattern occurs + as the left hand side of an assignment inside a var declaration + statement, the assignment must also have a right hand side value. + "var {x} = {};" is a legal syntactic statement, but, + "var {x};" is a syntactic error. + + Section 13.2.2 of the latest draft ES6 spec specifies this requirement: + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-variable-statement + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseVarDeclaration): + (JSC::Parser<LexerType>::parseVarDeclarationList): + (JSC::Parser<LexerType>::parseForStatement): + * parser/Parser.h: + +2015-02-04 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Unreviewed, fix a build break on EFL port since r179648. + + * heap/MachineStackMarker.cpp: EFL port doesn't use previousThread variable. + (JSC::MachineThreads::tryCopyOtherThreadStacks): + +2015-02-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ES6: Improved Console Support for Symbol Objects + https://bugs.webkit.org/show_bug.cgi?id=141173 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Runtime.json: + New type, "symbol". + + * inspector/InjectedScriptSource.js: + Handle Symbol objects in a few places. They don't have properties + and they cannot be implicitly converted to strings. + +2015-02-04 Mark Lam <mark.lam@apple.com> + + Undo gardening: Restoring the expected ERROR message since that is not the cause of the bot unhappiness. + + Not reviewed. + + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::tryCopyOtherThreadStacks): + +2015-02-04 Mark Lam <mark.lam@apple.com> + + Gardening: Changed expected ERROR message to WARNING to make test bots happy. + + Rubber stamped by Simon Fraser. + + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::tryCopyOtherThreadStacks): + +2015-02-04 Mark Lam <mark.lam@apple.com> + + r179576 introduce a deadlock potential during GC thread suspension. + <https://webkit.org/b/141268> + + Reviewed by Michael Saboff. + + http://trac.webkit.org/r179576 introduced a potential for deadlocking. + In the GC thread suspension loop, we currently delete + MachineThreads::Thread that we detect to be invalid. This is unsafe + because we may have already suspended some threads, and one of those + suspended threads may still be holding the C heap lock which we need + for deleting the invalid thread. + + The fix is to put the invalid threads in a separate toBeDeleted list, + and delete them only after GC has resumed all threads. + + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::removeCurrentThread): + - Undo refactoring removeThreadWithLockAlreadyAcquired() out of + removeCurrentThread() since it is no longer needed. + + (JSC::MachineThreads::tryCopyOtherThreadStacks): + - Put invalid Threads on a threadsToBeDeleted list, and delete those + Threads only after all threads have been resumed. + + (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): Deleted. + * heap/MachineStackMarker.h: + +2015-02-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Clean up Object Property Descriptor Collection + https://bugs.webkit.org/show_bug.cgi?id=141222 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + Use a list of options when determining which properties to collect + instead of a few booleans with overlapping responsibilities. + +2015-02-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: console.table with columnName filter for non-existent property should still show column + https://bugs.webkit.org/show_bug.cgi?id=141066 + + Reviewed by Timothy Hatcher. + + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::addToFrontend): + When a user provides a second argument, e.g. console.table(..., columnNames), + then pass that second argument to the frontend. + + * inspector/InjectedScriptSource.js: + Add a FIXME about the old, unused path now. + +2015-02-04 Saam Barati <saambarati1@gmail.com> + + TypeSet can use 1 byte instead of 4 bytes for its m_seenTypes member variable + https://bugs.webkit.org/show_bug.cgi?id=141204 + + Reviewed by Darin Adler. + + There is no need to use 32 bits to store a TypeSet::RuntimeType set + bit-vector when the largest value for a single TypeSet::RuntimeType + is 0x80. 8 bits is enough to represent the set of seen types. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * runtime/TypeSet.cpp: + (JSC::TypeSet::doesTypeConformTo): + * runtime/TypeSet.h: + (JSC::TypeSet::seenTypes): + +2015-02-04 Mark Lam <mark.lam@apple.com> + + Remove concept of makeUsableFromMultipleThreads(). + <https://webkit.org/b/141221> + + Reviewed by Mark Hahnenberg. + + Currently, we rely on VM::makeUsableFromMultipleThreads() being called before we + start acquiring the JSLock and entering the VM from different threads. + Acquisition of the JSLock will register the acquiring thread with the VM's thread + registry if not already registered. However, it will only do this if the VM's + thread specific key has been initialized by makeUsableFromMultipleThreads(). + + This is fragile, and also does not read intuitively because one would expect to + acquire the JSLock before calling any methods on the VM. This is exactly what + JSGlobalContextCreateInGroup() did (i.e. acquire the lock before calling + makeUsableFromMultipleThreads()), but is wrong. The result is that the invoking + thread will not have been registered with the VM during that first entry into + the VM. + + The fix is to make it so that we initialize the VM's thread specific key on + construction of the VM's MachineThreads registry instead of relying on + makeUsableFromMultipleThreads() being called. With this, we can eliminate + makeUsableFromMultipleThreads() altogether. + + Performance results are neutral in aggregate. + + * API/JSContextRef.cpp: + (JSGlobalContextCreateInGroup): + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::MachineThreads): + (JSC::MachineThreads::~MachineThreads): + (JSC::MachineThreads::addCurrentThread): + (JSC::MachineThreads::removeThread): + (JSC::MachineThreads::gatherConservativeRoots): + (JSC::MachineThreads::makeUsableFromMultipleThreads): Deleted. + * heap/MachineStackMarker.h: + * runtime/VM.cpp: + (JSC::VM::sharedInstance): + * runtime/VM.h: + (JSC::VM::makeUsableFromMultipleThreads): Deleted. + +2015-02-04 Chris Dumez <cdumez@apple.com> + + Add removeFirst(value) / removeAll(value) methods to WTF::Vector + https://bugs.webkit.org/show_bug.cgi?id=141192 + + Reviewed by Benjamin Poulain. + + Use new Vector::removeFirst(value) / removeAll(value) API to simplify the + code a bit. + + * inspector/InspectorValues.cpp: + (Inspector::InspectorObjectBase::remove): + +2015-02-03 Mark Lam <mark.lam@apple.com> + + Workaround a thread library bug where thread destructors may not get called. + <https://webkit.org/b/141209> + + Reviewed by Michael Saboff. + + There's a bug where thread destructors may not get called. As far as + we know, this only manifests on darwin ports. We will work around this + by checking at GC time if the platform thread is still valid. If not, + we'll purge it from the VM's registeredThreads list before proceeding + with thread scanning activity. + + Note: it is important that we do this invalid thread detection during + suspension, because the validity (and liveness) of the other thread is + only guaranteed while it is suspended. + + * API/tests/testapi.mm: + (threadMain): + - Added a test to enter the VM from another thread before we GC on + the main thread. + + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): + (JSC::MachineThreads::removeCurrentThread): + - refactored removeThreadWithLockAlreadyAcquired() out from + removeCurrentThread() so that we can also call it for purging invalid + threads. + (JSC::suspendThread): + - Added a return status to tell if the suspension succeeded or not. + (JSC::MachineThreads::tryCopyOtherThreadStacks): + - Check if the suspension failed, and purge the thread if we can't + suspend it. Failure to suspend implies that the thread has + terminated without calling its destructor. + * heap/MachineStackMarker.h: + +2015-02-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ASSERT mainThreadPthread launching remote debuggable JSContext app with Debug JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=141189 + + Reviewed by Michael Saboff. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::singleton): + Ensure we call WTF::initializeMainThread() on the main thread so that + we can perform automatic String <-> NSString conversions. + +2015-02-03 Brent Fulgham <bfulgham@apple.com> + + [Win] Project file cleanups after r179429. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2015-02-02 Filip Pizlo <fpizlo@apple.com> + + arguments[-1] should have well-defined behavior + https://bugs.webkit.org/show_bug.cgi?id=141183 + + Reviewed by Mark Lam. + + According to JSC's internal argument numbering, 0 is "this" and 1 is the first argument. + In the "arguments[i]" expression, "this" is not accessible and i = 0 refers to the first + argument. Previously we handled the bounds check in "arguments[i]" - where "arguments" is + statically known to be the current function's arguments object - as follows: + + add 1, i + branchAboveOrEqual i, callFrame.ArgumentCount, slowPath + + The problem with this is that if i = -1, this passes the test, and we end up accessing + what would be the "this" argument slot. That's wrong, since we should really be bottoming + out in arguments["-1"], which is usually undefined but could be anything. It's even worse + if the function is inlined or if we're in a constructor - in that case the "this" slot + could be garbage. + + It turns out that we had this bug in all of our engines. + + This fixes the issue by changing the algorithm to: + + load32 callFrame.ArgumentCount, tmp + sub 1, tmp + branchAboveOrEqual i, tmp, slowPath + + In some engines, we would have used the modified "i" (the one that had 1 added to it) for + the subsequent argument load; since we don't do this anymore I also had to change some of + the offsets on the BaseIndex arguments load. + + This also includes tests that are written in such a way as to get coverage on LLInt and + Baseline JIT (get-my-argument-by-val-wrap-around-no-warm-up), DFG and FTL + (get-my-argument-by-val-wrap-around), and DFG when we're being paranoid about the user + overwriting the "arguments" variable (get-my-argument-by-val-safe-wrap-around). This also + includes off-by-1 out-of-bounds tests for each of these cases, since in the process of + writing the patch I broke the arguments[arguments.length] case in the DFG and didn't see + any test failures. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::offsetOfArguments): + (JSC::AssemblyHelpers::offsetOfArgumentsIncludingThis): Deleted. + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_argument_by_val): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_argument_by_val): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * tests/stress/get-my-argument-by-val-out-of-bounds-no-warm-up.js: Added. + (foo): + * tests/stress/get-my-argument-by-val-out-of-bounds.js: Added. + (foo): + * tests/stress/get-my-argument-by-val-safe-out-of-bounds.js: Added. + (foo): + * tests/stress/get-my-argument-by-val-safe-wrap-around.js: Added. + (foo): + * tests/stress/get-my-argument-by-val-wrap-around-no-warm-up.js: Added. + (foo): + * tests/stress/get-my-argument-by-val-wrap-around.js: Added. + (foo): + +2015-02-02 Filip Pizlo <fpizlo@apple.com> + + MultiGetByOffset should be marked NodeMustGenerate + https://bugs.webkit.org/show_bug.cgi?id=140137 + + Reviewed by Michael Saboff. + + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToGetByOffset): We were sloppy - we should also clear NodeMustGenerate once it's a GetByOffset. + (JSC::DFG::Node::convertToMultiGetByOffset): Assert that we converted from something that already had NodeMustGenerate. + * dfg/DFGNodeType.h: We shouldn't DCE a node that does checks and could be effectful in baseline. Making MultiGetByOffset as NodeMustGenerate prevents DCE. FTL could still DCE the actual loads, but the checks will stay. + * tests/stress/multi-get-by-offset-dce.js: Added. This previously failed because the getter wasn't called. + (foo): + +2015-02-02 Filip Pizlo <fpizlo@apple.com> + + [FTL] inlined GetMyArgumentByVal with no arguments passed causes instant crash + https://bugs.webkit.org/show_bug.cgi?id=141180 + rdar://problem/19677552 + + Reviewed by Benjamin Poulain. + + If we do a GetMyArgumentByVal on an inlined call frame that has no arguments, then the + bounds check already terminates execution. This means we can skip the part where we + previously did an out-of-bound array access on the inlined call frame arguments vector. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::safelyInvalidateAfterTermination): + (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal): + (JSC::FTL::LowerDFGToLLVM::terminate): + (JSC::FTL::LowerDFGToLLVM::didAlreadyTerminate): + (JSC::FTL::LowerDFGToLLVM::crash): + * tests/stress/get-my-argument-by-val-inlined-no-formal-parameters.js: Added. + (foo): + (bar): + +2015-02-02 Filip Pizlo <fpizlo@apple.com> + + REGRESSION(r179477): arguments simplification no longer works + https://bugs.webkit.org/show_bug.cgi?id=141169 + + Reviewed by Mark Lam. + + The operations involved in callee/scope access don't exit and shouldn't get in the way + of strength-reducing a Flush to a PhantomLocal. Then the PhantomLocal shouldn't get in + the way of further such strength-reduction. We also need to canonicalize PhantomLocal + before running arguments simplification. + + * dfg/DFGMayExit.cpp: + (JSC::DFG::mayExit): + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + +2015-02-02 Filip Pizlo <fpizlo@apple.com> + + VirtualRegister should really know how to dump itself + https://bugs.webkit.org/show_bug.cgi?id=141171 + + Reviewed by Geoffrey Garen. + + Gives VirtualRegister a dump() method that pretty-prints the virtual register. The rest of + the patch is all about using this new power. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::constantName): + (JSC::CodeBlock::registerName): + * bytecode/CodeBlock.h: + (JSC::missingThisObjectMarker): Deleted. + * bytecode/VirtualRegister.cpp: Added. + (JSC::VirtualRegister::dump): + * bytecode/VirtualRegister.h: + (WTF::printInternal): Deleted. + * dfg/DFGArgumentPosition.h: + (JSC::DFG::ArgumentPosition::dump): + * dfg/DFGFlushedAt.cpp: + (JSC::DFG::FlushedAt::dump): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::dump): + * dfg/DFGPutLocalSinkingPhase.cpp: + * dfg/DFGSSAConversionPhase.cpp: + (JSC::DFG::SSAConversionPhase::run): + * dfg/DFGValidate.cpp: + (JSC::DFG::Validate::reportValidationContext): + * dfg/DFGValueSource.cpp: + (JSC::DFG::ValueSource::dump): + * dfg/DFGVariableEvent.cpp: + (JSC::DFG::VariableEvent::dump): + (JSC::DFG::VariableEvent::dumpSpillInfo): + * ftl/FTLExitArgumentForOperand.cpp: + (JSC::FTL::ExitArgumentForOperand::dump): + * ftl/FTLExitValue.cpp: + (JSC::FTL::ExitValue::dumpInContext): + * profiler/ProfilerBytecodeSequence.cpp: + (JSC::Profiler::BytecodeSequence::BytecodeSequence): + +2015-02-02 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the HandleBlock piece of this patch. + + * heap/HandleBlock.h: + * heap/HandleBlockInlines.h: + (JSC::HandleBlock::create): + (JSC::HandleBlock::destroy): + (JSC::HandleBlock::HandleBlock): + (JSC::HandleBlock::payloadEnd): + * heap/HandleSet.cpp: + (JSC::HandleSet::~HandleSet): + (JSC::HandleSet::grow): + +2015-02-02 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Support console.table + https://bugs.webkit.org/show_bug.cgi?id=141058 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + Include the firstLevelKeys filter when generating previews. + + * runtime/ConsoleClient.cpp: + (JSC::appendMessagePrefix): + Differentiate console.table logs to system log. + +2015-01-31 Filip Pizlo <fpizlo@apple.com> + + BinarySwitch should be faster on average + https://bugs.webkit.org/show_bug.cgi?id=141046 + + Reviewed by Anders Carlsson. + + This optimizes our binary switch using math. It's strictly better than what we had before + assuming we bottom out in some case (rather than fall through), assuming all cases get + hit with equal probability. The difference is particularly large for large switch + statements. For example, a switch statement with 1000 cases would previously require on + average 13.207 branches to get to some case, while now it just requires 10.464. + + This is also a progression for the fall-through case, though we could shave off another + 1/6 branch on average if we wanted to - though it would regress taking a case (not falling + through) by 1/6 branch. I believe it's better to bias the BinarySwitch for not falling + through. + + This also adds some randomness to the algorithm to minimize the likelihood of us + generating a switch statement that is always particularly bad for some input. Note that + the randomness has no effect on average-case performance assuming all cases are equally + likely. + + This ought to have no actual performance change because we don't rely on binary switches + that much. The main reason why this change is interesting is that I'm finding myself + increasingly relying on BinarySwitch, and I'd like to know that it's optimal. + + * jit/BinarySwitch.cpp: + (JSC::BinarySwitch::BinarySwitch): + (JSC::BinarySwitch::~BinarySwitch): + (JSC::BinarySwitch::build): + * jit/BinarySwitch.h: + +2015-02-02 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Extend CSS.getSupportedCSSProperties to provide values for properties for CSS Augmented JSContext + https://bugs.webkit.org/show_bug.cgi?id=141064 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/CSS.json: + +2015-02-02 Daniel Bates <dabates@apple.com> + + [iOS] ASSERTION FAILED: m_scriptExecutionContext->isContextThread() in ContextDestructionObserver::observeContext + https://bugs.webkit.org/show_bug.cgi?id=141057 + <rdar://problem/19068790> + + Reviewed by Alexey Proskuryakov. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::receivedIndicateMessage): Modified to call WTF::callOnWebThreadOrDispatchAsyncOnMainThread(). + (Inspector::dispatchAsyncOnQueueSafeForAnyDebuggable): Deleted; moved logic to common helper function, + WTF::callOnWebThreadOrDispatchAsyncOnMainThread() so that it can be called from both RemoteInspector::receivedIndicateMessage() + and CryptoKeyRSA::generatePair(). + +2015-02-02 Saam Barati <saambarati1@gmail.com> + + Create tests for JSC's Control Flow Profiler + https://bugs.webkit.org/show_bug.cgi?id=141123 + + Reviewed by Filip Pizlo. + + This patch creates a control flow profiler testing API in jsc.cpp + that accepts a function and a string as arguments. The string must + be a substring of the text of the function argument. The API returns + a boolean indicating whether or not the basic block that encloses the + substring has executed. + + This patch uses this API to test that the control flow profiler + behaves as expected on basic block boundaries. These tests do not + provide full coverage for all JavaScript statements that can create + basic blocks boundaries. Full coverage will come in a later patch. + + * jsc.cpp: + (GlobalObject::finishCreation): + (functionHasBasicBlockExecuted): + * runtime/ControlFlowProfiler.cpp: + (JSC::ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted): + * runtime/ControlFlowProfiler.h: + * tests/controlFlowProfiler: Added. + * tests/controlFlowProfiler.yaml: Added. + * tests/controlFlowProfiler/driver: Added. + * tests/controlFlowProfiler/driver/driver.js: Added. + (assert): + * tests/controlFlowProfiler/if-statement.js: Added. + (testIf): + (noMatches): + * tests/controlFlowProfiler/loop-statements.js: Added. + (forRegular): + (forIn): + (forOf): + (whileLoop): + * tests/controlFlowProfiler/switch-statements.js: Added. + (testSwitch): + * tests/controlFlowProfiler/test-jit.js: Added. + (tierUpToBaseline): + (tierUpToDFG): + (baselineTest): + (dfgTest): + +2015-01-28 Filip Pizlo <fpizlo@apple.com> + + Polymorphic call inlining should be based on polymorphic call inline caching rather than logging + https://bugs.webkit.org/show_bug.cgi?id=140660 + + Reviewed by Geoffrey Garen. + + When we first implemented polymorphic call inlining, we did the profiling based on a call + edge log. The idea was to store each call edge (a tuple of call site and callee) into a + global log that was processed lazily. Processing the log would give precise counts of call + edges, and could be used to drive well-informed inlining decisions - polymorphic or not. + This was a speed-up on throughput tests but a slow-down for latency tests. It was a net win + nonetheless. + + Experience with this code shows three things. First, the call edge profiler is buggy and + complex. It would take work to fix the bugs. Second, the call edge profiler incurs lots of + overhead for latency code that we care deeply about. Third, it's not at all clear that + having call edge counts for every possible callee is any better than just having call edge + counts for the limited number of callees that an inline cache would catch. + + So, this patch removes the call edge profiler and replaces it with a polymorphic call inline + cache. If we miss the basic call inline cache, we inflate the cache to be a jump to an + out-of-line stub that cases on the previously known callees. If that misses again, then we + rewrite that stub to include the new callee. We do this up to some number of callees. If we + hit the limit then we switch to using a plain virtual call. + + Substantial speed-up on V8Spider; undoes the slow-down that the original call edge profiler + caused. Might be a SunSpider speed-up (below 1%), depending on hardware. + + Rolling this back in after fixing https://bugs.webkit.org/show_bug.cgi?id=141107. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CallEdge.h: + (JSC::CallEdge::count): + (JSC::CallEdge::CallEdge): + * bytecode/CallEdgeProfile.cpp: Removed. + * bytecode/CallEdgeProfile.h: Removed. + * bytecode/CallEdgeProfileInlines.h: Removed. + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::unlink): + (JSC::CallLinkInfo::visitWeak): + * bytecode/CallLinkInfo.h: + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeFromCallLinkInfo): + (JSC::CallLinkStatus::isClosureCall): + (JSC::CallLinkStatus::makeClosureCall): + (JSC::CallLinkStatus::dump): + (JSC::CallLinkStatus::computeFromCallEdgeProfile): Deleted. + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::isSet): + (JSC::CallLinkStatus::variants): + (JSC::CallLinkStatus::size): + (JSC::CallLinkStatus::at): + (JSC::CallLinkStatus::operator[]): + (JSC::CallLinkStatus::canOptimize): + (JSC::CallLinkStatus::edges): Deleted. + (JSC::CallLinkStatus::canTrustCounts): Deleted. + * bytecode/CallVariant.cpp: + (JSC::variantListWithVariant): + (JSC::despecifiedVariantList): + * bytecode/CallVariant.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::~CodeBlock): + (JSC::CodeBlock::linkIncomingPolymorphicCall): + (JSC::CodeBlock::unlinkIncomingCalls): + (JSC::CodeBlock::noticeIncomingCall): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::isIncomingCallAlreadyLinked): Deleted. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasHeapPrediction): + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTierUpCheckInjectionPhase.cpp: + (JSC::DFG::TierUpCheckInjectionPhase::run): + (JSC::DFG::TierUpCheckInjectionPhase::removeFTLProfiling): Deleted. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * heap/Heap.cpp: + (JSC::Heap::collect): + * jit/BinarySwitch.h: + * jit/ClosureCallStubRoutine.cpp: Removed. + * jit/ClosureCallStubRoutine.h: Removed. + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + (JSC::operationLinkPolymorphicCallFor): + (JSC::operationLinkClosureCallFor): Deleted. + * jit/JITStubRoutine.h: + * jit/JITWriteBarrier.h: + * jit/PolymorphicCallStubRoutine.cpp: Added. + (JSC::PolymorphicCallNode::~PolymorphicCallNode): + (JSC::PolymorphicCallNode::unlink): + (JSC::PolymorphicCallCase::dump): + (JSC::PolymorphicCallStubRoutine::PolymorphicCallStubRoutine): + (JSC::PolymorphicCallStubRoutine::~PolymorphicCallStubRoutine): + (JSC::PolymorphicCallStubRoutine::variants): + (JSC::PolymorphicCallStubRoutine::edges): + (JSC::PolymorphicCallStubRoutine::visitWeak): + (JSC::PolymorphicCallStubRoutine::markRequiredObjectsInternal): + * jit/PolymorphicCallStubRoutine.h: Added. + (JSC::PolymorphicCallNode::PolymorphicCallNode): + (JSC::PolymorphicCallCase::PolymorphicCallCase): + (JSC::PolymorphicCallCase::variant): + (JSC::PolymorphicCallCase::codeBlock): + * jit/Repatch.cpp: + (JSC::linkSlowFor): + (JSC::linkFor): + (JSC::revertCall): + (JSC::unlinkFor): + (JSC::linkVirtualFor): + (JSC::linkPolymorphicCall): + (JSC::linkClosureCall): Deleted. + * jit/Repatch.h: + * jit/ThunkGenerators.cpp: + (JSC::linkPolymorphicCallForThunkGenerator): + (JSC::linkPolymorphicCallThunkGenerator): + (JSC::linkPolymorphicCallThatPreservesRegsThunkGenerator): + (JSC::linkClosureCallForThunkGenerator): Deleted. + (JSC::linkClosureCallThunkGenerator): Deleted. + (JSC::linkClosureCallThatPreservesRegsThunkGenerator): Deleted. + * jit/ThunkGenerators.h: + (JSC::linkPolymorphicCallThunkGeneratorFor): + (JSC::linkClosureCallThunkGeneratorFor): Deleted. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::jitCompileAndSetHeuristics): + * runtime/Options.h: + * runtime/VM.cpp: + (JSC::VM::prepareToDiscardCode): + (JSC::VM::ensureCallEdgeLog): Deleted. + * runtime/VM.h: + +2015-01-30 Filip Pizlo <fpizlo@apple.com> + + Converting Flushes and PhantomLocals to Phantoms requires an OSR availability analysis rather than just using the SetLocal's child + https://bugs.webkit.org/show_bug.cgi?id=141107 + + Reviewed by Michael Saboff. + + See the bugzilla for a discussion of the problem. This addresses the problem by ensuring + that Flushes are always strength-reduced to PhantomLocals, and CPS rethreading does a mini + OSR availability analysis to determine the right MovHint value to use for the Phantom. + + * dfg/DFGCPSRethreadingPhase.cpp: + (JSC::DFG::CPSRethreadingPhase::CPSRethreadingPhase): + (JSC::DFG::CPSRethreadingPhase::freeUnnecessaryNodes): + (JSC::DFG::CPSRethreadingPhase::clearVariables): + (JSC::DFG::CPSRethreadingPhase::canonicalizeFlushOrPhantomLocalFor): + (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock): + (JSC::DFG::CPSRethreadingPhase::clearVariablesAtHeadAndTail): Deleted. + * dfg/DFGNode.h: + (JSC::DFG::Node::convertPhantomToPhantomLocal): + (JSC::DFG::Node::convertFlushToPhantomLocal): + (JSC::DFG::Node::convertToPhantomLocal): Deleted. + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + * tests/stress/inline-call-that-doesnt-use-all-args.js: Added. + (foo): + (bar): + (baz): + +2015-01-31 Michael Saboff <msaboff@apple.com> + + Crash (DFG assertion) beneath AbstractInterpreter::verifyEdge() @ http://experilous.com/1/planet-generator/2014-09-28/version-1 + https://bugs.webkit.org/show_bug.cgi?id=141111 + + Reviewed by Filip Pizlo. + + In LowerDFGToLLVM::compileNode(), if we determine while compiling a node that we would have + exited, we don't need to process the OSR availability or abstract interpreter. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::safelyInvalidateAfterTermination): Broke this out a a separate + method since we need to call it at the top and near the bottom of compileNode(). + (JSC::FTL::LowerDFGToLLVM::compileNode): + +2015-01-31 Sam Weinig <sam@webkit.org> + + Remove even more Mountain Lion support + https://bugs.webkit.org/show_bug.cgi?id=141124 + + Reviewed by Alexey Proskuryakov. + + * API/tests/DateTests.mm: + * Configurations/Base.xcconfig: + * Configurations/DebugRelease.xcconfig: + * Configurations/FeatureDefines.xcconfig: + * Configurations/Version.xcconfig: + * jit/ExecutableAllocatorFixedVMPool.cpp: + +2015-01-31 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r179426. + https://bugs.webkit.org/show_bug.cgi?id=141119 + + "caused a memory use regression" (Requested by Guest45 on + #webkit). + + Reverted changeset: + + "Use FastMalloc (bmalloc) instead of BlockAllocator for GC + pages" + https://bugs.webkit.org/show_bug.cgi?id=140900 + http://trac.webkit.org/changeset/179426 + +2015-01-30 Daniel Bates <dabates@apple.com> + + Clean up: Remove unnecessary <dispatch/dispatch.h> header from RemoteInspectorDebuggableConnection.h + https://bugs.webkit.org/show_bug.cgi?id=141067 + + Reviewed by Timothy Hatcher. + + Remove the header <dispatch/dispatch.h> from RemoteInspectorDebuggableConnection.h as we + do not make use of its functionality. Instead, include this header in RemoteInspectorDebuggableConnection.mm + and RemoteInspector.mm. The latter depended on <dispatch/dispatch.h> being included via + header RemoteInspectorDebuggableConnection.h. + + * inspector/remote/RemoteInspector.mm: Include header <dispatch/dispatch.h>. + * inspector/remote/RemoteInspectorDebuggableConnection.h: Remove header <dispatch/dispatch.h>. + * inspector/remote/RemoteInspectorDebuggableConnection.mm: Include header <dispatch/dispatch.h>. + +2015-01-30 Yusuke Suzuki <utatane.tea@gmail.com> + + Implement ES6 Symbol + https://bugs.webkit.org/show_bug.cgi?id=140435 + + Reviewed by Geoffrey Garen. + + This patch implements ES6 Symbol. In this patch, we don't support + Symbol.keyFor, Symbol.for, Object.getOwnPropertySymbols. They will be + supported in the subsequent patches. + + Since ES6 Symbol is introduced as new primitive value, we implement + Symbol as a derived class from JSCell. And now JSValue accepts Symbol* + as a new primitive value. + + Symbol has a *unique* flagged StringImpl* as an `uid`. Which pointer + value represents the Symbol's identity. So don't compare Symbol's + JSCell pointer value for comparison. + This enables re-producing Symbol primitive value from StringImpl* uid + by executing`Symbol::create(vm, uid)`. This is needed to produce + Symbol primitive values from stored StringImpl* in `Object.getOwnPropertySymbols`. + + And Symbol.[[Description]] is folded into the string value of Symbol's uid. + By doing so, we can represent ES6 Symbol without extending current PropertyTable key; StringImpl*. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.order: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): + * builtins/BuiltinNames.h: + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + * interpreter/Interpreter.cpp: + * jit/JITOperations.cpp: + (JSC::getByVal): + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::getByVal): + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + * runtime/CommonIdentifiers.h: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + (JSC::CommonSlowPaths::opIn): + * runtime/ExceptionHelpers.cpp: + (JSC::createUndefinedVariableError): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::synthesizePrototype): + (JSC::JSValue::dumpInContextAssumingStructure): + (JSC::JSValue::toStringSlowCase): + * runtime/JSCJSValue.h: + * runtime/JSCJSValueInlines.h: + (JSC::JSValue::isSymbol): + (JSC::JSValue::isPrimitive): + (JSC::JSValue::toPropertyKey): + + It represents ToPropertyKey abstract operation in the ES6 spec. + It cleans up the old implementation's `isName` checks. + And to prevent performance regressions in + js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html + js/regress/fold-get-by-id-to-multi-get-by-offset.html + we annnotate this function as ALWAYS_INLINE. + + (JSC::JSValue::getPropertySlot): + (JSC::JSValue::get): + (JSC::JSValue::equalSlowCaseInline): + (JSC::JSValue::strictEqualSlowCaseInline): + * runtime/JSCell.cpp: + (JSC::JSCell::put): + (JSC::JSCell::putByIndex): + (JSC::JSCell::toPrimitive): + (JSC::JSCell::getPrimitiveNumber): + (JSC::JSCell::toNumber): + (JSC::JSCell::toObject): + * runtime/JSCell.h: + * runtime/JSCellInlines.h: + (JSC::JSCell::isSymbol): + (JSC::JSCell::toBoolean): + (JSC::JSCell::pureToBoolean): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::symbolPrototype): + (JSC::JSGlobalObject::symbolObjectStructure): + * runtime/JSONObject.cpp: + (JSC::Stringifier::Stringifier): + * runtime/JSSymbolTableObject.cpp: + (JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames): + * runtime/JSType.h: + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::isName): Deleted. + * runtime/MapData.cpp: + (JSC::MapData::find): + (JSC::MapData::add): + (JSC::MapData::remove): + (JSC::MapData::replaceAndPackBackingStore): + * runtime/MapData.h: + (JSC::MapData::clear): + * runtime/NameInstance.h: Removed. + * runtime/NamePrototype.cpp: Removed. + * runtime/ObjectConstructor.cpp: + (JSC::objectConstructorGetOwnPropertyDescriptor): + (JSC::objectConstructorDefineProperty): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncHasOwnProperty): + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + (JSC::objectProtoFuncPropertyIsEnumerable): + * runtime/Operations.cpp: + (JSC::jsTypeStringForValue): + (JSC::jsIsObjectType): + * runtime/PrivateName.h: + (JSC::PrivateName::PrivateName): + (JSC::PrivateName::operator==): + (JSC::PrivateName::operator!=): + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::find): + (JSC::PropertyTable::get): + * runtime/PropertyName.h: + (JSC::PropertyName::PropertyName): + (JSC::PropertyName::publicName): + * runtime/SmallStrings.h: + * runtime/StringConstructor.cpp: + (JSC::callStringConstructor): + + In ES6, String constructor accepts Symbol to execute `String(symbol)`. + + * runtime/Structure.cpp: + (JSC::Structure::getPropertyNamesFromStructure): + * runtime/StructureInlines.h: + (JSC::Structure::prototypeForLookup): + * runtime/Symbol.cpp: Added. + (JSC::Symbol::Symbol): + (JSC::SymbolObject::create): + (JSC::Symbol::toPrimitive): + (JSC::Symbol::toBoolean): + (JSC::Symbol::getPrimitiveNumber): + (JSC::Symbol::toObject): + (JSC::Symbol::toNumber): + (JSC::Symbol::destroy): + (JSC::Symbol::descriptiveString): + * runtime/Symbol.h: Added. + (JSC::Symbol::createStructure): + (JSC::Symbol::create): + (JSC::Symbol::privateName): + (JSC::Symbol::finishCreation): + (JSC::asSymbol): + * runtime/SymbolConstructor.cpp: Renamed from Source/JavaScriptCore/runtime/NameConstructor.cpp. + (JSC::SymbolConstructor::SymbolConstructor): + (JSC::SymbolConstructor::finishCreation): + (JSC::callSymbol): + (JSC::SymbolConstructor::getConstructData): + (JSC::SymbolConstructor::getCallData): + * runtime/SymbolConstructor.h: Renamed from Source/JavaScriptCore/runtime/NameConstructor.h. + (JSC::SymbolConstructor::create): + (JSC::SymbolConstructor::createStructure): + * runtime/SymbolObject.cpp: Renamed from Source/JavaScriptCore/runtime/NameInstance.cpp. + (JSC::SymbolObject::SymbolObject): + (JSC::SymbolObject::finishCreation): + (JSC::SymbolObject::defaultValue): + + Now JSC doesn't support @@toPrimitive. So instead of it, we implement + Symbol.prototype[@@toPrimitive] as ES5 Symbol.[[DefaultValue]]. + + * runtime/SymbolObject.h: Added. + (JSC::SymbolObject::create): + (JSC::SymbolObject::internalValue): + (JSC::SymbolObject::createStructure): + * runtime/SymbolPrototype.cpp: Added. + (JSC::SymbolPrototype::SymbolPrototype): + (JSC::SymbolPrototype::finishCreation): + (JSC::SymbolPrototype::getOwnPropertySlot): + (JSC::symbolProtoFuncToString): + (JSC::symbolProtoFuncValueOf): + * runtime/SymbolPrototype.h: Renamed from Source/JavaScriptCore/runtime/NamePrototype.h. + (JSC::SymbolPrototype::create): + (JSC::SymbolPrototype::createStructure): + + SymbolPrototype object is ordinary JS object. Not wrapper object of Symbol. + It is tested in js/symbol-prototype-is-ordinary-object.html. + + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2015-01-30 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the HandleBlock piece of this patch. + + * heap/HandleBlock.h: + * heap/HandleBlockInlines.h: + (JSC::HandleBlock::create): + (JSC::HandleBlock::destroy): + (JSC::HandleBlock::HandleBlock): + (JSC::HandleBlock::payloadEnd): + * heap/HandleSet.cpp: + (JSC::HandleSet::~HandleSet): + (JSC::HandleSet::grow): + +2015-01-30 Geoffrey Garen <ggaren@apple.com> + + GC marking threads should clear malloc caches + https://bugs.webkit.org/show_bug.cgi?id=141097 + + Reviewed by Sam Weinig. + + Follow-up based on Mark Hahnenberg's review: Release after the copy + phase, rather than after any phase, since we'd rather not release + between marking and copying. + + * heap/GCThread.cpp: + (JSC::GCThread::waitForNextPhase): + (JSC::GCThread::gcThreadMain): + +2015-01-30 Geoffrey Garen <ggaren@apple.com> + + GC marking threads should clear malloc caches + https://bugs.webkit.org/show_bug.cgi?id=141097 + + Reviewed by Andreas Kling. + + This is an attempt to ameliorate a potential memory use regression + caused by https://bugs.webkit.org/show_bug.cgi?id=140900 + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages. + + FastMalloc may accumulate a per-thread cache on each of the 8-ish + GC marking threads, which can be expensive. + + * heap/GCThread.cpp: + (JSC::GCThread::waitForNextPhase): Scavenge the current thread before + going to sleep. There's probably not too much value to keeping our + per-thread cache between GCs, and it has some memory footprint. + +2015-01-30 Chris Dumez <cdumez@apple.com> + + Rename shared() static member functions to singleton() for singleton classes. + https://bugs.webkit.org/show_bug.cgi?id=141088 + + Reviewed by Ryosuke Niwa and Benjamin Poulain. + + Rename shared() static member functions to singleton() for singleton + classes as per the recent coding style change. + + * inspector/remote/RemoteInspector.h: + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::singleton): + (Inspector::RemoteInspector::start): + (Inspector::RemoteInspector::shared): Deleted. + * inspector/remote/RemoteInspectorDebuggable.cpp: + (Inspector::RemoteInspectorDebuggable::~RemoteInspectorDebuggable): + (Inspector::RemoteInspectorDebuggable::init): + (Inspector::RemoteInspectorDebuggable::update): + (Inspector::RemoteInspectorDebuggable::setRemoteDebuggingAllowed): + (Inspector::RemoteInspectorDebuggable::pauseWaitingForAutomaticInspection): + (Inspector::RemoteInspectorDebuggable::unpauseForInitializedInspector): + * inspector/remote/RemoteInspectorDebuggableConnection.mm: + (Inspector::RemoteInspectorDebuggableConnection::setup): + (Inspector::RemoteInspectorDebuggableConnection::sendMessageToFrontend): + +2015-01-30 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the CopyWorkListSegment piece of this patch. + + * heap/CopiedBlockInlines.h: + (JSC::CopiedBlock::reportLiveBytes): + * heap/CopyWorkList.h: + (JSC::CopyWorkListSegment::create): + (JSC::CopyWorkListSegment::destroy): + (JSC::CopyWorkListSegment::CopyWorkListSegment): + (JSC::CopyWorkList::CopyWorkList): + (JSC::CopyWorkList::~CopyWorkList): + (JSC::CopyWorkList::append): + +2015-01-29 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r179357 and r179358. + https://bugs.webkit.org/show_bug.cgi?id=141062 + + Suspect this caused WebGL tests to start flaking (Requested by + kling on #webkit). + + Reverted changesets: + + "Polymorphic call inlining should be based on polymorphic call + inline caching rather than logging" + https://bugs.webkit.org/show_bug.cgi?id=140660 + http://trac.webkit.org/changeset/179357 + + "Unreviewed, fix no-JIT build." + http://trac.webkit.org/changeset/179358 + +2015-01-29 Geoffrey Garen <ggaren@apple.com> + + Removed op_ret_object_or_this + https://bugs.webkit.org/show_bug.cgi?id=141048 + + Reviewed by Michael Saboff. + + op_ret_object_or_this was one opcode that would keep us out of the + optimizing compilers. + + We don't need a special-purpose opcode; we can just use a branch. + + * bytecode/BytecodeBasicBlock.cpp: + (JSC::isTerminal): Removed. + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): Removed. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Removed. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitReturn): Use an explicit branch to determine + if we need to substitute 'this' for the return value. Our engine no longer + benefits from fused opcodes that dispatch less in the interpreter. + + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITCall32_64.cpp: + (JSC::JIT::emit_op_ret_object_or_this): Deleted. + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_ret_object_or_this): Deleted. + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: Removed. + +2015-01-29 Ryosuke Niwa <rniwa@webkit.org> + + Implement ES6 class syntax without inheritance support + https://bugs.webkit.org/show_bug.cgi?id=140918 + + Reviewed by Geoffrey Garen. + + Added the most basic support for ES6 class syntax. After this patch, we support basic class definition like: + class A { + constructor() { } + someMethod() { } + } + + We'll add the support for "extends" keyword and automatically generating a constructor in follow up patches. + We also don't support block scoping of a class declaration. + + We support both class declaration and class expression. A class expression is implemented by the newly added + ClassExprNode AST node. A class declaration is implemented by ClassDeclNode, which is a thin wrapper around + AssignResolveNode. + + Tests: js/class-syntax-declaration.html + js/class-syntax-expression.html + + * bytecompiler/NodesCodegen.cpp: + (JSC::ObjectLiteralNode::emitBytecode): Create a new object instead of delegating the work to PropertyListNode. + Also fixed the 5-space indentation. + (JSC::PropertyListNode::emitBytecode): Don't create a new object now that ObjectLiteralNode does this. + (JSC::ClassDeclNode::emitBytecode): Added. Just let the AssignResolveNode node emit the byte code. + (JSC::ClassExprNode::emitBytecode): Create the class constructor and add static methods to the constructor by + emitting the byte code for PropertyListNode. Add instance methods to the class's prototype object the same way. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createClassExpr): Added. Creates a ClassExprNode. + (JSC::ASTBuilder::createClassDeclStatement): Added. Creates a AssignResolveNode and wraps it by a ClassDeclNode. + + * parser/NodeConstructors.h: + (JSC::ClassDeclNode::ClassDeclNode): Added. + (JSC::ClassExprNode::ClassExprNode): Added. + + * parser/Nodes.h: + (JSC::ClassExprNode): Added. + (JSC::ClassDeclNode): Added. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseStatement): Added the support for class declaration. + (JSC::stringForFunctionMode): Return "method" for MethodMode. + (JSC::Parser<LexerType>::parseClassDeclaration): Added. Uses parseClass to create a class expression and wraps + it with ClassDeclNode as described above. + (JSC::Parser<LexerType>::parseClass): Parses a class expression. + (JSC::Parser<LexerType>::parseProperty): + (JSC::Parser<LexerType>::parseGetterSetter): Extracted from parseProperty to share the code between parseProperty + and parseClass. + (JSC::Parser<LexerType>::parsePrimaryExpression): Added the support for class expression. + + * parser/Parser.h: + (FunctionParseMode): Added MethodMode. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createClassExpr): Added. + (JSC::SyntaxChecker::createClassDeclStatement): Added. + +2015-01-29 Geoffrey Garen <ggaren@apple.com> + + Try to fix the Windows build. + + Not reviewed. + + * heap/WeakBlock.h: Use the fully qualified name when declaring our friend. + +2015-01-29 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the WeakBlock piece of this patch. + + * heap/WeakBlock.cpp: + (JSC::WeakBlock::create): + (JSC::WeakBlock::destroy): + (JSC::WeakBlock::WeakBlock): + * heap/WeakBlock.h: + * heap/WeakSet.cpp: + (JSC::WeakSet::~WeakSet): + (JSC::WeakSet::addAllocator): + (JSC::WeakSet::removeAllocator): + +2015-01-29 Geoffrey Garen <ggaren@apple.com> + + Use Vector instead of GCSegmentedArray in CodeBlockSet + https://bugs.webkit.org/show_bug.cgi?id=141044 + + Reviewed by Ryosuke Niwa. + + This is allowed now that we've gotten rid of fastMallocForbid. + + 4kB was a bit overkill for just storing a few pointers. + + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::CodeBlockSet): + * heap/CodeBlockSet.h: + * heap/Heap.cpp: + (JSC::Heap::Heap): + +2015-01-29 Filip Pizlo <fpizlo@apple.com> + + Unreviewed, fix no-JIT build. + + * jit/PolymorphicCallStubRoutine.cpp: + +2015-01-28 Filip Pizlo <fpizlo@apple.com> + + Polymorphic call inlining should be based on polymorphic call inline caching rather than logging + https://bugs.webkit.org/show_bug.cgi?id=140660 + + Reviewed by Geoffrey Garen. + + When we first implemented polymorphic call inlining, we did the profiling based on a call + edge log. The idea was to store each call edge (a tuple of call site and callee) into a + global log that was processed lazily. Processing the log would give precise counts of call + edges, and could be used to drive well-informed inlining decisions - polymorphic or not. + This was a speed-up on throughput tests but a slow-down for latency tests. It was a net win + nonetheless. + + Experience with this code shows three things. First, the call edge profiler is buggy and + complex. It would take work to fix the bugs. Second, the call edge profiler incurs lots of + overhead for latency code that we care deeply about. Third, it's not at all clear that + having call edge counts for every possible callee is any better than just having call edge + counts for the limited number of callees that an inline cache would catch. + + So, this patch removes the call edge profiler and replaces it with a polymorphic call inline + cache. If we miss the basic call inline cache, we inflate the cache to be a jump to an + out-of-line stub that cases on the previously known callees. If that misses again, then we + rewrite that stub to include the new callee. We do this up to some number of callees. If we + hit the limit then we switch to using a plain virtual call. + + Substantial speed-up on V8Spider; undoes the slow-down that the original call edge profiler + caused. Might be a SunSpider speed-up (below 1%), depending on hardware. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CallEdge.h: + (JSC::CallEdge::count): + (JSC::CallEdge::CallEdge): + * bytecode/CallEdgeProfile.cpp: Removed. + * bytecode/CallEdgeProfile.h: Removed. + * bytecode/CallEdgeProfileInlines.h: Removed. + * bytecode/CallLinkInfo.cpp: + (JSC::CallLinkInfo::unlink): + (JSC::CallLinkInfo::visitWeak): + * bytecode/CallLinkInfo.h: + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::computeFor): + (JSC::CallLinkStatus::computeFromCallLinkInfo): + (JSC::CallLinkStatus::isClosureCall): + (JSC::CallLinkStatus::makeClosureCall): + (JSC::CallLinkStatus::dump): + (JSC::CallLinkStatus::computeFromCallEdgeProfile): Deleted. + * bytecode/CallLinkStatus.h: + (JSC::CallLinkStatus::CallLinkStatus): + (JSC::CallLinkStatus::isSet): + (JSC::CallLinkStatus::variants): + (JSC::CallLinkStatus::size): + (JSC::CallLinkStatus::at): + (JSC::CallLinkStatus::operator[]): + (JSC::CallLinkStatus::canOptimize): + (JSC::CallLinkStatus::edges): Deleted. + (JSC::CallLinkStatus::canTrustCounts): Deleted. + * bytecode/CallVariant.cpp: + (JSC::variantListWithVariant): + (JSC::despecifiedVariantList): + * bytecode/CallVariant.h: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::~CodeBlock): + (JSC::CodeBlock::linkIncomingPolymorphicCall): + (JSC::CodeBlock::unlinkIncomingCalls): + (JSC::CodeBlock::noticeIncomingCall): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::isIncomingCallAlreadyLinked): Deleted. + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult): + (JSC::DFG::ByteCodeParser::handleCall): + (JSC::DFG::ByteCodeParser::handleInlining): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::foldConstants): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGDriver.cpp: + (JSC::DFG::compileImpl): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::hasHeapPrediction): + * dfg/DFGNodeType.h: + * dfg/DFGOperations.cpp: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGTierUpCheckInjectionPhase.cpp: + (JSC::DFG::TierUpCheckInjectionPhase::run): + (JSC::DFG::TierUpCheckInjectionPhase::removeFTLProfiling): Deleted. + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * heap/Heap.cpp: + (JSC::Heap::collect): + * jit/BinarySwitch.h: + * jit/ClosureCallStubRoutine.cpp: Removed. + * jit/ClosureCallStubRoutine.h: Removed. + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + (JSC::operationLinkPolymorphicCallFor): + (JSC::operationLinkClosureCallFor): Deleted. + * jit/JITStubRoutine.h: + * jit/JITWriteBarrier.h: + * jit/PolymorphicCallStubRoutine.cpp: Added. + (JSC::PolymorphicCallNode::~PolymorphicCallNode): + (JSC::PolymorphicCallNode::unlink): + (JSC::PolymorphicCallCase::dump): + (JSC::PolymorphicCallStubRoutine::PolymorphicCallStubRoutine): + (JSC::PolymorphicCallStubRoutine::~PolymorphicCallStubRoutine): + (JSC::PolymorphicCallStubRoutine::variants): + (JSC::PolymorphicCallStubRoutine::edges): + (JSC::PolymorphicCallStubRoutine::visitWeak): + (JSC::PolymorphicCallStubRoutine::markRequiredObjectsInternal): + * jit/PolymorphicCallStubRoutine.h: Added. + (JSC::PolymorphicCallNode::PolymorphicCallNode): + (JSC::PolymorphicCallCase::PolymorphicCallCase): + (JSC::PolymorphicCallCase::variant): + (JSC::PolymorphicCallCase::codeBlock): + * jit/Repatch.cpp: + (JSC::linkSlowFor): + (JSC::linkFor): + (JSC::revertCall): + (JSC::unlinkFor): + (JSC::linkVirtualFor): + (JSC::linkPolymorphicCall): + (JSC::linkClosureCall): Deleted. + * jit/Repatch.h: + * jit/ThunkGenerators.cpp: + (JSC::linkPolymorphicCallForThunkGenerator): + (JSC::linkPolymorphicCallThunkGenerator): + (JSC::linkPolymorphicCallThatPreservesRegsThunkGenerator): + (JSC::linkClosureCallForThunkGenerator): Deleted. + (JSC::linkClosureCallThunkGenerator): Deleted. + (JSC::linkClosureCallThatPreservesRegsThunkGenerator): Deleted. + * jit/ThunkGenerators.h: + (JSC::linkPolymorphicCallThunkGeneratorFor): + (JSC::linkClosureCallThunkGeneratorFor): Deleted. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::jitCompileAndSetHeuristics): + * runtime/Options.h: + * runtime/VM.cpp: + (JSC::VM::prepareToDiscardCode): + (JSC::VM::ensureCallEdgeLog): Deleted. + * runtime/VM.h: + +2015-01-29 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ES6: Improved Console Format for Set and Map Objects (like Arrays) + https://bugs.webkit.org/show_bug.cgi?id=122867 + + Reviewed by Timothy Hatcher. + + Add new Runtime.RemoteObject object subtypes for "map", "set", and "weakmap". + + Upgrade Runtime.ObjectPreview to include type/subtype information. Now, + an ObjectPreview can be used for any value, in place of a RemoteObject, + and not capture / hold a reference to the value. The value will be in + the string description. + + Adding this information to ObjectPreview can duplicate some information + in the protocol messages if a preview is provided, but simplifies + previews, so that all the information you need for any RemoteObject + preview is available. To slim messages further, make "overflow" and + "properties" only available on previews that may contain properties. + So, not primitives or null. + + Finally, for "Map/Set/WeakMap" add an "entries" list to the preview + that will return previews with "key" and "value" properties depending + on the collection type. To get live, non-preview objects from a + collection, use Runtime.getCollectionEntries. + + In order to keep the WeakMap's values Weak the frontend may provide + a unique object group name when getting collection entries. It may + then release that object group, e.g. when not showing the WeakMap's + values to the user, and thus remove the strong reference to the keys + so they may be garbage collected. + + * runtime/WeakMapData.h: + (JSC::WeakMapData::begin): + (JSC::WeakMapData::end): + Expose iterators so the Inspector may access WeakMap keys/values. + + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + (Inspector::jsInjectedScriptHostPrototypeFunctionWeakMapEntries): + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + Discern "map", "set", and "weakmap" object subtypes. + + (Inspector::JSInjectedScriptHost::weakMapEntries): + Return a list of WeakMap entries. These are strong references + that the Inspector code is responsible for releasing. + + * inspector/protocol/Runtime.json: + Update types and expose the new getCollectionEntries command. + + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getCollectionEntries): + * inspector/InjectedScript.h: + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getInternalProperties): + (Inspector::InjectedScript::getCollectionEntries): + Pass through to the InjectedScript and call getCollectionEntries. + + * inspector/scripts/codegen/generator.py: + Add another type with runtime casting. + + * inspector/InjectedScriptSource.js: + - Implement getCollectionEntries to get a range of values from a + collection. The non-Weak collections have an order to their keys (in + order of added) so range'd gets are okay. WeakMap does not have an + order, so only allow fetching a number of values. + - Update preview generation to address the Runtime.ObjectPreview + type changes. + +2015-01-28 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Re-landing just the GCArraySegment piece of this patch. + + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::CodeBlockSet): + * heap/CodeBlockSet.h: + * heap/GCSegmentedArray.h: + (JSC::GCArraySegment::GCArraySegment): + * heap/GCSegmentedArrayInlines.h: + (JSC::GCSegmentedArray<T>::GCSegmentedArray): + (JSC::GCSegmentedArray<T>::~GCSegmentedArray): + (JSC::GCSegmentedArray<T>::clear): + (JSC::GCSegmentedArray<T>::expand): + (JSC::GCSegmentedArray<T>::refill): + (JSC::GCArraySegment<T>::create): + (JSC::GCArraySegment<T>::destroy): + * heap/GCThreadSharedData.cpp: + (JSC::GCThreadSharedData::GCThreadSharedData): + * heap/Heap.cpp: + (JSC::Heap::Heap): + * heap/MarkStack.cpp: + (JSC::MarkStackArray::MarkStackArray): + * heap/MarkStack.h: + * heap/SlotVisitor.cpp: + (JSC::SlotVisitor::SlotVisitor): + +2015-01-29 Csaba Osztrogonác <ossy@webkit.org> + + Move HAVE_DTRACE definition back to Platform.h + https://bugs.webkit.org/show_bug.cgi?id=141033 + + Reviewed by Dan Bernstein. + + * Configurations/Base.xcconfig: + * JavaScriptCore.xcodeproj/project.pbxproj: + +2015-01-28 Geoffrey Garen <ggaren@apple.com> + + Removed fastMallocForbid / fastMallocAllow + https://bugs.webkit.org/show_bug.cgi?id=141012 + + Reviewed by Mark Hahnenberg. + + Copy non-current thread stacks before scanning them instead of scanning + them in-place. + + This operation is uncommon (i.e., never in the web content process), + and even in a stress test with 4 threads it only copies about 27kB, + so I think the performance cost is OK. + + Scanning in-place requires a complex dance where we constrain our GC + data structures not to use malloc, free, or any other interesting functions + that might acquire locks. We've gotten this wrong many times in the past, + and I just got it wrong again yesterday. Since this code path is rarely + tested, I want it to just make sense, and not depend on or constrain the + details of the rest of the GC heap's design. + + * heap/MachineStackMarker.cpp: + (JSC::otherThreadStack): Factored out a helper function for dealing with + unaligned and/or backwards pointers. + + (JSC::MachineThreads::tryCopyOtherThreadStack): This is now the only + constrained function, and it only calls memcpy and low-level thread APIs. + + (JSC::MachineThreads::tryCopyOtherThreadStacks): The design here is that + you do one pass over all the threads to compute their combined size, + and then a second pass to do all the copying. In theory, the threads may + grow in between passes, in which case you'll continue until the threads + stop growing. In practice, you never continue. + + (JSC::growBuffer): Helper function for growing. + + (JSC::MachineThreads::gatherConservativeRoots): + (JSC::MachineThreads::gatherFromOtherThread): Deleted. + * heap/MachineStackMarker.h: Updated for interface changes. + +2015-01-28 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: remove CSS.setPropertyText, CSS.toggleProperty and related dead code + https://bugs.webkit.org/show_bug.cgi?id=140961 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/CSS.json: Remove unused protocol methods. + +2015-01-28 Dana Burkart <dburkart@apple.com> + + Move ASan flag settings from DebugRelease.xcconfig to Base.xcconfig + https://bugs.webkit.org/show_bug.cgi?id=136765 + + Reviewed by Alexey Proskuryakov. + + * Configurations/Base.xcconfig: + * Configurations/DebugRelease.xcconfig: + +2015-01-27 Filip Pizlo <fpizlo@apple.com> + + ExitSiteData saying m_takesSlowPath shouldn't mean early returning takesSlowPath() since for the non-LLInt case we later set m_couldTakeSlowPath, which is more precise + https://bugs.webkit.org/show_bug.cgi?id=140980 + + Reviewed by Oliver Hunt. + + * bytecode/CallLinkStatus.cpp: + (JSC::CallLinkStatus::computeFor): + +2015-01-27 Filip Pizlo <fpizlo@apple.com> + + Move DFGBinarySwitch out of the DFG so that all of the JITs can use it + https://bugs.webkit.org/show_bug.cgi?id=140959 + + Rubber stamped by Geoffrey Garen. + + I want to use this for polymorphic stubs for https://bugs.webkit.org/show_bug.cgi?id=140660. + This code no longer has DFG dependencies so this is a very clean move. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGBinarySwitch.cpp: Removed. + * dfg/DFGBinarySwitch.h: Removed. + * dfg/DFGSpeculativeJIT.cpp: + * jit/BinarySwitch.cpp: Copied from Source/JavaScriptCore/dfg/DFGBinarySwitch.cpp. + * jit/BinarySwitch.h: Copied from Source/JavaScriptCore/dfg/DFGBinarySwitch.h. + +2015-01-27 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r179192. + https://bugs.webkit.org/show_bug.cgi?id=140953 + + Caused numerous layout test failures (Requested by mattbaker_ + on #webkit). + + Reverted changeset: + + "Use FastMalloc (bmalloc) instead of BlockAllocator for GC + pages" + https://bugs.webkit.org/show_bug.cgi?id=140900 + http://trac.webkit.org/changeset/179192 + +2015-01-27 Michael Saboff <msaboff@apple.com> + + REGRESSION(r178591): 20% regression in Octane box2d + https://bugs.webkit.org/show_bug.cgi?id=140948 + + Reviewed by Geoffrey Garen. + + Added check that we have a lexical environment to the arguments is captured check. + It doesn't make sense to resolve "arguments" when it really isn't captured. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::willResolveToArgumentsRegister): + +2015-01-26 Geoffrey Garen <ggaren@apple.com> + + Use FastMalloc (bmalloc) instead of BlockAllocator for GC pages + https://bugs.webkit.org/show_bug.cgi?id=140900 + + Reviewed by Mark Hahnenberg. + + Removes some more custom allocation code. + + Looks like a speedup. (See results attached to bugzilla.) + + Will hopefully reduce memory use by improving sharing between the GC and + malloc heaps. + + * API/JSBase.cpp: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: Feed the compiler. + + * heap/BlockAllocator.cpp: Removed. + * heap/BlockAllocator.h: Removed. No need for a custom allocator anymore. + + * heap/CodeBlockSet.cpp: + (JSC::CodeBlockSet::CodeBlockSet): + * heap/CodeBlockSet.h: Feed the compiler. + + * heap/CopiedBlock.h: + (JSC::CopiedBlock::createNoZeroFill): + (JSC::CopiedBlock::create): + (JSC::CopiedBlock::CopiedBlock): + (JSC::CopiedBlock::isOversize): + (JSC::CopiedBlock::payloadEnd): + (JSC::CopiedBlock::capacity): + * heap/CopiedBlockInlines.h: + (JSC::CopiedBlock::reportLiveBytes): Each copied block now tracks its + own size, since we can't rely on Region to tell us our size anymore. + + * heap/CopiedSpace.cpp: + (JSC::CopiedSpace::~CopiedSpace): + (JSC::CopiedSpace::tryAllocateOversize): + (JSC::CopiedSpace::tryReallocateOversize): + * heap/CopiedSpaceInlines.h: + (JSC::CopiedSpace::recycleEvacuatedBlock): + (JSC::CopiedSpace::recycleBorrowedBlock): + (JSC::CopiedSpace::allocateBlockForCopyingPhase): + (JSC::CopiedSpace::allocateBlock): + (JSC::CopiedSpace::startedCopying): Deallocate blocks directly, rather + than pushing them onto the block allocator's free list; the block + allocator doesn't exist anymore. + + * heap/CopyWorkList.h: + (JSC::CopyWorkListSegment::create): + (JSC::CopyWorkListSegment::CopyWorkListSegment): + (JSC::CopyWorkList::~CopyWorkList): + (JSC::CopyWorkList::append): + (JSC::CopyWorkList::CopyWorkList): Deleted. + * heap/GCSegmentedArray.h: + (JSC::GCArraySegment::GCArraySegment): + * heap/GCSegmentedArrayInlines.h: + (JSC::GCSegmentedArray<T>::GCSegmentedArray): + (JSC::GCSegmentedArray<T>::~GCSegmentedArray): + (JSC::GCSegmentedArray<T>::clear): + (JSC::GCSegmentedArray<T>::expand): + (JSC::GCSegmentedArray<T>::refill): + (JSC::GCArraySegment<T>::create): + * heap/GCThreadSharedData.cpp: + (JSC::GCThreadSharedData::GCThreadSharedData): + * heap/GCThreadSharedData.h: Feed the compiler. + + * heap/HandleBlock.h: + * heap/HandleBlockInlines.h: + (JSC::HandleBlock::create): + (JSC::HandleBlock::HandleBlock): + (JSC::HandleBlock::payloadEnd): + * heap/HandleSet.cpp: + (JSC::HandleSet::~HandleSet): + (JSC::HandleSet::grow): Same as above. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + * heap/Heap.h: Removed the block allocator since it is unused now. + + * heap/HeapBlock.h: + (JSC::HeapBlock::destroy): + (JSC::HeapBlock::HeapBlock): + (JSC::HeapBlock::region): Deleted. Removed the Region pointer from each + HeapBlock since a HeapBlock is just a normal allocation now. + + * heap/HeapInlines.h: + (JSC::Heap::blockAllocator): Deleted. + + * heap/HeapTimer.cpp: + * heap/MarkStack.cpp: + (JSC::MarkStackArray::MarkStackArray): + * heap/MarkStack.h: Feed the compiler. + + * heap/MarkedAllocator.cpp: + (JSC::MarkedAllocator::allocateBlock): No need to use a custom code path + based on size, since we use a general purpose allocator now. + + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::create): + (JSC::MarkedBlock::destroy): + (JSC::MarkedBlock::MarkedBlock): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::capacity): Track block size explicitly, like CopiedBlock. + + * heap/MarkedSpace.cpp: + (JSC::MarkedSpace::freeBlock): + * heap/MarkedSpace.h: + + * heap/Region.h: Removed. + + * heap/SlotVisitor.cpp: + (JSC::SlotVisitor::SlotVisitor): Removed reference to block allocator. + + * heap/SuperRegion.cpp: Removed. + * heap/SuperRegion.h: Removed. + + * heap/WeakBlock.cpp: + (JSC::WeakBlock::create): + (JSC::WeakBlock::WeakBlock): + * heap/WeakBlock.h: + * heap/WeakSet.cpp: + (JSC::WeakSet::~WeakSet): + (JSC::WeakSet::addAllocator): + (JSC::WeakSet::removeAllocator): Removed reference to block allocator. + +2015-01-27 Csaba Osztrogonác <ossy@webkit.org> + + [ARM] Typo fix after r176083 + https://bugs.webkit.org/show_bug.cgi?id=140937 + + Reviewed by Anders Carlsson. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::ldrh): + +2015-01-27 Csaba Osztrogonác <ossy@webkit.org> + + [Win] Unreviewed gardening, skip failing tests. + + * tests/exceptionFuzz.yaml: Skip exception fuzz tests due to bug140928. + * tests/mozilla/mozilla-tests.yaml: Skip ecma/Date/15.9.5.28-1.js due to bug140927. + +2015-01-26 Csaba Osztrogonác <ossy@webkit.org> + + [Win] Enable JSC stress tests by default + https://bugs.webkit.org/show_bug.cgi?id=128307 + + Unreviewed typo fix after r179165. + + * tests/mozilla/mozilla-tests.yaml: + +2015-01-26 Csaba Osztrogonác <ossy@webkit.org> + + [Win] Enable JSC stress tests by default + https://bugs.webkit.org/show_bug.cgi?id=128307 + + Reviewed by Brent Fulgham. + + * tests/mozilla/mozilla-tests.yaml: Skipped on Windows. + * tests/stress/ftl-arithcos.js: Skipped on Windows. + +2015-01-26 Ryosuke Niwa <rniwa@webkit.org> + + Parse a function expression as a primary expression + https://bugs.webkit.org/show_bug.cgi?id=140908 + + Reviewed by Mark Lam. + + Moved the code to generate an AST node for a function expression from parseMemberExpression + to parsePrimaryExpression to match the ES6 specification terminology: + https://people.mozilla.org/~jorendorff/es6-draft.html#sec-primary-expression + + There should be no behavior change from this change since parsePrimaryExpression is only + called in parseMemberExpression other than the fact failIfStackOverflow() is called. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parsePrimaryExpression): + (JSC::Parser<LexerType>::parseMemberExpression): + +2015-01-26 Myles C. Maxfield <mmaxfield@apple.com> + + [iOS] [SVG -> OTF Converter] Flip the switch off on iOS + https://bugs.webkit.org/show_bug.cgi?id=140860 + + Reviewed by Darin Adler. + + The fonts it makes are grotesque. (See what I did there? Typographic + humor is the best humor.) + + * Configurations/FeatureDefines.xcconfig: + +2015-01-23 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Rename InjectedScriptHost::type to subtype + https://bugs.webkit.org/show_bug.cgi?id=140841 + + Reviewed by Timothy Hatcher. + + We were using this to set the subtype of an "object" type RemoteObject + so we should clean up the name and call it subtype. + + * inspector/InjectedScriptHost.h: + * inspector/InjectedScriptSource.js: + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::subtype): + (Inspector::JSInjectedScriptHost::type): Deleted. + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + (Inspector::jsInjectedScriptHostPrototypeFunctionSubtype): + (Inspector::jsInjectedScriptHostPrototypeFunctionType): Deleted. + +2015-01-23 Michael Saboff <msaboff@apple.com> + + LayoutTests/js/script-tests/reentrant-caching.js crashing on 32 bit builds + https://bugs.webkit.org/show_bug.cgi?id=140843 + + Reviewed by Oliver Hunt. + + When we are in vmEntryToJavaScript, we keep the stack pointer at an + alignment sutiable for pointing to a call frame header, which is the + alignment post making a call. We adjust the sp when calling to JS code, + but don't adjust it before calling the out of stack handler. + + * llint/LowLevelInterpreter32_64.asm: + Moved stack point down 8 bytes to get it aligned. + +2015-01-23 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Object Previews in the Console + https://bugs.webkit.org/show_bug.cgi?id=129204 + + Reviewed by Timothy Hatcher. + + Update the very old, unused object preview code. Part of this comes from + the earlier WebKit legacy implementation, and the Blink implementation. + + A RemoteObject may include a preview, if it is asked for, and if the + RemoteObject is an object. Previews are a shallow (single level) list + of a limited number of properties on the object. The previewed + properties are always stringified (even if primatives). Previews are + limited to just 5 properties or 100 indices. Previews are marked + as lossless if they are a complete snapshot of the object. + + There is a path to make previews two levels deep, that is currently + unused but should soon be used for tables (e.g. IndexedDB). + + * inspector/InjectedScriptSource.js: + - Move some code off of InjectedScript to be generic functions + usable by RemoteObject as well. + - Update preview generation to use + + * inspector/protocol/Runtime.json: + - Add a new type, "accessor" for preview objects. This represents + a getter / setter. We currently don't get the value. + +2015-01-23 Michael Saboff <msaboff@apple.com> + + Immediate crash when setting JS breakpoint + https://bugs.webkit.org/show_bug.cgi?id=140811 + + Reviewed by Mark Lam. + + When the DFG stack layout phase doesn't allocate a register for the scope register, + it incorrectly sets the scope register in the code block to a bad value, one with + an offset of 0. Changed it so that we set the code block's scope register to the + invalid VirtualRegister instead. + + No tests needed as adding the ASSERT in setScopeRegister() was used to find the bug. + We crash with that ASSERT in testapi and likely many other tests as well. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::setScopeRegister): + (JSC::CodeBlock::scopeRegister): + Added ASSERTs to catch any future improper setting of the code block's scope register. + + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + +2015-01-22 Mark Hahnenberg <mhahnenb@gmail.com> + + EdenCollections unnecessarily visit SmallStrings + https://bugs.webkit.org/show_bug.cgi?id=140762 + + Reviewed by Geoffrey Garen. + + * heap/Heap.cpp: + (JSC::Heap::copyBackingStores): Also added a GCPhase for copying + backing stores, which is a significant portion of garbage collection. + (JSC::Heap::visitSmallStrings): Check to see if we need to visit + SmallStrings based on the collection type. + * runtime/SmallStrings.cpp: + (JSC::SmallStrings::SmallStrings): + (JSC::SmallStrings::visitStrongReferences): Set the fact that we have + visited the SmallStrings since the last modification. + * runtime/SmallStrings.h: + (JSC::SmallStrings::needsToBeVisited): If we're doing a + FullCollection, we need to visit. Otherwise, it depends on whether + we've been visited since the last modification/allocation. + +2015-01-22 Ryosuke Niwa <rniwa@webkit.org> + + Add a build flag for ES6 class syntax + https://bugs.webkit.org/show_bug.cgi?id=140760 + + Reviewed by Michael Saboff. + + Added ES6_CLASS_SYNTAX build flag and used it in tokenizer to recognize + "class", "extends", "static" and "super" keywords. + + * Configurations/FeatureDefines.xcconfig: + * parser/Keywords.table: + * parser/ParserTokens.h: + +2015-01-22 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r178894. + https://bugs.webkit.org/show_bug.cgi?id=140775 + + Broke JSC and bindings tests (Requested by ap_ on #webkit). + + Reverted changeset: + + "put_by_val_direct need to check the property is index or not + for using putDirect / putDirectIndex" + https://bugs.webkit.org/show_bug.cgi?id=140426 + http://trac.webkit.org/changeset/178894 + +2015-01-22 Mark Lam <mark.lam@apple.com> + + BytecodeGenerator::initializeCapturedVariable() sets a misleading value for the 5th operand of op_put_to_scope. + <https://webkit.org/b/140743> + + Reviewed by Oliver Hunt. + + BytecodeGenerator::initializeCapturedVariable() was setting the 5th operand to + op_put_to_scope to an inappropriate value (i.e. 0). As a result, the execution + of put_to_scope could store a wrong inferred value into the VariableWatchpointSet + for which ever captured variable is at local index 0. In practice, this turns + out to be the local for the Arguments object. In this reproduction case in the + bug, the wrong inferred value written there is the boolean true. + + Subsequently, DFG compilation occurs and CreateArguments is emitted to first do + a check of the local for the Arguments object. But because that local has a + wrong inferred value, the check always discovers a non-null value and we never + actually create the Arguments object. Immediately after this, an OSR exit + occurs leaving the Arguments object local uninitialized. Later on at arguments + tear off, we run into a boolean true where we had expected to find an Arguments + object, which in turn, leads to the crash. + + The fix is to: + 1. In the case where the resolveModeType is LocalClosureVar, change the + 5th operand of op_put_to_scope to be a boolean. True means that the + local var is watchable. False means it is not watchable. We no longer + pass the local index (instead of true) and UINT_MAX (instead of false). + + This allows us to express more clearer in the code what that value means, + as well as remove the redundant way of getting the local's identifier. + The identifier is always the one passed in the 2nd operand. + + 2. Previously, though intuitively, we know that the watchable variable + identifier should be the same as the one that is passed in operand 2, this + relationship was not clear in the code. By code analysis, I confirmed that + the callers of BytecodeGenerator::emitPutToScope() always use the same + identifier for operand 2 and for filling out the ResolveScopeInfo from + which we get the watchable variable identifier later. I've changed the + code to make this clear now by always using the identifier passed in + operand 2. + + 3. In the case where the resolveModeType is LocalClosureVar, + initializeCapturedVariable() and emitPutToScope() will now query + hasWatchableVariable() to determine if the local is watchable or not. + Accordingly, we pass the boolean result of hasWatchableVariable() as + operand 5 of op_put_to_scope. + + Also added some assertions. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::initializeCapturedVariable): + (JSC::BytecodeGenerator::hasConstant): + (JSC::BytecodeGenerator::emitPutToScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::hasWatchableVariable): + (JSC::BytecodeGenerator::watchableVariableIdentifier): + (JSC::BytecodeGenerator::watchableVariable): Deleted. + +2015-01-22 Ryosuke Niwa <rniwa@webkit.org> + + PropertyListNode::emitNode duplicates the code to put a constant property + https://bugs.webkit.org/show_bug.cgi?id=140761 + + Reviewed by Geoffrey Garen. + + Extracted PropertyListNode::emitPutConstantProperty to share the code. + + Also made PropertyListNode::emitBytecode private since nobody is calling this function directly. + + * bytecompiler/NodesCodegen.cpp: + (JSC::PropertyListNode::emitBytecode): + (JSC::PropertyListNode::emitPutConstantProperty): Added. + * parser/Nodes.h: + +2015-01-22 Yusuke Suzuki <utatane.tea@gmail.com> + + put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex + https://bugs.webkit.org/show_bug.cgi?id=140426 + + Reviewed by Geoffrey Garen. + + In the put_by_val_direct operation, we use JSObject::putDirect. + However, it only accepts non-index property. For index property, we need to use JSObject::putDirectIndex. + This patch changes Identifier::asIndex() to return Optional<uint32_t>. + It forces callers to check the value is index or not explicitly. + Additionally, it checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitDirectPutById): + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * jit/JITOperations.cpp: + * jit/Repatch.cpp: + (JSC::emitPutTransitionStubAndGetOldStructure): + * jsc.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::getOwnPropertySlot): + (JSC::Arguments::put): + (JSC::Arguments::deleteProperty): + (JSC::Arguments::defineOwnProperty): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSort): + * runtime/JSArray.cpp: + (JSC::JSArray::defineOwnProperty): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitive): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot): + (JSC::JSGenericTypedArrayView<Adaptor>::put): + (JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty): + (JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty): + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::putDirectAccessor): + (JSC::JSObject::putDirectCustomAccessor): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::putDirectMayBeIndex): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + (JSC::JSObject::getOwnPropertySlot): + (JSC::JSObject::getPropertySlot): + (JSC::JSObject::putDirectInternal): + * runtime/JSString.cpp: + (JSC::JSString::getStringPropertyDescriptor): + * runtime/JSString.h: + (JSC::JSString::getStringPropertySlot): + * runtime/LiteralParser.cpp: + (JSC::LiteralParser<CharType>::parse): + * runtime/PropertyName.h: + (JSC::toUInt32FromCharacters): + (JSC::toUInt32FromStringImpl): + (JSC::PropertyName::asIndex): + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + * runtime/StringObject.cpp: + (JSC::StringObject::deleteProperty): + * runtime/Structure.cpp: + (JSC::Structure::prototypeChainMayInterceptStoreTo): + +2015-01-21 Ryosuke Niwa <rniwa@webkit.org> + + Consolidate out arguments of parseFunctionInfo into a struct + https://bugs.webkit.org/show_bug.cgi?id=140754 + + Reviewed by Oliver Hunt. + + Introduced ParserFunctionInfo for storing out arguments of parseFunctionInfo. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createFunctionExpr): + (JSC::ASTBuilder::createGetterOrSetterProperty): This one takes a property name in addition to + ParserFunctionInfo since the property name and the function name could differ. + (JSC::ASTBuilder::createFuncDeclStatement): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseProperty): + (JSC::Parser<LexerType>::parseMemberExpression): + * parser/Parser.h: + * parser/ParserFunctionInfo.h: Added. + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createFunctionExpr): + (JSC::SyntaxChecker::createFuncDeclStatement): + (JSC::SyntaxChecker::createClassDeclStatement): + (JSC::SyntaxChecker::createGetterOrSetterProperty): + +2015-01-21 Mark Hahnenberg <mhahnenb@gmail.com> + + Change Heap::m_compiledCode to use a Vector + https://bugs.webkit.org/show_bug.cgi?id=140717 + + Reviewed by Andreas Kling. + + Right now it's a DoublyLinkedList, which is iterated during each + collection. This contributes to some of the longish Eden pause times. + A Vector would be more appropriate and would also allow ExecutableBase + to be 2 pointers smaller. + + * heap/Heap.cpp: + (JSC::Heap::deleteAllCompiledCode): + (JSC::Heap::deleteAllUnlinkedFunctionCode): + (JSC::Heap::clearUnmarkedExecutables): + * heap/Heap.h: + * runtime/Executable.h: No longer need to inherit from DoublyLinkedListNode. + +2015-01-21 Ryosuke Niwa <rniwa@webkit.org> + + BytecodeGenerator shouldn't expose all of its member variables + https://bugs.webkit.org/show_bug.cgi?id=140752 + + Reviewed by Mark Lam. + + Added "private:" and removed unused data members as detected by clang. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::lastOpcodeID): Added. Used in BinaryOpNode::emitBytecode. + * bytecompiler/NodesCodegen.cpp: + (JSC::BinaryOpNode::emitBytecode): + +2015-01-21 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ASSERT expanding objects in console PrimitiveBindingTraits<T>::assertValueHasExpectedType + https://bugs.webkit.org/show_bug.cgi?id=140746 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScriptSource.js: + Do not add impure properties to the descriptor object that will + eventually be sent to the frontend. + +2015-01-21 Matthew Mirman <mmirman@apple.com> + + Updated split such that it does not include the empty end of input string match. + https://bugs.webkit.org/show_bug.cgi?id=138129 + <rdar://problem/18807403> + + Reviewed by Filip Pizlo. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncSplit): + * tests/stress/empty_eos_regex_split.js: Added. + +2015-01-21 Michael Saboff <msaboff@apple.com> + + Eliminate Scope slot from JavaScript CallFrame + https://bugs.webkit.org/show_bug.cgi?id=136724 + + Reviewed by Geoffrey Garen. + + This finishes the removal of the scope chain slot from the call frame header. + + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::reifyInlinedCallFrames): + * dfg/DFGPreciseLocalClobberize.h: + (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::emitCall): + * ftl/FTLJSCall.cpp: + (JSC::FTL::JSCall::emit): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct): + (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct): + * interpreter/JSStack.h: + * interpreter/VMInspector.cpp: + (JSC::VMInspector::dumpFrame): + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITCall32_64.cpp: + (JSC::JIT::compileOpCall): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::privateCompileCTINativeCall): + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::linkClosureCall): + * jit/ThunkGenerators.cpp: + (JSC::virtualForThunkGenerator): + (JSC::nativeForGenerator): + Deleted ScopeChain slot from JSStack. Removed all code where ScopeChain was being + read or set. In most cases this was where we make JS calls. + + * interpreter/CallFrameClosure.h: + (JSC::CallFrameClosure::setArgument): + (JSC::CallFrameClosure::resetCallFrame): Deleted. + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + (JSC::Interpreter::prepareForRepeatCall): + * interpreter/ProtoCallFrame.cpp: + (JSC::ProtoCallFrame::init): + * interpreter/ProtoCallFrame.h: + (JSC::ProtoCallFrame::scope): Deleted. + (JSC::ProtoCallFrame::setScope): Deleted. + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter64.asm: + Removed the related scopeChainValue member from ProtoCallFrame. Reduced the number of + registers that needed to be copied from the ProtoCallFrame to a callee's frame + from 5 to 4. + + * llint/LowLevelInterpreter32_64.asm: + In addition to the prior changes, also deleted the unused macro getDeBruijnScope. + +2015-01-21 Michael Saboff <msaboff@apple.com> + + Eliminate construct methods from NullGetterFunction and NullSetterFunction classes + https://bugs.webkit.org/show_bug.cgi?id=140708 + + Reviewed by Mark Lam. + + Eliminated construct methods and change getConstructData() for both classes to return + ConstructTypeNone as they can never be called. + + * runtime/NullGetterFunction.cpp: + (JSC::NullGetterFunction::getConstructData): + (JSC::constructReturnUndefined): Deleted. + * runtime/NullSetterFunction.cpp: + (JSC::NullSetterFunction::getConstructData): + (JSC::constructReturnUndefined): Deleted. + +2015-01-21 Csaba Osztrogonác <ossy@webkit.org> + + Remove ENABLE(INSPECTOR) ifdef guards + https://bugs.webkit.org/show_bug.cgi?id=140668 + + Reviewed by Darin Adler. + + * Configurations/FeatureDefines.xcconfig: + * bindings/ScriptValue.cpp: + (Deprecated::ScriptValue::toInspectorValue): + * bindings/ScriptValue.h: + * inspector/ConsoleMessage.cpp: + * inspector/ConsoleMessage.h: + * inspector/ContentSearchUtilities.cpp: + * inspector/ContentSearchUtilities.h: + * inspector/IdentifiersFactory.cpp: + * inspector/IdentifiersFactory.h: + * inspector/InjectedScript.cpp: + * inspector/InjectedScript.h: + * inspector/InjectedScriptBase.cpp: + * inspector/InjectedScriptBase.h: + * inspector/InjectedScriptHost.cpp: + * inspector/InjectedScriptHost.h: + * inspector/InjectedScriptManager.cpp: + * inspector/InjectedScriptManager.h: + * inspector/InjectedScriptModule.cpp: + * inspector/InjectedScriptModule.h: + * inspector/InspectorAgentRegistry.cpp: + * inspector/InspectorBackendDispatcher.cpp: + * inspector/InspectorBackendDispatcher.h: + * inspector/InspectorProtocolTypes.h: + * inspector/JSGlobalObjectConsoleClient.cpp: + * inspector/JSGlobalObjectInspectorController.cpp: + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectScriptDebugServer.cpp: + * inspector/JSGlobalObjectScriptDebugServer.h: + * inspector/JSInjectedScriptHost.cpp: + * inspector/JSInjectedScriptHost.h: + * inspector/JSInjectedScriptHostPrototype.cpp: + * inspector/JSInjectedScriptHostPrototype.h: + * inspector/JSJavaScriptCallFrame.cpp: + * inspector/JSJavaScriptCallFrame.h: + * inspector/JSJavaScriptCallFramePrototype.cpp: + * inspector/JSJavaScriptCallFramePrototype.h: + * inspector/JavaScriptCallFrame.cpp: + * inspector/JavaScriptCallFrame.h: + * inspector/ScriptCallFrame.cpp: + (Inspector::ScriptCallFrame::buildInspectorObject): + * inspector/ScriptCallFrame.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::buildInspectorArray): + * inspector/ScriptCallStack.h: + * inspector/ScriptDebugServer.cpp: + * inspector/agents/InspectorAgent.cpp: + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorConsoleAgent.cpp: + * inspector/agents/InspectorConsoleAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/agents/JSGlobalObjectConsoleAgent.cpp: + * inspector/agents/JSGlobalObjectConsoleAgent.h: + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + * inspector/agents/JSGlobalObjectDebuggerAgent.h: + * inspector/agents/JSGlobalObjectRuntimeAgent.cpp: + * inspector/agents/JSGlobalObjectRuntimeAgent.h: + * inspector/scripts/codegen/cpp_generator_templates.py: + (CppGeneratorTemplates): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * runtime/TypeSet.cpp: + (JSC::TypeSet::inspectorTypeSet): + (JSC::StructureShape::inspectorRepresentation): + +2015-01-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Clean up InjectedScriptSource.js + https://bugs.webkit.org/show_bug.cgi?id=140709 + + Reviewed by Timothy Hatcher. + + This patch includes some relevant Blink patches and small changes. + + Patch by <aandrey@chromium.org> + DevTools: Remove console last result $_ on console clear. + https://src.chromium.org/viewvc/blink?revision=179179&view=revision + + Patch by <eustas@chromium.org> + [Inspect DOM properties] incorrect CSS Selector Syntax + https://src.chromium.org/viewvc/blink?revision=156903&view=revision + + * inspector/InjectedScriptSource.js: + +2015-01-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Cleanup RuntimeAgent a bit + https://bugs.webkit.org/show_bug.cgi?id=140706 + + Reviewed by Timothy Hatcher. + + * inspector/InjectedScript.h: + * inspector/InspectorBackendDispatcher.h: + * inspector/ScriptCallFrame.cpp: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::evaluate): + (Inspector::InspectorRuntimeAgent::getProperties): + (Inspector::InspectorRuntimeAgent::run): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::recompileAllJSFunctionsForTypeProfiling): + (Inspector::InspectorRuntimeAgent::setTypeProfilerEnabledState): + +2015-01-20 Matthew Mirman <mmirman@apple.com> + + Made Identity in the DFG allocate a new temp register and move + the old data to it. + https://bugs.webkit.org/show_bug.cgi?id=140700 + <rdar://problem/19339106> + + Reviewed by Filip Pizlo. + + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + Added scratch registers for Identity. + * tests/mozilla/mozilla-tests.yaml: enabled previously failing test + +2015-01-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Expanding event objects in console shows undefined for most values, it should have real values + https://bugs.webkit.org/show_bug.cgi?id=137306 + + Reviewed by Timothy Hatcher. + + Provide another optional parameter to getProperties, to gather a list + of all own and getter properties. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getProperties): + * inspector/InjectedScript.h: + * inspector/InjectedScriptSource.js: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getProperties): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + +2015-01-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Should show dynamic specificity values + https://bugs.webkit.org/show_bug.cgi?id=140647 + + Reviewed by Benjamin Poulain. + + * inspector/protocol/CSS.json: + Clarify CSSSelector optional values and add "dynamic" property indicating + if the selector can be dynamic based on the element it is matched against. + +2015-01-20 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r178751. + https://bugs.webkit.org/show_bug.cgi?id=140694 + + Caused 32-bit JSC test failures (Requested by JoePeck on + #webkit). + + Reverted changeset: + + "put_by_val_direct need to check the property is index or not + for using putDirect / putDirectIndex" + https://bugs.webkit.org/show_bug.cgi?id=140426 + http://trac.webkit.org/changeset/178751 + +2015-01-20 Yusuke Suzuki <utatane.tea@gmail.com> + + put_by_val_direct need to check the property is index or not for using putDirect / putDirectIndex + https://bugs.webkit.org/show_bug.cgi?id=140426 + + Reviewed by Geoffrey Garen. + + In the put_by_val_direct operation, we use JSObject::putDirect. + However, it only accepts non-index property. For index property, we need to use JSObject::putDirectIndex. + This patch changes Identifier::asIndex() to return Optional<uint32_t>. + It forces callers to check the value is index or not explicitly. + Additionally, it checks toString-ed Identifier is index or not to choose putDirect / putDirectIndex. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFor): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFor): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitDirectPutById): + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * jit/JITOperations.cpp: + * jit/Repatch.cpp: + (JSC::emitPutTransitionStubAndGetOldStructure): + * jsc.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.cpp: + (JSC::Arguments::getOwnPropertySlot): + (JSC::Arguments::put): + (JSC::Arguments::deleteProperty): + (JSC::Arguments::defineOwnProperty): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncSort): + * runtime/JSArray.cpp: + (JSC::JSArray::defineOwnProperty): + * runtime/JSCJSValue.cpp: + (JSC::JSValue::putToPrimitive): + * runtime/JSGenericTypedArrayViewInlines.h: + (JSC::JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot): + (JSC::JSGenericTypedArrayView<Adaptor>::put): + (JSC::JSGenericTypedArrayView<Adaptor>::defineOwnProperty): + (JSC::JSGenericTypedArrayView<Adaptor>::deleteProperty): + * runtime/JSObject.cpp: + (JSC::JSObject::put): + (JSC::JSObject::putDirectAccessor): + (JSC::JSObject::putDirectCustomAccessor): + (JSC::JSObject::deleteProperty): + (JSC::JSObject::putDirectMayBeIndex): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + (JSC::JSObject::getOwnPropertySlot): + (JSC::JSObject::getPropertySlot): + (JSC::JSObject::putDirectInternal): + * runtime/JSString.cpp: + (JSC::JSString::getStringPropertyDescriptor): + * runtime/JSString.h: + (JSC::JSString::getStringPropertySlot): + * runtime/LiteralParser.cpp: + (JSC::LiteralParser<CharType>::parse): + * runtime/PropertyName.h: + (JSC::toUInt32FromCharacters): + (JSC::toUInt32FromStringImpl): + (JSC::PropertyName::asIndex): + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + * runtime/StringObject.cpp: + (JSC::StringObject::deleteProperty): + * runtime/Structure.cpp: + (JSC::Structure::prototypeChainMayInterceptStoreTo): + +2015-01-20 Michael Saboff <msaboff@apple.com> + + REGRESSION(178696): Sporadic crashes while garbage collecting + https://bugs.webkit.org/show_bug.cgi?id=140688 + + Reviewed by Geoffrey Garen. + + Added missing visitor.append(&thisObject->m_nullSetterFunction). + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::visitChildren): + +2015-01-19 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: code generator should take supplemental specifications and allow cross-framework references + https://bugs.webkit.org/show_bug.cgi?id=136312 + + Reviewed by Joseph Pecoraro. + + Some types are shared between replay inputs from different frameworks. + Previously, these type declarations were duplicated in every input + specification file in which they were used. This caused some type encoding + traits to be emitted twice if used from WebCore inputs and WebKit2 inputs. + + This patch teaches the replay inputs code generator to accept multiple + input specification files. Inputs can freely reference types from other + frameworks without duplicating declarations. + + On the code generation side, the model could contain types and inputs from + frameworks that are not the target framework. Only generate code for the + target framework. + + To properly generate cross-framework type encoding traits, use + Type.encoding_type_argument in more places, and add the export macro for WebCore + and the Test framework. + + Adjust some tests so that enum coverage is preserved by moving the enum types + into "Test" (the target framework for tests). + + * JavaScriptCore.vcxproj/copy-files.cmd: + For Windows, copy over JSInputs.json as if it were a private header. + + * JavaScriptCore.xcodeproj/project.pbxproj: Make JSInputs.json a private header. + * replay/JSInputs.json: + Put all primitive types and WTF types in this specification file. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (Input.__init__): + (InputsModel.__init__): Keep track of the input's framework. + (InputsModel.parse_specification): Parse the framework here. Adjust to new format, + and allow either types or inputs to be missing from a single file. + + (InputsModel.parse_type_with_framework): + (InputsModel.parse_input_with_framework): + (Generator.should_generate_item): Added helper method. + (Generator.generate_header): Filter inputs to generate. + (Generator.generate_implementation): Filter inputs to generate. + (Generator.generate_enum_trait_declaration): Filter enums to generate. + Add WEBCORE_EXPORT macro to enum encoding traits. + + (Generator.generate_for_each_macro): Filter inputs to generate. + (Generator.generate_enum_trait_implementation): Filter enums to generate. + (generate_from_specifications): Added. + (generate_from_specifications.parse_json_from_file): + (InputsModel.parse_toplevel): Deleted. + (InputsModel.parse_type_with_framework_name): Deleted. + (InputsModel.parse_input): Deleted. + (generate_from_specification): Deleted. + * replay/scripts/CodeGeneratorReplayInputsTemplates.py: + * replay/scripts/tests/expected/fail-on-no-inputs.json-error: Removed. + * replay/scripts/tests/expected/fail-on-no-types.json-error: Removed. + * replay/scripts/tests/expected/generate-enum-encoding-helpers-with-guarded-values.json-TestReplayInputs.cpp: + * replay/scripts/tests/expected/generate-enum-encoding-helpers-with-guarded-values.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.cpp: + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.cpp: + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.cpp: + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-input-with-guard.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-inputs-with-flags.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-memoized-type-modes.json-TestReplayInputs.h: + * replay/scripts/tests/fail-on-c-style-enum-no-storage.json: + * replay/scripts/tests/fail-on-duplicate-enum-type.json: + * replay/scripts/tests/fail-on-duplicate-input-names.json: + * replay/scripts/tests/fail-on-duplicate-type-names.json: + * replay/scripts/tests/fail-on-enum-type-missing-values.json: + * replay/scripts/tests/fail-on-missing-input-member-name.json: + * replay/scripts/tests/fail-on-missing-input-name.json: + * replay/scripts/tests/fail-on-missing-input-queue.json: + * replay/scripts/tests/fail-on-missing-type-mode.json: + * replay/scripts/tests/fail-on-missing-type-name.json: + * replay/scripts/tests/fail-on-no-inputs.json: + Removed, no longer required to be in a single file. + + * replay/scripts/tests/fail-on-no-types.json: + Removed, no longer required to be in a single file. + + * replay/scripts/tests/fail-on-unknown-input-queue.json: + * replay/scripts/tests/fail-on-unknown-member-type.json: + * replay/scripts/tests/fail-on-unknown-type-mode.json: + * replay/scripts/tests/generate-enum-encoding-helpers-with-guarded-values.json: + * replay/scripts/tests/generate-enum-encoding-helpers.json: + * replay/scripts/tests/generate-enum-with-guard.json: + Include enums that are and are not generated. + + * replay/scripts/tests/generate-enums-with-same-base-name.json: + * replay/scripts/tests/generate-event-loop-shape-types.json: + * replay/scripts/tests/generate-input-with-guard.json: + * replay/scripts/tests/generate-input-with-vector-members.json: + * replay/scripts/tests/generate-inputs-with-flags.json: + * replay/scripts/tests/generate-memoized-type-modes.json: + +2015-01-20 Tomas Popela <tpopela@redhat.com> + + [GTK] Cannot compile 2.7.3 on PowerPC machines + https://bugs.webkit.org/show_bug.cgi?id=140616 + + Include climits for INT_MAX and wtf/DataLog.h for dataLogF + + Reviewed by Csaba Osztrogonác. + + * runtime/BasicBlockLocation.cpp: + +2015-01-19 Michael Saboff <msaboff@apple.com> + + A "cached" null setter should throw a TypeException when called in strict mode and doesn't + https://bugs.webkit.org/show_bug.cgi?id=139418 + + Reviewed by Filip Pizlo. + + Made a new NullSetterFunction class similar to NullGetterFunction. The difference is that + NullSetterFunction will throw a TypeError per the ECMA262 spec for a strict mode caller. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + Added new files NullSetterFunction.cpp and NullSetterFunction.h. + + * runtime/GetterSetter.h: + (JSC::GetterSetter::GetterSetter): + (JSC::GetterSetter::isSetterNull): + (JSC::GetterSetter::setSetter): + Change setter instances from using NullGetterFunction to using NullSetterFunction. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::nullSetterFunction): + Added m_nullSetterFunction and accessor. + + * runtime/NullSetterFunction.cpp: Added. + (JSC::GetCallerStrictnessFunctor::GetCallerStrictnessFunctor): + (JSC::GetCallerStrictnessFunctor::operator()): + (JSC::GetCallerStrictnessFunctor::callerIsStrict): + (JSC::callerIsStrict): + Method to determine if the caller is in strict mode. + + (JSC::callReturnUndefined): + (JSC::constructReturnUndefined): + (JSC::NullSetterFunction::getCallData): + (JSC::NullSetterFunction::getConstructData): + * runtime/NullSetterFunction.h: Added. + (JSC::NullSetterFunction::create): + (JSC::NullSetterFunction::createStructure): + (JSC::NullSetterFunction::NullSetterFunction): + Class with handlers for a null setter. + +2015-01-19 Saam Barati <saambarati1@gmail.com> + + Web Inspector: Provide a front end for JSC's Control Flow Profiler + https://bugs.webkit.org/show_bug.cgi?id=138454 + + Reviewed by Timothy Hatcher. + + This patch puts the final touches on what JSC needs to provide + for the Web Inspector to show a UI for the control flow profiler. + + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::recompileAllJSFunctionsForTypeProfiling): + * runtime/ControlFlowProfiler.cpp: + (JSC::ControlFlowProfiler::getBasicBlocksForSourceID): + * runtime/FunctionHasExecutedCache.cpp: + (JSC::FunctionHasExecutedCache::getFunctionRanges): + (JSC::FunctionHasExecutedCache::getUnexecutedFunctionRanges): Deleted. + * runtime/FunctionHasExecutedCache.h: + +2015-01-19 David Kilzer <ddkilzer@apple.com> + + [iOS] Only use LLVM static library arguments on 64-bit builds of libllvmForJSC.dylib + <http://webkit.org/b/140658> + + Reviewed by Filip Pizlo. + + * Configurations/LLVMForJSC.xcconfig: Set OTHER_LDFLAGS_LLVM + only when building for 64-bit architectures. + +2015-01-19 Filip Pizlo <fpizlo@apple.com> + + ClosureCallStubRoutine no longer needs codeOrigin + https://bugs.webkit.org/show_bug.cgi?id=140659 + + Reviewed by Michael Saboff. + + Once upon a time, we would look for the CodeOrigin associated with a return PC. This search + would start with the CodeBlock according to the caller frame's call frame header. But if the + call was a closure call, the return PC would be inside some closure call stub. So if the + CodeBlock search failed, we would search *all* closure call stub routines to see which one + encompasses the return PC. Then, we would use the CodeOrigin stored in the stub routine + object. This was all a bunch of madness, and we actually got rid of it - we now determine + the CodeOrigin for a call frame using the encoded code origin bits inside the tag of the + argument count. + + This patch removes the final vestiges of the madness: + + - Remove the totally unused method declaration for the thing that did the closure call stub + search. + + - Remove the CodeOrigin field from the ClosureCallStubRoutine. Except for that crazy search + that we no longer do, everyone else who finds a ClosureCallStubRoutine will find it via + the CallLinkInfo. The CallLinkInfo also has the CodeOrigin, so we don't need this field + anymore. + + * bytecode/CodeBlock.h: + * jit/ClosureCallStubRoutine.cpp: + (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine): + * jit/ClosureCallStubRoutine.h: + (JSC::ClosureCallStubRoutine::executable): + (JSC::ClosureCallStubRoutine::codeOrigin): Deleted. + * jit/Repatch.cpp: + (JSC::linkClosureCall): + +2015-01-19 Saam Barati <saambarati1@gmail.com> + + Basic block start offsets should never be larger than end offsets in the control flow profiler + https://bugs.webkit.org/show_bug.cgi?id=140377 + + Reviewed by Filip Pizlo. + + The bytecode generator will emit code more than once for some AST nodes. For instance, + the finally block of TryNode will emit two code paths for its finally block: one for + the normal path, and another for the path where an exception is thrown in the catch block. + + This repeated code emission of the same AST node previously broke how the control + flow profiler computed text ranges of basic blocks because when the same AST node + is emitted multiple times, there is a good chance that there are ranges that span + from the end offset of one of these duplicated nodes back to the start offset of + the same duplicated node. This caused a basic block range to report a larger start + offset than end offset. This was incorrect. Now, when this situation is encountered + while linking a CodeBlock, the faulty range in question is ignored. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler): + * bytecode/CodeBlock.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ForInNode::emitMultiLoopBytecode): + (JSC::ForOfNode::emitBytecode): + (JSC::TryNode::emitBytecode): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseConditionalExpression): + * runtime/ControlFlowProfiler.cpp: + (JSC::ControlFlowProfiler::ControlFlowProfiler): + * runtime/ControlFlowProfiler.h: + (JSC::ControlFlowProfiler::dummyBasicBlock): + +2015-01-19 Myles C. Maxfield <mmaxfield@apple.com> + + [SVG -> OTF Converter] Flip the switch on + https://bugs.webkit.org/show_bug.cgi?id=140592 + + Reviewed by Antti Koivisto. + + * Configurations/FeatureDefines.xcconfig: + +2015-01-19 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: convert to is<T> and downcast<T> for decoding replay inputs + https://bugs.webkit.org/show_bug.cgi?id=140512 + + Reviewed by Chris Dumez. + + Generate a SPECIALIZE_TYPE_TRAITS_* chunk of code for each input. This cannot + be done using REPLAY_INPUT_NAMES_FOR_EACH macro since that doesn't fully qualify + input types, and the type traits macro is defined in namespace WTF. + + * replay/NondeterministicInput.h: Make overridden methods public. + * replay/scripts/CodeGeneratorReplayInputs.py: + (Generator.generate_header): + (Generator.qualified_input_name): Allow forcing qualification. WTF is never a target framework. + (Generator.generate_input_type_trait_declaration): Added. + * replay/scripts/CodeGeneratorReplayInputsTemplates.py: Add a template. + * replay/scripts/tests/expected/generate-enum-encoding-helpers-with-guarded-values.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enum-with-guard.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-input-with-guard.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-input-with-vector-members.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-inputs-with-flags.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-memoized-type-modes.json-TestReplayInputs.h: + +2015-01-19 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r178653. + https://bugs.webkit.org/show_bug.cgi?id=140634 + + Broke multiple SVG tests on Mountain Lion (Requested by ap on + #webkit). + + Reverted changeset: + + "[SVG -> OTF Converter] Flip the switch on" + https://bugs.webkit.org/show_bug.cgi?id=140592 + http://trac.webkit.org/changeset/178653 + +2015-01-18 Dean Jackson <dino@apple.com> + + ES6: Support Array.of construction + https://bugs.webkit.org/show_bug.cgi?id=140605 + <rdar://problem/19513655> + + Reviewed by Geoffrey Garen. + + Add and implementation of Array.of, described in 22.1.2.3 of the ES6 + specification (15 Jan 2015). The Array.of() method creates a new Array + instance with a variable number of arguments, regardless of number or type + of the arguments. + + * runtime/ArrayConstructor.cpp: + (JSC::arrayConstructorOf): Create a new empty Array, then iterate + over the arguments, setting them to the appropriate index. + +2015-01-19 Myles C. Maxfield <mmaxfield@apple.com> + + [SVG -> OTF Converter] Flip the switch on + https://bugs.webkit.org/show_bug.cgi?id=140592 + + Reviewed by Antti Koivisto. + + * Configurations/FeatureDefines.xcconfig: + +2015-01-17 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: highlight data for overlay should use protocol type builders + https://bugs.webkit.org/show_bug.cgi?id=129441 + + Reviewed by Timothy Hatcher. + + Add a new domain for overlay types. + + * CMakeLists.txt: + * DerivedSources.make: + * inspector/protocol/OverlayTypes.json: Added. + +2015-01-17 Michael Saboff <msaboff@apple.com> + + Crash in JSScope::resolve() on tools.ups.com + https://bugs.webkit.org/show_bug.cgi?id=140579 + + Reviewed by Geoffrey Garen. + + For op_resolve_scope of a global property or variable that needs to check for the var + injection check watchpoint, we need to keep the scope around with a Phantom. The + baseline JIT slowpath for op_resolve_scope needs the scope value if the watchpoint + fired. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + +2015-01-16 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: code generator should introduce typedefs for protocol types that are arrays + https://bugs.webkit.org/show_bug.cgi?id=140557 + + Reviewed by Joseph Pecoraro. + + Currently, there is no generated type name for "array" type declarations such as Console.CallStack. + This makes it longwinded and confusing to use the type in C++ code. + + This patch adds a typedef for array type declarations, so types such as Console::CallStack + can be referred to directly, rather than using Inspector::Protocol::Array<Console::CallFrame>. + + Some tests were updated to cover array type declarations used as parameters and type members. + + * inspector/ScriptCallStack.cpp: Use the new typedef. + (Inspector::ScriptCallStack::buildInspectorArray): + * inspector/ScriptCallStack.h: + * inspector/scripts/codegen/cpp_generator.py: + (CppGenerator.cpp_protocol_type_for_type): If an ArrayType is nominal, use the typedef'd name instead. + * inspector/scripts/codegen/generate_cpp_protocol_types_header.py: + (_generate_typedefs_for_domain): Also generate typedefs for array type declarations. + (_generate_typedefs_for_domain.Inspector): + * inspector/scripts/codegen/models.py: Save the name of an ArrayType when it is a type declaration. + (ArrayType.__init__): + (Protocol.resolve_types): + (Protocol.lookup_type_reference): + * inspector/scripts/tests/commands-with-async-attribute.json: + * inspector/scripts/tests/commands-with-optional-call-return-parameters.json: + * inspector/scripts/tests/events-with-optional-parameters.json: + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * inspector/scripts/tests/type-declaration-object-type.json: + +2015-01-16 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: purge remaining PassRefPtr uses and minor cleanup + https://bugs.webkit.org/show_bug.cgi?id=140456 + + Reviewed by Andreas Kling. + + Get rid of PassRefPtr. Introduce default initializers where it makes sense. + Remove mistaken uses of AtomicString that were not removed as part of r174113. + + * replay/EmptyInputCursor.h: + * replay/InputCursor.h: + (JSC::InputCursor::InputCursor): + +2015-01-16 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: code generator should fail on duplicate parameter and member names + https://bugs.webkit.org/show_bug.cgi?id=140555 + + Reviewed by Timothy Hatcher. + + * inspector/scripts/codegen/models.py: + (find_duplicates): Add a helper function to find duplicates in a list. + (Protocol.parse_type_declaration): + (Protocol.parse_command): + (Protocol.parse_event): + * inspector/scripts/tests/expected/fail-on-duplicate-command-call-parameter-names.json-error: Added. + * inspector/scripts/tests/expected/fail-on-duplicate-command-return-parameter-names.json-error: Added. + * inspector/scripts/tests/expected/fail-on-duplicate-event-parameter-names.json-error: Added. + * inspector/scripts/tests/expected/fail-on-duplicate-type-member-names.json-error: Added. + * inspector/scripts/tests/fail-on-duplicate-command-call-parameter-names.json: Added. + * inspector/scripts/tests/fail-on-duplicate-command-return-parameter-names.json: Added. + * inspector/scripts/tests/fail-on-duplicate-event-parameter-names.json: Added. + * inspector/scripts/tests/fail-on-duplicate-type-member-names.json: Added. + +2015-01-16 Michael Saboff <msaboff@apple.com> + + REGRESSION (r174226): Header on huffingtonpost.com is too large + https://bugs.webkit.org/show_bug.cgi?id=140306 + + Reviewed by Filip Pizlo. + + BytecodeGenerator::willResolveToArguments() is used to check to see if we can use the + arguments register or whether we need to resolve "arguments". If the arguments have + been captured, then they are stored in the lexical environment and the arguments + register is not used. + + Changed BytecodeGenerator::willResolveToArguments() to also check to see if the arguments + register is captured. Renamed the function to willResolveToArgumentsRegister() to + better indicate what we are checking. + + Aligned 32 and 64 bit paths in ArgumentsRecoveryGenerator::generateFor() for creating + an arguments object that was optimized out of an inlined callFrame. The 32 bit path + incorrectly calculated the location of the reified callee frame. This alignment resulted + in the removal of operationCreateInlinedArgumentsDuringOSRExit() + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::willResolveToArgumentsRegister): + (JSC::BytecodeGenerator::uncheckedLocalArgumentsRegister): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitConstruct): + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::willResolveToArguments): Deleted. + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::getArgumentByVal): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::ArrayPatternNode::emitDirectBinding): + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::ArgumentsRecoveryGenerator::generateFor): + * dfg/DFGOperations.cpp: + (JSC::operationCreateInlinedArgumentsDuringOSRExit): Deleted. + * dfg/DFGOperations.h: + (JSC::operationCreateInlinedArgumentsDuringOSRExit): Deleted. + +2015-01-15 Csaba Osztrogonác <ossy@webkit.org> + + Remove ENABLE(SQL_DATABASE) guards + https://bugs.webkit.org/show_bug.cgi?id=140434 + + Reviewed by Darin Adler. + + * CMakeLists.txt: + * Configurations/FeatureDefines.xcconfig: + * DerivedSources.make: + * inspector/protocol/Database.json: + +2015-01-14 Alexey Proskuryakov <ap@apple.com> + + Web Inspector and regular console use different source code locations for messages + https://bugs.webkit.org/show_bug.cgi?id=140478 + + Reviewed by Brian Burg. + + * inspector/ConsoleMessage.h: Expose computed source location. + + * inspector/agents/InspectorConsoleAgent.cpp: + (Inspector::InspectorConsoleAgent::addMessageToConsole): + (Inspector::InspectorConsoleAgent::stopTiming): + (Inspector::InspectorConsoleAgent::count): + * inspector/agents/InspectorConsoleAgent.h: + addMessageToConsole() now takes a pre-made ConsoleMessage object. + + * inspector/JSGlobalObjectConsoleClient.cpp: + (Inspector::JSGlobalObjectConsoleClient::messageWithTypeAndLevel): + (Inspector::JSGlobalObjectConsoleClient::warnUnimplemented): + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::reportAPIException): + * inspector/agents/JSGlobalObjectDebuggerAgent.cpp: + (Inspector::JSGlobalObjectDebuggerAgent::breakpointActionLog): + Updated for the above changes. + +2015-01-15 Mark Lam <mark.lam@apple.com> + + [Part 2] Argument object created by "Function dot arguments" should use a clone of argument values. + <https://webkit.org/b/140093> + + Reviewed by Geoffrey Garen. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::createArguments): + - We should not fetching the lexicalEnvironment here. The reason we've + introduced the ClonedArgumentsCreationMode is because the lexicalEnvironment + may not be available to us at this point. Instead, we'll just pass a nullptr. + + * runtime/Arguments.cpp: + (JSC::Arguments::tearOffForCloning): + * runtime/Arguments.h: + (JSC::Arguments::finishCreation): + - Use the new tearOffForCloning() to tear off arguments right out of the values + passed on the stack. tearOff() is not appropriate for this purpose because + it takes slowArgumentsData into account. + +2015-01-14 Matthew Mirman <mmirman@apple.com> + + Removed accidental commit of "invalid_array.js" + http://trac.webkit.org/changeset/178439 + + * tests/stress/invalid_array.js: Removed. + +2015-01-14 Matthew Mirman <mmirman@apple.com> + + Fixes operationPutByIdOptimizes such that they check that the put didn't + change the structure of the object who's property access is being + cached. Also removes uses of the new base value from the cache generation code. + https://bugs.webkit.org/show_bug.cgi?id=139500 + + Reviewed by Filip Pizlo. + + * jit/JITOperations.cpp: + (JSC::operationPutByIdStrictOptimize): saved the structure before the put. + (JSC::operationPutByIdNonStrictOptimize): ditto. + (JSC::operationPutByIdDirectStrictOptimize): ditto. + (JSC::operationPutByIdDirectNonStrictOptimize): ditto. + * jit/Repatch.cpp: + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + (JSC::emitPutReplaceStub): + (JSC::emitPutTransitionStubAndGetOldStructure): Added. + (JSC::tryCachePutByID): + (JSC::repatchPutByID): + (JSC::tryBuildPutByIdList): + (JSC::tryRepatchIn): + (JSC::emitPutTransitionStub): Deleted. + * jit/Repatch.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/JSPropertyNameEnumerator.h: + (JSC::genericPropertyNameEnumerator): + * runtime/Operations.h: + (JSC::normalizePrototypeChainForChainAccess): restructured to not use the base value. + (JSC::normalizePrototypeChain): restructured to not use the base value. + * tests/mozilla/mozilla-tests.yaml: + * tests/stress/proto-setter.js: Added. + * tests/stress/put-by-id-build-list-order-recurse.js: Added. + Added test that fails without this patch. + +2015-01-13 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Remove unused ResizeImage and DecodeImageData timeline events + https://bugs.webkit.org/show_bug.cgi?id=140404 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/Timeline.json: + +2015-01-13 Yusuke Suzuki <utatane.tea@gmail.com> + + DFG can call PutByValDirect for generic arrays + https://bugs.webkit.org/show_bug.cgi?id=140389 + + Reviewed by Geoffrey Garen. + + Computed properties in object initializers (ES6) use the put_by_val_direct operation. + However, current DFG asserts that put_by_val_direct is not used for the generic array, + the assertion failure is raised. + This patch allow DFG to use put_by_val_direct to generic arrays. + + And fix the DFG put_by_val_direct implementation for string properties. + At first, put_by_val_direct is inteded to be used for spread elements. + So the property keys were limited to numbers (indexes). + But now, it's also used for computed properties in object initializers. + + * dfg/DFGOperations.cpp: + (JSC::DFG::operationPutByValInternal): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2015-01-13 Geoffrey Garen <ggaren@apple.com> + + Out of bounds access in BytecodeGenerator::emitGetById under DotAccessorNode::emitBytecode + https://bugs.webkit.org/show_bug.cgi?id=140397 + + Reviewed by Geoffrey Garen. + + Patch by Alexey Proskuryakov. + + Reviewed, performance tested, and ChangeLogged by Geoffrey Garen. + + No performance change. + + No test, since this is a small past-the-end read, which is very + difficult to turn into a reproducible failing test -- and existing tests + crash reliably using ASan. + + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::FunctionCallBracketNode::emitBytecode): + (JSC::PostfixNode::emitResolve): + (JSC::DeleteBracketNode::emitBytecode): + (JSC::DeleteDotNode::emitBytecode): + (JSC::PrefixNode::emitResolve): + (JSC::UnaryOpNode::emitBytecode): + (JSC::BitwiseNotNode::emitBytecode): + (JSC::BinaryOpNode::emitBytecode): + (JSC::EqualNode::emitBytecode): + (JSC::StrictEqualNode::emitBytecode): + (JSC::ThrowableBinaryOpNode::emitBytecode): + (JSC::AssignDotNode::emitBytecode): + (JSC::AssignBracketNode::emitBytecode): Use RefPtr in more places. Any + register used across a call to a function that might allocate a new + temporary register must be held in a RefPtr. + +2015-01-12 Michael Saboff <msaboff@apple.com> + + Local JSArray* "keys" in objectConstructorKeys() is not marked during garbage collection + https://bugs.webkit.org/show_bug.cgi?id=140348 + + Reviewed by Mark Lam. + + We used to read registers in MachineThreads::gatherFromCurrentThread(), but that is too late + because those registers may have been spilled on the stack and replaced with other values by + the time we call down to gatherFromCurrentThread(). + + Now we get the register contents at the same place that we demarcate the current top of + stack using the address of a local variable, in Heap::markRoots(). The register contents + buffer is passed along with the demarcation pointer. These need to be done at this level + in the call tree and no lower, as markRoots() calls various functions that visit object + pointers that may be latter proven dead. Any of those pointers that are left on the + stack or in registers could be incorrectly marked as live if we scan the stack contents + from a called function or one of its callees. The stack demarcation pointer and register + saving need to be done in the same function so that we have a consistent stack, active + and spilled registers. + + Because we don't want to make unnecessary calls to get the register contents, we use + a macro to allocated, and possibly align, the register structure and get the actual + register contents. + + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::gatherStackRoots): + * heap/Heap.h: + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::gatherFromCurrentThread): + (JSC::MachineThreads::gatherConservativeRoots): + * heap/MachineStackMarker.h: + +2015-01-12 Benjamin Poulain <benjamin@webkit.org> + + Add basic pattern matching support to the url filters + https://bugs.webkit.org/show_bug.cgi?id=140283 + + Reviewed by Andreas Kling. + + * JavaScriptCore.xcodeproj/project.pbxproj: + Make YarrParser.h private in order to use it from WebCore. + +2015-01-12 Geoffrey Garen <ggaren@apple.com> + + Out of bounds read in IdentifierArena::makeIdentifier + https://bugs.webkit.org/show_bug.cgi?id=140376 + + Patch by Alexey Proskuryakov. + + Reviewed and ChangeLogged by Geoffrey Garen. + + No test, since this is a small past-the-end read, which is very + difficult to turn into a reproducible failing test -- and existing tests + crash reliably using ASan. + + * parser/ParserArena.h: + (JSC::IdentifierArena::makeIdentifier): + (JSC::IdentifierArena::makeIdentifierLCharFromUChar): Check for a + zero-length string input, like we do in the literal parser, since it is + not valid to dereference characters in a zero-length string. + + A zero-length string is allowed in JavaScript -- for example, "". + +2015-01-11 Sam Weinig <sam@webkit.org> + + Remove support for SharedWorkers + https://bugs.webkit.org/show_bug.cgi?id=140344 + + Reviewed by Anders Carlsson. + + * Configurations/FeatureDefines.xcconfig: + +2015-01-12 Myles C. Maxfield <mmaxfield@apple.com> + + Allow targetting the SVG->OTF font converter with ENABLE(SVG_OTF_CONVERTER) + https://bugs.webkit.org/show_bug.cgi?id=136769 + + Reviewed by Antti Koivisto. + + * Configurations/FeatureDefines.xcconfig: + +2015-01-12 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r178266. + https://bugs.webkit.org/show_bug.cgi?id=140363 + + Broke a JSC test (Requested by ap on #webkit). + + Reverted changeset: + + "Local JSArray* "keys" in objectConstructorKeys() is not + marked during garbage collection" + https://bugs.webkit.org/show_bug.cgi?id=140348 + http://trac.webkit.org/changeset/178266 + +2015-01-12 Michael Saboff <msaboff@apple.com> + + Local JSArray* "keys" in objectConstructorKeys() is not marked during garbage collection + https://bugs.webkit.org/show_bug.cgi?id=140348 + + Reviewed by Mark Lam. + + Move the address of the local variable that is used to demarcate the top of the stack for + conservative roots down to MachineThreads::gatherFromCurrentThread() since it also gets + the register values using setjmp(). That way we don't lose any callee save register + contents between Heap::markRoots(), where it was set, and gatherFromCurrentThread(). + If we lose any JSObject* that are only in callee save registers, they will be GC'ed + erroneously. + + * heap/Heap.cpp: + (JSC::Heap::markRoots): + (JSC::Heap::gatherStackRoots): + * heap/Heap.h: + * heap/MachineStackMarker.cpp: + (JSC::MachineThreads::gatherFromCurrentThread): + (JSC::MachineThreads::gatherConservativeRoots): + * heap/MachineStackMarker.h: + +2015-01-11 Eric Carlson <eric.carlson@apple.com> + + Fix typo in testate.c error messages + https://bugs.webkit.org/show_bug.cgi?id=140305 + + Reviewed by Geoffrey Garen. + + * API/tests/testapi.c: + (main): "... script did not timed out ..." -> "... script did not time out ..." + +2015-01-09 Michael Saboff <msaboff@apple.com> + + Breakpoint doesn't fire in this HTML5 game + https://bugs.webkit.org/show_bug.cgi?id=140269 + + Reviewed by Mark Lam. + + When parsing a single line cached function, use the lineStartOffset of the + location where we found the cached function instead of the cached lineStartOffset. + The cache location's lineStartOffset has not been adjusted for any possible + containing functions. + + This change is not needed for multi-line cached functions. Consider the + single line source: + + function outer(){function inner1(){doStuff();}; (function inner2() {doMoreStuff()})()} + + The first parser pass, we parse and cache inner1() and inner2() with a lineStartOffset + of 0. Later when we parse outer() and find inner1() in the cache, SourceCode start + character is at outer()'s outermost open brace. That is what we should use for + lineStartOffset for inner1(). When done parsing inner1() we set the parsing token + to the saved location for inner1(), including the lineStartOffset of 0. We need + to use the value of lineStartOffset before we started parsing inner1(). That is + what the fix does. When we parse inner2() the lineStartOffset will be correct. + + For a multi-line function, the close brace is guaranteed to be on a different line + than the open brace. Hence, its lineStartOffset will not change with the change of + the SourceCode start character + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseFunctionInfo): + +2015-01-09 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Uncaught Exception in ProbeManager deleting breakpoint + https://bugs.webkit.org/show_bug.cgi?id=140279 + rdar://problem/19422299 + + Reviewed by Oliver Hunt. + + * runtime/MapData.cpp: + (JSC::MapData::replaceAndPackBackingStore): + The cell table also needs to have its values fixed. + +2015-01-09 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Remove or use TimelineAgent Resource related event types + https://bugs.webkit.org/show_bug.cgi?id=140155 + + Reviewed by Timothy Hatcher. + + Remove unused / stale Timeline event types. + + * inspector/protocol/Timeline.json: + +2015-01-09 Csaba Osztrogonác <ossy@webkit.org> + + REGRESSION(r177925): It broke the !ENABLE(INSPECTOR) build + https://bugs.webkit.org/show_bug.cgi?id=140098 + + Reviewed by Brian Burg. + + * inspector/InspectorBackendDispatcher.h: Missing ENABLE(INSPECTOR) guard added. + +2015-01-08 Mark Lam <mark.lam@apple.com> + + Argument object created by "Function dot arguments" should use a clone of the argument values. + <https://webkit.org/b/140093> + + Reviewed by Geoffrey Garen. + + After the change in <https://webkit.org/b/139827>, the dfg-tear-off-arguments-not-activation.js + test will crash. The relevant code which manifests the issue is as follows: + + function bar() { + return foo.arguments; + } + + function foo(p) { + var x = 42; + if (p) + return (function() { return x; }); + else + return bar(); + } + + In this case, foo() has no knowledge of bar() needing its LexicalEnvironment and + has dead code eliminated the SetLocal that stores it into its designated local. + In bar(), the factory for the Arguments object (for creating foo.arguments) tries + to read foo's LexicalEnvironment from its designated lexicalEnvironment local, + but instead, finds it to be uninitialized. This results in a null pointer access + which causes a crash. + + This can be resolved by having bar() instantiate a clone of the Arguments object + instead, and populate its elements with values fetched directly from foo's frame. + There's no need to reference foo's LexicalEnvironment (whether present or not). + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::createArguments): + * runtime/Arguments.h: + (JSC::Arguments::finishCreation): + +2015-01-08 Mark Lam <mark.lam@apple.com> + + Make the LLINT and Baseline JIT's op_create_arguments and op_get_argument_by_val use their lexicalEnvironment operand. + <https://webkit.org/b/140236> + + Reviewed by Geoffrey Garen. + + Will change the DFG to use the operand on a subsequent pass. For now, + the DFG uses a temporary thunk (operationCreateArgumentsForDFG()) to + retain the old behavior of getting the lexicalEnviroment from the + ExecState. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitGetArgumentByVal): + (JSC::BytecodeGenerator::createArgumentsIfNecessary): + - When the lexicalEnvironment is not available, pass the invalid VirtualRegister + instead of an empty JSValue as the lexicalEnvironment operand. + + * dfg/DFGOperations.cpp: + - Use the lexicalEnvironment from the ExecState for now. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + - Use the operationCreateArgumentsForDFG() thunk for now. + + * interpreter/CallFrame.cpp: + (JSC::CallFrame::lexicalEnvironmentOrNullptr): + * interpreter/CallFrame.h: + - Added this convenience function to return either the + lexicalEnvironment or a nullptr so that we don't need to do a + conditional check on codeBlock->needsActivation() at multiple sites. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::createArguments): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_arguments): + (JSC::JIT::emitSlow_op_get_argument_by_val): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_arguments): + (JSC::JIT::emitSlow_op_get_argument_by_val): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/Arguments.h: + (JSC::Arguments::create): + (JSC::Arguments::finishCreation): + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/JSLexicalEnvironment.cpp: + (JSC::JSLexicalEnvironment::argumentsGetter): + +2015-01-08 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Pause Reason Improvements (Breakpoint, Debugger Statement, Pause on Next Statement) + https://bugs.webkit.org/show_bug.cgi?id=138991 + + Reviewed by Timothy Hatcher. + + * debugger/Debugger.cpp: + (JSC::Debugger::Debugger): + (JSC::Debugger::pauseIfNeeded): + (JSC::Debugger::didReachBreakpoint): + When actually pausing, if we hit a breakpoint ensure the reason + is PausedForBreakpoint, otherwise use the current reason. + + * debugger/Debugger.h: + Make pause reason and pausing breakpoint ID public. + + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::buildAssertPauseReason): + (Inspector::buildCSPViolationPauseReason): + (Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason): + (Inspector::InspectorDebuggerAgent::buildExceptionPauseReason): + (Inspector::InspectorDebuggerAgent::handleConsoleAssert): + (Inspector::buildObjectForBreakpointCookie): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::InspectorDebuggerAgent::removeBreakpoint): + (Inspector::InspectorDebuggerAgent::resolveBreakpoint): + (Inspector::InspectorDebuggerAgent::pause): + (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP): + (Inspector::InspectorDebuggerAgent::currentCallFrames): + (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState): + Clean up creation of pause reason objects and other cleanup + of PassRefPtr use and InjectedScript use. + + (Inspector::InspectorDebuggerAgent::didPause): + Clean up so that we first check for an Exception, and then fall + back to including a Pause Reason derived from the Debugger. + + * inspector/protocol/Debugger.json: + Add new DebuggerStatement, Breakpoint, and PauseOnNextStatement reasons. + +2015-01-08 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Type check NSArray's in ObjC Interfaces have the right object types + https://bugs.webkit.org/show_bug.cgi?id=140209 + + Reviewed by Timothy Hatcher. + + Check the types of objects in NSArrays for all interfaces (commands, events, types) + when the user can set an array of objects. Previously we were only type checking + they were RWIJSONObjects, now we add an explicit check for the exact object type. + + * inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py: + (ObjCConfigurationImplementationGenerator._generate_success_block_for_command): + * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py: + (ObjCFrontendDispatcherImplementationGenerator._generate_event): + * inspector/scripts/codegen/generate_objc_protocol_types_implementation.py: + (ObjCProtocolTypesImplementationGenerator._generate_init_method_for_required_members): + (ObjCProtocolTypesImplementationGenerator._generate_setter_for_member): + * inspector/scripts/codegen/objc_generator.py: + (ObjCGenerator.objc_class_for_array_type): + (ObjCGenerator): + +2015-01-07 Mark Lam <mark.lam@apple.com> + + Add the lexicalEnvironment as an operand to op_get_argument_by_val. + <https://webkit.org/b/140233> + + Reviewed by Filip Pizlo. + + This patch only adds the operand to the bytecode. It is not in use yet. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetArgumentByVal): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2015-01-07 Yusuke Suzuki <utatane.tea@gmail.com> + + Investigate the character type of repeated string instead of checking is8Bit flag + https://bugs.webkit.org/show_bug.cgi?id=140139 + + Reviewed by Darin Adler. + + Instead of checking is8Bit flag of the repeated string, investigate + the actual value of the repeated character since i8Bit flag give a false negative case. + + * runtime/StringPrototype.cpp: + (JSC::repeatCharacter): + (JSC::stringProtoFuncRepeat): + (JSC::repeatSmallString): Deleted. + +2015-01-07 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ObjC Generate types from the GenericTypes domain + https://bugs.webkit.org/show_bug.cgi?id=140229 + + Reviewed by Timothy Hatcher. + + Generate types from the GenericTypes domain, as they are expected + by other domains (like Page domain). Also, don't include the @protocol + forward declaration for a domain if it doesn't have any commands. + + * inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py: + (ObjCBackendDispatcherHeaderGenerator._generate_objc_forward_declarations): + (ObjCBackendDispatcherHeaderGenerator): Deleted. + (ObjCBackendDispatcherHeaderGenerator._generate_objc_forward_declarations_for_domains): Deleted. + * inspector/scripts/codegen/objc_generator.py: + (ObjCGenerator): + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + +2015-01-07 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Remove unnecessary copyRef for paramsObject in generated dispatchers + https://bugs.webkit.org/show_bug.cgi?id=140228 + + Reviewed by Timothy Hatcher. + + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py: + (CppFrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py: + (ObjCFrontendDispatcherImplementationGenerator._generate_event_out_parameters): + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + +2015-01-07 Saam Barati <saambarati1@gmail.com> + + interpret op_profile_type in the LLInt instead of unconditionally calling into the slow path + https://bugs.webkit.org/show_bug.cgi?id=140165 + + Reviewed by Michael Saboff. + + Inlining the functionality of TypeProfilerLog::recordTypeInformationForLocation + into the LLInt speeds up type profiling. + + * llint/LLIntOffsetsExtractor.cpp: + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + * runtime/CommonSlowPaths.h: + * runtime/TypeProfilerLog.h: + (JSC::TypeProfilerLog::recordTypeInformationForLocation): Deleted. + +2015-01-07 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: purge PassRefPtr from Inspector code and use Ref for typed and untyped protocol objects + https://bugs.webkit.org/show_bug.cgi?id=140053 + + Reviewed by Andreas Kling. + + This patch replaces uses of PassRefPtr with uses of RefPtr&& and WTF::move() in code + related to Web Inspector. It also converts many uses of RefPtr to Ref where + references are always non-null. These two refactorings have been combined since + they tend to require similar changes to the code. + + Creation methods for subclasses of InspectorValue now return a Ref, and callsites + have been updated to take a Ref instead of RefPtr. + + Builders for typed protocol objects now return a Ref. Since there is no implicit + call to operator&, callsites now must explicitly call .release() to convert a + builder object into the corresponding protocol object once required fields are set. + Update callsites and use auto to eliminate repetition of longwinded protocol types. + + Tests for inspector protocol and replay inputs have been rebaselined. + + * bindings/ScriptValue.cpp: + (Deprecated::jsToInspectorValue): + (Deprecated::ScriptValue::toInspectorValue): + * bindings/ScriptValue.h: + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::addToFrontend): + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::buildObjectForSearchMatch): + (Inspector::ContentSearchUtilities::searchInTextByLines): + * inspector/ContentSearchUtilities.h: + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getFunctionDetails): + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getInternalProperties): + (Inspector::InjectedScript::wrapCallFrames): + (Inspector::InjectedScript::wrapObject): + (Inspector::InjectedScript::wrapTable): + * inspector/InjectedScript.h: + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::makeEvalCall): Split the early exits. + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::InspectorBackendDispatcher::CallbackBase::CallbackBase): + (Inspector::InspectorBackendDispatcher::CallbackBase::sendIfActive): + (Inspector::InspectorBackendDispatcher::create): + (Inspector::InspectorBackendDispatcher::dispatch): + (Inspector::InspectorBackendDispatcher::sendResponse): + (Inspector::InspectorBackendDispatcher::reportProtocolError): + (Inspector::getPropertyValue): Add a comment to clarify what this clever code does. + (Inspector::InspectorBackendDispatcher::getInteger): + (Inspector::InspectorBackendDispatcher::getDouble): + (Inspector::InspectorBackendDispatcher::getString): + (Inspector::InspectorBackendDispatcher::getBoolean): + (Inspector::InspectorBackendDispatcher::getObject): + (Inspector::InspectorBackendDispatcher::getArray): + (Inspector::InspectorBackendDispatcher::getValue): + * inspector/InspectorBackendDispatcher.h: Use a typed protocol object to collect + protocol error strings. + (Inspector::InspectorSupplementalBackendDispatcher::InspectorSupplementalBackendDispatcher): + Convert the supplemental dispatcher's reference to Ref since it is never null. + * inspector/InspectorEnvironment.h: + * inspector/InspectorProtocolTypes.h: Get rid of ArrayItemHelper and + StructItemTraits. Add more versions of addItem to handle pushing various types. + (Inspector::Protocol::Array::openAccessors): + (Inspector::Protocol::Array::addItem): + (Inspector::Protocol::Array::create): + (Inspector::Protocol::StructItemTraits::push): + (Inspector::Protocol::BindingTraits<Protocol::Array<T>>::runtimeCast): Assert argument. + (Inspector::Protocol::StructItemTraits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<String>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<int>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<double>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<bool>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<InspectorValue>::Traits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<InspectorObject>::Traits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<InspectorArray>::Traits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<Protocol::Array<T>>::Traits::pushRefPtr): Deleted. + * inspector/InspectorValues.cpp: Straighten out getArray and getObject to have + the same call signature as other getters. Use Ref where possible. + (Inspector::InspectorObjectBase::getBoolean): + (Inspector::InspectorObjectBase::getString): + (Inspector::InspectorObjectBase::getObject): + (Inspector::InspectorObjectBase::getArray): + (Inspector::InspectorObjectBase::getValue): + (Inspector::InspectorObjectBase::writeJSON): + (Inspector::InspectorArrayBase::get): + (Inspector::InspectorObject::create): + (Inspector::InspectorArray::create): + (Inspector::InspectorValue::null): + (Inspector::InspectorString::create): + (Inspector::InspectorBasicValue::create): + (Inspector::InspectorObjectBase::get): Deleted. + * inspector/InspectorValues.h: + (Inspector::InspectorObjectBase::setValue): + (Inspector::InspectorObjectBase::setObject): + (Inspector::InspectorObjectBase::setArray): + (Inspector::InspectorArrayBase::pushValue): + (Inspector::InspectorArrayBase::pushObject): + (Inspector::InspectorArrayBase::pushArray): + * inspector/JSGlobalObjectConsoleClient.cpp: + (Inspector::JSGlobalObjectConsoleClient::messageWithTypeAndLevel): + (Inspector::JSGlobalObjectConsoleClient::count): + (Inspector::JSGlobalObjectConsoleClient::timeEnd): + (Inspector::JSGlobalObjectConsoleClient::timeStamp): + * inspector/JSGlobalObjectConsoleClient.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::executionStopwatch): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/ScriptCallFrame.cpp: + (Inspector::ScriptCallFrame::buildInspectorObject): + * inspector/ScriptCallFrame.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::create): + (Inspector::ScriptCallStack::buildInspectorArray): + * inspector/ScriptCallStack.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::enable): + (Inspector::InspectorAgent::inspect): + (Inspector::InspectorAgent::activateExtraDomain): + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::handleConsoleAssert): + (Inspector::buildObjectForBreakpointCookie): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::continueToLocation): + (Inspector::InspectorDebuggerAgent::resolveBreakpoint): + (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): + (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP): + (Inspector::InspectorDebuggerAgent::currentCallFrames): + (Inspector::InspectorDebuggerAgent::didParseSource): + (Inspector::InspectorDebuggerAgent::breakpointActionProbe): + (Inspector::InspectorDebuggerAgent::breakProgram): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::buildErrorRangeObject): + (Inspector::InspectorRuntimeAgent::callFunctionOn): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::InspectorRuntimeAgent::getBasicBlocks): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/scripts/codegen/cpp_generator.py: + (CppGenerator.cpp_type_for_unchecked_formal_in_parameter): + (CppGenerator.cpp_type_for_type_with_name): + (CppGenerator.cpp_type_for_formal_async_parameter): + (CppGenerator.should_use_references_for_type): + (CppGenerator): + * inspector/scripts/codegen/cpp_generator_templates.py: + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py: + (CppBackendDispatcherHeaderGenerator.generate_output): + (CppBackendDispatcherHeaderGenerator._generate_async_handler_declaration_for_command): + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py: + (CppBackendDispatcherImplementationGenerator._generate_small_dispatcher_switch_implementation_for_domain): + (CppBackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py: + (CppFrontendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py: + (CppFrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + * inspector/scripts/codegen/generate_cpp_protocol_types_header.py: + (CppProtocolTypesHeaderGenerator.generate_output): + (_generate_class_for_object_declaration): + (_generate_unchecked_setter_for_member): + (_generate_forward_declarations_for_binding_traits): + * inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py: + (ObjCConfigurationImplementationGenerator._generate_success_block_for_command): + * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py: + (ObjCFrontendDispatcherImplementationGenerator._generate_event): + (ObjCFrontendDispatcherImplementationGenerator._generate_event_out_parameters): + * inspector/scripts/codegen/generate_objc_protocol_types_implementation.py: + (ObjCProtocolTypesImplementationGenerator.generate_output): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * replay/EncodedValue.cpp: + (JSC::EncodedValue::asObject): + (JSC::EncodedValue::asArray): + (JSC::EncodedValue::put<EncodedValue>): + (JSC::EncodedValue::append<EncodedValue>): + (JSC::EncodedValue::get<EncodedValue>): + * replay/EncodedValue.h: + * replay/scripts/CodeGeneratorReplayInputs.py: + (Type.borrow_type): + (Type.argument_type): + (Generator.generate_member_move_expression): + * runtime/ConsoleClient.cpp: + (JSC::ConsoleClient::printConsoleMessageWithArguments): + (JSC::ConsoleClient::internalMessageWithTypeAndLevel): + (JSC::ConsoleClient::logWithLevel): + (JSC::ConsoleClient::clear): + (JSC::ConsoleClient::dir): + (JSC::ConsoleClient::dirXML): + (JSC::ConsoleClient::table): + (JSC::ConsoleClient::trace): + (JSC::ConsoleClient::assertCondition): + (JSC::ConsoleClient::group): + (JSC::ConsoleClient::groupCollapsed): + (JSC::ConsoleClient::groupEnd): + * runtime/ConsoleClient.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::allStructureRepresentations): + (JSC::TypeSet::inspectorTypeSet): + (JSC::StructureShape::inspectorRepresentation): + * runtime/TypeSet.h: + +2015-01-07 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r178039. + https://bugs.webkit.org/show_bug.cgi?id=140187 + + Breaks ObjC Inspector Protocol (Requested by JoePeck on + #webkit). + + Reverted changeset: + + "Web Inspector: purge PassRefPtr from Inspector code and use + Ref for typed and untyped protocol objects" + https://bugs.webkit.org/show_bug.cgi?id=140053 + http://trac.webkit.org/changeset/178039 + +2015-01-06 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: purge PassRefPtr from Inspector code and use Ref for typed and untyped protocol objects + https://bugs.webkit.org/show_bug.cgi?id=140053 + + Reviewed by Andreas Kling. + + This patch replaces uses of PassRefPtr with uses of RefPtr&& and WTF::move() in code + related to Web Inspector. It also converts many uses of RefPtr to Ref where + references are always non-null. These two refactorings have been combined since + they tend to require similar changes to the code. + + Creation methods for subclasses of InspectorValue now return a Ref, and callsites + have been updated to take a Ref instead of RefPtr. + + Builders for typed protocol objects now return a Ref. Since there is no implicit + call to operator&, callsites now must explicitly call .release() to convert a + builder object into the corresponding protocol object once required fields are set. + Update callsites and use auto to eliminate repetition of longwinded protocol types. + + Tests for inspector protocol and replay inputs have been rebaselined. + + * bindings/ScriptValue.cpp: + (Deprecated::jsToInspectorValue): + (Deprecated::ScriptValue::toInspectorValue): + * bindings/ScriptValue.h: + * inspector/ConsoleMessage.cpp: + (Inspector::ConsoleMessage::addToFrontend): + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::buildObjectForSearchMatch): + (Inspector::ContentSearchUtilities::searchInTextByLines): + * inspector/ContentSearchUtilities.h: + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::getFunctionDetails): + (Inspector::InjectedScript::getProperties): + (Inspector::InjectedScript::getInternalProperties): + (Inspector::InjectedScript::wrapCallFrames): + (Inspector::InjectedScript::wrapObject): + (Inspector::InjectedScript::wrapTable): + * inspector/InjectedScript.h: + * inspector/InjectedScriptBase.cpp: + (Inspector::InjectedScriptBase::makeEvalCall): Split the early exits. + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::InspectorBackendDispatcher::CallbackBase::CallbackBase): + (Inspector::InspectorBackendDispatcher::CallbackBase::sendIfActive): + (Inspector::InspectorBackendDispatcher::create): + (Inspector::InspectorBackendDispatcher::dispatch): + (Inspector::InspectorBackendDispatcher::sendResponse): + (Inspector::InspectorBackendDispatcher::reportProtocolError): + (Inspector::getPropertyValue): Add a comment to clarify what this clever code does. + (Inspector::InspectorBackendDispatcher::getInteger): + (Inspector::InspectorBackendDispatcher::getDouble): + (Inspector::InspectorBackendDispatcher::getString): + (Inspector::InspectorBackendDispatcher::getBoolean): + (Inspector::InspectorBackendDispatcher::getObject): + (Inspector::InspectorBackendDispatcher::getArray): + (Inspector::InspectorBackendDispatcher::getValue): + * inspector/InspectorBackendDispatcher.h: Use a typed protocol object to collect + protocol error strings. + (Inspector::InspectorSupplementalBackendDispatcher::InspectorSupplementalBackendDispatcher): + Convert the supplemental dispatcher's reference to Ref since it is never null. + * inspector/InspectorEnvironment.h: + * inspector/InspectorProtocolTypes.h: Get rid of ArrayItemHelper and + StructItemTraits. Add more versions of addItem to handle pushing various types. + (Inspector::Protocol::Array::openAccessors): + (Inspector::Protocol::Array::addItem): + (Inspector::Protocol::Array::create): + (Inspector::Protocol::StructItemTraits::push): + (Inspector::Protocol::BindingTraits<Protocol::Array<T>>::runtimeCast): Assert argument. + (Inspector::Protocol::StructItemTraits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<String>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<int>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<double>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<bool>::Traits::pushRaw): Deleted. + (Inspector::Protocol::ArrayItemHelper<InspectorValue>::Traits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<InspectorObject>::Traits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<InspectorArray>::Traits::pushRefPtr): Deleted. + (Inspector::Protocol::ArrayItemHelper<Protocol::Array<T>>::Traits::pushRefPtr): Deleted. + * inspector/InspectorValues.cpp: Straighten out getArray and getObject to have + the same call signature as other getters. Use Ref where possible. + (Inspector::InspectorObjectBase::getBoolean): + (Inspector::InspectorObjectBase::getString): + (Inspector::InspectorObjectBase::getObject): + (Inspector::InspectorObjectBase::getArray): + (Inspector::InspectorObjectBase::getValue): + (Inspector::InspectorObjectBase::writeJSON): + (Inspector::InspectorArrayBase::get): + (Inspector::InspectorObject::create): + (Inspector::InspectorArray::create): + (Inspector::InspectorValue::null): + (Inspector::InspectorString::create): + (Inspector::InspectorBasicValue::create): + (Inspector::InspectorObjectBase::get): Deleted. + * inspector/InspectorValues.h: + (Inspector::InspectorObjectBase::setValue): + (Inspector::InspectorObjectBase::setObject): + (Inspector::InspectorObjectBase::setArray): + (Inspector::InspectorArrayBase::pushValue): + (Inspector::InspectorArrayBase::pushObject): + (Inspector::InspectorArrayBase::pushArray): + * inspector/JSGlobalObjectConsoleClient.cpp: + (Inspector::JSGlobalObjectConsoleClient::messageWithTypeAndLevel): + (Inspector::JSGlobalObjectConsoleClient::count): + (Inspector::JSGlobalObjectConsoleClient::timeEnd): + (Inspector::JSGlobalObjectConsoleClient::timeStamp): + * inspector/JSGlobalObjectConsoleClient.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::executionStopwatch): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/ScriptCallFrame.cpp: + (Inspector::ScriptCallFrame::buildInspectorObject): + * inspector/ScriptCallFrame.h: + * inspector/ScriptCallStack.cpp: + (Inspector::ScriptCallStack::create): + (Inspector::ScriptCallStack::buildInspectorArray): + * inspector/ScriptCallStack.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::enable): + (Inspector::InspectorAgent::inspect): + (Inspector::InspectorAgent::activateExtraDomain): + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::handleConsoleAssert): + (Inspector::buildObjectForBreakpointCookie): + (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): + (Inspector::InspectorDebuggerAgent::setBreakpoint): + (Inspector::InspectorDebuggerAgent::continueToLocation): + (Inspector::InspectorDebuggerAgent::resolveBreakpoint): + (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): + (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP): + (Inspector::InspectorDebuggerAgent::currentCallFrames): + (Inspector::InspectorDebuggerAgent::didParseSource): + (Inspector::InspectorDebuggerAgent::breakpointActionProbe): + (Inspector::InspectorDebuggerAgent::breakProgram): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::buildErrorRangeObject): + (Inspector::InspectorRuntimeAgent::callFunctionOn): + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + (Inspector::InspectorRuntimeAgent::getBasicBlocks): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/scripts/codegen/cpp_generator.py: + (CppGenerator.cpp_type_for_unchecked_formal_in_parameter): + (CppGenerator.cpp_type_for_type_with_name): + (CppGenerator.cpp_type_for_formal_async_parameter): + (CppGenerator.should_use_references_for_type): + (CppGenerator): + * inspector/scripts/codegen/cpp_generator_templates.py: + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py: + (CppBackendDispatcherHeaderGenerator.generate_output): + (CppBackendDispatcherHeaderGenerator._generate_async_handler_declaration_for_command): + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py: + (CppBackendDispatcherImplementationGenerator._generate_small_dispatcher_switch_implementation_for_domain): + (CppBackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py: + (CppFrontendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py: + (CppFrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + * inspector/scripts/codegen/generate_cpp_protocol_types_header.py: + (CppProtocolTypesHeaderGenerator.generate_output): + (_generate_class_for_object_declaration): + (_generate_unchecked_setter_for_member): + (_generate_forward_declarations_for_binding_traits): + * inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py: + (ObjCConfigurationImplementationGenerator._generate_success_block_for_command): + * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py: + (ObjCFrontendDispatcherImplementationGenerator._generate_event): + (ObjCFrontendDispatcherImplementationGenerator._generate_event_out_parameters): + * inspector/scripts/codegen/generate_objc_protocol_types_implementation.py: + (ObjCProtocolTypesImplementationGenerator.generate_output): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + * replay/EncodedValue.cpp: + (JSC::EncodedValue::asObject): + (JSC::EncodedValue::asArray): + (JSC::EncodedValue::put<EncodedValue>): + (JSC::EncodedValue::append<EncodedValue>): + (JSC::EncodedValue::get<EncodedValue>): + * replay/EncodedValue.h: + * replay/scripts/CodeGeneratorReplayInputs.py: + (Type.borrow_type): + (Type.argument_type): + (Generator.generate_member_move_expression): + * runtime/ConsoleClient.cpp: + (JSC::ConsoleClient::printConsoleMessageWithArguments): + (JSC::ConsoleClient::internalMessageWithTypeAndLevel): + (JSC::ConsoleClient::logWithLevel): + (JSC::ConsoleClient::clear): + (JSC::ConsoleClient::dir): + (JSC::ConsoleClient::dirXML): + (JSC::ConsoleClient::table): + (JSC::ConsoleClient::trace): + (JSC::ConsoleClient::assertCondition): + (JSC::ConsoleClient::group): + (JSC::ConsoleClient::groupCollapsed): + (JSC::ConsoleClient::groupEnd): + * runtime/ConsoleClient.h: + * runtime/TypeSet.cpp: + (JSC::TypeSet::allStructureRepresentations): + (JSC::TypeSet::inspectorTypeSet): + (JSC::StructureShape::inspectorRepresentation): + * runtime/TypeSet.h: + +2015-01-06 Chris Dumez <cdumez@apple.com> + + Drop ResourceResponseBase::connectionID and connectionReused members + https://bugs.webkit.org/show_bug.cgi?id=140158 + + Reviewed by Sam Weinig. + + Drop ResourceResponseBase::connectionID and connectionReused members. + Those were needed by the Chromium port but are no longer used. + + * inspector/protocol/Network.json: + +2015-01-06 Mark Lam <mark.lam@apple.com> + + Add the lexicalEnvironment as an operand to op_create_arguments. + <https://webkit.org/b/140148> + + Reviewed by Geoffrey Garen. + + This patch only adds the operand to the bytecode. It is not in use yet. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::createArgumentsIfNecessary): + - Adds the lexicalEnvironment register (if present) as an operand to + op_create_arguments. Else, adds a constant empty JSValue. + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2015-01-06 Alexey Proskuryakov <ap@apple.com> + + ADDRESS_SANITIZER macro is overloaded + https://bugs.webkit.org/show_bug.cgi?id=140130 + + Reviewed by Anders Carlsson. + + * interpreter/JSStack.cpp: (JSC::JSStack::sanitizeStack): Use the new macro. + This code is nearly unused (only compiled in when JIT is disabled at build time), + however I've been told that it's best to keep it. + +2015-01-06 Mark Lam <mark.lam@apple.com> + + Fix Use details for op_create_arguments. + <https://webkit.org/b/140110> + + Rubber stamped by Filip Pizlo. + + The previous patch was wrong about op_create_arguments not using its 1st operand. + It does read from it (hence, used) to check if the Arguments object has already + been created or not. This patch reverts the change for op_create_arguments. + + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + +2015-01-06 Mark Lam <mark.lam@apple.com> + + Fix Use details for op_create_lexical_environment and op_create_arguments. + <https://webkit.org/b/140110> + + Reviewed by Filip Pizlo. + + The current "Use" details for op_create_lexical_environment and + op_create_arguments are wrong. op_create_argument uses nothing instead of the + 1st operand (the output local). op_create_lexical_environment uses its 2nd + operand (the scope chain) instead of the 1st (the output local). + This patch fixes them to specify the proper uses. + + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + +2015-01-06 Yusuke Suzuki <utatane.tea@gmail.com> + + Implement ES6 String.prototype.repeat(count) + https://bugs.webkit.org/show_bug.cgi?id=140047 + + Reviewed by Darin Adler. + + Introducing ES6 String.prototype.repeat(count) function. + + * runtime/JSString.h: + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + (JSC::repeatSmallString): + (JSC::stringProtoFuncRepeat): + +2015-01-03 Michael Saboff <msaboff@apple.com> + + Crash in operationNewFunction when scrolling on Google+ + https://bugs.webkit.org/show_bug.cgi?id=140033 + + Reviewed by Oliver Hunt. + + In DFG code, the scope register can be eliminated because all uses have been + dead code eliminated. In the case where one of the uses was creating a function + that is never used, the baseline code will still create the function. If we OSR + exit to a path where that function gets created, check the scope register value + and set the new, but dead, function to undefined instead of creating a new function. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_new_func_exp): + +2015-01-01 Yusuke Suzuki <utatane.tea@gmail.com> + + String includes methods perform toString on searchString before toInt32 on a offset + https://bugs.webkit.org/show_bug.cgi?id=140031 + + Reviewed by Darin Adler. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncStartsWith): + (JSC::stringProtoFuncEndsWith): + (JSC::stringProtoFuncIncludes): + +2015-01-01 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Change to return std::unique_ptr<> in fooCreate() + https://bugs.webkit.org/show_bug.cgi?id=139983 + + Reviewed by Darin Adler. + + To avoid unnecessary std::unique_ptr<> casting, fooCreate() returns std::unique_ptr<> directly. + + * create_regex_tables: + * yarr/YarrPattern.h: + (JSC::Yarr::YarrPattern::reset): + (JSC::Yarr::YarrPattern::newlineCharacterClass): + (JSC::Yarr::YarrPattern::digitsCharacterClass): + (JSC::Yarr::YarrPattern::spacesCharacterClass): + (JSC::Yarr::YarrPattern::wordcharCharacterClass): + (JSC::Yarr::YarrPattern::nondigitsCharacterClass): + (JSC::Yarr::YarrPattern::nonspacesCharacterClass): + (JSC::Yarr::YarrPattern::nonwordcharCharacterClass): + +2015-01-01 Jeff Miller <jeffm@apple.com> + + Update user-visible copyright strings to include 2015 + https://bugs.webkit.org/show_bug.cgi?id=139880 + + Reviewed by Darin Adler. + + * Info.plist: + +2015-01-01 Darin Adler <darin@apple.com> + + We often misspell identifier as "identifer" + https://bugs.webkit.org/show_bug.cgi?id=140025 + + Reviewed by Michael Saboff. + + * runtime/ArrayConventions.h: Fix it. + +2014-12-29 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Move JavaScriptCore/yarr to std::unique_ptr + https://bugs.webkit.org/show_bug.cgi?id=139621 + + Reviewed by Anders Carlsson. + + Final clean up OwnPtr|PassOwnPtr in JavaScriptCore/yarr. + + * yarr/YarrInterpreter.cpp: + (JSC::Yarr::ByteCompiler::atomParenthesesSubpatternEnd): + * yarr/YarrInterpreter.h: + (JSC::Yarr::BytecodePattern::BytecodePattern): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::opCompileParenthesesSubpattern): + (JSC::Yarr::YarrGenerator::opCompileParentheticalAssertion): + (JSC::Yarr::YarrGenerator::opCompileBody): + * yarr/YarrPattern.cpp: + (JSC::Yarr::CharacterClassConstructor::charClass): + (JSC::Yarr::YarrPatternConstructor::YarrPatternConstructor): + (JSC::Yarr::YarrPatternConstructor::reset): + (JSC::Yarr::YarrPatternConstructor::atomPatternCharacter): + (JSC::Yarr::YarrPatternConstructor::atomCharacterClassEnd): + (JSC::Yarr::YarrPatternConstructor::atomParenthesesSubpatternBegin): + (JSC::Yarr::YarrPatternConstructor::atomParentheticalAssertionBegin): + (JSC::Yarr::YarrPatternConstructor::copyDisjunction): + (JSC::Yarr::YarrPatternConstructor::checkForTerminalParentheses): + (JSC::Yarr::YarrPatternConstructor::optimizeDotStarWrappedExpressions): + * yarr/YarrPattern.h: + (JSC::Yarr::PatternDisjunction::addNewAlternative): + (JSC::Yarr::YarrPattern::newlineCharacterClass): + (JSC::Yarr::YarrPattern::digitsCharacterClass): + (JSC::Yarr::YarrPattern::spacesCharacterClass): + (JSC::Yarr::YarrPattern::wordcharCharacterClass): + (JSC::Yarr::YarrPattern::nondigitsCharacterClass): + (JSC::Yarr::YarrPattern::nonspacesCharacterClass): + (JSC::Yarr::YarrPattern::nonwordcharCharacterClass): + +2014-12-26 Dan Bernstein <mitz@apple.com> + + <rdar://problem/19348208> REGRESSION (r177027): iOS builds use the wrong toolchain + https://bugs.webkit.org/show_bug.cgi?id=139950 + + Reviewed by David Kilzer. + + * Configurations/Base.xcconfig: Only define TOOLCHAINS when building for OS X, doing so + in a manner that works with Xcode 5.1.1. + +2014-12-22 Mark Lam <mark.lam@apple.com> + + Use ctiPatchCallByReturnAddress() in JITOperations.cpp. + <https://webkit.org/b/139892> + + Reviewed by Michael Saboff. + + The code in JITOperations.cpp sometimes calls RepatchBuffer::relinkCallerToFunction() + directly, and sometimes uses a helper function, ctiPatchCallByReturnAddress(). + This patch changes it to use the helper function consistently. + + * jit/JITOperations.cpp: + +2014-12-22 Mark Lam <mark.lam@apple.com> + + Fix some typos in a comment. + <https://webkit.org/b/139882> + + Reviewed by Michael Saboff. + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + +2014-12-22 Mark Lam <mark.lam@apple.com> + + Assert that Array elements not copied when changing shape to ArrayStorage type are indeed holes. + <https://webkit.org/b/138118> + + Reviewed by Michael Saboff. + + * runtime/JSObject.cpp: + (JSC::JSObject::convertInt32ToArrayStorage): + (JSC::JSObject::convertDoubleToArrayStorage): + (JSC::JSObject::convertContiguousToArrayStorage): + +2014-12-20 Eric Carlson <eric.carlson@apple.com> + + [iOS] add optimized fullscreen API + https://bugs.webkit.org/show_bug.cgi?id=139833 + <rdar://problem/18844486> + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: Add ENABLE_VIDEO_PRESENTATION_MODE. + +2014-12-20 David Kilzer <ddkilzer@apple.com> + + Switch from using PLATFORM_NAME to SDK selectors in WebCore, WebInspectorUI, WebKit, WebKit2 + <http://webkit.org/b/139463> + + Reviewed by Mark Rowe. + + * Configurations/JavaScriptCore.xcconfig: + - Simplify SECTORDER_FLAGS. + +2014-12-19 Andreas Kling <akling@apple.com> + + Plug leak below LLVMCopyStringRepOfTargetData(). + <https://webkit.org/b/139832> + + Reviewed by Michael Saboff. + + LLVMCopyStringRepOfTargetData() returns a strdup()'ed string, so make sure + to free() it after we're done using it. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + +2014-12-19 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: CRASH inspector-protocol/debugger/breakpoint-action-detach.html + https://bugs.webkit.org/show_bug.cgi?id=139797 + + Reviewed by Mark Lam. + + * debugger/Debugger.h: + * debugger/Debugger.cpp: + (JSC::Debugger::isAttached): + Check if we are the debugger for a particular global object. + (JSC::Debugger::pauseIfNeeded): + Pass the global object on when hitting a brekapoint. + + * inspector/ScriptDebugServer.h: + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::handleBreakpointHit): + Stop evaluting breakpoint actions if a previous action caused the + debugger to detach from this global object. + (Inspector::ScriptDebugServer::handlePause): + Standardize on passing JSGlobalObject parameter first. + +2014-12-19 Mark Lam <mark.lam@apple.com> + + [Win] Endless compiler warnings created by DFGEdge.h. + <https://webkit.org/b/139801> + + Reviewed by Brent Fulgham. + + Add a cast to fix the type just the way the 64-bit version does. + + * dfg/DFGEdge.h: + (JSC::DFG::Edge::makeWord): + +2014-12-19 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r177574. + https://bugs.webkit.org/show_bug.cgi?id=139821 + + "Broke Production builds by installing + libWebCoreTestSupport.dylib in the wrong directory" (Requested + by ddkilzer on #webkit). + + Reverted changeset: + + "Switch from using PLATFORM_NAME to SDK selectors in WebCore, + WebInspectorUI, WebKit, WebKit2" + https://bugs.webkit.org/show_bug.cgi?id=139463 + http://trac.webkit.org/changeset/177574 + +2014-12-19 Michael Saboff <msaboff@apple.com> + + REGRESSION(174226): Captured arguments in a using function compiled by the DFG have the initial value when the closure was invoked + https://bugs.webkit.org/show_bug.cgi?id=139808 + + Reviewed by Oliver Hunt. + + There are three changes here. + 1) Create a VariableWatchpointSet for captured arguments variables. + 2) Properly use the VariableWatchpointSet* found in op_put_to_scope in the 64 bit LLInt code. + 3) Add the same putLocalClosureVar path to the 32 bit LLInt code that exists in the 64 bit version. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-12-19 David Kilzer <ddkilzer@apple.com> + + Switch from using PLATFORM_NAME to SDK selectors in WebCore, WebInspectorUI, WebKit, WebKit2 + <http://webkit.org/b/139463> + + Reviewed by Mark Rowe. + + * Configurations/JavaScriptCore.xcconfig: + - Simplify SECTORDER_FLAGS. + +2014-12-18 Brent Fulgham <bfulgham@apple.com> + + Unreviewed build fix. + + * jsc.cpp: Remove typo. + +2014-12-17 Michael Saboff <msaboff@apple.com> + + Tests with infinite recursion frequently crash + https://bugs.webkit.org/show_bug.cgi?id=139548 + + Reviewed by Geoffrey Garen. + + While unwinding, if the call frame doesn't have a codeblock, then we + are in native code, handle appropriately. + + * interpreter/Interpreter.cpp: + (JSC::unwindCallFrame): + (JSC::UnwindFunctor::operator()): + Added checks for null CodeBlock. + + (JSC::Interpreter::unwind): Removed wrong ASSERT. + +2014-12-17 Chris Dumez <cdumez@apple.com> + + [iOS] Make it possible to toggle FeatureCounter support at runtime + https://bugs.webkit.org/show_bug.cgi?id=139688 + <rdar://problem/19266254> + + Reviewed by Andreas Kling. + + Stop linking against AppSupport framework as the functionality is no + longer in WTF (it was moved to WebCore). + + * Configurations/JavaScriptCore.xcconfig: + +2014-12-17 Brent Fulgham <bfulgham@apple.com> + + [Win] Correct DebugSuffix builds under MSBuild + https://bugs.webkit.org/show_bug.cgi?id=139733 + <rdar://problem/19276880> + + Reviewed by Simon Fraser. + + * JavaScriptCore.vcxproj/JavaScriptCore.proj: Make sure to use the + '_debug' suffix when building the DebugSuffix target. + +2014-12-16 Enrica Casucci <enrica@apple.com> + + Fix iOS builders for 8.0 + https://bugs.webkit.org/show_bug.cgi?id=139495 + + Reviewed by Michael Saboff. + + * Configurations/LLVMForJSC.xcconfig: + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-12-16 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r177380. + https://bugs.webkit.org/show_bug.cgi?id=139707 + + "Breaks js/regres/elidable-new-object-* tests" (Requested by + msaboff_ on #webkit). + + Reverted changeset: + + "Fixes operationPutByIdOptimizes such that they check that the + put didn't" + https://bugs.webkit.org/show_bug.cgi?id=139500 + http://trac.webkit.org/changeset/177380 + +2014-12-16 Matthew Mirman <mmirman@apple.com> + + Fixes operationPutByIdOptimizes such that they check that the put didn't + change the structure of the object who's property access is being + cached. + https://bugs.webkit.org/show_bug.cgi?id=139500 + + Reviewed by Geoffrey Garen. + + * jit/JITOperations.cpp: + (JSC::operationPutByIdStrictOptimize): saved the structure before the put. + (JSC::operationPutByIdNonStrictOptimize): ditto. + (JSC::operationPutByIdDirectStrictOptimize): ditto. + (JSC::operationPutByIdDirectNonStrictOptimize): ditto. + * jit/Repatch.cpp: + (JSC::tryCachePutByID): Added argument for the old structure + (JSC::repatchPutByID): Added argument for the old structure + * jit/Repatch.h: + * tests/stress/put-by-id-build-list-order-recurse.js: + Added test that fails without this patch. + +2014-12-15 Chris Dumez <cdumez@apple.com> + + [iOS] Add feature counting support + https://bugs.webkit.org/show_bug.cgi?id=139652 + <rdar://problem/19255690> + + Reviewed by Gavin Barraclough. + + Link against AppSupport framework on iOS as we need it to implement + the new FeatureCounter API in WTF. + + * Configurations/JavaScriptCore.xcconfig: + +2014-12-15 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r177284. + https://bugs.webkit.org/show_bug.cgi?id=139658 + + "Breaks API tests and LayoutTests on Yosemite Debug" + (Requested by msaboff on #webkit). + + Reverted changeset: + + "Make sure range based iteration of Vector<> still receives + bounds checking" + https://bugs.webkit.org/show_bug.cgi?id=138821 + http://trac.webkit.org/changeset/177284 + +2014-12-15 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + [EFL] FTL JIT not working on ARM64 + https://bugs.webkit.org/show_bug.cgi?id=139295 + + Reviewed by Michael Saboff. + + Added the missing code for stack unwinding and some additional small fixes + to get FTL working correctly. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLUnwindInfo.cpp: + (JSC::FTL::UnwindInfo::parse): + +2014-12-15 Oliver Hunt <oliver@apple.com> + + Make sure range based iteration of Vector<> still receives bounds checking + https://bugs.webkit.org/show_bug.cgi?id=138821 + + Reviewed by Mark Lam. + + Update code to deal with slightly changed iterator semantics. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::visitChildren): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitComplexPopScopes): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitSwitchIntJump): + * ftl/FTLAbbreviations.h: + (JSC::FTL::mdNode): + (JSC::FTL::buildCall): + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * parser/Parser.h: + (JSC::Scope::Scope): + * runtime/JSArray.cpp: + (JSC::JSArray::setLengthWithArrayStorage): + (JSC::JSArray::sortCompactedVector): + * tools/ProfileTreeNode.h: + (JSC::ProfileTreeNode::dumpInternal): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::matchCharacterClass): + +2014-12-14 Filip Pizlo <fpizlo@apple.com> + + PutLocalSinkingPhase has an invalid assertion about incoming values, because both liveness and deferral analyses are conservative + https://bugs.webkit.org/show_bug.cgi?id=139630 + + Reviewed by Oliver Hunt. + + Replaces a faulty assertion with code to handle an awesome special case. Also adds a lot of + comments that reconstruct my reasoning about this code. I had to work hard to remember how + deferral worked so I wrote my discoveries down. + + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertBottomConstantForUse): + * dfg/DFGPutLocalSinkingPhase.cpp: + * tests/stress/put-local-conservative.js: Added. + (foo): + (.result): + (bar): + +2014-12-14 Andreas Kling <akling@apple.com> + + Replace PassRef with Ref/Ref&& across the board. + <https://webkit.org/b/139587> + + Reviewed by Darin Adler. + + * runtime/Identifier.cpp: + (JSC::Identifier::add): + (JSC::Identifier::add8): + * runtime/Identifier.h: + (JSC::Identifier::add): + * runtime/IdentifierInlines.h: + (JSC::Identifier::add): + +2014-12-12 Matthew Mirman <mmirman@apple.com> + + shiftCountWithArrayStorage should exit to slow path if the object has a sparse map. + https://bugs.webkit.org/show_bug.cgi?id=139598 + <rdar://problem/18779367> + + Reviewed by Filip Pizlo. + + * runtime/JSArray.cpp: + (JSC::JSArray::shiftCountWithArrayStorage): Added check for object having a sparse map. + * tests/stress/sparse_splice.js: Added. + +2014-12-12 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Final clean up OwnPtr in JSC - runtime, ftl, and tool directories + https://bugs.webkit.org/show_bug.cgi?id=139532 + + Reviewed by Mark Lam. + + Final remove OwnPtr, PassOwnPtr in runtime, ftl, and tools directories of JSC. + + * builtins/BuiltinExecutables.h: + * bytecode/CodeBlock.h: + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): + * ftl/FTLAbstractHeap.cpp: + (JSC::FTL::IndexedAbstractHeap::atSlow): + * ftl/FTLAbstractHeap.h: + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLJITFinalizer.h: + * jsc.cpp: + (jscmain): + * parser/Lexer.h: + * runtime/PropertyMapHashTable.h: + (JSC::PropertyTable::clearDeletedOffsets): + (JSC::PropertyTable::addDeletedOffset): + * runtime/PropertyTable.cpp: + (JSC::PropertyTable::PropertyTable): + * runtime/RegExpObject.cpp: + * runtime/SmallStrings.cpp: + * runtime/Structure.cpp: + * runtime/StructureIDTable.cpp: + (JSC::StructureIDTable::StructureIDTable): + (JSC::StructureIDTable::resize): + * runtime/StructureIDTable.h: + * runtime/StructureTransitionTable.h: + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::~VM): + * runtime/VM.h: + * tools/CodeProfile.h: + (JSC::CodeProfile::CodeProfile): + (JSC::CodeProfile::addChild): + +2014-12-11 Dan Bernstein <mitz@apple.com> + + iOS Simulator production build fix. + + * Configurations/JavaScriptCore.xcconfig: Donât use an order file when building for the iOS + Simulator, as we did prior to 177027. + +2014-12-11 Joseph Pecoraro <pecoraro@apple.com> + + Explicitly export somre more RWIProtocol classes. + rdar://problem/19220408 + + Unreviewed build fix. + + * inspector/scripts/codegen/generate_objc_configuration_header.py: + (ObjCConfigurationHeaderGenerator._generate_configuration_interface_for_domains): + * inspector/scripts/codegen/generate_objc_header.py: + (ObjCHeaderGenerator._generate_event_interfaces): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + +2014-12-11 Alexey Proskuryakov <ap@apple.com> + + Explicitly export some RWIProtocol classes + rdar://problem/19220408 + + * inspector/scripts/codegen/generate_objc_header.py: + (ObjCHeaderGenerator._generate_type_interface): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + +2014-12-11 Mark Lam <mark.lam@apple.com> + + Fix broken build after r177146. + https://bugs.webkit.org/show_bug.cgi?id=139533 + + Not reviewed. + + * interpreter/CallFrame.h: + (JSC::ExecState::init): + - Restored CallFrame::init() minus the unused JSScope* arg. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + - Remove JSScope* arg when calling CallFrame::init(). + +2014-12-11 Michael Saboff <msaboff@apple.com> + + REGRESSION: Use of undefined CallFrame::ScopeChain value + https://bugs.webkit.org/show_bug.cgi?id=139533 + + Reviewed by Mark Lam. + + Removed CallFrame::scope() and CallFrame::setScope() and eliminated or changed + all usages of these funcitons. In some cases the scope is passed in or determined + another way. In some cases the scope is used to calculate other values. Lastly + were places where these functions where used that are no longer needed. For + example when making a call, the caller's ScopeChain was copied to the callee's + ScopeChain. This change no longer uses the ScopeChain call frame header slot. + That slot will be removed in a future patch. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * runtime/JSLexicalEnvironment.h: + (JSC::JSLexicalEnvironment::create): + (JSC::JSLexicalEnvironment::JSLexicalEnvironment): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_lexical_environment): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_lexical_environment): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + (JSC::LLInt::handleHostCall): + (JSC::LLInt::setUpCall): + (JSC::LLInt::llint_throw_stack_overflow_error): + Pass the current scope value to the helper operationCreateActivation() and + the call to JSLexicalEnvironment::create() instead of using the stack frame + scope chain value. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + CreateActivation now has a second child, the scope. + + * interpreter/CallFrame.h: + (JSC::ExecState::init): Deleted. This is dead code. + (JSC::ExecState::scope): Deleted. + (JSC::ExecState::setScope): Deleted. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::dumpRegisters): Changed so we didn't access the scope + chain slot. + + (JSC::Interpreter::execute): + (JSC::Interpreter::executeCall): + (JSC::Interpreter::executeConstruct): + Changed process to find JSScope values on the stack or by some other means. + + * runtime/JSWithScope.h: + (JSC::JSWithScope::JSWithScope): Deleted. + Eliminated unused constructor. + + * runtime/StrictEvalActivation.cpp: + (JSC::StrictEvalActivation::StrictEvalActivation): + * runtime/StrictEvalActivation.h: + (JSC::StrictEvalActivation::create): + Changed to pass in the current scope. + +2014-12-10 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use std::unique_ptr instead of OwnPtr in JSC - heap, jit, runtime, and parser directories + https://bugs.webkit.org/show_bug.cgi?id=139351 + + Reviewed by Filip Pizlo. + + As a step to use std::unique_ptr<>, this cleans up OwnPtr and PassOwnPtr. + + * bytecode/SamplingTool.h: + (JSC::SamplingTool::SamplingTool): + * heap/CopiedBlock.h: + (JSC::CopiedBlock::didSurviveGC): + (JSC::CopiedBlock::pin): + * heap/CopiedBlockInlines.h: + (JSC::CopiedBlock::reportLiveBytes): + * heap/GCActivityCallback.h: + * heap/GCThread.cpp: + * heap/Heap.h: + * heap/HeapInlines.h: + (JSC::Heap::markListSet): + * jit/ExecutableAllocator.cpp: + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JIT.h: + * jit/JITThunks.cpp: + (JSC::JITThunks::JITThunks): + (JSC::JITThunks::clearHostFunctionStubs): + * jit/JITThunks.h: + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + * parser/Parser.h: + (JSC::Scope::Scope): + (JSC::Scope::pushLabel): + * parser/ParserArena.cpp: + * parser/ParserArena.h: + (JSC::ParserArena::identifierArena): + * parser/SourceProviderCache.h: + * runtime/CodeCache.h: + * runtime/Executable.h: + * runtime/JSArray.cpp: + (JSC::JSArray::sortVector): + * runtime/JSGlobalObject.h: + +2014-12-10 Geoffrey Garen <ggaren@apple.com> + + Please disable the webkitFirstVersionWithInitConstructorSupport check on Apple TV + https://bugs.webkit.org/show_bug.cgi?id=139501 + + Reviewed by Gavin Barraclough. + + NSVersionOfLinkTimeLibrary only works if you link directly against + JavaScriptCore, which is a bit awkward for our Apple TV client to do. + + It's easy enough just to disable this check on Apple TV, since it has no + backwards compatibility requirement. + + * API/JSWrapperMap.mm: + (supportsInitMethodConstructors): + +2014-12-10 Matthew Mirman <mmirman@apple.com> + + Fixes operationPutByIds such that they check that the put didn't + change the structure of the object who's property access is being + cached. + https://bugs.webkit.org/show_bug.cgi?id=139196 + + Reviewed by Filip Pizlo. + + * jit/JITOperations.cpp: + (JSC::operationGetByIdOptimize): changed get to getPropertySlot + (JSC::operationPutByIdStrictBuildList): saved the structure before the put. + (JSC::operationPutByIdNonStrictBuildList): ditto. + (JSC::operationPutByIdDirectStrictBuildList): ditto. + (JSC::operationPutByIdDirectNonStrictBuildList): ditto. + * jit/Repatch.cpp: + (JSC::tryCachePutByID): fixed structure() to use the existant vm. + (JSC::tryBuildPutByIdList): Added a check that the old structure's id + is the same as the new. + (JSC::buildPutByIdList): Added an argument + * jit/Repatch.h: + (JSC::buildPutByIdList): Added an argument + * tests/stress/put-by-id-strict-build-list-order.js: Added. + +2014-12-10 Csaba Osztrogonác <ossy@webkit.org> + + URTBF after r177030. + + Fix linking failure occured on ARM buildbots: + lib/libjavascriptcore_efl.so.1.11.0: undefined reference to `JSC::Structure::get(JSC::VM&, JSC::PropertyName, unsigned int&)' + + * runtime/NullGetterFunction.cpp: + +2014-12-09 Michael Saboff <msaboff@apple.com> + + DFG Tries using an inner object's getter/setter when one hasn't been defined + https://bugs.webkit.org/show_bug.cgi?id=139229 + + Reviewed by Filip Pizlo. + + Added a new NullGetterFunction singleton class to use for getters and setters that + haven't been set to a user defined value. The NullGetterFunction callReturnUndefined() + and createReturnUndefined() methods return undefined. Changed all null checks of the + getter and setter pointers to the newly added isGetterNull() and isSetterNull() + helper methods. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + Added NullGetterFunction.cpp & .h to build files. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncLookupGetter): + (JSC::objectProtoFuncLookupSetter): + * runtime/PropertyDescriptor.cpp: + (JSC::PropertyDescriptor::setDescriptor): + (JSC::PropertyDescriptor::setAccessorDescriptor): + Changed checking getter and setter to null to use new isGetterNull() and isSetterNull() + helpers. + + * inspector/JSInjectedScriptHostPrototype.cpp: + (Inspector::JSInjectedScriptHostPrototype::finishCreation): + * inspector/JSJavaScriptCallFramePrototype.cpp: + * jit/JITOperations.cpp: + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * runtime/JSObject.cpp: + (JSC::JSObject::putIndexedDescriptor): + (JSC::putDescriptor): + (JSC::JSObject::defineOwnNonIndexProperty): + * runtime/MapPrototype.cpp: + (JSC::MapPrototype::finishCreation): + * runtime/SetPrototype.cpp: + (JSC::SetPrototype::finishCreation): + Updated calls to GetterSetter::create(), setGetter(), setSetter(), withGetter() + and withSetter() to provide a global object. + + * runtime/GetterSetter.cpp: + (JSC::GetterSetter::withGetter): + (JSC::GetterSetter::withSetter): + (JSC::callGetter): + (JSC::callSetter): + * runtime/GetterSetter.h: + (JSC::GetterSetter::GetterSetter): + (JSC::GetterSetter::create): + (JSC::GetterSetter::isGetterNull): + (JSC::GetterSetter::isSetterNull): + (JSC::GetterSetter::setGetter): + (JSC::GetterSetter::setSetter): + Changed to use NullGetterFunction for unspecified getters / setters. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + (JSC::JSGlobalObject::createThrowTypeError): + (JSC::JSGlobalObject::visitChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::nullGetterFunction): + (JSC::JSGlobalObject::evalFunction): + Added m_nullGetterFunction singleton. Updated calls to GetterSetter::create(), + setGetter() and setSetter() to provide a global object. + + * runtime/NullGetterFunction.cpp: Added. + (JSC::callReturnUndefined): + (JSC::constructReturnUndefined): + (JSC::NullGetterFunction::getCallData): + (JSC::NullGetterFunction::getConstructData): + * runtime/NullGetterFunction.h: Added. + (JSC::NullGetterFunction::create): + (JSC::NullGetterFunction::createStructure): + (JSC::NullGetterFunction::NullGetterFunction): + New singleton class that returns undefined when called. + +2014-12-09 Geoffrey Garen <ggaren@apple.com> + + Re-enable function.arguments + https://bugs.webkit.org/show_bug.cgi?id=139452 + <rdar://problem/18848149> + + Reviewed by Sam Weinig. + + Disabling function.arguments broke a few websites, and we don't have + time right now to work through the details. + + I'm re-enabling function.arguments but leaving in the infrastructure + to re-disable it, so we can try this experiment again in the future. + + * runtime/Options.h: + +2014-12-09 David Kilzer <ddkilzer@apple.com> + + Switch from using PLATFORM_NAME to SDK selectors in ANGLE, bmalloc, gtest, JavaScriptCore, WTF + <http://webkit.org/b/139212> + + Reviewed by Joseph Pecoraro. + + * Configurations/Base.xcconfig: + - Only set GCC_ENABLE_OBJC_GC, GCC_MODEL_TUNING and TOOLCHAINS + on OS X. + - Only set LLVM_LOCAL_HEADER_PATH and LLVM_SYSTEM_HEADER_PATH on + OS X. + - Set JAVASCRIPTCORE_CONTENTS_DIR and + JAVASCRIPTCORE_FRAMEWORKS_DIR separately for iOS and OS X. + + * Configurations/DebugRelease.xcconfig: + - Only set MACOSX_DEPLOYMENT_TARGET and SDKROOT on OS X. + + * Configurations/JSC.xcconfig: + - Only set CODE_SIGN_ENTITLEMENTS for iOS hardware builds. + + * Configurations/JavaScriptCore.xcconfig: + - Set OTHER_LDFLAGS separately for iOS and OS X. + - Set SECTORDER_FLAGS separately for iOS and OS X, but only for + Production builds. + - Only set EXCLUDED_SOURCE_FILE_NAMES for iOS. + + * Configurations/LLVMForJSC.xcconfig: + - Rename LLVM_LIBS_iphoneos to LLVM_LIBS_ios. + - Set LLVM_LIBRARY_PATHS and OTHER_LDFLAGS_LLVM_ENABLE_FTL_JIT + separately for iOS hardware and OS X. + - Fix curly braces in LIBRARY_SEARCH_PATHS. + - Merge OTHER_LDFLAGS_BASE into OTHER_LDFLAGS. (Could have been + done before this patch.) + + * Configurations/ToolExecutable.xcconfig: + - Only set CODE_SIGN_ENTITLEMENTS for iOS, per target. + - Only set CLANG_ENABLE_OBJC_ARC for i386 on the iOS Simulator. + - Add missing newline. + + * Configurations/Version.xcconfig: + - Set SYSTEM_VERSION_PREFIX separately for iOS and OS X. + +2014-12-08 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Fix EFL build fix since r177001 + https://bugs.webkit.org/show_bug.cgi?id=139428 + + Unreviewed, EFL build fix. + + Do not inherit duplicated class. ExpressionNode is already + child of ParserArenaFreeable class. + + * parser/Nodes.h: + +2014-12-08 Shivakumar JM <shiva.jm@samsung.com> + + Fix Build Warning in JavaScriptCore ControlFlowProfiler::dumpData() api. + https://bugs.webkit.org/show_bug.cgi?id=139384 + + Reviewed by Mark Lam. + + Fix Build Warning by using dataLog() function instead of dataLogF() function. + + * runtime/ControlFlowProfiler.cpp: + (JSC::ControlFlowProfiler::dumpData): + +2014-12-08 Saam Barati <saambarati1@gmail.com> + + Web Inspector: Enable runtime API for JSC's control flow profiler + https://bugs.webkit.org/show_bug.cgi?id=139346 + + Reviewed by Joseph Pecoraro. + + This patch creates an API that the Web Inspector can use + to get information about which basic blocks have exectued + from JSC's control flow profiler. + + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getBasicBlocks): + * inspector/agents/InspectorRuntimeAgent.h: + * inspector/protocol/Runtime.json: + +2014-12-08 Geoffrey Garen <ggaren@apple.com> + + Removed some allocation and cruft from the parser + https://bugs.webkit.org/show_bug.cgi?id=139416 + + Reviewed by Mark Lam. + + Now, the only AST nodes that require a destructor are the ones that + relate to pickling a function's arguments -- which will required some + deeper thinking to resolve. + + This is a < 1% parser speedup. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: Removed NodeInfo because it + was unused. + + * bytecompiler/NodesCodegen.cpp: + (JSC::CommaNode::emitBytecode): + (JSC::SourceElements::lastStatement): + (JSC::SourceElements::emitBytecode): Updated for interface change to linked list. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::ASTBuilder): + (JSC::ASTBuilder::varDeclarations): + (JSC::ASTBuilder::funcDeclarations): + (JSC::ASTBuilder::createFuncDeclStatement): + (JSC::ASTBuilder::addVar): Removed the ParserArenaData abstraction because + it wasn't buying us anything. We can just use Vector directly. + + (JSC::ASTBuilder::createCommaExpr): + (JSC::ASTBuilder::appendToCommaExpr): Changed to use a linked list instead + of a vector, to avoid allocating a vector with inline capacity in the + common case in which an expression is not followed by a vector. + + (JSC::ASTBuilder::Scope::Scope): Use Vector directly to avoid new'ing + up a Vector*. + + (JSC::ASTBuilder::appendToComma): Deleted. + (JSC::ASTBuilder::combineCommaNodes): Deleted. + + * parser/Lexer.cpp: + + * parser/NodeConstructors.h: + (JSC::StatementNode::StatementNode): + (JSC::CommaNode::CommaNode): + (JSC::SourceElements::SourceElements): Updated for interface change to linked list. + + * parser/NodeInfo.h: Removed. + + * parser/Nodes.cpp: + (JSC::SourceElements::append): + (JSC::SourceElements::singleStatement): Use a linked list instead of a + vector to track the statements in a list. This removes some allocation + and it means that we don't need a destructor anymore. + + (JSC::ScopeNode::ScopeNode): + (JSC::ProgramNode::ProgramNode): + (JSC::EvalNode::EvalNode): + (JSC::FunctionNode::FunctionNode): Updated for interface change to reference, + since these values are never null. + + * parser/Nodes.h: + (JSC::StatementNode::next): + (JSC::StatementNode::setNext): + (JSC::CommaNode::append): Deleted. Updated for interface change to linked list. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::didFinishParsing): Updated for interface change to reference. + + (JSC::Parser<LexerType>::parseVarDeclarationList): + (JSC::Parser<LexerType>::parseExpression): Track comma expressions as + an explicit list of CommaNodes, removing a use of vector and a destructor. + + * parser/Parser.h: + (JSC::Parser<LexerType>::parse): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createCommaExpr): + (JSC::SyntaxChecker::appendToCommaExpr): + (JSC::SyntaxChecker::appendToComma): Deleted. Updated for interface changes. + +2014-12-08 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r176979. + https://bugs.webkit.org/show_bug.cgi?id=139424 + + "New JSC test in this patch is failing" (Requested by mlam on + #webkit). + + Reverted changeset: + + "Fixes operationPutByIds such that they check that the put + didn't" + https://bugs.webkit.org/show_bug.cgi?id=139196 + http://trac.webkit.org/changeset/176979 + +2014-12-08 Matthew Mirman <mmirman@apple.com> + + Fixes operationPutByIds such that they check that the put didn't + change the structure of the object who's property access is being + cached. + https://bugs.webkit.org/show_bug.cgi?id=139196 + + Reviewed by Filip Pizlo. + + * jit/JITOperations.cpp: + (JSC::operationGetByIdOptimize): changed get to getPropertySlot + (JSC::operationPutByIdStrictBuildList): saved the structure before the put. + (JSC::operationPutByIdNonStrictBuildList): ditto. + (JSC::operationPutByIdDirectStrictBuildList): ditto. + (JSC::operationPutByIdDirectNonStrictBuildList): ditto. + * jit/Repatch.cpp: + (JSC::tryCachePutByID): fixed structure() to use the existant vm. + (JSC::tryBuildPutByIdList): Added a check that the old structure's id + is the same as the new. + (JSC::buildPutByIdList): Added an argument + * jit/Repatch.h: + (JSC::buildPutByIdList): Added an argument + * tests/stress/put-by-id-build-list-order-recurse.js: Test that failed before the change + * tests/stress/put-by-id-strict-build-list-order.js: Added. + + +2014-12-08 Anders Carlsson <andersca@apple.com> + + Change WTF::currentCPUTime to return std::chrono::microseconds and get rid of currentCPUTimeMS + https://bugs.webkit.org/show_bug.cgi?id=139410 + + Reviewed by Andreas Kling. + + * API/JSContextRef.cpp: + (JSContextGroupSetExecutionTimeLimit): + (JSContextGroupClearExecutionTimeLimit): + * runtime/Watchdog.cpp: + (JSC::Watchdog::setTimeLimit): + (JSC::Watchdog::didFire): + (JSC::Watchdog::startCountdownIfNeeded): + (JSC::Watchdog::startCountdown): + * runtime/Watchdog.h: + * runtime/WatchdogMac.cpp: + (JSC::Watchdog::startTimer): + +2014-12-08 Mark Lam <mark.lam@apple.com> + + CFA wrongly assumes that a speculation for SlowPutArrayStorageShape disallows ArrayStorageShape arrays. + <https://webkit.org/b/139327> + + Reviewed by Michael Saboff. + + The code generator and runtime slow paths expects otherwise. This patch fixes + CFA to match the code generator's expectation. + + * dfg/DFGArrayMode.h: + (JSC::DFG::ArrayMode::arrayModesThatPassFiltering): + (JSC::DFG::ArrayMode::arrayModesWithIndexingShapes): + +2014-12-08 Chris Dumez <cdumez@apple.com> + + Revert r176293 & r176275 + + Unreviewed, revert r176293 & r176275 changing the Vector API to use unsigned type + instead of size_t. There is some disagreement regarding the long-term direction + of the API and we shouldnât leave the API partly transitioned to unsigned type + while making a decision. + + * bytecode/PreciseJumpTargets.cpp: + * replay/EncodedValue.h: + +2014-12-07 Csaba Osztrogonác <ossy@webkit.org> + + Remove the unused WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND after r129453. + https://bugs.webkit.org/show_bug.cgi?id=139373 + + Reviewed by Sam Weinig. + + * interpreter/Interpreter.cpp: + +2014-12-06 Anders Carlsson <andersca@apple.com> + + Fix build with newer versions of clang. + rdar://problem/18978716 + + * ftl/FTLJITCode.h: + Add missing overrides. + +2014-12-05 Roger Fong <roger_fong@apple.com> + + [Win] proj files copying over too many resources.. + https://bugs.webkit.org/show_bug.cgi?id=139315. + <rdar://problem/19148278> + + Reviewed by Brent Fulgham. + + * JavaScriptCore.vcxproj/JavaScriptCore.proj: Only copy resource folders and JavaScriptCore.dll. + +2014-12-05 Juergen Ributzka <juergen@apple.com> + + [JSC][FTL] Add the data layout to the module and fix the pass order. + https://bugs.webkit.org/show_bug.cgi?id=138748 + + Reviewed by Oliver Hunt. + + This adds the data layout to the module, so it can be used by all + optimization passes in the LLVM optimizer pipeline. This also allows + FastISel to select more instructions, because less non-legal types are + generated. + + Also fix the order of the alias analysis passes in the optimization + pipeline. + + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + +2014-12-05 Geoffrey Garen <ggaren@apple.com> + + Removed an unused function. + + Reviewed by Michael Saboff. + + Broken out from https://bugs.webkit.org/show_bug.cgi?id=139305. + + * parser/ParserArena.h: + +2014-12-05 David Kilzer <ddkilzer@apple.com> + + FeatureDefines.xcconfig: Workaround bug in Xcode 5.1.1 when defining ENABLE_WEB_REPLAY + <http://webkit.org/b/139286> + + Reviewed by Daniel Bates. + + * Configurations/FeatureDefines.xcconfig: Switch back to using + PLATFORM_NAME to workaround a bug in Xcode 5.1.1 on 10.8. + +2014-12-04 Mark Rowe <mrowe@apple.com> + + Build fix after r176836. + + Reviewed by Mark Lam. + + * runtime/VM.h: + (JSC::VM::controlFlowProfiler): Don't try to export an inline function. + Doing so results in a weak external symbol being generated. + +2014-12-04 Saam Barati <saambarati1@gmail.com> + + JavaScript Control Flow Profiler + https://bugs.webkit.org/show_bug.cgi?id=137785 + + Reviewed by Filip Pizlo. + + This patch introduces a mechanism for JavaScriptCore to profile + which basic blocks have executed. This mechanism will then be + used by the Web Inspector to indicate which basic blocks + have and have not executed. + + The profiling works by compiling in an op_profile_control_flow + at the start of every basic block. Then, whenever this op code + executes, we know that a particular basic block has executed. + + When we tier up a CodeBlock that contains an op_profile_control_flow + that corresponds to an already executed basic block, we don't + have to emit code for that particular op_profile_control_flow + because the internal data structures used to keep track of + basic block locations has already recorded that the corresponding + op_profile_control_flow has executed. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + (JSC::CodeBlock::CodeBlock): + * bytecode/Instruction.h: + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::addOpProfileControlFlowBytecodeOffset): + (JSC::UnlinkedCodeBlock::opProfileControlFlowBytecodeOffsets): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitProfileControlFlow): + * bytecompiler/BytecodeGenerator.h: + * bytecompiler/NodesCodegen.cpp: + (JSC::ConditionalNode::emitBytecode): + (JSC::IfElseNode::emitBytecode): + (JSC::WhileNode::emitBytecode): + (JSC::ForNode::emitBytecode): + (JSC::ContinueNode::emitBytecode): + (JSC::BreakNode::emitBytecode): + (JSC::ReturnNode::emitBytecode): + (JSC::CaseClauseNode::emitBytecode): + (JSC::SwitchNode::emitBytecode): + (JSC::ThrowNode::emitBytecode): + (JSC::TryNode::emitBytecode): + (JSC::ProgramNode::emitBytecode): + (JSC::FunctionNode::emitBytecode): + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::basicBlockLocation): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * inspector/agents/InspectorRuntimeAgent.cpp: + (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_profile_control_flow): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_profile_control_flow): + * jsc.cpp: + (GlobalObject::finishCreation): + (functionFindTypeForExpression): + (functionReturnTypeFor): + (functionDumpBasicBlockExecutionRanges): + * llint/LowLevelInterpreter.asm: + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createFunctionExpr): + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createFuncDeclStatement): + (JSC::ASTBuilder::endOffset): + (JSC::ASTBuilder::setStartOffset): + * parser/NodeConstructors.h: + (JSC::Node::Node): + * parser/Nodes.h: + (JSC::CaseClauseNode::setStartOffset): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseSwitchClauses): + (JSC::Parser<LexerType>::parseSwitchDefaultClause): + (JSC::Parser<LexerType>::parseBlockStatement): + (JSC::Parser<LexerType>::parseStatement): + (JSC::Parser<LexerType>::parseFunctionDeclaration): + (JSC::Parser<LexerType>::parseIfStatement): + (JSC::Parser<LexerType>::parseExpression): + (JSC::Parser<LexerType>::parseConditionalExpression): + (JSC::Parser<LexerType>::parseProperty): + (JSC::Parser<LexerType>::parseMemberExpression): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createFunctionExpr): + (JSC::SyntaxChecker::createFuncDeclStatement): + (JSC::SyntaxChecker::createGetterOrSetterProperty): + (JSC::SyntaxChecker::operatorStackPop): + * runtime/BasicBlockLocation.cpp: Added. + (JSC::BasicBlockLocation::BasicBlockLocation): + (JSC::BasicBlockLocation::insertGap): + (JSC::BasicBlockLocation::getExecutedRanges): + (JSC::BasicBlockLocation::dumpData): + (JSC::BasicBlockLocation::emitExecuteCode): + * runtime/BasicBlockLocation.h: Added. + (JSC::BasicBlockLocation::startOffset): + (JSC::BasicBlockLocation::endOffset): + (JSC::BasicBlockLocation::setStartOffset): + (JSC::BasicBlockLocation::setEndOffset): + (JSC::BasicBlockLocation::hasExecuted): + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + * runtime/ControlFlowProfiler.cpp: Added. + (JSC::ControlFlowProfiler::~ControlFlowProfiler): + (JSC::ControlFlowProfiler::getBasicBlockLocation): + (JSC::ControlFlowProfiler::dumpData): + (JSC::ControlFlowProfiler::getBasicBlocksForSourceID): + * runtime/ControlFlowProfiler.h: Added. This class is in + charge of generating BasicBlockLocations and also + providing an interface that the Web Inspector can use to ping + which basic blocks have executed based on the source id of a script. + + (JSC::BasicBlockKey::BasicBlockKey): + (JSC::BasicBlockKey::isHashTableDeletedValue): + (JSC::BasicBlockKey::operator==): + (JSC::BasicBlockKey::hash): + (JSC::BasicBlockKeyHash::hash): + (JSC::BasicBlockKeyHash::equal): + * runtime/Executable.cpp: + (JSC::ProgramExecutable::ProgramExecutable): + (JSC::ProgramExecutable::initializeGlobalProperties): + * runtime/FunctionHasExecutedCache.cpp: + (JSC::FunctionHasExecutedCache::getUnexecutedFunctionRanges): + * runtime/FunctionHasExecutedCache.h: + * runtime/Options.h: + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::logTypesForTypeLocation): + (JSC::TypeProfiler::typeInformationForExpressionAtOffset): + (JSC::TypeProfiler::findLocation): + (JSC::TypeProfiler::dumpTypeProfilerData): + * runtime/TypeProfiler.h: + (JSC::TypeProfiler::functionHasExecutedCache): Deleted. + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::enableProfilerWithRespectToCount): + (JSC::disableProfilerWithRespectToCount): + (JSC::VM::enableTypeProfiler): + (JSC::VM::disableTypeProfiler): + (JSC::VM::enableControlFlowProfiler): + (JSC::VM::disableControlFlowProfiler): + (JSC::VM::dumpTypeProfilerData): + * runtime/VM.h: + (JSC::VM::functionHasExecutedCache): + (JSC::VM::controlFlowProfiler): + +2014-12-04 Filip Pizlo <fpizlo@apple.com> + + printInternal(PrintStream& out, JSC::JITCode::JITType type) ends up dumping a literal %s + https://bugs.webkit.org/show_bug.cgi?id=139274 + + Reviewed by Geoffrey Garen. + + * jit/JITCode.cpp: + (WTF::printInternal): + +2014-12-04 Geoffrey Garen <ggaren@apple.com> + + Removed the concept of ParserArenaRefCounted + https://bugs.webkit.org/show_bug.cgi?id=139277 + + Reviewed by Oliver Hunt. + + This is a step toward a parser speedup. + + Now that we have a clear root node type for each parse tree, there's no + need to have a concept for "I might be refcounted or arena allocated". + Instead, we can just use unique_ptr to manage the tree as a whole. + + * API/JSScriptRef.cpp: + (parseScript): + * builtins/BuiltinExecutables.cpp: + (JSC::BuiltinExecutables::createBuiltinExecutable): Updated for type change. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): Use unique_ptr. No need to call + destroyData() explicitly: the unique_ptr destructor will do everything + we need, as Bjarne intended. + + * parser/NodeConstructors.h: + (JSC::ParserArenaRoot::ParserArenaRoot): + (JSC::ParserArenaRefCounted::ParserArenaRefCounted): Deleted. + + * parser/Nodes.cpp: + (JSC::ScopeNode::ScopeNode): + (JSC::ProgramNode::ProgramNode): + (JSC::EvalNode::EvalNode): + (JSC::FunctionNode::FunctionNode): + (JSC::ProgramNode::create): Deleted. + (JSC::EvalNode::create): Deleted. + (JSC::FunctionNode::create): Deleted. All special create semantics can + just go away now that we play by C++ constructor / destructor rules. + + * parser/Nodes.h: + (JSC::ParserArenaRoot::parserArena): + (JSC::ParserArenaRoot::~ParserArenaRoot): Just a normal class now, which + holds onto the whole parse tree by virtue of owning the arena in which + all the parsed nodes (except for itself) were allocated. + + (JSC::ProgramNode::closedVariables): + (JSC::ParserArenaRefCounted::~ParserArenaRefCounted): Deleted. + + (JSC::ScopeNode::destroyData): Deleted. No need to destroy anything + explicitly anymore -- we can just rely on destructors. + + (JSC::ScopeNode::parserArena): Deleted. + + * parser/Parser.h: + (JSC::Parser<LexerType>::parse): + (JSC::parse): unique_ptr all the things. + + * parser/ParserArena.cpp: + (JSC::ParserArena::reset): + (JSC::ParserArena::isEmpty): + (JSC::ParserArena::contains): Deleted. + (JSC::ParserArena::last): Deleted. + (JSC::ParserArena::removeLast): Deleted. + (JSC::ParserArena::derefWithArena): Deleted. + * parser/ParserArena.h: + (JSC::ParserArena::swap): Much delete. Such wow. + + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + (JSC::CodeCache::getFunctionExecutableFromGlobalCode): + * runtime/Completion.cpp: + (JSC::checkSyntax): + * runtime/Executable.cpp: + (JSC::ProgramExecutable::checkSyntax): unique_ptr all the things. + +2014-12-04 Andreas Kling <akling@apple.com> + + REGRESSION(r173188): Text inserted when trying to delete a word from the Twitter message box. + <https://webkit.org/b/139076> + + Reviewed by Geoffrey Garen. + + The StringImpl* -> Weak<JSString> cache used by the DOM bindings + had a bug where the key could become a stale pointer if the cached + JSString had its internal StringImpl atomicized. + + If a new StringImpl was then later constructed at the exact same + address as the stale key, before the Weak<JSString> got booted out + of the string cache, we'd now have a situation where asking the + string cache for that key would return the old JSString. + + Solve this by not allowing JSString::toExistingAtomicString() to + change the JSString's internal StringImpl unless it's resolving a + rope string. (The StringImpl nullity determines rope state.) + + This means that calling toExistingAtomicString() may now have to + query the AtomicString table on each call rather than just once. + All clients of this API would be forced to do this regardless, + since they return value will be used to key into containers with + AtomicStringImpl* keys. + + No test because this relies on malloc putting two StringImpls + at the same address at different points in time and we have no + mechanism to reliably test that. + + * runtime/JSString.h: + (JSC::JSString::toExistingAtomicString): + +2014-12-04 Geoffrey Garen <ggaren@apple.com> + + Marked some final things final. + + Reviewed by Andreas Kling. + + * parser/Nodes.h: + +2014-12-04 Geoffrey Garen <ggaren@apple.com> + + Split out FunctionNode from FunctionBodyNode + https://bugs.webkit.org/show_bug.cgi?id=139273 + + Reviewed by Andreas Kling. + + This is step toward a parser speedup. + + We used to use FunctionBodyNode for two different purposes: + + (1) "I am the root function you are currently parsing"; + + (2) "I am a lazy record of a nested function, which you will parse later". + + This made for awkward lifetime semantics and interfaces. + + Now, case (1) is handled by FunctionBodyNode, and case (2) is handled by + a new node named FunctionNode. + + Since case (1) no longer needs to handle being the root of the parse + tree, FunctionBodyNode can be a normal arena-allocated node. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::generateFunctionCodeBlock): Use FunctionNode instead of + FunctionBodyNode, since we are producing the root of the function parse + tree. + + (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): Removed + some unused data, and default-initialized other data, which isn't filled + in meaningfully until recordParse() is called. (The previous values were + incorrect / meaningless, since the FunctionBodyNode didn't have + meaningful values in this case.) + + * bytecode/UnlinkedCodeBlock.h: Ditto. + + (JSC::UnlinkedFunctionExecutable::forceUsesArguments): Deleted. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): Use FunctionNode instead of + FunctionBodyNode, since we are generating code starting at the root of + the parse tree. + + (JSC::BytecodeGenerator::resolveCallee): + (JSC::BytecodeGenerator::addCallee): + * bytecompiler/BytecodeGenerator.h: Ditto. + + * bytecompiler/NodesCodegen.cpp: + (JSC::FunctionBodyNode::emitBytecode): + (JSC::FunctionNode::emitBytecode): Moved the emitBytecode implementation + to FunctionNode, since we never generate code for FunctionBodyNode, + since it's just a placeholder in the AST. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createFunctionBody): + (JSC::ASTBuilder::setUsesArguments): Deleted. Updated for interface + changes. + + * parser/Nodes.cpp: + (JSC::FunctionBodyNode::FunctionBodyNode): + (JSC::FunctionBodyNode::finishParsing): + (JSC::FunctionBodyNode::setEndPosition): + (JSC::FunctionNode::FunctionNode): + (JSC::FunctionNode::create): + (JSC::FunctionNode::finishParsing): + (JSC::FunctionBodyNode::create): Deleted. + + * parser/Nodes.h: + (JSC::FunctionBodyNode::parameters): + (JSC::FunctionBodyNode::source): + (JSC::FunctionBodyNode::startStartOffset): + (JSC::FunctionBodyNode::isInStrictContext): + (JSC::FunctionNode::parameters): + (JSC::FunctionNode::ident): + (JSC::FunctionNode::functionMode): + (JSC::FunctionNode::startColumn): + (JSC::FunctionNode::endColumn): + (JSC::ScopeNode::setSource): Deleted. + (JSC::FunctionBodyNode::parameterCount): Deleted. Split out the differences + between FunctionNode and FunctionBodyNode. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createClauseList): + (JSC::SyntaxChecker::setUsesArguments): Deleted. Removed setUsesArguments + since it wasn't used. + + * runtime/Executable.cpp: + (JSC::ProgramExecutable::checkSyntax): Removed a branch that was always + false. + +2014-12-02 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: timeline probe records have inaccurate per-probe hit counts + https://bugs.webkit.org/show_bug.cgi?id=138976 + + Reviewed by Joseph Pecoraro. + + Previously, the DebuggerAgent was responsible for assigning unique ids to samples. + However, this makes it impossible for the frontend's Timeline manager to associate + a Probe Sample timeline record with the corresponding probe sample data. The record + only included the probe batchId (misnamed as hitCount in ScriptDebugServer). + + This patch moves both the batchId and sampleId counters into ScriptDebugServer, so + any client of ScriptDebugListener will get the correct sampleId for each sample. + + * inspector/ScriptDebugListener.h: + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::ScriptDebugServer): + (Inspector::ScriptDebugServer::dispatchBreakpointActionProbe): + (Inspector::ScriptDebugServer::handleBreakpointHit): + * inspector/ScriptDebugServer.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::InspectorDebuggerAgent): + (Inspector::InspectorDebuggerAgent::breakpointActionProbe): + * inspector/agents/InspectorDebuggerAgent.h: + +2014-12-04 Oliver Hunt <oliver@apple.com> + + Serialization of MapData object provides unsafe access to internal types + https://bugs.webkit.org/show_bug.cgi?id=138653 + + Reviewed by Geoffrey Garen. + + Converting these ASSERTs into RELEASE_ASSERTs, as it is now obvious + that despite trying hard to be safe in all cases it's simply to easy + to use an iterator in an unsafe state. + + * runtime/MapData.h: + (JSC::MapData::const_iterator::key): + (JSC::MapData::const_iterator::value): + +2014-12-03 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Move JavaScriptCore/dfg to std::unique_ptr + https://bugs.webkit.org/show_bug.cgi?id=139169 + + Reviewed by Filip Pizlo. + + Use std::unique_ptr<>|std::make_unique<> in JavaScriptCore/dfg directory. + + * dfg/DFGBasicBlock.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::JITCompiler): + (JSC::DFG::JITCompiler::compile): + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::compileFunction): + (JSC::DFG::JITCompiler::linkFunction): + * dfg/DFGJITCompiler.h: + * dfg/DFGPlan.cpp: + (JSC::DFG::Plan::compileInThreadImpl): + (JSC::DFG::Plan::cancel): + * dfg/DFGPlan.h: + * dfg/DFGSlowPathGenerator.h: + * dfg/DFGWorklist.h: + * ftl/FTLFail.cpp: + (JSC::FTL::fail): + * ftl/FTLState.cpp: + (JSC::FTL::State::State): + +2014-12-03 Michael Saboff <msaboff@apple.com> + + REGRESSION (r176479): DFG ASSERTION beneath emitOSRExitCall running Kraken/imaging-gaussian-blur.js.ftl-no-cjit-osr-validation and other tests + https://bugs.webkit.org/show_bug.cgi?id=139246 + + Reviewed by Geoffrey Garen. + + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::buildExitArguments): + The DFG_ASSERT that checks liveness at exit time doesn't properly + handle the case where the local is not available at OSR exit time, + but the local is live in the bytecode. This now happens with the + allocated scope register when we are compiling for FTLForOSREntryMode + due to DCE done when the control flow was changed and a new entrypoint + was added in the OSR entrypoint creation phase. Therefore we silence + the assert when compiling for FTLForOSREntryMode. + +2014-12-03 Geoffrey Garen <ggaren@apple.com> + + Removed the global parser arena + https://bugs.webkit.org/show_bug.cgi?id=139236 + + Reviewed by Sam Weinig. + + Simplifies parser lifetime logic. + + There's no need to keep a global arena. We can create a new arena + each time we parse. + + * bytecompiler/BytecodeGenerator.h: Global replace to pass around a + ParserArena instead of VM*, since the VM no longer owns the arena. + (JSC::BytecodeGenerator::parserArena): + + * bytecompiler/NodesCodegen.cpp: Ditto. + (JSC::ArrayNode::toArgumentList): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + * parser/ASTBuilder.h: Ditto. + (JSC::ASTBuilder::ASTBuilder): + (JSC::ASTBuilder::createSourceElements): + (JSC::ASTBuilder::createCommaExpr): + (JSC::ASTBuilder::createLogicalNot): + (JSC::ASTBuilder::createUnaryPlus): + (JSC::ASTBuilder::createVoid): + (JSC::ASTBuilder::thisExpr): + (JSC::ASTBuilder::createResolve): + (JSC::ASTBuilder::createObjectLiteral): + (JSC::ASTBuilder::createArray): + (JSC::ASTBuilder::createNumberExpr): + (JSC::ASTBuilder::createString): + (JSC::ASTBuilder::createBoolean): + (JSC::ASTBuilder::createNull): + (JSC::ASTBuilder::createBracketAccess): + (JSC::ASTBuilder::createDotAccess): + (JSC::ASTBuilder::createSpreadExpression): + (JSC::ASTBuilder::createRegExp): + (JSC::ASTBuilder::createNewExpr): + (JSC::ASTBuilder::createConditionalExpr): + (JSC::ASTBuilder::createAssignResolve): + (JSC::ASTBuilder::createFunctionExpr): + (JSC::ASTBuilder::createFunctionBody): + (JSC::ASTBuilder::createGetterOrSetterProperty): + (JSC::ASTBuilder::createArguments): + (JSC::ASTBuilder::createArgumentsList): + (JSC::ASTBuilder::createProperty): + (JSC::ASTBuilder::createPropertyList): + (JSC::ASTBuilder::createElementList): + (JSC::ASTBuilder::createFormalParameterList): + (JSC::ASTBuilder::createClause): + (JSC::ASTBuilder::createClauseList): + (JSC::ASTBuilder::createFuncDeclStatement): + (JSC::ASTBuilder::createBlockStatement): + (JSC::ASTBuilder::createExprStatement): + (JSC::ASTBuilder::createIfStatement): + (JSC::ASTBuilder::createForLoop): + (JSC::ASTBuilder::createForInLoop): + (JSC::ASTBuilder::createForOfLoop): + (JSC::ASTBuilder::createEmptyStatement): + (JSC::ASTBuilder::createVarStatement): + (JSC::ASTBuilder::createEmptyVarExpression): + (JSC::ASTBuilder::createReturnStatement): + (JSC::ASTBuilder::createBreakStatement): + (JSC::ASTBuilder::createContinueStatement): + (JSC::ASTBuilder::createTryStatement): + (JSC::ASTBuilder::createSwitchStatement): + (JSC::ASTBuilder::createWhileStatement): + (JSC::ASTBuilder::createDoWhileStatement): + (JSC::ASTBuilder::createLabelStatement): + (JSC::ASTBuilder::createWithStatement): + (JSC::ASTBuilder::createThrowStatement): + (JSC::ASTBuilder::createDebugger): + (JSC::ASTBuilder::createConstStatement): + (JSC::ASTBuilder::appendConstDecl): + (JSC::ASTBuilder::combineCommaNodes): + (JSC::ASTBuilder::createDeconstructingAssignment): + (JSC::ASTBuilder::Scope::Scope): + (JSC::ASTBuilder::createNumber): + (JSC::ASTBuilder::makeTypeOfNode): + (JSC::ASTBuilder::makeDeleteNode): + (JSC::ASTBuilder::makeNegateNode): + (JSC::ASTBuilder::makeBitwiseNotNode): + (JSC::ASTBuilder::makeMultNode): + (JSC::ASTBuilder::makeDivNode): + (JSC::ASTBuilder::makeModNode): + (JSC::ASTBuilder::makeAddNode): + (JSC::ASTBuilder::makeSubNode): + (JSC::ASTBuilder::makeLeftShiftNode): + (JSC::ASTBuilder::makeRightShiftNode): + (JSC::ASTBuilder::makeURightShiftNode): + (JSC::ASTBuilder::makeBitOrNode): + (JSC::ASTBuilder::makeBitAndNode): + (JSC::ASTBuilder::makeBitXOrNode): + (JSC::ASTBuilder::makeFunctionCallNode): + (JSC::ASTBuilder::makeBinaryNode): + (JSC::ASTBuilder::makeAssignNode): + (JSC::ASTBuilder::makePrefixNode): + (JSC::ASTBuilder::makePostfixNode): + + * parser/NodeConstructors.h: Ditto. + (JSC::ParserArenaFreeable::operator new): + (JSC::ParserArenaDeletable::operator new): + (JSC::ParserArenaRefCounted::ParserArenaRefCounted): + + * parser/Nodes.cpp: Ditto. + (JSC::ScopeNode::ScopeNode): + (JSC::ProgramNode::ProgramNode): + (JSC::ProgramNode::create): + (JSC::EvalNode::EvalNode): + (JSC::EvalNode::create): + (JSC::FunctionBodyNode::FunctionBodyNode): + (JSC::FunctionBodyNode::create): + + * parser/Nodes.h: Ditto. + (JSC::ScopeNode::parserArena): + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::Parser): + (JSC::Parser<LexerType>::parseInner): + (JSC::Parser<LexerType>::parseProperty): The parser now owns its own + arena, and transfers ownership of its contents when invoking the ScopeNode + constructor. + + * parser/Parser.h: + (JSC::Parser<LexerType>::parse): No need to explicitly reset the arena, + since its lifetime is tied to the parser's lifetime now. + + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createProperty): + (JSC::SyntaxChecker::createGetterOrSetterProperty): + + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: The point of the patch: no more global. + +2014-12-03 Geoffrey Garen <ggaren@apple.com> + + The parser should allocate all pieces of the AST + https://bugs.webkit.org/show_bug.cgi?id=139230 + + Reviewed by Oliver Hunt. + + This is a step toward a 14% parsing speedup. + + Previously, allocation was split between the parser and certain node + constructor functions. This made for some duplicated code and circular + dependencies. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::createGetterOrSetterProperty): No need to pass through + the VM, since our callee no longer needs to allocate anything. + + (JSC::ASTBuilder::createProperty): Allocate the identifier for our + callee, since that is simpler than requiring our callee to notice that + we didn't do so, and do it for us. + + (JSC::ASTBuilder::createForInLoop): Allocate the DeconstructingAssignmentNode + for our callee, since that is simpler than requiring our callee to notice + that we didn't do so, and do it for us. + + Also, reuse some code instead of duplicating it. + + (JSC::ASTBuilder::createForOfLoop): Ditto. + + (JSC::ASTBuilder::createArrayPattern): + (JSC::ASTBuilder::createObjectPattern): + (JSC::ASTBuilder::createBindingLocation): No need to pass through a VM + pointer, since our callee no longer needs to allocate anything. + + (JSC::ASTBuilder::createBreakStatement): Deleted. + (JSC::ASTBuilder::createContinueStatement): Deleted. + + * parser/NodeConstructors.h: + (JSC::PropertyNode::PropertyNode): + (JSC::DeconstructionPatternNode::DeconstructionPatternNode): + (JSC::ArrayPatternNode::ArrayPatternNode): + (JSC::ArrayPatternNode::create): + (JSC::ObjectPatternNode::ObjectPatternNode): + (JSC::ObjectPatternNode::create): + (JSC::BindingNode::create): + (JSC::BindingNode::BindingNode): + (JSC::ContinueNode::ContinueNode): Deleted. + (JSC::BreakNode::BreakNode): Deleted. + (JSC::EnumerationNode::EnumerationNode): Deleted. + (JSC::ForInNode::ForInNode): Deleted. + (JSC::ForOfNode::ForOfNode): Deleted. Deleted a bunch of special cases + that don't exist anymore, now that the parser allocates all pieces of + the AST unconditionally. + + * parser/Nodes.h: Ditto. + + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseBreakStatement): + (JSC::Parser<LexerType>::parseContinueStatement): Allocate the null + identifier for our callee, since that is simpler than requiring our + callee to notice that we didn't do so, and do it for us. + + (JSC::Parser<LexerType>::parseProperty): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::createProperty): No need to pass through a VM + pointer, since our callee no longer needs to allocate anything. + +2014-12-03 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com> + + Remove unused JSC runtime options + https://bugs.webkit.org/show_bug.cgi?id=133070 + + Reviewed by Csaba Osztrogonác. + + * runtime/Options.h: + +2014-12-02 Mark Lam <mark.lam@apple.com> + + Rolling out r176592, r176603, r176616, and r176705 until build and perf issues are resolved. + https://bugs.webkit.org/show_bug.cgi?id=138821 + + Not reviewed. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::visitChildren): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitComplexPopScopes): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitSwitchIntJump): + * ftl/FTLAbbreviations.h: + (JSC::FTL::mdNode): + (JSC::FTL::buildCall): + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * parser/Parser.h: + (JSC::Scope::Scope): + * runtime/JSArray.cpp: + (JSC::JSArray::setLengthWithArrayStorage): + (JSC::JSArray::sortCompactedVector): + * tools/ProfileTreeNode.h: + (JSC::ProfileTreeNode::dumpInternal): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::matchCharacterClass): + +2014-12-02 Michael Saboff <msaboff@apple.com> + + Change CallFrame::globalThisValue() to not use CallFrame::scope() + https://bugs.webkit.org/show_bug.cgi?id=139202 + + Reviewed by Mark Lam. + + Changed to use the globalThis() on the globalObject associated with the + callee. Moved the inline definition to JSGlobalObject.h instead of + including JSGlobalObject.h in JSScope.h. Also moved it as JSScope + objects are no longer involved in getting the value. + + * runtime/JSGlobalObject.h: + (JSC::ExecState::globalThisValue): + * runtime/JSScope.h: + (JSC::ExecState::globalThisValue): Deleted. + +2014-12-02 Matthew Mirman <mmirman@apple.com> + + Fixes inline cache fast path accessing nonexistant getters. + <rdar://problem/18416918> + https://bugs.webkit.org/show_bug.cgi?id=136961 + + Reviewed by Filip Pizlo. + + Fixes a bug in inline caching where getters would have been able to + modify the property they are getting during + building the inline cache and then accessing that + property through the inline cache site causing a recursive + inline cache building and allowing the fast path of the cache to + try to load a getter for the property that no longer exists. + + * jit/JITOperations.cpp: Switched use of get to getPropertySlot. + * runtime/JSCJSValue.h: + added getPropertySlot for when you don't want to perform the get quite yet but want + to fill out the slot. + * runtime/JSCJSValueInlines.h: Added implementation for getPropertySlot + (JSC::JSValue::get): changed to simply call getPropertySlot + (JSC::JSValue::getPropertySlot): added. + * tests/stress/recursive_property_redefine_during_inline_caching.js: Added test case for bug. + (test): + +2014-12-01 Michael Saboff <msaboff@apple.com> + + Remove GetMyScope node from DFG + https://bugs.webkit.org/show_bug.cgi?id=139166 + + Reviewed by Oliver Hunt. + + Eliminated GetMyScope DFG node type. + + * dfg/DFGAbstractInterpreterInlines.h: + (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): + * dfg/DFGClobberize.h: + (JSC::DFG::clobberize): + * dfg/DFGDoesGC.cpp: + (JSC::DFG::doesGC): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::isLiveInBytecode): + * dfg/DFGNodeType.h: + * dfg/DFGPredictionPropagationPhase.cpp: + (JSC::DFG::PredictionPropagationPhase::propagate): + * dfg/DFGSafeToExecute.h: + (JSC::DFG::safeToExecute): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * ftl/FTLCapabilities.cpp: + (JSC::FTL::canCompile): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileNode): + (JSC::FTL::LowerDFGToLLVM::compileGetMyScope): Deleted. + +2014-12-01 Michael Saboff <msaboff@apple.com> + + Crash (integer overflow) beneath ByteCodeParser::handleGetById typing in search field on weather.com + https://bugs.webkit.org/show_bug.cgi?id=139165 + + Reviewed by Oliver Hunt. + + If we don't have any getById or putById variants, emit non-cached versions of these operations. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::handleGetById): + (JSC::DFG::ByteCodeParser::handlePutById): + +2014-12-01 Andreas Kling <akling@apple.com> + + Optimize constructing JSC::Identifier from AtomicString. + <https://webkit.org/b/139157> + + Reviewed by Michael Saboff. + + Add constructors for Identifier taking AtomicString and AtomicStringImpl. + This avoids branching on the string's isAtomic flag, which is obviously + always true for AtomicString & AtomicStringImpl. + + Had to add a Identifier(const char*) constructor to resolve implicit + ambiguity between String / AtomicString. + + Also made PrivateName::uid() return AtomicStringImpl* to take advantage + of the new constructor in a few places. + + * runtime/Identifier.h: + (JSC::Identifier::Identifier): + * runtime/IdentifierInlines.h: + (JSC::Identifier::Identifier): + * runtime/PrivateName.h: + (JSC::PrivateName::uid): + +2014-12-01 Alexey Proskuryakov <ap@apple.com> + + Several JavaScriptCore date tests are flaky, because they expect time to be frozen during execution + https://bugs.webkit.org/show_bug.cgi?id=139138 + + Reviewed by Mark Lam. + + Merged a fix by Bob Clary. + + * tests/mozilla/ecma/Date/15.9.1.1-1.js: + * tests/mozilla/ecma/Date/15.9.1.1-2.js: + * tests/mozilla/ecma/Date/15.9.2.1.js: + * tests/mozilla/ecma/Date/15.9.2.2-1.js: + * tests/mozilla/ecma/Date/15.9.2.2-2.js: + * tests/mozilla/ecma/Date/15.9.2.2-3.js: + * tests/mozilla/ecma/Date/15.9.2.2-4.js: + * tests/mozilla/ecma/Date/15.9.2.2-5.js: + * tests/mozilla/ecma/Date/15.9.2.2-6.js: + +2014-11-17 Oliver Hunt <oliver@apple.com> + + Make sure range based iteration of Vector<> still receives bounds checking + https://bugs.webkit.org/show_bug.cgi?id=138821 + + Reviewed by Mark Lam. + + There are a few uses of begin()/end() that explicitly require pointers, + so we use getPtr() to extract the underlying pointer generically. + + * bytecode/UnlinkedCodeBlock.cpp: + (JSC::UnlinkedCodeBlock::visitChildren): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitComplexPopScopes): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitSwitchIntJump): + * ftl/FTLAbbreviations.h: + (JSC::FTL::mdNode): + (JSC::FTL::buildCall): + * llint/LLIntData.cpp: + (JSC::LLInt::Data::performAssertions): + * parser/Parser.h: + (JSC::Scope::Scope): + * profiler/ProfileNode.cpp: + (JSC::ProfileNode::debugPrintRecursively): + * runtime/JSArray.cpp: + (JSC::JSArray::setLengthWithArrayStorage): + (JSC::JSArray::sortCompactedVector): + * tools/ProfileTreeNode.h: + (JSC::ProfileTreeNode::dumpInternal): + * yarr/YarrJIT.cpp: + (JSC::Yarr::YarrGenerator::matchCharacterClass): + +2014-11-29 Andreas Kling <akling@apple.com> + + PropertyTable keys should be AtomicStringImpl. + <https://webkit.org/b/139096> + + Reviewed by Sam Weinig. + + Since PropertyTable keys are really always Identifiers, switch the key + type from StringImpl* to AtomicStringImpl*. + + We have code in the GetByVal opcode implementations that assumes things + about this, so this change adds confidence to those algorithms. + + * bytecode/ComplexGetStatus.cpp: + (JSC::ComplexGetStatus::computeFor): + * bytecode/ComplexGetStatus.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeFromLLInt): + (JSC::GetByIdStatus::computeFor): + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/GetByIdStatus.h: + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeFromLLInt): + (JSC::PutByIdStatus::computeFor): + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.h: + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): + * dfg/DFGDesiredIdentifiers.cpp: + (JSC::DFG::DesiredIdentifiers::addLazily): + (JSC::DFG::DesiredIdentifiers::at): + * dfg/DFGDesiredIdentifiers.h: + (JSC::DFG::DesiredIdentifiers::operator[]): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::isStringPrototypeMethodSane): + * runtime/Identifier.h: + (JSC::Identifier::impl): + * runtime/IntendedStructureChain.cpp: + (JSC::IntendedStructureChain::mayInterceptStoreTo): + * runtime/IntendedStructureChain.h: + * runtime/PropertyMapHashTable.h: + * runtime/Structure.cpp: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::Structure::addPropertyTransitionToExistingStructureImpl): + (JSC::Structure::addPropertyTransitionToExistingStructureConcurrently): + (JSC::Structure::getConcurrently): + (JSC::Structure::add): + (JSC::Structure::remove): + * runtime/Structure.h: + (JSC::PropertyMapEntry::PropertyMapEntry): + * runtime/StructureInlines.h: + (JSC::Structure::getConcurrently): + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTable::Hash::hash): + +2014-11-28 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use std::unique_ptr<>|make_unique<> in ftl, bytecode of JSC + https://bugs.webkit.org/show_bug.cgi?id=139063 + + Reviewed by Andreas Kling. + + Clean up OwnPtr and PassOwnPtr in JSC. + + * bytecode/StructureStubClearingWatchpoint.cpp: + (JSC::StructureStubClearingWatchpoint::push): + * bytecode/StructureStubClearingWatchpoint.h: + (JSC::StructureStubClearingWatchpoint::StructureStubClearingWatchpoint): + * ftl/FTLCompile.cpp: + (JSC::FTL::mmAllocateDataSection): + * ftl/FTLJITFinalizer.h: + * ftl/FTLLink.cpp: + (JSC::FTL::link): + * parser/SourceProviderCacheItem.h: + +2014-11-27 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use std::unique_ptr instead of OwnPtr in JSC classes + https://bugs.webkit.org/show_bug.cgi?id=139009 + + Reviewed by Filip Pizlo. + + As a step of using std::unique_ptr<>, this patch replaces OwnPtr with + std::unique_ptr<>|std::make_unique<>. + + * bytecode/DFGExitProfile.cpp: + (JSC::DFG::ExitProfile::add): + * bytecode/DFGExitProfile.h: + * bytecode/LazyOperandValueProfile.cpp: + (JSC::CompressedLazyOperandValueProfileHolder::add): + * bytecode/LazyOperandValueProfile.h: + * heap/MarkedBlock.cpp: + (JSC::MarkedBlock::specializedSweep): + (JSC::MarkedBlock::stopAllocating): + * heap/MarkedBlock.h: + (JSC::MarkedBlock::clearNewlyAllocated): + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::findMagicComment): + * runtime/RegExp.cpp: + (JSC::RegExp::invalidateCode): + * runtime/RegExp.h: + * yarr/RegularExpression.cpp: + (JSC::Yarr::RegularExpression::Private::compile): + (JSC::Yarr::RegularExpression::isValid): + * yarr/YarrInterpreter.cpp: + (JSC::Yarr::ByteCompiler::compile): + (JSC::Yarr::ByteCompiler::regexBegin): + (JSC::Yarr::byteCompile): + * yarr/YarrInterpreter.h: + (JSC::Yarr::BytecodePattern::BytecodePattern): + +2014-11-24 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Clean up OwnPtr and PassOwnPtr in JSC - bytecode, jit, inspector, and interpreter + https://bugs.webkit.org/show_bug.cgi?id=139022 + + Reviewed by Filip Pizlo. + + As a step of using std::unique_ptr<>, this patch replaces OwnPtr with + std::unique_ptr<>|std::make_unique<>. + + * bytecode/DFGExitProfile.cpp: + (JSC::DFG::ExitProfile::add): + * bytecode/DFGExitProfile.h: + * dfg/DFGJITCompiler.cpp: + (JSC::DFG::JITCompiler::link): + (JSC::DFG::JITCompiler::linkFunction): + * dfg/DFGJITFinalizer.cpp: + (JSC::DFG::JITFinalizer::JITFinalizer): + * dfg/DFGJITFinalizer.h: + * heap/IncrementalSweeper.h: + * inspector/ContentSearchUtilities.cpp: + (Inspector::ContentSearchUtilities::findMagicComment): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/JSGlobalObjectRuntimeAgent.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::enableSampler): + * interpreter/Interpreter.h: + * jit/ExecutableAllocator.cpp: + (JSC::ExecutableAllocator::ExecutableAllocator): + * jit/ExecutableAllocator.h: + +2014-11-22 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Clean up OwnPtr and PassOwnPtr in some of JS classes + https://bugs.webkit.org/show_bug.cgi?id=138724 + + Reviewed by Filip Pizlo. + + As a step to use std::unique_ptr<> and std::make_unique<>, this patch replaces + OwnPtr with std::unique_ptr<>. Besides create() factory function is removed as well. + + * builtins/BuiltinExecutables.h: + (JSC::BuiltinExecutables::create): Deleted. + * bytecode/CodeBlock.h: + (JSC::CodeBlock::createRareDataIfNecessary): + * bytecode/StructureStubInfo.h: + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::hasRareData): + (JSC::UnlinkedCodeBlock::createRareDataIfNecessary): + * runtime/CodeCache.cpp: + (JSC::CodeCache::getGlobalCodeBlock): + * runtime/CodeCache.h: + (JSC::CodeCache::create): Deleted. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::clearRareData): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::createRareDataIfNeeded): + * runtime/RegExpConstructor.h: + * runtime/SmallStrings.cpp: + (JSC::SmallStrings::createSingleCharacterString): + (JSC::SmallStrings::singleCharacterStringRep): + * runtime/SmallStrings.h: + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + +2014-11-21 Michael Saboff <msaboff@apple.com> + + r176455: ASSERT(!m_vector.isEmpty()) in IntendedStructureChain.cpp(143) + https://bugs.webkit.org/show_bug.cgi?id=139000 + + Reviewed by Darin Adler. + + Check that the chainCount is non-zero before using a StructureChain. + + * bytecode/ComplexGetStatus.cpp: + (JSC::ComplexGetStatus::computeFor): + +2014-11-21 Michael Saboff <msaboff@apple.com> + + Allocate local ScopeChain register + https://bugs.webkit.org/show_bug.cgi?id=138793 + + Reviewed by Geoffrey Garen. + + Now we allocate the scope register as a local. The allocated register is stored in the + CodeBlock for use by other components. Update the DFG to work with a local scope register. + Changed usage of JSStack::ScopeChain access to the CallFrame header to use the allocated + local register. + + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + Updated to properly represent the operand inputs and bytecode result. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::setScopeRegister): + (JSC::CodeBlock::scopeRegister): + * bytecode/UnlinkedCodeBlock.h: + (JSC::UnlinkedCodeBlock::setScopeRegister): + (JSC::UnlinkedCodeBlock::scopeRegister): + Added scope register member and accessors. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::allocateAndEmitScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::scopeRegister): + Change m_scopeRegister to an allocated register. Added allocateAndEmitScope helper to + allocate the scope register, set the CodeBlock with its value and emit op_get_scope. + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::scope): Changed to access the scope using the new convention. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::get): + (JSC::DFG::ByteCodeParser::flush): + (JSC::DFG::ByteCodeParser::inlineCall): + (JSC::DFG::ByteCodeParser::parseBlock): + Changed op_create_lexical_environment to set the scope VirtualRegister operand. + Filled out op_get_scope processing to emit a GetScope node putting the result in + the scope VirtualRegister result operand. + Added Phantoms where appropriate to keep the Scope register alive in places where + it use is optimized away, but where the baseline JIT would need to use its value. + Eliminated uses of JSStack::ScopeChain. + + * dfg/DFGStackLayoutPhase.cpp: + (JSC::DFG::StackLayoutPhase::run): + Make sure that the scope register stack location is allocated using the same place + that the codeBlock expects. + + * dfg/DFGStrengthReductionPhase.cpp: + (JSC::DFG::StrengthReductionPhase::handleNode): + Allow strength reduction of Flush to skip of GetScope nodes looking for a prior + corresponding SetLocal. + + * interpreter/CallFrame.h: + (JSC::ExecState::scope): + (JSC::ExecState::setScope): + Added new scope() and setScope() helpers that take a VirtualRegister offset. + + * interpreter/Interpreter.cpp: + (JSC::eval): + Changed eval() to get the scope from the caller's scope register instead of from the + temporary frame created for eval. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::unwind): + Changed unwind() to manipulate the scope n the allocated register instead of from the + call frame slot. + + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::readNonInlinedFrame): + (JSC::StackVisitor::readInlinedFrame): + * interpreter/StackVisitor.h: + (JSC::StackVisitor::Frame::callee): + (JSC::StackVisitor::Frame::scope): Deleted. + Eliminated the scope member as it needed to change and no StackVisitor users use it. + + * jit/JITOperations.cpp: + (JSC::operationPushNameScope): + (JSC::operationPushWithScope): + * runtime/JSNameScope.h: + (JSC::JSNameScope::create): + * runtime/JSWithScope.h: + (JSC::JSWithScope::create): Deleted. + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + Deleted JSNameScope::create() and JSWithScope::create() flavors tht used the ScopeChain slot + in the CallFrame header. Changed the only user of these function, op_push_name_scope and + op_push_with_scope helpers, to use the remaining create variants that require explicit scope. + Those operations get the scope from the register pointed to by their scope operands. + + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Changed resolveScope to use the allocated register. + +2014-11-21 Csaba Osztrogonác <ossy@webkit.org> + + [JSC] Disable verifyHeap + https://bugs.webkit.org/show_bug.cgi?id=138962 + + Reviewed by Mark Lam. + + * runtime/Options.h: + +2014-11-20 Mark Lam <mark.lam@apple.com> + + Add some comments to describe the DFG UseKind representations. + <https://webkit.org/b/138934> + + Reviewed by Filip Pizlo. + + * dfg/DFGUseKind.h: + - Also regrouped the UseKind enums by representation to be more readable. + +2014-11-20 Mark Lam <mark.lam@apple.com> + + Add Heap verification infrastructure. + <https://webkit.org/b/138851> + + Reviewed by Geoffrey Garen. + + The verification infrastructure code is always built in but disabled by + default. When disabled, the cost is minimal: + 1. Heap has a m_verifier field. + 2. GC does a few "if (m_verifier)" checks that should fail. + 3. HeapVerifier takes up code space though not used. + + When enabled: + 1. The HeapVerifier will keep N number of GC cycle data. + Each GC cycle will contain a "before marking" and "after marking" live + object list. + The GC cycles is a circular buffer. Only data for the last N GC cycles + will be retained. + 2. During GC, the current GC cycle's live objects lists will be populated + before and after marking. + 3. The current GC cycle's live object lists will be validated before GC, + after marking, and after GC. + + Currently, the only validation being done is to verify that object + butterflies are allocated from valid blocks in the Storage (aka Copied) + space. + + * CMakeLists.txt: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::collect): + * heap/Heap.h: + * heap/HeapVerifier.cpp: Added. + (JSC::LiveObjectList::findObject): + (JSC::HeapVerifier::HeapVerifier): + (JSC::HeapVerifier::collectionTypeName): + (JSC::HeapVerifier::phaseName): + (JSC::getButterflyDetails): + (JSC::HeapVerifier::initializeGCCycle): + (JSC::GatherLiveObjFunctor::GatherLiveObjFunctor): + (JSC::GatherLiveObjFunctor::operator()): + (JSC::HeapVerifier::gatherLiveObjects): + (JSC::HeapVerifier::liveObjectListForGathering): + (JSC::trimDeadObjectsFromList): + (JSC::HeapVerifier::trimDeadObjects): + (JSC::HeapVerifier::verifyButterflyIsInStorageSpace): + (JSC::HeapVerifier::verify): + (JSC::HeapVerifier::reportObject): + (JSC::HeapVerifier::checkIfRecorded): + * heap/HeapVerifier.h: Added. + (JSC::LiveObjectData::LiveObjectData): + (JSC::LiveObjectList::LiveObjectList): + (JSC::LiveObjectList::reset): + (JSC::HeapVerifier::GCCycle::GCCycle): + (JSC::HeapVerifier::GCCycle::collectionTypeName): + (JSC::HeapVerifier::incrementCycle): + (JSC::HeapVerifier::currentCycle): + (JSC::HeapVerifier::cycleForIndex): + * runtime/Options.h: + +2014-11-20 Yusuke Suzuki <utatane.tea@gmail.com> + + Rename String.prototype.contains to String.prototype.includes + https://bugs.webkit.org/show_bug.cgi?id=138923 + + As per the latest TC39 meeting[1, 2], String.prototype.contains is + renamed to String.prototype.includes. This is because the name + `contains` breaks the web since it conflicts with existing `contains` + implementations in major libraries. + + [1]: https://github.com/mathiasbynens/String.prototype.includes + [2]: https://github.com/tc39/test262/pull/119 + + Reviewed by Geoffrey Garen. + + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::finishCreation): + (JSC::stringProtoFuncIncludes): + (JSC::stringProtoFuncContains): Deleted. + +2014-11-19 Mark Lam <mark.lam@apple.com> + + WTFCrashWithSecurityImplication under SpeculativeJIT::compile() when loading a page from theblaze.com. + <https://webkit.org/b/137642> + + Reviewed by Filip Pizlo. + + In the DFG, we have a ConstantFolding phase that occurs after all LocalCSE + phases have already transpired. Hence, Identity nodes introduced in the + ConstantFolding phase will be left in the node graph. Subsequently, the + DFG code generator asserts that CSE phases have consumed all Identity nodes. + This turns out to not be true. Hence, the crash. We fix this by teaching + the DFG code generator to emit code for Identity nodes. + + Unlike the DFG, the FTL does not have this issue. That is because the FTL + plan has GlobalCSE phases that come after ConstantFolding and any other + phases that can generate Identity nodes. Hence, for the FTL, it is true that + CSE will consume all Identity nodes, and the code generator should not see any + Identity nodes. + + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + +2014-11-19 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: JSContext inspection Resource search does not work + https://bugs.webkit.org/show_bug.cgi?id=131252 + + Reviewed by Timothy Hatcher. + + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::searchInContent): + * inspector/protocol/Debugger.json: + Do some cleanup of the description and implementation of content searching. + +2014-11-19 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Provide $exception in the console for the thrown exception value + https://bugs.webkit.org/show_bug.cgi?id=138726 + + Reviewed by Timothy Hatcher. + + * debugger/DebuggerScope.cpp: + (JSC::DebuggerScope::caughtValue): + * debugger/DebuggerScope.h: + Access the caught value if this scope is a catch scope. + + * runtime/JSNameScope.h: + (JSC::JSNameScope::isFunctionNameScope): + (JSC::JSNameScope::isCatchScope): + (JSC::JSNameScope::value): + Provide an accessor for the single value in the JSNameScope (with / catch block). + + * inspector/InjectedScriptSource.js: + Save the exception value and expose it via $exception. Since the command line api + is recreated on each evaluation, $exception is essentially readonly. + + * inspector/ScriptDebugServer.h: + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::dispatchDidPause): + (Inspector::ScriptDebugServer::exceptionOrCaughtValue): + When pausing, get the exception or caught value. The exception will be provided + if we are breaking on an explicit exception. When inside of a catch block, we + can get the caught value by walking up the scope chain. + + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::InspectorDebuggerAgent): + (Inspector::InspectorDebuggerAgent::resume): + (Inspector::InspectorDebuggerAgent::stepOver): + (Inspector::InspectorDebuggerAgent::stepInto): + (Inspector::InspectorDebuggerAgent::stepOut): + Clearing state can be done in didContinue. + + (Inspector::InspectorDebuggerAgent::didPause): + Set the exception value explicitly in the injected script when we have it. + + (Inspector::InspectorDebuggerAgent::didContinue): + Clear state saved when we had paused, including clearly an exception value if needed. + + (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState): + (Inspector::InspectorDebuggerAgent::clearExceptionValue): + Call into the injected script only when needed. + + * inspector/InjectedScript.cpp: + (Inspector::InjectedScript::setExceptionValue): + (Inspector::InjectedScript::clearExceptionValue): + * inspector/InjectedScript.h: + * inspector/InjectedScriptManager.cpp: + (Inspector::InjectedScriptManager::clearExceptionValue): + * inspector/InjectedScriptManager.h: + Clear on all injected scripts. + +2014-11-19 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed build fixes after r176329. + + - export all of the codegen python files as they are included by the main generator + - update the imports of the main generator to match __init__.py + - remove bundling the python scripts as framework resources, just have them PrivateHeaders + + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/scripts/generate-inspector-protocol-bindings.py: + +2014-11-18 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: standardize language-specific protocol generator file, class, and method prefixes + https://bugs.webkit.org/show_bug.cgi?id=138237 + + Reviewed by Joseph Pecoraro. + + Settle on cpp/objc/js file prefixes and Cpp/ObjC/JS class prefixes for generators. + Move C++-specific static methods into CppGenerator and add cpp_ prefixes where relevant. + Split the templates file into language-specific template files. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/scripts/codegen/__init__.py: + * inspector/scripts/codegen/cpp_generator.py: Copied from Source/JavaScriptCore/inspector/scripts/codegen/generator.py. + * inspector/scripts/codegen/cpp_generator_templates.py: Copied from Source/JavaScriptCore/inspector/scripts/codegen/generator_templates.py. + (CppGeneratorTemplates): + * inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_alternate_backend_dispatcher_header.py. + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_dispatcher_header.py. + * inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_dispatcher_implementation.py. + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_frontend_dispatcher_header.py. + * inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_frontend_dispatcher_implementation.py. + * inspector/scripts/codegen/generate_cpp_protocol_types_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_protocol_types_header.py. + * inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_protocol_types_implementation.py. + * inspector/scripts/codegen/generate_js_backend_commands.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_backend_commands.py. + * inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_backend_dispatcher_header.py. + * inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_backend_dispatcher_implementation.py. + * inspector/scripts/codegen/generate_objc_configuration_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_configuration_header.py. + * inspector/scripts/codegen/generate_objc_configuration_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_configuration_implementation.py. + * inspector/scripts/codegen/generate_objc_conversion_helpers.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_conversion_helpers.py. + * inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_frontend_dispatcher_implementation.py. + * inspector/scripts/codegen/generate_objc_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_header.py. + * inspector/scripts/codegen/generate_objc_internal_header.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_internal_header.py. + * inspector/scripts/codegen/generate_objc_protocol_types_implementation.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c_types_implementation.py. + * inspector/scripts/codegen/generator.py: + * inspector/scripts/codegen/generator_templates.py: + * inspector/scripts/codegen/objc_generator.py: Renamed from Source/JavaScriptCore/inspector/scripts/codegen/generate_objective_c.py. + * inspector/scripts/codegen/objc_generator_templates.py: Added. + * inspector/scripts/generate-inspector-protocol-bindings.py: + +2014-11-19 Juergen Ributzka <juergen@apple.com> + + Update WebKit to build with LLVM TOT + https://bugs.webkit.org/show_bug.cgi?id=138519 + + Reviewed by Alexey Proskuryakov. + + * Configurations/LLVMForJSC.xcconfig: + * llvm/LLVMAPIFunctions.h: + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-11-18 David Kilzer <ddkilzer@apple.com> + + FeatureDefines.xcconfig: Switch from using PLATFORM_NAME to SDK selectors + <http://webkit.org/b/138813> + + Reviewed by Mark Rowe. + + * Configurations/FeatureDefines.xcconfig: Switch to using SDK + selectors. + +2014-11-18 Chris Dumez <cdumez@apple.com> + + Update the Vector API to deal with unsigned types instead of size_t + https://bugs.webkit.org/show_bug.cgi?id=138824 + + Reviewed by Andreas Kling. + + Update code base to fix build errors related to the typing changes + in the Vector API (size_t -> unsigned). + + * bytecode/PreciseJumpTargets.cpp: + * replay/EncodedValue.h: + +2014-11-18 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r176207. + https://bugs.webkit.org/show_bug.cgi?id=138836 + + Not ready yet (Requested by ap on #webkit). + + Reverted changeset: + + "Update WebKit to build with LLVM TOT" + https://bugs.webkit.org/show_bug.cgi?id=138519 + http://trac.webkit.org/changeset/176207 + +2014-11-17 Mark Lam <mark.lam@apple.com> + + Add printing functionality in JITted code for debugging purposes. + <https://webkit.org/b/138660> + + Reviewed by Geoffrey Garen. + + Sometimes, for debugging, it'd be nice to be able to just print the + values of constants or registers used in JITted code, or even just + a string to log that certain pieces of JITted code have been executed. + Using the JIT probe mechanism, we can make this happen. + + * assembler/ARMv7Assembler.h: + * assembler/AbstractMacroAssembler.h: + (JSC::AbstractMacroAssembler::CPUState::registerName): + (JSC::AbstractMacroAssembler::CPUState::registerValue): + (JSC::AbstractMacroAssembler::print): + (JSC::AbstractMacroAssembler::PrintArg::PrintArg): + (JSC::AbstractMacroAssembler::appendPrintArg): + (JSC::AbstractMacroAssembler::printInternal): + (JSC::AbstractMacroAssembler::printCallback): + * assembler/MacroAssemblerARM.cpp: + (JSC::MacroAssemblerARM::printCPURegisters): + (JSC::MacroAssemblerARM::printRegister): + * assembler/MacroAssemblerARM.h: + * assembler/MacroAssemblerARMv7.cpp: + (JSC::MacroAssemblerARMv7::printCPURegisters): + (JSC::MacroAssemblerARMv7::printRegister): + * assembler/MacroAssemblerARMv7.h: + * assembler/MacroAssemblerX86Common.cpp: + (JSC::MacroAssemblerX86Common::printRegister): + * assembler/MacroAssemblerX86Common.h: + +2014-11-17 Anders Carlsson <andersca@apple.com> + + Fix JavaScriptCore build with newer versions of clang. + <rdar://problem/18978716> + + * heap/Heap.cpp: + (JSC::Heap::visitTempSortVectors): + (JSC::Heap::deleteAllCompiledCode): Deleted. + * inspector/agents/InspectorConsoleAgent.h: + +2014-11-17 Juergen Ributzka <juergen@apple.com> + + Update WebKit to build with LLVM TOT + https://bugs.webkit.org/show_bug.cgi?id=138519 + + Reviewed by Alexey Proskuryakov. + + * Configurations/LLVMForJSC.xcconfig: + * llvm/LLVMAPIFunctions.h: + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-11-14 Benjamin Poulain <bpoulain@apple.com> + + STRH can store values with the wrong offset + https://bugs.webkit.org/show_bug.cgi?id=138723 + + Reviewed by Michael Saboff. + + This is the counterpart of r176083 for the str instruction. + + I believe this code is currently unreachable because there is only one client of strh() + in the MacroAssembler and it always setup the scale explicitely. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::strh): + +2014-11-13 Mark Lam <mark.lam@apple.com> + + Reduce amount of cut-and-paste needed for probe mechanism implementations. + <https://webkit.org/b/138671> + + Reviewed by Geoffrey Garen. + + The existing code requires that each MacroAssembler implementation provide + their own copy of all of the probe implementations even when most of it is + identical. This patch hoists the common parts into AbstractMacroAssembler + (with some minor renaming). Each target specific MacroAssembler now only + need to implement a few target specific methods that are expected by and + documented in AbstractMacroAssembler.h in the ENABLE(MASM_PROBE) section. + + In this patch, I also simplified the X86 and X86_64 ports to use the same + port implementation. The ARMv7 probe implementation should not conditionally + exclude the higher FP registers (since the JIT doesn't). Fixed the ARMv7 + probe code to include the higher FP registers always. + + This is all done in preparation to add printing functionality in JITted code + for debugging. + + * assembler/AbstractMacroAssembler.h: + (JSC::AbstractMacroAssembler::Label::Label): + (JSC::AbstractMacroAssembler::ConvertibleLoadLabel::ConvertibleLoadLabel): + (JSC::AbstractMacroAssembler::DataLabelPtr::DataLabelPtr): + (JSC::AbstractMacroAssembler::DataLabel32::DataLabel32): + (JSC::AbstractMacroAssembler::DataLabelCompact::DataLabelCompact): + (JSC::AbstractMacroAssembler::Jump::link): + (JSC::AbstractMacroAssembler::Jump::linkTo): + (JSC::AbstractMacroAssembler::JumpList::link): + (JSC::AbstractMacroAssembler::JumpList::linkTo): + (JSC::AbstractMacroAssembler::ProbeContext::print): + (JSC::AbstractMacroAssembler::printIndent): + (JSC::AbstractMacroAssembler::printCPU): + (JSC::AbstractMacroAssembler::CachedTempRegister::CachedTempRegister): + - Except for the 3 printing methods (which are for the probe), the rest + are touched simply because we need to add the MacroAssemblerType to the + template args. + The MacroAssemblerType is used by the abstract probe code to call the + few probe methods that need to have CPU specific implementations. + + * assembler/MacroAssemblerARM.cpp: + (JSC::MacroAssemblerARM::printCPURegisters): + - This was refactored from ProbeContext::dumpCPURegisters() which no + longer exists. + (JSC::MacroAssemblerARM::ProbeContext::dumpCPURegisters): Deleted. + (JSC::MacroAssemblerARM::ProbeContext::dump): Deleted. + + * assembler/MacroAssemblerARM.h: + * assembler/MacroAssemblerARM64.h: + + * assembler/MacroAssemblerARMv7.cpp: + (JSC::MacroAssemblerARMv7::printCPURegisters): + - This was refactored from ProbeContext::dumpCPURegisters() which no + longer exists. + (JSC::MacroAssemblerARMv7::ProbeContext::dumpCPURegisters): Deleted. + (JSC::MacroAssemblerARMv7::ProbeContext::dump): Deleted. + + * assembler/MacroAssemblerARMv7.h: + * assembler/MacroAssemblerMIPS.h: + * assembler/MacroAssemblerSH4.h: + * assembler/MacroAssemblerX86.h: + (JSC::MacroAssemblerX86::trustedImm32FromPtr): Deleted. + (JSC::MacroAssemblerX86::probe): Deleted. + + * assembler/MacroAssemblerX86Common.cpp: + (JSC::MacroAssemblerX86Common::printCPURegisters): + - This was refactored from ProbeContext::dumpCPURegisters() which no + longer exists. + (JSC::MacroAssemblerX86Common::probe): + - This implementation of probe() is based on the one originally in + MacroAssemblerX86_64.h. It is generic and should work for both + 32-bit and 64-bit. + (JSC::MacroAssemblerX86Common::ProbeContext::dumpCPURegisters): Deleted. + (JSC::MacroAssemblerX86Common::ProbeContext::dump): Deleted. + + * assembler/MacroAssemblerX86Common.h: + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::trustedImm64FromPtr): Deleted. + (JSC::MacroAssemblerX86_64::probe): Deleted. + * jit/JITStubsARMv7.h: + +2014-11-13 Michael Saboff <msaboff@apple.com> + + Add scope operand to op_new_func* byte codes + https://bugs.webkit.org/show_bug.cgi?id=138707 + + Reviewed by Mark Lam. + + Added scope operand to op_new_func and op_new_func_expr to replace the implicit use + of exec->scope(). + + * bytecode/BytecodeList.json: Increased size of op_new_func & op_new_func_expr bytecodes. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Added scope operand to dump output. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitNewFunctionInternal): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + Emit scope operand. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + Added new scope source nodes to NewFunction, NewFunctionExpression & NewFunctionNoCheck. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::compileNewFunctionNoCheck): + (JSC::DFG::SpeculativeJIT::compileNewFunctionExpression): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::compile): + Use scope children when making new function JIT_Operation calls. Use JSScope* value instead of + exec->scope(). + + * dfg/DFGOperations.h: + * dfg/DFGOperations.cpp: + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::callOperation): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_new_func): + (JSC::JIT::emit_op_new_func_exp): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + Added new Jsc JIT_Operation parameter type for JSScope* values. Created declarations and + definitions for new JIT_Operations with Jsc parameters. Use the JSScope* parameters in lieu + of exec->scope() in operationNewFunction(). + Removed comment for unused Jsa (JSLexicalEnvironment*) JIT_Operation parameter type. + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + Use the scope operand instead of exec->scope(). + + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Changed the operand indecies for added scope operand. + +2014-11-13 Mark Lam <mark.lam@apple.com> + + Change X86/64 JIT probes to save/restore xmm regs as double instead of __m128. [Follow up] + <https://webkit.org/b/138708> + + Reviewed by Michael Saboff. + + Removed a stale comment and a now unnecessary #include. + + * assembler/X86Assembler.h: + +2014-11-13 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r176087. + https://bugs.webkit.org/show_bug.cgi?id=138714 + + Broke the build (Requested by ap on #webkit). + + Reverted changeset: + + "Update WebKit to build with LLVM TOT" + https://bugs.webkit.org/show_bug.cgi?id=138519 + http://trac.webkit.org/changeset/176087 + +2014-11-13 Mark Lam <mark.lam@apple.com> + + Change X86/64 JIT probes to save/restore xmm regs as double instead of __m128. + <https://webkit.org/b/138708> + + Reviewed by Michael Saboff. + + The JIT code only uses the xmm regs as double registers. This patch changes + the storage types of the FP registers in X86Assembler.h to double instead of + __m128, and updates the X86 and X86_64 JIT probe implementations accordingly. + + Also made some minor cosmetic changes in the output of the probe dump functions. + + * assembler/MacroAssemblerX86Common.cpp: + (JSC::MacroAssemblerX86Common::ProbeContext::dumpCPURegisters): + * assembler/X86Assembler.h: + * jit/JITStubsX86.h: + * jit/JITStubsX86Common.h: + * jit/JITStubsX86_64.h: + +2014-11-13 Juergen Ributzka <juergen@apple.com> + + Update WebKit to build with LLVM TOT + https://bugs.webkit.org/show_bug.cgi?id=138519 + + Reviewed by Geoffrey Garen. + + * Configurations/LLVMForJSC.xcconfig: + * llvm/LLVMAPIFunctions.h: + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + +2014-11-13 Benjamin Poulain <benjamin@webkit.org> + + ARMv7(s) Assembler: LDRH with immediate offset is loading from the wrong offset + https://bugs.webkit.org/show_bug.cgi?id=136914 + + Reviewed by Michael Saboff. + + TLDR: the immediate offset of half-word load was divided by 2. + + Story time: So I started getting those weird reports of :nth-child() behaving bizarrely + on ARMv7 and ARMv7s. To make things worse, the behavior changes depending on style updates. + + I started looking the disassembly on the tests cases... + + The first thing I noticed was that the computation of An+B looked wrong. For example, + in the case of n+6, the instruction should have been: + subs r1, r1, #6 + but was + subs r1, r1, #2 + + After spending a lot of time trying to find the error in the assembler, I discovered + the problem was not real, but just a bug in the disassembler. + This is the first fix: ARMv7DOpcodeAddSubtractImmediate3's immediate3() was truncating + the value to 2 bits instead of 3 bits. + + The disassembler being fixed, I still have no lead on the weird bug. Some disassembly later, + I realize the LDRH instruction is not decoded at all. The reason is that both LDRH and STRH + were under the umbrella ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord but the pattern + only matched SRTH. + + I fix that next, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord is split into + ARMv7DOpcodeStoreRegisterImmediateHalfWord and ARMv7DOpcodeLoadRegisterImmediateHalfWord, + each with their own pattern and their instruction group. + + Now that I can see the LDRHs correctly, there is something fishy about them, their offset + is way too small for the data I load. + + This time, looking at the binary, the generated code is indeed incorrect. It turns out that + the ARMv7 assembler shifted the offset of half-word load as if they were byte load: divided by 4. + As a result, all the load of half-words with more than zero offset were loading + values with a smaller offset than what they should have. + + That being fixed, I dump the assembly: still wrong. I am ready to throw my keyboard through + my screen at that point. + + Looking at the disassembler, there is yet again a bug. The computation of the scale() adjustment + of the offset was incorrect for anything but word loads. + I replaced it by a switch-case to make it explicit. + + STRH is likely incorrect too. I'll fix that in a follow up, I want to survey all the 16 bits cases + that are not directly used by the CSS JIT. + + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::ldrh): + Fix the immediate scaling. Add an assertion to make sure the alignment of the input is correct. + + * disassembler/ARMv7/ARMv7DOpcode.cpp: + (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): + Fix the scaling code. Just hardcode instruction-to-scale table. + + * disassembler/ARMv7/ARMv7DOpcode.h: + (JSC::ARMv7Disassembler::ARMv7DOpcodeAddSubtractImmediate3::immediate3): + The mask for a 3 bits immediate is not 3 :) + + (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): Deleted. + +2014-11-13 Andreas Kling <akling@apple.com> + + Generate put_by_id for bracket assignment with constant string subscript. + <https://webkit.org/b/138702> + + Reviewed by Geoffrey Garen. + + Transform o["f"]=x to o.f=x when generating bytecode. This allows our JIT + to inline-cache those accesses instead of always dropping out to C++. + + Just like the get_by_id transformations, this gets a bunch of use on + real-web content (and Speedometer) but little/none on raw JS benchmarks. + + * bytecompiler/NodesCodegen.cpp: + (JSC::AssignBracketNode::emitBytecode): + +2014-11-12 Mark Lam <mark.lam@apple.com> + + Create canonical lists of registers used by both the Assemblers and the JIT probes. + <https://webkit.org/b/138681> + + Reviewed by Filip Pizlo. + + * assembler/ARMAssembler.h: + * assembler/ARMv7Assembler.h: + * assembler/X86Assembler.h: + - The FP register storage type is still defined as __m128 because the JIT + probe code still expects that amount of storage to be available. Will + change this to double when the JIT probe code is updated accordingly in a + later patch. + +2014-11-12 Andreas Kling <akling@apple.com> + + Generate get_by_id for bracket access with constant string subscript. + <https://webkit.org/b/138663> + + Reviewed by Michael Saboff. + + Transform o["f"] into o.f when generating bytecode. This allows our JIT + to inline-cache those accesses instead of always dropping out to C++. + + This is surprisingly common in real-web content, less so in benchmarks. + Interestingly, Speedometer does hit the optimization quite a bit. + + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): + +2014-11-12 Mark Lam <mark.lam@apple.com> + + Rename USE(MASM_PROBE) to ENABLE(MASM_PROBE). + <https://webkit.org/b/138661> + + Reviewed by Michael Saboff. + + Also move the switch for enabling the use of MASM_PROBE from JavaScriptCore's + config.h to WTF's Platform.h. This ensures that the setting is consistently + applied even when building WebCore parts as well. + + * assembler/ARMAssembler.h: + * assembler/ARMv7Assembler.h: + * assembler/MacroAssemblerARM.cpp: + * assembler/MacroAssemblerARM.h: + * assembler/MacroAssemblerARMv7.cpp: + * assembler/MacroAssemblerARMv7.h: + * assembler/MacroAssemblerX86.h: + * assembler/MacroAssemblerX86Common.cpp: + * assembler/MacroAssemblerX86Common.h: + * assembler/MacroAssemblerX86_64.h: + * assembler/X86Assembler.h: + * config.h: + * jit/JITStubs.h: + * jit/JITStubsARM.h: + * jit/JITStubsARMv7.h: + * jit/JITStubsX86.h: + * jit/JITStubsX86Common.h: + * jit/JITStubsX86_64.h: + +2014-11-12 peavo@outlook.com <peavo@outlook.com> + + [WinCairo] Incorrect names for test executables in debug mode. + https://bugs.webkit.org/show_bug.cgi?id=138659 + + Reviewed by Alex Christensen. + + In debug mode, jsc.exe, and testapi.exe are not created, causing JSC test failures. + + * JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj: + * JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj: + +2014-11-11 Michael Saboff <msaboff@apple.com> + + Change DFG to use scope operand for op_resolve_scope + https://bugs.webkit.org/show_bug.cgi?id=138651 + + Reviewed by Geoffrey Garen. + + Changed to use the provided scope VirtualRegister. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getScope): Changed to use an argument scope register. + (JSC::DFG::ByteCodeParser::parseBlock): Created VirtualRegister from scope operand. + +2014-11-11 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Remove IncrementalSweeper::create() + https://bugs.webkit.org/show_bug.cgi?id=138243 + + Reviewed by Filip Pizlo. + + As a step to use std::unique_ptr<> and std::make_unique<>, this patch removes + IncrementalSweeper::create(), then set constructor of IncrementalSweeper to public. + Now we begins to use std::make_unique<> to create IncrementalSweeper instance. + + * heap/Heap.cpp: + (JSC::Heap::Heap): + (JSC::Heap::setIncrementalSweeper): + * heap/Heap.h: + * heap/IncrementalSweeper.cpp: + (JSC::IncrementalSweeper::create): Deleted. + * heap/IncrementalSweeper.h: + +2014-11-11 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Handle activating extra agents properly after inspector has connected + https://bugs.webkit.org/show_bug.cgi?id=138639 + + Reviewed by Timothy Hatcher. + + Instead of having the protocol configuration directly add the extra agent + to the inspector registry, isntead go through the augmentable controller. + The controller will initialize as required if we are already connected or not, + and will add to the registry. + + The functional change here is that the frontend can be notified to activate + extra agents multiple times as agents eventually become available. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::appendExtraAgent): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::activateExtraDomain): + * inspector/agents/InspectorAgent.h: + * inspector/augmentable/AugmentableInspectorController.h: + * inspector/scripts/codegen/generator_templates.py: + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/enum-values.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + Rebased results. + +2014-11-11 Michael Saboff <msaboff@apple.com> + + Use scope register when processing op_resolve_scope in LLInt and Baseline JIT + https://bugs.webkit.org/show_bug.cgi?id=138637 + + Reviewed by Mark Lam. + + Filled out op_resolve_scope processing to use the scope operand to access the current + scope chain. + + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + * jit/JITOperations.cpp: + * jit/JITOperations.h: + Added scope virtual register parameter to emitResolveClosure(). Added new callOperation() to + support the additional argument. + + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitResolveClosure): + (JSC::JIT::emit_op_resolve_scope): + (JSC::JIT::emitSlow_op_resolve_scope): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emitResolveClosure): + (JSC::JIT::emit_op_resolve_scope): + (JSC::JIT::emitSlow_op_resolve_scope): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + Added "scope" parameter to emitResolveClosure(). Passed scope register index to slow path. + Used scope virtual register instead of JSStack::ScopeChain. + +2014-11-11 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Don't require a debugger be attached for inspector auto attach + https://bugs.webkit.org/show_bug.cgi?id=138638 + + Reviewed by Timothy Hatcher. + + * inspector/remote/RemoteInspector.mm: + (Inspector::RemoteInspector::updateDebuggableAutomaticInspectCandidate): + +2014-11-11 Akos Kiss <akiss@inf.u-szeged.hu> + + Handle cases in StackVisitor::Frame::existingArguments() when lexicalEnvironment and/or unmodifiedArgumentsRegister is not set up yet + https://bugs.webkit.org/show_bug.cgi?id=138543 + + Reviewed by Geoffrey Garen. + + Exception fuzzing may may raise exceptions in places where they would be + otherwise impossible. Therefore, a callFrame may lack activation even if + the codeBlock signals need of activation. Also, even if codeBlock + signals the use of arguments, the unmodifiedArgumentsRegister may not be + initialized yet (neither locally nor in lexicalEnvironment). + + If codeBlock()->needsActivation() is false, unmodifiedArgumentsRegister + is already checked for Undefined. This patch applies the same check when + the condition is true (and also checks whether + callFrame()->hasActivation()). + + * interpreter/CallFrame.h: + (JSC::ExecState::hasActivation): + Moved to interpreter/CallFrameInlines.h. + * interpreter/CallFrameInlines.h: + (JSC::CallFrame::hasActivation): + Fixed to verify that the JSValue returned by uncheckedActivation() is a + cell. + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::existingArguments): + +2014-11-11 Andreas Kling <akling@apple.com> + + Another assertion fix for debug builds after r175846. + + generateByIdStub() can now be called with an empty prototype chain + if kind == GetUndefined, so tweak the assertion to cover that. + + * jit/Repatch.cpp: + (JSC::generateByIdStub): + +2014-11-10 Andreas Kling <akling@apple.com> + + Assertion fix for debug builds after r175846. + + PropertySlot::slotBase() will assert if the slot is unset, so reorder + the tests to check for isCacheableValue() first. + + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + +2014-11-10 Andreas Kling <akling@apple.com> + + The JIT should cache property lookup misses. + <https://webkit.org/b/135578> + + Add support for inline caching of missed property lookups. + Previously this would banish us to C++ slow path. + + It's implemented as a simple GetById cache that returns jsUndefined() + as long as the Structure chain check passes. There's no DFG exploitation + of this knowledge in this patch. + + Test: js/regress/undefined-property-access.js (~5.5x speedup) + + Reviewed by Filip Pizlo. + + * bytecode/PolymorphicGetByIdList.h: + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + + Add GetByIdAccess::SimpleMiss so we can communicate to the DFG that + the access has been cached. + + * jit/Repatch.cpp: + (JSC::toString): + (JSC::kindFor): + (JSC::generateByIdStub): + (JSC::tryCacheGetByID): + (JSC::tryBuildGetByIDList): + + Added a GetUndefined stub kind, just a simple "store jsUndefined()" snippet. + Use this to cache missed lookups, piggybacking mostly on the GetValue kind. + + * runtime/PropertySlot.h: + (JSC::PropertySlot::isUnset): + + Exposed the unset state so PropertySlot can communicate that lookup failed. + +2014-11-10 Michael Saboff <msaboff@apple.com> + + Add scope operand to op_create_lexical_environment + https://bugs.webkit.org/show_bug.cgi?id=138588 + + Reviewed by Geoffrey Garen. + + Added a second operand to op_create_lexical_environment that contains the scope register + to update. Note that the DFG relies on operationCreateActivation() to update the + scope register since we can't issue a set() with a non-local, non-argument register. + This is temporary until the scope register is allocated as a local. + + * bytecode/BytecodeList.json: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + Added the scope register operand. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + Filled in the scope register operand. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_create_lexical_environment): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_create_lexical_environment): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Set the scope register with the result of the appropriate create activation slow call. + +2014-11-09 Akos Kiss <akiss@inf.u-szeged.hu> + + Fix 'noreturn' function does return warning in LLVMOverrides.cpp + https://bugs.webkit.org/show_bug.cgi?id=138306 + + Reviewed by Filip Pizlo. + + Adding NO_RETURN where needed. + + * llvm/library/LLVMExports.cpp: + (initializeAndGetJSCLLVMAPI): + * llvm/library/LLVMOverrides.cpp: + * llvm/library/LLVMTrapCallback.h: + +2014-11-07 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Fix an alignment issue with operationPushCatchScope on ARMv7 + https://bugs.webkit.org/show_bug.cgi?id=138510 + + Reviewed by Csaba Osztrogonác. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JITInlines.h: + (JSC::JIT::callOperation): + +2014-11-07 Michael Saboff <msaboff@apple.com> + + Update scope related slow path code to use scope register added to opcodes + https://bugs.webkit.org/show_bug.cgi?id=138254 + + Reviewed by Mark Lam. + + Updated slow paths for op_pop_scope, op_push_name_scope and op_push_with_scope. + Added scope register index parameter to the front of the relevant argument lists of the + slow functions. In the case of op_push_name_scope for x86 (32 bit), there aren't enough + registers to accomodate all the parameters. Therefore, added two new JSVALUE32_64 slow + paths called operationPushCatchScope() and operationPushFunctionNameScope() to eliminate + the last "type" argument. + + + * assembler/MacroAssemblerCodeRef.h: + (JSC::FunctionPtr::FunctionPtr): Added a new template to take 6 arguments. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + New variants of setupArgumentsWithExecState() and callOperation() to handle the new + combinations of argument types and counts. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_push_with_scope): + (JSC::JIT::emit_op_pop_scope): + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_push_with_scope): + (JSC::JIT::emit_op_pop_scope): + (JSC::JIT::emit_op_push_name_scope): + Use the new slow paths. + + * jit/JITOperations.cpp: + * jit/JITOperations.h: + Updates to set the scope result using the scope register index. Added operationPushCatchScope() + and operationPushFunctionNameScope(). + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + Updated the scope slow paths to use the scope register index in the instruction to read and + write the register instead of using CallFrame::scope() and CallFrame::setScope(). + +2014-11-07 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Apply std::unique_ptr to slowPathCall() + https://bugs.webkit.org/show_bug.cgi?id=138489 + + Reviewed by Mark Lam. + + As a step to use std::unique_ptr<>, this patch makes slowPathCall() use std::unique_ptr<>, + std::make_unique<>, and WTF::move(). + + * dfg/DFGSlowPathGenerator.h: + (JSC::DFG::slowPathCall): + (JSC::DFG::slowPathMove): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateJSArray): + (JSC::DFG::SpeculativeJIT::addSlowPathGenerator): + (JSC::DFG::SpeculativeJIT::arrayify): + (JSC::DFG::SpeculativeJIT::compileIn): + (JSC::DFG::SpeculativeJIT::compileGetByValOnString): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare): + (JSC::DFG::SpeculativeJIT::compile): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::cachedGetById): + (JSC::DFG::SpeculativeJIT::cachedPutById): + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompare): + (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq): + (JSC::DFG::SpeculativeJIT::compile): + +2014-11-06 Mark Lam <mark.lam@apple.com> + + slow_path_get_direct_pname() needs to be hardened against a constant baseValue. + <https://webkit.org/b/138476> + + Reviewed by Michael Saboff. + + slow_path_get_direct_pname() currently assumes that the baseValue is always a + non-constant virtual register. However, this is not always the case like in the + following: + + function foo() { + var o = { a:1 }; + for (var n in o) + 0[n]; + } + foo(); + + This patch fixes it to also check for constant virtual register indexes. + + * runtime/CommonSlowPaths.cpp: + (JSC::SLOW_PATH_DECL): + +2014-11-06 Michael Saboff <msaboff@apple.com> + + REGRESSION (r174985-174986): Site display disappears + https://bugs.webkit.org/show_bug.cgi?id=138082 + + Reviewed by Geoffrey Garen. + + In support of the change in WebCore, this adds a new functor class to unwind to our + caller's frame possibly skipping of intermediate C++ frames. + + * interpreter/StackVisitor.h: + (JSC::CallerFunctor::CallerFunctor): + (JSC::CallerFunctor::callerFrame): + (JSC::CallerFunctor::operator()): + +2014-11-06 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use std::unique_ptr in CodeBlock class + https://bugs.webkit.org/show_bug.cgi?id=138395 + + Reviewed by Darin Adler. + + * bytecode/CodeBlock.h: Use std::unique_ptr. + (JSC::CodeBlock::setJITCodeMap): + * jit/CompactJITCodeMap.h: Use std::unique_ptr instead of OwnPtr|PassOwnPtr. + (JSC::CompactJITCodeMap::CompactJITCodeMap): + (JSC::CompactJITCodeMap::Encoder::finish): Use std::unique_ptr instead of PassOwnPtr. + +2014-11-05 Mark Lam <mark.lam@apple.com> + + PutById inline caches should have a store barrier when it triggers a structure transition. + <https://webkit.org/b/138441> + + Reviewed by Geoffrey Garen. + + After r174025, we no longer insert DFG store barriers when the payload of a + PutById operation is not a cell. However, this can lead to a crash when we have + PutById inline cache code transitioning the structure and re-allocating the + butterfly of an old gen object. The lack of a store barrier in that inline + cache results in the old gen object not being noticed during an eden GC scan. + As a result, its newly allocated butterfly will not be kept alive, which leads + to a stale butterfly pointer and, eventually, a crash. + + It is also possible that the new structure can be collected by the eden GC if + (at GC time): + 1. It is in the eden gen. + 2. The inline cache that installed it has been evicted. + 3. There are no live eden gen objects referring to it. + + The chances of this should be more rare than the butterfly re-allocation, but + it is still possible. Hence, the fix is to always add a store barrier if the + inline caches performs a structure transition. + + * jit/Repatch.cpp: + (JSC::emitPutTransitionStub): + - Added store barrier code based on SpeculativeJIT::storeToWriteBarrierBuffer()'s + implementation. + +2014-11-05 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use std::unique_ptr in JSClassRef and JSCallbackObject + https://bugs.webkit.org/show_bug.cgi?id=138402 + + Reviewed by Geoffrey Garen. + + * API/JSCallbackObject.h: Use std::unique_ptr instead of OwnPtr|PassOwnPtr. + (JSC::JSCallbackObjectData::setPrivateProperty): ditto. + * API/JSClassRef.cpp: ditto. + * API/JSClassRef.h: ditto. + +2014-11-05 Michael Saboff <msaboff@apple.com> + + Disable flakey float32-repeat-out-of-bounds.js and int8-repeat-out-of-bounds.js tests for ARM64 + https://bugs.webkit.org/show_bug.cgi?id=138381 + + Reviewed by Mark Lam. + + Disabled these test for ARM64. Will address the failures and then re-enable. + + * tests/stress/float32-repeat-out-of-bounds.js: + * tests/stress/int8-repeat-out-of-bounds.js: + +2014-11-05 Alexey Proskuryakov <ap@apple.com> + + Incorrect sandbox_check in RemoteInspector.mm + https://bugs.webkit.org/show_bug.cgi?id=138408 + + Reviewed by Joseph Pecoraro. + + * inspector/remote/RemoteInspector.mm: + (Inspector::canAccessWebInspectorMachPort): + +2014-11-03 Dean Jackson <dino@apple.com> + + Add ENABLE_FILTERS_LEVEL_2 feature guard. + https://bugs.webkit.org/show_bug.cgi?id=138362 + + Reviewed by Tim Horton. + + Add a new feature define for Level 2 of CSS Filters. + http://dev.w3.org/fxtf/filters-2/ + + * Configurations/FeatureDefines.xcconfig: + +2014-11-04 Mark Lam <mark.lam@apple.com> + + Rename checkMarkByte() to jumpIfIsRememberedOrInEden(). + <https://webkit.org/b/138369> + + Reviewed by Geoffrey Garen. + + Write barriers are needed for GC Eden collections so that we can scan pointers + pointing from old generation objects to eden generation objects. The barrier + currently checks the mark byte in a cell to see if we should skip adding the + cell to the GC remembered set. The addition should be skipped if: + + 1. The cell is in the young generation. It has no old to eden pointers by + definition. + 2. The cell is already in the remembered set. While it is ok to add the cell + to the GC remembered set more than once, it would be redundant. Hence, + we skip this as an optimization to avoid doing unnecessary work. + + The barrier currently names this check as checkMarkByte(). We should rename it + to jumpIfIsRememberedOrInEden() to be clearer about its intent. + + Similarly, Jump results of this check are currently named + ownerNotMarkedOrAlreadyRemembered. This can be misinterpreted as the owner is + not marked or not already remembered. We should rename it to + ownerIsRememberedOrInEden which is clearer about the intent of the + check. What we are really checking for is that the cell is in the eden gen, + which is implied by it being "not marked". + + * dfg/DFGOSRExitCompilerCommon.cpp: + (JSC::DFG::osrWriteBarrier): + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT32_64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * dfg/DFGSpeculativeJIT64.cpp: + (JSC::DFG::SpeculativeJIT::writeBarrier): + * jit/AssemblyHelpers.h: + (JSC::AssemblyHelpers::jumpIfIsRememberedOrInEden): + (JSC::AssemblyHelpers::checkMarkByte): Deleted. + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitWriteBarrier): + * llint/LowLevelInterpreter.asm: + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + * runtime/JSCell.h: + +2014-11-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Pause on exceptions should show the actual exception + https://bugs.webkit.org/show_bug.cgi?id=63096 + + Reviewed by Timothy Hatcher. + + * debugger/Debugger.h: + Expose accessor for the pause reason to subclasses. + + * inspector/JSInjectedScriptHost.cpp: + (Inspector::JSInjectedScriptHost::type): + New "error" subtype for error objects. + + * inspector/InjectedScriptSource.js: + When an object is an error object, use toString to provide a richer description. + + * inspector/protocol/Runtime.json: + Expose a new "error" subtype for Error types (TypeError, ReferenceError, EvalError, etc). + + * inspector/protocol/Debugger.json: + Provide type checked objects for different Debugger.pause pause reasons. + An exception provides the thrown object, but assert / CSP pauses provide + a richer typed object as the auxiliary data. + + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::dispatchDidPause): + When paused because of an exception, pass the exception on. + + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::handleConsoleAssert): + (Inspector::InspectorDebuggerAgent::scriptExecutionBlockedByCSP): + Provide richer data in pause events. + + * inspector/scripts/codegen/generate_backend_commands.py: + (BackendCommandsGenerator.generate_domain.is_anonymous_enum_param): + (BackendCommandsGenerator.generate_domain): + * inspector/scripts/tests/expected/enum-values.json-result: + Generate frontend enums for anonymous enum event parameters. + +2014-11-04 Michael Saboff <msaboff@apple.com> + + Disable flakey float32-repeat-out-of-bounds.js and int8-repeat-out-of-bounds.js tests for ARM64 + https://bugs.webkit.org/show_bug.cgi?id=138381 + + Reviewed by Mark Lam. + + Disabled these test for ARM64. Will address the failures and then re-enable. + + * tests/stress/float32-repeat-out-of-bounds.js: + * tests/stress/int8-repeat-out-of-bounds.js: + +2014-11-04 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Enum value collisions between different generators + https://bugs.webkit.org/show_bug.cgi?id=138343 + + Reviewed by Brian Burg. + + Each generator was using its own filtered list of domains_to_generate + to build the shared unique list of enum value encodings. This list + was slightly different across different generators. Instead always + use the list of all non-supplemental domains to generate the shared + list of enum values. + + * inspector/scripts/codegen/generator.py: + (Generator.non_supplemental_domains): + (Generator.domains_to_generate): + (Generator._traverse_and_assign_enum_values): + * inspector/scripts/tests/enum-values.json: Added. + * inspector/scripts/tests/expected/enum-values.json-result: Added. + +2014-11-03 Akos Kiss <akiss@inf.u-szeged.hu> + + Workaround for Cortex-A53 erratum 835769 + https://bugs.webkit.org/show_bug.cgi?id=138315 + + Reviewed by Filip Pizlo. + + This patch introduces CMake variable and preprocessor macro + WTF_CPU_ARM64_CORTEXA53 with the aim of enabling Cortex-A53-specific + code paths, if set true. The patch also implements one case where such + code paths are needed: the workaround for Cortex-A53 erratum 835769. If + WTF_CPU_ARM64_CORTEXA53 is set then: + - CMake checks whether the compiler already has support for a workaround + and adds -mfix-cortex-a53-835769 to the compiler flags if so, + - the ARM64 backend of offlineasm inserts a nop between memory and + multiply-accumulate instructions, and + - the ARM64 assembler also inserts a nop between memory and (64-bit) + multiply-accumulate instructions. + + * assembler/ARM64Assembler.h: + (JSC::ARM64Assembler::madd): + Call nopCortexA53Fix835769() to insert a nop if CPU(ARM64_CORTEXA53) and + if necessary. + (JSC::ARM64Assembler::msub): Likewise. + (JSC::ARM64Assembler::smaddl): Likewise. + (JSC::ARM64Assembler::smsubl): Likewise. + (JSC::ARM64Assembler::umaddl): Likewise. + (JSC::ARM64Assembler::umsubl): Likewise. + (JSC::ARM64Assembler::nopCortexA53Fix835769): + Added. Insert a nop if the previously emitted instruction was a load, a + store, or a prefetch, and if the current instruction is 64-bit. + * offlineasm/arm64.rb: + Add the arm64CortexA53Fix835769 phase and call it from + getModifiedListARM64 to insert nopCortexA53Fix835769 between appropriate + macro instructions. Also, lower nopCortexA53Fix835769 to nop if + CPU(ARM64_CORTEXA53), to nothing otherwise. + * offlineasm/instructions.rb: + Define macro instruction nopFixCortexA53Err835769. + +2014-11-03 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r175509. + https://bugs.webkit.org/show_bug.cgi?id=138349 + + broke some builds (Requested by msaboff on #webkit). + + Reverted changeset: + + "Update scope related slow path code to use scope register + added to opcodes" + https://bugs.webkit.org/show_bug.cgi?id=138254 + http://trac.webkit.org/changeset/175509 + +2014-11-03 Michael Saboff <msaboff@apple.com> + + Update scope related slow path code to use scope register added to opcodes + https://bugs.webkit.org/show_bug.cgi?id=138254 + + Reviewed by Mark Lam. + + Updated slow paths for op_pop_scope, op_push_name_scope and op_push_with_scope. + Added scope register index parameter to the front of the relevant argument lists of the + slow functions. In the case of op_push_name_scope for x86 (32 bit), there aren't enough + registers to accomodate all the parameters. Therefore, added two new JSVALUE32_64 slow + paths called operationPushCatchScope() and operationPushFunctionNameScope() to eliminate + the last "type" argument. + + + * assembler/MacroAssemblerCodeRef.h: + (JSC::FunctionPtr::FunctionPtr): Added a new template to take 6 arguments. + + * jit/CCallHelpers.h: + (JSC::CCallHelpers::setupArgumentsWithExecState): + * jit/JIT.h: + * jit/JITInlines.h: + (JSC::JIT::callOperation): + New variants of setupArgumentsWithExecState() and callOperation() to handle the new + combinations of argument types and counts. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_push_with_scope): + (JSC::JIT::emit_op_pop_scope): + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_push_with_scope): + (JSC::JIT::emit_op_pop_scope): + (JSC::JIT::emit_op_push_name_scope): + Use the new slow paths. + + * jit/JITOperations.cpp: + * jit/JITOperations.h: + Updates to set the scope result using the scope register index. Added operationPushCatchScope() + and operationPushFunctionNameScope(). + + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + Updated the scope slow paths to use the scope register index in the instruction to read and + write the register instead of using CallFrame::scope() and CallFrame::setScope(). + +2014-11-03 Michael Saboff <msaboff@apple.com> + + Add "get scope" byte code + https://bugs.webkit.org/show_bug.cgi?id=138326 + + Reviewed by Mark Lam. + + Added op_get_scope. Added implementations for the LLInt and baseline JIT. + Provided nop implementation for DFG and FTL. The new byte code is emitted + after op_enter for any function, program or eval. It is expected that the + DFG will be implemented such that unneeded op_get_scope would be eliminated + during DFG compilation. + + * bytecode/BytecodeList.json: + * bytecode/BytecodeUseDef.h: + (JSC::computeUsesForBytecodeOffset): + (JSC::computeDefsForBytecodeOffset): + Added new op_get_scope bytecode. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitGetScope): + * bytecompiler/BytecodeGenerator.h: + Emit new op_get_scope bytecode. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + Added framework for new op_get_scope bytecode. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_scope): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_get_scope): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Implementation of op_get_scope bytecode. + +2014-11-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Fix RWIProtocol 64-to-32 bit conversion warnings + https://bugs.webkit.org/show_bug.cgi?id=138325 + + Reviewed by Timothy Hatcher. + + * inspector/InspectorValues.h: + Vector's length really is an unsigned, so a static_cast here is fine. + + * inspector/scripts/codegen/generate_objective_c.py: + (ObjCGenerator.objc_type_for_raw_name): + Use int instead of NSInteger for APIs that eventually map to + InspectorObject's setInteger, which takes an int. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + Rebaselined results with the type change. + +2014-11-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Show Selector's Specificity + https://bugs.webkit.org/show_bug.cgi?id=138189 + + Reviewed by Timothy Hatcher. + + * inspector/protocol/CSS.json: + Create a new named type CSSSelector to include a selector's text and specificity. + The specificity tuple is optional as it may soon be made dynamic in some cases. + +2014-11-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ObjC Protocol Interfaces should throw exceptions for nil arguments + https://bugs.webkit.org/show_bug.cgi?id=138221 + + Reviewed by Timothy Hatcher. + + The RWIProtocol APIs will now raise exceptions when: + + - any properties are set on a type with a nil value or key (handled by RWIProtocolJSONObject) + - required parameters in type constructors have nil value + - required or optional command return parameters have nil values + - required or optional event parameters have nil values + + The exceptions include the name of the field when possible. + + * inspector/scripts/codegen/generate_objective_c.py: + (ObjCGenerator.is_type_objc_pointer_type): + Provide a quick check to see if type would be a pointer or not + in the ObjC API. Enums for example are not pointers in the API + because we manage converting them to/from strings. + + * inspector/scripts/codegen/generate_objective_c_backend_dispatcher_implementation.py: + (ObjectiveCConfigurationImplementationGenerator._generate_success_block_for_command): + * inspector/scripts/codegen/generate_objective_c_frontend_dispatcher_implementation.py: + (ObjectiveCFrontendDispatcherImplementationGenerator._generate_event): + * inspector/scripts/codegen/generate_objective_c_types_implementation.py: + (ObjectiveCTypesImplementationGenerator._generate_init_method_for_required_members): + (ObjectiveCTypesImplementationGenerator._generate_setter_for_member): + Throw exceptions when nil values are disallowed. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + Rebaseline tests which include the exception raise calls. + +2014-11-03 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: ALTERNATE_DISPATCHERS Let the frontend know about extra agents + https://bugs.webkit.org/show_bug.cgi?id=138236 + + Reviewed by Brian Burg. + + Inform the frontend about any extra domains the backend may have + above and beyond the default list of domains for the debuggable type. + This approach means there is almost no cost to normal debugging. + When a JSContext is debugged with extra agents, a message is sent + to the frontend letting it know which domains to then activate, + and perform any initialization work that may be required. + + * inspector/InspectorAgentBase.h: + (Inspector::InspectorAgentBase::domainName): + * inspector/InspectorAgentRegistry.cpp: + (Inspector::InspectorAgentRegistry::appendExtraAgent): + * inspector/InspectorAgentRegistry.h: + * inspector/scripts/codegen/generator_templates.py: + Provide a way to get a list of just the extra domains. + To aggregate this list provide a different "append" + specifically for extra agents. + + * inspector/JSGlobalObjectInspectorController.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + When a frontend connects, inform it of the extra domains. + + * inspector/protocol/Inspector.json: + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorAgent.cpp: + (Inspector::InspectorAgent::enable): + (Inspector::InspectorAgent::activateExtraDomains): + Send an event with the extra domains to activate. + +2014-11-01 Michael Saboff <msaboff@apple.com> + + Add scope operand to op_resolve_scope + https://bugs.webkit.org/show_bug.cgi?id=138253 + + Reviewed by Mark Lam. + + Added scope operand to op_resolve_scope. Although the scope register is filled in with + the ScopeChain register, this operand is not used in the processing of the bytecode. + That will be addressed in a future patch. + + * bytecode/BytecodeList.json: Lengthened the three bytecodes. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Added code to dump the scope operand. + + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::finalizeUnconditionally): + Updated the operand indecies for the processing of op_resolve_scope. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitResolveScope): + (JSC::BytecodeGenerator::emitGetOwnScope): + (JSC::BytecodeGenerator::emitReturn): + Added scope register to these emit functions and the bytecodes they emit. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::parseBlock): + * dfg/DFGCapabilities.cpp: + (JSC::DFG::capabilityLevel): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_resolve_scope): + (JSC::JIT::emitSlow_op_resolve_scope): + * jit/JITPropertyAccess32_64.cpp: + (JSC::JIT::emit_op_resolve_scope): + (JSC::JIT::emitSlow_op_resolve_scope): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + Updated the operand indecies for the processing of op_resolve_scope. + +2014-11-01 Carlos Garcia Campos <cgarcia@igalia.com> + + REGRESSION(CMake): Make it possible to build without introspection + https://bugs.webkit.org/show_bug.cgi?id=138006 + + Reviewed by Philippe Normand. + + Do not install introspection files when introspection is disabled. + + * PlatformGTK.cmake: + +2014-10-31 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use std::unique_ptr for TypeCountSet + https://bugs.webkit.org/show_bug.cgi?id=138242 + + Reviewed by Andreas Kling. + + * heap/Heap.cpp: + (JSC::Heap::protectedObjectTypeCounts): + Use std::unique_ptr<> instead of PassOwnPtr|OwnPtr. + (JSC::Heap::objectTypeCounts): ditto. + * heap/Heap.h: + +2014-10-31 Michael Saboff <msaboff@apple.com> + + Add scope operand to op_push_with_scope, op_push_name_scope and op_pop_scope + https://bugs.webkit.org/show_bug.cgi?id=138252 + + Reviewed by Geoffrey Garen. + + Added scope operand to op_push_with_scope, op_push_name_scope and op_pop_scope. + Although the scope register is filled in with the ScopeChain register for all + three bytecodes, this operand is not used in the processing of the bytecodes. + That will be addressed in a future patch. + + * bytecode/BytecodeList.json: Lengthened the three bytecodes. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dumpBytecode): Added code to dump the scope operand. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitPushWithScope): + (JSC::BytecodeGenerator::emitPopScope): + (JSC::BytecodeGenerator::emitComplexPopScopes): + (JSC::BytecodeGenerator::emitPopScopes): + (JSC::BytecodeGenerator::emitPushFunctionNameScope): + (JSC::BytecodeGenerator::emitPushCatchScope): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::scopeRegister): + Added scope register to these emit functions and the bytecodes they emit. + New m_scopeRegister and accessor. + + * bytecompiler/NodesCodegen.cpp: + (JSC::ContinueNode::emitBytecode): + (JSC::BreakNode::emitBytecode): + (JSC::ReturnNode::emitBytecode): + (JSC::WithNode::emitBytecode): + (JSC::TryNode::emitBytecode): + Created a RegisterID for the ScopeChain register and used it to emit the updated + bytecodes. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_push_with_scope): + (JSC::JIT::emit_op_push_name_scope): + * jit/JITOpcodes32_64.cpp: + (JSC::JIT::emit_op_push_with_scope): + (JSC::JIT::emit_op_push_name_scope): + * llint/LLIntSlowPaths.cpp: + (JSC::LLInt::LLINT_SLOW_PATH_DECL): + * llint/LowLevelInterpreter.asm: + Updated the operand indecies for the processing of the updated bytecodes. + +2014-10-31 Andreas Kling <akling@apple.com> + + Make writes to RegExpObject.lastIndex cacheable. + <https://webkit.org/b/138255> + + Reviewed by Geoffrey Garen. + + We were neglecting to IC the puts to RegExpObject.lastIndex on Octane/regexp, + and ended up spending 4.5% of a time profile in operationPutByIdNonStrict. + + ~3% progression on Octane/regexp. + + * runtime/RegExpObject.cpp: + (JSC::regExpObjectSetLastIndexStrict): + (JSC::regExpObjectSetLastIndexNonStrict): + (JSC::RegExpObject::put): + +2014-10-31 Chris Dumez <cdumez@apple.com> + + Fix a couple of warnings in JSC reported by clang static analyzer + https://bugs.webkit.org/show_bug.cgi?id=138240 + + Reviewed by Geoffrey Garen. + + Fix a couple of warnings in JSC reported by clang static analyzer about + value stored in variables never being read. This is addressed by + reducing the scope of the variable or removing the variable entirely. + + * dfg/DFGConstantFoldingPhase.cpp: + (JSC::DFG::ConstantFoldingPhase::emitGetByOffset): + * runtime/VM.cpp: + (JSC::VM::throwException): + +2014-10-30 Dana Burkart <dburkart@apple.com> + + <rdar://problem/18821260> Prepare for the mysterious future + + Reviewed by Lucas Forschler. + + * Configurations/Base.xcconfig: + * Configurations/DebugRelease.xcconfig: + * Configurations/FeatureDefines.xcconfig: + * Configurations/Version.xcconfig: + +2014-10-30 Saam Barati <saambarati1@gmail.com> + + AST Nodes should keep track of their end offset + https://bugs.webkit.org/show_bug.cgi?id=138143 + + Reviewed by Filip Pizlo. + + AST nodes nodes now have an int property for their end text + offsets. This change lays some foundational work that will be + needed in profiling which basic blocks have executed. + + * parser/ASTBuilder.h: + (JSC::ASTBuilder::setEndOffset): + * parser/Nodes.h: + (JSC::Node::endOffset): + (JSC::Node::setEndOffset): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseStatement): + (JSC::Parser<LexerType>::parseFunctionInfo): + (JSC::Parser<LexerType>::parseExpression): + (JSC::Parser<LexerType>::parseProperty): + * parser/Parser.h: + (JSC::Parser<LexerType>::parse): + * parser/SyntaxChecker.h: + (JSC::SyntaxChecker::operatorStackPop): + +2014-10-30 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Generate ObjC inspector protocol types and alternate dispatcher interfaces + https://bugs.webkit.org/show_bug.cgi?id=138048 + + Reviewed by Brian Burg. + + Generate Objective-C interfaces for inspector protocol types, command, and event dispatchers. + This is very much like the InspectorProtocolTypes, BackendDispatchers, and FrontendDispatchers, + but with an ObjC spin on things. + + The private API that clients would use is all encapsulated in RWIProtocol.h. It includes the + types interfaces, command handler protocol, and event dispatcher interface. Where possible the + API uses real enums, which hides the raw protocol enum strings from clients. + + Inspector protocol types are, like InspectorProtocolObjects, built on top of an InspectorObject. + This offers the flexibilty of adding arbitrary key/values using the RWIProtocolJSONObject + interface, which may be required for certain protocol objects like "Network.Headers" which + have no fields, but expect arbitrary properties to be added. + + Command handler protocols always have two callbacks. An error callback and a success callback. + The signature is very much like BackendDispatchers. In parameters are passed directly to + the selectors, and out parameters are defined by the success callback. It will be the client's + responsibility to call either of these callbacks to complete handling of a request. + + Event dispatcher interfaces are straight forward, just packaging up the arguments and sending + the message to the frontend. + + ObjC <-> Protocol conversion happens in each of the generated files. In type getters / setters, + in commands parameters and event parameters. For this to work we generate conversion helpers + for all enums, ObjC enum <-> protocol strings. For NSArray <-> InspectorArray there are some + static helpers to do the conversions. We do lose some type safety in these conversions. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/scripts/codegen/__init__.py: + * inspector/scripts/codegen/generate_alternate_backend_dispatcher_header.py: + (AlternateBackendDispatcherHeaderGenerator._generate_handler_declarations_for_domain): + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator._generate_alternate_handler_forward_declarations_for_domains.AlternateInspector): + (BackendDispatcherHeaderGenerator._generate_handler_declarations_for_domain): + (BackendDispatcherHeaderGenerator._generate_dispatcher_declarations_for_domain): + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: + (BackendDispatcherImplementationGenerator._generate_handler_class_destructor_for_domain): + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementations_for_domain): + * inspector/scripts/codegen/generate_frontend_dispatcher_header.py: + (FrontendDispatcherHeaderGenerator._generate_dispatcher_declarations_for_domain): + * inspector/scripts/codegen/generate_frontend_dispatcher_implementation.py: + (FrontendDispatcherImplementationGenerator._generate_dispatcher_implementations_for_domain): + * inspector/scripts/codegen/generate_objective_c.py: Added. + (join_type_and_name): + (strip_comment_markers): + (remove_duplicate_from_str): + (ObjCTypeCategory): + (ObjCTypeCategory.category_of_type): + (ObjCGenerator): + (ObjCGenerator.identifier_to_objc_identifier): + (ObjCGenerator.objc_identifier_to_identifier): + (ObjCGenerator.should_generate_domain_types_filter): + (ObjCGenerator.should_generate_domain_types_filter.should_generate_domain_types): + (ObjCGenerator.should_generate_domain_command_handler_filter): + (ObjCGenerator.should_generate_domain_command_handler_filter.should_generate_domain_command_handler): + (ObjCGenerator.should_generate_domain_event_dispatcher_filter): + (ObjCGenerator.should_generate_domain_event_dispatcher_filter.should_generate_domain_event_dispatcher): + (ObjCGenerator.objc_name_for_type): + (ObjCGenerator.objc_enum_name_for_anonymous_enum_declaration): + (ObjCGenerator.objc_enum_name_for_anonymous_enum_member): + (ObjCGenerator.objc_enum_name_for_anonymous_enum_parameter): + (ObjCGenerator.objc_enum_name_for_non_anonymous_enum): + (ObjCGenerator.variable_name_prefix_for_domain): + (ObjCGenerator.objc_accessor_type_for_raw_name): + (ObjCGenerator.objc_type_for_raw_name): + (ObjCGenerator.objc_class_for_raw_name): + (ObjCGenerator.protocol_type_for_raw_name): + (ObjCGenerator.protocol_type_for_type): + (ObjCGenerator.objc_class_for_type): + (ObjCGenerator.objc_accessor_type_for_member): + (ObjCGenerator.objc_accessor_type_for_member_internal): + (ObjCGenerator.objc_type_for_member): + (ObjCGenerator.objc_type_for_member_internal): + (ObjCGenerator.objc_type_for_param): + (ObjCGenerator.objc_type_for_param_internal): + (ObjCGenerator.objc_protocol_export_expression_for_variable): + (ObjCGenerator.objc_protocol_import_expression_for_member): + (ObjCGenerator.objc_protocol_import_expression_for_parameter): + (ObjCGenerator.objc_protocol_import_expression_for_variable): + (ObjCGenerator.objc_to_protocol_expression_for_member): + (ObjCGenerator.protocol_to_objc_expression_for_member): + (ObjCGenerator.objc_setter_method_for_member): + (ObjCGenerator.objc_setter_method_for_member_internal): + (ObjCGenerator.objc_getter_method_for_member): + (ObjCGenerator.objc_getter_method_for_member_internal): + * inspector/scripts/codegen/generate_objective_c_backend_dispatcher_header.py: Copied from Source/JavaScriptCore/inspector/scripts/codegen/generate_alternate_backend_dispatcher_header.py. + (ObjectiveCBackendDispatcherHeaderGenerator): + (ObjectiveCBackendDispatcherHeaderGenerator.output_filename): + (ObjectiveCBackendDispatcherHeaderGenerator.domains_to_generate): + (ObjectiveCBackendDispatcherHeaderGenerator.generate_output): + (ObjectiveCBackendDispatcherHeaderGenerator._generate_objc_forward_declarations): + (ObjectiveCBackendDispatcherHeaderGenerator._generate_objc_forward_declarations_for_domains): + (ObjectiveCBackendDispatcherHeaderGenerator._generate_objc_handler_declarations_for_domain): + (ObjectiveCBackendDispatcherHeaderGenerator._generate_objc_handler_declaration_for_command): + * inspector/scripts/codegen/generate_objective_c_backend_dispatcher_implementation.py: Added. + (ObjectiveCConfigurationImplementationGenerator): + (ObjectiveCConfigurationImplementationGenerator.__init__): + (ObjectiveCConfigurationImplementationGenerator.output_filename): + (ObjectiveCConfigurationImplementationGenerator.domains_to_generate): + (ObjectiveCConfigurationImplementationGenerator.generate_output): + (ObjectiveCConfigurationImplementationGenerator._generate_handler_implementation_for_domain): + (ObjectiveCConfigurationImplementationGenerator._generate_handler_implementation_for_command): + (ObjectiveCConfigurationImplementationGenerator._generate_success_block_for_command): + (ObjectiveCConfigurationImplementationGenerator._generate_conversions_for_command): + (ObjectiveCConfigurationImplementationGenerator._generate_invocation_for_command): + * inspector/scripts/codegen/generate_objective_c_configuration_header.py: Copied from Source/JavaScriptCore/inspector/scripts/codegen/generate_alternate_backend_dispatcher_header.py. + (ObjectiveCConfigurationHeaderGenerator): + (ObjectiveCConfigurationHeaderGenerator.output_filename): + (ObjectiveCConfigurationHeaderGenerator.generate_output): + (ObjectiveCConfigurationHeaderGenerator._generate_configuration_interface_for_domains): + (ObjectiveCConfigurationHeaderGenerator._generate_properties_for_domain): + * inspector/scripts/codegen/generate_objective_c_configuration_implementation.py: Added. + (ObjectiveCBackendDispatcherImplementationGenerator): + (ObjectiveCBackendDispatcherImplementationGenerator.__init__): + (ObjectiveCBackendDispatcherImplementationGenerator.output_filename): + (ObjectiveCBackendDispatcherImplementationGenerator.generate_output): + (ObjectiveCBackendDispatcherImplementationGenerator._generate_configuration_implementation_for_domains): + (ObjectiveCBackendDispatcherImplementationGenerator._generate_ivars): + (ObjectiveCBackendDispatcherImplementationGenerator._generate_dealloc): + (ObjectiveCBackendDispatcherImplementationGenerator._generate_handler_setter_for_domain): + (ObjectiveCBackendDispatcherImplementationGenerator._generate_event_dispatcher_getter_for_domain): + * inspector/scripts/codegen/generate_objective_c_conversion_helpers.py: Added. + (add_whitespace_separator): + (ObjectiveCConversionHelpersGenerator): + (ObjectiveCConversionHelpersGenerator.__init__): + (ObjectiveCConversionHelpersGenerator.output_filename): + (ObjectiveCConversionHelpersGenerator.domains_to_generate): + (ObjectiveCConversionHelpersGenerator.generate_output): + (ObjectiveCConversionHelpersGenerator._generate_enum_conversion_functions): + (ObjectiveCConversionHelpersGenerator._generate_anonymous_enum_conversion_for_declaration): + (ObjectiveCConversionHelpersGenerator._generate_anonymous_enum_conversion_for_member): + (ObjectiveCConversionHelpersGenerator._generate_anonymous_enum_conversion_for_parameter): + (ObjectiveCConversionHelpersGenerator._generate_enum_objc_to_protocol_string): + (ObjectiveCConversionHelpersGenerator._generate_enum_from_protocol_string): + * inspector/scripts/codegen/generate_objective_c_frontend_dispatcher_implementation.py: Added. + (ObjectiveCFrontendDispatcherImplementationGenerator): + (ObjectiveCFrontendDispatcherImplementationGenerator.__init__): + (ObjectiveCFrontendDispatcherImplementationGenerator.output_filename): + (ObjectiveCFrontendDispatcherImplementationGenerator.domains_to_generate): + (ObjectiveCFrontendDispatcherImplementationGenerator.generate_output): + (ObjectiveCFrontendDispatcherImplementationGenerator._generate_event_dispatcher_implementations): + (ObjectiveCFrontendDispatcherImplementationGenerator._generate_event): + (ObjectiveCFrontendDispatcherImplementationGenerator._generate_event_signature): + (ObjectiveCFrontendDispatcherImplementationGenerator._generate_event_out_parameters): + * inspector/scripts/codegen/generate_objective_c_header.py: Added. + (add_whitespace_separator): + (ObjectiveCHeaderGenerator): + (ObjectiveCHeaderGenerator.__init__): + (ObjectiveCHeaderGenerator.output_filename): + (ObjectiveCHeaderGenerator.generate_output): + (ObjectiveCHeaderGenerator._generate_forward_declarations): + (ObjectiveCHeaderGenerator._generate_enums): + (ObjectiveCHeaderGenerator._generate_types): + (ObjectiveCHeaderGenerator._generate_anonymous_enum_for_declaration): + (ObjectiveCHeaderGenerator._generate_anonymous_enum_for_member): + (ObjectiveCHeaderGenerator._generate_anonymous_enum_for_parameter): + (ObjectiveCHeaderGenerator._generate_enum): + (ObjectiveCHeaderGenerator._generate_enum.NS_ENUM): + (ObjectiveCHeaderGenerator._generate_type_interface): + (ObjectiveCHeaderGenerator._generate_init_method_for_required_members): + (ObjectiveCHeaderGenerator._generate_member_property): + (ObjectiveCHeaderGenerator._generate_command_protocols): + (ObjectiveCHeaderGenerator._generate_single_command_protocol): + (ObjectiveCHeaderGenerator._callback_block_for_command): + (ObjectiveCHeaderGenerator._generate_event_interfaces): + (ObjectiveCHeaderGenerator._generate_single_event_interface): + * inspector/scripts/codegen/generate_objective_c_internal_header.py: Copied from Source/JavaScriptCore/inspector/scripts/codegen/generate_alternate_backend_dispatcher_header.py. + (ObjectiveCTypesInternalHeaderGenerator): + (ObjectiveCTypesInternalHeaderGenerator.output_filename): + (ObjectiveCTypesInternalHeaderGenerator.generate_output): + (ObjectiveCTypesInternalHeaderGenerator._generate_event_dispatcher_private_interfaces): + * inspector/scripts/codegen/generate_objective_c_types_implementation.py: Added. + (add_whitespace_separator): + (ObjectiveCTypesImplementationGenerator): + (ObjectiveCTypesImplementationGenerator.__init__): + (ObjectiveCTypesImplementationGenerator.output_filename): + (ObjectiveCTypesImplementationGenerator.domains_to_generate): + (ObjectiveCTypesImplementationGenerator.generate_output): + (ObjectiveCTypesImplementationGenerator.generate_type_implementations): + (ObjectiveCTypesImplementationGenerator.generate_type_implementation): + (ObjectiveCTypesImplementationGenerator._generate_init_method_for_required_members): + (ObjectiveCTypesImplementationGenerator._generate_setter_for_member): + (ObjectiveCTypesImplementationGenerator._generate_getter_for_member): + * inspector/scripts/codegen/generate_protocol_types_header.py: + (ProtocolTypesHeaderGenerator._generate_forward_declarations): + (_generate_typedefs_for_domain): + (_generate_builders_for_domain): + * inspector/scripts/codegen/generator.py: + (Generator.wrap_with_guard_for_domain): + (Generator): + (Generator.wrap_with_guard): + * inspector/scripts/codegen/generator_templates.py: + (AlternateInspector): + (ObjCInspector): + * inspector/scripts/codegen/models.py: + (Framework.fromString): + (Frameworks): + * inspector/scripts/generate-inspector-protocol-bindings.py: + (generate_from_specification): + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + +2014-10-30 Andreas Kling <akling@apple.com> + + Unreviewed assertion fix. + + RegExpCachedResult::m_reified is now the dedicated member that knows whether + the result was reified into an array or not. Check that instead of m_result + which is now single-purpose. + + * runtime/RegExpCachedResult.cpp: + (JSC::RegExpCachedResult::setInput): + +2014-10-29 Andreas Kling <akling@apple.com> + + Use plain JSArray for RegExp matches instead of a lazily populated custom object. + <https://webkit.org/b/138191> + + Reviewed by Geoffrey Garen. + + We're already offering two RegExp matching APIs, one that collects subpattern + matches (exec), and one that simply tests for a match (test). + Given that, it was pretty overkill to lazily populate the resulting array of + matches, since the user could simply use test() if they didn't need them. + + This allows the JIT to generate better code for RegExp match arrays, and also + enables some fast paths in the JSC runtime that check if an object isJSArray(). + + Looks like ~1.5% improvement on Octane/regexp according to run-jsc-benchmarks. + + * jit/Repatch.cpp: + (JSC::tryCacheGetByID): + * runtime/JSArray.h: + (JSC::createArrayButterflyWithExactLength): Deleted. + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/RegExpCachedResult.cpp: + (JSC::RegExpCachedResult::visitChildren): + (JSC::RegExpCachedResult::lastResult): + (JSC::RegExpCachedResult::leftContext): + (JSC::RegExpCachedResult::rightContext): + * runtime/RegExpCachedResult.h: + (JSC::RegExpCachedResult::RegExpCachedResult): + (JSC::RegExpCachedResult::record): + (JSC::RegExpCachedResult::input): + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::getBackref): + (JSC::RegExpConstructor::getLastParen): + (JSC::RegExpConstructor::getLeftContext): + (JSC::RegExpConstructor::getRightContext): + * runtime/RegExpMatchesArray.cpp: + (JSC::createRegExpMatchesArray): + (JSC::RegExpMatchesArray::RegExpMatchesArray): Deleted. + (JSC::RegExpMatchesArray::create): Deleted. + (JSC::RegExpMatchesArray::finishCreation): Deleted. + (JSC::RegExpMatchesArray::visitChildren): Deleted. + (JSC::RegExpMatchesArray::reifyAllProperties): Deleted. + (JSC::RegExpMatchesArray::reifyMatchProperty): Deleted. + (JSC::RegExpMatchesArray::leftContext): Deleted. + (JSC::RegExpMatchesArray::rightContext): Deleted. + * runtime/RegExpMatchesArray.h: + (JSC::RegExpMatchesArray::createStructure): Deleted. + (JSC::RegExpMatchesArray::reifyAllPropertiesIfNecessary): Deleted. + (JSC::RegExpMatchesArray::reifyMatchPropertyIfNecessary): Deleted. + (JSC::RegExpMatchesArray::getOwnPropertySlot): Deleted. + (JSC::RegExpMatchesArray::getOwnPropertySlotByIndex): Deleted. + (JSC::RegExpMatchesArray::put): Deleted. + (JSC::RegExpMatchesArray::putByIndex): Deleted. + (JSC::RegExpMatchesArray::deleteProperty): Deleted. + (JSC::RegExpMatchesArray::deletePropertyByIndex): Deleted. + (JSC::RegExpMatchesArray::getOwnPropertyNames): Deleted. + (JSC::RegExpMatchesArray::defineOwnProperty): Deleted. + (JSC::isRegExpMatchesArray): Deleted. + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::exec): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncMatch): + +2014-10-29 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Fix Type Dependency Issues + https://bugs.webkit.org/show_bug.cgi?id=125664 + + Reviewed by Brian Burg. + + Now that all JSON protocol files are processed together again + in r174892, we can remove the duplicated types which were only + needed when the domains were split. + + * inspector/protocol/Console.json: + * inspector/protocol/Runtime.json: + +2014-10-28 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r175249. + https://bugs.webkit.org/show_bug.cgi?id=138138 + + Appears to be failing some JS tests (Requested by mlam_ on + #webkit). + + Reverted changeset: + + "Holes are not copied properly when Arrays change shape to + ArrayStorage type." + https://bugs.webkit.org/show_bug.cgi?id=138118 + http://trac.webkit.org/changeset/175249 + +2014-10-27 Mark Lam <mark.lam@apple.com> + + Holes are not copied properly when Arrays change shape to ArrayStorage type. + <https://webkit.org/b/138118> + + Reviewed by Mark Hahnenberg. + + When we convert non-ArrayStorage typed arrays into ArrayStorage typed arrays, + we skipped the holes. As a result, the slots in the ArrayStorage vector that + corresponds to those holes are uninitialize. This is now fixed. + + * runtime/JSObject.cpp: + (JSC::JSObject::convertUndecidedToArrayStorage): + (JSC::JSObject::convertInt32ToArrayStorage): + (JSC::JSObject::convertDoubleToArrayStorage): + (JSC::JSObject::convertContiguousToArrayStorage): + +2014-10-27 Mark Lam <mark.lam@apple.com> + + Crash when attempting to perform array iteration on a non-array with numeric keys not initialized. + <https://webkit.org/b/137814> + + Reviewed by Geoffrey Garen. + + The arrayIteratorNextThunkGenerator() thunk was not checking for the case where + the butterfly may be NULL. This was the source of the crash, and is now fixed. + + In addition, it is also not checking for the case where a property named "length" + may have been set on the iterated object. The thunk only checks the butterfly's + publicLength for its iteration operation. Array objects will work fine with this + because it always updates its butterfly's publicLength when its length changes. + In the case of iterable non-Array objects, the "length" property will require a + look up outside of the scope of this thunk. The fix is simply to limit the fast + case checks in this thunk to Array objects. + + * jit/ThunkGenerators.cpp: + (JSC::arrayIteratorNextThunkGenerator): + +2014-10-27 Mark Lam <mark.lam@apple.com> + + Simplified some JSObject methods for converting arrays to ArrayStorage shape. + <https://webkit.org/b/138119> + + Reviewed by Filip Pizlo. + + Currently, for each Undecided, Int32, Double, and Contiguous array shapes, + there are 3 JSObject methods to convert them to ArrayStorage shape: + ArrayStorage* convert<shape>ToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength); + ArrayStorage* convert<shape>ToArrayStorage(VM&, NonPropertyTransition); + ArrayStorage* convert<shape>ToArrayStorage(VM&); + + However, the neededLength that is passed is always m_butterfly->vectorLength(). + Hence, the method that takes a neededLength is really not needed. This patch + removes this unneeded verbosity. + + * runtime/JSObject.cpp: + (JSC::JSObject::convertUndecidedToArrayStorage): + (JSC::JSObject::convertInt32ToArrayStorage): + - Also reordered the placement of the DeferGC statement so this Int32 function + will look more similar to the others. + (JSC::JSObject::convertDoubleToArrayStorage): + (JSC::JSObject::convertContiguousToArrayStorage): + * runtime/JSObject.h: + +2014-10-25 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: timelines should not count time elapsed while paused in the debugger + https://bugs.webkit.org/show_bug.cgi?id=136351 + + Unreviewed, follow-up fix after r175203. The debugger agent should not assume + that the inspector environment's stopwatch has already been started. + + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::didPause): Check if the stopwatch isActive() before stopping. + +2014-10-18 Brian J. Burg <burg@cs.washington.edu> + + Web Inspector: timelines should not count time elapsed while paused in the debugger + https://bugs.webkit.org/show_bug.cgi?id=136351 + + Reviewed by Timothy Hatcher. + + Now that we have a stopwatch to provide pause-aware timing data, we can remove the + profiler's handling of debugger pause/continue callbacks. The debugger agent accounts + for suspended execution by pausing and resuming the stopwatch. + + * API/JSProfilerPrivate.cpp: + (JSStartProfiling): Use a fresh stopwatch when profiling from the JSC API. + * inspector/InspectorEnvironment.h: + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::executionStopwatch): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/ScriptDebugServer.cpp: + (Inspector::ScriptDebugServer::handlePause): + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::InspectorDebuggerAgent::didPause): + (Inspector::InspectorDebuggerAgent::breakpointActionProbe): + (Inspector::InspectorDebuggerAgent::didContinue): + * inspector/agents/InspectorDebuggerAgent.h: + * profiler/LegacyProfiler.cpp: + (JSC::LegacyProfiler::profiler): Use nullptr. + (JSC::LegacyProfiler::startProfiling): Hand off a stopwatch to the profile generator. + (JSC::LegacyProfiler::stopProfiling): Use nullptr. + (JSC::LegacyProfiler::didPause): Deleted. + (JSC::LegacyProfiler::didContinue): Deleted. + * profiler/LegacyProfiler.h: + * profiler/Profile.cpp: The root node should always have a start time of 0.0. + (JSC::Profile::Profile): + * profiler/ProfileGenerator.cpp: Remove debugger pause/continue callbacks and the + timestamp member that was used to track time elapsed by the debugger. Just use the + stopwatch's elapsed times to generate start/elapsed times for function calls. + + (JSC::ProfileGenerator::create): + (JSC::ProfileGenerator::ProfileGenerator): + (JSC::AddParentForConsoleStartFunctor::operator()): The parent node of |console.profile| + should have a start time of 0.0, since it represents the starting node of profiling. + + (JSC::ProfileGenerator::beginCallEntry): + (JSC::ProfileGenerator::endCallEntry): + (JSC::ProfileGenerator::didPause): Deleted. + (JSC::ProfileGenerator::didContinue): Deleted. + * profiler/ProfileGenerator.h: + +2014-10-24 Mark Lam <mark.lam@apple.com> + + Simplified IndexingType's hasAnyArrayStorage(). + <https://webkit.org/b/138051> + + Reviewed by Michael Saboff. + + IndexingType's hasAnyArrayStorage() currently does subtraction of ArrayStorageShape + with the purpose of making non-ArrayStorage types underflow (with that subtraction) + and have a result that exceeds SlowPutArrayStorageShape. What it is doing is + basically checking for a shape value that is greater equal to ArrayStorageShape. + We can just simplify the code as such. + + Also added a comment to describe the structure of the bits in IndexingType. + + * runtime/IndexingType.h: + (JSC::hasAnyArrayStorage): + +2014-10-23 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Provide a way to have alternate inspector agents + https://bugs.webkit.org/show_bug.cgi?id=137901 + + Reviewed by Brian Burg. + + Provide a way to use alternate inspector agents debugging a JSContext. + Expose a very slim private API that a client could use to know when + an inspector has connected/disconnected, and a way to register its + augmentative agents. + + * Configurations/FeatureDefines.xcconfig: + * JavaScriptCore.xcodeproj/project.pbxproj: + New feature guard. New files. + + * API/JSContextRef.cpp: + (JSGlobalContextGetAugmentableInspectorController): + * API/JSContextRefInspectorSupport.h: Added. + Access to the private interface from a JSContext. + + * inspector/JSGlobalObjectInspectorController.cpp: + (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController): + (Inspector::JSGlobalObjectInspectorController::connectFrontend): + (Inspector::JSGlobalObjectInspectorController::disconnectFrontend): + * inspector/JSGlobalObjectInspectorController.h: + * inspector/augmentable/AugmentableInspectorController.h: Added. + (Inspector::AugmentableInspectorController::~AugmentableInspectorController): + (Inspector::AugmentableInspectorController::connected): + * inspector/augmentable/AugmentableInspectorControllerClient.h: Added. + (Inspector::AugmentableInspectorControllerClient::~AugmentableInspectorControllerClient): + * inspector/augmentable/AlternateDispatchableAgent.h: Added. + (Inspector::AlternateDispatchableAgent::AlternateDispatchableAgent): + Provide the private APIs a client could use to add alternate agents using alternate backend dispatchers. + + * inspector/scripts/codegen/__init__.py: + * inspector/scripts/generate-inspector-protocol-bindings.py: + (generate_from_specification): + New includes, and use the new generator. + + * inspector/scripts/codegen/generate_alternate_backend_dispatcher_header.py: Added. + (AlternateBackendDispatcherHeaderGenerator): + (AlternateBackendDispatcherHeaderGenerator.__init__): + (AlternateBackendDispatcherHeaderGenerator.output_filename): + (AlternateBackendDispatcherHeaderGenerator.generate_output): + (AlternateBackendDispatcherHeaderGenerator._generate_handler_declarations_for_domain): + (AlternateBackendDispatcherHeaderGenerator._generate_handler_declaration_for_command): + Generate the abstract AlternateInspectorBackendDispatcher interfaces. + + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator.generate_output): + (BackendDispatcherHeaderGenerator._generate_alternate_handler_forward_declarations_for_domains): + (BackendDispatcherHeaderGenerator._generate_alternate_handler_forward_declarations_for_domains.AlternateInspector): + Forward declare alternate dispatchers, and allow setting an alternate dispatcher on a domain dispatcher. + + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: + (BackendDispatcherImplementationGenerator.generate_output): + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + Check for and dispatch on an AlternateInspectorBackendDispatcher if there is one for this domain. + + * inspector/scripts/codegen/generator_templates.py: + (AlternateInspectorBackendDispatcher): + (AlternateInspector): + Template boilerplate for prelude and postlude. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + Rebaseline tests. + +2014-10-23 Michael Saboff <msaboff@apple.com> + + offsets.rb:183:in `buildOffsetsMap': unhandled exception - is offlineasm dependency tracking broken? (132668) + https://bugs.webkit.org/show_bug.cgi?id=138017 + + Reviewed by Mark Lam. + + Removed from the nput file $(SRCROOT)/llint/LowLevelAssembler.asm and output file + $(BUILT_PRODUCTS_DIR)/LLIntOffsets/LLIntDesiredOffsets.h from the Generate Derived Sources + build phase in the LLInt Offset target. There is no need for Xcode to do any dependency + checking with these files as the ruby script offlineasm/generate_offset_extractor.rb will + do that for us. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2014-10-23 Michael Saboff <msaboff@apple.com> + + Change CallFrame::lexicalGlobalObject() to use Callee instead of JSScope + https://bugs.webkit.org/show_bug.cgi?id=136901 + + Reviewed by Mark Lam. + + Implement ExecState::lexicalGlobalObject() using Callee. + + * runtime/JSScope.h: + (JSC::ExecState::lexicalGlobalObject): + +2014-10-22 Milan Crha <mcrha@redhat.com> + + Prefix isnan() with std::. + <https://webkit.org/b/137966>. + + Reviewed by Carlos Garcia Campos. + + * profiler/ProfileNode.h: + (JSC::ProfileNode::Call::setStartTime): + (JSC::ProfileNode::Call::setElapsedTime): + +2014-10-22 Mark Lam <mark.lam@apple.com> + + Refactoring to simplify some code in DatePrototype.cpp. + <https://webkit.org/b/137997> + + Reviewed by Filip Pizlo. + + A bunch of functions in DatePrototype.cpp have the pattern of loading a + constant into a local variable only to pass it to a callee function + immediately after. There is no other use for that variable. This adds + additional verbosity with no added benefit. + + This patch refactors those functions to just pass the constant arg directly. + + * runtime/DatePrototype.cpp: + (JSC::dateProtoFuncSetMilliSeconds): + (JSC::dateProtoFuncSetUTCMilliseconds): + (JSC::dateProtoFuncSetSeconds): + (JSC::dateProtoFuncSetUTCSeconds): + (JSC::dateProtoFuncSetMinutes): + (JSC::dateProtoFuncSetUTCMinutes): + (JSC::dateProtoFuncSetHours): + (JSC::dateProtoFuncSetUTCHours): + (JSC::dateProtoFuncSetDate): + (JSC::dateProtoFuncSetUTCDate): + (JSC::dateProtoFuncSetMonth): + (JSC::dateProtoFuncSetUTCMonth): + (JSC::dateProtoFuncSetFullYear): + (JSC::dateProtoFuncSetUTCFullYear): + +2014-10-22 Byungseon Shin <sun.shin@lge.com> + + String(new Date(Mar 30 2014 01:00:00)) is wrong in CET + https://bugs.webkit.org/show_bug.cgi?id=130967 + + Reviewed by Mark Lam. + + By definition of calculateLocalTimeOffset, input time should be UTC time. + But there are many cases when input time is based on local time. + So, it gives erroneous results while calculating offset of DST boundary time. + By adding a argument to distinguish UTC and local time, we can get the correct offset. + + * JavaScriptCore.order: + * runtime/DateConstructor.cpp: + (JSC::constructDate): + (JSC::callDate): + (JSC::dateUTC): + * runtime/DateInstance.cpp: + (JSC::DateInstance::calculateGregorianDateTime): + (JSC::DateInstance::calculateGregorianDateTimeUTC): + * runtime/DatePrototype.cpp: + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetMilliSeconds): + (JSC::dateProtoFuncSetUTCMilliseconds): + (JSC::dateProtoFuncSetSeconds): + (JSC::dateProtoFuncSetUTCSeconds): + (JSC::dateProtoFuncSetMinutes): + (JSC::dateProtoFuncSetUTCMinutes): + (JSC::dateProtoFuncSetHours): + (JSC::dateProtoFuncSetUTCHours): + (JSC::dateProtoFuncSetDate): + (JSC::dateProtoFuncSetUTCDate): + (JSC::dateProtoFuncSetMonth): + (JSC::dateProtoFuncSetUTCMonth): + (JSC::dateProtoFuncSetFullYear): + (JSC::dateProtoFuncSetUTCFullYear): + (JSC::dateProtoFuncSetYear): + * runtime/JSDateMath.cpp: + (JSC::localTimeOffset): + (JSC::gregorianDateTimeToMS): + (JSC::msToGregorianDateTime): + (JSC::parseDateFromNullTerminatedCharacters): + * runtime/JSDateMath.h: + * runtime/VM.h: + (JSC::LocalTimeOffsetCache::LocalTimeOffsetCache): + (JSC::LocalTimeOffsetCache::reset): + Passing TimeType argument to distingush UTC time and local time. + +2014-10-22 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Fix generator importing of protocol type "any", treat as value + https://bugs.webkit.org/show_bug.cgi?id=137931 + + Reviewed by Timothy Hatcher. + + Treat incoming "any" objects as InspectorValues, which can be any type. + Add the necessary boilerplate to import. + + * inspector/InspectorBackendDispatcher.cpp: + (Inspector::AsMethodBridges::asValue): + (Inspector::InspectorBackendDispatcher::getValue): + * inspector/InspectorBackendDispatcher.h: + * inspector/scripts/codegen/generator.py: + (Generator.keyed_get_method_for_type): + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + +2014-10-22 Michael Saboff <msaboff@apple.com> + + REGRESSION(r174996): Broke C_LOOP + https://bugs.webkit.org/show_bug.cgi?id=137971 + + Reviewed by Mark Lam. + + Removed incorrect move to cfr (CallFrameRegister) before we make the call to a native function. + After r174996, the source register for the move contained garbage causing the crash. The move + to cfr before making the call to the native function is wrong and should have been removed + some time ago. This brings the ARM64 / C_LOOP code path inline with the other CPU paths. + Tested on ARM64 as well as a C_LOOP build. + + * llint/LowLevelInterpreter64.asm: + +2014-10-21 Mark Lam <mark.lam@apple.com> + + Remove erroneous canUseJIT() in the intrinsics version of JITThunks::hostFunctionStub(). + <https://webkit.org/b/137937> + + Reviewed by Michael Saboff. + + This version of JITThunks::hostFunctionStub() can only be called from the intrinsics + version of VM::getHostFunction() which asserts canUseJIT(). Hence, we can eliminate + the canUseJIT() check in JITThunks::hostFunctionStub(). We don't handle the + !canUseJIT() case properly there anyway. + + * jit/JITThunks.cpp: + (JSC::JITThunks::hostFunctionStub): + +2014-10-21 Michael Saboff <msaboff@apple.com> + + Add operator==(PropertyName, const char*) + https://bugs.webkit.org/show_bug.cgi?id=137925 + + Reviewed by Mark Lam. + + * runtime/PropertyName.h: + (JSC::operator==): Added to simplify comparison with string literals. + + +2014-10-21 Michael Saboff <msaboff@apple.com> + + Change native call frames to use the scope from their Callee instead of their caller's scope + https://bugs.webkit.org/show_bug.cgi?id=137907 + + Reviewed by Mark Lam. + + Changed setting of scope for native CallFrames to use the scope associated with the + Callee instead of the caller's scope. + + * jit/ThunkGenerators.cpp: + (JSC::nativeForGenerator): + * llint/LowLevelInterpreter32_64.asm: + * llint/LowLevelInterpreter64.asm: + +2014-10-21 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> + + Add missing ENABLE(FTL_NATIVE_CALL_INLINING) guard to BundlePath.cpp after r174940 + https://bugs.webkit.org/show_bug.cgi?id=137924 + + Reviewed by Csaba Osztrogonác. + + * runtime/BundlePath.cpp: + +2014-10-21 Dániel Bátyai <dbatyai.u-szeged@partner.samsung.com> + + Fix FTL Native Inlining for EFL + https://bugs.webkit.org/show_bug.cgi?id=137774 + + Reviewed by Michael Saboff. + + Added required functionality for Native Inlining to EFL, and fixed a bug/typo in the original code, + which caused incorrect memory allocation. + + * CMakeLists.txt: + * create-llvm-ir-from-source-file.py: Added. + * create-symbol-table-index.py: Added. + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::lower): + (JSC::FTL::LowerDFGToLLVM::getModuleByPathForSymbol): + (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability): + (JSC::FTL::LowerDFGToLLVM::exitValueForNode): + * runtime/BundlePath.cpp: Added. + (JSC::bundlePath): + * runtime/JSDataViewPrototype.cpp: + (JSC::getData): + (JSC::setData): + * runtime/MathObject.cpp: + +2014-10-21 Milan Crha <mcrha@redhat.com> + + Move JSC::MacroAssemblerX86Common::s_sse2CheckState definition to MacroAssemblerX86Common.cpp. + <https://webkit.org/b/137807> + + Reviewed by Csaba Osztrogonác. + + * assembler/MacroAssemblerX86Common.cpp: + * jit/JIT.cpp: + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed add back copyright line that was accidentally removed. + + * inspector/scripts/codegen/generator_templates.py: + (GeneratorTemplates): + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: InspectorBackendCommands should include when to activate particular domains + https://bugs.webkit.org/show_bug.cgi?id=137753 + + Reviewed by Timothy Hatcher. + + Add an availability property to domains that only activate for + particular debuggable types. If missing, the domain is always + activated. Otherwise it must be a debuggable type string. + When a frontend is opened for that debuggable type, the domain + will be activated. + + * inspector/scripts/codegen/models.py: + (Protocol.parse_domain): + (Domain.__init__): + (Domains): + Parse and validate the Domain's "availability" property. + + * inspector/scripts/codegen/generate_backend_commands.py: + (BackendCommandsGenerator.generate_domain): + Emit InspectorBackend.activateDomain with debuggable type filter. + + * inspector/protocol/ApplicationCache.json: + * inspector/protocol/CSS.json: + * inspector/protocol/DOM.json: + * inspector/protocol/DOMDebugger.json: + * inspector/protocol/DOMStorage.json: + * inspector/protocol/Database.json: + * inspector/protocol/IndexedDB.json: + * inspector/protocol/LayerTree.json: + * inspector/protocol/Network.json: + * inspector/protocol/Page.json: + * inspector/protocol/Replay.json: + * inspector/protocol/Timeline.json: + * inspector/protocol/Worker.json: + These domains only activate for Web debuggables. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + Update existing tests that now have activate output. + + * inspector/scripts/tests/expected/fail-on-domain-availability.json-error: Added. + * inspector/scripts/tests/fail-on-domain-availability.json: Added. + Add a test for "availability" validation. + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + [Win] Build fix for generated inspector files. + + Rubberstamped by Brent Fulgham. + + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator._generate_async_handler_declaration_for_command): + * inspector/scripts/codegen/generator_templates.py: + (GeneratorTemplates): + +2014-10-20 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed build fix. + + We need to (1) pass the 'windows' argument to our script for checking feature definitions, + and (2) we must use Cwd::realpath on our path input arguments to avoid Cygwin and Windows + getting confused about path separators versus escape characters. + + + * JavaScriptCore.vcxproj/build-generated-files.pl: + +2014-10-20 Mark Lam <mark.lam@apple.com> + + [Follow up] Web Process crash when starting the web inspector after r174025. + <https://webkit.org/b/137340> + + Reviewed by Geoffrey Garen. + + Applied Geoff's feedback to clean up some code for better clarity after + r174856. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::insertCheck): + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertOutOfOrder): + +2014-10-20 Mark Lam <mark.lam@apple.com> + + Factor out JITCode::typeName() for debugging use. + <https://webkit.org/b/137888> + + Reviewed by Geoffrey Garen. + + JITCode's printInternal() currently decodes the JITType into a string and + prints it. This change factors out the part that decodes the JITType into + JITCode::typeName() so that we can call it from lldb while debugging to + quickly decode a JITType value. + + * jit/JITCode.cpp: + (JSC::JITCode::typeName): + (WTF::printInternal): + * jit/JITCode.h: + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed Windows Build Fix #2 after r174892. + + * JavaScriptCore.vcxproj/build-generated-files.pl: + Define FEATURE_DEFINES for JavaScriptCore's DerivedSources.make. + This uses the same technique as WebCore. + +2014-10-20 Mark Lam <mark.lam@apple.com> + + Fix placement of a few items in vcxproj ItemGroups. + <https://webkit.org/b/137886> + + Reviewed by Geoffrey Garen. + + https://webkit.org/b/137873 is likely a cut-and-paste error that manifested + because we had ClCompile and ClInclude entries mixed up in the wrong ItemGroups. + We should fix these so that ClCompile entries are in the ClCompile ItemGroup, + and ClInclude entries in the ClInclude ItemGroup. This will help reduce the + chance of future cut-and-paste errors of this nature. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + Unreviewed Windows Build Fix after r174892. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + Update file name to the new generated file name. + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Rename generated Inspector.json to CombinedDomains.json to prevent name collisions + https://bugs.webkit.org/show_bug.cgi?id=137825 + + Reviewed by Timothy Hatcher. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.xcodeproj/project.pbxproj: + * inspector/protocol/Inspector.json: Renamed from Source/JavaScriptCore/inspector/protocol/InspectorDomain.json. + +2014-10-20 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Generate all Inspector domains together in JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=137748 + + Reviewed by Brian Burg. + + * inspector/protocol/ApplicationCache.json: Renamed from Source/WebCore/inspector/protocol/ApplicationCache.json. + * inspector/protocol/CSS.json: Renamed from Source/WebCore/inspector/protocol/CSS.json. + * inspector/protocol/DOM.json: Renamed from Source/WebCore/inspector/protocol/DOM.json. + * inspector/protocol/DOMDebugger.json: Renamed from Source/WebCore/inspector/protocol/DOMDebugger.json. + * inspector/protocol/DOMStorage.json: Renamed from Source/WebCore/inspector/protocol/DOMStorage.json. + * inspector/protocol/Database.json: Renamed from Source/WebCore/inspector/protocol/Database.json. + * inspector/protocol/IndexedDB.json: Renamed from Source/WebCore/inspector/protocol/IndexedDB.json. + * inspector/protocol/LayerTree.json: Renamed from Source/WebCore/inspector/protocol/LayerTree.json. + * inspector/protocol/Network.json: Renamed from Source/WebCore/inspector/protocol/Network.json. + * inspector/protocol/Page.json: Renamed from Source/WebCore/inspector/protocol/Page.json. + * inspector/protocol/Replay.json: Renamed from Source/WebCore/inspector/protocol/Replay.json. + * inspector/protocol/Timeline.json: Renamed from Source/WebCore/inspector/protocol/Timeline.json. + * inspector/protocol/Worker.json: Renamed from Source/WebCore/inspector/protocol/Worker.json. + Move all protocol files into this directory. + + * inspector/InspectorProtocolTypesBase.h: Renamed from Source/JavaScriptCore/inspector/InspectorProtocolTypes.h. + Renamed the base types file to not clash with the generated types file. + + * CMakeLists.txt: + * DerivedSources.make: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.vcxproj/copy-files.cmd: + * JavaScriptCore.xcodeproj/project.pbxproj: + Update build phases for new JSON files and new filenames. + + * inspector/scripts/tests/expected/commands-with-async-attribute.json-result: + * inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result: + * inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result: + * inspector/scripts/tests/expected/events-with-optional-parameters.json-result: + * inspector/scripts/tests/expected/generate-domains-with-feature-guards.json-result: + * inspector/scripts/tests/expected/same-type-id-different-domain.json-result: + * inspector/scripts/tests/expected/shadowed-optional-type-setters.json-result: + * inspector/scripts/tests/expected/type-declaration-aliased-primitive-type.json-result: + * inspector/scripts/tests/expected/type-declaration-array-type.json-result: + * inspector/scripts/tests/expected/type-declaration-enum-type.json-result: + * inspector/scripts/tests/expected/type-declaration-object-type.json-result: + * inspector/scripts/tests/expected/type-requiring-runtime-casts.json-result: + Updated names of things now that prefixes are no longer needed. + + * inspector/ConsoleMessage.h: + * inspector/ContentSearchUtilities.cpp: + * inspector/ContentSearchUtilities.h: + * inspector/InjectedScript.h: + * inspector/InjectedScriptBase.h: + * inspector/ScriptCallFrame.h: + * inspector/ScriptCallStack.h: + * inspector/agents/InspectorAgent.h: + * inspector/agents/InspectorConsoleAgent.h: + * inspector/agents/InspectorDebuggerAgent.cpp: + (Inspector::breakpointActionTypeForString): + * inspector/agents/InspectorDebuggerAgent.h: + * inspector/agents/InspectorRuntimeAgent.h: + * runtime/TypeProfiler.cpp: + * runtime/TypeSet.cpp: + Update includes and update a few function names that are generated. + + * inspector/scripts/codegen/generate_protocol_types_header.py: + (ProtocolTypesHeaderGenerator.output_filename): + (ProtocolTypesHeaderGenerator.generate_output): + Include an export macro for type string constants defined in the implementation file. + + * inspector/scripts/codegen/generate_backend_commands.py: + (BackendCommandsGenerator.output_filename): + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator.output_filename): + (BackendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: + (BackendDispatcherImplementationGenerator.output_filename): + (BackendDispatcherImplementationGenerator.generate_output): + (BackendDispatcherImplementationGenerator._generate_async_dispatcher_class_for_domain): + (BackendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_command): + * inspector/scripts/codegen/generate_frontend_dispatcher_header.py: + (FrontendDispatcherHeaderGenerator.output_filename): + (FrontendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_frontend_dispatcher_implementation.py: + (FrontendDispatcherImplementationGenerator.output_filename): + (FrontendDispatcherImplementationGenerator.generate_output): + (FrontendDispatcherImplementationGenerator._generate_dispatcher_implementation_for_event): + (_generate_class_for_object_declaration): + (_generate_builder_setter_for_member): + (_generate_unchecked_setter_for_member): + * inspector/scripts/codegen/generate_protocol_types_implementation.py: + (ProtocolTypesImplementationGenerator.output_filename): + (ProtocolTypesImplementationGenerator.generate_output): + (ProtocolTypesImplementationGenerator._generate_enum_mapping): + * inspector/scripts/codegen/models.py: + (Framework.fromString): + (Frameworks): + * inspector/scripts/generate-inspector-protocol-bindings.py: + Simplify generator now that prefixes are no longer needed. This updates + filenames, includes, and the list of supported directories. + +2014-10-20 Csaba Osztrogonác <ossy@webkit.org> + + Remove obsolete comments after r99798 + https://bugs.webkit.org/show_bug.cgi?id=137871 + + Reviewed by Darin Adler. + + r99798 removed the comment in MacroAssemblerARMv7::supportsFloatingPointTruncate(), + so we should remove the stale references to this removed comment. + + * assembler/MacroAssemblerX86.h: + * assembler/MacroAssemblerX86_64.h: + +2014-10-20 Csaba Osztrogonác <ossy@webkit.org> + + MacroAssemblerX86Common.cpp should be built on Windows too + https://bugs.webkit.org/show_bug.cgi?id=137873 + + Reviewed by Brent Fulgham. + + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + +2014-10-20 Csaba Osztrogonác <ossy@webkit.org> + + [cmake] Remove duplicated source files + https://bugs.webkit.org/show_bug.cgi?id=137875 + + Reviewed by Gyuyoung Kim. + + * CMakeLists.txt: + +2014-10-18 Brian J. Burg <burg@cs.washington.edu> + + Web Replay: code generator shouldn't complain about enums without a storage type if they are in an enclosing scope + https://bugs.webkit.org/show_bug.cgi?id=137084 + + Reviewed by Joseph Pecoraro. + + In order to generate encode/decode method declarations without pulling in lots of headers, + the generator must forward declare enums (for enum classes or enums with explicit sizes). + + Change the generator to not require an explicit size if an enum is declared inside a struct + or class definition. In that case, it must pull in headers since scoped enums can't be + forward declared. + + This patch also fixes some chained if-statements that should be if-else statements. + + Test: updated replay/scripts/tests/generate-enum-encoding-helpers.json to cover the new case. + + * replay/scripts/CodeGeneratorReplayInputs.py: + (InputsModel.parse_type_with_framework_name.is): + (InputsModel.parse_type_with_framework_name.is.must): + (Generator.generate_enum_trait_implementation): + (InputsModel.parse_type_with_framework_name): Deleted. + * replay/scripts/CodeGeneratorReplayInputsTemplates.py: + * replay/scripts/tests/expected/fail-on-c-style-enum-no-storage.json-error: + * replay/scripts/tests/expected/generate-enum-encoding-helpers-with-guarded-values.json-TestReplayInputs.cpp: + (JSC::EncodingTraits<WebCore::MouseButton>::decodeValue): + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.cpp: + (JSC::EncodingTraits<WebCore::MouseButton>::decodeValue): + (JSC::EncodingTraits<WebCore::PlatformEvent::Type>::encodeValue): + (JSC::EncodingTraits<WebCore::PlatformEvent::Type>::decodeValue): + * replay/scripts/tests/expected/generate-enum-encoding-helpers.json-TestReplayInputs.h: + * replay/scripts/tests/expected/generate-enums-with-same-base-name.json-TestReplayInputs.cpp: + (JSC::EncodingTraits<WebCore::FormData1::Type>::decodeValue): + (JSC::EncodingTraits<PlatformEvent1::Type>::decodeValue): + * replay/scripts/tests/generate-enum-encoding-helpers.json: Added a new input to cover this case. + +2014-10-17 Mark Lam <mark.lam@apple.com> + + Web Process crash when starting the web inspector after r174025. + <https://webkit.org/b/137340> + + Reviewed by Filip Pizlo. + + After r174025, we can generate a bad graph in the DFG fixup phase like so: + + 102:<!0:-> StoreBarrier(Check:KnownCell:@19, ..., bc#44) + 60:<!0:-> PutStructure(Check:KnownCell:@19, ..., bc#44) + 103:<!0:-> Check(Check:NotCell:@54, ..., bc#44) + // ^-- PutByOffset's StoreBarrier has been elided and replaced + // with a speculation check which can OSR exit. + 61:<!0:-> PutByOffset(Check:KnownCell:@19, ..., bc#44) + + As a result, the structure change will get executed even if we end up OSR + exiting before the PutByOffset. In the baseline JIT code, the structure now + erroneously tells the put operation that there is a value in that property + slot when it is actually uninitialized (hence, the crash). + + The fix is to insert the Check at the earliest point possible: + + 1. If the checked node is in the same bytecode as the PutByOffset, then + the earliest point where we can insert the Check is right after the + checked node. + + 2. If the checked node is from a preceding bytecode (before the PutByOffset), + then the earliest point where we can insert the Check is at the start + of the current bytecode. + + Also reverted the workaround from r174749: https://webkit.org/b/137758. + + Benchmark results appear to be a wash on aggregate. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::indexOfNode): + (JSC::DFG::FixupPhase::indexOfFirstNodeOfExitOrigin): + (JSC::DFG::FixupPhase::fixupNode): + (JSC::DFG::FixupPhase::insertCheck): + * dfg/DFGInsertionSet.h: + (JSC::DFG::InsertionSet::insertOutOfOrder): + (JSC::DFG::InsertionSet::insertOutOfOrderNode): + +2014-10-10 Oliver Hunt <oliver@apple.com> + + Various arguments optimisations in codegen fail to account for arguments being in lexical record + https://bugs.webkit.org/show_bug.cgi?id=137617 + + Reviewed by Michael Saboff. + + Rework the way we track |arguments| references so that we don't try + to use the |arguments| reference on the stack if it's not safe. + + To do this without nuking performance it was necessary to update + the parser to track modification of the |arguments| reference + itself. + + * bytecode/CodeBlock.cpp: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::willResolveToArguments): + (JSC::BytecodeGenerator::uncheckedLocalArgumentsRegister): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitConstruct): + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::uncheckedRegisterForArguments): Deleted. + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::hasSafeLocalArgumentsRegister): + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::getArgumentByVal): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::ArrayPatternNode::emitDirectBinding): + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::existingArguments): + * parser/Nodes.h: + (JSC::ScopeNode::modifiesArguments): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): + * parser/Parser.h: + (JSC::Scope::getCapturedVariables): + * parser/ParserModes.h: + +2014-10-17 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Use WTF::move() instead of std::move() to help ensure move semantics in JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=137809 + + Reviewed by Csaba Osztrogonác. + + Substitution of WTF::move() for std::move(). Clean up std::move() in JavaScriptCore. + + * bytecode/GetByIdStatus.cpp: + (JSC::GetByIdStatus::computeForStubInfo): + * bytecode/PutByIdStatus.cpp: + (JSC::PutByIdStatus::computeForStubInfo): + * bytecode/PutByIdVariant.cpp: + (JSC::PutByIdVariant::setter): + +2014-10-15 Oliver Hunt <oliver@apple.com> + + Use a single allocation for the Arguments object + https://bugs.webkit.org/show_bug.cgi?id=137751 + + Reviewed by Filip Pizlo. + + This patch removes the secondary allocation for parameters in the Arguments + object. This is faily simple, but we needed to make it possible for the JIT + to allocate a variable GC object. To do this i've added a new + emitAllocateVariableSizedJSObject function to the JIT that does the work to + find the correct heap for a variable sized allocation and then bump that + allocator. + + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::emitAllocateArguments): + * dfg/DFGSpeculativeJIT.h: + (JSC::DFG::SpeculativeJIT::emitAllocateVariableSizedJSObject): + * heap/CopyToken.h: + * heap/Heap.h: + (JSC::Heap::subspaceForObjectWithoutDestructor): + (JSC::Heap::subspaceForObjectNormalDestructor): + (JSC::Heap::subspaceForObjectsWithImmortalStructure): + * heap/MarkedSpace.h: + (JSC::MarkedSpace::subspaceForObjectsWithNormalDestructor): + (JSC::MarkedSpace::subspaceForObjectsWithImmortalStructure): + (JSC::MarkedSpace::subspaceForObjectsWithoutDestructor): + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::createArguments): + * runtime/Arguments.cpp: + (JSC::Arguments::visitChildren): + (JSC::Arguments::copyBackingStore): + (JSC::Arguments::tearOff): + (JSC::Arguments::allocateRegisterArray): Deleted. + * runtime/Arguments.h: + (JSC::Arguments::create): + (JSC::Arguments::isTornOff): + (JSC::Arguments::offsetOfRegisterArray): + (JSC::Arguments::registerArraySizeInBytes): + (JSC::Arguments::registerArray): + (JSC::Arguments::allocationSize): Deleted. + +2014-10-15 Filip Pizlo <fpizlo@apple.com> + + Apparently we've had a hole in arguments capture all along + https://bugs.webkit.org/show_bug.cgi?id=137767 + + Reviewed by Oliver Hunt. + + * dfg/DFGByteCodeParser.cpp: + (JSC::DFG::ByteCodeParser::getArgument): + * tests/stress/arguments-captured.js: Added. + (foo): + (bar): + +2014-10-16 Saam Barati <saambarati1@gmail.com> + + Have the ProfileType node in the DFG convert to a structure check where it can + https://bugs.webkit.org/show_bug.cgi?id=137596 + + Reviewed by Filip Pizlo. + + TypeSet now keeps track of the live set of Structures it has seen. + It no longer nukes everything during GC. It now only removes unmarked + structures during GC. This modification allows the ProfileType node + to convert into a CheckStructure node safely in the DFG. + + This change brings up the conversion rate from ProfileType to Check + or CheckStructrue from ~45% to ~65%. This change also speeds the + type profiler up significantly: consistently between 2x-20x faster. + + This patch also does some slight refactoring: a few type profiler + related fields are moved from VM to TypeProfiler. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + * dfg/DFGNode.h: + (JSC::DFG::Node::convertToCheckStructure): + * heap/Heap.cpp: + (JSC::Heap::collect): + * runtime/SymbolTable.cpp: + (JSC::SymbolTable::uniqueIDForVariable): + * runtime/SymbolTable.h: + * runtime/TypeLocationCache.cpp: + (JSC::TypeLocationCache::getTypeLocation): + * runtime/TypeProfiler.cpp: + (JSC::TypeProfiler::TypeProfiler): + (JSC::TypeProfiler::nextTypeLocation): + (JSC::TypeProfiler::invalidateTypeSetCache): + (JSC::TypeProfiler::dumpTypeProfilerData): + * runtime/TypeProfiler.h: + (JSC::TypeProfiler::getNextUniqueVariableID): + * runtime/TypeProfilerLog.cpp: + (JSC::TypeProfilerLog::processLogEntries): + * runtime/TypeSet.cpp: + (JSC::TypeSet::addTypeInformation): + (JSC::TypeSet::invalidateCache): + * runtime/TypeSet.h: + (JSC::TypeSet::structureSet): + * runtime/VM.cpp: + (JSC::VM::VM): + (JSC::VM::enableTypeProfiler): + (JSC::VM::disableTypeProfiler): + (JSC::VM::dumpTypeProfilerData): + (JSC::VM::nextTypeLocation): Deleted. + (JSC::VM::invalidateTypeSetCache): Deleted. + * runtime/VM.h: + (JSC::VM::typeProfiler): + (JSC::VM::getNextUniqueVariableID): Deleted. + * tests/typeProfiler/dfg-jit-optimizations.js: + +2014-10-16 Adrien Destugues <pulkomandy@gmail.com> + + Use isnan from std namespace in ProfileGenerator.cpp + https://bugs.webkit.org/show_bug.cgi?id=137653 + + Reviewed by Darin Adler. + + The C++ isnan() function is in the std namespace. The unprefixed isnan + may be available because of C99 headers leakage in C++, but should not + be used. + + No new tests: no functional change, build fix on platforms which don't + export C99 functions in C++. + + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::beginCallEntry): + (JSC::ProfileGenerator::endCallEntry): + (JSC::ProfileGenerator::didPause): + (JSC::ProfileGenerator::didContinue): + +2014-10-15 Michael Saboff <msaboff@apple.com> + + REGRESSION(r174025): remote inspector crashes frequently when executing inspector frontend's JavaScript + https://bugs.webkit.org/show_bug.cgi?id=137758 + + Rubber stamped by Filip Pizlo. + + Reverted r174025 for just PutByOffset Nodes. + + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): + +2014-10-14 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Clean up unnecessary PassOwnPtr.h inclusion + https://bugs.webkit.org/show_bug.cgi?id=137726 + + Reviewed by Chris Dumez. + + * API/JSCallbackObject.h: Remove PassOwnPtr.h inclusion. + * bytecode/DFGExitProfile.cpp: ditto. + +2014-10-14 Brent Fulgham <bfulgham@apple.com> + + [Win] Unreviewed gardening. Ignore Visual Studio *.sdf files. + + * JavaScriptCore.vcxproj: Modified properties svn:ignore and svn:ignore. + * JavaScriptCore.vcxproj/jsc: Modified property svn:ignore. + +2014-10-14 Matthew Mirman <mmirman@apple.com> + + Removes references to LLVMJIT which is no longer part of LLVM + https://bugs.webkit.org/show_bug.cgi?id=137708 + + Reviewed by Filip Pizlo. + + * Configurations/LLVMForJSC.xcconfig: removed -lLLVMJIT + * llvm/LLVMAPIFunctions.h: removed LinkInJIT + +2014-10-14 peavo@outlook.com <peavo@outlook.com> + + [Win32] Thunk is not implemented. + https://bugs.webkit.org/show_bug.cgi?id=137691 + + Reviewed by Mark Lam. + + Thunks for functions with double operands (floor, etc.) are not implemented on Win32. + + * jit/ThunkGenerators.cpp: + +2014-10-12 Alexey Proskuryakov <ap@apple.com> + + Adding svn:ignore so that .pyc files don't show up as new. + + * inspector/scripts/codegen: Added property svn:ignore. + +2014-10-10 Commit Queue <commit-queue@webkit.org> + + Unreviewed, rolling out r174606. + https://bugs.webkit.org/show_bug.cgi?id=137621 + + broke a JSC test (Requested by estes on #webkit). + + Reverted changeset: + + "Various arguments optimisations in codegen fail to account + for arguments being in lexical record" + https://bugs.webkit.org/show_bug.cgi?id=137617 + http://trac.webkit.org/changeset/174606 + +2014-10-10 Oliver Hunt <oliver@apple.com> + + Various arguments optimisations in codegen fail to account for arguments being in lexical record + https://bugs.webkit.org/show_bug.cgi?id=137617 + + Reviewed by Michael Saboff. + + Rework the way we track |arguments| references so that we don't try + to use the |arguments| reference on the stack if it's not safe. + + To do this without nuking performance it was necessary to update + the parser to track modification of the |arguments| reference + itself. + + * bytecode/CodeBlock.cpp: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::willResolveToArguments): + (JSC::BytecodeGenerator::uncheckedLocalArgumentsRegister): + (JSC::BytecodeGenerator::emitCall): + (JSC::BytecodeGenerator::emitConstruct): + (JSC::BytecodeGenerator::emitEnumeration): + (JSC::BytecodeGenerator::uncheckedRegisterForArguments): Deleted. + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::hasSafeLocalArgumentsRegister): + * bytecompiler/NodesCodegen.cpp: + (JSC::BracketAccessorNode::emitBytecode): + (JSC::DotAccessorNode::emitBytecode): + (JSC::getArgumentByVal): + (JSC::CallFunctionCallDotNode::emitBytecode): + (JSC::ApplyFunctionCallDotNode::emitBytecode): + (JSC::ArrayPatternNode::emitDirectBinding): + * interpreter/StackVisitor.cpp: + (JSC::StackVisitor::Frame::existingArguments): + * parser/Nodes.h: + (JSC::ScopeNode::modifiesArguments): + * parser/Parser.cpp: + (JSC::Parser<LexerType>::parseInner): + * parser/Parser.h: + (JSC::Scope::getCapturedVariables): + * parser/ParserModes.h: + +2014-10-09 Joseph Pecoraro <pecoraro@apple.com> + + Web Inspector: Remove unused generator code + https://bugs.webkit.org/show_bug.cgi?id=137564 + + Reviewed by Brian Burg. + + * inspector/scripts/codegen/generate_backend_dispatcher_header.py: + (BackendDispatcherHeaderGenerator.generate_output): Deleted. + * inspector/scripts/codegen/generate_backend_dispatcher_implementation.py: + (BackendDispatcherImplementationGenerator.generate_output): + * inspector/scripts/codegen/generate_frontend_dispatcher_header.py: + (FrontendDispatcherHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_frontend_dispatcher_implementation.py: + (FrontendDispatcherImplementationGenerator.generate_output): + * inspector/scripts/codegen/generate_protocol_types_header.py: + (ProtocolTypesHeaderGenerator.generate_output): + * inspector/scripts/codegen/generate_protocol_types_implementation.py: + (ProtocolTypesImplementationGenerator.generate_output): + inputFilename is now handled by the generic generator base class. + + * inspector/scripts/codegen/models.py: + (Framework.fromString): + (Frameworks): + * inspector/scripts/generate-inspector-protocol-bindings.py: + The WTF framework is unused. Remove unexpected frameworks. + +2014-10-09 Dean Jackson <dino@apple.com> + + Remove ENABLE_CSS3_CONDITIONAL_RULES + https://bugs.webkit.org/show_bug.cgi?id=137571 + + Reviewed by Simon Fraser. + + * Configurations/FeatureDefines.xcconfig: + +2014-10-09 Adrien Destugues <pulkomandy@gmail.com> + + Fix compiler warning on noreturn function + https://bugs.webkit.org/show_bug.cgi?id=137558 + + Reviewed by Darin Adler. + + The function is marked "noreturn", but the stub implementation does + return. No new tests: function is never called. Only fixes a warning. + + * heap/HeapStatistics.cpp: + (JSC::HeapStatistics::exitWithFailure): + +2014-10-09 Akos Kiss <akiss@inf.u-szeged.hu> + + Ensure that inline assembly Thunk functions don't conflict with the section designations of the compiler + https://bugs.webkit.org/show_bug.cgi?id=137434 + + Reviewed by Michael Saboff. + + The ARM64 version of the defineUnaryDoubleOpWrapper macro in + ThunkGenerators.cpp contains inline assembly with .text assembler + directive followed by a static variable declaration. This macro gets + expanded several times afterwards, however, only during the compilation + of the first expansion does gcc insert a .data assembler directive + before the assembled version of the static variable. Thus, only the + first variable gets allocated in the .data section, all the others + remain in .text. If JavaScriptCore is built as a shared library then + this causes a segmentation fault during dynamic linking. + + This patch puts a .previous directive at the end of the inline assembly + to ensure that the assumptions of the compiler about the sections are + not broken and the following variable goes to the right place. + + * jit/ThunkGenerators.cpp: + +2014-10-08 Oliver Hunt <oliver@apple.com> + + Make sure arguments tearoff is performed through the environment record if necessary + https://bugs.webkit.org/show_bug.cgi?id=137538 + + Reviewed by Michael Saboff. + + Fairly simple change. If we have a lexical record we need to pull the unmodified + arguments object from the record and then use the standard op_tear_off_arguments + instruction on the temporary. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetOwnScope): + (JSC::BytecodeGenerator::emitReturn): + * bytecompiler/BytecodeGenerator.h: + +2014-10-08 peavo@outlook.com <peavo@outlook.com> + + [WinCairo] Enable JIT on 32-bit. + https://bugs.webkit.org/show_bug.cgi?id=137521 + + Reviewed by Mark Lam. + + Enable JIT on Windows 32-bit, but disable it at runtime if SSE2 is not present. + + * JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl: + * runtime/Options.cpp: + (JSC::recomputeDependentOptions): + +2014-10-08 Brent Fulgham <bfulgham@apple.com> + + [Win] Resolve some static analysis warnings in JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=137508 + + Reviewed by Geoffrey Garen. + + * API/tests/testapi.c: + (assertEqualsAsCharactersPtr): MSVC insists on using %Iu as its format specifier + for size_t. Make the format string conditional on Windows. + * bytecode/Watchpoint.h: + (JSC::InlineWatchpointSet::encodeState): Silence warning about left-shifting 'state' + as a 32-bit value before OR-ing it with a 64-bit value. + * dfg/DFGFixupPhase.cpp: + (JSC::DFG::FixupPhase::fixupNode): Silence warning about operator prescedence + causing the || operation to take place before the >= test. + * dfg/DFGInPlaceAbstractState.cpp: + (JSC::DFG::InPlaceAbstractState::endBasicBlock): Ditto (|| before !=) + * testRegExp.cpp: + (testOneRegExp): Ditto %Iu format specifier. + * yarr/YarrInterpreter.cpp: + (JSC::Yarr::Interpreter::allocParenthesesDisjunctionContext): Silence warning about + using a 32-bit value as part of a 64-bit calculation. + +2014-10-07 Simon Fraser <simon.fraser@apple.com> + + Roll-over Changelogs. + + * ChangeLog-2014-10-07: Copied from Source/JavaScriptCore/ChangeLog. + +== Rolled over to ChangeLog-2014-10-07 == diff --git a/Configurations/Base.xcconfig b/Configurations/Base.xcconfig index 912be77..ded3d37 100644 --- a/Configurations/Base.xcconfig +++ b/Configurations/Base.xcconfig @@ -1,4 +1,4 @@ -// Copyright (C) 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. +// Copyright (C) 2009, 2010, 2011, 2013, 2014 Apple Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions @@ -21,8 +21,12 @@ // (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 "iOS.xcconfig" -#include "../../../../Internal/Configurations/UseInternalSDK.xcconfig" +#include "../../../../Internal/Configurations/HaveInternalSDK.xcconfig" + +USE_INTERNAL_SDK = $(USE_INTERNAL_SDK_$(CONFIGURATION)); +USE_INTERNAL_SDK_Production = YES; +USE_INTERNAL_SDK_Debug = $(HAVE_INTERNAL_SDK); +USE_INTERNAL_SDK_Release = $(HAVE_INTERNAL_SDK); CLANG_CXX_LANGUAGE_STANDARD = gnu++0x; CLANG_CXX_LIBRARY = libc++; @@ -33,32 +37,26 @@ CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; +COMBINE_HIDPI_IMAGES = NO; DEBUG_INFORMATION_FORMAT = dwarf-with-dsym; +ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DEBUGGING_SYMBOLS = default; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_CPP_EXCEPTIONS = NO; GCC_ENABLE_CPP_RTTI = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; -GCC_ENABLE_OBJC_GC = $(GCC_ENABLE_OBJC_GC_$(PLATFORM_NAME)); -GCC_ENABLE_OBJC_GC_iphoneos = NO; -GCC_ENABLE_OBJC_GC_iphonesimulator = NO; -GCC_ENABLE_OBJC_GC_macosx = $(GCC_ENABLE_OBJC_GC_macosx_$(CONFIGURATION)); -GCC_ENABLE_OBJC_GC_macosx_Production = supported; -GCC_ENABLE_OBJC_GC_macosx_Debug = $(GCC_ENABLE_OBJC_GC_macosx_Debug_or_Release); -GCC_ENABLE_OBJC_GC_macosx_Release = $(GCC_ENABLE_OBJC_GC_macosx_Debug_or_Release); -GCC_ENABLE_OBJC_GC_macosx_Debug_or_Release = $(GCC_ENABLE_OBJC_GC_macosx_Debug_or_Release_$(USE_INTERNAL_SDK)); -GCC_ENABLE_OBJC_GC_macosx_Debug_or_Release_ = NO; -GCC_ENABLE_OBJC_GC_macosx_Debug_or_Release_YES = supported; +GCC_ENABLE_OBJC_GC = $(GCC_ENABLE_OBJC_GC_$(PLATFORM_NAME)_$(USE_INTERNAL_SDK)); +GCC_ENABLE_OBJC_GC_macosx_ = NO; +GCC_ENABLE_OBJC_GC_macosx_YES = supported; GCC_ENABLE_SYMBOL_SEPARATION = NO; GCC_FAST_OBJC_DISPATCH = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; -GCC_MODEL_TUNING = $(GCC_MODEL_TUNING_$(PLATFORM_NAME)); -GCC_MODEL_TUNING_macosx = G5; +GCC_NO_COMMON_BLOCKS = YES; GCC_OBJC_CALL_CXX_CDTORS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; -GCC_PREPROCESSOR_DEFINITIONS = $(DEBUG_DEFINES) HAVE_DTRACE=$(HAVE_DTRACE) WEBKIT_VERSION_MIN_REQUIRED=WEBKIT_VERSION_LATEST HAVE_HEADER_DETECTION_H JSC_OBJC_API_AVAILABLE_MAC_OS_X_1080 $(FEATURE_DEFINES) $(GCC_PREPROCESSOR_DEFINITIONS); +GCC_PREPROCESSOR_DEFINITIONS = $(DEBUG_DEFINES) HAVE_HEADER_DETECTION_H $(FEATURE_DEFINES) $(inherited); GCC_STRICT_ALIASING = YES; GCC_THREADSAFE_STATICS = NO; GCC_TREAT_WARNINGS_AS_ERRORS = YES; @@ -86,15 +84,9 @@ LINKER_DISPLAYS_MANGLED_NAMES = YES; PREBINDING = NO; WARNING_CFLAGS = -Wall -Wextra -Wcast-qual -Wchar-subscripts -Wextra-tokens -Wformat=2 -Winit-self -Wmissing-format-attribute -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wundef -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough; -LLVM_LOCAL_HEADER_PATH = $(LLVM_LOCAL_HEADER_PATH_$(PLATFORM_NAME)) -LLVM_LOCAL_HEADER_PATH_macosx = "${BUILT_PRODUCTS_DIR}/usr/local/LLVMForJavaScriptCore/include" -LLVM_LOCAL_HEADER_PATH_iphoneos = ; -LLVM_LOCAL_HEADER_PATH_iphonesimulator = ; +LLVM_LOCAL_HEADER_PATH[sdk=macosx*] = "$(BUILT_PRODUCTS_DIR)/usr/local/LLVMForJavaScriptCore/include"; -LLVM_SYSTEM_HEADER_PATH = $(LLVM_SYSTEM_HEADER_PATH_$(PLATFORM_NAME)) -LLVM_SYSTEM_HEADER_PATH_macosx = /usr/local/LLVMForJavaScriptCore/include; -LLVM_SYSTEM_HEADER_PATH_iphoneos = ; -LLVM_SYSTEM_HEADER_PATH_iphonesimulator = ; +LLVM_SYSTEM_HEADER_PATH[sdk=macosx*] = /usr/local/LLVMForJavaScriptCore/include; HEADER_SEARCH_PATHS = . icu $(LLVM_LOCAL_HEADER_PATH) "${BUILT_PRODUCTS_DIR}/ExtraIncludesForLocalLLVMBuild" $(LLVM_SYSTEM_HEADER_PATH) "${BUILT_PRODUCTS_DIR}/usr/local/include" $(HEADER_SEARCH_PATHS); @@ -109,19 +101,14 @@ STAGED_FRAMEWORKS_SEARCH_PATH_YES = $(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/StagedFram NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR = $(SYSTEM_LIBRARY_DIR)/Frameworks; -JAVASCRIPTCORE_FRAMEWORKS_DIR = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_$(PLATFORM_NAME)); -JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR); -JAVASCRIPTCORE_FRAMEWORKS_DIR_iphonesimulator = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_iphoneos); - -JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_$(USE_STAGING_INSTALL_PATH)); +JAVASCRIPTCORE_FRAMEWORKS_DIR[sdk=iphone*] = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR); +JAVASCRIPTCORE_FRAMEWORKS_DIR = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_$(PLATFORM_NAME)_USE_STAGING_INSTALL_PATH_$(USE_STAGING_INSTALL_PATH)); JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_ = $(JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_NO); JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_NO = $(NORMAL_JAVASCRIPTCORE_FRAMEWORKS_DIR); JAVASCRIPTCORE_FRAMEWORKS_DIR_macosx_USE_STAGING_INSTALL_PATH_YES = $(SYSTEM_LIBRARY_DIR)/StagedFrameworks/Safari; -JAVASCRIPTCORE_CONTENTS_DIR = $(JAVASCRIPTCORE_CONTENTS_DIR_$(PLATFORM_NAME)); -JAVASCRIPTCORE_CONTENTS_DIR_iphoneos = JavaScriptCore.framework; -JAVASCRIPTCORE_CONTENTS_DIR_iphonesimulator = $(JAVASCRIPTCORE_CONTENTS_DIR_iphoneos); -JAVASCRIPTCORE_CONTENTS_DIR_macosx = JavaScriptCore.framework/Versions/A; +JAVASCRIPTCORE_CONTENTS_DIR[sdk=iphone*] = JavaScriptCore.framework; +JAVASCRIPTCORE_CONTENTS_DIR[sdk=macosx*] = JavaScriptCore.framework/Versions/A; JAVASCRIPTCORE_RESOURCES_DIR = $(JAVASCRIPTCORE_CONTENTS_DIR)/Resources; JAVASCRIPTCORE_LIBRARIES_DIR = $(JAVASCRIPTCORE_CONTENTS_DIR)/Libraries; @@ -144,19 +131,14 @@ DEAD_CODE_STRIPPING_debug = NO; DEAD_CODE_STRIPPING_normal = YES; DEAD_CODE_STRIPPING = $(DEAD_CODE_STRIPPING_$(CURRENT_VARIANT)); -SECTORDER_FLAGS = $(SECTORDER_FLAGS_$(PLATFORM_NAME)); -SECTORDER_FLAGS_iphoneos = -Wl,-order_file,$(SDKROOT)/AppleInternal/OrderFiles/JavaScriptCore.order; -SECTORDER_FLAGS_macosx = -Wl,-order_file,JavaScriptCore.order; - SDKROOT = macosx.internal; +INSTALL_PATH_PREFIX[sdk=iphonesimulator8.*] = $(DEVELOPER_INSTALL_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/$(SDK_DIR:file); INSTALL_PATH = $(INSTALL_PATH_PREFIX)$(INSTALL_PATH_ACTUAL); -HAVE_DTRACE = 1; - -TOOLCHAINS = $(TOOLCHAINS_$(PLATFORM_NAME)); -TOOLCHAINS_iphoneos = $(TOOLCHAINS); -TOOLCHAINS_iphonesimulator = $(TOOLCHAINS); -TOOLCHAINS_macosx = $(TOOLCHAINS_macosx_$(MAC_OS_X_VERSION_MAJOR)); -TOOLCHAINS_macosx_1080 = default; -TOOLCHAINS_macosx_1090 = $(TOOLCHAINS); -TOOLCHAINS_macosx_101000 = $(TOOLCHAINS_macosx_1090); + +LD_DYLIB_INSTALL_NAME[sdk=iphonesimulator8.*]=$(LD_DYLIB_INSTALL_NAME_$(MACH_O_TYPE)); +LD_DYLIB_INSTALL_NAME_mh_dylib=$(INSTALL_PATH_ACTUAL)/$(EXECUTABLE_PATH); + +OTHER_CFLAGS = $(ASAN_OTHER_CFLAGS); +OTHER_CPLUSPLUSFLAGS = $(ASAN_OTHER_CPLUSPLUSFLAGS); +OTHER_LDFLAGS = $(ASAN_OTHER_LDFLAGS); diff --git a/Configurations/CompileRuntimeToLLVMIR.xcconfig b/Configurations/CompileRuntimeToLLVMIR.xcconfig index aa50d48..41ccb33 100644 --- a/Configurations/CompileRuntimeToLLVMIR.xcconfig +++ b/Configurations/CompileRuntimeToLLVMIR.xcconfig @@ -34,8 +34,6 @@ GCC_GENERATE_DEBUGGING_SYMBOLS = NO; HEADER_SEARCH_PATHS = "${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore" $(HEADER_SEARCH_PATHS); -SECTORDER_FLAGS = ; - OTHER_CFLAGS = -c -flto; OTHER_CPLUSPLUSFLAGS = -c -flto; OTHER_LDFLAGS = ; diff --git a/Configurations/DebugRelease.xcconfig b/Configurations/DebugRelease.xcconfig index a070ea4..91e815d 100644 --- a/Configurations/DebugRelease.xcconfig +++ b/Configurations/DebugRelease.xcconfig @@ -1,4 +1,4 @@ -// Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved. +// Copyright (C) 2009, 2010, 2013, 2014 Apple Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions @@ -27,26 +27,16 @@ ARCHS = $(ARCHS_STANDARD_32_64_BIT); ONLY_ACTIVE_ARCH = YES; -MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(PLATFORM_NAME)); -MACOSX_DEPLOYMENT_TARGET_iphoneos = 10.5; -MACOSX_DEPLOYMENT_TARGET_iphonesimulator = 10.5; -MACOSX_DEPLOYMENT_TARGET_macosx = $(MACOSX_DEPLOYMENT_TARGET_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -MACOSX_DEPLOYMENT_TARGET_macosx_1080 = 10.8; +MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(PLATFORM_NAME)_$(TARGET_MAC_OS_X_VERSION_MAJOR)); MACOSX_DEPLOYMENT_TARGET_macosx_1090 = 10.9; MACOSX_DEPLOYMENT_TARGET_macosx_101000 = 10.10; +MACOSX_DEPLOYMENT_TARGET_macosx_101100 = 10.11; +MACOSX_DEPLOYMENT_TARGET_macosx_101200 = 10.12; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; DEBUG_INFORMATION_FORMAT = dwarf; -SECTORDER_FLAGS = ; - -OTHER_CFLAGS = $(ASAN_OTHER_CFLAGS); -OTHER_CPLUSPLUSFLAGS = $(ASAN_OTHER_CPLUSPLUSFLAGS); -OTHER_LDFLAGS = $(ASAN_OTHER_LDFLAGS); - -SDKROOT = $(SDKROOT_$(PLATFORM_NAME)); -SDKROOT_iphoneos = $(SDKROOT); -SDKROOT_iphonesimulator = $(SDKROOT); -SDKROOT_macosx = $(SDKROOT_macosx_$(USE_INTERNAL_SDK)); +SDKROOT[sdk=iphone*] = $(SDKROOT); +SDKROOT = $(SDKROOT_$(PLATFORM_NAME)_$(USE_INTERNAL_SDK)); SDKROOT_macosx_ = macosx; SDKROOT_macosx_YES = macosx.internal; diff --git a/Configurations/FeatureDefines.xcconfig b/Configurations/FeatureDefines.xcconfig index e8e2332..5c030ba 100644 --- a/Configurations/FeatureDefines.xcconfig +++ b/Configurations/FeatureDefines.xcconfig @@ -1,4 +1,4 @@ -// Copyright (C) 2009, 2010, 2014 Apple Inc. All rights reserved. +// Copyright (C) 2009, 2010, 2014, 2015 Apple Inc. All rights reserved. // Copyright (C) 2009 Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -31,145 +31,127 @@ // Set any ENABLE_FEATURE_NAME macro to an empty string to disable that feature. -ENABLE_3D_RENDERING = ENABLE_3D_RENDERING; +ENABLE_3D_TRANSFORMS = ENABLE_3D_TRANSFORMS; ENABLE_ACCELERATED_2D_CANVAS = ; -ENABLE_ACCELERATED_OVERFLOW_SCROLLING = $(ENABLE_ACCELERATED_OVERFLOW_SCROLLING_$(PLATFORM_NAME)); -ENABLE_ACCELERATED_OVERFLOW_SCROLLING_iphoneos = ENABLE_ACCELERATED_OVERFLOW_SCROLLING; -ENABLE_ACCELERATED_OVERFLOW_SCROLLING_iphonesimulator = $(ENABLE_ACCELERATED_OVERFLOW_SCROLLING_iphoneos); -ENABLE_AVF_CAPTIONS = $(ENABLE_AVF_CAPTIONS_$(PLATFORM_NAME)); -ENABLE_AVF_CAPTIONS_macosx = $(ENABLE_AVF_CAPTIONS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_AVF_CAPTIONS_macosx_1080 = ; +ENABLE_ACCELERATED_OVERFLOW_SCROLLING[sdk=iphone*] = ENABLE_ACCELERATED_OVERFLOW_SCROLLING; +ENABLE_ATTACHMENT_ELEMENT = ; +ENABLE_AVF_CAPTIONS[sdk=iphone*] = ENABLE_AVF_CAPTIONS; +ENABLE_AVF_CAPTIONS[sdk=macosx*] = $(ENABLE_AVF_CAPTIONS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_AVF_CAPTIONS_macosx_1090 = ; ENABLE_AVF_CAPTIONS_macosx_101000 = ENABLE_AVF_CAPTIONS; -ENABLE_AVF_CAPTIONS_iphoneos = ENABLE_AVF_CAPTIONS; -ENABLE_AVF_CAPTIONS_iphonesimulator = $(ENABLE_AVF_CAPTIONS_iphoneos); +ENABLE_AVF_CAPTIONS_macosx_101100 = ENABLE_AVF_CAPTIONS; +ENABLE_AVF_CAPTIONS_macosx_101200 = ENABLE_AVF_CAPTIONS; ENABLE_CACHE_PARTITIONING = ENABLE_CACHE_PARTITIONING; -ENABLE_CANVAS_PATH = ; +ENABLE_CANVAS_PATH = ENABLE_CANVAS_PATH; ENABLE_CANVAS_PROXY = ; ENABLE_CHANNEL_MESSAGING = ENABLE_CHANNEL_MESSAGING; +ENABLE_ES6_ARROWFUNCTION_SYNTAX = ; +ENABLE_ES6_CLASS_SYNTAX = ENABLE_ES6_CLASS_SYNTAX; +ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX = ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX; +ENABLE_CONTENT_FILTERING = ENABLE_CONTENT_FILTERING; ENABLE_CSP_NEXT = ; +ENABLE_CSS_ANIMATIONS_LEVEL_2 = ; ENABLE_CSS_BOX_DECORATION_BREAK = ENABLE_CSS_BOX_DECORATION_BREAK; ENABLE_CSS_COMPOSITING = ENABLE_CSS_COMPOSITING; ENABLE_CSS_DEVICE_ADAPTATION = ; -ENABLE_CSS_EXCLUSIONS = ; -ENABLE_CSS_FILTERS = ENABLE_CSS_FILTERS; ENABLE_CSS_GRID_LAYOUT = ; ENABLE_CSS_IMAGE_ORIENTATION = ; ENABLE_CSS_IMAGE_RESOLUTION = ; ENABLE_CSS_REGIONS = ENABLE_CSS_REGIONS; +ENABLE_CSS_SELECTORS_LEVEL4 = ; ENABLE_CSS_SHAPES = ENABLE_CSS_SHAPES; -ENABLE_CSS_TRANSFORMS_ANIMATIONS_UNPREFIXED = ; -ENABLE_CSS3_CONDITIONAL_RULES = ; ENABLE_CSS3_TEXT = ; ENABLE_CSS3_TEXT_LINE_BREAK = ; ENABLE_CURSOR_VISIBILITY = ENABLE_CURSOR_VISIBILITY; ENABLE_CUSTOM_SCHEME_HANDLER = ; -ENABLE_DASHBOARD_SUPPORT = $(ENABLE_DASHBOARD_SUPPORT_$(PLATFORM_NAME)); -ENABLE_DASHBOARD_SUPPORT_macosx = ENABLE_DASHBOARD_SUPPORT; +ENABLE_DASHBOARD_SUPPORT[sdk=macosx*] = ENABLE_DASHBOARD_SUPPORT; ENABLE_DATALIST_ELEMENT = ; ENABLE_DATA_TRANSFER_ITEMS = ; ENABLE_DETAILS_ELEMENT = ENABLE_DETAILS_ELEMENT; -ENABLE_DEVICE_ORIENTATION = $(ENABLE_DEVICE_ORIENTATION_$(PLATFORM_NAME)); -ENABLE_DEVICE_ORIENTATION_iphoneos = ENABLE_DEVICE_ORIENTATION; -ENABLE_DEVICE_ORIENTATION_iphonesimulator = $(ENABLE_DEVICE_ORIENTATION_iphoneos); +ENABLE_DEVICE_ORIENTATION[sdk=iphone*] = ENABLE_DEVICE_ORIENTATION; ENABLE_DOM4_EVENTS_CONSTRUCTOR = ENABLE_DOM4_EVENTS_CONSTRUCTOR; -ENABLE_ENCRYPTED_MEDIA = $(ENABLE_ENCRYPTED_MEDIA_$(PLATFORM_NAME)); -ENABLE_ENCRYPTED_MEDIA_macosx = $(ENABLE_ENCRYPTED_MEDIA_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_ENCRYPTED_MEDIA_macosx_1080 = ; -ENABLE_ENCRYPTED_MEDIA_macosx_1090 = ENABLE_ENCRYPTED_MEDIA; -ENABLE_ENCRYPTED_MEDIA_macosx_101000 = ENABLE_ENCRYPTED_MEDIA; -ENABLE_ENCRYPTED_MEDIA_V2 = $(ENABLE_ENCRYPTED_MEDIA_V2_$(PLATFORM_NAME)); -ENABLE_ENCRYPTED_MEDIA_V2_macosx = $(ENABLE_ENCRYPTED_MEDIA_V2_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_ENCRYPTED_MEDIA_V2_macosx_1080 = ; -ENABLE_ENCRYPTED_MEDIA_V2_macosx_1090 = ENABLE_ENCRYPTED_MEDIA_V2; -ENABLE_ENCRYPTED_MEDIA_V2_macosx_101000 = ENABLE_ENCRYPTED_MEDIA_V2; -ENABLE_FILTERS = ENABLE_FILTERS; +ENABLE_ENCRYPTED_MEDIA[sdk=macosx*] = ENABLE_ENCRYPTED_MEDIA; +ENABLE_ENCRYPTED_MEDIA_V2[sdk=macosx*] = ENABLE_ENCRYPTED_MEDIA_V2; +ENABLE_FILTERS_LEVEL_2[sdk=iphone*] = ENABLE_FILTERS_LEVEL_2; +ENABLE_FILTERS_LEVEL_2[sdk=macosx*] = $(ENABLE_FILTERS_LEVEL_2_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); +ENABLE_FILTERS_LEVEL_2_macosx_1090 = ; +ENABLE_FILTERS_LEVEL_2_macosx_101000 = ENABLE_FILTERS_LEVEL_2; +ENABLE_FILTERS_LEVEL_2_macosx_101100 = ENABLE_FILTERS_LEVEL_2; +ENABLE_FILTERS_LEVEL_2_macosx_101200 = ENABLE_FILTERS_LEVEL_2; ENABLE_FONT_LOAD_EVENTS = ; -ENABLE_FULLSCREEN_API = $(ENABLE_FULLSCREEN_API_$(PLATFORM_NAME)); -ENABLE_FULLSCREEN_API_macosx = ENABLE_FULLSCREEN_API; -ENABLE_GAMEPAD = $(ENABLE_GAMEPAD_$(PLATFORM_NAME)); -ENABLE_GAMEPAD_macosx = ; +ENABLE_FULLSCREEN_API[sdk=macosx*] = ENABLE_FULLSCREEN_API; +ENABLE_GAMEPAD[sdk=macosx*] = ; ENABLE_GAMEPAD_DEPRECATED = ; ENABLE_GEOLOCATION = ENABLE_GEOLOCATION; -ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING = $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING_$(PLATFORM_NAME)); -ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING_macosx = ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING; -ENABLE_HIGH_DPI_CANVAS = $(ENABLE_HIGH_DPI_CANVAS_$(PLATFORM_NAME)); -ENABLE_ICONDATABASE = $(ENABLE_ICONDATABASE_$(PLATFORM_NAME)); -ENABLE_ICONDATABASE_macosx = ENABLE_ICONDATABASE; -ENABLE_SERVICE_CONTROLS = $(ENABLE_SERVICE_CONTROLS_$(PLATFORM_NAME)); -ENABLE_SERVICE_CONTROLS_macosx = $(ENABLE_SERVICE_CONTROLS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_SERVICE_CONTROLS_macosx_1080 = ; +ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING[sdk=macosx*] = ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING; +ENABLE_ICONDATABASE[sdk=macosx*] = ENABLE_ICONDATABASE; +ENABLE_SERVICE_CONTROLS[sdk=macosx*] = $(ENABLE_SERVICE_CONTROLS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_SERVICE_CONTROLS_macosx_1090 = ; ENABLE_SERVICE_CONTROLS_macosx_101000 = ENABLE_SERVICE_CONTROLS; +ENABLE_SERVICE_CONTROLS_macosx_101100 = ENABLE_SERVICE_CONTROLS; +ENABLE_SERVICE_CONTROLS_macosx_101200 = ENABLE_SERVICE_CONTROLS; ENABLE_INDEXED_DATABASE = ENABLE_INDEXED_DATABASE; ENABLE_INDEXED_DATABASE_IN_WORKERS = ; ENABLE_INDIE_UI = ; -ENABLE_INPUT_SPEECH = ; -ENABLE_INPUT_TYPE_COLOR = $(ENABLE_INPUT_TYPE_COLOR_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_COLOR_macosx = ; -ENABLE_INPUT_TYPE_COLOR_POPOVER = $(ENABLE_INPUT_TYPE_COLOR_POPOVER_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_COLOR_POPOVER_macosx = ; -ENABLE_INPUT_TYPE_DATE = $(ENABLE_INPUT_TYPE_DATE_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_DATE_iphoneos = ENABLE_INPUT_TYPE_DATE; -ENABLE_INPUT_TYPE_DATE_iphonesimulator = $(ENABLE_INPUT_TYPE_DATE_iphoneos); +ENABLE_INPUT_TYPE_COLOR[sdk=macosx*] = ; +ENABLE_INPUT_TYPE_COLOR_POPOVER[sdk=macosx*] = ; +ENABLE_INPUT_TYPE_DATE[sdk=iphone*] = ENABLE_INPUT_TYPE_DATE; ENABLE_INPUT_TYPE_DATETIME_INCOMPLETE = ; -ENABLE_INPUT_TYPE_DATETIMELOCAL = $(ENABLE_INPUT_TYPE_DATETIMELOCAL_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_DATETIMELOCAL_iphoneos = ENABLE_INPUT_TYPE_DATETIMELOCAL; -ENABLE_INPUT_TYPE_DATETIMELOCAL_iphonesimulator = $(ENABLE_INPUT_TYPE_DATETIMELOCAL_iphoneos); -ENABLE_INPUT_TYPE_MONTH = $(ENABLE_INPUT_TYPE_MONTH_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_MONTH_iphoneos = ENABLE_INPUT_TYPE_MONTH; -ENABLE_INPUT_TYPE_MONTH_iphonesimulator = $(ENABLE_INPUT_TYPE_MONTH_iphoneos); -ENABLE_INPUT_TYPE_TIME = $(ENABLE_INPUT_TYPE_TIME_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_TIME_iphoneos = ENABLE_INPUT_TYPE_TIME; -ENABLE_INPUT_TYPE_TIME_iphonesimulator = $(ENABLE_INPUT_TYPE_TIME_iphoneos); -ENABLE_INPUT_TYPE_WEEK = $(ENABLE_INPUT_TYPE_WEEK_$(PLATFORM_NAME)); -ENABLE_INPUT_TYPE_WEEK_iphoneos = ENABLE_INPUT_TYPE_WEEK; -ENABLE_INPUT_TYPE_WEEK_iphonesimulator = $(ENABLE_INPUT_TYPE_WEEK_iphoneos); -ENABLE_INSPECTOR = ENABLE_INSPECTOR; -ENABLE_IOS_AIRPLAY = $(ENABLE_IOS_AIRPLAY_$(PLATFORM_NAME)); -ENABLE_IOS_AIRPLAY_iphoneos = ENABLE_IOS_AIRPLAY; -ENABLE_IOS_AIRPLAY_iphonesimulator = $(ENABLE_IOS_AIRPLAY_iphoneos); -ENABLE_IOS_TEXT_AUTOSIZING = $(ENABLE_IOS_TEXT_AUTOSIZING_$(PLATFORM_NAME)); -ENABLE_IOS_TEXT_AUTOSIZING_iphoneos = ENABLE_IOS_TEXT_AUTOSIZING; -ENABLE_IOS_TEXT_AUTOSIZING_iphonesimulator = $(ENABLE_IOS_TEXT_AUTOSIZING_iphoneos); +ENABLE_INPUT_TYPE_DATETIMELOCAL[sdk=iphone*] = ENABLE_INPUT_TYPE_DATETIMELOCAL; +ENABLE_INPUT_TYPE_MONTH[sdk=iphone*] = ENABLE_INPUT_TYPE_MONTH; +ENABLE_INPUT_TYPE_TIME[sdk=iphone*] = ENABLE_INPUT_TYPE_TIME; +ENABLE_INPUT_TYPE_WEEK[sdk=iphone*] = ENABLE_INPUT_TYPE_WEEK; + +ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS[sdk=iphone*] = ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS; +ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS[sdk=macosx*] = $(ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)) +ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS_macosx_1090 = ; +ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS_macosx_101000 = ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS; +ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS_macosx_101100 = ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS; +ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS_macosx_101200 = ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS; + +ENABLE_WIRELESS_PLAYBACK_TARGET[sdk=iphone*] = ENABLE_WIRELESS_PLAYBACK_TARGET; +ENABLE_WIRELESS_PLAYBACK_TARGET[sdk=macosx*] = $(ENABLE_WIRELESS_PLAYBACK_TARGET_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)) +ENABLE_WIRELESS_PLAYBACK_TARGET_macosx_1090 = ; +ENABLE_WIRELESS_PLAYBACK_TARGET_macosx_101000 = ; +ENABLE_WIRELESS_PLAYBACK_TARGET_macosx_101100 = ENABLE_WIRELESS_PLAYBACK_TARGET; +ENABLE_WIRELESS_PLAYBACK_TARGET_macosx_101200 = ENABLE_WIRELESS_PLAYBACK_TARGET; + +ENABLE_INTL = ; + +ENABLE_IOS_GESTURE_EVENTS[sdk=iphone*] = $(ENABLE_IOS_GESTURE_EVENTS_ios_WITH_INTERNAL_SDK_$(USE_INTERNAL_SDK)); +ENABLE_IOS_GESTURE_EVENTS_ios_WITH_INTERNAL_SDK_YES = ENABLE_IOS_GESTURE_EVENTS; + +ENABLE_IOS_TEXT_AUTOSIZING[sdk=iphone*] = ENABLE_IOS_TEXT_AUTOSIZING; + +ENABLE_IOS_TOUCH_EVENTS[sdk=iphone*] = $(ENABLE_IOS_TOUCH_EVENTS_ios_WITH_INTERNAL_SDK_$(USE_INTERNAL_SDK)); +ENABLE_IOS_TOUCH_EVENTS_ios_WITH_INTERNAL_SDK_YES = ENABLE_IOS_TOUCH_EVENTS; + ENABLE_LEGACY_CSS_VENDOR_PREFIXES = ENABLE_LEGACY_CSS_VENDOR_PREFIXES; -ENABLE_LEGACY_NOTIFICATIONS = $(ENABLE_LEGACY_NOTIFICATIONS_$(PLATFORM_NAME)); -ENABLE_LEGACY_NOTIFICATIONS_macosx = ENABLE_LEGACY_NOTIFICATIONS; +ENABLE_LEGACY_NOTIFICATIONS[sdk=macosx*] = ENABLE_LEGACY_NOTIFICATIONS; ENABLE_LEGACY_VENDOR_PREFIXES = ENABLE_LEGACY_VENDOR_PREFIXES; ENABLE_LEGACY_WEB_AUDIO = ENABLE_LEGACY_WEB_AUDIO; -ENABLE_LETTERPRESS = $(ENABLE_LETTERPRESS_$(PLATFORM_NAME)); -ENABLE_LETTERPRESS_iphoneos = ENABLE_LETTERPRESS; -ENABLE_LETTERPRESS_iphonesimulator = $(ENABLE_LETTERPRESS_iphoneos); - -ENABLE_LINK_LONG_PRESS = $(ENABLE_LINK_LONG_PRESS_$(PLATFORM_NAME)); -ENABLE_LINK_LONG_PRESS_macosx = $(ENABLE_LINK_LONG_PRESS_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_LINK_LONG_PRESS_macosx_1080 = ; -ENABLE_LINK_LONG_PRESS_macosx_1090 = ; -ENABLE_LINK_LONG_PRESS_macosx_101000 = ENABLE_LINK_LONG_PRESS; - +ENABLE_LETTERPRESS[sdk=iphone*] = ENABLE_LETTERPRESS; ENABLE_LINK_PREFETCH = ; ENABLE_MATHML = ENABLE_MATHML; ENABLE_MEDIA_CONTROLS_SCRIPT = ENABLE_MEDIA_CONTROLS_SCRIPT; +ENABLE_MEDIA_SESSION = ; -ENABLE_MEDIA_SOURCE = $(ENABLE_MEDIA_SOURCE_$(PLATFORM_NAME)); -ENABLE_MEDIA_SOURCE_macosx = $(ENABLE_MEDIA_SOURCE_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_MEDIA_SOURCE_macosx_1080 = ; +ENABLE_MEDIA_SOURCE[sdk=macosx*] = $(ENABLE_MEDIA_SOURCE_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_MEDIA_SOURCE_macosx_1090 = ; ENABLE_MEDIA_SOURCE_macosx_101000 = ENABLE_MEDIA_SOURCE; +ENABLE_MEDIA_SOURCE_macosx_101100 = ENABLE_MEDIA_SOURCE; +ENABLE_MEDIA_SOURCE_macosx_101200 = ENABLE_MEDIA_SOURCE; ENABLE_MEDIA_STATISTICS = ; -ENABLE_METER_ELEMENT = $(ENABLE_METER_ELEMENT_$(PLATFORM_NAME)); -ENABLE_METER_ELEMENT_macosx = ENABLE_METER_ELEMENT; +ENABLE_MEDIA_STREAM = ; +ENABLE_METER_ELEMENT[sdk=macosx*] = ENABLE_METER_ELEMENT; ENABLE_MHTML = ; -ENABLE_MOUSE_CURSOR_SCALE = $(ENABLE_MOUSE_CURSOR_SCALE_$(PLATFORM_NAME)); -ENABLE_MOUSE_CURSOR_SCALE_macosx = ENABLE_MOUSE_CURSOR_SCALE; +ENABLE_MOUSE_CURSOR_SCALE[sdk=macosx*] = ENABLE_MOUSE_CURSOR_SCALE; ENABLE_NAVIGATOR_CONTENT_UTILS = ; ENABLE_NAVIGATOR_HWCONCURRENCY = ; ENABLE_NOSNIFF = ; -ENABLE_NOTIFICATIONS = $(ENABLE_NOTIFICATIONS_$(PLATFORM_NAME)); -ENABLE_NOTIFICATIONS_macosx = ENABLE_NOTIFICATIONS; -ENABLE_PDFKIT_PLUGIN = $(ENABLE_PDFKIT_PLUGIN_$(PLATFORM_NAME)); -ENABLE_PDFKIT_PLUGIN_macosx = ENABLE_PDFKIT_PLUGIN; +ENABLE_NOTIFICATIONS[sdk=macosx*] = ENABLE_NOTIFICATIONS; +ENABLE_PDFKIT_PLUGIN[sdk=macosx*] = ENABLE_PDFKIT_PLUGIN; ENABLE_PICTURE_SIZES = ; ENABLE_POINTER_LOCK = ; ENABLE_PROMISES = ENABLE_PROMISES; @@ -177,76 +159,73 @@ ENABLE_PROXIMITY_EVENTS = ; ENABLE_PUBLIC_SUFFIX_LIST = ENABLE_PUBLIC_SUFFIX_LIST; ENABLE_QUOTA = ; ENABLE_REQUEST_ANIMATION_FRAME = ENABLE_REQUEST_ANIMATION_FRAME; -ENABLE_REMOTE_INSPECTOR = $(ENABLE_REMOTE_INSPECTOR_$(PLATFORM_NAME)); -ENABLE_REMOTE_INSPECTOR_iphoneos = ENABLE_REMOTE_INSPECTOR; -ENABLE_REMOTE_INSPECTOR_iphonesimulator = $(ENABLE_REMOTE_INSPECTOR_iphoneos); -ENABLE_REMOTE_INSPECTOR_macosx = $(ENABLE_REMOTE_INSPECTOR_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)) -ENABLE_REMOTE_INSPECTOR_macosx_1080 = ; +ENABLE_REQUEST_AUTOCOMPLETE = ; +ENABLE_REMOTE_INSPECTOR[sdk=iphone*] = ENABLE_REMOTE_INSPECTOR; +ENABLE_REMOTE_INSPECTOR[sdk=macosx*] = $(ENABLE_REMOTE_INSPECTOR_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_REMOTE_INSPECTOR_macosx_1090 = ; ENABLE_REMOTE_INSPECTOR_macosx_101000 = ENABLE_REMOTE_INSPECTOR; +ENABLE_REMOTE_INSPECTOR_macosx_101100 = ENABLE_REMOTE_INSPECTOR; +ENABLE_REMOTE_INSPECTOR_macosx_101200 = ENABLE_REMOTE_INSPECTOR; ENABLE_RESOLUTION_MEDIA_QUERY = ; -ENABLE_SCRIPTED_SPEECH = ; -ENABLE_SHARED_WORKERS = ; -ENABLE_SPEECH_SYNTHESIS = $(ENABLE_SPEECH_SYNTHESIS_$(PLATFORM_NAME)); +ENABLE_RUBBER_BANDING[sdk=macosx*] = ENABLE_RUBBER_BANDING; +ENABLE_CSS_SCROLL_SNAP = ENABLE_CSS_SCROLL_SNAP; ENABLE_SPEECH_SYNTHESIS = ENABLE_SPEECH_SYNTHESIS; -ENABLE_SQL_DATABASE = ENABLE_SQL_DATABASE; -ENABLE_SUBPIXEL_LAYOUT = ENABLE_SUBPIXEL_LAYOUT; -ENABLE_SUBTLE_CRYPTO = $(ENABLE_SUBTLE_CRYPTO_$(PLATFORM_NAME)); -ENABLE_SUBTLE_CRYPTO_macosx = $(ENABLE_SUBTLE_CRYPTO_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_SUBTLE_CRYPTO_macosx_1080 = ; -ENABLE_SUBTLE_CRYPTO_macosx_1090 = ENABLE_SUBTLE_CRYPTO; -ENABLE_SUBTLE_CRYPTO_macosx_101000 = ENABLE_SUBTLE_CRYPTO; -ENABLE_SUBTLE_CRYPTO_iphoneos = ENABLE_SUBTLE_CRYPTO; -ENABLE_SUBTLE_CRYPTO_iphonesimulator = $(ENABLE_SUBTLE_CRYPTO_iphoneos); +ENABLE_STREAMS_API = ; +ENABLE_SUBTLE_CRYPTO = ENABLE_SUBTLE_CRYPTO; ENABLE_SVG_FONTS = ENABLE_SVG_FONTS; +ENABLE_SVG_OTF_CONVERTER = ENABLE_SVG_OTF_CONVERTER; -ENABLE_TELEPHONE_NUMBER_DETECTION = $(ENABLE_TELEPHONE_NUMBER_DETECTION_$(PLATFORM_NAME)); -ENABLE_TELEPHONE_NUMBER_DETECTION_macosx = $(ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_1080 = ; +ENABLE_TELEPHONE_NUMBER_DETECTION[sdk=iphone*] = ENABLE_TELEPHONE_NUMBER_DETECTION; +ENABLE_TELEPHONE_NUMBER_DETECTION[sdk=macosx*] = $(ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_1090 = ; ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_101000 = ENABLE_TELEPHONE_NUMBER_DETECTION; -ENABLE_TELEPHONE_NUMBER_DETECTION_iphoneos = ENABLE_TELEPHONE_NUMBER_DETECTION; -ENABLE_TELEPHONE_NUMBER_DETECTION_iphonesimulator = $(ENABLE_TELEPHONE_NUMBER_DETECTION_iphoneos); +ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_101100 = ENABLE_TELEPHONE_NUMBER_DETECTION; +ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_101200 = ENABLE_TELEPHONE_NUMBER_DETECTION; ENABLE_TEMPLATE_ELEMENT = ENABLE_TEMPLATE_ELEMENT; ENABLE_TEXT_AUTOSIZING = ; -ENABLE_TOUCH_EVENTS = $(ENABLE_TOUCH_EVENTS_$(PLATFORM_NAME)); -ENABLE_TOUCH_EVENTS_iphoneos = ENABLE_TOUCH_EVENTS; -ENABLE_TOUCH_EVENTS_iphonesimulator = $(ENABLE_TOUCH_EVENTS_iphoneos); + +ENABLE_CSS_TRAILING_WORD = ENABLE_CSS_TRAILING_WORD; + +// FIXME: Remove the USE_INTERNAL_SDK condition once we support touch events when building for iOS with +// the public SDK. We will also need to update FeatureDefines.h. +ENABLE_TOUCH_EVENTS[sdk=iphone*] = $(ENABLE_TOUCH_EVENTS_ios_WITH_INTERNAL_SDK_$(USE_INTERNAL_SDK)); +ENABLE_TOUCH_EVENTS_ios_WITH_INTERNAL_SDK_YES = ENABLE_TOUCH_EVENTS; + ENABLE_TOUCH_ICON_LOADING = ; ENABLE_USERSELECT_ALL = ENABLE_USERSELECT_ALL; ENABLE_VIDEO = ENABLE_VIDEO; +ENABLE_VIDEO_PRESENTATION_MODE[sdk=iphone*] = ENABLE_VIDEO_PRESENTATION_MODE; ENABLE_VIDEO_TRACK = ENABLE_VIDEO_TRACK; ENABLE_DATACUE_VALUE = ENABLE_DATACUE_VALUE; ENABLE_VIEW_MODE_CSS_MEDIA = ; ENABLE_WEBGL = ENABLE_WEBGL; +ENABLE_WEBGL2 = ; ENABLE_WEB_AUDIO = ENABLE_WEB_AUDIO; -ENABLE_WEB_REPLAY = $(ENABLE_WEB_REPLAY_$(PLATFORM_NAME)); -ENABLE_WEB_REPLAY_macosx = $(ENABLE_WEB_REPLAY_macosx_$(CONFIGURATION)); -ENABLE_WEB_REPLAY_macosx_Debug = ENABLE_WEB_REPLAY; -ENABLE_WEB_REPLAY_macosx_Release = ENABLE_WEB_REPLAY; -ENABLE_WEB_REPLAY_macosx_Production = ; -ENABLE_WEB_REPLAY_iphoneos = ; -ENABLE_WEB_REPLAY_iphonesimulator = ; +ENABLE_WEB_REPLAY = $(ENABLE_WEB_REPLAY_$(PLATFORM_NAME)_$(CONFIGURATION)); +ENABLE_WEB_REPLAY_macosx_Debug = ; +ENABLE_WEB_REPLAY_macosx_Release = ; ENABLE_WEB_SOCKETS = ENABLE_WEB_SOCKETS; -ENABLE_WEB_TIMING = $(ENABLE_WEB_TIMING_$(PLATFORM_NAME)); -ENABLE_WEB_TIMING_macosx = $(ENABLE_WEB_TIMING_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -ENABLE_WEB_TIMING_macosx_1080 = ; +ENABLE_WEB_TIMING[sdk=iphone*] = ENABLE_WEB_TIMING; +ENABLE_WEB_TIMING[sdk=macosx*] = $(ENABLE_WEB_TIMING_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); ENABLE_WEB_TIMING_macosx_1090 = ; ENABLE_WEB_TIMING_macosx_101000 = ENABLE_WEB_TIMING; -ENABLE_WEB_TIMING_iphoneos = ; -ENABLE_WEB_TIMING_iphonesimulator = ; +ENABLE_WEB_TIMING_macosx_101100 = ENABLE_WEB_TIMING; +ENABLE_WEB_TIMING_macosx_101200 = ENABLE_WEB_TIMING; ENABLE_WEBVTT_REGIONS = ENABLE_WEBVTT_REGIONS; ENABLE_XHR_TIMEOUT = ENABLE_XHR_TIMEOUT; -ENABLE_XSLT = ENABLE_XSLT; -ENABLE_FTL_JIT = $(ENABLE_FTL_JIT_$(PLATFORM_NAME)); -ENABLE_FTL_JIT_macosx = ENABLE_FTL_JIT; -ENABLE_FTL_JIT_iphoneos = ENABLE_FTL_JIT; -ENABLE_FTL_JIT_iphonesimulator = ; +// FIXME: Remove the USE_INTERNAL_SDK condition once we support XSLT when building for iOS with the +// public SDK. We will also need to update FeatureDefines.h. +ENABLE_XSLT[sdk=macosx*] = ENABLE_XSLT; +ENABLE_XSLT[sdk=iphone*] = $(ENABLE_XSLT_ios_WITH_INTERNAL_SDK_$(USE_INTERNAL_SDK)); +ENABLE_XSLT_ios_WITH_INTERNAL_SDK_YES = ENABLE_XSLT; + +ENABLE_FTL_JIT[sdk=macosx*] = ENABLE_FTL_JIT; +ENABLE_FTL_JIT[sdk=iphoneos*] = ENABLE_FTL_JIT; -ENABLE_LLINT_C_LOOP = ; +ENABLE_SATURATED_LAYOUT_ARITHMETIC = ENABLE_SATURATED_LAYOUT_ARITHMETIC; -FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ACCELERATED_OVERFLOW_SCROLLING) $(ENABLE_AVF_CAPTIONS) $(ENABLE_CACHE_PARTITIONING) $(ENABLE_CANVAS_PATH) $(ENABLE_CANVAS_PROXY) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_DEVICE_ADAPTATION) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_GRID_LAYOUT) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHAPES) $(ENABLE_CSS_TRANSFORMS_ANIMATIONS_UNPREFIXED) $(ENABLE_CSS3_CONDITIONAL_RULES) $(ENABLE_CSS3_TEXT) $(ENABLE_CSS3_TEXT_LINE_BREAK) $(ENABLE_CURSOR_VISIBILITY) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DOM4_EVENTS_CONSTRUCTOR) $(ENABLE_ENCRYPTED_MEDIA) $(ENABLE_ENCRYPTED_MEDIA_V2) $(ENABLE_FILTERS) $(ENABLE_FONT_LOAD_EVENTS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GAMEPAD_DEPRECATED) $(ENABLE_GEOLOCATION) $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_SERVICE_CONTROLS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INDEXED_DATABASE_IN_WORKERS) $(ENABLE_INDIE_UI) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_COLOR_POPOVER) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME_INCOMPLETE) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_INSPECTOR) $(ENABLE_IOS_AIRPLAY) $(ENABLE_IOS_TEXT_AUTOSIZING) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LETTERPRESS) $(ENABLE_LINK_LONG_PRESS) $(ENABLE_LINK_PREFETCH) $(ENABLE_MATHML) $(ENABLE_MEDIA_CONTROLS_SCRIPT) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MOUSE_CURSOR_SCALE) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NAVIGATOR_HWCONCURRENCY) $(ENABLE_NOTIFICATIONS) $(ENABLE_PDFKIT_PLUGIN) $(ENABLE_POINTER_LOCK) $(ENABLE_PROMISES) $(ENABLE_PROXIMITY_EVENTS) $(ENABLE_PUBLIC_SUFFIX_LIST) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_REMOTE_INSPECTOR) $(ENABLE_RESOLUTION_MEDIA_QUERY) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHARED_WORKERS) $(ENABLE_SPEECH_SYNTHESIS) $(ENABLE_SQL_DATABASE) $(ENABLE_SUBPIXEL_LAYOUT) $(ENABLE_SUBTLE_CRYPTO) $(ENABLE_SVG_FONTS) $(ENABLE_TELEPHONE_NUMBER_DETECTION) $(ENABLE_TEMPLATE_ELEMENT) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TOUCH_EVENTS) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_USERSELECT_ALL) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_DATACUE_VALUE) $(ENABLE_VIEW_MODE_CSS_MEDIA) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_REPLAY) $(ENABLE_WEB_SOCKETS) $(ENABLE_PICTURE_SIZES) $(ENABLE_WEB_TIMING) $(ENABLE_WEBVTT_REGIONS) $(ENABLE_XHR_TIMEOUT) $(ENABLE_XSLT) $(ENABLE_FTL_JIT) $(ENABLE_LLINT_C_LOOP) $(FEATURE_DEFINES_$(PLATFORM_NAME)); +FEATURE_DEFINES = $(ENABLE_3D_TRANSFORMS) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ACCELERATED_OVERFLOW_SCROLLING) $(ENABLE_AVF_CAPTIONS) $(ENABLE_ATTACHMENT_ELEMENT) $(ENABLE_CACHE_PARTITIONING) $(ENABLE_CANVAS_PATH) $(ENABLE_CANVAS_PROXY) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_ES6_ARROWFUNCTION_SYNTAX) $(ENABLE_ES6_CLASS_SYNTAX) $(ENABLE_ES6_TEMPLATE_LITERAL_SYNTAX) $(ENABLE_CONTENT_FILTERING) $(ENABLE_CSP_NEXT) $(ENABLE_CSS_ANIMATIONS_LEVEL_2) $(ENABLE_CSS_BOX_DECORATION_BREAK) $(ENABLE_CSS_COMPOSITING) $(ENABLE_CSS_DEVICE_ADAPTATION) $(ENABLE_CSS_GRID_LAYOUT) $(ENABLE_CSS_IMAGE_ORIENTATION) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SELECTORS_LEVEL4) $(ENABLE_CSS_SHAPES) $(ENABLE_CSS3_TEXT) $(ENABLE_CSS3_TEXT_LINE_BREAK) $(ENABLE_CURSOR_VISIBILITY) $(ENABLE_CUSTOM_SCHEME_HANDLER) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST_ELEMENT) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS_ELEMENT) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DOM4_EVENTS_CONSTRUCTOR) $(ENABLE_ENCRYPTED_MEDIA) $(ENABLE_ENCRYPTED_MEDIA_V2) $(ENABLE_FILTERS_LEVEL_2) $(ENABLE_FONT_LOAD_EVENTS) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GAMEPAD_DEPRECATED) $(ENABLE_GEOLOCATION) $(ENABLE_HIDDEN_PAGE_DOM_TIMER_THROTTLING) $(ENABLE_ICONDATABASE) $(ENABLE_SERVICE_CONTROLS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INDEXED_DATABASE_IN_WORKERS) $(ENABLE_INDIE_UI) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_TYPE_COLOR_POPOVER) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME_INCOMPLETE) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_WIRELESS_PLAYBACK_TARGET) $(ENABLE_INTL) $(ENABLE_IOS_GESTURE_EVENTS) $(ENABLE_IOS_TEXT_AUTOSIZING) $(ENABLE_IOS_TOUCH_EVENTS) $(ENABLE_LEGACY_CSS_VENDOR_PREFIXES) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LEGACY_VENDOR_PREFIXES) $(ENABLE_LEGACY_WEB_AUDIO) $(ENABLE_LETTERPRESS) $(ENABLE_LINK_PREFETCH) $(ENABLE_MATHML) $(ENABLE_MEDIA_CONTROLS_SCRIPT) $(ENABLE_MEDIA_SESSION) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_MEDIA_STREAM) $(ENABLE_METER_ELEMENT) $(ENABLE_MHTML) $(ENABLE_MOUSE_CURSOR_SCALE) $(ENABLE_NAVIGATOR_CONTENT_UTILS) $(ENABLE_NAVIGATOR_HWCONCURRENCY) $(ENABLE_NOTIFICATIONS) $(ENABLE_PDFKIT_PLUGIN) $(ENABLE_PICTURE_SIZES) $(ENABLE_POINTER_LOCK) $(ENABLE_PROMISES) $(ENABLE_PROXIMITY_EVENTS) $(ENABLE_PUBLIC_SUFFIX_LIST) $(ENABLE_QUOTA) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_REQUEST_AUTOCOMPLETE) $(ENABLE_REMOTE_INSPECTOR) $(ENABLE_RESOLUTION_MEDIA_QUERY) $(ENABLE_RUBBER_BANDING) $(ENABLE_CSS_SCROLL_SNAP) $(ENABLE_SPEECH_SYNTHESIS) $(ENABLE_STREAMS_API) $(ENABLE_SUBTLE_CRYPTO) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_OTF_CONVERTER) $(ENABLE_TELEPHONE_NUMBER_DETECTION) $(ENABLE_TEMPLATE_ELEMENT) $(ENABLE_TEXT_AUTOSIZING) $(ENABLE_TOUCH_EVENTS) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_CSS_TRAILING_WORD) $(ENABLE_USERSELECT_ALL) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_DATACUE_VALUE) $(ENABLE_VIEW_MODE_CSS_MEDIA) $(ENABLE_WEBGL) $(ENABLE_WEBGL2) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_REPLAY) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WEBVTT_REGIONS) $(ENABLE_XHR_TIMEOUT) $(ENABLE_XSLT) $(ENABLE_FTL_JIT) $(ENABLE_JIT) $(ENABLE_SATURATED_LAYOUT_ARITHMETIC) $(ENABLE_VIDEO_PRESENTATION_MODE); diff --git a/Configurations/JSC.xcconfig b/Configurations/JSC.xcconfig index 8190416..d1d32ef 100644 --- a/Configurations/JSC.xcconfig +++ b/Configurations/JSC.xcconfig @@ -26,8 +26,7 @@ INSTALL_PATH_ACTUAL = $(JAVASCRIPTCORE_FRAMEWORKS_DIR)/$(JAVASCRIPTCORE_RESOURCES_DIR); PRODUCT_NAME = jsc; -CODE_SIGN_ENTITLEMENTS = $(CODE_SIGN_ENTITLEMENTS_$(PLATFORM_NAME)); -CODE_SIGN_ENTITLEMENTS_iphoneos = entitlements.plist; +CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*] = entitlements.plist; // Explicitly add the PrivateHeaders directory to the search path so that generated header files can be found in production builds. HEADER_SEARCH_PATHS = $(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders $(inherited); diff --git a/Configurations/JavaScriptCore.xcconfig b/Configurations/JavaScriptCore.xcconfig index a02e6b3..0cb895f 100644 --- a/Configurations/JavaScriptCore.xcconfig +++ b/Configurations/JavaScriptCore.xcconfig @@ -1,4 +1,4 @@ -// Copyright (C) 2009 Apple Inc. All rights reserved. +// Copyright (C) 2009, 2014 Apple Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions @@ -37,10 +37,13 @@ JSVALUE_MODEL_x86_64 = 64; OTHER_LDFLAGS_HIDE_SYMBOLS = -Wl,-unexported_symbol -Wl,__ZTISt9bad_alloc -Wl,-unexported_symbol -Wl,__ZTISt9exception -Wl,-unexported_symbol -Wl,__ZTSSt9bad_alloc -Wl,-unexported_symbol -Wl,__ZTSSt9exception -Wl,-unexported_symbol -Wl,__ZdlPvS_ -Wl,-unexported_symbol -Wl,__ZnwmPv -Wl,-unexported_symbol -Wl,__ZNKSt3__18functionIFvvEEclEv -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvvEEC1EOS2_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvvEEC2EOS2_ -Wl,-unexported_symbol -Wl,__ZNKSt3__18functionIFvRN3JSC17BytecodeGeneratorEPNS1_10RegisterIDEEEclES3_S5_ -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvRN3JSC17BytecodeGeneratorEPNS1_10RegisterIDEEED1Ev -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvRN3JSC17BytecodeGeneratorEPNS1_10RegisterIDEEED2Ev -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvvEED1Ev -Wl,-unexported_symbol -Wl,__ZNSt3__18functionIFvvEED2Ev -Wl,-unexported_symbol -Wl,__ZTVNSt3__117bad_function_callE -Wl,-all_load; OTHER_LDFLAGS_BASE = -lobjc -Wl,-Y,3 $(OTHER_LDFLAGS_HIDE_SYMBOLS); -OTHER_LDFLAGS = $(inherited) $(OTHER_LDFLAGS_$(PLATFORM_NAME)); -OTHER_LDFLAGS_iphoneos = $(OTHER_LDFLAGS_BASE); -OTHER_LDFLAGS_iphonesimulator = $(OTHER_LDFLAGS_iphoneos); -OTHER_LDFLAGS_macosx = $(OTHER_LDFLAGS_BASE) -sub_library libobjc -framework CoreServices; +OTHER_LDFLAGS[sdk=iphone*] = $(inherited) $(OTHER_LDFLAGS_BASE); +OTHER_LDFLAGS[sdk=macosx*] = $(inherited) $(OTHER_LDFLAGS_BASE) -sub_library libobjc -framework CoreServices; + +SECTORDER_FLAGS = $(SECTORDER_FLAGS_$(CONFIGURATION)); +SECTORDER_FLAGS_Production[sdk=iphoneos*] = -Wl,-order_file,$(SDKROOT)/AppleInternal/OrderFiles/JavaScriptCore.order; +SECTORDER_FLAGS_Production[sdk=macosx*] = -Wl,-order_file,JavaScriptCore.order; + GCC_PREFIX_HEADER = JavaScriptCorePrefix.h; GCC_SYMBOLS_PRIVATE_EXTERN = YES; HEADER_SEARCH_PATHS = "${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore" $(HEADER_SEARCH_PATHS); @@ -51,6 +54,4 @@ PRODUCT_NAME = JavaScriptCore; INSTALLHDRS_SCRIPT_PHASE = YES; -EXCLUDED_SOURCE_FILE_NAMES = $(EXCLUDED_SOURCE_FILE_NAMES_$(PLATFORM_NAME)); -EXCLUDED_SOURCE_FILE_NAMES_iphoneos = framework.sb; -EXCLUDED_SOURCE_FILE_NAMES_iphonesimulator = $(EXCLUDED_SOURCE_FILE_NAMES_iphoneos); +EXCLUDED_SOURCE_FILE_NAMES[sdk=iphone*] = framework.sb; diff --git a/Configurations/LLVMForJSC.xcconfig b/Configurations/LLVMForJSC.xcconfig index 8a66842..9b4c44b 100644 --- a/Configurations/LLVMForJSC.xcconfig +++ b/Configurations/LLVMForJSC.xcconfig @@ -27,34 +27,23 @@ // Only export our hook for initializing LLVM and returning the API struct. OTHER_LDFLAGS_HIDE_SYMBOLS = -Wl,-exported_symbol -Wl,_initializeAndGetJSCLLVMAPI -Wl,-all_load; -LLVM_LIBS_ios = -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMTableGen -lLLVMInstrumentation -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser -lLLVMARM64Disassembler -lLLVMARM64CodeGen -lLLVMARM64AsmParser -lLLVMARM64Desc -lLLVMARM64Info -lLLVMARM64AsmPrinter -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMDebugInfo -lLLVMOption -lLLVMInterpreter -lLLVMJIT -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCDisassembler -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lprotobuf +LLVM_LIBS_ios = -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMDebugInfo -lLLVMOption -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCDisassembler -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64AsmPrinter -lLLVMAArch64Utils; +LLVM_LIBS_ios_8_0 = -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMTableGen -lLLVMInstrumentation -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser -lLLVMARM64Disassembler -lLLVMARM64CodeGen -lLLVMARM64AsmParser -lLLVMARM64Desc -lLLVMARM64Info -lLLVMARM64AsmPrinter -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMDebugInfo -lLLVMOption -lLLVMInterpreter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCDisassembler -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lprotobuf; +LLVM_LIBS_ios[sdk=iphoneos8.0*] = $(LLVM_LIBS_ios_8_0); +LLVM_LIBS_ios[sdk=iphoneos8.1*] = $(LLVM_LIBS_ios_8_0); +LLVM_LIBS_ios[sdk=iphoneos8.2*] = $(LLVM_LIBS_ios_8_0); +LLVM_LIBS_macosx = -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMDebugInfo -lLLVMOption -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCDisassembler -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lLLVMX86Disassembler -lLLVMX86CodeGen -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils; -#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/AspenLLVM.xcconfig" +LLVM_LIBRARY_PATHS[sdk=iphoneos*] = "$(BUILT_PRODUCTS_DIR)/usr/local/lib" /usr/local/lib; +LLVM_LIBRARY_PATHS[sdk=macosx*] = "$(BUILT_PRODUCTS_DIR)/usr/local/LLVMForJavaScriptCore/lib" /usr/local/LLVMForJavaScriptCore/lib; -// In general, we prefer to not append libraries this way because it may interfere with the required -// ordering of library linkage (as determined by their dependencies on other libraries). In this -// case, we'll make this a one time exception to work around the fact that there are pre-existing -// versions of AspenLLVM.xcconfig that overrides LLVM_LIBS_ios but is missing -lLLVMMCDisassembler. -LLVM_LIBS_iphoneos = $(LLVM_LIBS_ios) -lLLVMMCDisassembler +LIBRARY_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR) $(LLVM_LIBRARY_PATHS) $(LIBRARY_SEARCH_PATHS); -LLVM_LIBS_macosx = -lLLVMTableGen -lLLVMDebugInfo -lLLVMOption -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMIRReader -lLLVMAsmParser -lLLVMMCDisassembler -lLLVMMCParser -lLLVMInstrumentation -lLLVMBitReader -lLLVMInterpreter -lLLVMipo -lLLVMVectorize -lLLVMLinker -lLLVMBitWriter -lLLVMMCJIT -lLLVMJIT -lLLVMCodeGen -lLLVMObjCARCOpts -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMTarget -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport; +OTHER_LDFLAGS_LLVM = $(OTHER_LDFLAGS_LLVM_$(ENABLE_FTL_JIT)_$(CURRENT_ARCH)); +OTHER_LDFLAGS_LLVM_ENABLE_FTL_JIT_arm64[sdk=iphoneos*] = -lpthread -lm $(LLVM_LIBS_ios); +OTHER_LDFLAGS_LLVM_ENABLE_FTL_JIT_x86_64[sdk=macosx*] = -lpthread -lm $(LLVM_LIBS_macosx); -LLVM_LIBRARY_PATHS = $(LLVM_LIBRARY_PATHS_$(PLATFORM_NAME)) -LLVM_LIBRARY_PATHS_macosx = "${BUILT_PRODUCTS_DIR}/usr/local/LLVMForJavaScriptCore/lib" /usr/local/LLVMForJavaScriptCore/lib; -LLVM_LIBRARY_PATHS_iphoneos = "${BUILT_PRODUCTS_DIR}/usr/local/lib" /usr/local/lib; -LLVM_LIBRARY_PATHS_iphonesimulator = ; - -LIBRARY_SEARCH_PATHS = ${BUILT_PRODUCTS_DIR} $(LLVM_LIBRARY_PATHS) $(LIBRARY_SEARCH_PATHS) - -OTHER_LDFLAGS_LLVM = $(OTHER_LDFLAGS_LLVM_$(ENABLE_FTL_JIT)); -OTHER_LDFLAGS_LLVM_ = ; -OTHER_LDFLAGS_LLVM_ENABLE_FTL_JIT = -lpthread -lm $(LLVM_LIBS_$(PLATFORM_NAME)); - -OTHER_LDFLAGS_BASE = -lobjc -Wl,-Y,3 $(OTHER_LDFLAGS_HIDE_SYMBOLS); -OTHER_LDFLAGS = $(inherited) $(OTHER_LDFLAGS_$(PLATFORM_NAME)); -OTHER_LDFLAGS_iphoneos = $(OTHER_LDFLAGS_BASE) $(OTHER_LDFLAGS_LLVM); -OTHER_LDFLAGS_iphonesimulator = $(OTHER_LDFLAGS_iphoneos); -OTHER_LDFLAGS_macosx = $(OTHER_LDFLAGS_BASE) $(OTHER_LDFLAGS_LLVM) +OTHER_LDFLAGS = $(inherited) -lobjc -Wl,-Y,3 $(OTHER_LDFLAGS_HIDE_SYMBOLS) $(OTHER_LDFLAGS_LLVM); GCC_SYMBOLS_PRIVATE_EXTERN = YES; HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore" $(HEADER_SEARCH_PATHS); diff --git a/Configurations/ToolExecutable.xcconfig b/Configurations/ToolExecutable.xcconfig index 6929310..6ffcc87 100644 --- a/Configurations/ToolExecutable.xcconfig +++ b/Configurations/ToolExecutable.xcconfig @@ -26,10 +26,10 @@ INSTALL_PATH_ACTUAL = $(JAVASCRIPTCORE_FRAMEWORKS_DIR)/$(JAVASCRIPTCORE_RESOURCES_DIR); PRODUCT_NAME = $(TARGET_NAME); -CODE_SIGN_ENTITLEMENTS = $(CODE_SIGN_ENTITLEMENTS_$(PLATFORM_NAME)_$(TARGET_NAME)); -CODE_SIGN_ENTITLEMENTS_iphoneos_minidom = entitlements.plist; -CODE_SIGN_ENTITLEMENTS_iphoneos_testapi = entitlements.plist; -CODE_SIGN_ENTITLEMENTS_iphoneos_testRegExp = entitlements.plist; +CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*] = $(CODE_SIGN_ENTITLEMENTS_ios_$(TARGET_NAME)); +CODE_SIGN_ENTITLEMENTS_ios_minidom = entitlements.plist; +CODE_SIGN_ENTITLEMENTS_ios_testapi = entitlements.plist; +CODE_SIGN_ENTITLEMENTS_ios_testRegExp = entitlements.plist; SKIP_INSTALL = $(SKIP_INSTALL_$(FORCE_TOOL_INSTALL)); SKIP_INSTALL_ = YES; @@ -38,8 +38,7 @@ SKIP_INSTALL_YES = NO; GCC_ENABLE_OBJC_GC = NO; CLANG_ENABLE_OBJC_ARC = $(CLANG_ENABLE_OBJC_ARC_$(CURRENT_ARCH)); -CLANG_ENABLE_OBJC_ARC_i386 = $(CLANG_ENABLE_OBJC_ARC_i386_$(PLATFORM_NAME)); -CLANG_ENABLE_OBJC_ARC_i386_iphonesimulator = YES; # For iOS Simulator version 4.0 and greater +CLANG_ENABLE_OBJC_ARC_i386[sdk=iphonesimulator*] = YES; CLANG_ENABLE_OBJC_ARC_x86_64 = YES; CLANG_ENABLE_OBJC_ARC_armv7 = YES; CLANG_ENABLE_OBJC_ARC_armv7k = YES; @@ -51,4 +50,4 @@ OTHER_CPLUSPLUSFLAGS = $(ASAN_OTHER_CPLUSPLUSFLAGS); OTHER_LDFLAGS = $(ASAN_OTHER_LDFLAGS); // Explicitly add the PrivateHeaders directory to the search path so that generated header files can be found in production builds. -HEADER_SEARCH_PATHS = $(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders $(inherited); \ No newline at end of file +HEADER_SEARCH_PATHS = $(JAVASCRIPTCORE_FRAMEWORKS_DIR)/JavaScriptCore.framework/PrivateHeaders $(inherited); diff --git a/Configurations/Version.xcconfig b/Configurations/Version.xcconfig index 985194f..04ef8f1 100644 --- a/Configurations/Version.xcconfig +++ b/Configurations/Version.xcconfig @@ -21,25 +21,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -MAJOR_VERSION = 600; +MAJOR_VERSION = 601; MINOR_VERSION = 1; -TINY_VERSION = 4; -MICRO_VERSION = 17; -NANO_VERSION = 5; -FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(TINY_VERSION).$(MICRO_VERSION).$(NANO_VERSION); +TINY_VERSION = 46; +MICRO_VERSION = 3; +NANO_VERSION = 0; +FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(TINY_VERSION).$(MICRO_VERSION); // The bundle version and short version string are set based on the current build configuration, see below. BUNDLE_VERSION = $(BUNDLE_VERSION_$(CONFIGURATION)); SHORT_VERSION_STRING = $(SHORT_VERSION_STRING_$(CONFIGURATION)) // The system version prefix is based on the current system version. -SYSTEM_VERSION_PREFIX = $(SYSTEM_VERSION_PREFIX_$(PLATFORM_NAME)); -SYSTEM_VERSION_PREFIX_iphoneos = 8; -SYSTEM_VERSION_PREFIX_iphonesimulator = $(SYSTEM_VERSION_PREFIX_iphoneos); -SYSTEM_VERSION_PREFIX_macosx = $(SYSTEM_VERSION_PREFIX_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)); -SYSTEM_VERSION_PREFIX_macosx_1080 = 8; +SYSTEM_VERSION_PREFIX[sdk=iphone*] = 8; +SYSTEM_VERSION_PREFIX = $(SYSTEM_VERSION_PREFIX_$(PLATFORM_NAME)_$(TARGET_MAC_OS_X_VERSION_MAJOR)); SYSTEM_VERSION_PREFIX_macosx_1090 = 9; SYSTEM_VERSION_PREFIX_macosx_101000 = 10; +SYSTEM_VERSION_PREFIX_macosx_101100 = 11; +SYSTEM_VERSION_PREFIX_macosx_101200 = 12; // The production build always uses the full version with a system version prefix. BUNDLE_VERSION_Production = $(SYSTEM_VERSION_PREFIX)$(FULL_VERSION); diff --git a/Configurations/iOS.xcconfig b/Configurations/iOS.xcconfig deleted file mode 100644 index 177b319..0000000 --- a/Configurations/iOS.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/AspenFamily.xcconfig" diff --git a/DerivedSources.make b/DerivedSources.make index cc307d7..677f4ce 100644 --- a/DerivedSources.make +++ b/DerivedSources.make @@ -1,4 +1,4 @@ -# Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013 Apple Inc. All rights reserved. +# Copyright (C) 2006, 2007, 2008, 2009, 2011, 2013, 2015 Apple Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -36,7 +36,7 @@ VPATH = \ .PHONY : all all : \ ArrayConstructor.lut.h \ - ArrayPrototype.lut.h \ + ArrayIteratorPrototype.lut.h \ BooleanPrototype.lut.h \ DateConstructor.lut.h \ DatePrototype.lut.h \ @@ -48,15 +48,16 @@ all : \ JSPromiseConstructor.lut.h \ KeywordLookup.h \ Lexer.lut.h \ - NamePrototype.lut.h \ NumberConstructor.lut.h \ NumberPrototype.lut.h \ ObjectConstructor.lut.h \ RegExpConstructor.lut.h \ RegExpPrototype.lut.h \ RegExpJitTables.h \ - RegExpObject.lut.h \ StringConstructor.lut.h \ + StringIteratorPrototype.lut.h \ + SymbolConstructor.lut.h \ + SymbolPrototype.lut.h \ udis86_itab.h \ Bytecodes.h \ InitBytecodes.asm \ @@ -66,28 +67,28 @@ all : \ # builtin functions .PHONY: JSCBuiltins -# Windows has specific needs for specifying the path to its interpreters +PYTHON = python +PERL = perl + ifeq ($(OS),Windows_NT) - PYTHON = /usr/bin/python - PERL = /usr/bin/perl + DELETE = cmd //C del else - PYTHON = python - PERL = perl + DELETE = rm -f endif # -------- JSCBuiltins: $(JavaScriptCore)/generate-js-builtins JSCBuiltins.h JSCBuiltins.cpp -JSCBuiltins.h: $(JavaScriptCore)/generate-js-builtins $(JavaScriptCore)/builtins/*.js - $(PYTHON) $^ $@ +JSCBuiltins.h: $(JavaScriptCore)/generate-js-builtins $(JavaScriptCore)/builtins + $(PYTHON) $(JavaScriptCore)/generate-js-builtins --input-directory $(JavaScriptCore)/builtins --output $@ JSCBuiltins.cpp: JSCBuiltins.h # lookup tables for classes %.lut.h: create_hash_table %.cpp - $^ -i > $@ + $(PERL) $^ -i > $@ Lexer.lut.h: create_hash_table Keywords.table - $^ > $@ + $(PERL) $^ > $@ # character tables for Yarr @@ -100,7 +101,7 @@ KeywordLookup.h: KeywordLookupGenerator.py Keywords.table # udis86 instruction tables udis86_itab.h: $(JavaScriptCore)/disassembler/udis86/itab.py $(JavaScriptCore)/disassembler/udis86/optable.xml - (PYTHONPATH=$(JavaScriptCore)/disassembler/udis86 $(PYTHON) $(JavaScriptCore)/disassembler/udis86/itab.py $(JavaScriptCore)/disassembler/udis86/optable.xml || exit 1) + $(PYTHON) $(JavaScriptCore)/disassembler/udis86/itab.py $(JavaScriptCore)/disassembler/udis86/optable.xml # Bytecode files @@ -113,22 +114,54 @@ InitBytecodes.asm: $(JavaScriptCore)/generate-bytecode-files $(JavaScriptCore)/b # Inspector interfaces INSPECTOR_DOMAINS = \ + $(JavaScriptCore)/inspector/protocol/ApplicationCache.json \ + $(JavaScriptCore)/inspector/protocol/CSS.json \ $(JavaScriptCore)/inspector/protocol/Console.json \ + $(JavaScriptCore)/inspector/protocol/DOM.json \ + $(JavaScriptCore)/inspector/protocol/DOMDebugger.json \ + $(JavaScriptCore)/inspector/protocol/DOMStorage.json \ + $(JavaScriptCore)/inspector/protocol/Database.json \ $(JavaScriptCore)/inspector/protocol/Debugger.json \ $(JavaScriptCore)/inspector/protocol/GenericTypes.json \ - $(JavaScriptCore)/inspector/protocol/InspectorDomain.json \ - $(JavaScriptCore)/inspector/protocol/Profiler.json \ + $(JavaScriptCore)/inspector/protocol/Inspector.json \ + $(JavaScriptCore)/inspector/protocol/LayerTree.json \ + $(JavaScriptCore)/inspector/protocol/Network.json \ + $(JavaScriptCore)/inspector/protocol/OverlayTypes.json \ + $(JavaScriptCore)/inspector/protocol/Page.json \ $(JavaScriptCore)/inspector/protocol/Runtime.json \ + $(JavaScriptCore)/inspector/protocol/Timeline.json \ + $(JavaScriptCore)/inspector/protocol/Worker.json \ # +ifeq ($(findstring ENABLE_INDEXED_DATABASE,$(FEATURE_DEFINES)), ENABLE_INDEXED_DATABASE) + INSPECTOR_DOMAINS := $(INSPECTOR_DOMAINS) $(JavaScriptCore)/inspector/protocol/IndexedDB.json +endif + +ifeq ($(findstring ENABLE_WEB_REPLAY,$(FEATURE_DEFINES)), ENABLE_WEB_REPLAY) + INSPECTOR_DOMAINS := $(INSPECTOR_DOMAINS) $(JavaScriptCore)/inspector/protocol/Replay.json +endif + INSPECTOR_GENERATOR_SCRIPTS = \ - $(JavaScriptCore)/inspector/scripts/CodeGeneratorInspector.py \ - $(JavaScriptCore)/inspector/scripts/CodeGeneratorInspectorStrings.py \ + $(JavaScriptCore)/inspector/scripts/codegen/__init__.py \ + $(JavaScriptCore)/inspector/scripts/codegen/cpp_generator_templates.py \ + $(JavaScriptCore)/inspector/scripts/codegen/cpp_generator.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_cpp_protocol_types_header.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generate_js_backend_commands.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generator_templates.py \ + $(JavaScriptCore)/inspector/scripts/codegen/generator.py \ + $(JavaScriptCore)/inspector/scripts/codegen/models.py \ + $(JavaScriptCore)/inspector/scripts/generate-combined-inspector-json.py \ + $(JavaScriptCore)/inspector/scripts/generate-inspector-protocol-bindings.py \ # all : \ - InspectorJS.json \ - InspectorJSFrontendDispatchers.h \ + CombinedDomains.json \ + InspectorFrontendDispatchers.h \ InjectedScriptSource.h \ # @@ -136,21 +169,21 @@ all : \ # adding, modifying, or removing domains will trigger regeneration of inspector files. .PHONY: force -EnabledInspectorDomains : force - echo '$(INSPECTOR_DOMAINS)' | cmp -s - $@ || echo '$(INSPECTOR_DOMAINS)' > $@ +EnabledInspectorDomains : $(JavaScriptCore)/UpdateContents.py force + $(PYTHON) $(JavaScriptCore)/UpdateContents.py '$(INSPECTOR_DOMAINS)' $@ -InspectorJS.json : inspector/scripts/generate-combined-inspector-json.py $(INSPECTOR_DOMAINS) EnabledInspectorDomains - $(PYTHON) $(JavaScriptCore)/inspector/scripts/generate-combined-inspector-json.py $(INSPECTOR_DOMAINS) > ./InspectorJS.json +CombinedDomains.json : inspector/scripts/generate-combined-inspector-json.py $(INSPECTOR_DOMAINS) EnabledInspectorDomains + $(PYTHON) $(JavaScriptCore)/inspector/scripts/generate-combined-inspector-json.py $(INSPECTOR_DOMAINS) > ./CombinedDomains.json # Inspector Backend Dispatchers, Frontend Dispatchers, Type Builders -InspectorJSFrontendDispatchers.h : InspectorJS.json $(INSPECTOR_GENERATOR_SCRIPTS) - $(PYTHON) $(JavaScriptCore)/inspector/scripts/CodeGeneratorInspector.py ./InspectorJS.json --output_h_dir . --output_cpp_dir . --output_js_dir . --output_type JavaScript +InspectorFrontendDispatchers.h : CombinedDomains.json $(INSPECTOR_GENERATOR_SCRIPTS) + $(PYTHON) $(JavaScriptCore)/inspector/scripts/generate-inspector-protocol-bindings.py --framework JavaScriptCore --outputDir . ./CombinedDomains.json InjectedScriptSource.h : inspector/InjectedScriptSource.js $(JavaScriptCore)/inspector/scripts/jsmin.py $(JavaScriptCore)/inspector/scripts/xxd.pl echo "//# sourceURL=__WebInspectorInjectedScript__" > ./InjectedScriptSource.min.js $(PYTHON) $(JavaScriptCore)/inspector/scripts/jsmin.py < $(JavaScriptCore)/inspector/InjectedScriptSource.js >> ./InjectedScriptSource.min.js $(PERL) $(JavaScriptCore)/inspector/scripts/xxd.pl InjectedScriptSource_js ./InjectedScriptSource.min.js InjectedScriptSource.h - rm -f ./InjectedScriptSource.min.js + $(DELETE) InjectedScriptSource.min.js # Web Replay inputs generator diff --git a/Info.plist b/Info.plist index 7a2f110..e5675ce 100644 --- a/Info.plist +++ b/Info.plist @@ -7,7 +7,7 @@ <key>CFBundleExecutable</key> <string>${PRODUCT_NAME}</string> <key>CFBundleGetInfoString</key> - <string>${BUNDLE_VERSION}, Copyright 2003-2014 Apple Inc.; Copyright 1999-2001 Harri Porten <porten@kde.org>; Copyright 2001 Peter Kelly <pmk@post.com>; Copyright 1997-2005 University of Cambridge; Copyright 1991, 2000, 2001 by Lucent Technologies.</string> + <string>${BUNDLE_VERSION}, Copyright 2003-2015 Apple Inc.; Copyright 1999-2001 Harri Porten <porten@kde.org>; Copyright 2001 Peter Kelly <pmk@post.com>; Copyright 1997-2005 University of Cambridge; Copyright 1991, 2000, 2001 by Lucent Technologies.</string> <key>CFBundleIdentifier</key> <string>com.apple.${PRODUCT_NAME}</string> <key>CFBundleInfoDictionaryVersion</key> diff --git a/JavaScriptCore.order b/JavaScriptCore.order index 633dd45..6a3c1a5 100644 --- a/JavaScriptCore.order +++ b/JavaScriptCore.order @@ -173,20 +173,14 @@ __ZN3JSC19ExecutableAllocatorC1ERNS_2VME __ZN3JSC4HeapC1EPNS_2VMENS_8HeapTypeE __ZN3JSC4HeapC2EPNS_2VMENS_8HeapTypeE __ZN3WTF7ramSizeEv -__ZN3JSC14BlockAllocatorC1Ev __ZN3JSC11SuperRegionC1Ev __ZN3JSC11MarkedSpaceC1EPNS_4HeapE __ZN3JSC11MarkedSpaceC2EPNS_4HeapE __ZN3JSC11CopiedSpaceC1EPNS_4HeapE __ZN3JSC14MachineThreadsC1EPNS_4HeapE __ZN3JSC18GCThreadSharedDataC1EPNS_2VME -__ZN3JSC14BlockAllocator27blockFreeingThreadStartFuncEPv __ZN3JSC18GCThreadSharedDataC2EPNS_2VME -__ZN3JSC14MarkStackArrayC1ERNS_14BlockAllocatorE -__ZN3JSC14BlockAllocator22blockFreeingThreadMainEv -__ZN3JSC14BlockAllocator8allocateINS_16MarkStackSegmentEEEPNS_9DeadBlockEv __ZN3WTF15ThreadCondition9timedWaitERNS_5MutexEd -__ZN3JSC14BlockAllocator21tryAllocateFromRegionERNS0_9RegionSetERN3WTF16DoublyLinkedListINS_6RegionEEERm __ZN3WTF21PageAllocationAligned8allocateEmmNS_11OSAllocator5UsageEb __ZN3JSC11SlotVisitorC1ERNS_18GCThreadSharedDataE __ZN3JSC11CopyVisitorC1ERNS_18GCThreadSharedDataE @@ -198,7 +192,6 @@ __ZN3JSC8GCThread12gcThreadMainEv __ZN3WTF16registerGCThreadEv __ZN3JSC8GCThread16waitForNextPhaseEv __ZN3JSC9HandleSetC1EPNS_2VME -__ZN3JSC14BlockAllocator8allocateINS_11HandleBlockEEEPNS_9DeadBlockEv __ZN3JSC11HandleStackC1Ev __ZN3WTF10BlockStackIN3JSC7JSValueEE4growEv __ZN3WTF6VectorIPN3JSC7JSValueELm0ENS_15CrashOnOverflowEE14expandCapacityEm @@ -210,7 +203,6 @@ __ZN3JSCL13retainAPILockEPKv __ZN3JSC18IncrementalSweeper6createEPNS_4HeapE __ZN3JSC11CopiedSpace4initEv __ZN3JSC11CopiedSpace13allocateBlockEv -__ZN3JSC14BlockAllocator8allocateINS_11CopiedBlockEEEPNS_9DeadBlockEv __ZN3WTF9HashTableIPN3JSC11CopiedBlockES3_NS_17IdentityExtractorENS_7PtrHashIS3_EENS_10HashTraitsIS3_EES8_E3addINS_22IdentityHashTranslatorIS6_EES3_S3_EENS_18HashTableAddResultINS_17HashTableIteratorIS3_S3_S4_S6_S8_S8_EEEERKT0_RKT1_ __ZN3JSC8WatchdogC1Ev __ZN3JSC8Watchdog9initTimerEv @@ -233,7 +225,6 @@ __ZN3JSC15MarkedAllocator16allocateSlowCaseEm __ZN3JSC4Heap11didAllocateEm __ZN3JSC25DefaultGCActivityCallback11didAllocateEm __ZN3JSC15MarkedAllocator13allocateBlockEm -__ZN3JSC14BlockAllocator8allocateINS_11MarkedBlockEEEPNS_9DeadBlockEv __ZN3JSC11MarkedBlock6createEPNS_9DeadBlockEPNS_15MarkedAllocatorEmNS0_14DestructorTypeE __ZN3JSC11MarkedBlock5sweepENS0_9SweepModeE __ZN3JSC7WeakSet5sweepEv @@ -285,7 +276,6 @@ __ZN3JSC9Structure16putSpecificValueERNS_2VMENS_12PropertyNameEjPNS_6JSCellE __ZN3JSC13PropertyTable3addERKNS_16PropertyMapEntryERiNS0_22EffectOnPropertyOffsetE __ZN3JSC24StructureTransitionTable3addERNS_2VMEPNS_9StructureE __ZN3JSC7WeakSet13findAllocatorEv -__ZN3JSC14BlockAllocator8allocateINS_9WeakBlockEEEPNS_9DeadBlockEv __ZN3JSC9WeakBlock6createEPNS_9DeadBlockE __ZN3JSC8JSObject43setStructureAndReallocateStorageIfNecessaryERNS_2VMEPNS_9StructureE __ZN3JSC8JSObject20growOutOfLineStorageERNS_2VMEmm @@ -553,7 +543,6 @@ __ZN3JSC25JSSegmentedVariableObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitor __ZN3JSC19JSSymbolTableObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC7JSScope13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC11CopiedBlock15reportLiveBytesEPNS_6JSCellEj -__ZN3JSC14BlockAllocator8allocateINS_19CopyWorkListSegmentEEEPNS_9DeadBlockEv __ZN3JSC13PropertyTable13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC12RegExpObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC6JSCell13visitChildrenEPS0_RNS_11SlotVisitorE @@ -590,7 +579,6 @@ __ZN3JSC4Heap17copyBackingStoresEv __ZN3JSC11CopiedSpace14startedCopyingEv __ZN3JSC11MarkedSpace12forEachBlockINS_8CapacityEEENT_10ReturnTypeERS3_ __ZN3JSC11CopiedSpace11doneCopyingEv -__ZN3JSC14BlockAllocator10deallocateINS_9HeapBlockINS_19CopyWorkListSegmentEEEEEvPT_ __ZN3JSC11SlotVisitor31finalizeUnconditionalFinalizersEv __ZN3JSC12SmallStrings20finalizeSmallStringsEv __ZN3JSC4Heap26deleteUnmarkedCompiledCodeEv @@ -637,7 +625,6 @@ __ZN3JSC14MachineThreads29makeUsableFromMultipleThreadsEv __ZN3JSC12GlobalJSLockD1Ev _JSGlobalContextCreateInGroup __ZN3JSC14JSGlobalObjectC1ERNS_2VMEPNS_9StructureEPKNS_23GlobalObjectMethodTableE -__ZN3JSC14JSGlobalObject28javaScriptExperimentsEnabledEPKS0_ _JSGlobalContextRetain _JSStringCreateWithCFString _JSEvaluateScript @@ -1049,7 +1036,6 @@ __ZN3WTF25TCMalloc_Central_FreeList18ReleaseListToSpansENS_11HardenedSLLE __ZN3JSC11CopiedSpace21recycleEvacuatedBlockEPNS_11CopiedBlockE __ZN3WTF7HashSetIPN3JSC11CopiedBlockENS_7PtrHashIS3_EENS_10HashTraitsIS3_EEE6removeERKS3_ __ZN3WTF7HashSetIPN3JSC11CopiedBlockENS_7PtrHashIS3_EENS_10HashTraitsIS3_EEE6removeENS_29HashTableConstIteratorAdapterINS_9HashTableIS3_S3_NS_17IdentityExtractorES5_S7_S7_EES3_EE -__ZN3JSC14BlockAllocator10deallocateINS_9HeapBlockINS_11CopiedBlockEEEEEvPT_ __ZN3WTF13StringBuilder6appendEPKtj __ZN3JSC24UnlinkedProgramCodeBlock13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC17UnlinkedCodeBlock13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE @@ -1300,7 +1286,6 @@ __ZN3WTF9HashTableINSt3__14pairIPN3JSC8JSObjectEjEENS_12KeyValuePairIS6_NS3_4Wea __ZN3WTF9HashTableINSt3__14pairIPN3JSC8JSObjectEjEENS_12KeyValuePairIS6_NS3_4WeakINS3_9StructureEEEEENS_24KeyValuePairKeyExtractorISB_EENS_8PairHashIS5_jEENS_18HashMapValueTraitsINS_10HashTraitsIS6_EENSH_ISA_EEEESI_E3addINS_17HashMapTranslatorISK_SF_EES6_NS3_8PassWeakIS9_EEEENS_18HashTableAddResultINS_17HashTableIteratorIS6_SB_SD_SF_SK_SI_EEEERKT0_RKT1_ __ZN3WTF9HashTableINSt3__14pairIPN3JSC8JSObjectEjEENS_12KeyValuePairIS6_NS3_4WeakINS3_9StructureEEEEENS_24KeyValuePairKeyExtractorISB_EENS_8PairHashIS5_jEENS_18HashMapValueTraitsINS_10HashTraitsIS6_EENSH_ISA_EEEESI_E6lookupINS_22IdentityHashTranslatorISF_EES6_EEPSB_RKT0_ __ZN3WTF9HashTableINSt3__14pairIPN3JSC8JSObjectEjEENS_12KeyValuePairIS6_NS3_4WeakINS3_9StructureEEEEENS_24KeyValuePairKeyExtractorISB_EENS_8PairHashIS5_jEENS_18HashMapValueTraitsINS_10HashTraitsIS6_EENSH_ISA_EEEESI_E6rehashEi -__ZN3JSC12JSActivation6createERNS_2VMEPNS_9ExecStateEPNS_9CodeBlockE __ZNK3JSC7JSValue3getEPNS_9ExecStateENS_12PropertyNameERNS_12PropertySlotE __ZNK3JSC19BracketAccessorNode10isLocationEv __ZNK3JSC19BracketAccessorNode21isBracketAccessorNodeEv @@ -1312,8 +1297,6 @@ __ZNK3JSC7JSScope14isDynamicScopeERb __ZN3JSC17AssignBracketNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE __ZN3JSC17BytecodeGenerator12emitPutByValEPNS_10RegisterIDES2_S2_ __ZN3JSC12RegExpObjectC1EPNS_14JSGlobalObjectEPNS_9StructureEPNS_6RegExpE -__ZN3JSC12JSActivation18getOwnPropertySlotEPNS_6JSCellEPNS_9ExecStateENS_12PropertyNameERNS_12PropertySlotE -__ZN3JSC12JSActivation14symbolTableGetENS_12PropertyNameERNS_12PropertySlotE __ZN3JSC17ObjectConstructor18getOwnPropertySlotEPNS_6JSCellEPNS_9ExecStateENS_12PropertyNameERNS_12PropertySlotE __ZN3JSC21getStaticFunctionSlotINS_8JSObjectEEEbPNS_9ExecStateEPKNS_9HashTableEPS1_NS_12PropertyNameERNS_12PropertySlotE __ZN3JSC14ArrayPrototype18getOwnPropertySlotEPNS_6JSCellEPNS_9ExecStateENS_12PropertyNameERNS_12PropertySlotE @@ -1352,9 +1335,7 @@ __ZN3JSC17BytecodeGenerator20emitNextPropertyNameEPNS_10RegisterIDES2_S2_S2_S2_P __ZN3JSC11PostfixNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10RegisterIDE __ZN3JSC11PostfixNode11emitResolveERNS_17BytecodeGeneratorEPNS_10RegisterIDE __ZN3JSC17BytecodeGenerator7emitIncEPNS_10RegisterIDE -__ZN3JSC14jsIsObjectTypeEPNS_9ExecStateENS_7JSValueE __ZN3JSC6JSCell11getCallDataEPS0_RNS_8CallDataE -__ZN3JSC22JSPropertyNameIterator6createEPNS_9ExecStateEPNS_8JSObjectE __ZN3JSC8JSObject16getPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE __ZN3JSC8JSObject19getOwnPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE __ZN3JSC8JSObject27getOwnNonIndexPropertyNamesEPS0_PNS_9ExecStateERNS_17PropertyNameArrayENS_15EnumerationModeE @@ -1638,13 +1619,10 @@ __ZN3JSC3JIT19emit_compareAndJumpENS_8OpcodeIDEjjjNS_23MacroAssemblerX86Common19 __ZN3JSC3JIT17emit_op_loop_hintEPNS_11InstructionE __ZN3JSC8Watchdog9isEnabledEv __ZN3JSC3JIT16emit_op_jeq_nullEPNS_11InstructionE -__ZN3JSC3JIT18emit_op_get_pnamesEPNS_11InstructionE __ZN3JSC3JIT11emit_op_jmpEPNS_11InstructionE -__ZN3JSC3JIT20emit_op_get_by_pnameEPNS_11InstructionE __ZN3JSC3JIT22compileGetDirectOffsetENS_12X86Registers10RegisterIDES2_S2_S2_NS0_15FinalObjectModeE __ZN3JSC3JIT17emit_op_new_arrayEPNS_11InstructionE __ZN3JSC3JIT17emit_op_nstricteqEPNS_11InstructionE -__ZN3JSC3JIT18emit_op_next_pnameEPNS_11InstructionE __ZN3JSC3JIT11emit_op_incEPNS_11InstructionE __ZN3JSC3JIT13emit_op_jlessEPNS_11InstructionE __ZN3JSC3JIT24emitSlow_op_convert_thisEPNS_11InstructionERPNS_13SlowCaseEntryE @@ -1663,7 +1641,6 @@ __ZN3JSC3JIT23emit_compareAndJumpSlowEjjjNS_23MacroAssemblerX86Common15DoubleCon __ZN3JSC12X86Assembler23X86InstructionFormatter11twoByteOp64ENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDE __ZN3JSC23MacroAssemblerX86Common12branchDoubleENS0_15DoubleConditionENS_12X86Registers13XMMRegisterIDES3_ __ZN3JSC12X86Assembler23X86InstructionFormatter9twoByteOpENS0_15TwoByteOpcodeIDEiNS_12X86Registers10RegisterIDE -__ZN3JSC3JIT24emitSlow_op_get_by_pnameEPNS_11InstructionERPNS_13SlowCaseEntryE __ZN3JSC3JIT21emitSlow_op_nstricteqEPNS_11InstructionERPNS_13SlowCaseEntryE __ZN3JSC3JIT15emitSlow_op_incEPNS_11InstructionERPNS_13SlowCaseEntryE __ZN3JSC3JIT17emitSlow_op_jlessEPNS_11InstructionERPNS_13SlowCaseEntryE @@ -1674,8 +1651,7 @@ _cti_op_get_by_val_generic __ZN3JSCL8getByValEPNS_9ExecStateENS_7JSValueES2_NS_16ReturnAddressPtrE _cti_op_stricteq _cti_op_jtrue -_cti_op_is_object -_cti_op_get_pnames +_cti_op_is_object_or_null __ZN3JSC8JSString12toThisObjectEPNS_6JSCellEPNS_9ExecStateE __ZN3JSC12StringObjectC1ERNS_2VMEPNS_9StructureE __ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE @@ -2622,7 +2598,6 @@ __ZN3JSC17JITStubRoutineSet8markSlowEm __ZN3WTF7HashMapImPN3JSC21GCAwareJITStubRoutineENS_7IntHashImEENS_10HashTraitsImEENS6_IS3_EEE4findERKm __ZN3JSC13JSFinalObject13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC17StructureRareData13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE -__ZN3JSC22JSPropertyNameIterator13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC14StructureChain13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC14MarkStackArray6expandEv __ZN3JSC17ProgramExecutable13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE @@ -2631,12 +2606,10 @@ __ZN3JSC18FunctionExecutable13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC9CodeBlock29stronglyVisitStrongReferencesERNS_11SlotVisitorE __ZN3JSC13EvalCodeCache14visitAggregateERNS_11SlotVisitorE __ZN3JSC9CodeBlock27stronglyVisitWeakReferencesERNS_11SlotVisitorE -__ZN3JSC12JSActivation13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC9CodeBlock31performTracingFixpointIterationERNS_11SlotVisitorE __ZN3JSC16JSCallbackObjectINS_20JSDestructibleObjectEE13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3JSC18RegExpMatchesArray13visitChildrenEPNS_6JSCellERNS_11SlotVisitorE __ZN3WTF9HashTableIPvS1_NS_17IdentityExtractorENS_7PtrHashIS1_EENS_10HashTraitsIS1_EES6_E16lookupForWritingINS_22IdentityHashTranslatorIS4_EES1_EENSt3__14pairIPS1_bEERKT0_ -__ZN3JSC14BlockAllocator10deallocateINS_9HeapBlockINS_16MarkStackSegmentEEEEEvPT_ __ZThn16_N3JSC9CodeBlock19visitWeakReferencesERNS_11SlotVisitorE __ZN3JSC9CodeBlock23finalizeUnconditionallyEv __ZN3JSC17StructureStubInfo19visitWeakReferencesEv @@ -2666,7 +2639,6 @@ __ZN3JSC18FunctionExecutable7destroyEPNS_6JSCellE __ZN3JSC17ProgramExecutable7destroyEPNS_6JSCellE __ZN3JSC17SharedSymbolTable7destroyEPNS_6JSCellE __ZN3JSC10JSFunction7destroyEPNS_6JSCellE -__ZN3JSC22JSPropertyNameIterator7destroyEPNS_6JSCellE __ZN3JSC19ResolveGlobalStatus10computeForEPNS_9CodeBlockEiPNS_16ResolveOperationERNS_10IdentifierE __ZN3JSC13GetByIdStatus10computeForERNS_2VMEPNS_9StructureERNS_10IdentifierE __ZN3JSC3DFG14SpeculativeJIT23emitObjectOrOtherBranchENS0_4EdgeEjj @@ -2897,13 +2869,11 @@ __ZN3JSC11MarkedSpace9freeBlockEPNS_11MarkedBlockE __ZN3JSC15MarkedAllocator11removeBlockEPNS_11MarkedBlockE __ZN3WTF7HashSetIPN3JSC11MarkedBlockENS_15MarkedBlockHashENS_10HashTraitsIS3_EEE6removeERKS3_ __ZN3JSC7WeakSetD1Ev -__ZN3JSC14BlockAllocator10deallocateINS_9HeapBlockINS_11MarkedBlockEEEEEvPT_ __ZN3JSC16NativeExecutable7destroyEPNS_6JSCellE __ZN3JSC11RegExpCache8finalizeENS_6HandleINS_7UnknownEEEPv __ZN3JSC6RegExp14invalidateCodeEv __ZN3JSC6RegExp7destroyEPNS_6JSCellE __ZN3JSC4Yarr13YarrCodeBlockD2Ev -__ZN3JSC14BlockAllocator10deallocateINS_9HeapBlockINS_9WeakBlockEEEEEvPT_ __ZN3JSC17RegExpConstructor7destroyEPNS_6JSCellE __ZN3JSC4Heap14FinalizerOwner8finalizeENS_6HandleINS_7UnknownEEEPv __ZN3JSC14JSGlobalObject7destroyEPNS_6JSCellE @@ -2976,7 +2946,6 @@ __ZN3JSC6ParserINS_5LexerItEEE19parseBreakStatementINS_10ASTBuilderEEENT_9Statem __ZN3WTF6VectorIPN3JSC8JSObjectELm4ENS_15CrashOnOverflowEE15reserveCapacityEm __ZN3WTF15BinarySemaphore4waitEd __ZN3WTF15BinarySemaphore6signalEv -_JSValueIsObject __ZN3JSCL19arrayProtoFuncShiftEPNS_9ExecStateE __ZN3JSC5shiftILNS_7JSArray14ShiftCountModeE0EEEvPNS_9ExecStateEPNS_8JSObjectEjjjj __ZN3JSC7JSArray26shiftCountWithArrayStorageEjjPNS_12ArrayStorageE @@ -3068,7 +3037,6 @@ __ZNK3JSC26UnlinkedFunctionExecutable11paramStringEv __ZN3JSC22jsMakeNontrivialStringIPKcN3WTF6StringES2_S4_S2_S4_EENS_7JSValueEPNS_9ExecStateET_T0_T1_T2_T3_T4_ __ZN3WTF13tryMakeStringIPKcNS_6StringES2_S3_S2_S3_EENS_10PassRefPtrINS_10StringImplEEET_T0_T1_T2_T3_T4_ __ZN3JSC4Yarr12ByteCompiler26alternativeBodyDisjunctionEb -__ZN3JSC9Arguments20didTearOffActivationEPNS_9ExecStateEPNS_12JSActivationE __ZN3JSC3JIT24emit_op_create_argumentsEPNS_11InstructionE __ZN3JSC3JIT16emit_op_new_funcEPNS_11InstructionE _cti_op_create_arguments @@ -3209,7 +3177,6 @@ __ZN3JSCL24dateProtoFuncToGMTStringEPNS_9ExecStateE __ZN3JSCL19formateDateInstanceEPNS_9ExecStateENS_14DateTimeFormatEb __ZNK3JSC12DateInstance29calculateGregorianDateTimeUTCEPNS_9ExecStateE __ZN3JSC17DateInstanceCache3addEd -__ZN3JSC21msToGregorianDateTimeEPNS_9ExecStateEdbRN3WTF17GregorianDateTimeE __ZN3WTF8msToYearEd __ZN3WTF11msToMinutesEd __ZN3WTF9msToHoursEd @@ -3285,7 +3252,6 @@ __ZN3JSC3JIT21emitLoadInt32ToDoubleEiNS_12X86Registers13XMMRegisterIDE __ZN3JSC14MacroAssembler20convertInt32ToDoubleENS_22AbstractMacroAssemblerINS_12X86AssemblerEE5Imm32ENS_12X86Registers13XMMRegisterIDE __ZN3JSC3JIT15emitSlow_op_modEPNS_11InstructionERPNS_13SlowCaseEntryE __ZN3JSCL20dateProtoFuncSetYearEPNS_9ExecStateE -__ZN3JSC21gregorianDateTimeToMSEPNS_9ExecStateERKN3WTF17GregorianDateTimeEdb __ZN3WTF18dateToDaysFrom1970Eiii __ZN3JSC10PrefixNode11emitBracketERNS_17BytecodeGeneratorEPNS_10RegisterIDE __ZN3JSC16globalFuncEscapeEPNS_9ExecStateE @@ -3406,7 +3372,6 @@ _operationEnsureContiguous __ZN3JSC8JSObject20ensureContiguousSlowERNS_2VME __ZN3JSC8JSObject20ensureContiguousSlowERNS_2VMENS0_22DoubleToContiguousModeE _operationMakeRope3 -_operationIsObject __ZN3JSC3DFG12slowPathCallINS_22AbstractMacroAssemblerINS_12X86AssemblerEE4JumpEPFxPNS_9ExecStateExPNS_7JSArrayEENS0_11NoResultTagENS_12X86Registers10RegisterIDESE_SE_EEN3WTF10PassOwnPtrINS0_17SlowPathGeneratorEEET_PNS0_14SpeculativeJITET0_T1_T2_T3_T4_NS0_18SpillRegistersModeE __ZN3JSC3DFG14SpeculativeJIT13callOperationEPFxPNS_9ExecStateExPNS_7JSArrayEENS_12X86Registers10RegisterIDES9_S9_ _operationArrayPush @@ -3735,8 +3700,6 @@ __ZN3JSC3DFG15AssemblyHelpers9boxDoubleENS_12X86Registers13XMMRegisterIDENS2_10R __ZN3JSC3DFG12GPRTemporaryC1EPNS0_14SpeculativeJITERNS0_23SpeculateIntegerOperandE __ZN3JSC3DFG12GPRTemporaryC2EPNS0_14SpeculativeJITERNS0_23SpeculateIntegerOperandE __ZN3JSC23MacroAssemblerX86Common9compare32ENS0_19RelationalConditionENS_12X86Registers10RegisterIDENS_22AbstractMacroAssemblerINS_12X86AssemblerEE12TrustedImm32ES3_ -__ZN3JSC12JSActivation3putEPNS_6JSCellEPNS_9ExecStateENS_12PropertyNameENS_7JSValueERNS_15PutPropertySlotE -__ZN3JSC12JSActivation14symbolTablePutEPNS_9ExecStateENS_12PropertyNameENS_7JSValueEb _cti_op_mod __ZN3JSC3DFG14SpeculativeJIT21compileObjectEqualityEPNS0_4NodeE __ZN3JSCL24dateProtoFuncToUTCStringEPNS_9ExecStateE @@ -4143,7 +4106,6 @@ __ZN3JSCL20callArrayConstructorEPNS_9ExecStateE __ZN3WTF5DequeINS_19FunctionWithContextELm0EE6removeEm __ZN3JSC17BytecodeGenerator20emitLoadGlobalObjectEPNS_10RegisterIDE __ZN3JSC4Yarr13YarrGeneratorILNS0_18YarrJITCompileModeE1EE29generatePatternCharacterFixedEm -__ZN3JSC12JSActivation15argumentsGetterEPNS_9ExecStateENS_7JSValueENS_12PropertyNameE __ZN3JSCL21dateProtoFuncSetMonthEPNS_9ExecStateE _operationCompareLess __ZN3JSCL23dateProtoFuncSetUTCDateEPNS_9ExecStateE @@ -4555,7 +4517,6 @@ __ZN3JSC17JITStubRoutineSetD2Ev __ZN3JSC13DFGCodeBlocksD1Ev __ZN3JSC13DFGCodeBlocksD2Ev __ZN3JSC9HandleSetD1Ev -__ZN3JSC14BlockAllocator10deallocateINS_9HeapBlockINS_11HandleBlockEEEEEvPT_ __ZN3JSC11SlotVisitorD1Ev __ZN3JSC14MarkStackArrayD1Ev __ZN3JSC18GCThreadSharedDataD1Ev @@ -4567,8 +4528,6 @@ __ZN3JSC11CopiedSpaceD1Ev __ZN3JSC11CopiedSpaceD2Ev __ZN3JSC11MarkedSpaceD1Ev __ZN3JSC11MarkedSpace12forEachBlockINS_4FreeEEENT_10ReturnTypeERS3_ -__ZN3JSC14BlockAllocatorD1Ev -__ZN3JSC14BlockAllocator18releaseFreeRegionsEv __ZN3JSC11SuperRegionD1Ev __ZN3WTF13MetaAllocatorD2Ev __ZN3JSC19ExecutableAllocatorD1Ev @@ -4617,14 +4576,8 @@ __ZN3JSCL24regExpConstructorDollar6EPNS_9ExecStateENS_7JSValueENS_12PropertyName __ZN3JSC5LexerIhE23parseIdentifierSlowCaseILb1EEENS_11JSTokenTypeEPNS_11JSTokenDataEjb __ZN3JSC4Yarr13YarrGeneratorILNS0_18YarrJITCompileModeE1EE33generatePatternCharacterNonGreedyEm __ZN3JSC4Yarr13YarrGeneratorILNS0_18YarrJITCompileModeE1EE34backtrackPatternCharacterNonGreedyEm -__ZN3JSC13NamePrototypeC1EPNS_9ExecStateEPNS_9StructureE -__ZN3JSC12NameInstanceC2ERNS_2VMEPNS_9StructureEPNS_8JSStringE -__ZN3JSC13NamePrototype14finishCreationEPNS_9ExecStateE -__ZN3JSC15NameConstructorC1EPNS_14JSGlobalObjectEPNS_9StructureE -__ZN3JSC15NameConstructor14finishCreationEPNS_9ExecStateEPNS_13NamePrototypeE _JSStringIsEqualToUTF8CString _JSStringIsEqual -__ZN3JSC12NameInstance7destroyEPNS_6JSCellE __ZN3WTF3MD5C1Ev __ZN3WTF3MD58addBytesEPKhm __ZN3WTFL12MD5TransformEPjPKj @@ -4772,12 +4725,9 @@ __ZN3JSCL26callNativeErrorConstructorEPNS_9ExecStateE __ZN3JSC17BytecodeGenerator35emitThrowExpressionTooDeepExceptionEv __ZN3JSC22createOutOfMemoryErrorEPNS_14JSGlobalObjectE __ZN3JSCL17mathProtoFuncACosEPNS_9ExecStateE -__ZN3JSC12JSActivation14deletePropertyEPNS_6JSCellEPNS_9ExecStateENS_12PropertyNameE __ZN3JSC11JSNameScope3putEPNS_6JSCellEPNS_9ExecStateENS_12PropertyNameENS_7JSValueERNS_15PutPropertySlotE __ZN3JSC14symbolTablePutINS_11JSNameScopeEEEbPT_PNS_9ExecStateENS_12PropertyNameENS_7JSValueEb -__ZN3JSC15NameConstructor11getCallDataEPNS_6JSCellERNS_8CallDataE __ZN3JSCL20constructPrivateNameEPNS_9ExecStateE -__ZN3JSC12NameInstanceC1ERNS_2VMEPNS_9StructureEPNS_8JSStringE __ZN3JSCL29objectProtoFuncToLocaleStringEPNS_9ExecStateE __ZN3JSC13JSNotAnObject24getOwnPropertyDescriptorEPNS_8JSObjectEPNS_9ExecStateENS_12PropertyNameERNS_18PropertyDescriptorE __ZN3JSCL20isNonLatin1IdentPartEi @@ -4925,7 +4875,7 @@ _llint_slow_path_bitxor _llint_slow_path_check_has_instance _llint_slow_path_instanceof _llint_slow_path_typeof -_llint_slow_path_is_object +_llint_slow_path_is_object_or_null _llint_slow_path_is_function _llint_slow_path_in _llint_slow_path_resolve @@ -4940,7 +4890,6 @@ _llint_slow_path_put_by_id _llint_slow_path_del_by_id _llint_slow_path_get_by_val _llint_slow_path_get_argument_by_val -_llint_slow_path_get_by_pname _llint_slow_path_put_by_val _llint_slow_path_del_by_val _llint_slow_path_put_by_index @@ -4968,8 +4917,6 @@ _llint_slow_path_tear_off_activation _llint_slow_path_tear_off_arguments _llint_slow_path_strcat _llint_slow_path_to_primitive -_llint_slow_path_get_pnames -_llint_slow_path_next_pname _llint_slow_path_push_with_scope _llint_slow_path_pop_scope _llint_slow_path_push_name_scope @@ -5036,7 +4983,6 @@ _llint_op_put_by_id_transition_normal _llint_op_put_by_id_transition_normal_out_of_line _llint_op_get_by_val _llint_op_get_argument_by_val -_llint_op_get_by_pname _llint_op_put_by_val _llint_op_jmp _llint_op_jeq_null @@ -5051,7 +4997,6 @@ _llint_op_ret _llint_op_call_put_result _llint_op_ret_object_or_this _llint_op_to_primitive -_llint_op_next_pname _llint_op_catch _llint_op_get_scoped_var _llint_op_put_scoped_var @@ -5068,7 +5013,7 @@ _llint_op_greater _llint_op_greatereq _llint_op_mod _llint_op_typeof -_llint_op_is_object +_llint_op_is_object_or_null _llint_op_is_function _llint_op_in _llint_op_put_to_base_variable @@ -5109,7 +5054,6 @@ _llint_op_call_varargs _llint_op_call_eval _llint_generic_return_point _llint_op_strcat -_llint_op_get_pnames _llint_op_push_with_scope _llint_op_pop_scope _llint_op_push_name_scope diff --git a/JavaScriptCore.vcxproj/JavaScriptCore.proj b/JavaScriptCore.vcxproj/JavaScriptCore.proj index 6b3f971..b89bac4 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCore.proj +++ b/JavaScriptCore.vcxproj/JavaScriptCore.proj @@ -4,9 +4,11 @@ <!-- normalize configuration case --> <PropertyGroup Condition="'$(CONFIGURATION)'=='Release'"> <CONFIG>Production</CONFIG> + <DebugSuffix></DebugSuffix> </PropertyGroup> <PropertyGroup Condition="'$(CONFIGURATION)'=='Debug'"> <CONFIG>DebugSuffix</CONFIG> + <DebugSuffix>_debug</DebugSuffix> </PropertyGroup> <!-- Wrapper to build JavaScriptCore for both win32 and x64. --> @@ -60,7 +62,7 @@ <Message Text="Building $(CONFIGURATION) Solution" /> <Error Text="DSTROOT property or environment variable must be defined." Condition="'$(DSTROOT)' == ''" /> <Message Text="Output=$(WebKit_OutputDir)" /> - <MSBuild Projects="@(JavaScriptCore)" Properties="Configuration=$(CONFIG)" Targets="ReBuild" /> + <MSBuild Projects="@(JavaScriptCore)" Properties="Configuration=$(CONFIG)" Targets="Build" /> </Target> <Target Name="PostBuild" AfterTargets="Build"> @@ -83,6 +85,18 @@ <CreateItem Include="$(ConfigurationBuildDir)\bin64\*.pdb"> <Output TaskParameter="Include" ItemName="Bin64SymbolFiles" /> </CreateItem> + <CreateItem Include="$(ConfigurationBuildDir)\bin32\JavaScriptCore$(DebugSuffix).dll"> + <Output TaskParameter="Include" ItemName="Bin32DLLFiles" /> + </CreateItem> + <CreateItem Include="$(ConfigurationBuildDir)\bin64\JavaScriptCore$(DebugSuffix).dll"> + <Output TaskParameter="Include" ItemName="Bin64DLLFiles" /> + </CreateItem> + <CreateItem Include="$(ConfigurationBuildDir)\bin32\*.resources"> + <Output TaskParameter="Include" ItemName="Bin32ResourceFolders" /> + </CreateItem> + <CreateItem Include="$(ConfigurationBuildDir)\bin64\*.resources"> + <Output TaskParameter="Include" ItemName="Bin64ResourceFolders" /> + </CreateItem> <CreateItem Include="$(ConfigurationBuildDir)\bin32\JavaScriptCore.resources\**\*.*"> <Output TaskParameter="Include" ItemName="Bin32Resources" /> </CreateItem> @@ -106,11 +120,13 @@ <Copy SourceFiles="@(Lib32Files)" DestinationFolder="$(AppleInternalLib32)" /> <Copy SourceFiles="@(Lib64Files)" DestinationFolder="$(AppleInternalLib64)" /> <Copy SourceFiles="@(Bin32Files)" DestinationFolder="$(AppleInternalBin32)" /> - <Copy SourceFiles="@(Bin32Files)" DestinationFolder="$(DSTROOT)\$(ProgramFilesAAS32)" /> + <Copy SourceFiles="@(Bin32DLLFiles)" DestinationFolder="$(DSTROOT)\$(ProgramFilesAAS32)" /> + <Copy SourceFiles="@(Bin32ResourceFolders)" DestinationFolder="$(DSTROOT)\$(ProgramFilesAAS32)" /> <Copy SourceFiles="@(Bin32SymbolFiles)" DestinationFolder="$(AppleInternal32Symbols)" /> <Copy SourceFiles="@(Bin32Resources)" DestinationFiles="@(Bin32Resources->'$(DSTROOT)\$(ProgramFilesAAS32)\JavaScriptCore.resources\%(RecursiveDir)%(Filename)%(Extension)')" /> <Copy SourceFiles="@(Bin64Files)" DestinationFolder="$(AppleInternalBin64)" /> - <Copy SourceFiles="@(Bin64Files)" DestinationFolder="$(DSTROOT)\$(ProgramFilesAAS64)" /> + <Copy SourceFiles="@(Bin64DLLFiles)" DestinationFolder="$(DSTROOT)\$(ProgramFilesAAS64)" /> + <Copy SourceFiles="@(Bin64ResourceFolders)" DestinationFolder="$(DSTROOT)\$(ProgramFilesAAS64)" /> <Copy SourceFiles="@(Bin64SymbolFiles)" DestinationFolder="$(AppleInternal64Symbols)" /> <Copy SourceFiles="@(Bin64Resources)" DestinationFiles="@(Bin64Resources->'$(DSTROOT)\$(ProgramFilesAAS64)\JavaScriptCore.resources\%(RecursiveDir)%(Filename)%(Extension)')" /> <Copy SourceFiles="@(Derived32Sources)" DestinationFiles="@(Derived32Sources->'$(DSTROOT)\AppleInternal\Sources32\JavaScriptCore\%(RecursiveDir)%(Filename)%(Extension)')" /> diff --git a/JavaScriptCore.vcxproj/JavaScriptCore.sln b/JavaScriptCore.vcxproj/JavaScriptCore.sln index 6aa8521..8fe5da4 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCore.sln +++ b/JavaScriptCore.vcxproj/JavaScriptCore.sln @@ -1,6 +1,8 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaScriptCore", "JavaScriptCore.vcxproj", "{22413D41-3A18-42B7-92A8-CEDC6CE86920}" ProjectSection(ProjectDependencies) = postProject {9221744B-5715-4F56-9590-42F7AB23DD8B} = {9221744B-5715-4F56-9590-42F7AB23DD8B} @@ -33,12 +35,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LLIntOffsetsExtractor", "LL EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testapi", "testapi\testapi.vcxproj", "{5CC08E13-2CF9-4C2E-8544-07DA4E8C1843}" ProjectSection(ProjectDependencies) = postProject - {BB16286B-AADC-46C1-BC0D-6C06F323E04B} = {BB16286B-AADC-46C1-BC0D-6C06F323E04B} + {FE09F693-9744-4D73-A17C-DE3209EB1905} = {FE09F693-9744-4D73-A17C-DE3209EB1905} + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F} = {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testRegExp", "testRegExp\testRegExp.vcxproj", "{BB16286B-AADC-46C1-BC0D-6C06F323E04B}" ProjectSection(ProjectDependencies) = postProject - {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} = {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} + {FE09F693-9744-4D73-A17C-DE3209EB1905} = {FE09F693-9744-4D73-A17C-DE3209EB1905} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WTF", "..\..\WTF\WTF.vcxproj\WTF.vcxproj", "{8EF73779-BED3-45BB-816D-9FF58399AFA5}" @@ -48,6 +51,23 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WTF", "..\..\WTF\WTF.vcxpro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WTFGenerated", "..\..\WTF\WTF.vcxproj\WTFGenerated.vcxproj", "{F7366596-0520-4433-B8FF-D843E31E5199}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jscLauncher", "jsc\jsclauncher.vcxproj", "{FE09F693-9744-4D73-A17C-DE3209EB1905}" + ProjectSection(ProjectDependencies) = postProject + {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} = {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testapiLauncher", "testapi\testapiLauncher.vcxproj", "{FE09F693-9744-4D73-A17C-FE3209EB1905}" + ProjectSection(ProjectDependencies) = postProject + {5CC08E13-2CF9-4C2E-8544-07DA4E8C1843} = {5CC08E13-2CF9-4C2E-8544-07DA4E8C1843} + {FE09F693-9744-4D73-A17C-DE3209EB1905} = {FE09F693-9744-4D73-A17C-DE3209EB1905} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testRegExpLauncher", "testRegExp\testRegExpLauncher.vcxproj", "{1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}" + ProjectSection(ProjectDependencies) = postProject + {BB16286B-AADC-46C1-BC0D-6C06F323E04B} = {BB16286B-AADC-46C1-BC0D-6C06F323E04B} + {FE09F693-9744-4D73-A17C-DE3209EB1905} = {FE09F693-9744-4D73-A17C-DE3209EB1905} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_WinCairo|Win32 = Debug_WinCairo|Win32 @@ -304,6 +324,78 @@ Global {F7366596-0520-4433-B8FF-D843E31E5199}.Release|Win32.Build.0 = Release|Win32 {F7366596-0520-4433-B8FF-D843E31E5199}.Release|x64.ActiveCfg = Release|x64 {F7366596-0520-4433-B8FF-D843E31E5199}.Release|x64.Build.0 = Release|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|Win32.ActiveCfg = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|Win32.Build.0 = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|x64.ActiveCfg = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|x64.Build.0 = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|Win32.Build.0 = Debug|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|x64.ActiveCfg = Debug|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|x64.Build.0 = Debug|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|Win32.ActiveCfg = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|Win32.Build.0 = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|x64.ActiveCfg = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|x64.Build.0 = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|Win32.ActiveCfg = Production|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|Win32.Build.0 = Production|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|x64.ActiveCfg = Production|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|x64.Build.0 = Production|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|Win32.ActiveCfg = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|Win32.Build.0 = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|x64.ActiveCfg = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|x64.Build.0 = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|Win32.ActiveCfg = Release|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|Win32.Build.0 = Release|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|x64.ActiveCfg = Release|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|x64.Build.0 = Release|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|Win32.ActiveCfg = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|Win32.Build.0 = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|x64.ActiveCfg = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|x64.Build.0 = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|Win32.Build.0 = Debug|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|x64.ActiveCfg = Debug|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|x64.Build.0 = Debug|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|Win32.ActiveCfg = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|Win32.Build.0 = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|x64.ActiveCfg = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|x64.Build.0 = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|Win32.ActiveCfg = Production|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|Win32.Build.0 = Production|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|x64.ActiveCfg = Production|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|x64.Build.0 = Production|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|Win32.ActiveCfg = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|Win32.Build.0 = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|x64.ActiveCfg = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|x64.Build.0 = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|Win32.ActiveCfg = Release|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|Win32.Build.0 = Release|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|x64.ActiveCfg = Release|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|x64.Build.0 = Release|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|Win32.ActiveCfg = Debug_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|Win32.Build.0 = Debug_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|x64.ActiveCfg = Debug_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|x64.Build.0 = Debug_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|Win32.ActiveCfg = Debug|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|Win32.Build.0 = Debug|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|x64.ActiveCfg = Debug|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|x64.Build.0 = Debug|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|Win32.ActiveCfg = DebugSuffix|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|Win32.Build.0 = DebugSuffix|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|x64.ActiveCfg = DebugSuffix|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|x64.Build.0 = DebugSuffix|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|Win32.ActiveCfg = Production|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|Win32.Build.0 = Production|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|x64.ActiveCfg = Production|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|x64.Build.0 = Production|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|Win32.ActiveCfg = Release_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|Win32.Build.0 = Release_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|x64.ActiveCfg = Release_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|x64.Build.0 = Release_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|Win32.ActiveCfg = Release|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|Win32.Build.0 = Release|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|x64.ActiveCfg = Release|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/JavaScriptCore.vcxproj/JavaScriptCore.submit.sln b/JavaScriptCore.vcxproj/JavaScriptCore.submit.sln index bdfe54f..1a50adb 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCore.submit.sln +++ b/JavaScriptCore.vcxproj/JavaScriptCore.submit.sln @@ -18,12 +18,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsc", "jsc\jsc.vcxproj", "{ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testRegExp", "testRegExp\testRegExp.vcxproj", "{BB16286B-AADC-46C1-BC0D-6C06F323E04B}" ProjectSection(ProjectDependencies) = postProject - {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} = {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} + {FE09F693-9744-4D73-A17C-DE3209EB1905} = {FE09F693-9744-4D73-A17C-DE3209EB1905} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testapi", "testapi\testapi.vcxproj", "{5CC08E13-2CF9-4C2E-8544-07DA4E8C1843}" ProjectSection(ProjectDependencies) = postProject - {BB16286B-AADC-46C1-BC0D-6C06F323E04B} = {BB16286B-AADC-46C1-BC0D-6C06F323E04B} + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F} = {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LLIntAssembly", "LLInt\LLIntAssembly\LLIntAssembly.vcxproj", "{9221744B-5715-4F56-9590-42F7AB23DD8B}" @@ -41,6 +41,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LLIntOffsetsExtractor", "LL {877150A0-41B3-4730-9D98-1B8298098B14} = {877150A0-41B3-4730-9D98-1B8298098B14} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jscLauncher", "jsc\jscLauncher.vcxproj", "{FE09F693-9744-4D73-A17C-DE3209EB1905}" + ProjectSection(ProjectDependencies) = postProject + {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} = {2BD437CF-BDAC-4119-9ED6-E10EF46C69F3} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testapiLauncher", "testapi\testapiLauncher.vcxproj", "{FE09F693-9744-4D73-A17C-FE3209EB1905}" + ProjectSection(ProjectDependencies) = postProject + {5CC08E13-2CF9-4C2E-8544-07DA4E8C1843} = {5CC08E13-2CF9-4C2E-8544-07DA4E8C1843} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testRegExpLauncher", "testRegExp\testRegExpLauncher.vcxproj", "{1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}" + ProjectSection(ProjectDependencies) = postProject + {BB16286B-AADC-46C1-BC0D-6C06F323E04B} = {BB16286B-AADC-46C1-BC0D-6C06F323E04B} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_WinCairo|Win32 = Debug_WinCairo|Win32 @@ -249,6 +264,78 @@ Global {D595E3F6-24F2-4C60-935C-95D50C6B3E96}.Release|Win32.Build.0 = Release|Win32 {D595E3F6-24F2-4C60-935C-95D50C6B3E96}.Release|x64.ActiveCfg = Release|x64 {D595E3F6-24F2-4C60-935C-95D50C6B3E96}.Release|x64.Build.0 = Release|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|Win32.ActiveCfg = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|Win32.Build.0 = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|x64.ActiveCfg = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug_WinCairo|x64.Build.0 = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|Win32.Build.0 = Debug|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|x64.ActiveCfg = Debug|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Debug|x64.Build.0 = Debug|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|Win32.ActiveCfg = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|Win32.Build.0 = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|x64.ActiveCfg = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.DebugSuffix|x64.Build.0 = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|Win32.ActiveCfg = Production|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|Win32.Build.0 = Production|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|x64.ActiveCfg = Production|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Production|x64.Build.0 = Production|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|Win32.ActiveCfg = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|Win32.Build.0 = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|x64.ActiveCfg = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release_WinCairo|x64.Build.0 = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|Win32.ActiveCfg = Release|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|Win32.Build.0 = Release|Win32 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|x64.ActiveCfg = Release|x64 + {FE09F693-9744-4D73-A17C-DE3209EB1905}.Release|x64.Build.0 = Release|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|Win32.ActiveCfg = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|Win32.Build.0 = Debug_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|x64.ActiveCfg = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug_WinCairo|x64.Build.0 = Debug_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|Win32.Build.0 = Debug|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|x64.ActiveCfg = Debug|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Debug|x64.Build.0 = Debug|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|Win32.ActiveCfg = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|Win32.Build.0 = DebugSuffix|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|x64.ActiveCfg = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.DebugSuffix|x64.Build.0 = DebugSuffix|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|Win32.ActiveCfg = Production|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|Win32.Build.0 = Production|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|x64.ActiveCfg = Production|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Production|x64.Build.0 = Production|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|Win32.ActiveCfg = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|Win32.Build.0 = Release_WinCairo|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|x64.ActiveCfg = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release_WinCairo|x64.Build.0 = Release_WinCairo|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|Win32.ActiveCfg = Release|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|Win32.Build.0 = Release|Win32 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|x64.ActiveCfg = Release|x64 + {FE09F693-9744-4D73-A17C-FE3209EB1905}.Release|x64.Build.0 = Release|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|Win32.ActiveCfg = Debug_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|Win32.Build.0 = Debug_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|x64.ActiveCfg = Debug_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug_WinCairo|x64.Build.0 = Debug_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|Win32.ActiveCfg = Debug|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|Win32.Build.0 = Debug|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|x64.ActiveCfg = Debug|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Debug|x64.Build.0 = Debug|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|Win32.ActiveCfg = DebugSuffix|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|Win32.Build.0 = DebugSuffix|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|x64.ActiveCfg = DebugSuffix|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.DebugSuffix|x64.Build.0 = DebugSuffix|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|Win32.ActiveCfg = Production|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|Win32.Build.0 = Production|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|x64.ActiveCfg = Production|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Production|x64.Build.0 = Production|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|Win32.ActiveCfg = Release_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|Win32.Build.0 = Release_WinCairo|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|x64.ActiveCfg = Release_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release_WinCairo|x64.Build.0 = Release_WinCairo|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|Win32.ActiveCfg = Release|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|Win32.Build.0 = Release|Win32 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|x64.ActiveCfg = Release|x64 + {1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj index 14e46d3..1c1e5f3 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj +++ b/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj @@ -61,7 +61,7 @@ <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <ConfigurationType>DynamicLibrary</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <UseDebugLibraries>true</UseDebugLibraries> @@ -85,7 +85,7 @@ <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <ConfigurationType>DynamicLibrary</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> <UseDebugLibraries>true</UseDebugLibraries> @@ -97,7 +97,7 @@ <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> @@ -121,7 +121,7 @@ <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> @@ -304,8 +304,7 @@ <ClCompile Include="..\API\OpaqueJSString.cpp" /> <ClCompile Include="..\assembler\LinkBuffer.cpp" /> <ClCompile Include="..\assembler\MacroAssembler.cpp" /> - <ClInclude Include="..\API\JSCTestRunnerUtils.h" /> - <ClInclude Include="..\assembler\MacroAssemblerX86Common.cpp" /> + <ClCompile Include="..\assembler\MacroAssemblerX86Common.cpp" /> <ClCompile Include="..\bindings\ScriptFunctionCall.cpp" /> <ClCompile Include="..\bindings\ScriptObject.cpp" /> <ClCompile Include="..\bindings\ScriptValue.cpp" /> @@ -313,15 +312,21 @@ <ClCompile Include="..\bytecode\ArrayAllocationProfile.cpp" /> <ClCompile Include="..\bytecode\ArrayProfile.cpp" /> <ClCompile Include="..\bytecode\BytecodeBasicBlock.cpp" /> + <ClCompile Include="..\bytecode\BytecodeIntrinsicRegistry.cpp" /> <ClCompile Include="..\bytecode\BytecodeLivenessAnalysis.cpp" /> + <ClCompile Include="..\bytecode\CallEdge.cpp" /> <ClCompile Include="..\bytecode\CallLinkInfo.cpp" /> <ClCompile Include="..\bytecode\CallLinkStatus.cpp" /> + <ClCompile Include="..\bytecode\CallVariant.cpp" /> <ClCompile Include="..\bytecode\CodeBlock.cpp" /> <ClCompile Include="..\bytecode\CodeBlockHash.cpp" /> <ClCompile Include="..\bytecode\CodeBlockJettisoningWatchpoint.cpp" /> <ClCompile Include="..\bytecode\CodeOrigin.cpp" /> <ClCompile Include="..\bytecode\CodeType.cpp" /> + <ClCompile Include="..\bytecode\ComplexGetStatus.cpp" /> + <ClCompile Include="..\bytecode\ConstantStructureCheck.cpp" /> <ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp" /> + <ClCompile Include="..\bytecode\DeferredSourceDump.cpp" /> <ClCompile Include="..\bytecode\DFGExitProfile.cpp" /> <ClCompile Include="..\bytecode\ExecutionCounter.cpp" /> <ClCompile Include="..\bytecode\ExitKind.cpp" /> @@ -335,7 +340,6 @@ <ClCompile Include="..\bytecode\Opcode.cpp" /> <ClCompile Include="..\bytecode\PolymorphicGetByIdList.cpp" /> <ClCompile Include="..\bytecode\PolymorphicPutByIdList.cpp" /> - <ClCompile Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.cpp" /> <ClCompile Include="..\bytecode\PreciseJumpTargets.cpp" /> <ClCompile Include="..\bytecode\PutByIdStatus.cpp" /> <ClCompile Include="..\bytecode\PutByIdVariant.cpp" /> @@ -343,74 +347,95 @@ <ClCompile Include="..\bytecode\SamplingTool.cpp" /> <ClCompile Include="..\bytecode\SpecialPointer.cpp" /> <ClCompile Include="..\bytecode\SpeculatedType.cpp" /> + <ClCompile Include="..\bytecode\StructureSet.cpp" /> <ClCompile Include="..\bytecode\StructureStubClearingWatchpoint.cpp" /> <ClCompile Include="..\bytecode\StructureStubInfo.cpp" /> + <ClCompile Include="..\bytecode\ToThisStatus.cpp" /> + <ClCompile Include="..\bytecode\TrackedReferences.cpp" /> <ClCompile Include="..\bytecode\UnlinkedCodeBlock.cpp" /> <ClCompile Include="..\bytecode\UnlinkedInstructionStream.cpp" /> <ClCompile Include="..\bytecode\ValueRecovery.cpp" /> + <ClCompile Include="..\bytecode\VariableWriteFireDetail.cpp" /> + <ClCompile Include="..\bytecode\VirtualRegister.cpp" /> <ClCompile Include="..\bytecode\Watchpoint.cpp" /> <ClCompile Include="..\bytecompiler\BytecodeGenerator.cpp" /> <ClCompile Include="..\bytecompiler\NodesCodegen.cpp" /> <ClCompile Include="..\debugger\Debugger.cpp" /> - <ClCompile Include="..\debugger\DebuggerActivation.cpp" /> <ClCompile Include="..\debugger\DebuggerCallFrame.cpp" /> + <ClCompile Include="..\debugger\DebuggerScope.cpp" /> <ClCompile Include="..\dfg\DFGAbstractHeap.cpp" /> <ClCompile Include="..\dfg\DFGAbstractValue.cpp" /> - <ClCompile Include="..\dfg\DFGArgumentsSimplificationPhase.cpp" /> + <ClCompile Include="..\dfg\DFGArgumentsEliminationPhase.cpp" /> + <ClCompile Include="..\dfg\DFGArgumentsUtilities.cpp" /> <ClCompile Include="..\dfg\DFGArithMode.cpp" /> <ClCompile Include="..\dfg\DFGArrayMode.cpp" /> <ClCompile Include="..\dfg\DFGAtTailAbstractState.cpp" /> <ClCompile Include="..\dfg\DFGAvailability.cpp" /> + <ClCompile Include="..\dfg\DFGAvailabilityMap.cpp" /> <ClCompile Include="..\dfg\DFGBackwardsPropagationPhase.cpp" /> <ClCompile Include="..\dfg\DFGBasicBlock.cpp" /> - <ClCompile Include="..\dfg\DFGBinarySwitch.cpp" /> <ClCompile Include="..\dfg\DFGBlockInsertionSet.cpp" /> + <ClCompile Include="..\dfg\DFGBlockSet.cpp" /> + <ClCompile Include="..\dfg\DFGBlockWorklist.cpp" /> <ClCompile Include="..\dfg\DFGByteCodeParser.cpp" /> <ClCompile Include="..\dfg\DFGCapabilities.cpp" /> <ClCompile Include="..\dfg\DFGCFAPhase.cpp" /> <ClCompile Include="..\dfg\DFGCFGSimplificationPhase.cpp" /> + <ClCompile Include="..\dfg\DFGCleanUpPhase.cpp" /> <ClCompile Include="..\dfg\DFGClobberize.cpp" /> <ClCompile Include="..\dfg\DFGClobberSet.cpp" /> + <ClCompile Include="..\dfg\DFGCombinedLiveness.cpp" /> <ClCompile Include="..\dfg\DFGCommon.cpp" /> <ClCompile Include="..\dfg\DFGCommonData.cpp" /> <ClCompile Include="..\dfg\DFGCompilationKey.cpp" /> <ClCompile Include="..\dfg\DFGCompilationMode.cpp" /> <ClCompile Include="..\dfg\DFGConstantFoldingPhase.cpp" /> + <ClCompile Include="..\dfg\DFGConstantHoistingPhase.cpp" /> <ClCompile Include="..\dfg\DFGCPSRethreadingPhase.cpp" /> <ClCompile Include="..\dfg\DFGCriticalEdgeBreakingPhase.cpp" /> <ClCompile Include="..\dfg\DFGCSEPhase.cpp" /> <ClCompile Include="..\dfg\DFGDCEPhase.cpp" /> <ClCompile Include="..\dfg\DFGDesiredIdentifiers.cpp" /> - <ClCompile Include="..\dfg\DFGDesiredStructureChains.cpp" /> <ClCompile Include="..\dfg\DFGDesiredTransitions.cpp" /> <ClCompile Include="..\dfg\DFGDesiredWatchpoints.cpp" /> <ClCompile Include="..\dfg\DFGDesiredWeakReferences.cpp" /> <ClCompile Include="..\dfg\DFGDesiredWriteBarriers.cpp" /> <ClCompile Include="..\dfg\DFGDisassembler.cpp" /> + <ClCompile Include="..\dfg\DFGDoesGC.cpp" /> <ClCompile Include="..\dfg\DFGDominators.cpp" /> <ClCompile Include="..\dfg\DFGDriver.cpp" /> <ClCompile Include="..\dfg\DFGEdge.cpp" /> + <ClCompile Include="..\dfg\DFGEpoch.cpp" /> <ClCompile Include="..\dfg\DFGFailedFinalizer.cpp" /> <ClCompile Include="..\dfg\DFGFinalizer.cpp" /> <ClCompile Include="..\dfg\DFGFixupPhase.cpp" /> <ClCompile Include="..\dfg\DFGFlushedAt.cpp" /> <ClCompile Include="..\dfg\DFGFlushFormat.cpp" /> + <ClCompile Include="..\dfg\DFGFrozenValue.cpp" /> <ClCompile Include="..\dfg\DFGFunctionWhitelist.cpp" /> <ClCompile Include="..\dfg\DFGGraph.cpp" /> <ClCompile Include="..\dfg\DFGGraphSafepoint.cpp" /> + <ClCompile Include="..\dfg\DFGHeapLocation.cpp" /> <ClCompile Include="..\dfg\DFGInPlaceAbstractState.cpp" /> + <ClCompile Include="..\dfg\DFGInsertOSRHintsForUpdate.cpp" /> <ClCompile Include="..\dfg\DFGIntegerCheckCombiningPhase.cpp" /> + <ClCompile Include="..\dfg\DFGIntegerRangeOptimizationPhase.cpp" /> <ClCompile Include="..\dfg\DFGInvalidationPointInjectionPhase.cpp" /> <ClCompile Include="..\dfg\DFGJITCode.cpp" /> <ClCompile Include="..\dfg\DFGJITCompiler.cpp" /> <ClCompile Include="..\dfg\DFGJITFinalizer.cpp" /> <ClCompile Include="..\dfg\DFGJumpReplacement.cpp" /> <ClCompile Include="..\dfg\DFGLazyJSValue.cpp" /> + <ClCompile Include="..\dfg\DFGLazyNode.cpp" /> <ClCompile Include="..\dfg\DFGLICMPhase.cpp" /> <ClCompile Include="..\dfg\DFGLivenessAnalysisPhase.cpp" /> <ClCompile Include="..\dfg\DFGLongLivedState.cpp" /> <ClCompile Include="..\dfg\DFGLoopPreHeaderCreationPhase.cpp" /> + <ClCompile Include="..\dfg\DFGMayExit.cpp" /> + <ClCompile Include="..\dfg\DFGMinifiedGraph.cpp" /> <ClCompile Include="..\dfg\DFGMinifiedNode.cpp" /> + <ClCompile Include="..\dfg\DFGMovHintRemovalPhase.cpp" /> + <ClCompile Include="..\dfg\DFGNaiveDominators.cpp" /> <ClCompile Include="..\dfg\DFGNaturalLoops.cpp" /> <ClCompile Include="..\dfg\DFGNode.cpp" /> <ClCompile Include="..\dfg\DFGNodeFlags.cpp" /> @@ -424,33 +449,47 @@ <ClCompile Include="..\dfg\DFGOSRExitCompiler32_64.cpp" /> <ClCompile Include="..\dfg\DFGOSRExitCompiler64.cpp" /> <ClCompile Include="..\dfg\DFGOSRExitCompilerCommon.cpp" /> + <ClCompile Include="..\dfg\DFGOSRExitFuzz.cpp" /> <ClCompile Include="..\dfg\DFGOSRExitJumpPlaceholder.cpp" /> <ClCompile Include="..\dfg\DFGOSRExitPreparation.cpp" /> + <ClCompile Include="..\dfg\DFGObjectAllocationSinkingPhase.cpp" /> + <ClCompile Include="..\dfg\DFGObjectMaterializationData.cpp" /> + <ClCompile Include="..\dfg\DFGPhantomInsertionPhase.cpp" /> <ClCompile Include="..\dfg\DFGPhase.cpp" /> + <ClCompile Include="..\dfg\DFGPhiChildren.cpp" /> <ClCompile Include="..\dfg\DFGPlan.cpp" /> + <ClCompile Include="..\dfg\DFGPrePostNumbering.cpp" /> <ClCompile Include="..\dfg\DFGPredictionInjectionPhase.cpp" /> <ClCompile Include="..\dfg\DFGPredictionPropagationPhase.cpp" /> - <ClCompile Include="..\dfg\DFGResurrectionForValidationPhase.cpp" /> + <ClCompile Include="..\dfg\DFGPromotedHeapLocation.cpp" /> + <ClCompile Include="..\dfg\DFGPureValue.cpp" /> + <ClCompile Include="..\dfg\DFGPutStackSinkingPhase.cpp" /> <ClCompile Include="..\dfg\DFGSafepoint.cpp" /> <ClCompile Include="..\dfg\DFGSpeculativeJIT.cpp" /> <ClCompile Include="..\dfg\DFGSpeculativeJIT32_64.cpp" /> <ClCompile Include="..\dfg\DFGSpeculativeJIT64.cpp" /> + <ClCompile Include="..\dfg\DFGSSACalculator.cpp" /> <ClCompile Include="..\dfg\DFGSSAConversionPhase.cpp" /> <ClCompile Include="..\dfg\DFGSSALoweringPhase.cpp" /> <ClCompile Include="..\dfg\DFGStackLayoutPhase.cpp" /> <ClCompile Include="..\dfg\DFGStaticExecutionCountEstimationPhase.cpp" /> - <ClCompile Include="..\dfg\DFGStoreBarrierElisionPhase.cpp" /> + <ClCompile Include="..\dfg\DFGStoreBarrierInsertionPhase.cpp" /> <ClCompile Include="..\dfg\DFGStrengthReductionPhase.cpp" /> + <ClCompile Include="..\dfg\DFGStructureAbstractValue.cpp" /> + <ClCompile Include="..\dfg\DFGStructureRegistrationPhase.cpp" /> <ClCompile Include="..\dfg\DFGThreadData.cpp" /> <ClCompile Include="..\dfg\DFGThunks.cpp" /> <ClCompile Include="..\dfg\DFGTierUpCheckInjectionPhase.cpp" /> <ClCompile Include="..\dfg\DFGToFTLDeferredCompilationCallback.cpp" /> <ClCompile Include="..\dfg\DFGToFTLForOSREntryDeferredCompilationCallback.cpp" /> + <ClCompile Include="..\dfg\DFGTransition.cpp" /> <ClCompile Include="..\dfg\DFGTypeCheckHoistingPhase.cpp" /> <ClCompile Include="..\dfg\DFGUnificationPhase.cpp" /> <ClCompile Include="..\dfg\DFGUseKind.cpp" /> <ClCompile Include="..\dfg\DFGValidate.cpp" /> <ClCompile Include="..\dfg\DFGValueSource.cpp" /> + <ClCompile Include="..\dfg\DFGValueStrength.cpp" /> + <ClCompile Include="..\dfg\DFGVarargsForwardingPhase.cpp" /> <ClCompile Include="..\dfg\DFGVariableAccessData.cpp" /> <ClCompile Include="..\dfg\DFGVariableAccessDataDump.cpp" /> <ClCompile Include="..\dfg\DFGVariableEvent.cpp" /> @@ -472,7 +511,9 @@ <ClCompile Include="..\ftl\FTLDWARFRegister.cpp" /> <ClCompile Include="..\ftl\FTLExitArgument.cpp" /> <ClCompile Include="..\ftl\FTLExitArgumentForOperand.cpp" /> + <ClCompile Include="..\ftl\FTLExitPropertyValue.cpp" /> <ClCompile Include="..\ftl\FTLExitThunkGenerator.cpp" /> + <ClCompile Include="..\ftl\FTLExitTimeObjectMaterialization.cpp" /> <ClCompile Include="..\ftl\FTLExitValue.cpp" /> <ClCompile Include="..\ftl\FTLFail.cpp" /> <ClCompile Include="..\ftl\FTLForOSREntryJITCode.cpp" /> @@ -481,12 +522,15 @@ <ClCompile Include="..\ftl\FTLJITCode.cpp" /> <ClCompile Include="..\ftl\FTLJITFinalizer.cpp" /> <ClCompile Include="..\ftl\FTLJSCall.cpp" /> + <ClCompile Include="..\ftl\FTLJSCallBase.cpp" /> + <ClCompile Include="..\ftl\FTLJSCallVarargs.cpp" /> <ClCompile Include="..\ftl\FTLLink.cpp" /> <ClCompile Include="..\ftl\FTLLocation.cpp" /> <ClCompile Include="..\ftl\FTLLowerDFGToLLVM.cpp" /> <ClCompile Include="..\ftl\FTLOSREntry.cpp" /> <ClCompile Include="..\ftl\FTLOSRExit.cpp" /> <ClCompile Include="..\ftl\FTLOSRExitCompiler.cpp" /> + <ClCompile Include="..\ftl\FTLOperations.cpp" /> <ClCompile Include="..\ftl\FTLOutput.cpp" /> <ClCompile Include="..\ftl\FTLRecoveryOpcode.cpp" /> <ClCompile Include="..\ftl\FTLRegisterAtOffset.cpp" /> @@ -499,7 +543,6 @@ <ClCompile Include="..\ftl\FTLUnwindInfo.cpp" /> <ClCompile Include="..\ftl\FTLValueFormat.cpp" /> <ClCompile Include="..\ftl\FTLValueRange.cpp" /> - <ClCompile Include="..\heap\BlockAllocator.cpp" /> <ClCompile Include="..\heap\CodeBlockSet.cpp" /> <ClCompile Include="..\heap\ConservativeRoots.cpp" /> <ClCompile Include="..\heap\CopiedSpace.cpp" /> @@ -516,6 +559,7 @@ <ClCompile Include="..\heap\Heap.cpp" /> <ClCompile Include="..\heap\HeapStatistics.cpp" /> <ClCompile Include="..\heap\HeapTimer.cpp" /> + <ClCompile Include="..\heap\HeapVerifier.cpp" /> <ClCompile Include="..\heap\IncrementalSweeper.cpp" /> <ClCompile Include="..\heap\JITStubRoutineSet.cpp" /> <ClCompile Include="..\heap\MachineStackMarker.cpp" /> @@ -524,7 +568,6 @@ <ClCompile Include="..\heap\MarkedSpace.cpp" /> <ClCompile Include="..\heap\MarkStack.cpp" /> <ClCompile Include="..\heap\SlotVisitor.cpp" /> - <ClCompile Include="..\heap\SuperRegion.cpp" /> <ClCompile Include="..\heap\Weak.cpp" /> <ClCompile Include="..\heap\WeakBlock.cpp" /> <ClCompile Include="..\heap\WeakHandleOwner.cpp" /> @@ -555,7 +598,6 @@ <ClCompile Include="..\inspector\agents\InspectorAgent.cpp" /> <ClCompile Include="..\inspector\agents\InspectorConsoleAgent.cpp" /> <ClCompile Include="..\inspector\agents\InspectorDebuggerAgent.cpp" /> - <ClCompile Include="..\inspector\agents\InspectorProfilerAgent.cpp" /> <ClCompile Include="..\inspector\agents\InspectorRuntimeAgent.cpp" /> <ClCompile Include="..\interpreter\AbstractPC.cpp" /> <ClCompile Include="..\interpreter\CallFrame.cpp" /> @@ -563,12 +605,13 @@ <ClCompile Include="..\interpreter\JSStack.cpp" /> <ClCompile Include="..\interpreter\ProtoCallFrame.cpp" /> <ClCompile Include="..\interpreter\StackVisitor.cpp" /> - <ClCompile Include="..\interpreter\VMInspector.cpp" /> <ClCompile Include="..\jit\AccessorCallJITStubRoutine.cpp" /> <ClCompile Include="..\jit\ArityCheckFailReturnThunks.cpp" /> <ClCompile Include="..\jit\AssemblyHelpers.cpp" /> - <ClCompile Include="..\jit\ClosureCallStubRoutine.cpp" /> + <ClCompile Include="..\jit\BinarySwitch.cpp" /> + <ClCompile Include="..\jit\ExecutableAllocationFuzz.cpp" /> <ClCompile Include="..\jit\ExecutableAllocator.cpp" /> + <ClCompile Include="..\jit\ExecutableAllocatorFixedVMPool.cpp" /> <ClCompile Include="..\jit\GCAwareJITStubRoutine.cpp" /> <ClCompile Include="..\jit\HostCallReturnValue.cpp" /> <ClCompile Include="..\jit\JIT.cpp" /> @@ -590,10 +633,14 @@ <ClCompile Include="..\jit\JITStubs.cpp" /> <ClCompile Include="..\jit\JITThunks.cpp" /> <ClCompile Include="..\jit\JITToDFGDeferredCompilationCallback.cpp" /> + <ClCompile Include="..\jit\SetupVarargsFrame.cpp" /> + <ClCompile Include="..\jit\PolymorphicCallStubRoutine.cpp" /> <ClCompile Include="..\jit\Reg.cpp" /> <ClCompile Include="..\jit\RegisterPreservationWrapperGenerator.cpp" /> + <ClCompile Include="..\jit\RegisterSet.cpp" /> <ClCompile Include="..\jit\Repatch.cpp" /> <ClCompile Include="..\jit\ScratchRegisterAllocator.cpp" /> + <ClCompile Include="..\jit\TempRegisterSet.cpp" /> <ClCompile Include="..\jit\ThunkGenerators.cpp" /> <ClCompile Include="..\llint\LLIntCLoop.cpp" /> <ClCompile Include="..\llint\LLIntData.cpp" /> @@ -631,20 +678,18 @@ <ClCompile Include="..\profiler\ProfilerOSRExitSite.cpp" /> <ClCompile Include="..\profiler\ProfilerProfiledBytecodes.cpp" /> <ClCompile Include="..\runtime\ArgList.cpp" /> - <ClCompile Include="..\runtime\Arguments.cpp" /> - <ClCompile Include="..\runtime\ArgumentsIteratorConstructor.cpp" /> - <ClCompile Include="..\runtime\ArgumentsIteratorPrototype.cpp" /> <ClCompile Include="..\runtime\ArrayBuffer.cpp" /> <ClCompile Include="..\runtime\ArrayBufferNeuteringWatchpoint.cpp" /> <ClCompile Include="..\runtime\ArrayBufferView.cpp" /> <ClCompile Include="..\runtime\ArrayConstructor.cpp" /> - <ClCompile Include="..\runtime\ArrayIteratorConstructor.cpp" /> <ClCompile Include="..\runtime\ArrayIteratorPrototype.cpp" /> <ClCompile Include="..\runtime\ArrayPrototype.cpp" /> + <ClCompile Include="..\runtime\BasicBlockLocation.cpp" /> <ClCompile Include="..\runtime\BooleanConstructor.cpp" /> <ClCompile Include="..\runtime\BooleanObject.cpp" /> <ClCompile Include="..\runtime\BooleanPrototype.cpp" /> <ClCompile Include="..\runtime\CallData.cpp" /> + <ClCompile Include="..\runtime\ClonedArguments.cpp" /> <ClCompile Include="..\runtime\CodeCache.cpp" /> <ClCompile Include="..\runtime\CodeSpecializationKind.cpp" /> <ClCompile Include="..\runtime\CommonIdentifiers.cpp" /> @@ -654,33 +699,44 @@ <ClCompile Include="..\runtime\Completion.cpp" /> <ClCompile Include="..\runtime\ConsoleClient.cpp" /> <ClCompile Include="..\runtime\ConsolePrototype.cpp" /> + <ClCompile Include="..\runtime\ConstantMode.cpp" /> <ClCompile Include="..\runtime\ConstructData.cpp" /> + <ClCompile Include="..\runtime\ControlFlowProfiler.cpp" /> <ClCompile Include="..\runtime\CustomGetterSetter.cpp" /> <ClCompile Include="..\runtime\DataView.cpp" /> <ClCompile Include="..\runtime\DateConstructor.cpp" /> <ClCompile Include="..\runtime\DateConversion.cpp" /> <ClCompile Include="..\runtime\DateInstance.cpp" /> <ClCompile Include="..\runtime\DatePrototype.cpp" /> + <ClCompile Include="..\runtime\DirectArguments.cpp" /> + <ClCompile Include="..\runtime\DirectArgumentsOffset.cpp" /> <ClCompile Include="..\runtime\DumpContext.cpp" /> <ClCompile Include="..\runtime\Error.cpp" /> <ClCompile Include="..\runtime\ErrorConstructor.cpp" /> <ClCompile Include="..\runtime\ErrorHandlingScope.cpp" /> <ClCompile Include="..\runtime\ErrorInstance.cpp" /> <ClCompile Include="..\runtime\ErrorPrototype.cpp" /> + <ClCompile Include="..\runtime\Exception.cpp" /> + <ClCompile Include="..\runtime\ExceptionFuzz.cpp" /> <ClCompile Include="..\runtime\ExceptionHelpers.cpp" /> <ClCompile Include="..\runtime\Executable.cpp" /> <ClCompile Include="..\runtime\FunctionConstructor.cpp" /> <ClCompile Include="..\runtime\FunctionExecutableDump.cpp" /> + <ClCompile Include="..\runtime\FunctionHasExecutedCache.cpp" /> <ClCompile Include="..\runtime\FunctionPrototype.cpp" /> + <ClCompile Include="..\runtime\FunctionRareData.cpp" /> <ClCompile Include="..\runtime\GetterSetter.cpp" /> <ClCompile Include="..\runtime\Identifier.cpp" /> <ClCompile Include="..\runtime\IndexingType.cpp" /> + <ClCompile Include="..\runtime\InferredValue.cpp" /> <ClCompile Include="..\runtime\InitializeThreading.cpp" /> <ClCompile Include="..\runtime\IntendedStructureChain.cpp" /> <ClCompile Include="..\runtime\InternalFunction.cpp" /> + <ClCompile Include="..\runtime\IntlObject.cpp" /> + <ClCompile Include="..\runtime\IteratorOperations.cpp" /> + <ClCompile Include="..\runtime\IteratorPrototype.cpp" /> <ClCompile Include="..\runtime\JSAPIValueWrapper.cpp" /> - <ClCompile Include="..\runtime\JSActivation.cpp" /> - <ClCompile Include="..\runtime\JSArgumentsIterator.cpp" /> + <ClCompile Include="..\runtime\JSLexicalEnvironment.cpp" /> <ClCompile Include="..\runtime\JSArray.cpp" /> <ClCompile Include="..\runtime\JSArrayIterator.cpp" /> <ClCompile Include="..\runtime\JSArrayBuffer.cpp" /> @@ -689,14 +745,18 @@ <ClCompile Include="..\runtime\JSArrayBufferView.cpp" /> <ClCompile Include="..\runtime\JSBoundFunction.cpp" /> <ClCompile Include="..\runtime\JSCJSValue.cpp" /> + <ClCompile Include="..\runtime\JSCallee.cpp" /> + <ClCompile Include="..\runtime\JSCatchScope.cpp" /> <ClCompile Include="..\runtime\JSCell.cpp" /> <ClCompile Include="..\runtime\JSConsole.cpp" /> <ClCompile Include="..\runtime\JSDataView.cpp" /> <ClCompile Include="..\runtime\JSDataViewPrototype.cpp" /> <ClCompile Include="..\runtime\JSDateMath.cpp" /> <ClCompile Include="..\runtime\JSFunction.cpp" /> + <ClCompile Include="..\runtime\JSFunctionNameScope.cpp" /> <ClCompile Include="..\runtime\JSGlobalObject.cpp" /> <ClCompile Include="..\runtime\JSGlobalObjectFunctions.cpp" /> + <ClCompile Include="..\runtime\JSJob.cpp" /> <ClCompile Include="..\runtime\JSLock.cpp" /> <ClCompile Include="..\runtime\JSMap.cpp" /> <ClCompile Include="..\runtime\JSMapIterator.cpp" /> @@ -707,39 +767,38 @@ <ClCompile Include="..\runtime\JSPromise.cpp" /> <ClCompile Include="..\runtime\JSPromiseConstructor.cpp" /> <ClCompile Include="..\runtime\JSPromiseDeferred.cpp" /> - <ClCompile Include="..\runtime\JSPromiseFunctions.cpp" /> - <ClCompile Include="..\runtime\JSPromiseReaction.cpp" /> <ClCompile Include="..\runtime\JSPromisePrototype.cpp" /> - <ClCompile Include="..\runtime\JSPropertyNameIterator.cpp" /> + <ClCompile Include="..\runtime\JSPropertyNameEnumerator.cpp" /> <ClCompile Include="..\runtime\JSProxy.cpp" /> <ClCompile Include="..\runtime\JSScope.cpp" /> <ClCompile Include="..\runtime\JSSegmentedVariableObject.cpp" /> <ClCompile Include="..\runtime\JSSet.cpp" /> <ClCompile Include="..\runtime\JSSetIterator.cpp" /> <ClCompile Include="..\runtime\JSString.cpp" /> + <ClCompile Include="..\runtime\JSStringIterator.cpp" /> <ClCompile Include="..\runtime\JSStringJoiner.cpp" /> <ClCompile Include="..\runtime\JSSymbolTableObject.cpp" /> + <ClCompile Include="..\runtime\JSTemplateRegistryKey.cpp" /> <ClCompile Include="..\runtime\JSTypedArrayConstructors.cpp" /> <ClCompile Include="..\runtime\JSTypedArrayPrototypes.cpp" /> <ClCompile Include="..\runtime\JSTypedArrays.cpp" /> - <ClCompile Include="..\runtime\JSVariableObject.cpp" /> + <ClCompile Include="..\runtime\JSEnvironmentRecord.cpp" /> <ClCompile Include="..\runtime\JSWeakMap.cpp" /> + <ClCompile Include="..\runtime\JSWeakSet.cpp" /> <ClCompile Include="..\runtime\JSWithScope.cpp" /> <ClCompile Include="..\runtime\JSWrapperObject.cpp" /> <ClCompile Include="..\runtime\LiteralParser.cpp" /> <ClCompile Include="..\runtime\Lookup.cpp" /> <ClCompile Include="..\runtime\MapConstructor.cpp" /> - <ClCompile Include="..\runtime\MapData.cpp" /> - <ClCompile Include="..\runtime\MapIteratorConstructor.cpp" /> <ClCompile Include="..\runtime\MapIteratorPrototype.cpp" /> <ClCompile Include="..\runtime\MapPrototype.cpp" /> + <ClCompile Include="..\runtime\MathCommon.cpp" /> <ClCompile Include="..\runtime\MathObject.cpp" /> <ClCompile Include="..\runtime\MemoryStatistics.cpp" /> - <ClCompile Include="..\runtime\NameConstructor.cpp" /> - <ClCompile Include="..\runtime\NameInstance.cpp" /> - <ClCompile Include="..\runtime\NamePrototype.cpp" /> <ClCompile Include="..\runtime\NativeErrorConstructor.cpp" /> <ClCompile Include="..\runtime\NativeErrorPrototype.cpp" /> + <ClCompile Include="..\runtime\NullGetterFunction.cpp" /> + <ClCompile Include="..\runtime\NullSetterFunction.cpp" /> <ClCompile Include="..\runtime\NumberConstructor.cpp" /> <ClCompile Include="..\runtime\NumberObject.cpp" /> <ClCompile Include="..\runtime\NumberPrototype.cpp" /> @@ -748,7 +807,6 @@ <ClCompile Include="..\runtime\Operations.cpp" /> <ClCompile Include="..\runtime\Options.cpp" /> <ClCompile Include="..\runtime\PropertyDescriptor.cpp" /> - <ClCompile Include="..\runtime\PropertyNameArray.cpp" /> <ClCompile Include="..\runtime\PropertySlot.cpp" /> <ClCompile Include="..\runtime\PropertyTable.cpp" /> <ClCompile Include="..\runtime\PrototypeMap.cpp" /> @@ -759,49 +817,71 @@ <ClCompile Include="..\runtime\RegExpMatchesArray.cpp" /> <ClCompile Include="..\runtime\RegExpObject.cpp" /> <ClCompile Include="..\runtime\RegExpPrototype.cpp" /> + <ClCompile Include="..\runtime\RuntimeType.cpp" /> <ClCompile Include="..\runtime\SamplingCounter.cpp" /> <ClCompile Include="..\runtime\SetConstructor.cpp" /> - <ClCompile Include="..\runtime\SetIteratorConstructor.cpp" /> <ClCompile Include="..\runtime\SetIteratorPrototype.cpp" /> <ClCompile Include="..\runtime\SetPrototype.cpp" /> + <ClCompile Include="..\runtime\ScopeOffset.cpp" /> + <ClCompile Include="..\runtime\ScopedArguments.cpp" /> + <ClCompile Include="..\runtime\ScopedArgumentsTable.cpp" /> <ClCompile Include="..\runtime\SimpleTypedArrayController.cpp" /> <ClCompile Include="..\runtime\SmallStrings.cpp" /> <ClCompile Include="..\runtime\SparseArrayValueMap.cpp" /> <ClCompile Include="..\runtime\StrictEvalActivation.cpp" /> <ClCompile Include="..\runtime\StringConstructor.cpp" /> <ClCompile Include="..\runtime\StringObject.cpp" /> + <ClCompile Include="..\runtime\StringIteratorPrototype.cpp" /> <ClCompile Include="..\runtime\StringPrototype.cpp" /> <ClCompile Include="..\runtime\StringRecursionChecker.cpp" /> <ClCompile Include="..\runtime\Structure.cpp" /> <ClCompile Include="..\runtime\StructureChain.cpp" /> <ClCompile Include="..\runtime\StructureIDTable.cpp" /> <ClCompile Include="..\runtime\StructureRareData.cpp" /> + <ClCompile Include="..\runtime\Symbol.cpp" /> + <ClCompile Include="..\runtime\SymbolConstructor.cpp" /> + <ClCompile Include="..\runtime\SymbolObject.cpp" /> + <ClCompile Include="..\runtime\SymbolPrototype.cpp" /> <ClCompile Include="..\runtime\SymbolTable.cpp" /> + <ClCompile Include="..\runtime\TemplateRegistry.cpp" /> <ClCompile Include="..\runtime\TestRunnerUtils.cpp" /> <ClCompile Include="..\runtime\TypedArrayController.cpp" /> <ClCompile Include="..\runtime\TypedArrayType.cpp" /> + <ClCompile Include="..\runtime\TypeofType.cpp" /> + <ClCompile Include="..\runtime\TypeLocationCache.cpp" /> + <ClCompile Include="..\runtime\TypeProfiler.cpp" /> + <ClCompile Include="..\runtime\TypeProfilerLog.cpp" /> + <ClCompile Include="..\runtime\TypeSet.cpp" /> <ClCompile Include="..\runtime\VM.cpp" /> <ClCompile Include="..\runtime\VMEntryScope.cpp" /> + <ClCompile Include="..\runtime\VarOffset.cpp" /> <ClCompile Include="..\runtime\Watchdog.cpp" /> <ClCompile Include="..\runtime\WatchdogNone.cpp" /> <ClCompile Include="..\runtime\WeakMapConstructor.cpp" /> <ClCompile Include="..\runtime\WeakMapData.cpp" /> <ClCompile Include="..\runtime\WeakMapPrototype.cpp" /> + <ClCompile Include="..\runtime\WeakSetConstructor.cpp" /> + <ClCompile Include="..\runtime\WeakSetPrototype.cpp" /> <ClCompile Include="..\tools\CodeProfile.cpp" /> <ClCompile Include="..\tools\CodeProfiling.cpp" /> + <ClCompile Include="..\tools\FunctionOverrides.cpp" /> + <ClCompile Include="..\tools\JSDollarVM.cpp" /> + <ClCompile Include="..\tools\JSDollarVMPrototype.cpp" /> <ClCompile Include="..\yarr\RegularExpression.cpp" /> <ClCompile Include="..\yarr\YarrCanonicalizeUCS2.cpp" /> <ClCompile Include="..\yarr\YarrInterpreter.cpp" /> <ClCompile Include="..\yarr\YarrJIT.cpp" /> <ClCompile Include="..\yarr\YarrPattern.cpp" /> <ClCompile Include="..\yarr\YarrSyntaxChecker.cpp" /> - <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSBackendDispatchers.cpp" /> - <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSFrontendDispatchers.cpp" /> - <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSTypeBuilders.cpp" /> + <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorBackendDispatchers.cpp" /> + <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorFrontendDispatchers.cpp" /> + <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorProtocolObjects.cpp" /> <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSCBuiltins.cpp" /> + <ClCompile Include="JavaScriptCoreDLL.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ArrayConstructor.lut.h" /> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ArrayIteratorPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ArrayPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\BooleanPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\DateConstructor.lut.h" /> @@ -809,9 +889,9 @@ <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ErrorPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\HeaderDetection.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InjectedScriptSource.h" /> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSBackendDispatchers.h" /> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSFrontendDispatchers.h" /> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSTypeBuilders.h" /> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorBackendDispatchers.h" /> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorFrontendDispatchers.h" /> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorProtocolObjects.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSDataViewPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSGlobalObject.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSONObject.lut.h" /> @@ -819,15 +899,14 @@ <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSPromisePrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\KeywordLookup.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\Lexer.lut.h" /> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\NamePrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\NumberConstructor.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\NumberPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ObjectConstructor.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\RegExpConstructor.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\RegExpJitTables.h" /> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\RegExpObject.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\RegExpPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\StringConstructor.lut.h" /> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\SymbolPrototype.lut.h" /> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSCBuiltins.h" /> </ItemGroup> <ItemGroup> @@ -838,6 +917,7 @@ <ClInclude Include="..\API\JSAPIWrapperObject.h" /> <ClInclude Include="..\API\JSBase.h" /> <ClInclude Include="..\API\JSBasePrivate.h" /> + <ClInclude Include="..\API\JSCTestRunnerUtils.h" /> <ClInclude Include="..\API\JSCallbackConstructor.h" /> <ClInclude Include="..\API\JSCallbackFunction.h" /> <ClInclude Include="..\API\JSCallbackObject.h" /> @@ -883,11 +963,15 @@ <ClInclude Include="..\bytecode\ArrayProfile.h" /> <ClInclude Include="..\bytecode\ByValInfo.h" /> <ClInclude Include="..\bytecode\BytecodeBasicBlock.h" /> + <ClInclude Include="..\bytecode\BytecodeKills.h" /> + <ClInclude Include="..\bytecode\BytecodeIntrinsicRegistry.h" /> <ClInclude Include="..\bytecode\BytecodeLivenessAnalysis.h" /> <ClInclude Include="..\bytecode\BytecodeUseDef.h" /> + <ClInclude Include="..\bytecode\CallEdge.h" /> <ClInclude Include="..\bytecode\CallLinkInfo.h" /> <ClInclude Include="..\bytecode\CallLinkStatus.h" /> <ClInclude Include="..\bytecode\CallReturnOffsetToBytecodeOffset.h" /> + <ClInclude Include="..\bytecode\CallVariant.h" /> <ClInclude Include="..\bytecode\CodeBlock.h" /> <ClInclude Include="..\bytecode\CodeBlockHash.h" /> <ClInclude Include="..\bytecode\CodeBlockJettisoningWatchpoint.h" /> @@ -895,8 +979,11 @@ <ClInclude Include="..\bytecode\CodeOrigin.h" /> <ClInclude Include="..\bytecode\CodeType.h" /> <ClInclude Include="..\bytecode\Comment.h" /> + <ClInclude Include="..\bytecode\ComplexGetStatus.h" /> + <ClInclude Include="..\bytecode\ConstantStructureCheck.h" /> <ClInclude Include="..\bytecode\DataFormat.h" /> <ClInclude Include="..\bytecode\DeferredCompilationCallback.h" /> + <ClInclude Include="..\bytecode\DeferredSourceDump.h" /> <ClInclude Include="..\bytecode\DFGExitProfile.h" /> <ClInclude Include="..\bytecode\EvalCodeCache.h" /> <ClInclude Include="..\bytecode\ExecutionCounter.h" /> @@ -915,7 +1002,6 @@ <ClInclude Include="..\bytecode\Operands.h" /> <ClInclude Include="..\bytecode\PolymorphicGetByIdList.h" /> <ClInclude Include="..\bytecode\PolymorphicPutByIdList.h" /> - <ClInclude Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.h" /> <ClInclude Include="..\bytecode\PreciseJumpTargets.h" /> <ClInclude Include="..\bytecode\PutByIdStatus.h" /> <ClInclude Include="..\bytecode\PutByIdVariant.h" /> @@ -927,11 +1013,14 @@ <ClInclude Include="..\bytecode\StructureSet.h" /> <ClInclude Include="..\bytecode\StructureStubClearingWatchpoint.h" /> <ClInclude Include="..\bytecode\StructureStubInfo.h" /> + <ClInclude Include="..\bytecode\ToThisStatus.h" /> + <ClInclude Include="..\bytecode\TrackedReferences.h" /> + <ClInclude Include="..\bytecode\TypeLocation.h" /> <ClInclude Include="..\bytecode\UnlinkedCodeBlock.h" /> <ClInclude Include="..\bytecode\UnlinkedInstructionStream.h" /> <ClInclude Include="..\bytecode\ValueProfile.h" /> <ClInclude Include="..\bytecode\ValueRecovery.h" /> - <ClInclude Include="..\bytecode\VariableWatchpointSet.h" /> + <ClInclude Include="..\bytecode\VariableWriteFireDetail.h" /> <ClInclude Include="..\bytecode\VirtualRegister.h" /> <ClInclude Include="..\bytecode\Watchpoint.h" /> <ClInclude Include="..\bytecompiler\BytecodeGenerator.h" /> @@ -941,9 +1030,10 @@ <ClInclude Include="..\config.h" /> <ClInclude Include="..\debugger\Breakpoint.h" /> <ClInclude Include="..\debugger\Debugger.h" /> - <ClInclude Include="..\debugger\DebuggerActivation.h" /> <ClInclude Include="..\debugger\DebuggerCallFrame.h" /> + <ClInclude Include="..\debugger\DebuggerEvalEnabler.h" /> <ClInclude Include="..\debugger\DebuggerPrimitives.h" /> + <ClInclude Include="..\debugger\DebuggerScope.h" /> <ClInclude Include="..\dfg\DFGAbstractHeap.h" /> <ClInclude Include="..\dfg\DFGAbstractInterpreter.h" /> <ClInclude Include="..\dfg\DFGAbstractInterpreterInlines.h" /> @@ -952,83 +1042,105 @@ <ClInclude Include="..\dfg\DFGAllocator.h" /> <ClInclude Include="..\dfg\DFGAnalysis.h" /> <ClInclude Include="..\dfg\DFGArgumentPosition.h" /> - <ClInclude Include="..\dfg\DFGArgumentsSimplificationPhase.h" /> + <ClInclude Include="..\dfg\DFGArgumentsEliminationPhase.h" /> + <ClInclude Include="..\dfg\DFGArgumentsUtilities.h" /> <ClInclude Include="..\dfg\DFGArrayifySlowPathGenerator.h" /> <ClInclude Include="..\dfg\DFGArithMode.h" /> <ClInclude Include="..\dfg\DFGArrayMode.h" /> <ClInclude Include="..\dfg\DFGAtTailAbstractState.h" /> <ClInclude Include="..\dfg\DFGAvailability.h" /> + <ClInclude Include="..\dfg\DFGAvailabilityMap.h" /> <ClInclude Include="..\dfg\DFGBackwardsPropagationPhase.h" /> <ClInclude Include="..\dfg\DFGBasicBlock.h" /> <ClInclude Include="..\dfg\DFGBasicBlockInlines.h" /> - <ClInclude Include="..\dfg\DFGBinarySwitch.h" /> <ClInclude Include="..\dfg\DFGBlockInsertionSet.h" /> + <ClInclude Include="..\dfg\DFGBlockMap.h" /> + <ClInclude Include="..\dfg\DFGBlockMapInlines.h" /> + <ClInclude Include="..\dfg\DFGBlockWorklist.h" /> + <ClInclude Include="..\dfg\DFGBlockSet.h" /> + <ClInclude Include="..\dfg\DFGBlockSetInlines.h" /> <ClInclude Include="..\dfg\DFGBranchDirection.h" /> <ClInclude Include="..\dfg\DFGByteCodeParser.h" /> <ClInclude Include="..\dfg\DFGCallArrayAllocatorSlowPathGenerator.h" /> + <ClInclude Include="..\dfg\DFGCallCreateDirectArgumentsSlowPathGenerator.h" /> <ClInclude Include="..\dfg\DFGCapabilities.h" /> <ClInclude Include="..\dfg\DFGCCallHelpers.h" /> <ClInclude Include="..\dfg\DFGCFAPhase.h" /> <ClInclude Include="..\dfg\DFGCFGSimplificationPhase.h" /> + <ClInclude Include="..\dfg\DFGCleanUpPhase.h" /> <ClInclude Include="..\dfg\DFGClobberize.h" /> <ClInclude Include="..\dfg\DFGClobberSet.h" /> + <ClInclude Include="..\dfg\DFGCombinedLiveness.h" /> <ClInclude Include="..\dfg\DFGCommon.h" /> <ClInclude Include="..\dfg\DFGCommonData.h" /> <ClInclude Include="..\dfg\DFGCompilationKey.h" /> <ClInclude Include="..\dfg\DFGCompilationMode.h" /> <ClInclude Include="..\dfg\DFGConstantFoldingPhase.h" /> + <ClInclude Include="..\dfg\DFGConstantHoistingPhase.h" /> <ClInclude Include="..\dfg\DFGCPSRethreadingPhase.h" /> <ClInclude Include="..\dfg\DFGCriticalEdgeBreakingPhase.h" /> <ClInclude Include="..\dfg\DFGCSEPhase.h" /> <ClInclude Include="..\dfg\DFGDCEPhase.h" /> <ClInclude Include="..\dfg\DFGDesiredIdentifiers.h" /> - <ClInclude Include="..\dfg\DFGDesiredStructureChains.h" /> <ClInclude Include="..\dfg\DFGDesiredTransitions.h" /> <ClInclude Include="..\dfg\DFGDesiredWatchpoints.h" /> <ClInclude Include="..\dfg\DFGDesiredWeakReferences.h" /> <ClInclude Include="..\dfg\DFGDesiredWriteBarriers.h" /> <ClInclude Include="..\dfg\DFGDisassembler.h" /> + <ClInclude Include="..\dfg\DFGDoesGC.h" /> <ClInclude Include="..\dfg\DFGDominators.h" /> <ClInclude Include="..\dfg\DFGDoubleFormatState.h" /> <ClInclude Include="..\dfg\DFGDriver.h" /> <ClInclude Include="..\dfg\DFGEdge.h" /> <ClInclude Include="..\dfg\DFGEdgeDominates.h" /> <ClInclude Include="..\dfg\DFGEdgeUsesStructure.h" /> + <ClInclude Include="..\dfg\DFGEpoch.h" /> <ClInclude Include="..\dfg\DFGFailedFinalizer.h" /> <ClInclude Include="..\dfg\DFGFiltrationResult.h" /> <ClInclude Include="..\dfg\DFGFinalizer.h" /> <ClInclude Include="..\dfg\DFGFixupPhase.h" /> <ClInclude Include="..\dfg\DFGFlushedAt.h" /> <ClInclude Include="..\dfg\DFGFlushFormat.h" /> + <ClInclude Include="..\dfg\DFGForAllKills.h" /> <ClInclude Include="..\dfg\DFGFPRInfo.h" /> + <ClInclude Include="..\dfg\DFGFrozenValue.h" /> <ClInclude Include="..\dfg\DFGFunctionWhitelist.h" /> <ClInclude Include="..\dfg\DFGGenerationInfo.h" /> <ClInclude Include="..\dfg\DFGGPRInfo.h" /> <ClInclude Include="..\dfg\DFGGraph.h" /> <ClInclude Include="..\dfg\DFGGraphSafepoint.h" /> + <ClInclude Include="..\dfg\DFGHeapLocation.h" /> <ClInclude Include="..\dfg\DFGInPlaceAbstractState.h" /> + <ClInclude Include="..\dfg\DFGInsertOSRHintsForUpdate.h" /> <ClInclude Include="..\dfg\DFGInsertionSet.h" /> <ClInclude Include="..\dfg\DFGIntegerCheckCombiningPhase.h" /> + <ClInclude Include="..\dfg\DFGIntegerRangeOptimizationPhase.h" /> <ClInclude Include="..\dfg\DFGInvalidationPointInjectionPhase.h" /> <ClInclude Include="..\dfg\DFGJITCode.h" /> <ClInclude Include="..\dfg\DFGJITCompiler.h" /> <ClInclude Include="..\dfg\DFGJITFinalizer.h" /> <ClInclude Include="..\dfg\DFGJumpReplacement.h" /> <ClInclude Include="..\dfg\DFGLazyJSValue.h" /> + <ClInclude Include="..\dfg\DFGLazyNode.h" /> <ClInclude Include="..\dfg\DFGLICMPhase.h" /> <ClInclude Include="..\dfg\DFGLivenessAnalysisPhase.h" /> <ClInclude Include="..\dfg\DFGLongLivedState.h" /> <ClInclude Include="..\dfg\DFGLoopPreHeaderCreationPhase.h" /> + <ClInclude Include="..\dfg\DFGMayExit.h" /> <ClInclude Include="..\dfg\DFGMergeMode.h" /> <ClInclude Include="..\dfg\DFGMinifiedGraph.h" /> <ClInclude Include="..\dfg\DFGMinifiedID.h" /> <ClInclude Include="..\dfg\DFGMinifiedNode.h" /> + <ClInclude Include="..\dfg\DFGMovHintRemovalPhase.h" /> + <ClInclude Include="..\dfg\DFGNaiveDominators.h" /> <ClInclude Include="..\dfg\DFGNaturalLoops.h" /> <ClInclude Include="..\dfg\DFGNode.h" /> <ClInclude Include="..\dfg\DFGNodeAllocator.h" /> <ClInclude Include="..\dfg\DFGNodeFlags.h" /> <ClInclude Include="..\dfg\DFGNodeOrigin.h" /> <ClInclude Include="..\dfg\DFGNodeType.h" /> + <ClInclude Include="..\dfg\DFGObjectAllocationSinkingPhase.h" /> + <ClInclude Include="..\dfg\DFGObjectMaterializationData.h" /> <ClInclude Include="..\dfg\DFGOperations.h" /> <ClInclude Include="..\dfg\DFGOSRAvailabilityAnalysisPhase.h" /> <ClInclude Include="..\dfg\DFGOSREntry.h" /> @@ -1038,15 +1150,23 @@ <ClInclude Include="..\dfg\DFGOSRExitCompilationInfo.h" /> <ClInclude Include="..\dfg\DFGOSRExitCompiler.h" /> <ClInclude Include="..\dfg\DFGOSRExitCompilerCommon.h" /> + <ClInclude Include="..\dfg\DFGOSRExitFuzz.h" /> <ClInclude Include="..\dfg\DFGOSRExitJumpPlaceholder.h" /> <ClInclude Include="..\dfg\DFGOSRExitPreparation.h" /> + <ClInclude Include="..\dfg\DFGPhantomInsertionPhase.h" /> <ClInclude Include="..\dfg\DFGPhase.h" /> + <ClInclude Include="..\dfg\DFGPhiChildren.h" /> <ClInclude Include="..\dfg\DFGPlan.h" /> + <ClInclude Include="..\dfg\DFGPrePostNumbering.h" /> + <ClInclude Include="..\dfg\DFGPreciseLocalClobberize.h" /> <ClInclude Include="..\dfg\DFGPredictionInjectionPhase.h" /> <ClInclude Include="..\dfg\DFGPredictionPropagationPhase.h" /> + <ClInclude Include="..\dfg\DFGPromoteHeapAccess.h" /> + <ClInclude Include="..\dfg\DFGPromotedHeapLocation.h" /> + <ClInclude Include="..\dfg\DFGPureValue.h" /> + <ClInclude Include="..\dfg\DFGPutStackSinkingPhase.h" /> <ClInclude Include="..\dfg\DFGRegisterBank.h" /> <ClInclude Include="..\dfg\DFGRegisterSet.h" /> - <ClInclude Include="..\dfg\DFGResurrectionForValidationPhase.h" /> <ClInclude Include="..\dfg\DFGSafeToExecute.h" /> <ClInclude Include="..\dfg\DFGSafepoint.h" /> <ClInclude Include="..\dfg\DFGSaneStringGetByValSlowPathGenerator.h" /> @@ -1056,24 +1176,29 @@ <ClInclude Include="..\dfg\DFGSilentRegisterSavePlan.h" /> <ClInclude Include="..\dfg\DFGSlowPathGenerator.h" /> <ClInclude Include="..\dfg\DFGSpeculativeJIT.h" /> + <ClInclude Include="..\dfg\DFGSSACalculator.h" /> <ClInclude Include="..\dfg\DFGSSAConversionPhase.h" /> <ClInclude Include="..\dfg\DFGSSALoweringPhase.h" /> <ClInclude Include="..\dfg\DFGStackLayoutPhase.h" /> <ClInclude Include="..\dfg\DFGStaticExecutionCountEstimationPhase.h" /> - <ClInclude Include="..\dfg\DFGStoreBarrierElisionPhase.h" /> + <ClInclude Include="..\dfg\DFGStoreBarrierInsertionPhase.h" /> <ClInclude Include="..\dfg\DFGStrengthReductionPhase.h" /> <ClInclude Include="..\dfg\DFGStructureAbstractValue.h" /> + <ClInclude Include="..\dfg\DFGStructureClobberState.h" /> + <ClInclude Include="..\dfg\DFGStructureRegistrationPhase.h" /> <ClInclude Include="..\dfg\DFGThreadData.h" /> <ClInclude Include="..\dfg\DFGThunks.h" /> <ClInclude Include="..\dfg\DFGTierUpCheckInjectionPhase.h" /> <ClInclude Include="..\dfg\DFGToFTLDeferredCompilationCallback.h" /> <ClInclude Include="..\dfg\DFGToFTLForOSREntryDeferredCompilationCallback.h" /> + <ClInclude Include="..\dfg\DFGTransition.h" /> <ClInclude Include="..\dfg\DFGTypeCheckHoistingPhase.h" /> <ClInclude Include="..\dfg\DFGUnificationPhase.h" /> <ClInclude Include="..\dfg\DFGUseKind.h" /> <ClInclude Include="..\dfg\DFGValidate.h" /> - <ClInclude Include="..\dfg\DFGValueRecoveryOverride.h" /> <ClInclude Include="..\dfg\DFGValueSource.h" /> + <ClInclude Include="..\dfg\DFGValueStrength.h" /> + <ClInclude Include="..\dfg\DFGVarargsForwardingPhase.h" /> <ClInclude Include="..\dfg\DFGVariableAccessData.h" /> <ClInclude Include="..\dfg\DFGVariableAccessDataDump.h" /> <ClInclude Include="..\dfg\DFGVariableEvent.h" /> @@ -1098,7 +1223,9 @@ <ClInclude Include="..\ftl\FTLExitArgument.h" /> <ClInclude Include="..\ftl\FTLExitArgumentForOperand.h" /> <ClInclude Include="..\ftl\FTLExitArgumentList.h" /> + <ClInclude Include="..\ftl\FTLExitPropertyValue.h" /> <ClInclude Include="..\ftl\FTLExitThunkGenerator.h" /> + <ClInclude Include="..\ftl\FTLExitTimeObjectMaterialization.h" /> <ClInclude Include="..\ftl\FTLExitValue.h" /> <ClInclude Include="..\ftl\FTLFail.h" /> <ClInclude Include="..\ftl\FTLFormattedValue.h" /> @@ -1110,6 +1237,8 @@ <ClInclude Include="..\ftl\FTLJITCode.h" /> <ClInclude Include="..\ftl\FTLJITFinalizer.h" /> <ClInclude Include="..\ftl\FTLJSCall.h" /> + <ClInclude Include="..\ftl\FTLJSCallBase.h" /> + <ClInclude Include="..\ftl\FTLJSCallVarargs.h" /> <ClInclude Include="..\ftl\FTLLink.h" /> <ClInclude Include="..\ftl\FTLLocation.h" /> <ClInclude Include="..\ftl\FTLLowerDFGToLLVM.h" /> @@ -1118,6 +1247,7 @@ <ClInclude Include="..\ftl\FTLOSRExit.h" /> <ClInclude Include="..\ftl\FTLOSRExitCompilationInfo.h" /> <ClInclude Include="..\ftl\FTLOSRExitCompiler.h" /> + <ClInclude Include="..\ftl\FTLOperations.h" /> <ClInclude Include="..\ftl\FTLOutput.h" /> <ClInclude Include="..\ftl\FTLRecoveryOpcode.h" /> <ClInclude Include="..\ftl\FTLRegisterAtOffset.h" /> @@ -1135,7 +1265,6 @@ <ClInclude Include="..\ftl\FTLValueRange.h" /> <ClInclude Include="..\ftl\FTLWeight.h" /> <ClInclude Include="..\ftl\FTLWeightedTarget.h" /> - <ClInclude Include="..\heap\BlockAllocator.h" /> <ClInclude Include="..\heap\CodeBlockSet.h" /> <ClInclude Include="..\heap\ConservativeRoots.h" /> <ClInclude Include="..\heap\CopiedAllocator.h" /> @@ -1149,7 +1278,6 @@ <ClInclude Include="..\heap\CopyWorkList.h" /> <ClInclude Include="..\heap\CopyWriteBarrier.h" /> <ClInclude Include="..\heap\DeferGC.h" /> - <ClInclude Include="..\heap\DelayedReleaseScope.h" /> <ClInclude Include="..\heap\EdenGCActivityCallback.h" /> <ClInclude Include="..\heap\FullGCActivityCallback.h" /> <ClInclude Include="..\heap\GCActivityCallback.h" /> @@ -1166,12 +1294,12 @@ <ClInclude Include="..\heap\HandleStack.h" /> <ClInclude Include="..\heap\HandleTypes.h" /> <ClInclude Include="..\heap\Heap.h" /> - <ClInclude Include="..\heap\HeapBlock.h" /> <ClInclude Include="..\heap\HeapInlines.h" /> <ClInclude Include="..\heap\HeapOperation.h" /> <ClInclude Include="..\heap\HeapRootVisitor.h" /> <ClInclude Include="..\heap\HeapStatistics.h" /> <ClInclude Include="..\heap\HeapTimer.h" /> + <ClInclude Include="..\heap\HeapVerifier.h" /> <ClInclude Include="..\heap\IncrementalSweeper.h" /> <ClInclude Include="..\heap\JITStubRoutineSet.h" /> <ClInclude Include="..\heap\ListableHandler.h" /> @@ -1184,12 +1312,10 @@ <ClInclude Include="..\heap\MarkedSpace.h" /> <ClInclude Include="..\heap\MarkStack.h" /> <ClInclude Include="..\heap\RecursiveAllocationScope.h" /> - <ClInclude Include="..\heap\Region.h" /> <ClInclude Include="..\heap\SlotVisitor.h" /> <ClInclude Include="..\heap\SlotVisitorInlines.h" /> <ClInclude Include="..\heap\Strong.h" /> <ClInclude Include="..\heap\StrongInlines.h" /> - <ClInclude Include="..\heap\SuperRegion.h" /> <ClInclude Include="..\heap\TinyBloomFilter.h" /> <ClInclude Include="..\heap\UnconditionalFinalizer.h" /> <ClInclude Include="..\heap\Weak.h" /> @@ -1214,7 +1340,6 @@ <ClInclude Include="..\inspector\InspectorBackendDispatcher.h" /> <ClInclude Include="..\inspector\InspectorEnvironment.h" /> <ClInclude Include="..\inspector\InspectorFrontendChannel.h" /> - <ClInclude Include="..\inspector\InspectorTypeBuilder.h" /> <ClInclude Include="..\inspector\InspectorValues.h" /> <ClInclude Include="..\inspector\JSInjectedScriptHost.h" /> <ClInclude Include="..\inspector\JSInjectedScriptHostPrototype.h" /> @@ -1231,26 +1356,26 @@ <ClInclude Include="..\inspector\agents\InspectorAgent.h" /> <ClInclude Include="..\inspector\agents\InspectorConsoleAgent.h" /> <ClInclude Include="..\inspector\agents\InspectorDebuggerAgent.h" /> - <ClInclude Include="..\inspector\agents\InspectorProfilerAgent.h" /> <ClInclude Include="..\inspector\agents\InspectorRuntimeAgent.h" /> <ClInclude Include="..\interpreter\AbstractPC.h" /> <ClInclude Include="..\interpreter\CachedCall.h" /> <ClInclude Include="..\interpreter\CallFrame.h" /> <ClInclude Include="..\interpreter\CallFrameInlines.h" /> <ClInclude Include="..\interpreter\CallFrameClosure.h" /> + <ClInclude Include="..\interpreter\VMEntryRecord.h" /> <ClInclude Include="..\interpreter\Interpreter.h" /> <ClInclude Include="..\interpreter\JSStack.h" /> <ClInclude Include="..\interpreter\JSStackInlines.h" /> <ClInclude Include="..\interpreter\ProtoCallFrame.h" /> <ClInclude Include="..\interpreter\Register.h" /> <ClInclude Include="..\interpreter\StackVisitor.h" /> - <ClInclude Include="..\interpreter\VMInspector.h" /> <ClInclude Include="..\jit\AccessorCallJITStubRoutine.h" /> <ClInclude Include="..\jit\ArityCheckFailReturnThunks.h" /> <ClInclude Include="..\jit\AssemblyHelpers.h" /> + <ClInclude Include="..\jit\BinarySwitch.h" /> <ClInclude Include="..\jit\CCallHelpers.h" /> - <ClInclude Include="..\jit\ClosureCallStubRoutine.h" /> <ClInclude Include="..\jit\CompactJITCodeMap.h" /> + <ClInclude Include="..\jit\ExecutableAllocationFuzz.h" /> <ClInclude Include="..\jit\ExecutableAllocator.h" /> <ClInclude Include="..\jit\FPRInfo.h" /> <ClInclude Include="..\jit\GCAwareJITStubRoutine.h" /> @@ -1273,14 +1398,14 @@ <ClInclude Include="..\jit\JITToDFGDeferredCompilationCallback.h" /> <ClInclude Include="..\jit\JITWriteBarrier.h" /> <ClInclude Include="..\jit\JSInterfaceJIT.h" /> - <ClCompile Include="..\jit\RegisterSet.cpp" /> + <ClInclude Include="..\jit\SetupVarargsFrame.h" /> + <ClInclude Include="..\jit\PolymorphicCallStubRoutine.h" /> <ClInclude Include="..\jit\Reg.h" /> <ClInclude Include="..\jit\RegisterPreservationWrapperGenerator.h" /> <ClInclude Include="..\jit\RegisterSet.h" /> <ClInclude Include="..\jit\Repatch.h" /> <ClInclude Include="..\jit\ScratchRegisterAllocator.h" /> <ClInclude Include="..\jit\SpecializedThunkJIT.h" /> - <ClCompile Include="..\jit\TempRegisterSet.cpp" /> <ClInclude Include="..\jit\TempRegisterSet.h" /> <ClInclude Include="..\jit\ThunkGenerator.h" /> <ClInclude Include="..\jit\ThunkGenerators.h" /> @@ -1302,7 +1427,6 @@ <ClInclude Include="..\parser\ASTBuilder.h" /> <ClInclude Include="..\parser\Lexer.h" /> <ClInclude Include="..\parser\NodeConstructors.h" /> - <ClInclude Include="..\parser\NodeInfo.h" /> <ClInclude Include="..\parser\Nodes.h" /> <ClInclude Include="..\parser\Parser.h" /> <ClInclude Include="..\parser\ParserArena.h" /> @@ -1334,16 +1458,16 @@ <ClInclude Include="..\profiler\ProfilerOSRExitSite.h" /> <ClInclude Include="..\profiler\ProfilerProfiledBytecodes.h" /> <ClInclude Include="..\runtime\ArgList.h" /> - <ClInclude Include="..\runtime\Arguments.h" /> + <ClInclude Include="..\runtime\ArgumentsMode.h" /> <ClInclude Include="..\runtime\ArrayBuffer.h" /> <ClInclude Include="..\runtime\ArrayBufferNeuteringWatchpoint.h" /> <ClInclude Include="..\runtime\ArrayBufferView.h" /> <ClInclude Include="..\runtime\ArrayConstructor.h" /> <ClInclude Include="..\runtime\ArrayConventions.h" /> - <ClInclude Include="..\runtime\ArrayIteratorConstructor.h" /> <ClInclude Include="..\runtime\ArrayIteratorPrototype.h" /> <ClInclude Include="..\runtime\ArrayPrototype.h" /> <ClInclude Include="..\runtime\ArrayStorage.h" /> + <ClInclude Include="..\runtime\BasicBlockLocation.h" /> <ClInclude Include="..\runtime\BatchedTransitionOptimizer.h" /> <ClInclude Include="..\runtime\BigInteger.h" /> <ClInclude Include="..\runtime\BooleanConstructor.h" /> @@ -1353,6 +1477,7 @@ <ClInclude Include="..\runtime\ButterflyInlines.h" /> <ClInclude Include="..\runtime\CallData.h" /> <ClInclude Include="..\runtime\ClassInfo.h" /> + <ClInclude Include="..\runtime\ClonedArguments.h" /> <ClInclude Include="..\runtime\CodeCache.h" /> <ClInclude Include="..\runtime\CodeSpecializationKind.h" /> <ClInclude Include="..\runtime\CommonIdentifiers.h" /> @@ -1365,6 +1490,7 @@ <ClInclude Include="..\runtime\ConsoleTypes.h" /> <ClInclude Include="..\runtime\ConstantMode.h" /> <ClInclude Include="..\runtime\ConstructData.h" /> + <ClInclude Include="..\runtime\ControlFlowProfiler.h" /> <ClInclude Include="..\runtime\CustomGetterSetter.h" /> <ClInclude Include="..\runtime\DataView.h" /> <ClInclude Include="..\runtime\DateConstructor.h" /> @@ -1372,19 +1498,29 @@ <ClInclude Include="..\runtime\DateInstance.h" /> <ClInclude Include="..\runtime\DateInstanceCache.h" /> <ClInclude Include="..\runtime\DatePrototype.h" /> + <ClInclude Include="..\runtime\DirectArguments.h" /> + <ClInclude Include="..\runtime\DirectArgumentsOffset.h" /> <ClInclude Include="..\runtime\DumpContext.h" /> + <ClInclude Include="..\runtime\EnumerationMode.h" /> <ClInclude Include="..\runtime\Error.h" /> <ClInclude Include="..\runtime\ErrorConstructor.h" /> <ClInclude Include="..\runtime\ErrorHandlingScope.h" /> <ClInclude Include="..\runtime\ErrorInstance.h" /> <ClInclude Include="..\runtime\ErrorPrototype.h" /> + <ClInclude Include="..\runtime\Exception.h" /> + <ClInclude Include="..\runtime\ExceptionFuzz.h" /> <ClInclude Include="..\runtime\ExceptionHelpers.h" /> <ClInclude Include="..\runtime\Executable.h" /> <ClInclude Include="..\runtime\Float32Array.h" /> <ClInclude Include="..\runtime\Float64Array.h" /> <ClInclude Include="..\runtime\FunctionConstructor.h" /> <ClInclude Include="..\runtime\FunctionExecutableDump.h" /> + <ClInclude Include="..\runtime\FunctionHasExecutedCache.h" /> <ClInclude Include="..\runtime\FunctionPrototype.h" /> + <ClInclude Include="..\runtime\FunctionRareData.h" /> + <ClInclude Include="..\runtime\GenericArguments.h" /> + <ClInclude Include="..\runtime\GenericArgumentsInlines.h" /> + <ClInclude Include="..\runtime\GenericOffset.h" /> <ClInclude Include="..\runtime\GenericTypedArrayView.h" /> <ClInclude Include="..\runtime\GenericTypedArrayViewInlines.h" /> <ClInclude Include="..\runtime\GetterSetter.h" /> @@ -1392,16 +1528,20 @@ <ClInclude Include="..\runtime\IndexingHeader.h" /> <ClInclude Include="..\runtime\IndexingHeaderInlines.h" /> <ClInclude Include="..\runtime\IndexingType.h" /> + <ClInclude Include="..\runtime\InferredValue.h" /> <ClInclude Include="..\runtime\InitializeThreading.h" /> <ClInclude Include="..\runtime\Int16Array.h" /> <ClInclude Include="..\runtime\Int32Array.h" /> <ClInclude Include="..\runtime\Int8Array.h" /> <ClInclude Include="..\runtime\IntendedStructureChain.h" /> <ClInclude Include="..\runtime\InternalFunction.h" /> + <ClInclude Include="..\runtime\IntlObject.h" /> <ClInclude Include="..\runtime\Intrinsic.h" /> + <ClInclude Include="..\runtime\IterationStatus.h" /> + <ClInclude Include="..\runtime\IteratorOperations.h" /> + <ClInclude Include="..\runtime\IteratorPrototype.h" /> <ClInclude Include="..\runtime\JSAPIValueWrapper.h" /> - <ClInclude Include="..\runtime\JSActivation.h" /> - <ClInclude Include="..\runtime\JSArgumentsIterator.h" /> + <ClInclude Include="..\runtime\JSLexicalEnvironment.h" /> <ClInclude Include="..\runtime\JSArray.h" /> <ClInclude Include="..\runtime\JSArrayBuffer.h" /> <ClInclude Include="..\runtime\JSArrayBufferConstructor.h" /> @@ -1413,6 +1553,8 @@ <ClInclude Include="..\runtime\JSCInlines.h" /> <ClInclude Include="..\runtime\JSCJSValue.h" /> <ClInclude Include="..\runtime\JSCJSValueInlines.h" /> + <ClInclude Include="..\runtime\JSCallee.h" /> + <ClInclude Include="..\runtime\JSCatchScope.h" /> <ClInclude Include="..\runtime\JSCell.h" /> <ClInclude Include="..\runtime\JSConsole.h" /> <ClInclude Include="..\runtime\JSDataView.h" /> @@ -1423,6 +1565,7 @@ <ClInclude Include="..\runtime\JSFloat32Array.h" /> <ClInclude Include="..\runtime\JSFloat64Array.h" /> <ClInclude Include="..\runtime\JSFunction.h" /> + <ClInclude Include="..\runtime\JSFunctionNameScope.h" /> <ClInclude Include="..\runtime\JSGenericTypedArrayView.h" /> <ClInclude Include="..\runtime\JSGenericTypedArrayViewConstructor.h" /> <ClInclude Include="..\runtime\JSGenericTypedArrayViewConstructorInlines.h" /> @@ -1431,6 +1574,7 @@ <ClInclude Include="..\runtime\JSGenericTypedArrayViewPrototypeInlines.h" /> <ClInclude Include="..\runtime\JSGlobalObject.h" /> <ClInclude Include="..\runtime\JSGlobalObjectFunctions.h" /> + <ClInclude Include="..\runtime\JSJob.h" /> <ClInclude Include="..\runtime\JSInt16Array.h" /> <ClInclude Include="..\runtime\JSInt32Array.h" /> <ClInclude Include="..\runtime\JSInt8Array.h" /> @@ -1444,10 +1588,8 @@ <ClInclude Include="..\runtime\JSPromise.h" /> <ClInclude Include="..\runtime\JSPromiseConstructor.h" /> <ClInclude Include="..\runtime\JSPromiseDeferred.h" /> - <ClInclude Include="..\runtime\JSPromiseFunctions.h" /> - <ClInclude Include="..\runtime\JSPromiseReaction.h" /> <ClInclude Include="..\runtime\JSPromisePrototype.h" /> - <ClInclude Include="..\runtime\JSPropertyNameIterator.h" /> + <ClInclude Include="..\runtime\JSPropertyNameEnumerator.h" /> <ClInclude Include="..\runtime\JSProxy.h" /> <ClInclude Include="..\runtime\JSScope.h" /> <ClInclude Include="..\runtime\JSSegmentedVariableObject.h" /> @@ -1455,8 +1597,10 @@ <ClInclude Include="..\runtime\JSSetIterator.h" /> <ClInclude Include="..\runtime\JSString.h" /> <ClInclude Include="..\runtime\JSStringBuilder.h" /> + <ClInclude Include="..\runtime\JSStringIterator.h" /> <ClInclude Include="..\runtime\JSStringJoiner.h" /> <ClInclude Include="..\runtime\JSSymbolTableObject.h" /> + <ClInclude Include="..\runtime\JSTemplateRegistryKey.h" /> <ClInclude Include="..\runtime\JSType.h" /> <ClInclude Include="..\runtime\JSTypeInfo.h" /> <ClInclude Include="..\runtime\JSTypedArrayConstructors.h" /> @@ -1466,26 +1610,27 @@ <ClInclude Include="..\runtime\JSUint32Array.h" /> <ClInclude Include="..\runtime\JSUint8Array.h" /> <ClInclude Include="..\runtime\JSUint8ClampedArray.h" /> - <ClInclude Include="..\runtime\JSVariableObject.h" /> + <ClInclude Include="..\runtime\JSEnvironmentRecord.h" /> <ClInclude Include="..\runtime\JSWeakMap.h" /> + <ClInclude Include="..\runtime\JSWeakSet.h" /> <ClInclude Include="..\runtime\JSWithScope.h" /> <ClInclude Include="..\runtime\JSWrapperObject.h" /> <ClInclude Include="..\runtime\LiteralParser.h" /> <ClInclude Include="..\runtime\Lookup.h" /> <ClInclude Include="..\runtime\MapConstructor.h" /> <ClInclude Include="..\runtime\MapData.h" /> - <ClInclude Include="..\runtime\MapIteratorConstructor.h" /> + <ClInclude Include="..\runtime\MapDataInlines.h" /> <ClInclude Include="..\runtime\MapIteratorPrototype.h" /> <ClInclude Include="..\runtime\MapPrototype.h" /> <ClInclude Include="..\runtime\MatchResult.h" /> + <ClInclude Include="..\runtime\MathCommon.h" /> <ClInclude Include="..\runtime\MathObject.h" /> <ClInclude Include="..\runtime\MemoryStatistics.h" /> <ClInclude Include="..\runtime\Microtask.h" /> - <ClInclude Include="..\runtime\NameConstructor.h" /> - <ClInclude Include="..\runtime\NameInstance.h" /> - <ClInclude Include="..\runtime\NamePrototype.h" /> <ClInclude Include="..\runtime\NativeErrorConstructor.h" /> <ClInclude Include="..\runtime\NativeErrorPrototype.h" /> + <ClInclude Include="..\runtime\NullGetterFunction.h" /> + <ClInclude Include="..\runtime\NullSetterFunction.h" /> <ClInclude Include="..\runtime\NumberConstructor.h" /> <ClInclude Include="..\runtime\NumberObject.h" /> <ClInclude Include="..\runtime\NumberPrototype.h" /> @@ -1515,9 +1660,13 @@ <ClInclude Include="..\runtime\RegExpObject.h" /> <ClInclude Include="..\runtime\RegExpPrototype.h" /> <ClInclude Include="..\runtime\Reject.h" /> + <ClInclude Include="..\runtime\RuntimeFlags.h" /> + <ClInclude Include="..\runtime\RuntimeType.h" /> <ClInclude Include="..\runtime\SamplingCounter.h" /> + <ClInclude Include="..\runtime\ScopeOffset.h" /> + <ClInclude Include="..\runtime\ScopedArguments.h" /> + <ClInclude Include="..\runtime\ScopedArgumentsTable.h" /> <ClInclude Include="..\runtime\SetConstructor.h" /> - <ClInclude Include="..\runtime\SetIteratorConstructor.h" /> <ClInclude Include="..\runtime\SetIteratorPrototype.h" /> <ClInclude Include="..\runtime\SetPrototype.h" /> <ClInclude Include="..\runtime\SimpleTypedArrayController.h" /> @@ -1526,6 +1675,7 @@ <ClInclude Include="..\runtime\StackAlignment.h" /> <ClInclude Include="..\runtime\StrictEvalActivation.h" /> <ClInclude Include="..\runtime\StringConstructor.h" /> + <ClInclude Include="..\runtime\StringIteratorPrototype.h" /> <ClInclude Include="..\runtime\StringObject.h" /> <ClInclude Include="..\runtime\StringPrototype.h" /> <ClInclude Include="..\runtime\StringRecursionChecker.h" /> @@ -1536,7 +1686,13 @@ <ClInclude Include="..\runtime\StructureRareData.h" /> <ClInclude Include="..\runtime\StructureRareDataInlines.h" /> <ClInclude Include="..\runtime\StructureTransitionTable.h" /> + <ClInclude Include="..\runtime\Symbol.h" /> + <ClInclude Include="..\runtime\SymbolConstructor.h" /> + <ClInclude Include="..\runtime\SymbolObject.h" /> + <ClInclude Include="..\runtime\SymbolPrototype.h" /> <ClInclude Include="..\runtime\SymbolTable.h" /> + <ClInclude Include="..\runtime\TemplateRegistry.h" /> + <ClInclude Include="..\runtime\TemplateRegistryKey.h" /> <ClInclude Include="..\runtime\TestRunnerUtils.h" /> <ClInclude Include="..\runtime\Tracing.h" /> <ClInclude Include="..\runtime\ToNativeFromValue.h" /> @@ -1544,6 +1700,11 @@ <ClInclude Include="..\runtime\TypedArrayController.h" /> <ClInclude Include="..\runtime\TypedArrayInlines.h" /> <ClInclude Include="..\runtime\TypedArrayType.h" /> + <ClInclude Include="..\runtime\TypeofType.h" /> + <ClInclude Include="..\runtime\TypeLocationCache.h" /> + <ClInclude Include="..\runtime\TypeProfiler.h" /> + <ClInclude Include="..\runtime\TypeProfilerLog.h" /> + <ClInclude Include="..\runtime\TypeSet.h" /> <ClInclude Include="..\runtime\TypedArrays.h" /> <ClInclude Include="..\runtime\Uint16Array.h" /> <ClInclude Include="..\runtime\Uint16WithFraction.h" /> @@ -1551,16 +1712,22 @@ <ClInclude Include="..\runtime\Uint8Array.h" /> <ClInclude Include="..\runtime\VM.h" /> <ClInclude Include="..\runtime\VMEntryScope.h" /> + <ClInclude Include="..\runtime\VarOffset.h" /> <ClInclude Include="..\runtime\Watchdog.h" /> <ClInclude Include="..\runtime\WeakGCMap.h" /> <ClInclude Include="..\runtime\WeakMapConstructor.h" /> <ClInclude Include="..\runtime\WeakMapData.h" /> <ClInclude Include="..\runtime\WeakMapPrototype.h" /> + <ClInclude Include="..\runtime\WeakSetConstructor.h" /> + <ClInclude Include="..\runtime\WeakSetPrototype.h" /> <ClInclude Include="..\runtime\WeakRandom.h" /> <ClInclude Include="..\runtime\WriteBarrier.h" /> <ClInclude Include="..\runtime\WriteBarrierInlines.h" /> <ClInclude Include="..\tools\CodeProfile.h" /> <ClInclude Include="..\tools\CodeProfiling.h" /> + <ClInclude Include="..\tools\FunctionOverrides.h" /> + <ClInclude Include="..\tools\JSDollarVM.h" /> + <ClInclude Include="..\tools\JSDollarVMPrototype.h" /> <ClInclude Include="..\tools\ProfileTreeNode.h" /> <ClInclude Include="..\tools\TieredMMapArray.h" /> <ClInclude Include="..\yarr\RegularExpression.h" /> @@ -1574,6 +1741,63 @@ </ItemGroup> <ItemGroup> <None Include="..\bytecode\BytecodeList.json" /> + <None Include="..\inspector\scripts\codegen\cpp_generator.py" /> + <None Include="..\inspector\scripts\codegen\cpp_generator_templates.py" /> + <None Include="..\inspector\scripts\codegen\generate_cpp_backend_dispatcher_header.py" /> + <None Include="..\inspector\scripts\codegen\generate_cpp_backend_dispatcher_implementation.py" /> + <None Include="..\inspector\scripts\codegen\generate_cpp_frontend_dispatcher_header.py" /> + <None Include="..\inspector\scripts\codegen\generate_cpp_frontend_dispatcher_implementation.py" /> + <None Include="..\inspector\scripts\codegen\generate_cpp_protocol_types_header.py" /> + <None Include="..\inspector\scripts\codegen\generate_cpp_protocol_types_implementation.py" /> + <None Include="..\inspector\scripts\codegen\generate_js_backend_commands.py" /> + <None Include="..\inspector\scripts\codegen\generator.py" /> + <None Include="..\inspector\scripts\codegen\generator_templates.py" /> + <None Include="..\inspector\scripts\codegen\models.py" /> + <None Include="..\inspector\scripts\codegen\__init__.py" /> + <None Include="..\inspector\scripts\cssmin.py" /> + <None Include="..\inspector\scripts\generate-combined-inspector-json.py" /> + <None Include="..\inspector\scripts\generate-inspector-protocol-bindings.py" /> + <None Include="..\inspector\scripts\inline-and-minify-stylesheets-and-scripts.py" /> + <None Include="..\inspector\scripts\jsmin.py" /> + <None Include="..\inspector\scripts\tests\commands-with-async-attribute.json" /> + <None Include="..\inspector\scripts\tests\commands-with-optional-call-return-parameters.json" /> + <None Include="..\inspector\scripts\tests\domains-with-varying-command-sizes.json" /> + <None Include="..\inspector\scripts\tests\events-with-optional-parameters.json" /> + <None Include="..\inspector\scripts\tests\expected\commands-with-async-attribute.json-result" /> + <None Include="..\inspector\scripts\tests\expected\commands-with-optional-call-return-parameters.json-result" /> + <None Include="..\inspector\scripts\tests\expected\domains-with-varying-command-sizes.json-result" /> + <None Include="..\inspector\scripts\tests\expected\events-with-optional-parameters.json-result" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-duplicate-type-declarations.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-enum-with-no-values.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-string-typed-optional-parameter-flag.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-string-typed-optional-type-member.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-type-declaration-using-type-reference.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-type-with-lowercase-name.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-unknown-type-reference-in-type-declaration.json-error" /> + <None Include="..\inspector\scripts\tests\expected\fail-on-unknown-type-reference-in-type-member.json-error" /> + <None Include="..\inspector\scripts\tests\expected\same-type-id-different-domain.json-result" /> + <None Include="..\inspector\scripts\tests\expected\shadowed-optional-type-setters.json-result" /> + <None Include="..\inspector\scripts\tests\expected\type-declaration-aliased-primitive-type.json-result" /> + <None Include="..\inspector\scripts\tests\expected\type-declaration-array-type.json-result" /> + <None Include="..\inspector\scripts\tests\expected\type-declaration-enum-type.json-result" /> + <None Include="..\inspector\scripts\tests\expected\type-declaration-object-type.json-result" /> + <None Include="..\inspector\scripts\tests\expected\type-requiring-runtime-casts.json-result" /> + <None Include="..\inspector\scripts\tests\fail-on-duplicate-type-declarations.json" /> + <None Include="..\inspector\scripts\tests\fail-on-enum-with-no-values.json" /> + <None Include="..\inspector\scripts\tests\fail-on-string-typed-optional-parameter-flag.json" /> + <None Include="..\inspector\scripts\tests\fail-on-string-typed-optional-type-member.json" /> + <None Include="..\inspector\scripts\tests\fail-on-type-declaration-using-type-reference.json" /> + <None Include="..\inspector\scripts\tests\fail-on-type-with-lowercase-name.json" /> + <None Include="..\inspector\scripts\tests\fail-on-unknown-type-reference-in-type-declaration.json" /> + <None Include="..\inspector\scripts\tests\fail-on-unknown-type-reference-in-type-member.json" /> + <None Include="..\inspector\scripts\tests\same-type-id-different-domain.json" /> + <None Include="..\inspector\scripts\tests\shadowed-optional-type-setters.json" /> + <None Include="..\inspector\scripts\tests\type-declaration-aliased-primitive-type.json" /> + <None Include="..\inspector\scripts\tests\type-declaration-array-type.json" /> + <None Include="..\inspector\scripts\tests\type-declaration-enum-type.json" /> + <None Include="..\inspector\scripts\tests\type-declaration-object-type.json" /> + <None Include="..\inspector\scripts\tests\type-requiring-runtime-casts.json" /> + <None Include="..\inspector\scripts\xxd.pl" /> <None Include="JavaScriptCorePostBuild.cmd"> <FileType>Document</FileType> </None> @@ -1606,4 +1830,4 @@ <ImportGroup Label="ExtensionTargets"> <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" /> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters index a987236..a66b830 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters +++ b/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters @@ -67,6 +67,18 @@ <Filter Include="llvm"> <UniqueIdentifier>{852e9415-245c-4012-aeb8-38ca9efb73b8}</UniqueIdentifier> </Filter> + <Filter Include="inspector\scripts"> + <UniqueIdentifier>{a29d27c0-2c34-482b-87cc-21e7ef290c88}</UniqueIdentifier> + </Filter> + <Filter Include="inspector\scripts\codegen"> + <UniqueIdentifier>{17e304e8-c0e8-4b18-88fa-62b86eba9959}</UniqueIdentifier> + </Filter> + <Filter Include="inspector\scripts\tests"> + <UniqueIdentifier>{0a034c97-3947-47c4-8085-2ddc8aa1ade0}</UniqueIdentifier> + </Filter> + <Filter Include="inspector\scripts\tests\expected"> + <UniqueIdentifier>{6be9d367-0091-4ebb-b96c-4ef83790362b}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="..\API\JSBase.cpp"> @@ -117,6 +129,9 @@ <ClCompile Include="..\assembler\MacroAssembler.cpp"> <Filter>assembler</Filter> </ClCompile> + <ClCompile Include="..\assembler\MacroAssemblerX86Common.cpp"> + <Filter>assembler</Filter> + </ClCompile> <ClCompile Include="..\builtins\BuiltinExecutables.cpp"> <Filter>builtins</Filter> </ClCompile> @@ -129,6 +144,9 @@ <ClCompile Include="..\bytecode\BytecodeBasicBlock.cpp"> <Filter>bytecode</Filter> </ClCompile> + <ClCompile Include="..\bytecode\BytecodeIntrinsicRegistry.cpp"> + <Filter>bytecode</Filter> + </ClCompile> <ClCompile Include="..\bytecode\BytecodeLivenessAnalysis.cpp"> <Filter>bytecode</Filter> </ClCompile> @@ -213,18 +231,15 @@ <ClCompile Include="..\debugger\Debugger.cpp"> <Filter>debugger</Filter> </ClCompile> - <ClCompile Include="..\debugger\DebuggerActivation.cpp"> + <ClCompile Include="..\debugger\DebuggerCallFrame.cpp"> <Filter>debugger</Filter> </ClCompile> - <ClCompile Include="..\debugger\DebuggerCallFrame.cpp"> + <ClCompile Include="..\debugger\DebuggerScope.cpp"> <Filter>debugger</Filter> </ClCompile> <ClCompile Include="..\disassembler\Disassembler.cpp"> <Filter>disassembler</Filter> </ClCompile> - <ClCompile Include="..\heap\BlockAllocator.cpp"> - <Filter>heap</Filter> - </ClCompile> <ClCompile Include="..\heap\ConservativeRoots.cpp"> <Filter>heap</Filter> </ClCompile> @@ -267,6 +282,9 @@ <ClCompile Include="..\heap\HeapTimer.cpp"> <Filter>heap</Filter> </ClCompile> + <ClCompile Include="..\heap\HeapVerifier.cpp"> + <Filter>heap</Filter> + </ClCompile> <ClCompile Include="..\heap\IncrementalSweeper.cpp"> <Filter>heap</Filter> </ClCompile> @@ -291,9 +309,6 @@ <ClCompile Include="..\heap\SlotVisitor.cpp"> <Filter>heap</Filter> </ClCompile> - <ClCompile Include="..\heap\SuperRegion.cpp"> - <Filter>heap</Filter> - </ClCompile> <ClCompile Include="..\heap\Weak.cpp"> <Filter>heap</Filter> </ClCompile> @@ -330,9 +345,6 @@ <ClCompile Include="..\inspector\agents\InspectorDebuggerAgent.cpp"> <Filter>inspector</Filter> </ClCompile> - <ClCompile Include="..\inspector\agents\InspectorProfilerAgent.cpp"> - <Filter>inspector</Filter> - </ClCompile> <ClCompile Include="..\inspector\agents\InspectorRuntimeAgent.cpp"> <Filter>inspector</Filter> </ClCompile> @@ -354,12 +366,6 @@ <ClCompile Include="..\interpreter\StackVisitor.cpp"> <Filter>interpreter</Filter> </ClCompile> - <ClCompile Include="..\interpreter\VMInspector.cpp"> - <Filter>interpreter</Filter> - </ClCompile> - <ClCompile Include="..\jit\ClosureCallStubRoutine.cpp"> - <Filter>jit</Filter> - </ClCompile> <ClCompile Include="..\jit\ExecutableAllocator.cpp"> <Filter>jit</Filter> </ClCompile> @@ -510,15 +516,15 @@ <ClCompile Include="..\runtime\ArgList.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\Arguments.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\ArrayConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> <ClCompile Include="..\runtime\ArrayPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\BasicBlockLocation.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\BooleanConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -552,6 +558,9 @@ <ClCompile Include="..\runtime\ConstructData.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\ControlFlowProfiler.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\CustomGetterSetter.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -591,9 +600,15 @@ <ClCompile Include="..\runtime\FunctionConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\FunctionHasExecutedCache.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\FunctionPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\FunctionRareData.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\GetterSetter.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -609,7 +624,16 @@ <ClCompile Include="..\runtime\InternalFunction.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\JSActivation.cpp"> + <ClCompile Include="..\runtime\IntlObject.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\IteratorOperations.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\IteratorPrototype.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\JSLexicalEnvironment.cpp"> <Filter>runtime</Filter> </ClCompile> <ClCompile Include="..\runtime\JSAPIValueWrapper.cpp"> @@ -621,6 +645,9 @@ <ClCompile Include="..\runtime\JSBoundFunction.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\JSCallee.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\JSCell.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -639,6 +666,9 @@ <ClCompile Include="..\runtime\JSGlobalObjectFunctions.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\JSJob.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\JSLock.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -657,7 +687,7 @@ <ClCompile Include="..\runtime\JSONObject.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\JSPropertyNameIterator.cpp"> + <ClCompile Include="..\runtime\JSPropertyNameEnumerator.cpp"> <Filter>runtime</Filter> </ClCompile> <ClCompile Include="..\runtime\JSProxy.cpp"> @@ -678,13 +708,19 @@ <ClCompile Include="..\runtime\JSString.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\JSStringIterator.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\JSStringJoiner.cpp"> <Filter>runtime</Filter> </ClCompile> <ClCompile Include="..\runtime\JSSymbolTableObject.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\JSVariableObject.cpp"> + <ClCompile Include="..\runtime\JSTemplateRegistryKey.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\JSEnvironmentRecord.cpp"> <Filter>runtime</Filter> </ClCompile> <ClCompile Include="..\runtime\JSWithScope.cpp"> @@ -693,6 +729,9 @@ <ClCompile Include="..\runtime\JSWeakMap.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\JSWeakSet.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\JSWrapperObject.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -705,28 +744,25 @@ <ClCompile Include="..\runtime\MapPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\MapData.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\MapConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\MathObject.cpp"> + <ClCompile Include="..\runtime\MathCommon.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\NameConstructor.cpp"> + <ClCompile Include="..\runtime\MathObject.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\NameInstance.cpp"> + <ClCompile Include="..\runtime\NativeErrorConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\NamePrototype.cpp"> + <ClCompile Include="..\runtime\NativeErrorPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\NativeErrorConstructor.cpp"> + <ClCompile Include="..\runtime\NullGetterFunction.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\NativeErrorPrototype.cpp"> + <ClCompile Include="..\runtime\NullSetterFunction.cpp"> <Filter>runtime</Filter> </ClCompile> <ClCompile Include="..\runtime\NumberConstructor.cpp"> @@ -753,9 +789,6 @@ <ClCompile Include="..\runtime\PropertyDescriptor.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\PropertyNameArray.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\PropertySlot.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -780,6 +813,9 @@ <ClCompile Include="..\runtime\RegExpPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\RuntimeType.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\SamplingCounter.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -792,15 +828,9 @@ <ClCompile Include="..\runtime\SetIteratorPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\SetIteratorConstructor.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\SetConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\SetIteratorConstructor.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\SparseArrayValueMap.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -810,6 +840,9 @@ <ClCompile Include="..\runtime\StringConstructor.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\StringIteratorPrototype.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\StringObject.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -828,9 +861,36 @@ <ClCompile Include="..\runtime\StructureIDTable.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\Symbol.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\SymbolConstructor.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\SymbolObject.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\SymbolPrototype.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\SymbolTable.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\TemplateRegistry.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\TypeLocationCache.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\TypeProfiler.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\TypeProfilerLog.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\TypeSet.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\runtime\Watchdog.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -843,6 +903,15 @@ <ClCompile Include="..\tools\CodeProfiling.cpp"> <Filter>tools</Filter> </ClCompile> + <ClCompile Include="..\tools\FunctionOverrides.cpp"> + <Filter>tools</Filter> + </ClCompile> + <ClCompile Include="..\tools\JSDollarVM.cpp"> + <Filter>tools</Filter> + </ClCompile> + <ClCompile Include="..\tools\JSDollarVMPrototype.cpp"> + <Filter>tools</Filter> + </ClCompile> <ClCompile Include="..\yarr\RegularExpression.cpp"> <Filter>yarr</Filter> </ClCompile> @@ -945,12 +1014,6 @@ <ClCompile Include="..\runtime\JSPromiseDeferred.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\JSPromiseFunctions.cpp"> - <Filter>runtime</Filter> - </ClCompile> - <ClCompile Include="..\runtime\JSPromiseReaction.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\JSPromisePrototype.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -963,6 +1026,12 @@ <ClCompile Include="..\runtime\WeakMapPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\runtime\WeakSetConstructor.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\WeakSetPrototype.cpp"> + <Filter>runtime</Filter> + </ClCompile> <ClCompile Include="..\heap\CodeBlockSet.cpp"> <Filter>heap</Filter> </ClCompile> @@ -972,6 +1041,9 @@ <ClCompile Include="..\bytecode\DeferredCompilationCallback.cpp"> <Filter>bytecode</Filter> </ClCompile> + <ClCompile Include="..\bytecode\DeferredSourceDump.cpp"> + <Filter>bytecode</Filter> + </ClCompile> <ClCompile Include="..\dfg\DFGCompilationKey.cpp"> <Filter>dfg</Filter> </ClCompile> @@ -993,9 +1065,6 @@ <ClCompile Include="..\dfg\DFGAbstractValue.cpp"> <Filter>dfg</Filter> </ClCompile> - <ClCompile Include="..\dfg\DFGArgumentsSimplificationPhase.cpp"> - <Filter>dfg</Filter> - </ClCompile> <ClCompile Include="..\dfg\DFGArrayMode.cpp"> <Filter>dfg</Filter> </ClCompile> @@ -1008,9 +1077,6 @@ <ClCompile Include="..\dfg\DFGBasicBlock.cpp"> <Filter>dfg</Filter> </ClCompile> - <ClCompile Include="..\dfg\DFGBinarySwitch.cpp"> - <Filter>dfg</Filter> - </ClCompile> <ClCompile Include="..\dfg\DFGBlockInsertionSet.cpp"> <Filter>dfg</Filter> </ClCompile> @@ -1056,9 +1122,6 @@ <ClCompile Include="..\dfg\DFGDesiredIdentifiers.cpp"> <Filter>dfg</Filter> </ClCompile> - <ClCompile Include="..\dfg\DFGDesiredStructureChains.cpp"> - <Filter>dfg</Filter> - </ClCompile> <ClCompile Include="..\dfg\DFGDesiredTransitions.cpp"> <Filter>dfg</Filter> </ClCompile> @@ -1122,6 +1185,9 @@ <ClCompile Include="..\dfg\DFGLazyJSValue.cpp"> <Filter>dfg</Filter> </ClCompile> + <ClCompile Include="..\dfg\DFGLazyNode.cpp"> + <Filter>dfg</Filter> + </ClCompile> <ClCompile Include="..\dfg\DFGLICMPhase.cpp"> <Filter>dfg</Filter> </ClCompile> @@ -1272,21 +1338,9 @@ <ClCompile Include="..\runtime\CompilationResult.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\ArrayIteratorConstructor.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\ArrayIteratorPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\ArgumentsIteratorConstructor.cpp"> - <Filter>runtime</Filter> - </ClCompile> - <ClCompile Include="..\runtime\ArgumentsIteratorPrototype.cpp"> - <Filter>runtime</Filter> - </ClCompile> - <ClCompile Include="..\runtime\MapIteratorConstructor.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\MapIteratorPrototype.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -1296,9 +1350,6 @@ <ClCompile Include="..\runtime\JSArrayIterator.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="..\runtime\JSArgumentsIterator.cpp"> - <Filter>runtime</Filter> - </ClCompile> <ClCompile Include="..\runtime\JSMapIterator.cpp"> <Filter>runtime</Filter> </ClCompile> @@ -1332,15 +1383,9 @@ <ClCompile Include="..\dfg\DFGAvailability.cpp"> <Filter>dfg</Filter> </ClCompile> - <ClCompile Include="..\dfg\DFGResurrectionForValidationPhase.cpp"> - <Filter>dfg</Filter> - </ClCompile> <ClCompile Include="..\bytecode\CodeBlockJettisoningWatchpoint.cpp"> <Filter>bytecode</Filter> </ClCompile> - <ClCompile Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.cpp"> - <Filter>bytecode</Filter> - </ClCompile> <ClCompile Include="..\bindings\ScriptValue.cpp"> <Filter>bindings</Filter> </ClCompile> @@ -1359,13 +1404,13 @@ <ClCompile Include="..\runtime\ArrayBufferNeuteringWatchpoint.cpp"> <Filter>runtime</Filter> </ClCompile> - <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSBackendDispatchers.cpp"> + <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorBackendDispatchers.cpp"> <Filter>Derived Sources</Filter> </ClCompile> - <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSFrontendDispatchers.cpp"> + <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorFrontendDispatchers.cpp"> <Filter>Derived Sources</Filter> </ClCompile> - <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSTypeBuilders.cpp"> + <ClCompile Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorProtocolObjects.cpp"> <Filter>Derived Sources</Filter> </ClCompile> <ClCompile Include="..\jit\ArityCheckFailReturnThunks.cpp"> @@ -1608,6 +1653,139 @@ <ClCompile Include="..\runtime\MemoryStatistics.cpp"> <Filter>runtime</Filter> </ClCompile> + <ClCompile Include="..\bytecode\ComplexGetStatus.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\ConstantStructureCheck.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGDoesGC.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGFrozenValue.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGHeapLocation.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGMayExit.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGPureValue.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGStructureAbstractValue.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGStructureRegistrationPhase.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGTransition.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGValueStrength.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\runtime\Exception.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\runtime\ExceptionFuzz.cpp"> + <Filter>runtime</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\StructureSet.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\ToThisStatus.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\CallEdge.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\CallVariant.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGAvailabilityMap.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGBlockSet.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGBlockWorklist.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGInsertOSRHintsForUpdate.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGNaiveDominators.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGObjectAllocationSinkingPhase.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGObjectMaterializationData.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGPhiChildren.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGPrePostNumbering.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGPromotedHeapLocation.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGSSACalculator.cpp"> + <Filter>dfg</Filter> + </ClCompile> + <ClCompile Include="..\ftl\FTLExitPropertyValue.cpp"> + <Filter>ftl</Filter> + </ClCompile> + <ClCompile Include="..\ftl\FTLExitTimeObjectMaterialization.cpp"> + <Filter>ftl</Filter> + </ClCompile> + <ClCompile Include="..\ftl\FTLOperations.cpp"> + <Filter>ftl</Filter> + </ClCompile> + <ClCompile Include="..\jit\BinarySwitch.cpp"> + <Filter>jit</Filter> + </ClCompile> + <ClCompile Include="..\jit\PolymorphicCallStubRoutine.cpp"> + <Filter>jit</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\VirtualRegister.cpp"> + <Filter>bytecode</Filter> + </ClCompile> + <ClCompile Include="..\jit\SetupVarargsFrame.cpp" /> + <ClCompile Include="JavaScriptCoreDLL.cpp"> + <Filter>API</Filter> + </ClCompile> + <ClCompile Include="..\dfg\DFGPutStackSinkingPhase.cpp" /> + <ClCompile Include="..\ftl\FTLJSCallBase.cpp" /> + <ClCompile Include="..\ftl\FTLJSCallVarargs.cpp" /> + <ClCompile Include="..\runtime\JSCatchScope.cpp" /> + <ClCompile Include="..\runtime\JSFunctionNameScope.cpp" /> + <ClCompile Include="..\jit\ExecutableAllocatorFixedVMPool.cpp"> + <Filter>jit</Filter> + </ClCompile> + <ClCompile Include="..\bytecode\VariableWriteFireDetail.cpp" /> + <ClCompile Include="..\dfg\DFGArgumentsEliminationPhase.cpp" /> + <ClCompile Include="..\dfg\DFGArgumentsUtilities.cpp" /> + <ClCompile Include="..\dfg\DFGCleanUpPhase.cpp" /> + <ClCompile Include="..\dfg\DFGEpoch.cpp" /> + <ClCompile Include="..\dfg\DFGMovHintRemovalPhase.cpp" /> + <ClCompile Include="..\dfg\DFGPhantomInsertionPhase.cpp" /> + <ClCompile Include="..\dfg\DFGVarargsForwardingPhase.cpp" /> + <ClCompile Include="..\jit\ExecutableAllocationFuzz.cpp" /> + <ClCompile Include="..\runtime\ClonedArguments.cpp" /> + <ClCompile Include="..\runtime\ConstantMode.cpp" /> + <ClCompile Include="..\runtime\DirectArguments.cpp" /> + <ClCompile Include="..\runtime\DirectArgumentsOffset.cpp" /> + <ClCompile Include="..\runtime\InferredValue.cpp" /> + <ClCompile Include="..\runtime\ScopeOffset.cpp" /> + <ClCompile Include="..\runtime\ScopedArguments.cpp" /> + <ClCompile Include="..\runtime\ScopedArgumentsTable.cpp" /> + <ClCompile Include="..\runtime\TypeofType.cpp" /> + <ClCompile Include="..\runtime\VarOffset.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\API\APICallbackFunction.h"> @@ -1748,6 +1926,9 @@ <ClInclude Include="..\bytecode\BytecodeBasicBlock.h"> <Filter>bytecode</Filter> </ClInclude> + <ClInclude Include="..\bytecode\BytecodeIntrinsicRegistry.h"> + <Filter>bytecode</Filter> + </ClInclude> <ClInclude Include="..\bytecode\BytecodeLivenessAnalysis.h"> <Filter>bytecode</Filter> </ClInclude> @@ -1847,6 +2028,9 @@ <ClInclude Include="..\bytecode\StructureStubInfo.h"> <Filter>bytecode</Filter> </ClInclude> + <ClInclude Include="..\bytecode\TypeLocation.h"> + <Filter>bytecode</Filter> + </ClInclude> <ClInclude Include="..\bytecode\UnlinkedCodeBlock.h"> <Filter>bytecode</Filter> </ClInclude> @@ -1883,15 +2067,18 @@ <ClInclude Include="..\debugger\Debugger.h"> <Filter>debugger</Filter> </ClInclude> - <ClInclude Include="..\debugger\DebuggerActivation.h"> + <ClInclude Include="..\debugger\DebuggerCallFrame.h"> <Filter>debugger</Filter> </ClInclude> - <ClInclude Include="..\debugger\DebuggerCallFrame.h"> + <ClInclude Include="..\debugger\DebuggerEvalEnabler.h"> <Filter>debugger</Filter> </ClInclude> <ClInclude Include="..\debugger\DebuggerPrimitives.h"> <Filter>debugger</Filter> </ClInclude> + <ClInclude Include="..\debugger\DebuggerScope.h"> + <Filter>debugger</Filter> + </ClInclude> <ClInclude Include="..\dfg\DFGDriver.h"> <Filter>dfg</Filter> </ClInclude> @@ -1901,9 +2088,6 @@ <ClInclude Include="..\disassembler\Disassembler.h"> <Filter>disassembler</Filter> </ClInclude> - <ClInclude Include="..\heap\BlockAllocator.h"> - <Filter>heap</Filter> - </ClInclude> <ClInclude Include="..\heap\ConservativeRoots.h"> <Filter>heap</Filter> </ClInclude> @@ -1985,9 +2169,6 @@ <ClInclude Include="..\heap\Heap.h"> <Filter>heap</Filter> </ClInclude> - <ClInclude Include="..\heap\HeapBlock.h"> - <Filter>heap</Filter> - </ClInclude> <ClInclude Include="..\heap\HeapInlines.h"> <Filter>heap</Filter> </ClInclude> @@ -2003,6 +2184,9 @@ <ClInclude Include="..\heap\HeapTimer.h"> <Filter>heap</Filter> </ClInclude> + <ClInclude Include="..\heap\HeapVerifier.h"> + <Filter>heap</Filter> + </ClInclude> <ClInclude Include="..\heap\IncrementalSweeper.h"> <Filter>heap</Filter> </ClInclude> @@ -2039,9 +2223,6 @@ <ClInclude Include="..\heap\RecursiveAllocationScope.h"> <Filter>heap</Filter> </ClInclude> - <ClInclude Include="..\heap\Region.h"> - <Filter>heap</Filter> - </ClInclude> <ClInclude Include="..\heap\SlotVisitor.h"> <Filter>heap</Filter> </ClInclude> @@ -2054,9 +2235,6 @@ <ClInclude Include="..\heap\StrongInlines.h"> <Filter>heap</Filter> </ClInclude> - <ClInclude Include="..\heap\SuperRegion.h"> - <Filter>heap</Filter> - </ClInclude> <ClInclude Include="..\heap\TinyBloomFilter.h"> <Filter>heap</Filter> </ClInclude> @@ -2105,9 +2283,6 @@ <ClInclude Include="..\inspector\InspectorFrontendChannel.h"> <Filter>inspector</Filter> </ClInclude> - <ClInclude Include="..\inspector\InspectorTypeBuilder.h"> - <Filter>inspector</Filter> - </ClInclude> <ClInclude Include="..\inspector\InspectorValues.h"> <Filter>inspector</Filter> </ClInclude> @@ -2117,9 +2292,6 @@ <ClInclude Include="..\inspector\agents\InspectorDebuggerAgent.h"> <Filter>inspector</Filter> </ClInclude> - <ClInclude Include="..\inspector\agents\InspectorProfilerAgent.h"> - <Filter>inspector</Filter> - </ClInclude> <ClInclude Include="..\inspector\agents\InspectorRuntimeAgent.h"> <Filter>inspector</Filter> </ClInclude> @@ -2138,6 +2310,9 @@ <ClInclude Include="..\interpreter\CallFrameClosure.h"> <Filter>interpreter</Filter> </ClInclude> + <ClInclude Include="..\interpreter\VMEntryRecord.h"> + <Filter>interpreter</Filter> + </ClInclude> <ClInclude Include="..\interpreter\Interpreter.h"> <Filter>interpreter</Filter> </ClInclude> @@ -2156,12 +2331,6 @@ <ClInclude Include="..\interpreter\StackVisitor.h"> <Filter>interpreter</Filter> </ClInclude> - <ClInclude Include="..\interpreter\VMInspector.h"> - <Filter>interpreter</Filter> - </ClInclude> - <ClInclude Include="..\jit\ClosureCallStubRoutine.h"> - <Filter>jit</Filter> - </ClInclude> <ClInclude Include="..\jit\CompactJITCodeMap.h"> <Filter>jit</Filter> </ClInclude> @@ -2264,9 +2433,6 @@ <ClInclude Include="..\parser\NodeConstructors.h"> <Filter>parser</Filter> </ClInclude> - <ClInclude Include="..\parser\NodeInfo.h"> - <Filter>parser</Filter> - </ClInclude> <ClInclude Include="..\parser\Nodes.h"> <Filter>parser</Filter> </ClInclude> @@ -2357,9 +2523,6 @@ <ClInclude Include="..\runtime\ArgList.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\Arguments.h"> - <Filter>runtime</Filter> - </ClInclude> <ClInclude Include="..\runtime\ArrayConstructor.h"> <Filter>runtime</Filter> </ClInclude> @@ -2372,6 +2535,9 @@ <ClInclude Include="..\runtime\ArrayStorage.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\BasicBlockLocation.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\BatchedTransitionOptimizer.h"> <Filter>runtime</Filter> </ClInclude> @@ -2426,6 +2592,9 @@ <ClInclude Include="..\runtime\ConstructData.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\ControlFlowProfiler.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\CustomGetterSetter.h"> <Filter>runtime</Filter> </ClInclude> @@ -2444,6 +2613,9 @@ <ClInclude Include="..\runtime\DatePrototype.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\EnumerationMode.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\Error.h"> <Filter>runtime</Filter> </ClInclude> @@ -2468,9 +2640,15 @@ <ClInclude Include="..\runtime\FunctionConstructor.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\FunctionHasExecutedCache.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\FunctionPrototype.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\FunctionRareData.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\GetterSetter.h"> <Filter>runtime</Filter> </ClInclude> @@ -2492,10 +2670,22 @@ <ClInclude Include="..\runtime\InternalFunction.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\IntlObject.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\Intrinsic.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\JSActivation.h"> + <ClInclude Include="..\runtime\IterationStatus.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\IteratorOperations.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\IteratorPrototype.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\JSLexicalEnvironment.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\JSAPIValueWrapper.h"> @@ -2507,6 +2697,9 @@ <ClInclude Include="..\runtime\JSBoundFunction.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\JSCallee.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\JSCell.h"> <Filter>runtime</Filter> </ClInclude> @@ -2531,6 +2724,9 @@ <ClInclude Include="..\runtime\JSGlobalObjectFunctions.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\JSJob.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\JSLock.h"> <Filter>runtime</Filter> </ClInclude> @@ -2546,7 +2742,7 @@ <ClInclude Include="..\runtime\JSONObject.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\JSPropertyNameIterator.h"> + <ClInclude Include="..\runtime\JSPropertyNameEnumerator.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\JSProxy.h"> @@ -2564,19 +2760,25 @@ <ClInclude Include="..\runtime\JSStringBuilder.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\JSStringIterator.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\JSStringJoiner.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\JSSymbolTableObject.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\JSTemplateRegistryKey.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\JSType.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\JSTypeInfo.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\JSVariableObject.h"> + <ClInclude Include="..\runtime\JSEnvironmentRecord.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\JSWithScope.h"> @@ -2597,19 +2799,16 @@ <ClInclude Include="..\runtime\MathObject.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\NameConstructor.h"> - <Filter>runtime</Filter> - </ClInclude> - <ClInclude Include="..\runtime\NameInstance.h"> + <ClInclude Include="..\runtime\NativeErrorConstructor.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\NamePrototype.h"> + <ClInclude Include="..\runtime\NativeErrorPrototype.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\NativeErrorConstructor.h"> + <ClInclude Include="..\runtime\NullGetterFunction.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\NativeErrorPrototype.h"> + <ClInclude Include="..\runtime\NullSetterFunction.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\NumberConstructor.h"> @@ -2696,6 +2895,12 @@ <ClInclude Include="..\runtime\Reject.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\RuntimeFlags.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\RuntimeType.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\SamplingCounter.h"> <Filter>runtime</Filter> </ClInclude> @@ -2711,6 +2916,9 @@ <ClInclude Include="..\runtime\StringConstructor.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\StringIteratorPrototype.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\StringObject.h"> <Filter>runtime</Filter> </ClInclude> @@ -2735,12 +2943,42 @@ <ClInclude Include="..\runtime\StructureTransitionTable.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\Symbol.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\SymbolConstructor.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\SymbolObject.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\SymbolPrototype.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\SymbolTable.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\TemplateRegistry.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\TemplateRegistryKey.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\Tracing.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\TypeLocationCache.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\TypeProfiler.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\TypeProfilerLog.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\TypeSet.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\Uint16WithFraction.h"> <Filter>runtime</Filter> </ClInclude> @@ -2765,6 +3003,15 @@ <ClInclude Include="..\tools\CodeProfiling.h"> <Filter>tools</Filter> </ClInclude> + <ClInclude Include="..\tools\FunctionOverrides.h"> + <Filter>tools</Filter> + </ClInclude> + <ClInclude Include="..\tools\JSDollarVM.h"> + <Filter>tools</Filter> + </ClInclude> + <ClInclude Include="..\tools\JSDollarVMPrototype.h"> + <Filter>tools</Filter> + </ClInclude> <ClInclude Include="..\tools\ProfileTreeNode.h"> <Filter>tools</Filter> </ClInclude> @@ -2832,13 +3079,13 @@ <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\HeaderDetection.h"> <Filter>Derived Sources</Filter> </ClInclude> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSBackendDispatchers.h"> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorBackendDispatchers.h"> <Filter>Derived Sources</Filter> </ClInclude> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSFrontendDispatchers.h"> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorFrontendDispatchers.h"> <Filter>Derived Sources</Filter> </ClInclude> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorJSTypeBuilders.h"> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\InspectorProtocolObjects.h"> <Filter>Derived Sources</Filter> </ClInclude> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\JSGlobalObject.lut.h"> @@ -2871,6 +3118,9 @@ <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\StringConstructor.lut.h"> <Filter>Derived Sources</Filter> </ClInclude> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ArrayIteratorPrototype.lut.h"> + <Filter>Derived Sources</Filter> + </ClInclude> <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\ArrayPrototype.lut.h"> <Filter>Derived Sources</Filter> </ClInclude> @@ -2883,9 +3133,6 @@ <ClInclude Include="..\runtime\VMEntryScope.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\assembler\MacroAssemblerX86Common.cpp"> - <Filter>assembler</Filter> - </ClInclude> <ClInclude Include="..\runtime\IntendedStructureChain.h"> <Filter>runtime</Filter> </ClInclude> @@ -2946,12 +3193,6 @@ <ClInclude Include="..\runtime\JSPromiseDeferred.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\JSPromiseFunctions.h"> - <Filter>runtime</Filter> - </ClInclude> - <ClInclude Include="..\runtime\JSPromiseReaction.h"> - <Filter>runtime</Filter> - </ClInclude> <ClInclude Include="..\runtime\JSPromisePrototype.h"> <Filter>runtime</Filter> </ClInclude> @@ -3069,10 +3310,7 @@ <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\KeywordLookup.lut.h"> <Filter>Derived Sources</Filter> </ClInclude> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\RegExpObject.lut.h"> - <Filter>Derived Sources</Filter> - </ClInclude> - <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\NamePrototype.lut.h"> + <ClInclude Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\SymbolPrototype.lut.h"> <Filter>Derived Sources</Filter> </ClInclude> <ClInclude Include="..\heap\CodeBlockSet.h"> @@ -3081,6 +3319,9 @@ <ClInclude Include="..\bytecode\DeferredCompilationCallback.h"> <Filter>bytecode</Filter> </ClInclude> + <ClInclude Include="..\bytecode\DeferredSourceDump.h"> + <Filter>bytecode</Filter> + </ClInclude> <ClInclude Include="..\dfg\DFGCompilationKey.h"> <Filter>dfg</Filter> </ClInclude> @@ -3108,6 +3349,9 @@ <ClInclude Include="..\runtime\MapData.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\MapDataInlines.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\SetPrototype.h"> <Filter>runtime</Filter> </ClInclude> @@ -3120,9 +3364,6 @@ <ClInclude Include="..\runtime\SetConstructor.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\SetIteratorConstructor.h"> - <Filter>runtime</Filter> - </ClInclude> <ClInclude Include="..\dfg\DFGAbstractHeap.h"> <Filter>dfg</Filter> </ClInclude> @@ -3147,9 +3388,6 @@ <ClInclude Include="..\dfg\DFGArgumentPosition.h"> <Filter>dfg</Filter> </ClInclude> - <ClInclude Include="..\dfg\DFGArgumentsSimplificationPhase.h"> - <Filter>dfg</Filter> - </ClInclude> <ClInclude Include="..\dfg\DFGArrayifySlowPathGenerator.h"> <Filter>dfg</Filter> </ClInclude> @@ -3168,9 +3406,6 @@ <ClInclude Include="..\dfg\DFGBasicBlockInlines.h"> <Filter>dfg</Filter> </ClInclude> - <ClInclude Include="..\dfg\DFGBinarySwitch.h"> - <Filter>dfg</Filter> - </ClInclude> <ClInclude Include="..\dfg\DFGBlockInsertionSet.h"> <Filter>dfg</Filter> </ClInclude> @@ -3225,9 +3460,6 @@ <ClInclude Include="..\dfg\DFGDesiredIdentifiers.h"> <Filter>dfg</Filter> </ClInclude> - <ClInclude Include="..\dfg\DFGDesiredStructureChains.h"> - <Filter>dfg</Filter> - </ClInclude> <ClInclude Include="..\dfg\DFGDesiredTransitions.h"> <Filter>dfg</Filter> </ClInclude> @@ -3315,6 +3547,9 @@ <ClInclude Include="..\dfg\DFGLazyJSValue.h"> <Filter>dfg</Filter> </ClInclude> + <ClInclude Include="..\dfg\DFGLazyNode.h"> + <Filter>dfg</Filter> + </ClInclude> <ClInclude Include="..\dfg\DFGLICMPhase.h"> <Filter>dfg</Filter> </ClInclude> @@ -3459,9 +3694,6 @@ <ClInclude Include="..\dfg\DFGValidate.h"> <Filter>dfg</Filter> </ClInclude> - <ClInclude Include="..\dfg\DFGValueRecoveryOverride.h"> - <Filter>dfg</Filter> - </ClInclude> <ClInclude Include="..\dfg\DFGValueSource.h"> <Filter>dfg</Filter> </ClInclude> @@ -3507,15 +3739,9 @@ <ClInclude Include="..\runtime\ArrayIteratorPrototype.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\ArrayIteratorConstructor.h"> - <Filter>runtime</Filter> - </ClInclude> <ClInclude Include="..\runtime\MapIteratorPrototype.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\MapIteratorConstructor.h"> - <Filter>runtime</Filter> - </ClInclude> <ClInclude Include="..\runtime\Microtask.h"> <Filter>runtime</Filter> </ClInclude> @@ -3534,13 +3760,19 @@ <ClInclude Include="..\runtime\WeakMapConstructor.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\runtime\WeakSetConstructor.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\WeakSetPrototype.h"> + <Filter>runtime</Filter> + </ClInclude> <ClInclude Include="..\runtime\JSWeakMap.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\JSArrayIterator.h"> + <ClInclude Include="..\runtime\JSWeakSet.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\runtime\JSArgumentsIterator.h"> + <ClInclude Include="..\runtime\JSArrayIterator.h"> <Filter>runtime</Filter> </ClInclude> <ClInclude Include="..\runtime\JSMapIterator.h"> @@ -3576,9 +3808,6 @@ <ClInclude Include="..\jit\JITInlineCacheGenerator.h"> <Filter>jit</Filter> </ClInclude> - <ClInclude Include="..\dfg\DFGResurrectionForValidationPhase.h"> - <Filter>dfg</Filter> - </ClInclude> <ClInclude Include="..\dfg\DFGAvailability.h"> <Filter>dfg</Filter> </ClInclude> @@ -3588,18 +3817,9 @@ <ClInclude Include="..\bytecode\CodeBlockJettisoningWatchpoint.h"> <Filter>bytecode</Filter> </ClInclude> - <ClInclude Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.h"> - <Filter>bytecode</Filter> - </ClInclude> <ClInclude Include="..\runtime\StackAlignment.h"> <Filter>runtime</Filter> </ClInclude> - <ClInclude Include="..\heap\DelayedReleaseScope.h"> - <Filter>heap</Filter> - </ClInclude> - <ClInclude Include="..\bytecode\VariableWatchpointSet.h"> - <Filter>bytecode</Filter> - </ClInclude> <ClInclude Include="..\bindings\ScriptFunctionCall.h"> <Filter>bindings</Filter> </ClInclude> @@ -3913,6 +4133,149 @@ <ClInclude Include="..\runtime\MemoryStatistics.h"> <Filter>runtime</Filter> </ClInclude> + <ClInclude Include="..\bytecode\ComplexGetStatus.h"> + <Filter>bytecode</Filter> + </ClInclude> + <ClInclude Include="..\bytecode\ConstantStructureCheck.h"> + <Filter>bytecode</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGDoesGC.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGFrozenValue.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGHeapLocation.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGMayExit.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGPureValue.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGStructureClobberState.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGStructureRegistrationPhase.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGTransition.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGValueStrength.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\runtime\Exception.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\runtime\ExceptionFuzz.h"> + <Filter>runtime</Filter> + </ClInclude> + <ClInclude Include="..\bytecode\ToThisStatus.h"> + <Filter>bytecode</Filter> + </ClInclude> + <ClInclude Include="..\bytecode\CallVariant.h"> + <Filter>bytecode</Filter> + </ClInclude> + <ClInclude Include="..\bytecode\CallEdge.h"> + <Filter>bytecode</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGAvailabilityMap.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGBlockMap.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGBlockMapInlines.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGBlockSet.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGSSACalculator.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGBlockSetInlines.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGBlockWorklist.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGInsertOSRHintsForUpdate.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGNaiveDominators.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGObjectAllocationSinkingPhase.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGObjectMaterializationData.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGPhiChildren.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGPrePostNumbering.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGPromotedHeapLocation.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGPromoteHeapAccess.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\ftl\FTLExitPropertyValue.h"> + <Filter>ftl</Filter> + </ClInclude> + <ClInclude Include="..\ftl\FTLExitTimeObjectMaterialization.h"> + <Filter>ftl</Filter> + </ClInclude> + <ClInclude Include="..\ftl\FTLOperations.h"> + <Filter>ftl</Filter> + </ClInclude> + <ClInclude Include="..\jit\BinarySwitch.h"> + <Filter>jit</Filter> + </ClInclude> + <ClInclude Include="..\dfg\DFGPreciseLocalClobberize.h"> + <Filter>dfg</Filter> + </ClInclude> + <ClInclude Include="..\jit\PolymorphicCallStubRoutine.h"> + <Filter>jit</Filter> + </ClInclude> + <ClInclude Include="..\jit\SetupVarargsFrame.h" /> + <ClInclude Include="..\dfg\DFGPutStackSinkingPhase.h" /> + <ClInclude Include="..\ftl\FTLJSCallBase.h" /> + <ClInclude Include="..\ftl\FTLJSCallVarargs.h" /> + <ClInclude Include="..\runtime\JSCatchScope.h" /> + <ClInclude Include="..\runtime\JSFunctionNameScope.h" /> + <ClInclude Include="..\runtime\MathCommon.h" /> + <ClInclude Include="..\bytecode\BytecodeKills.h" /> + <ClInclude Include="..\bytecode\VariableWriteFireDetail.h" /> + <ClInclude Include="..\dfg\DFGArgumentsEliminationPhase.h" /> + <ClInclude Include="..\dfg\DFGArgumentsUtilities.h" /> + <ClInclude Include="..\dfg\DFGCallCreateDirectArgumentsSlowPathGenerator.h" /> + <ClInclude Include="..\dfg\DFGCleanUpPhase.h" /> + <ClInclude Include="..\dfg\DFGEpoch.h" /> + <ClInclude Include="..\dfg\DFGForAllKills.h" /> + <ClInclude Include="..\dfg\DFGMovHintRemovalPhase.h" /> + <ClInclude Include="..\dfg\DFGPhantomInsertionPhase.h" /> + <ClInclude Include="..\dfg\DFGVarargsForwardingPhase.h" /> + <ClInclude Include="..\jit\ExecutableAllocationFuzz.h" /> + <ClInclude Include="..\runtime\ArgumentsMode.h" /> + <ClInclude Include="..\runtime\ClonedArguments.h" /> + <ClInclude Include="..\runtime\DirectArguments.h" /> + <ClInclude Include="..\runtime\DirectArgumentsOffset.h" /> + <ClInclude Include="..\runtime\GenericArguments.h" /> + <ClInclude Include="..\runtime\GenericArgumentsInlines.h" /> + <ClInclude Include="..\runtime\GenericOffset.h" /> + <ClInclude Include="..\runtime\InferredValue.h" /> + <ClInclude Include="..\runtime\ScopeOffset.h" /> + <ClInclude Include="..\runtime\ScopedArguments.h" /> + <ClInclude Include="..\runtime\ScopedArgumentsTable.h" /> + <ClInclude Include="..\runtime\TypeofType.h" /> + <ClInclude Include="..\runtime\VarOffset.h" /> </ItemGroup> <ItemGroup> <None Include="JavaScriptCorePreLink.cmd" /> @@ -3921,6 +4284,177 @@ <None Include="..\bytecode\BytecodeList.json"> <Filter>bytecode</Filter> </None> + <None Include="..\inspector\scripts\cssmin.py"> + <Filter>inspector\scripts</Filter> + </None> + <None Include="..\inspector\scripts\generate-combined-inspector-json.py"> + <Filter>inspector\scripts</Filter> + </None> + <None Include="..\inspector\scripts\generate-inspector-protocol-bindings.py"> + <Filter>inspector\scripts</Filter> + </None> + <None Include="..\inspector\scripts\inline-and-minify-stylesheets-and-scripts.py"> + <Filter>inspector\scripts</Filter> + </None> + <None Include="..\inspector\scripts\jsmin.py"> + <Filter>inspector\scripts</Filter> + </None> + <None Include="..\inspector\scripts\xxd.pl"> + <Filter>inspector\scripts</Filter> + </None> + <None Include="..\inspector\scripts\codegen\__init__.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\cpp_generator.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\cpp_generator_templates.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_cpp_backend_dispatcher_header.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_cpp_backend_dispatcher_implementation.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_cpp_frontend_dispatcher_header.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_cpp_frontend_dispatcher_implementation.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_cpp_protocol_types_header.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_cpp_protocol_types_implementation.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generate_js_backend_commands.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generator.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\generator_templates.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\codegen\models.py"> + <Filter>inspector\scripts\codegen</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\commands-with-async-attribute.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\commands-with-optional-call-return-parameters.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\domains-with-varying-command-sizes.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\events-with-optional-parameters.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-duplicate-type-declarations.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-enum-with-no-values.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-string-typed-optional-parameter-flag.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-string-typed-optional-type-member.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-type-declaration-using-type-reference.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-type-with-lowercase-name.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-unknown-type-reference-in-type-declaration.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\fail-on-unknown-type-reference-in-type-member.json-error"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\same-type-id-different-domain.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\shadowed-optional-type-setters.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\type-declaration-aliased-primitive-type.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\type-declaration-array-type.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\type-declaration-enum-type.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\type-declaration-object-type.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\expected\type-requiring-runtime-casts.json-result"> + <Filter>inspector\scripts\tests\expected</Filter> + </None> + <None Include="..\inspector\scripts\tests\commands-with-async-attribute.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\commands-with-optional-call-return-parameters.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\domains-with-varying-command-sizes.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\events-with-optional-parameters.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-duplicate-type-declarations.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-enum-with-no-values.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-string-typed-optional-parameter-flag.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-string-typed-optional-type-member.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-type-declaration-using-type-reference.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-type-with-lowercase-name.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-unknown-type-reference-in-type-declaration.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\fail-on-unknown-type-reference-in-type-member.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\same-type-id-different-domain.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\shadowed-optional-type-setters.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\type-declaration-aliased-primitive-type.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\type-declaration-array-type.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\type-declaration-enum-type.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\type-declaration-object-type.json"> + <Filter>inspector\scripts\tests</Filter> + </None> + <None Include="..\inspector\scripts\tests\type-requiring-runtime-casts.json"> + <Filter>inspector\scripts\tests</Filter> + </None> </ItemGroup> <ItemGroup> <MASM Include="$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\$(ProjectName)\DerivedSources\LowLevelInterpreterWin.asm"> @@ -3930,4 +4464,4 @@ <Filter>jit</Filter> </MASM> </ItemGroup> -</Project> \ No newline at end of file +</Project> diff --git a/JavaScriptCore.vcxproj/JavaScriptCoreCommon.props b/JavaScriptCore.vcxproj/JavaScriptCoreCommon.props index 9b00e4f..6954c3d 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCoreCommon.props +++ b/JavaScriptCore.vcxproj/JavaScriptCoreCommon.props @@ -5,8 +5,10 @@ <PropertyGroup /> <ItemDefinitionGroup> <ClCompile> + <DisableSpecificWarnings>4611;%(DisableSpecificWarnings)</DisableSpecificWarnings> <AdditionalIncludeDirectories>..\;..\tools\;..\runtime\;..\llint\;..\jit\;..\disassembler\;..\heap\;..\debugger\;..\assembler\;..\profiler\;..\yarr\;..\interpreter\;..\bytecode\;..\builtins\;..\dfg\;..\bytecompiler\;..\parser\;..\API\;..\ftl\;..\bindings\;..\inspector\;..\ftl;..\llvm;..\llvm\library;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\JavaScriptCore\DerivedSources\;$(ConfigurationBuildDir)\include\;$(ConfigurationBuildDir)\include\JavaScriptCore\;$(ConfigurationBuildDir)\include\private\;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <ForcedIncludeFiles>ICUVersion.h;%(ForcedIncludeFiles)</ForcedIncludeFiles> + <DisableSpecificWarnings>4611;%(DisableSpecificWarnings)</DisableSpecificWarnings> </ClCompile> <Link> <AdditionalDependencies>winmm.lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;WTF$(DebugSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies> @@ -16,4 +18,4 @@ </Link> </ItemDefinitionGroup> <ItemGroup /> -</Project> \ No newline at end of file +</Project> diff --git a/JavaScriptCore.vcxproj/JavaScriptCoreDLL.cpp b/JavaScriptCore.vcxproj/JavaScriptCoreDLL.cpp new file mode 100644 index 0000000..779e1b8 --- /dev/null +++ b/JavaScriptCore.vcxproj/JavaScriptCoreDLL.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (C) 2015 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 <Windows.h> +#include <math.h> + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: +#if defined(_M_X64) || defined(__x86_64__) + // The VS2013 runtime has a bug where it mis-detects AVX-capable processors + // if the feature has been disabled in firmware. This causes us to crash + // in some of the math functions. For now, we disable those optimizations + // because Microsoft is not going to fix the problem in VS2013. + // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+. + _set_FMA3_enable(0); +#endif + break; + + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make b/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make index 78a514e..8868e40 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make +++ b/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.make @@ -1,12 +1,12 @@ all: - touch "%ConfigurationBuildDir%\buildfailed" - perl build-generated-files.pl "%ConfigurationBuildDir%" "$(WEBKIT_LIBRARIES)" "%PlatformArchitecture%" - copy-files.cmd + @type NUL > "%ConfigurationBuildDir%\buildfailed" + @perl build-generated-files.pl "%ConfigurationBuildDir%" "$(WEBKIT_LIBRARIES)" "%PlatformArchitecture%" + @copy-files.cmd - -del "%ConfigurationBuildDir%\include\private\JavaScriptCore\stdbool.h" "%ConfigurationBuildDir%\include\private\JavaScriptCore\stdint.h" - -del "%ConfigurationBuildDir%\buildfailed" + -@del "%ConfigurationBuildDir%\include\private\JavaScriptCore\stdbool.h" "%ConfigurationBuildDir%\include\private\JavaScriptCore\stdint.h" >nul 2>nul + -@del "%ConfigurationBuildDir%\buildfailed" clean: - -del "%ConfigurationBuildDir%\buildfailed" + -@del "%ConfigurationBuildDir%\buildfailed" copy-files.cmd clean - -del /s /q "%ConfigurationBuildDir%\obj%PlatformArchitecture%\JavaScriptCore\DerivedSources" + -@del /s /q "%ConfigurationBuildDir%\obj%PlatformArchitecture%\JavaScriptCore\DerivedSources" diff --git a/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj b/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj index 3275c40..c03de34 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj +++ b/JavaScriptCore.vcxproj/JavaScriptCoreGenerated.vcxproj @@ -64,7 +64,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -84,17 +84,17 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -114,7 +114,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -223,4 +223,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/JavaScriptCore.vcxproj/JavaScriptCorePostBuild.cmd b/JavaScriptCore.vcxproj/JavaScriptCorePostBuild.cmd index 8b0a3a4..b4d17c7 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCorePostBuild.cmd +++ b/JavaScriptCore.vcxproj/JavaScriptCorePostBuild.cmd @@ -1,2 +1,2 @@ -if exist "%WEBKIT_LIBRARIES%\tools\VersionStamper\VersionStamper.exe" "%WEBKIT_LIBRARIES%\tools\VersionStamper\VersionStamper.exe" --verbose "%TARGETPATH%" +perl "%WEBKIT_LIBRARIES%\tools\scripts\version-stamp.pl" "%INTDIR%" "%TARGETPATH%" if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd b/JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd index 72ab16a..b8cf878 100644 --- a/JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd +++ b/JavaScriptCore.vcxproj/JavaScriptCorePreBuild.cmd @@ -1,6 +1,8 @@ -%SystemDrive%\cygwin\bin\which.exe perl +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% cmd /c if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" if errorlevel 1 exit 1 echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" + +perl "%WEBKIT_LIBRARIES%\tools\scripts\auto-version.pl" "%INTDIR%" diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make b/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make index 5aff3ba..6da9beb 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make +++ b/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.make @@ -1,5 +1,5 @@ all: - touch "%ConfigurationBuildDir%\buildfailed" + @type NUL > "%ConfigurationBuildDir%\buildfailed" perl build-LLIntAssembly.pl "%ConfigurationBuildDir%" "$(WEBKIT_LIBRARIES)" "$(DEBUGSUFFIX)" "%PlatformArchitecture%" -del "%ConfigurationBuildDir%\buildfailed" diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj b/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj index 3f705e0..9b0f13a 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj +++ b/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/LLIntAssembly.vcxproj @@ -58,7 +58,7 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -74,7 +74,7 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -82,7 +82,7 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -98,7 +98,7 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -280,4 +280,4 @@ nmake /nologo -f $(ProjectName).make DEBUGSUFFIX=_debug</NMakeReBuildCommandLine <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl b/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl index 7afe748..6f43c95 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl +++ b/JavaScriptCore.vcxproj/LLInt/LLIntAssembly/build-LLIntAssembly.pl @@ -67,4 +67,4 @@ my $OUTPUTFILENAME = File::Spec->catfile($DERIVED_SOURCES_DIR, 'LowLevelInterpre my $offlineAsm = File::Spec->catfile($XSRCROOT, 'offlineasm', 'asm.rb'); my $lowLevelInterpreter = File::Spec->catfile($XSRCROOT, 'llint', 'LowLevelInterpreter.asm'); my $offsetsExtractor = File::Spec->catfile($BUILD_PRODUCTS_DIR, 'LLIntOffsetsExtractor', "LLIntOffsetsExtractor$ARGV[2].exe"); -system('/usr/bin/env', 'ruby', $offlineAsm, '-I.', $lowLevelInterpreter, $offsetsExtractor, $OUTPUTFILENAME) and die "Failed to generate $OUTPUTFILENAME: $!"; +system('ruby', $offlineAsm, '-I.', $lowLevelInterpreter, $offsetsExtractor, $OUTPUTFILENAME) and die "Failed to generate $OUTPUTFILENAME: $!"; diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make b/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make index e6bdb85..b2447b0 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make +++ b/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.make @@ -1,5 +1,5 @@ all: - touch "%ConfigurationBuildDir%\buildfailed" + @type NUL > "%ConfigurationBuildDir%\buildfailed" perl build-LLIntDesiredOffsets.pl "%ConfigurationBuildDir%" "$(WEBKIT_LIBRARIES)" "%PlatformArchitecture%" -del "%ConfigurationBuildDir%\buildfailed" diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj b/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj index 16f783f..b7796b4 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj +++ b/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/LLIntDesiredOffsets.vcxproj @@ -58,7 +58,7 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -74,7 +74,7 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -82,7 +82,7 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -98,7 +98,7 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> <ConfigurationType>Makefile</ConfigurationType> @@ -266,4 +266,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl b/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl index 84cb438..c6f5efc 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl +++ b/JavaScriptCore.vcxproj/LLInt/LLIntDesiredOffsets/build-LLIntDesiredOffsets.pl @@ -55,4 +55,4 @@ unless (-d $BUILD_PRODUCTS_DIR) { my $generateOffsetExtractor = File::Spec->catfile($XSRCROOT, 'offlineasm', 'generate_offset_extractor.rb'); my $lowLevelInterpreter = File::Spec->catfile($XSRCROOT, 'llint', 'LowLevelInterpreter.asm'); my $OUTPUTFILENAME = File::Spec->catfile($BUILD_PRODUCTS_DIR, 'LLIntDesiredOffsets.h'); -system('/usr/bin/env', 'ruby', $generateOffsetExtractor, "-I$BUILD_PRODUCTS_DIR", $lowLevelInterpreter, $OUTPUTFILENAME) and die "Failed to generate $OUTPUTFILENAME: $!"; +system('ruby', $generateOffsetExtractor, "-I$BUILD_PRODUCTS_DIR", $lowLevelInterpreter, $OUTPUTFILENAME) and die "Failed to generate $OUTPUTFILENAME: $!"; diff --git a/JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj b/JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj index bf1b1a3..2a24278 100644 --- a/JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj +++ b/JavaScriptCore.vcxproj/LLInt/LLIntOffsetsExtractor/LLIntOffsetsExtractor.vcxproj @@ -61,7 +61,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> @@ -81,7 +81,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> @@ -101,7 +101,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> @@ -111,7 +111,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> diff --git a/JavaScriptCore.vcxproj/build-generated-files.pl b/JavaScriptCore.vcxproj/build-generated-files.pl index 7bd1316..2415c1f 100755 --- a/JavaScriptCore.vcxproj/build-generated-files.pl +++ b/JavaScriptCore.vcxproj/build-generated-files.pl @@ -49,10 +49,10 @@ for (@ARGV) { s/\"$//; } -my $XDSTROOT = $ARGV[0]; +my $XDSTROOT = Cwd::realpath($ARGV[0]); $ENV{'XDSTROOT'} = $XDSTROOT; -my $SDKROOT = $ARGV[1]; +my $SDKROOT = Cwd::realpath($ARGV[1]); $ENV{'SDKROOT'} = $SDKROOT; my $BUILD_PRODUCTS_DIR = File::Spec->catdir($XDSTROOT, "obj$ARGV[2]", 'JavaScriptCore'); @@ -65,9 +65,13 @@ unless (-d $DERIVED_SOURCES_DIR) { chdir $DERIVED_SOURCES_DIR or die "Couldn't change directory to $DERIVED_SOURCES_DIR: $!"; +my $featureDefinesCommand = File::Spec->catfile($SDKROOT, 'tools', 'scripts', 'feature-defines.pl'); +my $featureDefines = `$featureDefinesCommand $SDKROOT windows`; +chomp($featureDefines); +$ENV{'FEATURE_DEFINES'} = $featureDefines; + $ENV{'JavaScriptCore'} = $XSRCROOT; $ENV{'DFTABLES_EXTENSION'} = '.exe'; my $DERIVED_SOURCES_MAKEFILE = File::Spec->catfile($XSRCROOT, 'DerivedSources.make'); - -system('/usr/bin/make', '-f', $DERIVED_SOURCES_MAKEFILE, '-j', $NUMCPUS) and die "Failed to build $DERIVED_SOURCES_MAKEFILE: $!"; +system('make', '-f', $DERIVED_SOURCES_MAKEFILE, '-j', $NUMCPUS) and die "Failed to build $DERIVED_SOURCES_MAKEFILE: $!"; diff --git a/JavaScriptCore.vcxproj/copy-files.cmd b/JavaScriptCore.vcxproj/copy-files.cmd index 535e27b..a245c3e 100755 --- a/JavaScriptCore.vcxproj/copy-files.cmd +++ b/JavaScriptCore.vcxproj/copy-files.cmd @@ -9,7 +9,7 @@ if "%1" EQU "clean" goto :clean if "%1" EQU "rebuild" call :clean echo Copying public headers... -mkdir "%PublicHeadersDirectory%" 2>NUL +@mkdir "%PublicHeadersDirectory%" 2>NUL for %%f in ( APICast.h APIShims.h @@ -33,7 +33,7 @@ for %%f in ( OpaqueJSString.h WebKitAvailability.h ) do ( - xcopy /y /d ..\API\%%f "%PublicHeadersDirectory%" >NUL + @xcopy /y /d ..\API\%%f "%PublicHeadersDirectory%" >NUL ) echo Copying private headers... @@ -58,45 +58,50 @@ for %%d in ( runtime yarr ) do ( - xcopy /y /d ..\%%d\*.h "%PrivateHeadersDirectory%" >NUL + @xcopy /y /d ..\%%d\*.h "%PrivateHeadersDirectory%" >NUL ) echo Copying Inspector scripts as if they were private headers... for %%d in ( inspector\scripts + inspector\scripts\codegen ) do ( - xcopy /y /d ..\%%d\* "%PrivateHeadersDirectory%" >NUL + @xcopy /y /d ..\%%d\* "%PrivateHeadersDirectory%" >NUL ) echo Copying Inspector generated files as if they were private headers... -xcopy /y "%DerivedSourcesDirectory%\InspectorJS.json" "%PrivateHeadersDirectory%" >NUL -xcopy /y "%DerivedSourcesDirectory%\InspectorJSTypeBuilders.h" "%PrivateHeadersDirectory%" >NUL -xcopy /y "%DerivedSourcesDirectory%\InspectorJSBackendDispatchers.h" "%PrivateHeadersDirectory%" >NUL -xcopy /y "%DerivedSourcesDirectory%\InspectorJSFrontendDispatchers.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\CombinedDomains.json" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\InspectorProtocolObjects.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\InspectorBackendDispatchers.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\InspectorFrontendDispatchers.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\InspectorBackendCommands.js" "%PrivateHeadersDirectory%" >NUL echo Copying Web Replay scripts as if they were private headers... for %%d in ( replay\scripts ) do ( - xcopy /y /d ..\%%d\* "%PrivateHeadersDirectory%" >NUL + @xcopy /y /d ..\%%d\* "%PrivateHeadersDirectory%" >NUL ) echo Copying Web Replay generated headers as if they were private headers... -xcopy /y "%DerivedSourcesDirectory%\JSReplayInputs.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\JSReplayInputs.h" "%PrivateHeadersDirectory%" >NUL + +echo Copying Web Replay specification files as if they were private headers... +@xcopy /y /d ..\replay\*.json "%PrivateHeadersDirectory%" >NUL echo Copying builtins header as if it were a private header... -xcopy /y "%DerivedSourcesDirectory%\JSCBuiltins.h" "%PrivateHeadersDirectory%" >NUL -xcopy /y "%DerivedSourcesDirectory%\Bytecodes.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\JSCBuiltins.h" "%PrivateHeadersDirectory%" >NUL +@xcopy /y "%DerivedSourcesDirectory%\Bytecodes.h" "%PrivateHeadersDirectory%" >NUL echo Copying resources... -mkdir "%ResourcesDirectory%" 2>NUL -xcopy /y /d JavaScriptCore.resources\* "%ResourcesDirectory%" >NUL +@mkdir "%ResourcesDirectory%" 2>NUL +@xcopy /y /d JavaScriptCore.resources\* "%ResourcesDirectory%" >NUL goto :EOF :clean echo Deleting copied files... -if exist "%PublicHeadersDirectory%" rmdir /s /q "%PublicHeadersDirectory%" >NUL -if exist "%PrivateHeadersDirectory%" rmdir /s /q "%PrivateHeadersDirectory%" >NUL -if exist "%ResourcesDirectory%" rmdir /s /q "%ResourcesDirectory%" >NUL +@if exist "%PublicHeadersDirectory%" rmdir /s /q "%PublicHeadersDirectory%" >NUL 2>NUL +@if exist "%PrivateHeadersDirectory%" rmdir /s /q "%PrivateHeadersDirectory%" >NUL 2>NUL +@if exist "%ResourcesDirectory%" rmdir /s /q "%ResourcesDirectory%" >NUL 2>NUL diff --git a/JavaScriptCore.vcxproj/jsc/DLLLauncherMain.cpp b/JavaScriptCore.vcxproj/jsc/DLLLauncherMain.cpp new file mode 100644 index 0000000..e2359a2 --- /dev/null +++ b/JavaScriptCore.vcxproj/jsc/DLLLauncherMain.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This file contains code for a launcher executable for WebKit apps. When compiled into foo.exe, it +// will set PATH so that Apple Application Support DLLs can be found, then will load foo.dll and +// call its dllLauncherEntryPoint function, which should be declared like so: +// extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstCmdLine, int nCmdShow); +// If USE_CONSOLE_ENTRY_POINT is defined, this function will be called instead: +// extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, const char* argv[]); + +#include <shlwapi.h> +#include <string> +#include <vector> +#include <windows.h> + +using namespace std; + +#if defined _M_IX86 +#define PROCESSORARCHITECTURE "x86" +#elif defined _M_IA64 +#define PROCESSORARCHITECTURE "ia64" +#elif defined _M_X64 +#define PROCESSORARCHITECTURE "amd64" +#else +#define PROCESSORARCHITECTURE "*" +#endif + +#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='" PROCESSORARCHITECTURE "' publicKeyToken='6595b64144ccf1df' language='*'\"") +#if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(WIN_CAIRO) +#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.VC80.CRT' version='8.0.50727.6195' processorArchitecture='" PROCESSORARCHITECTURE "' publicKeyToken='1fc8b3b9a1e18e3b' language='*'\"") +#endif + +static void enableTerminationOnHeapCorruption() +{ + // Enable termination on heap corruption on OSes that support it (Vista and XPSP3). + // http://msdn.microsoft.com/en-us/library/aa366705(VS.85).aspx + + HEAP_INFORMATION_CLASS heapEnableTerminationOnCorruption = static_cast<HEAP_INFORMATION_CLASS>(1); + + HMODULE module = ::GetModuleHandleW(L"kernel32.dll"); + if (!module) + return; + + typedef BOOL (WINAPI*HSI)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); + HSI heapSetInformation = reinterpret_cast<HSI>(::GetProcAddress(module, "HeapSetInformation")); + if (!heapSetInformation) + return; + + heapSetInformation(0, heapEnableTerminationOnCorruption, 0, 0); +} + +static wstring getStringValue(HKEY key, const wstring& valueName) +{ + DWORD type = 0; + DWORD bufferSize = 0; + if (::RegQueryValueExW(key, valueName.c_str(), 0, &type, 0, &bufferSize) != ERROR_SUCCESS || type != REG_SZ) + return wstring(); + + vector<wchar_t> buffer(bufferSize / sizeof(wchar_t)); + if (::RegQueryValueExW(key, valueName.c_str(), 0, &type, reinterpret_cast<LPBYTE>(&buffer[0]), &bufferSize) != ERROR_SUCCESS) + return wstring(); + + return &buffer[0]; +} + +static wstring applePathFromRegistry(const wstring& key, const wstring& value) +{ + HKEY applePathKey = 0; + if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_READ, &applePathKey) != ERROR_SUCCESS) + return wstring(); + wstring path = getStringValue(applePathKey, value); + ::RegCloseKey(applePathKey); + return path; +} + +static wstring appleApplicationSupportDirectory() +{ + return applePathFromRegistry(L"SOFTWARE\\Apple Inc.\\Apple Application Support", L"InstallDir"); +} + +static wstring copyEnvironmentVariable(const wstring& variable) +{ + DWORD length = ::GetEnvironmentVariableW(variable.c_str(), 0, 0); + if (!length) + return wstring(); + vector<wchar_t> buffer(length); + if (!GetEnvironmentVariable(variable.c_str(), &buffer[0], buffer.size()) || !buffer[0]) + return wstring(); + return &buffer[0]; +} + +static bool prependPath(const wstring& directoryToPrepend) +{ + wstring pathVariable = L"PATH"; + wstring oldPath = copyEnvironmentVariable(pathVariable); + wstring newPath = directoryToPrepend + L';' + oldPath; + return ::SetEnvironmentVariableW(pathVariable.c_str(), newPath.c_str()); +} + +static int fatalError(const wstring& programName, const wstring& message) +{ + wstring caption = programName + L" can't open."; + ::MessageBoxW(0, message.c_str(), caption.c_str(), MB_ICONERROR); + return 1; +} + +static bool directoryExists(const wstring& path) +{ + DWORD attrib = ::GetFileAttributes(path.c_str()); + + return ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY)); +} + +static bool modifyPath(const wstring& programName) +{ +#ifdef WIN_CAIRO + +#if defined(_M_X64) + wstring pathWinCairo = copyEnvironmentVariable(L"WEBKIT_LIBRARIES") + L"\\bin64"; +#else + wstring pathWinCairo = copyEnvironmentVariable(L"WEBKIT_LIBRARIES") + L"\\bin32"; +#endif + prependPath(pathWinCairo); + return true; + +#else + + const wstring& pathPrefix = appleApplicationSupportDirectory(); + + if (!directoryExists(pathPrefix)) { + fatalError(programName, L"Failed to determine path to AAS directory."); + return false; + } + + if (prependPath(pathPrefix)) + return true; + + fatalError(programName, L"Failed to modify PATH environment variable."); + return false; +#endif +} + +static wstring getLastErrorString(HRESULT hr) +{ + static const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; + static const size_t bufSize = 4096; + + wchar_t errorMessage[bufSize]; + DWORD len = ::FormatMessageW(kFlags, 0, hr, 0, errorMessage, bufSize, 0); + if (len >= bufSize) + len = bufSize - 1; + + errorMessage[len] = 0; + + return errorMessage; +} + +#if USE_CONSOLE_ENTRY_POINT +int main(int argc, const char* argv[]) +#else +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpstrCmdLine, int nCmdShow) +#endif +{ +#if defined(_M_X64) || defined(__x86_64__) + // The VS2013 runtime has a bug where it mis-detects AVX-capable processors + // if the feature has been disabled in firmware. This causes us to crash + // in some of the math functions. For now, we disable those optimizations + // because Microsoft is not going to fix the problem in VS2013. + // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+. + _set_FMA3_enable(0); +#endif + + enableTerminationOnHeapCorruption(); + + // Get the path of our executable. + wchar_t exePath[MAX_PATH]; + if (!::GetModuleFileNameW(0, exePath, _countof(exePath))) + return fatalError(L"Unknown Program", L"Failed to determine name of executable: " + getLastErrorString(::GetLastError())); + + ::PathRemoveExtensionW(exePath); + + wstring programName = ::PathFindFileNameW(exePath); + + if (!modifyPath(programName)) + return 1; + + // Load our corresponding DLL. + wstring dllName = programName + L".dll"; + if (!::PathRemoveFileSpecW(exePath)) + return fatalError(programName, L"::PathRemoveFileSpecW failed: " + getLastErrorString(::GetLastError())); + if (!::PathAppendW(exePath, dllName.c_str())) + return fatalError(programName, L"::PathAppendW failed: " + getLastErrorString(::GetLastError())); + HMODULE module = ::LoadLibraryW(exePath); + if (!module) + return fatalError(programName, L"::LoadLibraryW failed: \npath=" + wstring(exePath) + L"\n" + getLastErrorString(::GetLastError())); + +#if USE_CONSOLE_ENTRY_POINT + typedef int (WINAPI*EntryPoint)(int, const char*[]); +#if defined _M_AMD64 || defined _WIN64 + const char* entryPointName = "dllLauncherEntryPoint"; +#else + const char* entryPointName = "_dllLauncherEntryPoint@8"; +#endif +#else + typedef int (WINAPI*EntryPoint)(HINSTANCE, HINSTANCE, LPWSTR, int); +#if defined _M_AMD64 || defined _WIN64 + const char* entryPointName = "dllLauncherEntryPoint"; +#else + const char* entryPointName = "_dllLauncherEntryPoint@16"; +#endif +#endif + + EntryPoint entryPoint = reinterpret_cast<EntryPoint>(::GetProcAddress(module, entryPointName)); + if (!entryPoint) + return fatalError(programName, L"Failed to find dllLauncherEntryPoint function: " + getLastErrorString(::GetLastError())); + +#if USE_CONSOLE_ENTRY_POINT + return entryPoint(argc, argv); +#else + return entryPoint(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow); +#endif +} diff --git a/JavaScriptCore.vcxproj/jsc/DLLLauncherWinCairo.props b/JavaScriptCore.vcxproj/jsc/DLLLauncherWinCairo.props new file mode 100644 index 0000000..dd13fbc --- /dev/null +++ b/JavaScriptCore.vcxproj/jsc/DLLLauncherWinCairo.props @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ImportGroup Label="PropertySheets" /> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup> + <ClCompile> + <PreprocessorDefinitions>WIN_CAIRO;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup /> +</Project> \ No newline at end of file diff --git a/JavaScriptCore.vcxproj/jsc/jsc.vcxproj b/JavaScriptCore.vcxproj/jsc/jsc.vcxproj index a829c05..921dcf5 100644 --- a/JavaScriptCore.vcxproj/jsc/jsc.vcxproj +++ b/JavaScriptCore.vcxproj/jsc/jsc.vcxproj @@ -57,73 +57,73 @@ </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> @@ -182,18 +182,42 @@ <Import Project="jscProduction.props" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <PrecompiledHeader> diff --git a/JavaScriptCore.vcxproj/jsc/jscCommon.props b/JavaScriptCore.vcxproj/jsc/jscCommon.props index 8545424..3abbdf6 100644 --- a/JavaScriptCore.vcxproj/jsc/jscCommon.props +++ b/JavaScriptCore.vcxproj/jsc/jscCommon.props @@ -8,11 +8,11 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalIncludeDirectories>..\..\;..\..\tools\;..\..\runtime\;..\..\llint\;..\..\jit\;..\..\disassembler\;..\..\heap\;..\..\debugger\;..\..\assembler\;..\..\profiler\;..\..\interpreter\;..\..\bytecode\;..\..\dfg\;..\..\bytecompiler\;..\..\parser\;..\..\API\;$(ConfigurationBuildDir)\include\;$(ConfigurationBuildDir)\include\private\;$(ConfigurationBuildDir)\include\JavaScriptCore\;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\JavaScriptCore\DerivedSources\;$(WebKit_Libraries)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>USE_CONSOLE_ENTRY_POINT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ForcedIncludeFiles>ICUVersion.h</ForcedIncludeFiles> </ClCompile> <Link> - <AdditionalDependencies>WTF$(DebugSuffix).lib;JavaScriptCore$(DebugSuffix).lib;winmm.lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>WTF$(DebugSuffix).lib;JavaScriptCore$(DebugSuffix).lib;winmm.lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <ModuleDefinitionFile> </ModuleDefinitionFile> <SubSystem>Console</SubSystem> diff --git a/JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj b/JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj new file mode 100644 index 0000000..05a5b46 --- /dev/null +++ b/JavaScriptCore.vcxproj/jsc/jscLauncher.vcxproj @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="DebugSuffix|Win32"> + <Configuration>DebugSuffix</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="DebugSuffix|x64"> + <Configuration>DebugSuffix</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_WinCairo|Win32"> + <Configuration>Debug_WinCairo</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_WinCairo|x64"> + <Configuration>Debug_WinCairo</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Production|Win32"> + <Configuration>Production</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Production|x64"> + <Configuration>Production</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_WinCairo|Win32"> + <Configuration>Release_WinCairo</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_WinCairo|x64"> + <Configuration>Release_WinCairo</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{FE09F693-9744-4D73-A17C-DE3209EB1905}</ProjectGuid> + <RootNamespace>jscLauncher</RootNamespace> + <Keyword>Win32Proj</Keyword> + <ProjectName>jscLauncher</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscRelease.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscRelease.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscRelease.props" /> + <Import Project="DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscRelease.props" /> + <Import Project="DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscProduction.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscProduction.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscDebug.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscDebug.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscDebug.props" /> + <Import Project="DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscDebug.props" /> + <Import Project="DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscDebug.props" /> + <Import Project="$(WebKit_Libraries)\tools\vsprops\debugsuffix.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="jscDebug.props" /> + <Import Project="$(WebKit_Libraries)\tools\vsprops\debugsuffix.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Production|x64'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">jsc$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">jsc$(DebugSuffix)</TargetName> + </PropertyGroup> + <ItemDefinitionGroup> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="DLLLauncherMain.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="jscLauncherPostBuild.cmd" /> + <None Include="jscLauncherPreBuild.cmd" /> + <None Include="jscLauncherPreLink.cmd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/JavaScriptCore.vcxproj/jsc/jscLauncherPostBuild.cmd b/JavaScriptCore.vcxproj/jsc/jscLauncherPostBuild.cmd new file mode 100644 index 0000000..02da44b --- /dev/null +++ b/JavaScriptCore.vcxproj/jsc/jscLauncherPostBuild.cmd @@ -0,0 +1 @@ +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" \ No newline at end of file diff --git a/JavaScriptCore.vcxproj/jsc/jscLauncherPreBuild.cmd b/JavaScriptCore.vcxproj/jsc/jscLauncherPreBuild.cmd new file mode 100644 index 0000000..4e5ccc5 --- /dev/null +++ b/JavaScriptCore.vcxproj/jsc/jscLauncherPreBuild.cmd @@ -0,0 +1,6 @@ +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul +if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% +cmd /c +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" +if errorlevel 1 exit 1 +echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.vcxproj/jsc/jscLauncherPreLink.cmd b/JavaScriptCore.vcxproj/jsc/jscLauncherPreLink.cmd new file mode 100644 index 0000000..e69de29 diff --git a/JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd b/JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd index 72ab16a..4e5ccc5 100644 --- a/JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd +++ b/JavaScriptCore.vcxproj/jsc/jscPreBuild.cmd @@ -1,4 +1,4 @@ -%SystemDrive%\cygwin\bin\which.exe perl +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% cmd /c if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj b/JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj index 00897fd..9c8bec1 100644 --- a/JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj +++ b/JavaScriptCore.vcxproj/libllvmForJSC/libllvmForJSC.vcxproj @@ -61,12 +61,12 @@ <ConfigurationType>DynamicLibrary</ConfigurationType> <CharacterSet>Unicode</CharacterSet> <WholeProgramOptimization>true</WholeProgramOptimization> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> @@ -77,7 +77,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'"> <ConfigurationType>DynamicLibrary</ConfigurationType> @@ -89,7 +89,7 @@ </PropertyGroup> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Production|Win32'"> <ConfigurationType>DynamicLibrary</ConfigurationType> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'"> <ConfigurationType>DynamicLibrary</ConfigurationType> diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj b/JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj index dc7805b..337b235 100644 --- a/JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj +++ b/JavaScriptCore.vcxproj/testRegExp/testRegExp.vcxproj @@ -58,73 +58,73 @@ </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> @@ -183,18 +183,42 @@ <Import Project="testRegExpProduction.props" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'"> + <TargetExt>.dll</TargetExt> + </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <PrecompiledHeader> diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props b/JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props index b35061d..eddf98b 100644 --- a/JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props +++ b/JavaScriptCore.vcxproj/testRegExp/testRegExpCommon.props @@ -5,11 +5,11 @@ <PropertyGroup /> <ItemDefinitionGroup> <ClCompile> - <PreprocessorDefinitions>_CONSOLE;__STD_C;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>USE_CONSOLE_ENTRY_POINT;_CONSOLE;__STD_C;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ConfigurationBuildDir)\obj$(PlatformArchitecture)\JavaScriptCore\DerivedSources;..\..\;..\..\assembler;..\..\API;..\..\parser;..\..\heap;..\..\runtime;..\..\bytecode;..\..\interpreter;..\..\debugger;..\..\bytecompiler;..\..\profiler;..\..\jit;$(WebKit_Libraries)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> - <AdditionalDependencies>JavaScriptCore$(DebugSuffix).lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;WTF$(DebugSuffix).lib;winmm.lib;user32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>JavaScriptCore$(DebugSuffix).lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;WTF$(DebugSuffix).lib;winmm.lib;user32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <SubSystem>Console</SubSystem> </Link> </ItemDefinitionGroup> diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj new file mode 100644 index 0000000..a6509a4 --- /dev/null +++ b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncher.vcxproj @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="DebugSuffix|Win32"> + <Configuration>DebugSuffix</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="DebugSuffix|x64"> + <Configuration>DebugSuffix</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_WinCairo|Win32"> + <Configuration>Debug_WinCairo</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_WinCairo|x64"> + <Configuration>Debug_WinCairo</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Production|Win32"> + <Configuration>Production</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Production|x64"> + <Configuration>Production</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_WinCairo|Win32"> + <Configuration>Release_WinCairo</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_WinCairo|x64"> + <Configuration>Release_WinCairo</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{1B8A5CB0-D0CF-4458-8247-8FBA5C6EA20F}</ProjectGuid> + <RootNamespace>testRegExpLauncher</RootNamespace> + <Keyword>Win32Proj</Keyword> + <ProjectName>testRegExpLauncher</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpRelease.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpRelease.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpRelease.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpRelease.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpProduction.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpProduction.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpDebug.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpDebug.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpDebug.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpDebug.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpDebug.props" /> + <Import Project="$(WebKit_Libraries)\tools\vsprops\debugsuffix.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testRegExpDebug.props" /> + <Import Project="$(WebKit_Libraries)\tools\vsprops\debugsuffix.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Production|x64'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">testRegExp$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">testRegExp$(DebugSuffix)</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'"> + <TargetName>testRegExp$(DebugSuffix)</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'"> + <TargetName>testRegExp$(DebugSuffix)</TargetName> + </PropertyGroup> + <ItemDefinitionGroup> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="../jsc/DLLLauncherMain.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="testRegExpLauncherPostBuild.cmd" /> + <None Include="testRegExpLauncherPreBuild.cmd" /> + <None Include="testRegExpLauncherPreLink.cmd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPostBuild.cmd b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPostBuild.cmd new file mode 100644 index 0000000..0204125 --- /dev/null +++ b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPostBuild.cmd @@ -0,0 +1,3 @@ +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" + +cmd /c diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreBuild.cmd b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreBuild.cmd new file mode 100644 index 0000000..4e5ccc5 --- /dev/null +++ b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreBuild.cmd @@ -0,0 +1,6 @@ +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul +if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% +cmd /c +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" +if errorlevel 1 exit 1 +echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreLink.cmd b/JavaScriptCore.vcxproj/testRegExp/testRegExpLauncherPreLink.cmd new file mode 100644 index 0000000..e69de29 diff --git a/JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd b/JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd index 72ab16a..4e5ccc5 100644 --- a/JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd +++ b/JavaScriptCore.vcxproj/testRegExp/testRegExpPreBuild.cmd @@ -1,4 +1,4 @@ -%SystemDrive%\cygwin\bin\which.exe perl +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% cmd /c if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.vcxproj/testapi/testapi.vcxproj b/JavaScriptCore.vcxproj/testapi/testapi.vcxproj index bb317ad..b26c84d 100644 --- a/JavaScriptCore.vcxproj/testapi/testapi.vcxproj +++ b/JavaScriptCore.vcxproj/testapi/testapi.vcxproj @@ -57,73 +57,73 @@ </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120_xp</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120_xp</PlatformToolset> + <PlatformToolset>v120</PlatformToolset> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> + <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v120</PlatformToolset> @@ -292,10 +292,14 @@ </ItemGroup> <ItemGroup> <ClCompile Include="..\..\API\tests\testapi.c" /> + <ClCompile Include="..\..\API\tests\CompareAndSwapTest.cpp" /> + <ClInclude Include="..\..\API\tests\CompareAndSwapTest.h" /> <ClCompile Include="..\..\API\tests\CustomGlobalObjectClassTest.c" /> <ClInclude Include="..\..\API\tests\CustomGlobalObjectClassTest.h" /> + <ClCompile Include="..\..\API\tests\GlobalContextWithFinalizerTest.cpp" /> + <ClInclude Include="..\..\API\tests\GlobalContextWithFinalizerTest.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> +</Project> \ No newline at end of file diff --git a/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters b/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters index 9641ef7..3598f8b 100644 --- a/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters +++ b/JavaScriptCore.vcxproj/testapi/testapi.vcxproj.filters @@ -8,7 +8,11 @@ </ItemGroup> <ItemGroup> <ClCompile Include="..\..\API\tests\testapi.c" /> + <ClCompile Include="..\..\API\tests\CompareAndSwapTest.cpp" /> + <ClInclude Include="..\..\API\tests\CompareAndSwapTest.h" /> <ClCompile Include="..\..\API\tests\CustomGlobalObjectClassTest.c" /> <ClInclude Include="..\..\API\tests\CustomGlobalObjectClassTest.h" /> + <ClCompile Include="..\..\API\tests\GlobalContextWithFinalizerTest.cpp" /> + <ClInclude Include="..\..\API\tests\GlobalContextWithFinalizerTest.h" /> </ItemGroup> </Project> diff --git a/JavaScriptCore.vcxproj/testapi/testapiCommon.props b/JavaScriptCore.vcxproj/testapi/testapiCommon.props index c8c791a..cdf25c5 100644 --- a/JavaScriptCore.vcxproj/testapi/testapiCommon.props +++ b/JavaScriptCore.vcxproj/testapi/testapiCommon.props @@ -5,12 +5,12 @@ <PropertyGroup /> <ItemDefinitionGroup> <Link> - <AdditionalDependencies>CoreFoundation$(DebugSuffix).lib;JavaScriptCore$(DebugSuffix).lib;WTF$(DebugSuffix).lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>CoreFoundation$(DebugSuffix).lib;JavaScriptCore$(DebugSuffix).lib;WTF$(DebugSuffix).lib;libicuin$(DebugSuffix).lib;libicuuc$(DebugSuffix).lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <SubSystem>Console</SubSystem> </Link> <ClCompile> - <PreprocessorDefinitions>NOMINMAX;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(ProjectDir)\..\..\API;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>NOMINMAX;USE_CONSOLE_ENTRY_POINT;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(ProjectDir)\..\..\API;$(ProjectDir)\..\..\;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> </ItemDefinitionGroup> <ItemGroup /> diff --git a/JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props b/JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props index 0da8cdf..e58c40c 100644 --- a/JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props +++ b/JavaScriptCore.vcxproj/testapi/testapiCommonCFLite.props @@ -5,12 +5,12 @@ <PropertyGroup /> <ItemDefinitionGroup> <Link> - <AdditionalDependencies>CFLite.lib;JavaScriptCore$(DebugSuffix).lib;WTF$(DebugSuffix).lib;libicuin.lib;libicuuc.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>CFLite.lib;JavaScriptCore$(DebugSuffix).lib;WTF$(DebugSuffix).lib;libicuin.lib;libicuuc.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <SubSystem>Console</SubSystem> </Link> <ClCompile> - <PreprocessorDefinitions>NOMINMAX;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(ProjectDir)\..\..\API;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>NOMINMAX;USE_CONSOLE_ENTRY_POINT;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(ProjectDir)\..\..\API;$(ProjectDir)\..\..\;$(ConfigurationBuildDir)\include\JavaScriptCore;$(ConfigurationBuildDir)\include\private\JavaScriptCore;$(ConfigurationBuildDir)\include;$(ConfigurationBuildDir)\include\private;$(WebKit_Libraries)\include;$(WebKit_Libraries)\include\private;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> </ItemDefinitionGroup> <ItemGroup /> diff --git a/JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj b/JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj new file mode 100644 index 0000000..fb15f4d --- /dev/null +++ b/JavaScriptCore.vcxproj/testapi/testapiLauncher.vcxproj @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="DebugSuffix|Win32"> + <Configuration>DebugSuffix</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="DebugSuffix|x64"> + <Configuration>DebugSuffix</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_WinCairo|Win32"> + <Configuration>Debug_WinCairo</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug_WinCairo|x64"> + <Configuration>Debug_WinCairo</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Production|Win32"> + <Configuration>Production</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Production|x64"> + <Configuration>Production</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_WinCairo|Win32"> + <Configuration>Release_WinCairo</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release_WinCairo|x64"> + <Configuration>Release_WinCairo</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{FE09F693-9744-4D73-A17C-FE3209EB1905}</ProjectGuid> + <RootNamespace>testapiLauncher</RootNamespace> + <Keyword>Win32Proj</Keyword> + <ProjectName>testapiLauncher</ProjectName> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120_xp</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiRelease.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiRelease.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiReleaseCFLite.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiReleaseCFLite.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Production|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiProduction.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Production|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiProduction.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiDebug.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiDebug.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiDebugCFLite.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiDebugCFLite.props" /> + <Import Project="..\jsc\DLLLauncherWinCairo.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiDebug.props" /> + <Import Project="$(WebKit_Libraries)\tools\vsprops\debugsuffix.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="testapiDebug.props" /> + <Import Project="$(WebKit_Libraries)\tools\vsprops\debugsuffix.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Production|x64'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">testapi$(DebugSuffix)</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">testapi$(DebugSuffix)</TargetName> + </PropertyGroup> + <ItemDefinitionGroup> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="../jsc/DLLLauncherMain.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="testapiLauncherPostBuild.cmd" /> + <None Include="testapiLauncherPreBuild.cmd" /> + <None Include="testapiLauncherPreLink.cmd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/JavaScriptCore.vcxproj/testapi/testapiLauncherPostBuild.cmd b/JavaScriptCore.vcxproj/testapi/testapiLauncherPostBuild.cmd new file mode 100644 index 0000000..64fb320 --- /dev/null +++ b/JavaScriptCore.vcxproj/testapi/testapiLauncherPostBuild.cmd @@ -0,0 +1,3 @@ +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" + +@xcopy /y /d "%PROJECTDIR%\..\..\API\tests\testapi.js" "%OUTDIR%" >nul 2>nul diff --git a/JavaScriptCore.vcxproj/testapi/testapiLauncherPreBuild.cmd b/JavaScriptCore.vcxproj/testapi/testapiLauncherPreBuild.cmd new file mode 100644 index 0000000..4e5ccc5 --- /dev/null +++ b/JavaScriptCore.vcxproj/testapi/testapiLauncherPreBuild.cmd @@ -0,0 +1,6 @@ +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul +if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% +cmd /c +if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" +if errorlevel 1 exit 1 +echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.vcxproj/testapi/testapiLauncherPreLink.cmd b/JavaScriptCore.vcxproj/testapi/testapiLauncherPreLink.cmd new file mode 100644 index 0000000..e69de29 diff --git a/JavaScriptCore.vcxproj/testapi/testapiPostBuild.cmd b/JavaScriptCore.vcxproj/testapi/testapiPostBuild.cmd index 0820433..64fb320 100644 --- a/JavaScriptCore.vcxproj/testapi/testapiPostBuild.cmd +++ b/JavaScriptCore.vcxproj/testapi/testapiPostBuild.cmd @@ -1,3 +1,3 @@ if exist "%CONFIGURATIONBUILDDIR%\buildfailed" del "%CONFIGURATIONBUILDDIR%\buildfailed" -xcopy /y /d "%PROJECTDIR%\..\..\API\tests\testapi.js" "%OUTDIR%" +@xcopy /y /d "%PROJECTDIR%\..\..\API\tests\testapi.js" "%OUTDIR%" >nul 2>nul diff --git a/JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd b/JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd index 72ab16a..49e1723 100644 --- a/JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd +++ b/JavaScriptCore.vcxproj/testapi/testapiPreBuild.cmd @@ -1,6 +1,6 @@ -%SystemDrive%\cygwin\bin\which.exe perl +%SystemDrive%\cygwin\bin\which.exe perl >nul 2>nul if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH% cmd /c if exist "%CONFIGURATIONBUILDDIR%\buildfailed" perl -wnle "if (/XX%PROJECTNAME%XX/) { print } else { exit 1 }" "%CONFIGURATIONBUILDDIR%\buildfailed" if errorlevel 1 exit 1 -echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" +@echo XX%PROJECTNAME%XX > "%CONFIGURATIONBUILDDIR%\buildfailed" diff --git a/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore.xcodeproj/project.pbxproj index 308d9df..67e8a29 100644 --- a/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore.xcodeproj/project.pbxproj @@ -74,11 +74,16 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 0A6441519420A6C61AD1882E /* MapDataInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 593D43CCA0BBE06D89C59707 /* MapDataInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F0123321944EA1B00843A0C /* DFGValueStrength.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0123301944EA1B00843A0C /* DFGValueStrength.cpp */; }; + 0F0123331944EA1B00843A0C /* DFGValueStrength.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0123311944EA1B00843A0C /* DFGValueStrength.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F0332C018ADFAE1005F979A /* ExitingJITType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0332BF18ADFAE1005F979A /* ExitingJITType.cpp */; }; 0F0332C318B01763005F979A /* GetByIdVariant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0332C118B01763005F979A /* GetByIdVariant.cpp */; }; 0F0332C418B01763005F979A /* GetByIdVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0332C218B01763005F979A /* GetByIdVariant.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F0332C618B53FA9005F979A /* FTLWeight.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0332C518B53FA9005F979A /* FTLWeight.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F0332C818B546EC005F979A /* FTLWeightedTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0332C718B546EC005F979A /* FTLWeightedTarget.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F04396D1B03DC0B009598B7 /* DFGCombinedLiveness.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F04396B1B03DC0B009598B7 /* DFGCombinedLiveness.cpp */; }; + 0F04396E1B03DC0B009598B7 /* DFGCombinedLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F04396C1B03DC0B009598B7 /* DFGCombinedLiveness.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F05C3B41683CF9200BAF45B /* DFGArrayifySlowPathGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F0776BF14FF002B00102332 /* JITCompilationEffort.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0776BD14FF002800102332 /* JITCompilationEffort.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F0B839C14BCF46300885B4F /* LLIntThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0B839714BCF45A00885B4F /* LLIntThunks.cpp */; }; @@ -92,6 +97,8 @@ 0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */; }; 0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F12DE0F1979D5FD0006FF4E /* ExceptionFuzz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F12DE0D1979D5FD0006FF4E /* ExceptionFuzz.cpp */; }; + 0F12DE101979D5FD0006FF4E /* ExceptionFuzz.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F12DE0E1979D5FD0006FF4E /* ExceptionFuzz.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F136D4D174AD69E0075B354 /* DeferGC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F136D4B174AD69B0075B354 /* DeferGC.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */; }; 0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -99,8 +106,7 @@ 0F13912C16771C3D009CCB07 /* ProfilerProfiledBytecodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F13912716771C30009CCB07 /* ProfilerProfiledBytecodes.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F13E04E16164A1F00DC8DE7 /* IndexingType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */; }; 0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */; }; - 0F16015E156198C900C2587C /* DFGArgumentsSimplificationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F16015B156198BF00C2587C /* DFGArgumentsSimplificationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F1725FF1B48719A00AC3A55 /* DFGMinifiedGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1725FE1B48719A00AC3A55 /* DFGMinifiedGraph.cpp */; }; 0F190CAC189D82F6000AE5F0 /* ProfilerJettisonReason.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F190CAA189D82F6000AE5F0 /* ProfilerJettisonReason.cpp */; }; 0F190CAD189D82F6000AE5F0 /* ProfilerJettisonReason.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F190CAB189D82F6000AE5F0 /* ProfilerJettisonReason.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F1DD84A18A945BE0026F3FA /* JSCInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1DD84918A945BE0026F3FA /* JSCInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -108,6 +114,7 @@ 0F1E3A471534CBB9000F9456 /* DFGDoubleFormatState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F1E3A67153A21E2000F9456 /* DFGSilentRegisterSavePlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F1FE51C1922A3BC006987C5 /* AbortReason.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FE51B1922A3BC006987C5 /* AbortReason.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F20C2591A8013AB00DA3229 /* VirtualRegister.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F20C2581A8013AB00DA3229 /* VirtualRegister.cpp */; }; 0F21C27D14BE727A00ADC64B /* CodeSpecializationKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F21C27F14BEAA8200ADC64B /* BytecodeConventions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F235BD317178E1C00690C7F /* FTLExitArgument.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F235BBD17178E1C00690C7F /* FTLExitArgument.cpp */; }; @@ -205,13 +212,30 @@ 0F2B670917B6B5AB00A7AE3F /* TypedArrays.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2B670A17B6B5AB00A7AE3F /* TypedArrayType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B66DC17B6B5AB00A7AE3F /* TypedArrayType.cpp */; }; 0F2B670B17B6B5AB00A7AE3F /* TypedArrayType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CE219D0BA7D00B1D1B5 /* DFGAvailabilityMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CD619D0BA7D00B1D1B5 /* DFGAvailabilityMap.cpp */; }; + 0F2B9CE319D0BA7D00B1D1B5 /* DFGAvailabilityMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CD719D0BA7D00B1D1B5 /* DFGAvailabilityMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CE419D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CD819D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.cpp */; }; + 0F2B9CE519D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CD919D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CE619D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CDA19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.cpp */; }; + 0F2B9CE719D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CDB19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CE819D0BA7D00B1D1B5 /* DFGObjectMaterializationData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CDC19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.cpp */; }; + 0F2B9CE919D0BA7D00B1D1B5 /* DFGObjectMaterializationData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CDD19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CEA19D0BA7D00B1D1B5 /* DFGPhiChildren.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CDE19D0BA7D00B1D1B5 /* DFGPhiChildren.cpp */; }; + 0F2B9CEB19D0BA7D00B1D1B5 /* DFGPhiChildren.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CDF19D0BA7D00B1D1B5 /* DFGPhiChildren.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CEC19D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CE019D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.cpp */; }; + 0F2B9CED19D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CE119D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CF419D0BAC100B1D1B5 /* FTLExitPropertyValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CEE19D0BAC100B1D1B5 /* FTLExitPropertyValue.cpp */; }; + 0F2B9CF519D0BAC100B1D1B5 /* FTLExitPropertyValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CEF19D0BAC100B1D1B5 /* FTLExitPropertyValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CF619D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CF019D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.cpp */; }; + 0F2B9CF719D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CF119D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2B9CF819D0BAC100B1D1B5 /* FTLOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2B9CF219D0BAC100B1D1B5 /* FTLOperations.cpp */; }; + 0F2B9CF919D0BAC100B1D1B5 /* FTLOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B9CF319D0BAC100B1D1B5 /* FTLOperations.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC15151C5D4D00CD8910 /* DFGFixupPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */; }; 0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC2B151FDE8B00CD8910 /* Operands.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC451522801B00CD8910 /* DFGMinifiedGraph.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC3D1522801700CD8910 /* DFGMinifiedGraph.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC461522802000CD8910 /* DFGMinifiedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC3E1522801700CD8910 /* DFGMinifiedNode.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0F2BDC471522802500CD8910 /* DFGValueRecoveryOverride.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC401522801700CD8910 /* DFGValueSource.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC491522809600CD8910 /* DFGVariableEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC411522801700CD8910 /* DFGVariableEvent.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2BDC4A1522809A00CD8910 /* DFGVariableEventStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */; }; @@ -219,6 +243,21 @@ 0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */; }; 0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */; }; 0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */; }; + 0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */; }; + 0F2D4DDE19832D34007D4B19 /* DebuggerScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2D4DE819832DAC007D4B19 /* ToThisStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */; }; + 0F2D4DE919832DAC007D4B19 /* ToThisStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2D4DEA19832DAC007D4B19 /* TypeLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE719832DAC007D4B19 /* TypeLocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2D4DEB19832DC4007D4B19 /* TypeProfilerLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DDF19832D91007D4B19 /* TypeProfilerLog.cpp */; }; + 0F2D4DEC19832DC4007D4B19 /* TypeProfilerLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE019832D91007D4B19 /* TypeProfilerLog.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2D4DEF19832DD3007D4B19 /* TypeSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DE319832D91007D4B19 /* TypeSet.cpp */; }; + 0F2D4DF019832DD6007D4B19 /* TypeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DE419832D91007D4B19 /* TypeSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2DD80B1AB3D85800BBB8E8 /* BytecodeKills.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2DD80A1AB3D85800BBB8E8 /* BytecodeKills.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2DD8111AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2DD80C1AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.cpp */; }; + 0F2DD8121AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2DD80D1AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2DD8131AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2DD80E1AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.cpp */; }; + 0F2DD8141AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2DD80F1AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F2DD8151AB3D8BE00BBB8E8 /* DFGForAllKills.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2DD8101AB3D8BE00BBB8E8 /* DFGForAllKills.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 65987F2F16828A7E003C2F8D /* UnusedPointer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */; }; @@ -242,6 +281,10 @@ 0F38B01817CFE75500B144D3 /* DFGCompilationKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F38B01417CFE75500B144D3 /* DFGCompilationKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F38B01917CFE75500B144D3 /* DFGCompilationMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F38B01517CFE75500B144D3 /* DFGCompilationMode.cpp */; }; 0F38B01A17CFE75500B144D3 /* DFGCompilationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F392C891B46188400844728 /* DFGOSRExitFuzz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F392C871B46188400844728 /* DFGOSRExitFuzz.cpp */; }; + 0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F392C881B46188400844728 /* DFGOSRExitFuzz.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F3A1BF91A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3A1BF71A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp */; }; + 0F3A1BFA1A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3A1BF81A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F3AC752183EA1040032029F /* StackAlignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC751183EA1040032029F /* StackAlignment.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F3AC754188E5EC80032029F /* ExitingJITType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC753188E5EC80032029F /* ExitingJITType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */; }; @@ -250,6 +293,12 @@ 0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3B3A251544C991003ED0FF /* DFGCFGSimplificationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F3B3A2B15475000003ED0FF /* DFGValidate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A2915474FF4003ED0FF /* DFGValidate.cpp */; }; 0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3B3A2A15474FF4003ED0FF /* DFGValidate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F3B7E2A19A11B8000D9BC56 /* CallVariant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B7E2419A11B8000D9BC56 /* CallVariant.cpp */; }; + 0F3B7E2B19A11B8000D9BC56 /* CallVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3B7E2519A11B8000D9BC56 /* CallVariant.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F3D0BBC194A414300FC9CF9 /* ConstantStructureCheck.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3D0BBA194A414300FC9CF9 /* ConstantStructureCheck.cpp */; }; + 0F3D0BBD194A414300FC9CF9 /* ConstantStructureCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3D0BBB194A414300FC9CF9 /* ConstantStructureCheck.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F3E01AA19D353A500F61B7F /* DFGPrePostNumbering.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3E01A819D353A500F61B7F /* DFGPrePostNumbering.cpp */; }; + 0F3E01AB19D353A500F61B7F /* DFGPrePostNumbering.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3E01A919D353A500F61B7F /* DFGPrePostNumbering.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F426A481460CBB300131F8F /* ValueRecovery.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A451460CBAB00131F8F /* ValueRecovery.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F426A491460CBB700131F8F /* VirtualRegister.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A461460CBAB00131F8F /* VirtualRegister.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F426A4B1460CD6E00131F8F /* DataFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A4A1460CD6B00131F8F /* DataFormat.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -280,6 +329,7 @@ 0F4CED5F18CEA7AB00802FE0 /* PolymorphicGetByIdList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4CED5D18CEA7AB00802FE0 /* PolymorphicGetByIdList.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F4F29DF18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */; }; 0F4F29E018B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F5541B11613C1FB00CE3E25 /* SpecialPointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5541AF1613C1FB00CE3E25 /* SpecialPointer.cpp */; }; 0F5541B21613C1FB00CE3E25 /* SpecialPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F55989817C86C5800A1E543 /* ToNativeFromValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F55989717C86C5600A1E543 /* ToNativeFromValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -290,6 +340,10 @@ 0F56A1D515001CF4002992B1 /* ExecutionCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */; }; 0F572D4F16879FDD00E57FBD /* ThunkGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F572D4D16879FDB00E57FBD /* ThunkGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F5780A218FE1E98001E72D9 /* PureNaN.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5780A118FE1E98001E72D9 /* PureNaN.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F5874ED194FEB1200AAB2C1 /* DFGMayExit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5874EB194FEB1200AAB2C1 /* DFGMayExit.cpp */; }; + 0F5874EE194FEB1200AAB2C1 /* DFGMayExit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5874EC194FEB1200AAB2C1 /* DFGMayExit.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */; }; + 0F5A1274192D9FDF008764A3 /* DFGDoesGC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F5A52D017ADD717008ECB2D /* CopyToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A52CF17ADD717008ECB2D /* CopyToken.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F5A6283188C98D40072C9DF /* FTLValueRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5A6281188C98D40072C9DF /* FTLValueRange.cpp */; }; 0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A6282188C98D40072C9DF /* FTLValueRange.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -299,6 +353,8 @@ 0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F6237971AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */; }; + 0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F63943F15C75F19006A597C /* DFGTypeCheckHoistingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F63944015C75F1D006A597C /* DFGTypeCheckHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */; }; 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63945115D07051006A597C /* ArrayProfile.cpp */; }; @@ -306,14 +362,20 @@ 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63948115E48114006A597C /* DFGArrayMode.cpp */; }; 0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63948215E48114006A597C /* DFGArrayMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F64B2711A784BAF006E4E66 /* BinarySwitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F64B26F1A784BAF006E4E66 /* BinarySwitch.cpp */; }; + 0F64B2721A784BAF006E4E66 /* BinarySwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F64B2701A784BAF006E4E66 /* BinarySwitch.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F64B2791A7957B2006E4E66 /* CallEdge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F64B2771A7957B2006E4E66 /* CallEdge.cpp */; }; + 0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F64B2781A7957B2006E4E66 /* CallEdge.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F666EC0183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F666EC1183566F900D017F1 /* FullBytecodeLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F666EC61835672B00D017F1 /* DFGAvailability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F666EC21835672B00D017F1 /* DFGAvailability.cpp */; }; 0F666EC71835672B00D017F1 /* DFGAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EC31835672B00D017F1 /* DFGAvailability.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0F666ECC1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */; }; - 0F666ECD1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.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, ); }; }; + 0F682FB219BCB36400FA3BAD /* DFGSSACalculator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F682FB019BCB36400FA3BAD /* DFGSSACalculator.cpp */; }; + 0F682FB319BCB36400FA3BAD /* DFGSSACalculator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F682FB119BCB36400FA3BAD /* DFGSSACalculator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F69CC88193AC60A0045759E /* DFGFrozenValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F69CC86193AC60A0045759E /* DFGFrozenValue.cpp */; }; + 0F69CC89193AC60A0045759E /* DFGFrozenValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F69CC87193AC60A0045759E /* DFGFrozenValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F6B1CB5185FC9E900845D97 /* FTLJSCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6B1CB3185FC9E900845D97 /* FTLJSCall.cpp */; }; 0F6B1CB6185FC9E900845D97 /* FTLJSCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CB4185FC9E900845D97 /* FTLJSCall.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F6B1CB91861244C00845D97 /* ArityCheckMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CB71861244C00845D97 /* ArityCheckMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -326,13 +388,15 @@ 0F6B1CC61862C47800845D97 /* FTLUnwindInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CC21862C47800845D97 /* FTLUnwindInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F6B1CC918641DF800845D97 /* ArityCheckFailReturnThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */; }; 0F6B1CCA18641DF800845D97 /* ArityCheckFailReturnThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F6C73501AC9F99F00BE1682 /* VariableWriteFireDetail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6C734E1AC9F99F00BE1682 /* VariableWriteFireDetail.cpp */; }; + 0F6C73511AC9F99F00BE1682 /* VariableWriteFireDetail.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6C734F1AC9F99F00BE1682 /* VariableWriteFireDetail.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F6E845A19030BEF00562741 /* DFGVariableAccessData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */; }; + 0F6FC750196110A800E1D02D /* ComplexGetStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */; }; + 0F6FC751196110A800E1D02D /* ComplexGetStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */; }; 0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F714CA416EA92F000F3EBEB /* DFGBackwardsPropagationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */; }; 0F714CA516EA92F200F3EBEB /* DFGBackwardsPropagationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.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, ); }; }; 0F743BAA16B88249009F9277 /* ARM64Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 652A3A201651C66100A80AFE /* ARM64Disassembler.cpp */; }; 0F7576D218E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7576D018E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp */; }; 0F7576D318E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7576D118E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -345,6 +409,8 @@ 0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */; }; 0F766D3915AE4A1F008F363E /* StructureStubClearingWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; }; + 0F79085519A290B200F6310C /* DFGStructureRegistrationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F79085319A290B200F6310C /* DFGStructureRegistrationPhase.cpp */; }; + 0F79085619A290B200F6310C /* DFGStructureRegistrationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F79085419A290B200F6310C /* DFGStructureRegistrationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E1F14172C2F00179C94 /* DFGCapabilities.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, ); }; }; @@ -352,6 +418,13 @@ 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, ); }; }; 0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F893BDB1936E23C001211F4 /* DFGStructureAbstractValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */; }; + 0F898F311B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F898F2F1B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp */; }; + 0F898F321B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F898F301B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F8F14331ADF090100ED792C /* DFGEpoch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F142F1ADF090100ED792C /* DFGEpoch.cpp */; }; + 0F8F14341ADF090100ED792C /* DFGEpoch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8F14301ADF090100ED792C /* DFGEpoch.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F8F14351ADF090100ED792C /* DFGMovHintRemovalPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F14311ADF090100ED792C /* DFGMovHintRemovalPhase.cpp */; }; + 0F8F14361ADF090100ED792C /* DFGMovHintRemovalPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8F14321ADF090100ED792C /* DFGMovHintRemovalPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F8F2B95172E04A0007DBDA5 /* FTLLink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */; }; 0F8F2B96172E04A3007DBDA5 /* FTLLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8F2B94172E049E007DBDA5 /* FTLLink.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */; }; @@ -363,7 +436,6 @@ 0F8F94421667633500D61971 /* CodeType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F943F1667632D00D61971 /* CodeType.cpp */; }; 0F8F94441667635400D61971 /* JITCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F94431667635200D61971 /* JITCode.cpp */; }; 0F8F9446166764F100D61971 /* CodeOrigin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8F9445166764EE00D61971 /* CodeOrigin.cpp */; }; - 0F9181C718415CA50057B669 /* VariableWatchpointSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9181C618415CA50057B669 /* VariableWatchpointSet.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 */; }; @@ -380,9 +452,12 @@ 0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329B14CA7DC10085F3C6 /* StructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F93B4A918B92C4D00178A3F /* PutByIdVariant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */; }; 0F93B4AA18B92C4D00178A3F /* PutByIdVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F952ABC1B487A7700C367C5 /* TrackedReferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F952ABA1B487A7700C367C5 /* TrackedReferences.cpp */; }; + 0F952ABD1B487A7700C367C5 /* TrackedReferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F952ABB1B487A7700C367C5 /* TrackedReferences.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F96EBB316676EF6008BADE3 /* CodeBlockWithJITType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F9749711687ADE400A4FF6A /* JSCellInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F978B3B1AAEA71D007C7369 /* ConstantMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F978B3A1AAEA71D007C7369 /* ConstantMode.cpp */; }; 0F98206016BFE38100240D02 /* PreciseJumpTargets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F98205D16BFE37F00240D02 /* PreciseJumpTargets.cpp */; }; 0F98206116BFE38300240D02 /* PreciseJumpTargets.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F98205E16BFE37F00240D02 /* PreciseJumpTargets.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F9C5E5E18E35F5E00D431C3 /* FTLDWARFRegister.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9C5E5C18E35F5E00D431C3 /* FTLDWARFRegister.cpp */; }; @@ -392,6 +467,10 @@ 0F9D339717FFC4E60073C2BC /* DFGFlushedAt.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D339517FFC4E60073C2BC /* DFGFlushedAt.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F9D339A1803ADB70073C2BC /* FTLStackMaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D33981803ADB70073C2BC /* FTLStackMaps.cpp */; }; 0F9D339B1803ADB70073C2BC /* FTLStackMaps.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D33991803ADB70073C2BC /* FTLStackMaps.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F9D36941AE9CC33000D4DFB /* DFGCleanUpPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D36921AE9CC33000D4DFB /* DFGCleanUpPhase.cpp */; }; + 0F9D36951AE9CC33000D4DFB /* DFGCleanUpPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D36931AE9CC33000D4DFB /* DFGCleanUpPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0F9E32631B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9E32611B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.cpp */; }; + 0F9E32641B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9E32621B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F9FB4F417FCB91700CB67F8 /* DFGStackLayoutPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9FB4F217FCB91700CB67F8 /* DFGStackLayoutPhase.cpp */; }; 0F9FB4F517FCB91700CB67F8 /* DFGStackLayoutPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9FB4F317FCB91700CB67F8 /* DFGStackLayoutPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0F9FC8C314E1B5FE00D52AE0 /* PolymorphicPutByIdList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9FC8BF14E1B5FB00D52AE0 /* PolymorphicPutByIdList.cpp */; }; @@ -405,6 +484,7 @@ 0FA7A8EB18B413C80052371D /* Reg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA7A8E918B413C80052371D /* Reg.cpp */; }; 0FA7A8EC18B413C80052371D /* Reg.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA7A8EA18B413C80052371D /* Reg.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FA7A8EE18CE4FD80052371D /* ScratchRegisterAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA7A8ED18CE4FD80052371D /* ScratchRegisterAllocator.cpp */; }; + 0FAA3E0919D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAA3E0819D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.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, ); }; }; 0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB105821675480C00F8AB6E /* ExitKind.cpp */; }; @@ -417,6 +497,11 @@ 0FB14E1F18124ACE009B6B4D /* JITInlineCacheGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E1D18124ACE009B6B4D /* JITInlineCacheGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB14E211812570B009B6B4D /* DFGInlineCacheWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FB14E2318130955009B6B4D /* DFGInlineCacheWrapperInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FB17660196B8F9E0091052A /* DFGHeapLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB1765C196B8F9E0091052A /* DFGHeapLocation.cpp */; }; + 0FB17661196B8F9E0091052A /* DFGHeapLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB1765D196B8F9E0091052A /* DFGHeapLocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FB17662196B8F9E0091052A /* DFGPureValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */; }; + 0FB17663196B8F9E0091052A /* DFGPureValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB1765F196B8F9E0091052A /* DFGPureValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FB438A319270B1D00E1FBC9 /* StructureSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */; }; 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, ); }; }; @@ -434,12 +519,15 @@ 0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */; }; 0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FBD7E691447999600481315 /* CodeOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBD7E671447998F00481315 /* CodeOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBDB9AC1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FBE0F7216C1DB030082C5E8 /* DFGCPSRethreadingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE0F6B16C1DB010082C5E8 /* DFGCPSRethreadingPhase.cpp */; }; 0FBE0F7316C1DB050082C5E8 /* DFGCPSRethreadingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBE0F6C16C1DB010082C5E8 /* DFGCPSRethreadingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FBE0F7416C1DB090082C5E8 /* DFGPredictionInjectionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE0F6D16C1DB010082C5E8 /* DFGPredictionInjectionPhase.cpp */; }; 0FBE0F7516C1DB0B0082C5E8 /* DFGPredictionInjectionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE0F6F16C1DB010082C5E8 /* DFGUnificationPhase.cpp */; }; 0FBE0F7716C1DB120082C5E8 /* DFGUnificationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBE0F7016C1DB010082C5E8 /* DFGUnificationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FBF158C19B7A53100695DD0 /* DFGBlockSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBF158A19B7A53100695DD0 /* DFGBlockSet.cpp */; }; + 0FBF158D19B7A53100695DD0 /* DFGBlockSetInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBF158B19B7A53100695DD0 /* DFGBlockSetInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC0976A1468A6F700CF2442 /* DFGOSRExit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC097681468A6EF00CF2442 /* DFGOSRExit.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0976F14693AEF00CF2442 /* DFGOSRExitCompiler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC0977214693AF900CF2442 /* DFGOSRExitCompiler64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC0977014693AEF00CF2442 /* DFGOSRExitCompiler64.cpp */; }; @@ -455,6 +543,13 @@ 0FC314121814559100033232 /* RegisterSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC314101814559100033232 /* RegisterSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC314131814559100033232 /* TempRegisterSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC314111814559100033232 /* TempRegisterSet.cpp */; }; 0FC3141518146D7000033232 /* RegisterSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC3141418146D7000033232 /* RegisterSet.cpp */; }; + 0FC3CCFC19ADA410006AC72A /* DFGBlockMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC3CCF519ADA410006AC72A /* DFGBlockMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FC3CCFD19ADA410006AC72A /* DFGBlockMapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC3CCF619ADA410006AC72A /* DFGBlockMapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FC3CCFE19ADA410006AC72A /* DFGBlockSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC3CCF719ADA410006AC72A /* DFGBlockSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FC3CCFF19ADA410006AC72A /* DFGBlockWorklist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC3CCF819ADA410006AC72A /* DFGBlockWorklist.cpp */; }; + 0FC3CD0019ADA410006AC72A /* DFGBlockWorklist.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC3CCF919ADA410006AC72A /* DFGBlockWorklist.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FC3CD0119ADA411006AC72A /* DFGNaiveDominators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC3CCFA19ADA410006AC72A /* DFGNaiveDominators.cpp */; }; + 0FC3CD0219ADA411006AC72A /* DFGNaiveDominators.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC3CCFB19ADA410006AC72A /* DFGNaiveDominators.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC712DE17CD8779008CC93C /* DeferredCompilationCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC712DC17CD8778008CC93C /* DeferredCompilationCallback.cpp */; }; 0FC712DF17CD877C008CC93C /* DeferredCompilationCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC712DD17CD8778008CC93C /* DeferredCompilationCallback.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC712E217CD8791008CC93C /* JITToDFGDeferredCompilationCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC712E017CD878F008CC93C /* JITToDFGDeferredCompilationCallback.cpp */; }; @@ -463,8 +558,6 @@ 0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC8150814043BCA00CFA603 /* WriteBarrierSupport.cpp */; }; 0FC97F33182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F2F182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp */; }; 0FC97F34182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F30182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0FC97F35182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F31182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp */; }; - 0FC97F36182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC97F3D18202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F3718202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp */; }; 0FC97F3E18202119002C9B26 /* DFGInvalidationPointInjectionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC97F3818202119002C9B26 /* DFGInvalidationPointInjectionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FC97F3F18202119002C9B26 /* DFGJumpReplacement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FC97F3918202119002C9B26 /* DFGJumpReplacement.cpp */; }; @@ -475,11 +568,9 @@ 0FCEFAAB1804C13E00472CE4 /* FTLSaveRestore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAA91804C13E00472CE4 /* FTLSaveRestore.cpp */; }; 0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FCEFAB01805CA6D00472CE4 /* InitializeLLVM.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAE1805CA6D00472CE4 /* InitializeLLVM.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 0FCEFAB11805CA6D00472CE4 /* InitializeLLVMMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAAF1805CA6D00472CE4 /* InitializeLLVMMac.mm */; }; 0FCEFAC11805D94E00472CE4 /* LLVMOverrides.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC01805D94100472CE4 /* LLVMOverrides.cpp */; }; 0FCEFAC31805E74000472CE4 /* LLVMExports.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC21805E74000472CE4 /* LLVMExports.cpp */; }; 0FCEFACA1805E75500472CE4 /* InitializeLLVM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC41805E75500472CE4 /* InitializeLLVM.cpp */; }; - 0FCEFACB1805E75500472CE4 /* InitializeLLVMPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC51805E75500472CE4 /* InitializeLLVMPOSIX.cpp */; }; 0FCEFACC1805E75500472CE4 /* InitializeLLVMPOSIX.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAC61805E75500472CE4 /* InitializeLLVMPOSIX.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FCEFACD1805E75500472CE4 /* LLVMAPI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC71805E75500472CE4 /* LLVMAPI.cpp */; }; 0FCEFACE1805E75500472CE4 /* LLVMAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAC81805E75500472CE4 /* LLVMAPI.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -492,6 +583,10 @@ 0FCEFADC18064A1400472CE4 /* config_llvm.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFADB18064A1400472CE4 /* config_llvm.h */; }; 0FCEFADF180738C000472CE4 /* FTLLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */; }; 0FCEFAE0180738C000472CE4 /* FTLLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFADE180738C000472CE4 /* FTLLocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FD1202F1A8AED12000F5280 /* FTLJSCallBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD1202D1A8AED12000F5280 /* FTLJSCallBase.cpp */; }; + 0FD120301A8AED12000F5280 /* FTLJSCallBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD1202E1A8AED12000F5280 /* FTLJSCallBase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FD120331A8C85BD000F5280 /* FTLJSCallVarargs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD120311A8C85BD000F5280 /* FTLJSCallVarargs.cpp */; }; + 0FD120341A8C85BD000F5280 /* FTLJSCallVarargs.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD120321A8C85BD000F5280 /* FTLJSCallVarargs.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD2C92316D01EE900C7803F /* StructureInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD3C82014115CF800FD81CB /* DFGDriver.cpp */; }; 0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD3C82214115D0E00FD81CB /* DFGDriver.h */; }; @@ -517,6 +612,10 @@ 0FD8A32A17D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD8A32217D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD8A32317D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp */; }; 0FD8A32C17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD8A32417D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FD949821A97DB9600E28966 /* JSCatchScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD9497E1A97DB9600E28966 /* JSCatchScope.cpp */; }; + 0FD949831A97DB9600E28966 /* JSCatchScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD9497F1A97DB9600E28966 /* JSCatchScope.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FD949841A97DB9600E28966 /* JSFunctionNameScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD949801A97DB9600E28966 /* JSFunctionNameScope.cpp */; }; + 0FD949851A97DB9600E28966 /* JSFunctionNameScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD949811A97DB9600E28966 /* JSFunctionNameScope.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FDB2CC9173DA520007B3C1B /* FTLAbbreviatedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CC7173DA51E007B3C1B /* FTLAbbreviatedTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FDB2CCA173DA523007B3C1B /* FTLValueFromBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CC8173DA51E007B3C1B /* FTLValueFromBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FDB2CE7174830A2007B3C1B /* DFGWorklist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */; }; @@ -524,8 +623,32 @@ 0FDB2CEA174896C7007B3C1B /* ConcurrentJITLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; }; 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050141AA9091100D33B33 /* ArgumentsMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050151AA9091100D33B33 /* DirectArgumentsOffset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0500D1AA9091100D33B33 /* DirectArgumentsOffset.cpp */; }; + 0FE050161AA9091100D33B33 /* DirectArgumentsOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0500E1AA9091100D33B33 /* DirectArgumentsOffset.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050171AA9091100D33B33 /* DirectArguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0500F1AA9091100D33B33 /* DirectArguments.cpp */; }; + 0FE050181AA9091100D33B33 /* DirectArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050101AA9091100D33B33 /* DirectArguments.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050191AA9091100D33B33 /* GenericArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050111AA9091100D33B33 /* GenericArguments.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE0501A1AA9091100D33B33 /* GenericArgumentsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050121AA9091100D33B33 /* GenericArgumentsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE0501B1AA9091100D33B33 /* GenericOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050131AA9091100D33B33 /* GenericOffset.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050251AA9095600D33B33 /* ClonedArguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0501C1AA9095600D33B33 /* ClonedArguments.cpp */; }; + 0FE050261AA9095600D33B33 /* ClonedArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0501D1AA9095600D33B33 /* ClonedArguments.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050271AA9095600D33B33 /* ScopedArguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0501E1AA9095600D33B33 /* ScopedArguments.cpp */; }; + 0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0501F1AA9095600D33B33 /* ScopedArguments.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE050291AA9095600D33B33 /* ScopedArgumentsTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050201AA9095600D33B33 /* ScopedArgumentsTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE0502A1AA9095600D33B33 /* ScopeOffset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE050211AA9095600D33B33 /* ScopeOffset.cpp */; }; + 0FE0502B1AA9095600D33B33 /* ScopeOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050221AA9095600D33B33 /* ScopeOffset.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE0502C1AA9095600D33B33 /* VarOffset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE050231AA9095600D33B33 /* VarOffset.cpp */; }; + 0FE0502D1AA9095600D33B33 /* VarOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050241AA9095600D33B33 /* VarOffset.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE0502F1AAA806900D33B33 /* ScopedArgumentsTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */; }; 0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; }; + 0FE254F61ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE254F41ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp */; }; + 0FE254F71ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE254F51ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE7211D193B9C590031F6ED /* DFGTransition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE7211B193B9C590031F6ED /* DFGTransition.cpp */; }; + 0FE7211E193B9C590031F6ED /* DFGTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE7211C193B9C590031F6ED /* DFGTransition.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FE834171A6EF97B00D04847 /* PolymorphicCallStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE834151A6EF97B00D04847 /* PolymorphicCallStubRoutine.cpp */; }; + 0FE834181A6EF97B00D04847 /* PolymorphicCallStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE834161A6EF97B00D04847 /* PolymorphicCallStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */; }; 0FE8534C1723CDA500B618F5 /* DFGDesiredWatchpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FE95F7918B5694700B531FB /* FTLDataSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE95F7718B5694700B531FB /* FTLDataSection.cpp */; }; @@ -558,8 +681,14 @@ 0FEA0A33170D40BF00BB722C /* DFGJITCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEA0A2F170D40BF00BB722C /* DFGJITCode.cpp */; }; 0FEA0A34170D40BF00BB722C /* DFGJITCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEA0A30170D40BF00BB722C /* DFGJITCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FEB3ECF16237F6C00AB67AD /* MacroAssembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEB3ECE16237F6700AB67AD /* MacroAssembler.cpp */; }; + 0FED67B91B26256D0066CE15 /* DFGConstantHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FED67B71B26256D0066CE15 /* DFGConstantHoistingPhase.cpp */; }; + 0FED67BA1B26256D0066CE15 /* DFGConstantHoistingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FED67B81B26256D0066CE15 /* DFGConstantHoistingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FEE98411A8865B700754E93 /* SetupVarargsFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEE98401A8865B600754E93 /* SetupVarargsFrame.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FEE98431A89227500754E93 /* SetupVarargsFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEE98421A89227500754E93 /* SetupVarargsFrame.cpp */; }; 0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */; }; 0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FF054F91AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */; }; + 0FF054FA1AC35B4400E5BE57 /* ExecutableAllocationFuzz.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FF0F19916B729F6005DF95B /* DFGLongLivedState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB4B51C16B62772003F696B /* DFGLongLivedState.cpp */; }; 0FF0F19B16B729FA005DF95B /* DFGLongLivedState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51D16B62772003F696B /* DFGLongLivedState.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FF0F19C16B72A03005DF95B /* DFGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB4B51E16B62772003F696B /* DFGNode.cpp */; }; @@ -605,9 +734,13 @@ 0FF729BE166AD360000F5BA3 /* ProfilerExecutionCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF7299E166AD347000F5BA3 /* ProfilerExecutionCounter.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FF729BF166AD360000F5BA3 /* ProfilerOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF729A0166AD347000F5BA3 /* ProfilerOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FF729C0166AD360000F5BA3 /* ProfilerOriginStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF729A2166AD347000F5BA3 /* ProfilerOriginStack.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FF8BDEA1AD4CF7100DFE884 /* InferredValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF8BDE81AD4CF7100DFE884 /* InferredValue.cpp */; }; + 0FF8BDEB1AD4CF7100DFE884 /* InferredValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF8BDE91AD4CF7100DFE884 /* InferredValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FF922D414F46B410041A24E /* LLIntOffsetsExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */; }; 0FFA549716B8835000B3A982 /* A64DOpcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 652A3A221651C69700A80AFE /* A64DOpcode.cpp */; }; 0FFA549816B8835300B3A982 /* A64DOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 652A3A231651C69700A80AFE /* A64DOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */; }; + 0FFB6C391AF48DDC00DB1BF7 /* TypeofType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFB6C371AF48DDC00DB1BF7 /* TypeofType.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FFB921816D02EB20055A5DB /* DFGAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51916B62772003F696B /* DFGAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FFB921A16D02EC50055A5DB /* DFGBasicBlockInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FFB921B16D02F010055A5DB /* DFGNodeAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51F16B62772003F696B /* DFGNodeAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -629,7 +762,7 @@ 0FFFC96014EF90BD00C72532 /* DFGVirtualRegisterAllocationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; 140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; }; 140566D6107EC271005DBC8D /* JSFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A85E0255597D01FF60F7 /* JSFunction.cpp */; }; - 140B7D1D0DC69AF7009C42B8 /* JSActivation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */; }; + 140B7D1D0DC69AF7009C42B8 /* JSLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14DA818F0D99FD2000B0A4FB /* JSLexicalEnvironment.cpp */; }; 140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 141211310A48794D00480255 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; }; 141211340A48795800480255 /* minidom.c in Sources */ = {isa = PBXBuildFile; fileRef = 141211020A48780900480255 /* minidom.c */; }; @@ -699,7 +832,6 @@ 14469DE4107EC7E700650446 /* NumberPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C40E16D4E900A06E92 /* NumberPrototype.cpp */; }; 14469DE5107EC7E700650446 /* ObjectConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C60E16D4E900A06E92 /* ObjectConstructor.cpp */; }; 14469DE6107EC7E700650446 /* ObjectPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */; }; - 14469DE7107EC7E700650446 /* PropertyNameArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65400C0F0A69BAF200509887 /* PropertyNameArray.cpp */; }; 14469DE8107EC7E700650446 /* PropertySlot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65621E6B089E859700760F35 /* PropertySlot.cpp */; }; 14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC18C3C00E16EE3300B34460 /* StringConstructor.cpp */; }; 14469DEC107EC7E700650446 /* StringObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC18C3C20E16EE3300B34460 /* StringObject.cpp */; }; @@ -715,7 +847,6 @@ 147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; 147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */; settings = {ATTRIBUTES = (Private, ); }; }; 147F39BD107EC37600427A48 /* ArgList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF605110E203EF800B9A64D /* ArgList.cpp */; }; - 147F39BE107EC37600427A48 /* Arguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC257DE50E1F51C50016B6C9 /* Arguments.cpp */; }; 147F39BF107EC37600427A48 /* ArrayConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7952060E15E8A800A898AB /* ArrayConstructor.cpp */; }; 147F39C0107EC37600427A48 /* ArrayPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */; }; 147F39C1107EC37600427A48 /* CommonIdentifiers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65EA73620BAE35D1001BB560 /* CommonIdentifiers.cpp */; }; @@ -738,9 +869,7 @@ 147F39D4107EC37600427A48 /* JSObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC22A3980E16E14800AF21C8 /* JSObject.cpp */; }; 147F39D5107EC37600427A48 /* JSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9B60E1842FA000F9297 /* JSString.cpp */; }; 147F39D6107EC37600427A48 /* JSCJSValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8870255597D01FF60F7 /* JSCJSValue.cpp */; }; - 147F39D7107EC37600427A48 /* JSVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */; }; - 14816E1B154CC56C00B8054C /* BlockAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14816E19154CC56C00B8054C /* BlockAllocator.cpp */; }; - 14816E1C154CC56C00B8054C /* BlockAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 14816E1A154CC56C00B8054C /* BlockAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 147F39D7107EC37600427A48 /* JSEnvironmentRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC22A39A0E16E14800AF21C8 /* JSEnvironmentRecord.cpp */; }; 1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B74C0A43032800517CFC /* JSStringRef.cpp */; }; 1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B7E20A43076000517CFC /* JSObjectRef.cpp */; }; 14874AE315EBDE4A002E3587 /* JSNameScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14874ADF15EBDE4A002E3587 /* JSNameScope.cpp */; }; @@ -784,15 +913,12 @@ 14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F97446138C853E00DA1C67 /* HeapRootVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A28D4A7177B71C80007FA3C /* JSStringRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACF7376171CA6FB00C9BB1E /* Weak.cpp */; }; - 1CAA9A1E18F4997F000A369D /* InspectorProfilerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CAA9A1C18F4997F000A369D /* InspectorProfilerAgent.cpp */; }; - 1CAA9A1F18F4997F000A369D /* InspectorProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAA9A1D18F4997F000A369D /* InspectorProfilerAgent.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 1CAA9A2218F4A220000A369D /* JSGlobalObjectProfilerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CAA9A2018F4A220000A369D /* JSGlobalObjectProfilerAgent.cpp */; }; - 1CAA9A2318F4A220000A369D /* JSGlobalObjectProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAA9A2118F4A220000A369D /* JSGlobalObjectProfilerAgent.h */; }; 2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */; }; 2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; }; + 2A05ABD51961DF2400341750 /* JSPropertyNameEnumerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */; }; + 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */; }; 2A111245192FCE79005EE18D /* CustomGetterSetter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A111243192FCE79005EE18D /* CustomGetterSetter.cpp */; }; 2A111246192FCE79005EE18D /* CustomGetterSetter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A111244192FCE79005EE18D /* CustomGetterSetter.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 2A2825D018341F2D0087FBA9 /* DelayedReleaseScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */; }; 2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; }; 2A4BB7F318A41179008A0FCD /* JSManagedValueInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A4BB7F218A41179008A0FCD /* JSManagedValueInternal.h */; }; 2A4EC90B1860D6C20094F782 /* WriteBarrierBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A4EC9091860D6C20094F782 /* WriteBarrierBuffer.cpp */; }; @@ -813,274 +939,92 @@ 2AAD964A18569417001F93BE /* RecursiveAllocationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AAD964918569417001F93BE /* RecursiveAllocationScope.h */; }; 2AC922BB18A16182003CE0FB /* FTLDWARFDebugLineInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AC922B918A16182003CE0FB /* FTLDWARFDebugLineInfo.cpp */; }; 2AC922BC18A16182003CE0FB /* FTLDWARFDebugLineInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AC922BA18A16182003CE0FB /* FTLDWARFDebugLineInfo.h */; }; - 2ACCF3DE185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */; }; - 2ACCF3DF185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */; }; + 2AD2EDFB19799E38004D6478 /* EnumerationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AD2EDFA19799E38004D6478 /* EnumerationMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AD8932917E3868F00668276 /* HeapIterationScope.h */; }; 2ADFA26318EF3540004F9FCC /* GCLogging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2ADFA26218EF3540004F9FCC /* GCLogging.cpp */; }; 2AF7382C18BBBF92008A5A37 /* StructureIDTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AF7382A18BBBF92008A5A37 /* StructureIDTable.cpp */; }; 2AF7382D18BBBF92008A5A37 /* StructureIDTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AF7382B18BBBF92008A5A37 /* StructureIDTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; 371D842D17C98B6E00ECF994 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 371D842C17C98B6E00ECF994 /* libz.dylib */; }; 41359CF30FDD89AD00206180 /* DateConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateConversion.h */; }; + 4340A4841A9051AF00D73CCA /* MathCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4340A4821A9051AF00D73CCA /* MathCommon.cpp */; }; + 4340A4851A9051AF00D73CCA /* MathCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 4340A4831A9051AF00D73CCA /* MathCommon.h */; }; 4443AE3316E188D90076F110 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51F0EB6105C86C6B00E6DF1B /* Foundation.framework */; }; 451539B912DC994500EF7AC4 /* Yarr.h in Headers */ = {isa = PBXBuildFile; fileRef = 451539B812DC994500EF7AC4 /* Yarr.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 5510502618EB827500001F3E /* JSCallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440F88F0A508B100005F061 /* JSCallbackFunction.h */; }; - 5540757218DA58AD00EFF7F2 /* ArgList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF605120E203EF800B9A64D /* ArgList.h */; }; - 5540757318DA58AD00EFF7F2 /* Arguments.h in Headers */ = {isa = PBXBuildFile; fileRef = BC257DE60E1F51C50016B6C9 /* Arguments.h */; }; - 5540757418DA58AD00EFF7F2 /* ArgumentsIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A76140C8182982CB00750624 /* ArgumentsIteratorConstructor.h */; }; - 5540757518DA58AD00EFF7F2 /* ArgumentsIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A76140CA182982CB00750624 /* ArgumentsIteratorPrototype.h */; }; - 5540757718DA58AD00EFF7F2 /* ArityCheckMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CB71861244C00845D97 /* ArityCheckMode.h */; }; - 5540757C18DA58AD00EFF7F2 /* StructureIDBlob.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AAAA31018BD49D100394CC8 /* StructureIDBlob.h */; }; - 5540758318DA58AD00EFF7F2 /* ArrayBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2617ADB5F3005AB174 /* ArrayBuffer.h */; }; - 5540758418DA58AD00EFF7F2 /* ArrayBufferNeuteringWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */; }; - 5540758518DA58AD00EFF7F2 /* ArrayBufferView.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2817ADB5F3005AB174 /* ArrayBufferView.h */; }; - 5540758618DA58AD00EFF7F2 /* ArrayConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7952070E15E8A800A898AB /* ArrayConstructor.h */; }; - 5540758718DA58AD00EFF7F2 /* ArrayConventions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */; }; - 5540758818DA58AD00EFF7F2 /* ArrayIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7BDAEC117F4EA1400F6140C /* ArrayIteratorConstructor.h */; }; - 5540758918DA58AD00EFF7F2 /* ArrayIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A7BDAEC317F4EA1400F6140C /* ArrayIteratorPrototype.h */; }; - 5540758B18DA58AD00EFF7F2 /* ArrayPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A84E0255597D01FF60F7 /* ArrayPrototype.h */; }; - 5540758D18DA58AD00EFF7F2 /* StructureIDTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AF7382B18BBBF92008A5A37 /* StructureIDTable.h */; }; - 5540758E18DA58AD00EFF7F2 /* ArrayStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */; }; - 5540759318DA58AD00EFF7F2 /* BatchedTransitionOptimizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */; }; - 5540759418DA58AD00EFF7F2 /* BigInteger.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D013BFDE710023D87C /* BigInteger.h */; }; - 5540759618DA58AD00EFF7F2 /* BooleanObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 704FD35305697E6D003DBED9 /* BooleanObject.h */; }; - 5540759A18DA58AD00EFF7F2 /* Butterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */; }; - 5540759B18DA58AD00EFF7F2 /* ButterflyInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */; }; - 554075A318DA58AD00EFF7F2 /* CallData.h in Headers */ = {isa = PBXBuildFile; fileRef = 145C507F0D9DF63B0088F6B9 /* CallData.h */; }; - 554075AB18DA58AD00EFF7F2 /* ClassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */; }; - 554075B218DA58AD00EFF7F2 /* CodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A77F1820164088B200640A47 /* CodeCache.h */; }; - 554075B718DA58AD00EFF7F2 /* CodeSpecializationKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */; }; - 554075B918DA58AD00EFF7F2 /* CommonIdentifiers.h in Headers */ = {isa = PBXBuildFile; fileRef = 65EA73630BAE35D1001BB560 /* CommonIdentifiers.h */; }; - 554075BA18DA58AD00EFF7F2 /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; }; - 554075BB18DA58AD00EFF7F2 /* CommonSlowPathsExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6553A33017A1F1EE008CF6F3 /* CommonSlowPathsExceptions.h */; }; - 554075BD18DA58AD00EFF7F2 /* CompilationResult.h in Headers */ = {isa = PBXBuildFile; fileRef = A7E5A3A61797432D00E893C0 /* CompilationResult.h */; }; - 554075BE18DA58AD00EFF7F2 /* JSConsole.h in Headers */ = {isa = PBXBuildFile; fileRef = A53CE08418BC1A5600BEDF76 /* JSConsole.h */; }; - 554075BF18DA58AD00EFF7F2 /* Completion.h in Headers */ = {isa = PBXBuildFile; fileRef = F5BB2BC5030F772101FCFE1D /* Completion.h */; }; - 554075C018DA58AD00EFF7F2 /* ConcurrentJITLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */; }; - 554075C418DA58AD00EFF7F2 /* ConsoleTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A5FD0071189B038C00633231 /* ConsoleTypes.h */; }; - 554075C518DA58AD00EFF7F2 /* ConstantMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */; }; - 554075C618DA58AD00EFF7F2 /* ConstructData.h in Headers */ = {isa = PBXBuildFile; fileRef = BC8F3CCF0DAF17BA00577A80 /* ConstructData.h */; }; - 554075D518DA58AD00EFF7F2 /* DataView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66B117B6B5AB00A7AE3F /* DataView.h */; }; - 554075D618DA58AD00EFF7F2 /* DateConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203460E17135E002C7E82 /* DateConstructor.h */; }; - 554075D718DA58AD00EFF7F2 /* DateConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateConversion.h */; }; - 554075D818DA58AD00EFF7F2 /* DateInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1166010E1997B1008066DD /* DateInstance.h */; }; - 554075D918DA58AD00EFF7F2 /* DateInstanceCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A1563010966365006FA260 /* DateInstanceCache.h */; }; - 554075DA18DA58AD00EFF7F2 /* DatePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD203480E17135E002C7E82 /* DatePrototype.h */; }; - 554075DC18DA58AD00EFF7F2 /* Debugger.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8590255597D01FF60F7 /* Debugger.h */; }; - 5540766D18DA58AD00EFF7F2 /* DumpContext.h in Headers */ = {isa = PBXBuildFile; fileRef = A70447EC17A0BD7000F5898E /* DumpContext.h */; }; - 5540767018DA58AD00EFF7F2 /* Error.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3046060E1F497F003232CF /* Error.h */; }; - 5540767118DA58AD00EFF7F2 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; }; - 5540767218DA58AD00EFF7F2 /* ErrorHandlingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FEB58C13187B8B160098EF0B /* ErrorHandlingScope.h */; }; - 5540767318DA58AD00EFF7F2 /* ErrorInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E98B0E183E38000F9297 /* ErrorInstance.h */; }; - 5540767418DA58AD00EFF7F2 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; }; - 5540767718DA58AD00EFF7F2 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; }; - 5540767818DA58AD00EFF7F2 /* Executable.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CAFEE21035DDE60028A609 /* Executable.h */; }; - 5540767E18DA58AD00EFF7F2 /* Float32Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2917ADB5F3005AB174 /* Float32Array.h */; }; - 5540767F18DA58AD00EFF7F2 /* Float64Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2A17ADB5F3005AB174 /* Float64Array.h */; }; - 5540768318DA58AD00EFF7F2 /* ConsoleClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A53CE08918BC21C300BEDF76 /* ConsoleClient.h */; }; - 5540769118DA58AD00EFF7F2 /* ConsolePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */; }; - 554076B618DA58AD00EFF7F2 /* FunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */; }; - 554076B718DA58AD00EFF7F2 /* FunctionExecutableDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B52216B6278D003F696B /* FunctionExecutableDump.h */; }; - 554076B818DA58AD00EFF7F2 /* FunctionPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A85D0255597D01FF60F7 /* FunctionPrototype.h */; }; - 554076C218DA58AD00EFF7F2 /* GenericTypedArrayView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66B217B6B5AB00A7AE3F /* GenericTypedArrayView.h */; }; - 554076C318DA58AD00EFF7F2 /* GenericTypedArrayViewInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66B317B6B5AB00A7AE3F /* GenericTypedArrayViewInlines.h */; }; - 554076D618DA58AD00EFF7F2 /* Identifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 933A349A038AE7C6008635CE /* Identifier.h */; }; - 554076DA18DA58AD00EFF7F2 /* IndexingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38D15ED8E3800F167B2 /* IndexingHeader.h */; }; - 554076DB18DA58AD00EFF7F2 /* IndexingHeaderInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */; }; - 554076DC18DA58AD00EFF7F2 /* IndexingType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */; }; - 554076DF18DA58AD00EFF7F2 /* InitializeThreading.h in Headers */ = {isa = PBXBuildFile; fileRef = E178633F0D9BEC0000D74E75 /* InitializeThreading.h */; }; - 554076F818DA58AD00EFF7F2 /* Int16Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2C17ADB5F3005AB174 /* Int16Array.h */; }; - 554076F918DA58AD00EFF7F2 /* Int32Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2D17ADB5F3005AB174 /* Int32Array.h */; }; - 554076FA18DA58AD00EFF7F2 /* Int8Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */; }; - 554076FB18DA58AD00EFF7F2 /* IntendedStructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = A78853F817972629001440E4 /* IntendedStructureChain.h */; }; - 554076FC18DA58AD00EFF7F2 /* InternalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BC11667A0E199C05008066DD /* InternalFunction.h */; }; - 554076FE18DA58AD00EFF7F2 /* Intrinsic.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BF642A148DB2B5004DE36A /* Intrinsic.h */; }; - 5540771818DA58AD00EFF7F2 /* JSActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DA818E0D99FD2000B0A4FB /* JSActivation.h */; settings = {ATTRIBUTES = (); }; }; - 5540771918DA58AD00EFF7F2 /* JSAPIValueWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0894D60FAFBA2D00001865 /* JSAPIValueWrapper.h */; }; - 5540771B18DA58AD00EFF7F2 /* JSArgumentsIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A76140CC182982CB00750624 /* JSArgumentsIterator.h */; }; - 5540771C18DA58AD00EFF7F2 /* JSArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 938772E5038BFE19008635CE /* JSArray.h */; }; - 5540771D18DA58AD00EFF7F2 /* JSArrayBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66B517B6B5AB00A7AE3F /* JSArrayBuffer.h */; }; - 5540771E18DA58AD00EFF7F2 /* JSArrayBufferConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66B717B6B5AB00A7AE3F /* JSArrayBufferConstructor.h */; }; - 5540771F18DA58AD00EFF7F2 /* JSArrayBufferPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66B917B6B5AB00A7AE3F /* JSArrayBufferPrototype.h */; }; - 5540772018DA58AD00EFF7F2 /* JSArrayBufferView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66BB17B6B5AB00A7AE3F /* JSArrayBufferView.h */; }; - 5540772118DA58AD00EFF7F2 /* JSArrayBufferViewInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66BC17B6B5AB00A7AE3F /* JSArrayBufferViewInlines.h */; }; - 5540772218DA58AD00EFF7F2 /* JSArrayIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7BDAEC517F4EA1400F6140C /* JSArrayIterator.h */; }; - 5540772518DA58AD00EFF7F2 /* (null) in Headers */ = {isa = PBXBuildFile; }; - 5540772B18DA58AD00EFF7F2 /* JSCell.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1167D80E19BCC9008066DD /* JSCell.h */; }; - 5540772C18DA58AD00EFF7F2 /* JSCellInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */; }; - 5540772D18DA58AD00EFF7F2 /* JSCInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1DD84918A945BE0026F3FA /* JSCInlines.h */; }; - 5540772E18DA58AD00EFF7F2 /* JSCJSValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABB36E099C076400E2A24F /* JSCJSValue.h */; }; - 5540772F18DA58AD00EFF7F2 /* JSCJSValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 865A30F0135007E100CDB49E /* JSCJSValueInlines.h */; }; - 5540773618DA58AD00EFF7F2 /* JSDataView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66BE17B6B5AB00A7AE3F /* JSDataView.h */; }; - 5540773718DA58AD00EFF7F2 /* JSDataViewPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C017B6B5AB00A7AE3F /* JSDataViewPrototype.h */; }; - 5540773818DA58AD00EFF7F2 /* JSDateMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9788FC231471AD0C0068CE2D /* JSDateMath.h */; }; - 5540773918DA58AD00EFF7F2 /* JSDestructibleObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A7F687160432D400F76B98 /* JSDestructibleObject.h */; }; - 5540773B18DA58AD00EFF7F2 /* JSExportMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */; }; - 5540773C18DA58AD00EFF7F2 /* JSFloat32Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C117B6B5AB00A7AE3F /* JSFloat32Array.h */; }; - 5540773D18DA58AD00EFF7F2 /* JSFloat64Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C217B6B5AB00A7AE3F /* JSFloat64Array.h */; }; - 5540773E18DA58AD00EFF7F2 /* JSFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A85F0255597D01FF60F7 /* JSFunction.h */; }; - 5540773F18DA58AD00EFF7F2 /* JSFunctionInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A72028B91797603D0098028C /* JSFunctionInlines.h */; }; - 5540774018DA58AD00EFF7F2 /* JSGenericTypedArrayView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C317B6B5AB00A7AE3F /* JSGenericTypedArrayView.h */; }; - 5540774118DA58AD00EFF7F2 /* JSGenericTypedArrayViewConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C417B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h */; }; - 5540774218DA58AD00EFF7F2 /* JSGenericTypedArrayViewConstructorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C517B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h */; }; - 5540774318DA58AD00EFF7F2 /* JSGenericTypedArrayViewInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C617B6B5AB00A7AE3F /* JSGenericTypedArrayViewInlines.h */; }; - 5540774418DA58AD00EFF7F2 /* JSGenericTypedArrayViewPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C717B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototype.h */; }; - 5540774518DA58AD00EFF7F2 /* JSGenericTypedArrayViewPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C817B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototypeInlines.h */; }; - 5540774618DA58AD00EFF7F2 /* JSGlobalObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A8E894330CD0603F00367179 /* JSGlobalObject.h */; }; - 5540774818DA58AD00EFF7F2 /* JSGlobalObjectDebuggable.h in Headers */ = {isa = PBXBuildFile; fileRef = A59455911824744700CC3843 /* JSGlobalObjectDebuggable.h */; }; - 5540774A18DA58AD00EFF7F2 /* JSGlobalObjectFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */; }; - 5540775018DA58AD00EFF7F2 /* JSInt16Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66CA17B6B5AB00A7AE3F /* JSInt16Array.h */; }; - 5540775118DA58AD00EFF7F2 /* JSInt32Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66CB17B6B5AB00A7AE3F /* JSInt32Array.h */; }; - 5540775218DA58AD00EFF7F2 /* JSInt8Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */; }; - 5540775518DA58AD00EFF7F2 /* JSLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 65EA4C9A092AF9E20093D800 /* JSLock.h */; }; - 5540775818DA58AD00EFF7F2 /* JSMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A700874017CBE8EB00C3E643 /* JSMap.h */; }; - 5540775918DA58AD00EFF7F2 /* JSMapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF90182D991400522C22 /* JSMapIterator.h */; }; - 5540775B18DA58AD00EFF7F2 /* JSNameScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 14874AE015EBDE4A002E3587 /* JSNameScope.h */; }; - 5540775C18DA58AD00EFF7F2 /* JSObject.h in Headers */ = {isa = PBXBuildFile; fileRef = BC22A3990E16E14800AF21C8 /* JSObject.h */; }; - 5540775F18DA58AD00EFF7F2 /* JSONObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9935D0FD7325100A0B2D0 /* JSONObject.h */; }; - 5540776218DA58AD00EFF7F2 /* JSPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C184E1917BEDBD3007CB63A /* JSPromise.h */; }; - 5540776318DA58AD00EFF7F2 /* JSPromiseConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C184E2117BEE240007CB63A /* JSPromiseConstructor.h */; }; - 5540776418DA58AD00EFF7F2 /* JSPromiseDeferred.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CD9187124BB00955C24 /* JSPromiseDeferred.h */; }; - 5540776518DA58AD00EFF7F2 /* JSPromiseFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CD1186F8A9300955C24 /* JSPromiseFunctions.h */; }; - 5540776618DA58AD00EFF7F2 /* JSPromisePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C184E1D17BEE22E007CB63A /* JSPromisePrototype.h */; }; - 5540776718DA58AD00EFF7F2 /* JSPromiseReaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CDD1871258D00955C24 /* JSPromiseReaction.h */; }; - 5540776818DA58AD00EFF7F2 /* JSProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 862553CF16136AA5009F17D0 /* JSProxy.h */; }; - 5540776B18DA58AD00EFF7F2 /* JSScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 14874AE215EBDE4A002E3587 /* JSScope.h */; }; - 5540776D18DA58AD00EFF7F2 /* JSSegmentedVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0F157F3327004A4E7D /* JSSegmentedVariableObject.h */; }; - 5540776E18DA58AD00EFF7F2 /* JSSet.h in Headers */ = {isa = PBXBuildFile; fileRef = A7299D9C17D12837005F5FF9 /* JSSet.h */; }; - 5540776F18DA58AD00EFF7F2 /* JSSetIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD6A182F499700588807 /* JSSetIterator.h */; }; - 5540777118DA58AD00EFF7F2 /* JSStackInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAEB17987AB600299DB2 /* JSStackInlines.h */; }; - 5540777218DA58AD00EFF7F2 /* JSString.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8620255597D01FF60F7 /* JSString.h */; }; - 5540777318DA58AD00EFF7F2 /* JSStringBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E85538111B9968001AF51E /* JSStringBuilder.h */; }; - 5540777418DA58AD00EFF7F2 /* JSStringJoiner.h in Headers */ = {isa = PBXBuildFile; fileRef = 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */; }; - 5540777818DA58AD00EFF7F2 /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; }; - 5540777918DA58AD00EFF7F2 /* JSType.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABB454099C2A0F00E2A24F /* JSType.h */; }; - 5540777A18DA58AD00EFF7F2 /* JSTypedArrayConstructors.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66CD17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h */; }; - 5540777B18DA58AD00EFF7F2 /* JSTypedArrayPrototypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66CF17B6B5AB00A7AE3F /* JSTypedArrayPrototypes.h */; }; - 5540777C18DA58AD00EFF7F2 /* JSTypedArrays.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D117B6B5AB00A7AE3F /* JSTypedArrays.h */; }; - 5540777D18DA58AD00EFF7F2 /* JSTypeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */; }; - 5540777E18DA58AD00EFF7F2 /* JSUint16Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D417B6B5AB00A7AE3F /* JSUint16Array.h */; }; - 5540777F18DA58AD00EFF7F2 /* JSUint32Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D517B6B5AB00A7AE3F /* JSUint32Array.h */; }; - 5540778018DA58AD00EFF7F2 /* JSUint8Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D217B6B5AB00A7AE3F /* JSUint8Array.h */; }; - 5540778118DA58AD00EFF7F2 /* JSUint8ClampedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D317B6B5AB00A7AE3F /* JSUint8ClampedArray.h */; }; - 5540778518DA58AD00EFF7F2 /* JSVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F252560D08DD8D004ECFFF /* JSVariableObject.h */; }; - 5540778818DA58AD00EFF7F2 /* JSWeakMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3AE217DA41AE006538AF /* JSWeakMap.h */; }; - 5540778B18DA58AD00EFF7F2 /* JSWithScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 1442566015EDE98D0066A49B /* JSWithScope.h */; }; - 5540778D18DA58AD00EFF7F2 /* JSWrapperObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C7A1720A8EAACB00FA37EA /* JSWrapperObject.h */; }; - 5540779818DA58AD00EFF7F2 /* LiteralParser.h in Headers */ = {isa = PBXBuildFile; fileRef = A7E2EA690FB460CF00601F06 /* LiteralParser.h */; }; - 554077A918DA58AD00EFF7F2 /* Lookup.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8690255597D01FF60F7 /* Lookup.h */; }; - 554077B718DA58AD00EFF7F2 /* MapConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A700873817CBE85300C3E643 /* MapConstructor.h */; }; - 554077B818DA58AD00EFF7F2 /* MapData.h in Headers */ = {isa = PBXBuildFile; fileRef = A78507D517CBC6FD0011F6E7 /* MapData.h */; }; - 554077B918DA58AD00EFF7F2 /* MapIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF8C182D991400522C22 /* MapIteratorConstructor.h */; }; - 554077BA18DA58AD00EFF7F2 /* MapIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF8E182D991400522C22 /* MapIteratorPrototype.h */; }; - 554077BB18DA58AD00EFF7F2 /* MapPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A700873C17CBE8D300C3E643 /* MapPrototype.h */; }; - 554077C118DA58AD00EFF7F2 /* MatchResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 8612E4CB1522918400C836BE /* MatchResult.h */; }; - 554077C218DA58AD00EFF7F2 /* MathObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A86B0255597D01FF60F7 /* MathObject.h */; }; - 554077C318DA58AD00EFF7F2 /* MemoryStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 90213E3C123A40C200D422F3 /* MemoryStatistics.h */; }; - 554077C518DA58AD00EFF7F2 /* Microtask.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CE5187631B600955C24 /* Microtask.h */; }; - 554077C718DA58AD00EFF7F2 /* NameConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FA1560F036008E9222 /* NameConstructor.h */; }; - 554077C818DA58AD00EFF7F2 /* NameInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FC1560F036008E9222 /* NameInstance.h */; }; - 554077C918DA58AD00EFF7F2 /* NamePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FE1560F036008E9222 /* NamePrototype.h */; }; - 554077CA18DA58AD00EFF7F2 /* NativeErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */; }; - 554077CB18DA58AD00EFF7F2 /* NativeErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E90B0E1839DB000F9297 /* NativeErrorPrototype.h */; }; - 554077D118DA58AD00EFF7F2 /* NumberConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C30E16D4E900A06E92 /* NumberConstructor.h */; }; - 554077D318DA58AD00EFF7F2 /* NumberObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8710255597D01FF60F7 /* NumberObject.h */; }; - 554077D418DA58AD00EFF7F2 /* NumberPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C50E16D4E900A06E92 /* NumberPrototype.h */; }; - 554077D618DA58AD00EFF7F2 /* NumericStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 142D3938103E4560007DCB52 /* NumericStrings.h */; }; - 554077DA18DA58AD00EFF7F2 /* ObjectConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */; }; - 554077DB18DA58AD00EFF7F2 /* ObjectPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */; }; - 554077E018DA58AD00EFF7F2 /* Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8780255597D01FF60F7 /* Operations.h */; }; - 554077E118DA58AD00EFF7F2 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; }; - 554077EA18DA58AD00EFF7F2 /* PrivateName.h in Headers */ = {isa = PBXBuildFile; fileRef = 868916A9155F285400CB2B9A /* PrivateName.h */; }; - 554077FD18DA58AD00EFF7F2 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; }; - 554077FE18DA58AD00EFF7F2 /* PropertyMapHashTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BC95437C0EBA70FD0072B6D3 /* PropertyMapHashTable.h */; }; - 554077FF18DA58AD00EFF7F2 /* PropertyName.h in Headers */ = {isa = PBXBuildFile; fileRef = 86158AB2155C8B3F00B45C9C /* PropertyName.h */; }; - 5540780018DA58AD00EFF7F2 /* PropertyNameArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 65400C100A69BAF200509887 /* PropertyNameArray.h */; }; - 5540780118DA58AD00EFF7F2 /* PropertyOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF7168A15A3B231008F5DAA /* PropertyOffset.h */; }; - 5540780318DA58AD00EFF7F2 /* PropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 65621E6C089E859700760F35 /* PropertySlot.h */; }; - 5540780418DA58AD00EFF7F2 /* PropertyStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */; }; - 5540780518DA58AD00EFF7F2 /* Protect.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C02FBB0637462A003E7EE6 /* Protect.h */; }; - 5540780618DA58AD00EFF7F2 /* PrototypeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D844A316AA2C7000A65AF0 /* PrototypeMap.h */; }; - 5540780818DA58AD00EFF7F2 /* PutDirectIndexMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */; }; - 5540780A18DA58AD00EFF7F2 /* PutPropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */; }; - 5540780E18DA58AD00EFF7F2 /* RegExp.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A87E0255597D01FF60F7 /* RegExp.h */; }; - 5540780F18DA58AD00EFF7F2 /* RegExpCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B3E11C7B228007A5315 /* RegExpCache.h */; }; - 5540781018DA58AD00EFF7F2 /* RegExpConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD202BE0E1706A7002C7E82 /* RegExpConstructor.h */; }; - 5540781218DA58AD00EFF7F2 /* RegExpKey.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B4011C7B235007A5315 /* RegExpKey.h */; }; - 5540781318DA58AD00EFF7F2 /* RegExpObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A87C0255597D01FF60F7 /* RegExpObject.h */; }; - 5540781518DA58AD00EFF7F2 /* RegExpPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */; }; - 5540781918DA58AD00EFF7F2 /* RegisterPreservationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CB81861244C00845D97 /* RegisterPreservationMode.h */; }; - 5540781D18DA58AD00EFF7F2 /* Reject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39115ED8E3800F167B2 /* Reject.h */; }; - 5540782618DA58AD00EFF7F2 /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; }; - 5540783318DA58AD00EFF7F2 /* SetConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7299DA417D12858005F5FF9 /* SetConstructor.h */; }; - 5540783418DA58AD00EFF7F2 /* SetIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD66182F499700588807 /* SetIteratorConstructor.h */; }; - 5540783518DA58AD00EFF7F2 /* SetIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD68182F499700588807 /* SetIteratorPrototype.h */; }; - 5540783618DA58AD00EFF7F2 /* SetPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A7299DA017D12848005F5FF9 /* SetPrototype.h */; }; - 5540783818DA58AD00EFF7F2 /* SimpleTypedArrayController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D717B6B5AB00A7AE3F /* SimpleTypedArrayController.h */; }; - 5540783C18DA58AD00EFF7F2 /* SmallStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 93303FEA0E6A72C000786E6A /* SmallStrings.h */; }; - 5540784118DA58AD00EFF7F2 /* SparseArrayValueMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39215ED8E3800F167B2 /* SparseArrayValueMap.h */; }; - 5540784518DA58AD00EFF7F2 /* StackAlignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC751183EA1040032029F /* StackAlignment.h */; }; - 5540784918DA58AD00EFF7F2 /* StrictEvalActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = A730B6101250068F009D25B1 /* StrictEvalActivation.h */; }; - 5540784A18DA58AD00EFF7F2 /* StringConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C3C10E16EE3300B34460 /* StringConstructor.h */; }; - 5540784B18DA58AD00EFF7F2 /* StringObject.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C3C30E16EE3300B34460 /* StringObject.h */; }; - 5540784C18DA58AD00EFF7F2 /* StringPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C3C60E16EE3300B34460 /* StringPrototype.h */; }; - 5540784F18DA58AD00EFF7F2 /* Structure.h in Headers */ = {isa = PBXBuildFile; fileRef = BCDE3AB10E6C82CF001453A7 /* Structure.h */; }; - 5540785018DA58AD00EFF7F2 /* StructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E4EE7080EBB7963005934AA /* StructureChain.h */; }; - 5540785118DA58AD00EFF7F2 /* StructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD2C92316D01EE900C7803F /* StructureInlines.h */; }; - 5540785218DA58AD00EFF7F2 /* StructureRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FE18A316BAEC4000AF3061 /* StructureRareData.h */; }; - 5540785318DA58AD00EFF7F2 /* StructureRareDataInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C20BA92C16BB1C1500B3AEA2 /* StructureRareDataInlines.h */; }; - 5540785718DA58AD00EFF7F2 /* StructureTransitionTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BC9041470EB9250900FE26FA /* StructureTransitionTable.h */; }; - 5540785918DA58AD00EFF7F2 /* SymbolTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A396A60CD2933100B5B4FF /* SymbolTable.h */; }; - 5540785C18DA58AD00EFF7F2 /* TestRunnerUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA2C17A17D7CF84009D015F /* TestRunnerUtils.h */; }; - 5540786018DA58AD00EFF7F2 /* ToNativeFromValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F55989717C86C5600A1E543 /* ToNativeFromValue.h */; }; - 5540786118DA58AD00EFF7F2 /* Tracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53726E0E1C54880021E549 /* Tracing.h */; }; - 5540786218DA58AD00EFF7F2 /* TypedArrayAdaptors.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66D817B6B5AB00A7AE3F /* TypedArrayAdaptors.h */; }; - 5540786318DA58AD00EFF7F2 /* TypedArrayController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66DA17B6B5AB00A7AE3F /* TypedArrayController.h */; }; - 5540786418DA58AD00EFF7F2 /* TypedArrayInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4B94DB17B9F07500DD03A4 /* TypedArrayInlines.h */; }; - 5540786518DA58AD00EFF7F2 /* TypedArrays.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */; }; - 5540786618DA58AD00EFF7F2 /* TypedArrayType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */; }; - 5540786E18DA58AD00EFF7F2 /* Uint16Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF3217ADB5F3005AB174 /* Uint16Array.h */; }; - 5540786F18DA58AD00EFF7F2 /* Uint16WithFraction.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D113BFDE710023D87C /* Uint16WithFraction.h */; }; - 5540787018DA58AD00EFF7F2 /* Uint32Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF3317ADB5F3005AB174 /* Uint32Array.h */; }; - 5540787118DA58AD00EFF7F2 /* Uint8Array.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */; }; - 5540787218DA58AD00EFF7F2 /* Uint8ClampedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */; }; - 5540787A18DA58AD00EFF7F2 /* VM.h in Headers */ = {isa = PBXBuildFile; fileRef = E18E3A560DF9278C00D90B34 /* VM.h */; }; - 5540787B18DA58AD00EFF7F2 /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; }; - 5540787D18DA58AD00EFF7F2 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; }; - 5540788118DA58AD00EFF7F2 /* WeakGCMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */; }; - 5540788518DA58AD00EFF7F2 /* WeakMapConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */; }; - 5540788618DA58AD00EFF7F2 /* WeakMapData.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3AEA17DA5168006538AF /* WeakMapData.h */; }; - 5540788718DA58AD00EFF7F2 /* WeakMapPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3AE017DA41AE006538AF /* WeakMapPrototype.h */; }; - 5540788818DA58AD00EFF7F2 /* WeakRandom.h in Headers */ = {isa = PBXBuildFile; fileRef = 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */; }; - 5540788D18DA58AD00EFF7F2 /* WriteBarrier.h in Headers */ = {isa = PBXBuildFile; fileRef = A7DCB77912E3D90500911940 /* WriteBarrier.h */; }; - 5540788F18DA58AD00EFF7F2 /* WriteBarrierInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2B6D75218A33793004A9301 /* WriteBarrierInlines.h */; }; - 554078AB18DA58AD00EFF7F2 /* ArrayConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7952060E15E8A800A898AB /* ArrayConstructor.cpp */; }; - 554078AF18DA58AD00EFF7F2 /* ArrayPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */; }; - 55407A3818DA58AD00EFF7F2 /* NumberConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C20E16D4E900A06E92 /* NumberConstructor.cpp */; }; - 55407A3A18DA58AD00EFF7F2 /* NumberPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C40E16D4E900A06E92 /* NumberPrototype.cpp */; }; + 52678F8E1A031009006A306D /* BasicBlockLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52678F8C1A031009006A306D /* BasicBlockLocation.cpp */; }; + 52678F8F1A031009006A306D /* BasicBlockLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 52678F8D1A031009006A306D /* BasicBlockLocation.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 52678F911A04177C006A306D /* ControlFlowProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 52678F901A04177C006A306D /* ControlFlowProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 527773DE1AAF83AC00BDE7E8 /* RuntimeType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 527773DD1AAF83AC00BDE7E8 /* RuntimeType.cpp */; }; + 52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */; }; + 52B310FF1975B4240080857C /* TypeLocationCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B310FE1975B4240080857C /* TypeLocationCache.cpp */; }; + 52B311011975B4670080857C /* TypeLocationCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B311001975B4670080857C /* TypeLocationCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 52B717B51A0597E1007AF4F3 /* ControlFlowProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52B717B41A0597E1007AF4F3 /* ControlFlowProfiler.cpp */; }; + 52C0611F1AA51E1C00B4ADBA /* RuntimeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 52C952B719A289850069B386 /* TypeProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 52C952B619A289850069B386 /* TypeProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 52C952B919A28A1C0069B386 /* TypeProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */; }; 5D53726F0E1C54880021E549 /* Tracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53726E0E1C54880021E549 /* Tracing.h */; }; 5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; }; 5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 14D857740A4696C80032146C /* testapi.js */; }; 5DBB1525131D0BD70056AD36 /* minidom.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 1412110D0A48788700480255 /* minidom.js */; }; 5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */ = {isa = PBXBuildFile; fileRef = F692A8540255597D01FF60F7 /* create_hash_table */; settings = {ATTRIBUTES = (); }; }; + 62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */; }; + 62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 62F2AA371B0BEDE300610C7A /* DFGLazyNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */; }; + 62F2AA381B0BEDE300610C7A /* DFGLazyNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; 651122FD14046A4C002B101D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; }; 651122FE14046A4C002B101D /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; }; 6511230714046B0A002B101D /* testRegExp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 651122E5140469BA002B101D /* testRegExp.cpp */; }; 6514F21918B3E1670098FF8B /* Bytecodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6514F21718B3E1670098FF8B /* Bytecodes.h */; settings = {ATTRIBUTES = (Private, ); }; }; 65303D641447B9E100D3F904 /* ParserTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = 65303D631447B9E100D3F904 /* ParserTokens.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 6546F5211A32B313006F07D5 /* NullGetterFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6546F51F1A32A59C006F07D5 /* NullGetterFunction.cpp */; }; + 65525FC51A6DD801007B5495 /* NullSetterFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65525FC31A6DD3B3007B5495 /* NullSetterFunction.cpp */; }; 6553A33117A1F1EE008CF6F3 /* CommonSlowPathsExceptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6553A32F17A1F1EE008CF6F3 /* CommonSlowPathsExceptions.cpp */; }; 6553A33217A1F1EE008CF6F3 /* CommonSlowPathsExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6553A33017A1F1EE008CF6F3 /* CommonSlowPathsExceptions.h */; }; + 65570F5A1AA4C3EA009B3C23 /* Regress141275.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65570F591AA4C00A009B3C23 /* Regress141275.mm */; }; 655EB29B10CE2581001A990E /* NodesCodegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 655EB29A10CE2581001A990E /* NodesCodegen.cpp */; }; + 657CF45819BF6662004ACBF2 /* JSCallee.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 657CF45619BF6662004ACBF2 /* JSCallee.cpp */; }; + 657CF45919BF6662004ACBF2 /* JSCallee.h in Headers */ = {isa = PBXBuildFile; fileRef = 657CF45719BF6662004ACBF2 /* JSCallee.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 658D3A5619638268003C45D6 /* VMEntryRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 658D3A5519638268003C45D6 /* VMEntryRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; 65C02850171795E200351E35 /* ARMv7Disassembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C0284F171795E200351E35 /* ARMv7Disassembler.cpp */; }; 65C0285C1717966800351E35 /* ARMv7DOpcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C0285A1717966800351E35 /* ARMv7DOpcode.cpp */; }; 65C0285D1717966800351E35 /* ARMv7DOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C0285B1717966800351E35 /* ARMv7DOpcode.h */; }; 65FB5117184EEE7000C12B70 /* ProtoCallFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65FB5116184EE9BC00C12B70 /* ProtoCallFrame.cpp */; }; - 7C008CD2186F8A9300955C24 /* JSPromiseFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C008CD0186F8A9300955C24 /* JSPromiseFunctions.cpp */; }; - 7C008CD3186F8A9300955C24 /* JSPromiseFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CD1186F8A9300955C24 /* JSPromiseFunctions.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 6AD2CB4D19B9140100065719 /* DebuggerEvalEnabler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6AD2CB4C19B9140100065719 /* DebuggerEvalEnabler.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70113D4B1A8DB093003848C4 /* IteratorOperations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70113D491A8DB093003848C4 /* IteratorOperations.cpp */; }; + 70113D4C1A8DB093003848C4 /* IteratorOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 70113D4A1A8DB093003848C4 /* IteratorOperations.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 7013CA8B1B491A9400CAE613 /* JSJob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7013CA891B491A9400CAE613 /* JSJob.cpp */; }; + 7013CA8C1B491A9400CAE613 /* JSJob.h in Headers */ = {isa = PBXBuildFile; fileRef = 7013CA8A1B491A9400CAE613 /* JSJob.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 705B41AB1A6E501E00716757 /* Symbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 705B41A31A6E501E00716757 /* Symbol.cpp */; }; + 705B41AC1A6E501E00716757 /* Symbol.h in Headers */ = {isa = PBXBuildFile; fileRef = 705B41A41A6E501E00716757 /* Symbol.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 705B41AD1A6E501E00716757 /* SymbolConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 705B41A51A6E501E00716757 /* SymbolConstructor.cpp */; }; + 705B41AE1A6E501E00716757 /* SymbolConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 705B41A61A6E501E00716757 /* SymbolConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 705B41AF1A6E501E00716757 /* SymbolObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 705B41A71A6E501E00716757 /* SymbolObject.cpp */; }; + 705B41B01A6E501E00716757 /* SymbolObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 705B41A81A6E501E00716757 /* SymbolObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 705B41B11A6E501E00716757 /* SymbolPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 705B41A91A6E501E00716757 /* SymbolPrototype.cpp */; }; + 705B41B21A6E501E00716757 /* SymbolPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 705B41AA1A6E501E00716757 /* SymbolPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 7094C4DE1AE439530041A2EE /* BytecodeIntrinsicRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7094C4DC1AE439530041A2EE /* BytecodeIntrinsicRegistry.cpp */; }; + 7094C4DF1AE439530041A2EE /* BytecodeIntrinsicRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 7094C4DD1AE439530041A2EE /* BytecodeIntrinsicRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 709FB8671AE335C60039D069 /* JSWeakSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709FB8611AE335C60039D069 /* JSWeakSet.cpp */; }; + 709FB8681AE335C60039D069 /* JSWeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 709FB8621AE335C60039D069 /* JSWeakSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 709FB8691AE335C60039D069 /* WeakSetConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709FB8631AE335C60039D069 /* WeakSetConstructor.cpp */; }; + 709FB86A1AE335C60039D069 /* WeakSetConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 709FB8641AE335C60039D069 /* WeakSetConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 709FB86B1AE335C60039D069 /* WeakSetPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 709FB8651AE335C60039D069 /* WeakSetPrototype.cpp */; }; + 709FB86C1AE335C60039D069 /* WeakSetPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 709FB8661AE335C60039D069 /* WeakSetPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70B0A9D11A9B66460001306A /* RuntimeFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 70B0A9D01A9B66200001306A /* RuntimeFlags.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70DC3E091B2DF2C700054299 /* IteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70DC3E071B2DF2C700054299 /* IteratorPrototype.cpp */; }; + 70DC3E0A1B2DF2C700054299 /* IteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 70DC3E081B2DF2C700054299 /* IteratorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70EC0EC21AA0D7DA00B6AAFA /* JSStringIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70EC0EBC1AA0D7DA00B6AAFA /* JSStringIterator.cpp */; }; + 70EC0EC31AA0D7DA00B6AAFA /* JSStringIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 70EC0EBD1AA0D7DA00B6AAFA /* JSStringIterator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70EC0EC61AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70EC0EC01AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp */; }; + 70EC0EC71AA0D7DA00B6AAFA /* StringIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 70EC0EC11AA0D7DA00B6AAFA /* StringIteratorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70ECA6051AFDBEA200449739 /* JSTemplateRegistryKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70ECA6001AFDBEA200449739 /* JSTemplateRegistryKey.cpp */; }; + 70ECA6061AFDBEA200449739 /* JSTemplateRegistryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6011AFDBEA200449739 /* JSTemplateRegistryKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70ECA6071AFDBEA200449739 /* TemplateRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 70ECA6021AFDBEA200449739 /* TemplateRegistry.cpp */; }; + 70ECA6081AFDBEA200449739 /* TemplateRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6031AFDBEA200449739 /* TemplateRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 70ECA6091AFDBEA200449739 /* TemplateRegistryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 70ECA6041AFDBEA200449739 /* TemplateRegistryKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7C008CDA187124BB00955C24 /* JSPromiseDeferred.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C008CD8187124BB00955C24 /* JSPromiseDeferred.cpp */; }; 7C008CDB187124BB00955C24 /* JSPromiseDeferred.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CD9187124BB00955C24 /* JSPromiseDeferred.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 7C008CDE1871258D00955C24 /* JSPromiseReaction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C008CDC1871258D00955C24 /* JSPromiseReaction.cpp */; }; - 7C008CDF1871258D00955C24 /* JSPromiseReaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CDD1871258D00955C24 /* JSPromiseReaction.h */; }; 7C008CE7187631B600955C24 /* Microtask.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C008CE5187631B600955C24 /* Microtask.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7C184E1A17BEDBD3007CB63A /* JSPromise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C184E1817BEDBD3007CB63A /* JSPromise.cpp */; }; 7C184E1B17BEDBD3007CB63A /* JSPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C184E1917BEDBD3007CB63A /* JSPromise.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1090,7 +1034,6 @@ 7C184E2317BEE240007CB63A /* JSPromiseConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C184E2117BEE240007CB63A /* JSPromiseConstructor.h */; }; 7E4EE7090EBB7963005934AA /* StructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E4EE7080EBB7963005934AA /* StructureChain.h */; settings = {ATTRIBUTES = (Private, ); }; }; 7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */; }; - 7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; 840480131021A1D9008E7F01 /* JSAPIValueWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = BC0894D60FAFBA2D00001865 /* JSAPIValueWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; }; 860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */; settings = {ATTRIBUTES = (Private, ); }; }; 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */ = {isa = PBXBuildFile; fileRef = 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1115,7 +1058,7 @@ 86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B7E12DBA33700A9FE7B /* YarrInterpreter.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86704B8612DBA33700A9FE7B /* YarrJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86704B7F12DBA33700A9FE7B /* YarrJIT.cpp */; }; 86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8012DBA33700A9FE7B /* YarrJIT.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8112DBA33700A9FE7B /* YarrParser.h */; settings = {ATTRIBUTES = (); }; }; + 86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8112DBA33700A9FE7B /* YarrParser.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86704B8912DBA33700A9FE7B /* YarrPattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86704B8212DBA33700A9FE7B /* YarrPattern.cpp */; }; 86704B8A12DBA33700A9FE7B /* YarrPattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8312DBA33700A9FE7B /* YarrPattern.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */; }; @@ -1161,12 +1104,6 @@ 86E3C61C167BABEE006D760A /* JSVirtualMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 86E3C610167BAB87006D760A /* JSVirtualMachine.mm */; }; 86E3C61D167BABEE006D760A /* JSVirtualMachineInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E3C611167BAB87006D760A /* JSVirtualMachineInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86E85539111B9968001AF51E /* JSStringBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 86E85538111B9968001AF51E /* JSStringBuilder.h */; }; - 86EBF2FF1560F06A008E9222 /* NameConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EBF2F91560F036008E9222 /* NameConstructor.cpp */; }; - 86EBF3001560F06A008E9222 /* NameConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FA1560F036008E9222 /* NameConstructor.h */; }; - 86EBF3011560F06A008E9222 /* NameInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EBF2FB1560F036008E9222 /* NameInstance.cpp */; }; - 86EBF3021560F06A008E9222 /* NameInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FC1560F036008E9222 /* NameInstance.h */; }; - 86EBF3031560F06A008E9222 /* NamePrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EBF2FD1560F036008E9222 /* NamePrototype.cpp */; }; - 86EBF3041560F06A008E9222 /* NamePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EBF2FE1560F036008E9222 /* NamePrototype.h */; }; 86EC9DC41328DF82002B2AD7 /* DFGByteCodeParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */; }; 86EC9DC51328DF82002B2AD7 /* DFGByteCodeParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */; settings = {ATTRIBUTES = (Private, ); }; }; 86EC9DC61328DF82002B2AD7 /* DFGGenerationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EC9DB61328DF82002B2AD7 /* DFGGenerationInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1222,7 +1159,7 @@ 978801411471AD920041B016 /* JSDateMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9788FC231471AD0C0068CE2D /* JSDateMath.h */; settings = {ATTRIBUTES = (Private, ); }; }; 9928FF3B18AC4AEC00B8CF12 /* JSReplayInputs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9928FF3918AC4AEC00B8CF12 /* JSReplayInputs.cpp */; }; 9928FF3C18AC4AEC00B8CF12 /* JSReplayInputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 9928FF3A18AC4AEC00B8CF12 /* JSReplayInputs.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 996231E918D1804200C03FDA /* InspectorJSBackendCommands.js in Headers */ = {isa = PBXBuildFile; fileRef = A53243961856A475002ED692 /* InspectorJSBackendCommands.js */; settings = {ATTRIBUTES = (Private, ); }; }; + 996231E918D1804200C03FDA /* InspectorBackendCommands.js in Headers */ = {isa = PBXBuildFile; fileRef = A53243961856A475002ED692 /* InspectorBackendCommands.js */; settings = {ATTRIBUTES = (Private, ); }; }; 99CC0B6218BE9946006CEBCC /* CodeGeneratorReplayInputsTemplates.py in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1E18A1B1E70026D88F /* CodeGeneratorReplayInputsTemplates.py */; settings = {ATTRIBUTES = (Private, ); }; }; 99CC0B6318BE9950006CEBCC /* CodeGeneratorReplayInputs.py in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1D18A1B1E70026D88F /* CodeGeneratorReplayInputs.py */; settings = {ATTRIBUTES = (Private, ); }; }; 99E45A2418A1B2590026D88F /* EmptyInputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1F18A1B2590026D88F /* EmptyInputCursor.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1230,6 +1167,13 @@ 99E45A2618A1B2590026D88F /* EncodedValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2118A1B2590026D88F /* EncodedValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; 99E45A2718A1B2590026D88F /* InputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2218A1B2590026D88F /* InputCursor.h */; settings = {ATTRIBUTES = (Private, ); }; }; 99E45A2818A1B2590026D88F /* NondeterministicInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2318A1B2590026D88F /* NondeterministicInput.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 9E729407190F01A5001A91B5 /* InitializeThreading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */; }; + 9E729408190F021E001A91B5 /* InitializeLLVMPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFAC51805E75500472CE4 /* InitializeLLVMPOSIX.cpp */; }; + 9E72940B190F0514001A91B5 /* BundlePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E72940A190F0514001A91B5 /* BundlePath.h */; }; + 9EA5C7A1190F084200508EBE /* BundlePath.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9E729409190F0306001A91B5 /* BundlePath.mm */; }; + 9EA5C7A2190F088700508EBE /* InitializeLLVMMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9EA5C7A0190F05D200508EBE /* InitializeLLVMMac.cpp */; }; + A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A12BBFF11B044A8B00664B69 /* IntlObject.h */; }; + A12BBFF41B044A9800664B69 /* IntlObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A12BBFF31B044A9800664B69 /* IntlObject.cpp */; }; A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1712B3A11C7B212007A5315 /* RegExpCache.cpp */; }; A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B3E11C7B228007A5315 /* RegExpCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */ = {isa = PBXBuildFile; fileRef = A1712B4011C7B235007A5315 /* RegExpKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1264,16 +1208,14 @@ A513E5CB185F9624007E95AD /* InjectedScriptManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A513E5C9185F9624007E95AD /* InjectedScriptManager.h */; settings = {ATTRIBUTES = (Private, ); }; }; A514B2C2185A684400F3C7CB /* InjectedScriptBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */; }; A514B2C3185A684400F3C7CB /* InjectedScriptBase.h in Headers */ = {isa = PBXBuildFile; fileRef = A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A532438718568335002ED692 /* InspectorJSBackendDispatchers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438118568317002ED692 /* InspectorJSBackendDispatchers.cpp */; }; - A532438818568335002ED692 /* InspectorJSBackendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438218568317002ED692 /* InspectorJSBackendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A532438918568335002ED692 /* InspectorJSFrontendDispatchers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438318568317002ED692 /* InspectorJSFrontendDispatchers.cpp */; }; - A532438A18568335002ED692 /* InspectorJSFrontendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438418568317002ED692 /* InspectorJSFrontendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A532438B18568335002ED692 /* InspectorJSTypeBuilders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438518568317002ED692 /* InspectorJSTypeBuilders.cpp */; }; - A532438C18568335002ED692 /* InspectorJSTypeBuilders.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438618568317002ED692 /* InspectorJSTypeBuilders.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A532439218569709002ED692 /* CodeGeneratorInspector.py in Headers */ = {isa = PBXBuildFile; fileRef = A532438F185696E6002ED692 /* CodeGeneratorInspector.py */; settings = {ATTRIBUTES = (Private, ); }; }; - A532439318569709002ED692 /* CodeGeneratorInspectorStrings.py in Headers */ = {isa = PBXBuildFile; fileRef = A5324390185696E6002ED692 /* CodeGeneratorInspectorStrings.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A532438718568335002ED692 /* InspectorBackendDispatchers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438118568317002ED692 /* InspectorBackendDispatchers.cpp */; }; + A532438818568335002ED692 /* InspectorBackendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438218568317002ED692 /* InspectorBackendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A532438918568335002ED692 /* InspectorFrontendDispatchers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438318568317002ED692 /* InspectorFrontendDispatchers.cpp */; }; + A532438A18568335002ED692 /* InspectorFrontendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438418568317002ED692 /* InspectorFrontendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A532438B18568335002ED692 /* InspectorProtocolObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438518568317002ED692 /* InspectorProtocolObjects.cpp */; }; + A532438C18568335002ED692 /* InspectorProtocolObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438618568317002ED692 /* InspectorProtocolObjects.h */; settings = {ATTRIBUTES = (Private, ); }; }; A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */ = {isa = PBXBuildFile; fileRef = A5324391185696E6002ED692 /* generate-combined-inspector-json.py */; settings = {ATTRIBUTES = (Private, ); }; }; - A53243981856A489002ED692 /* InspectorJS.json in Headers */ = {isa = PBXBuildFile; fileRef = A53243951856A475002ED692 /* InspectorJS.json */; settings = {ATTRIBUTES = (Private, ); }; }; + A53243981856A489002ED692 /* CombinedDomains.json in Headers */ = {isa = PBXBuildFile; fileRef = A53243951856A475002ED692 /* CombinedDomains.json */; settings = {ATTRIBUTES = (Private, ); }; }; A53CE08518BC1A5600BEDF76 /* ConsolePrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */; }; A53CE08618BC1A5600BEDF76 /* ConsolePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */; }; A53CE08718BC1A5600BEDF76 /* JSConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A53CE08318BC1A5600BEDF76 /* JSConsole.cpp */; }; @@ -1288,9 +1230,11 @@ A54CF2FA184EAEDA00237F19 /* ScriptObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A54CF2F8184EAEDA00237F19 /* ScriptObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; A54E8EB018BFFBBB00556D28 /* GCSegmentedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A343F7418A1748B0039B085 /* GCSegmentedArray.h */; settings = {ATTRIBUTES = (Private, ); }; }; A54E8EB118BFFBBE00556D28 /* GCSegmentedArrayInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A343F7718A1749D0039B085 /* GCSegmentedArrayInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A552C37F1ADDB8FE00139726 /* JSRemoteInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A552C37D1ADDB8FE00139726 /* JSRemoteInspector.cpp */; }; + A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; A55D93A5185012A800400DED /* ScriptFunctionCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A55D93A3185012A800400DED /* ScriptFunctionCall.cpp */; }; A55D93A6185012A800400DED /* ScriptFunctionCall.h in Headers */ = {isa = PBXBuildFile; fileRef = A55D93A4185012A800400DED /* ScriptFunctionCall.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A55D93AC18514F7900400DED /* InspectorTypeBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A55D93AB18514F7900400DED /* InspectorTypeBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A55D93AC18514F7900400DED /* InspectorProtocolTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A55D93AB18514F7900400DED /* InspectorProtocolTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; A57D23E51890CEBF0031C7FA /* InspectorDebuggerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A57D23E31890CEBF0031C7FA /* InspectorDebuggerAgent.cpp */; }; A57D23E61890CEBF0031C7FA /* InspectorDebuggerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A57D23E41890CEBF0031C7FA /* InspectorDebuggerAgent.h */; settings = {ATTRIBUTES = (Private, ); }; }; A57D23E91891B0770031C7FA /* JSGlobalObjectDebuggerAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A57D23E71891B0770031C7FA /* JSGlobalObjectDebuggerAgent.cpp */; }; @@ -1328,11 +1272,32 @@ A5BA15ED182340B400A82E69 /* RemoteInspectorXPCConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = A5BA15E6182340B300A82E69 /* RemoteInspectorXPCConnection.h */; settings = {ATTRIBUTES = (Private, ); }; }; A5BA15EE182340B400A82E69 /* RemoteInspectorXPCConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = A5BA15E7182340B300A82E69 /* RemoteInspectorXPCConnection.mm */; }; A5BA15F0182345AF00A82E69 /* RemoteInspectorDebuggable.h in Headers */ = {isa = PBXBuildFile; fileRef = A5BA15EF182345AF00A82E69 /* RemoteInspectorDebuggable.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A5C3A1A518C0490200C9593A /* JSConsoleClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5C3A1A318C0490200C9593A /* JSConsoleClient.cpp */; }; - A5C3A1A618C0490200C9593A /* JSConsoleClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A5C3A1A418C0490200C9593A /* JSConsoleClient.h */; }; + A5C3A1A518C0490200C9593A /* JSGlobalObjectConsoleClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5C3A1A318C0490200C9593A /* JSGlobalObjectConsoleClient.cpp */; }; + A5C3A1A618C0490200C9593A /* JSGlobalObjectConsoleClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A5C3A1A418C0490200C9593A /* JSGlobalObjectConsoleClient.h */; }; A5CEEE14187F3BAD00E55C99 /* InspectorAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5CEEE12187F3BAD00E55C99 /* InspectorAgent.cpp */; }; A5D0A1BB1862301B00C7B496 /* InspectorEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A5D0A1BA1862301B00C7B496 /* InspectorEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; }; A5D2E665195E174000A518E7 /* JSContextRefInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A5D2E664195E173800A518E7 /* JSContextRefInternal.h */; }; + A5EA70E719F5B1010098F5EC /* AugmentableInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70E419F5B1010098F5EC /* AugmentableInspectorController.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA70E819F5B1010098F5EC /* AugmentableInspectorControllerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70E519F5B1010098F5EC /* AugmentableInspectorControllerClient.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA70E919F5B1010098F5EC /* AlternateDispatchableAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70E619F5B1010098F5EC /* AlternateDispatchableAgent.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA70EC19F5B3EA0098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70EA19F5B3D50098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA70EE19F5B5C40098F5EC /* JSContextRefInspectorSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70ED19F5B5C40098F5EC /* JSContextRefInspectorSupport.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710319F6DE6F0098F5EC /* generate_objc_backend_dispatcher_header.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70EF19F6DE5A0098F5EC /* generate_objc_backend_dispatcher_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710419F6DE720098F5EC /* generate_objc_backend_dispatcher_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F019F6DE5A0098F5EC /* generate_objc_backend_dispatcher_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710519F6DE740098F5EC /* generate_objc_configuration_header.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F119F6DE5A0098F5EC /* generate_objc_configuration_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710619F6DE760098F5EC /* generate_objc_configuration_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F219F6DE5A0098F5EC /* generate_objc_configuration_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710719F6DE780098F5EC /* generate_objc_conversion_helpers.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F319F6DE5A0098F5EC /* generate_objc_conversion_helpers.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710819F6DE7A0098F5EC /* generate_objc_frontend_dispatcher_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F419F6DE5A0098F5EC /* generate_objc_frontend_dispatcher_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710919F6DE7C0098F5EC /* generate_objc_header.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F519F6DE5A0098F5EC /* generate_objc_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710A19F6DE7E0098F5EC /* generate_objc_internal_header.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F619F6DE5A0098F5EC /* generate_objc_internal_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710C19F6DE820098F5EC /* objc_generator.py in Headers */ = {isa = PBXBuildFile; fileRef = A5EA70F819F6DE5A0098F5EC /* objc_generator.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EA710E19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A5EA710D19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EF9B141A1D43F600702E90 /* generate_cpp_backend_dispatcher_header.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D11A05C76F005CAB76 /* generate_cpp_backend_dispatcher_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EF9B151A1D43FA00702E90 /* generate_cpp_backend_dispatcher_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D21A05C76F005CAB76 /* generate_cpp_backend_dispatcher_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EF9B161A1D440000702E90 /* generate_cpp_frontend_dispatcher_header.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D31A05C76F005CAB76 /* generate_cpp_frontend_dispatcher_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EF9B171A1D440300702E90 /* generate_cpp_frontend_dispatcher_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D41A05C76F005CAB76 /* generate_cpp_frontend_dispatcher_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EF9B181A1D440600702E90 /* generate_cpp_protocol_types_header.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D51A05C76F005CAB76 /* generate_cpp_protocol_types_header.py */; settings = {ATTRIBUTES = (Private, ); }; }; + A5EF9B191A1D440700702E90 /* generate_cpp_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D61A05C76F005CAB76 /* generate_cpp_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; A5FD0067189AFE9C00633231 /* ScriptArguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FD0065189AFE9C00633231 /* ScriptArguments.cpp */; }; A5FD0068189AFE9C00633231 /* ScriptArguments.h in Headers */ = {isa = PBXBuildFile; fileRef = A5FD0066189AFE9C00633231 /* ScriptArguments.h */; settings = {ATTRIBUTES = (Private, ); }; }; A5FD006D189B00AA00633231 /* ScriptCallFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FD0069189B00A900633231 /* ScriptCallFrame.cpp */; }; @@ -1366,15 +1331,12 @@ A704D90717A0BAA8006BA554 /* DFGMergeMode.h in Headers */ = {isa = PBXBuildFile; fileRef = A704D90217A0BAA8006BA554 /* DFGMergeMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; A709F2F017A0AC0400512E98 /* SlowPathCall.h in Headers */ = {isa = PBXBuildFile; fileRef = A709F2EF17A0AC0400512E98 /* SlowPathCall.h */; settings = {ATTRIBUTES = (Private, ); }; }; A709F2F217A0AC2A00512E98 /* CommonSlowPaths.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A709F2F117A0AC2A00512E98 /* CommonSlowPaths.cpp */; }; - A70B083217A0B79B00DAF14B /* DFGBinarySwitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A70B083017A0B79B00DAF14B /* DFGBinarySwitch.cpp */; }; - A70B083317A0B79B00DAF14B /* DFGBinarySwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = A70B083117A0B79B00DAF14B /* DFGBinarySwitch.h */; }; A71236E51195F33C00BD2174 /* JITOpcodes32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */; }; A72028B61797601E0098028C /* JSCTestRunnerUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72028B41797601E0098028C /* JSCTestRunnerUtils.cpp */; }; A72028B81797601E0098028C /* JSCTestRunnerUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = A72028B51797601E0098028C /* JSCTestRunnerUtils.h */; settings = {ATTRIBUTES = (Private, ); }; }; A72028BA1797603D0098028C /* JSFunctionInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A72028B91797603D0098028C /* JSFunctionInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A72700780DAC605600E548D7 /* JSNotAnObject.cpp */; }; A72701B90DADE94900E548D7 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; }; - A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */; }; A7280A2811557E3000D56957 /* JSObjectRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A79EDB0811531CD60019E912 /* JSObjectRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; A729009C17976C6000317298 /* MacroAssemblerARMv7.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A729009B17976C6000317298 /* MacroAssemblerARMv7.cpp */; }; A7299D9D17D12837005F5FF9 /* JSSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7299D9B17D12837005F5FF9 /* JSSet.cpp */; }; @@ -1395,27 +1357,16 @@ A7386556118697B400540279 /* ThunkGenerators.h in Headers */ = {isa = PBXBuildFile; fileRef = A7386553118697B400540279 /* ThunkGenerators.h */; settings = {ATTRIBUTES = (Private, ); }; }; A73A535A1799CD5D00170C19 /* DFGLazyJSValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */; }; A73A535B1799CD5D00170C19 /* DFGLazyJSValue.h in Headers */ = {isa = PBXBuildFile; fileRef = A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A73E1330179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A73E132C179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp */; }; - A73E1331179624CD00E4DEA8 /* DFGDesiredStructureChains.h in Headers */ = {isa = PBXBuildFile; fileRef = A73E132D179624CD00E4DEA8 /* DFGDesiredStructureChains.h */; settings = {ATTRIBUTES = (Private, ); }; }; A741017F179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = A741017E179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7482B9311671147003B0712 /* JSWeakObjectMapRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7482B9411671147003B0712 /* JSWeakObjectMapRefPrivate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7482B7A1166CDEA003B0712 /* JSWeakObjectMapRefPrivate.cpp */; }; A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A74DE1D0120B875600D40D5B /* ARMv7Assembler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A74DE1CB120B86D600D40D5B /* ARMv7Assembler.cpp */; }; - A74DEF91182D991400522C22 /* MapIteratorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A74DEF8B182D991400522C22 /* MapIteratorConstructor.cpp */; }; - A74DEF92182D991400522C22 /* MapIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF8C182D991400522C22 /* MapIteratorConstructor.h */; }; A74DEF93182D991400522C22 /* MapIteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A74DEF8D182D991400522C22 /* MapIteratorPrototype.cpp */; }; A74DEF94182D991400522C22 /* MapIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF8E182D991400522C22 /* MapIteratorPrototype.h */; }; A74DEF95182D991400522C22 /* JSMapIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A74DEF8F182D991400522C22 /* JSMapIterator.cpp */; }; - A74DEF96182D991400522C22 /* JSMapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF90182D991400522C22 /* JSMapIterator.h */; }; + A74DEF96182D991400522C22 /* JSMapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A74DEF90182D991400522C22 /* JSMapIterator.h */; settings = {ATTRIBUTES = (Private, ); }; }; A75706DE118A2BCF0057F88F /* JITArithmetic32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */; }; A75EE9B218AAB7E200AAD043 /* BuiltinNames.h in Headers */ = {isa = PBXBuildFile; fileRef = A75EE9B018AAB7E200AAD043 /* BuiltinNames.h */; }; - A76140CD182982CB00750624 /* ArgumentsIteratorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A76140C7182982CB00750624 /* ArgumentsIteratorConstructor.cpp */; }; - A76140CE182982CB00750624 /* ArgumentsIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A76140C8182982CB00750624 /* ArgumentsIteratorConstructor.h */; }; - A76140CF182982CB00750624 /* ArgumentsIteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A76140C9182982CB00750624 /* ArgumentsIteratorPrototype.cpp */; }; - A76140D0182982CB00750624 /* ArgumentsIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A76140CA182982CB00750624 /* ArgumentsIteratorPrototype.h */; }; - A76140D1182982CB00750624 /* JSArgumentsIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A76140CB182982CB00750624 /* JSArgumentsIterator.cpp */; }; - A76140D2182982CB00750624 /* JSArgumentsIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A76140CC182982CB00750624 /* JSArgumentsIterator.h */; }; A766B44F0EE8DCD1009518CA /* ExecutableAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; A767B5B517A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A767B5B317A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.cpp */; }; A767B5B617A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = A767B5B417A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1434,7 +1385,6 @@ A77F1825164192C700640A47 /* ParserModes.h in Headers */ = {isa = PBXBuildFile; fileRef = A77F18241641925400640A47 /* ParserModes.h */; settings = {ATTRIBUTES = (Private, ); }; }; A784A26111D16622005776AC /* ASTBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7411B98B8D0065A14F /* ASTBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; }; A784A26411D16622005776AC /* SyntaxChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A7EE7711B98B8D0065A14F /* SyntaxChecker.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A78507D617CBC6FD0011F6E7 /* MapData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78507D417CBC6FD0011F6E7 /* MapData.cpp */; }; A78507D717CBC6FD0011F6E7 /* MapData.h in Headers */ = {isa = PBXBuildFile; fileRef = A78507D517CBC6FD0011F6E7 /* MapData.h */; settings = {ATTRIBUTES = (Private, ); }; }; A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; A78853F917972629001440E4 /* IntendedStructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78853F717972629001440E4 /* IntendedStructureChain.cpp */; }; @@ -1450,12 +1400,10 @@ A78A977F179738D5009DF744 /* FTLGeneratedFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = A78A977C179738D5009DF744 /* FTLGeneratedFunction.h */; }; A78A9780179738D5009DF744 /* FTLJITFinalizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78A977D179738D5009DF744 /* FTLJITFinalizer.cpp */; }; A78A9781179738D5009DF744 /* FTLJITFinalizer.h in Headers */ = {isa = PBXBuildFile; fileRef = A78A977E179738D5009DF744 /* FTLJITFinalizer.h */; }; - A790DD6B182F499700588807 /* SetIteratorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A790DD65182F499700588807 /* SetIteratorConstructor.cpp */; }; - A790DD6C182F499700588807 /* SetIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD66182F499700588807 /* SetIteratorConstructor.h */; }; A790DD6D182F499700588807 /* SetIteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A790DD67182F499700588807 /* SetIteratorPrototype.cpp */; }; A790DD6E182F499700588807 /* SetIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD68182F499700588807 /* SetIteratorPrototype.h */; }; A790DD6F182F499700588807 /* JSSetIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A790DD69182F499700588807 /* JSSetIterator.cpp */; }; - A790DD70182F499700588807 /* JSSetIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD6A182F499700588807 /* JSSetIterator.h */; }; + A790DD70182F499700588807 /* JSSetIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A790DD6A182F499700588807 /* JSSetIterator.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7986D5717A0BB1E00A95DD0 /* DFGEdgeUsesStructure.h in Headers */ = {isa = PBXBuildFile; fileRef = A7986D5617A0BB1E00A95DD0 /* DFGEdgeUsesStructure.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7A4AE0817973B26005612B1 /* MacroAssemblerX86Common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A4AE0717973B26005612B1 /* MacroAssemblerX86Common.cpp */; }; A7A4AE1017973B4D005612B1 /* JITStubsX86Common.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A4AE0C17973B4D005612B1 /* JITStubsX86Common.h */; }; @@ -1475,8 +1423,6 @@ A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */; }; A7B4ACAF1484C9CE00B38A36 /* JSExportMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = A79E781F15EECBA80047C855 /* UnlinkedCodeBlock.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A7BDAEC617F4EA1400F6140C /* ArrayIteratorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7BDAEC017F4EA1400F6140C /* ArrayIteratorConstructor.cpp */; }; - A7BDAEC717F4EA1400F6140C /* ArrayIteratorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7BDAEC117F4EA1400F6140C /* ArrayIteratorConstructor.h */; }; A7BDAEC817F4EA1400F6140C /* ArrayIteratorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7BDAEC217F4EA1400F6140C /* ArrayIteratorPrototype.cpp */; }; A7BDAEC917F4EA1400F6140C /* ArrayIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A7BDAEC317F4EA1400F6140C /* ArrayIteratorPrototype.h */; }; A7BDAECA17F4EA1400F6140C /* JSArrayIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7BDAEC417F4EA1400F6140C /* JSArrayIterator.cpp */; }; @@ -1537,6 +1483,7 @@ A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7FCC26D17A0B6AA00786D1A /* FTLSwitchCase.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FCC26C17A0B6AA00786D1A /* FTLSwitchCase.h */; settings = {ATTRIBUTES = (Private, ); }; }; A8A4748E151A8306004123FF /* libWTF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8A4748D151A8306004123FF /* libWTF.a */; }; + AD86A93E1AA4D88D002FE77F /* WeakGCMapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; ADDB1F6318D77DBE009B58A8 /* OpaqueRootSet.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */; }; B59F89391891F29F00D5CCDC /* UnlinkedInstructionStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B59F89381891ADB500D5CCDC /* UnlinkedInstructionStream.cpp */; }; @@ -1567,7 +1514,7 @@ BC18C4130E16F5CD00B34460 /* JavaScript.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAA8B4A0D32C39A0041BCFF /* JavaScript.h */; settings = {ATTRIBUTES = (Public, ); }; }; BC18C4140E16F5CD00B34460 /* JavaScriptCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAA8B4B0D32C39A0041BCFF /* JavaScriptCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; BC18C4150E16F5CD00B34460 /* JavaScriptCorePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = F5C290E60284F98E018635CA /* JavaScriptCorePrefix.h */; }; - BC18C4160E16F5CD00B34460 /* JSActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DA818E0D99FD2000B0A4FB /* JSActivation.h */; settings = {ATTRIBUTES = (); }; }; + BC18C4160E16F5CD00B34460 /* JSLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DA818E0D99FD2000B0A4FB /* JSLexicalEnvironment.h */; settings = {ATTRIBUTES = (); }; }; BC18C4170E16F5CD00B34460 /* JSArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 938772E5038BFE19008635CE /* JSArray.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4180E16F5CD00B34460 /* JSBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 142711380A460BBB0080EEEA /* JSBase.h */; settings = {ATTRIBUTES = (Public, ); }; }; BC18C4190E16F5CD00B34460 /* JSCallbackConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440F8AC0A508D200005F061 /* JSCallbackConstructor.h */; }; @@ -1589,7 +1536,7 @@ BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABB454099C2A0F00E2A24F /* JSType.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C42B0E16F5CD00B34460 /* JSCJSValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 14ABB36E099C076400E2A24F /* JSCJSValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C42C0E16F5CD00B34460 /* JSValueRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 1482B6EA0A4300B300517CFC /* JSValueRef.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F252560D08DD8D004ECFFF /* JSVariableObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BC18C42D0E16F5CD00B34460 /* JSEnvironmentRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F252560D08DD8D004ECFFF /* JSEnvironmentRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 65C7A1720A8EAACB00FA37EA /* JSWrapperObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4310E16F5CD00B34460 /* Lexer.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8660255597D01FF60F7 /* Lexer.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4370E16F5CD00B34460 /* Lookup.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8690255597D01FF60F7 /* Lookup.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1621,12 +1568,8 @@ BC18C46B0E16F5CD00B34460 /* SymbolTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A396A60CD2933100B5B4FF /* SymbolTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C47A0E16F5CD00B34460 /* WebKitAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */; settings = {ATTRIBUTES = (Public, ); }; }; BC18C5240E16FC8A00B34460 /* ArrayPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C5230E16FC8A00B34460 /* ArrayPrototype.lut.h */; }; - BC18C52C0E16FCD200B34460 /* RegExpObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52B0E16FCD200B34460 /* RegExpObject.lut.h */; }; BC18C52E0E16FCE100B34460 /* Lexer.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52D0E16FCE100B34460 /* Lexer.lut.h */; }; - BC257DE80E1F51C50016B6C9 /* Arguments.h in Headers */ = {isa = PBXBuildFile; fileRef = BC257DE60E1F51C50016B6C9 /* Arguments.h */; }; BC3046070E1F497F003232CF /* Error.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3046060E1F497F003232CF /* Error.h */; settings = {ATTRIBUTES = (Private, ); }; }; - BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */ = {isa = PBXBuildFile; fileRef = BC3135620F302FA3003DFD3A /* DebuggerActivation.h */; settings = {ATTRIBUTES = (Private, ); }; }; - BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */; }; BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC756FC90E2031B200DE7D12 /* JSGlobalObjectFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */; }; BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC87CDB810712ACA000614CF /* JSONObject.lut.h */; }; @@ -1648,7 +1591,6 @@ BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCFD8C900EEB2EE700283848 /* JumpTable.cpp */; }; BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; C20328201981979D0088B499 /* CustomGlobalObjectClassTest.c in Sources */ = {isa = PBXBuildFile; fileRef = C203281E1981979D0088B499 /* CustomGlobalObjectClassTest.c */; }; - C20B25991706536200C21F4E /* Region.h in Headers */ = {isa = PBXBuildFile; fileRef = C20B25981706536200C21F4E /* Region.h */; settings = {ATTRIBUTES = (Private, ); }; }; C20BA92D16BB1C1500B3AEA2 /* StructureRareDataInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C20BA92C16BB1C1500B3AEA2 /* StructureRareDataInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 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, ); }; }; @@ -1685,12 +1627,9 @@ C2C0F7CE17BBFC5B00464FE4 /* DFGDesiredTransitions.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C0F7CC17BBFC5B00464FE4 /* DFGDesiredTransitions.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, ); }; }; C2CF39C116E15A8100DD69BE /* JSAPIWrapperObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.mm */; }; C2CF39C216E15A8100DD69BE /* JSAPIWrapperObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */; }; C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DA778218E259990066FCB6 /* HeapInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; - C2DF442F1707AC0100A5CA96 /* SuperRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2DF442D1707AC0100A5CA96 /* SuperRegion.cpp */; }; - C2DF44301707AC0100A5CA96 /* SuperRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = C2DF442E1707AC0100A5CA96 /* SuperRegion.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2E526BB1590EF000054E48D /* HeapTimer.cpp */; }; C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E526BC1590EF000054E48D /* HeapTimer.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAA3F8149A830800FCE112 /* CopiedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1702,20 +1641,42 @@ C2FCAE1217A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */; }; C2FCAE1317A9C24E0034C735 /* BytecodeLivenessAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */; settings = {ATTRIBUTES = (Private, ); }; }; C2FE18A416BAEC4000AF3061 /* StructureRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FE18A316BAEC4000AF3061 /* StructureRareData.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C442CB251A6CDB8C005D3D7C /* JSInputs.json in Headers */ = {isa = PBXBuildFile; fileRef = 9928FF3D18AC4B1C00B8CF12 /* JSInputs.json */; settings = {ATTRIBUTES = (Private, ); }; }; + C4703CC0192844960013FBEA /* generate-inspector-protocol-bindings.py in Headers */ = {isa = PBXBuildFile; fileRef = C4703CBF192844960013FBEA /* generate-inspector-protocol-bindings.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4703CCE192844CC0013FBEA /* generate_js_backend_commands.py in Headers */ = {isa = PBXBuildFile; fileRef = C4703CC3192844CC0013FBEA /* generate_js_backend_commands.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4703CD5192844CC0013FBEA /* generator_templates.py in Headers */ = {isa = PBXBuildFile; fileRef = C4703CCA192844CC0013FBEA /* generator_templates.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4703CD6192844CC0013FBEA /* generator.py in Headers */ = {isa = PBXBuildFile; fileRef = C4703CCB192844CC0013FBEA /* generator.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4703CD7192844CC0013FBEA /* models.py in Headers */ = {isa = PBXBuildFile; fileRef = C4703CCC192844CC0013FBEA /* models.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4F4B6F31A05C944005CAB76 /* cpp_generator_templates.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6CF1A05C76F005CAB76 /* cpp_generator_templates.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4F4B6F41A05C944005CAB76 /* cpp_generator.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D01A05C76F005CAB76 /* cpp_generator.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4F4B6F51A05C984005CAB76 /* generate_objc_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D71A05C76F005CAB76 /* generate_objc_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; }; + C4F4B6F61A05C984005CAB76 /* objc_generator_templates.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D81A05C76F005CAB76 /* objc_generator_templates.py */; settings = {ATTRIBUTES = (Private, ); }; }; + DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */; settings = {ATTRIBUTES = (Private, ); }; }; E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; }; E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; }; - E178636D0D9BEEC300D74E75 /* InitializeThreading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */; }; E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E3A570DF9278C00D90B34 /* VM.cpp */; }; E49DC16B12EF293E00184A1F /* SourceProviderCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E49DC15512EF277200184A1F /* SourceProviderCache.cpp */; }; E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC15112EF272200184A1F /* SourceProviderCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE0D4A061AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */; }; + FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */; }; + FE1C0FFD1B193E9800B53FCA /* Exception.h in Headers */ = {isa = PBXBuildFile; fileRef = FE1C0FFC1B193E9800B53FCA /* Exception.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE1C0FFF1B194FD100B53FCA /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1C0FFE1B194FD100B53FCA /* Exception.cpp */; }; FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; }; FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; }; - FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */; }; - FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4A331E15BD2E07006F54F3 /* VMInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; - FE5248F9191442D900B7FDE4 /* VariableWatchpointSetInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE384EE51ADDB7AD0055DE2C /* JSDollarVM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */; }; + FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE384EE71ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */; }; + FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE4BFF2B1AD476E700088F87 /* FunctionOverrides.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */; }; + FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */; }; + FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4D55B71AE716CA0052E459 /* IterationStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE5068651AE246390009DAB7 /* DeferredSourceDump.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5068641AE246390009DAB7 /* DeferredSourceDump.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE5068671AE25E280009DAB7 /* DeferredSourceDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5068661AE25E280009DAB7 /* DeferredSourceDump.cpp */; }; FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */; }; FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */; }; + FE7BA6101A1A7CEC00F1F7B4 /* HeapVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */; settings = {ATTRIBUTES = (Private, ); }; }; FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; }; FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB51F6B1A97B688001F921C /* Regress141809.mm */; }; @@ -1725,6 +1686,7 @@ FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */; }; FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = FED94F2C171E3E2300BE77A4 /* Watchdog.h */; settings = {ATTRIBUTES = (Private, ); }; }; FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */; }; + FEF040511AAE662D00BD28B0 /* CompareAndSwapTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */; }; FEF6835E174343CC00A32E25 /* JITStubsARM.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF6835A174343CC00A32E25 /* JITStubsARM.h */; settings = {ATTRIBUTES = (Private, ); }; }; FEF6835F174343CC00A32E25 /* JITStubsARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF6835B174343CC00A32E25 /* JITStubsARMv7.h */; settings = {ATTRIBUTES = (Private, ); }; }; FEF68360174343CC00A32E25 /* JITStubsX86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF6835C174343CC00A32E25 /* JITStubsX86_64.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1746,34 +1708,6 @@ remoteGlobalIDString = 0F4680A914BA7FD900BFE272; remoteInfo = "LLInt Offsets"; }; - 5540756418DA58AD00EFF7F2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0FCEFAB51805D61600472CE4; - remoteInfo = llvmForJSC; - }; - 5540756618DA58AD00EFF7F2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 65788A9D18B409EB00C189FF; - remoteInfo = "Offline Assembler"; - }; - 5540756818DA58AD00EFF7F2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 65FB3F6609D11E9100F49DEB; - remoteInfo = "Generate Derived Sources"; - }; - 55F8FC2B18EB937B00783E6E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 5540756218DA58AD00EFF7F2; - remoteInfo = CompileRuntimeToLLVMIR; - }; 5D69E911152BE5470028D720 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -1886,11 +1820,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0F0123301944EA1B00843A0C /* DFGValueStrength.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValueStrength.cpp; path = dfg/DFGValueStrength.cpp; sourceTree = "<group>"; }; + 0F0123311944EA1B00843A0C /* DFGValueStrength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGValueStrength.h; path = dfg/DFGValueStrength.h; sourceTree = "<group>"; }; 0F0332BF18ADFAE1005F979A /* ExitingJITType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExitingJITType.cpp; sourceTree = "<group>"; }; 0F0332C118B01763005F979A /* GetByIdVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetByIdVariant.cpp; sourceTree = "<group>"; }; 0F0332C218B01763005F979A /* GetByIdVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetByIdVariant.h; sourceTree = "<group>"; }; 0F0332C518B53FA9005F979A /* FTLWeight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLWeight.h; path = ftl/FTLWeight.h; sourceTree = "<group>"; }; 0F0332C718B546EC005F979A /* FTLWeightedTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLWeightedTarget.h; path = ftl/FTLWeightedTarget.h; sourceTree = "<group>"; }; + 0F04396B1B03DC0B009598B7 /* DFGCombinedLiveness.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCombinedLiveness.cpp; path = dfg/DFGCombinedLiveness.cpp; sourceTree = "<group>"; }; + 0F04396C1B03DC0B009598B7 /* DFGCombinedLiveness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCombinedLiveness.h; path = dfg/DFGCombinedLiveness.h; sourceTree = "<group>"; }; 0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayifySlowPathGenerator.h; path = dfg/DFGArrayifySlowPathGenerator.h; sourceTree = "<group>"; }; 0F0776BD14FF002800102332 /* JITCompilationEffort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCompilationEffort.h; sourceTree = "<group>"; }; 0F0B839714BCF45A00885B4F /* LLIntThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntThunks.cpp; path = llint/LLIntThunks.cpp; sourceTree = "<group>"; }; @@ -1904,6 +1842,8 @@ 0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutDirectIndexMode.h; sourceTree = "<group>"; }; 0F0CD4C315F6B6B50032F1C0 /* SparseArrayValueMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SparseArrayValueMap.cpp; sourceTree = "<group>"; }; 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntCallLinkInfo.h; sourceTree = "<group>"; }; + 0F12DE0D1979D5FD0006FF4E /* ExceptionFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionFuzz.cpp; sourceTree = "<group>"; }; + 0F12DE0E1979D5FD0006FF4E /* ExceptionFuzz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionFuzz.h; sourceTree = "<group>"; }; 0F136D4B174AD69B0075B354 /* DeferGC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeferGC.h; sourceTree = "<group>"; }; 0F13912416771C30009CCB07 /* ProfilerBytecodeSequence.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerBytecodeSequence.cpp; path = profiler/ProfilerBytecodeSequence.cpp; sourceTree = "<group>"; }; 0F13912516771C30009CCB07 /* ProfilerBytecodeSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerBytecodeSequence.h; path = profiler/ProfilerBytecodeSequence.h; sourceTree = "<group>"; }; @@ -1911,8 +1851,7 @@ 0F13912716771C30009CCB07 /* ProfilerProfiledBytecodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerProfiledBytecodes.h; path = profiler/ProfilerProfiledBytecodes.h; sourceTree = "<group>"; }; 0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexingType.cpp; sourceTree = "<group>"; }; 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPaths.h; sourceTree = "<group>"; }; - 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArgumentsSimplificationPhase.cpp; path = dfg/DFGArgumentsSimplificationPhase.cpp; sourceTree = "<group>"; }; - 0F16015B156198BF00C2587C /* DFGArgumentsSimplificationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArgumentsSimplificationPhase.h; path = dfg/DFGArgumentsSimplificationPhase.h; sourceTree = "<group>"; }; + 0F1725FE1B48719A00AC3A55 /* DFGMinifiedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedGraph.cpp; path = dfg/DFGMinifiedGraph.cpp; sourceTree = "<group>"; }; 0F190CAA189D82F6000AE5F0 /* ProfilerJettisonReason.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerJettisonReason.cpp; path = profiler/ProfilerJettisonReason.cpp; sourceTree = "<group>"; }; 0F190CAB189D82F6000AE5F0 /* ProfilerJettisonReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerJettisonReason.h; path = profiler/ProfilerJettisonReason.h; sourceTree = "<group>"; }; 0F1DD84918A945BE0026F3FA /* JSCInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCInlines.h; sourceTree = "<group>"; }; @@ -1921,6 +1860,7 @@ 0F1E3A501537C2CB000F9456 /* DFGSlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSlowPathGenerator.h; path = dfg/DFGSlowPathGenerator.h; sourceTree = "<group>"; }; 0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSilentRegisterSavePlan.h; path = dfg/DFGSilentRegisterSavePlan.h; sourceTree = "<group>"; }; 0F1FE51B1922A3BC006987C5 /* AbortReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbortReason.h; sourceTree = "<group>"; }; + 0F20C2581A8013AB00DA3229 /* VirtualRegister.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VirtualRegister.cpp; sourceTree = "<group>"; }; 0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeSpecializationKind.h; sourceTree = "<group>"; }; 0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeConventions.h; sourceTree = "<group>"; }; 0F235BBD17178E1C00690C7F /* FTLExitArgument.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLExitArgument.cpp; path = ftl/FTLExitArgument.cpp; sourceTree = "<group>"; }; @@ -2018,13 +1958,30 @@ 0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrays.h; sourceTree = "<group>"; }; 0F2B66DC17B6B5AB00A7AE3F /* TypedArrayType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypedArrayType.cpp; sourceTree = "<group>"; }; 0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrayType.h; sourceTree = "<group>"; }; + 0F2B9CD619D0BA7D00B1D1B5 /* DFGAvailabilityMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAvailabilityMap.cpp; path = dfg/DFGAvailabilityMap.cpp; sourceTree = "<group>"; }; + 0F2B9CD719D0BA7D00B1D1B5 /* DFGAvailabilityMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAvailabilityMap.h; path = dfg/DFGAvailabilityMap.h; sourceTree = "<group>"; }; + 0F2B9CD819D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGInsertOSRHintsForUpdate.cpp; path = dfg/DFGInsertOSRHintsForUpdate.cpp; sourceTree = "<group>"; }; + 0F2B9CD919D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInsertOSRHintsForUpdate.h; path = dfg/DFGInsertOSRHintsForUpdate.h; sourceTree = "<group>"; }; + 0F2B9CDA19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGObjectAllocationSinkingPhase.cpp; path = dfg/DFGObjectAllocationSinkingPhase.cpp; sourceTree = "<group>"; }; + 0F2B9CDB19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGObjectAllocationSinkingPhase.h; path = dfg/DFGObjectAllocationSinkingPhase.h; sourceTree = "<group>"; }; + 0F2B9CDC19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGObjectMaterializationData.cpp; path = dfg/DFGObjectMaterializationData.cpp; sourceTree = "<group>"; }; + 0F2B9CDD19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGObjectMaterializationData.h; path = dfg/DFGObjectMaterializationData.h; sourceTree = "<group>"; }; + 0F2B9CDE19D0BA7D00B1D1B5 /* DFGPhiChildren.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPhiChildren.cpp; path = dfg/DFGPhiChildren.cpp; sourceTree = "<group>"; }; + 0F2B9CDF19D0BA7D00B1D1B5 /* DFGPhiChildren.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPhiChildren.h; path = dfg/DFGPhiChildren.h; sourceTree = "<group>"; }; + 0F2B9CE019D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPromotedHeapLocation.cpp; path = dfg/DFGPromotedHeapLocation.cpp; sourceTree = "<group>"; }; + 0F2B9CE119D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPromotedHeapLocation.h; path = dfg/DFGPromotedHeapLocation.h; sourceTree = "<group>"; }; + 0F2B9CEE19D0BAC100B1D1B5 /* FTLExitPropertyValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLExitPropertyValue.cpp; path = ftl/FTLExitPropertyValue.cpp; sourceTree = "<group>"; }; + 0F2B9CEF19D0BAC100B1D1B5 /* FTLExitPropertyValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLExitPropertyValue.h; path = ftl/FTLExitPropertyValue.h; sourceTree = "<group>"; }; + 0F2B9CF019D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLExitTimeObjectMaterialization.cpp; path = ftl/FTLExitTimeObjectMaterialization.cpp; sourceTree = "<group>"; }; + 0F2B9CF119D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLExitTimeObjectMaterialization.h; path = ftl/FTLExitTimeObjectMaterialization.h; sourceTree = "<group>"; }; + 0F2B9CF219D0BAC100B1D1B5 /* FTLOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLOperations.cpp; path = ftl/FTLOperations.cpp; sourceTree = "<group>"; }; + 0F2B9CF319D0BAC100B1D1B5 /* FTLOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLOperations.h; path = ftl/FTLOperations.h; sourceTree = "<group>"; }; 0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFixupPhase.cpp; path = dfg/DFGFixupPhase.cpp; sourceTree = "<group>"; }; 0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFixupPhase.h; path = dfg/DFGFixupPhase.h; sourceTree = "<group>"; }; 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInsertionSet.h; path = dfg/DFGInsertionSet.h; sourceTree = "<group>"; }; 0F2BDC2B151FDE8B00CD8910 /* Operands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Operands.h; sourceTree = "<group>"; }; 0F2BDC3D1522801700CD8910 /* DFGMinifiedGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedGraph.h; path = dfg/DFGMinifiedGraph.h; sourceTree = "<group>"; }; 0F2BDC3E1522801700CD8910 /* DFGMinifiedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedNode.h; path = dfg/DFGMinifiedNode.h; sourceTree = "<group>"; }; - 0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGValueRecoveryOverride.h; path = dfg/DFGValueRecoveryOverride.h; sourceTree = "<group>"; }; 0F2BDC401522801700CD8910 /* DFGValueSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGValueSource.h; path = dfg/DFGValueSource.h; sourceTree = "<group>"; }; 0F2BDC411522801700CD8910 /* DFGVariableEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableEvent.h; path = dfg/DFGVariableEvent.h; sourceTree = "<group>"; }; 0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEventStream.cpp; path = dfg/DFGVariableEventStream.cpp; sourceTree = "<group>"; }; @@ -2032,6 +1989,21 @@ 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedNode.cpp; path = dfg/DFGMinifiedNode.cpp; sourceTree = "<group>"; }; 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValueSource.cpp; path = dfg/DFGValueSource.cpp; sourceTree = "<group>"; }; 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = "<group>"; }; + 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerScope.cpp; sourceTree = "<group>"; }; + 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerScope.h; sourceTree = "<group>"; }; + 0F2D4DDF19832D91007D4B19 /* TypeProfilerLog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeProfilerLog.cpp; sourceTree = "<group>"; }; + 0F2D4DE019832D91007D4B19 /* TypeProfilerLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeProfilerLog.h; sourceTree = "<group>"; }; + 0F2D4DE319832D91007D4B19 /* TypeSet.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeSet.cpp; sourceTree = "<group>"; }; + 0F2D4DE419832D91007D4B19 /* TypeSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeSet.h; sourceTree = "<group>"; }; + 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ToThisStatus.cpp; sourceTree = "<group>"; }; + 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ToThisStatus.h; sourceTree = "<group>"; }; + 0F2D4DE719832DAC007D4B19 /* TypeLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeLocation.h; sourceTree = "<group>"; }; + 0F2DD80A1AB3D85800BBB8E8 /* BytecodeKills.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeKills.h; sourceTree = "<group>"; }; + 0F2DD80C1AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArgumentsEliminationPhase.cpp; path = dfg/DFGArgumentsEliminationPhase.cpp; sourceTree = "<group>"; }; + 0F2DD80D1AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArgumentsEliminationPhase.h; path = dfg/DFGArgumentsEliminationPhase.h; sourceTree = "<group>"; }; + 0F2DD80E1AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArgumentsUtilities.cpp; path = dfg/DFGArgumentsUtilities.cpp; sourceTree = "<group>"; }; + 0F2DD80F1AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArgumentsUtilities.h; path = dfg/DFGArgumentsUtilities.h; sourceTree = "<group>"; }; + 0F2DD8101AB3D8BE00BBB8E8 /* DFGForAllKills.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGForAllKills.h; path = dfg/DFGForAllKills.h; sourceTree = "<group>"; }; 0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDCEPhase.cpp; path = dfg/DFGDCEPhase.cpp; sourceTree = "<group>"; }; 0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDCEPhase.h; path = dfg/DFGDCEPhase.h; sourceTree = "<group>"; }; 0F2FCCF218A60070001A27F8 /* DFGGraphSafepoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGGraphSafepoint.cpp; path = dfg/DFGGraphSafepoint.cpp; sourceTree = "<group>"; }; @@ -2053,6 +2025,10 @@ 0F38B01417CFE75500B144D3 /* DFGCompilationKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCompilationKey.h; path = dfg/DFGCompilationKey.h; sourceTree = "<group>"; }; 0F38B01517CFE75500B144D3 /* DFGCompilationMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCompilationMode.cpp; path = dfg/DFGCompilationMode.cpp; sourceTree = "<group>"; }; 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCompilationMode.h; path = dfg/DFGCompilationMode.h; sourceTree = "<group>"; }; + 0F392C871B46188400844728 /* DFGOSRExitFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitFuzz.cpp; path = dfg/DFGOSRExitFuzz.cpp; sourceTree = "<group>"; }; + 0F392C881B46188400844728 /* DFGOSRExitFuzz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitFuzz.h; path = dfg/DFGOSRExitFuzz.h; sourceTree = "<group>"; }; + 0F3A1BF71A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPutStackSinkingPhase.cpp; path = dfg/DFGPutStackSinkingPhase.cpp; sourceTree = "<group>"; }; + 0F3A1BF81A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPutStackSinkingPhase.h; path = dfg/DFGPutStackSinkingPhase.h; sourceTree = "<group>"; }; 0F3AC751183EA1040032029F /* StackAlignment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackAlignment.h; sourceTree = "<group>"; }; 0F3AC753188E5EC80032029F /* ExitingJITType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExitingJITType.h; sourceTree = "<group>"; }; 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGConstantFoldingPhase.cpp; path = dfg/DFGConstantFoldingPhase.cpp; sourceTree = "<group>"; }; @@ -2061,6 +2037,12 @@ 0F3B3A251544C991003ED0FF /* DFGCFGSimplificationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFGSimplificationPhase.h; path = dfg/DFGCFGSimplificationPhase.h; sourceTree = "<group>"; }; 0F3B3A2915474FF4003ED0FF /* DFGValidate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValidate.cpp; path = dfg/DFGValidate.cpp; sourceTree = "<group>"; }; 0F3B3A2A15474FF4003ED0FF /* DFGValidate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGValidate.h; path = dfg/DFGValidate.h; sourceTree = "<group>"; }; + 0F3B7E2419A11B8000D9BC56 /* CallVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallVariant.cpp; sourceTree = "<group>"; }; + 0F3B7E2519A11B8000D9BC56 /* CallVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallVariant.h; sourceTree = "<group>"; }; + 0F3D0BBA194A414300FC9CF9 /* ConstantStructureCheck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConstantStructureCheck.cpp; sourceTree = "<group>"; }; + 0F3D0BBB194A414300FC9CF9 /* ConstantStructureCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantStructureCheck.h; sourceTree = "<group>"; }; + 0F3E01A819D353A500F61B7F /* DFGPrePostNumbering.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPrePostNumbering.cpp; path = dfg/DFGPrePostNumbering.cpp; sourceTree = "<group>"; }; + 0F3E01A919D353A500F61B7F /* DFGPrePostNumbering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPrePostNumbering.h; path = dfg/DFGPrePostNumbering.h; sourceTree = "<group>"; }; 0F426A451460CBAB00131F8F /* ValueRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueRecovery.h; sourceTree = "<group>"; }; 0F426A461460CBAB00131F8F /* VirtualRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VirtualRegister.h; sourceTree = "<group>"; }; 0F426A4A1460CD6B00131F8F /* DataFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataFormat.h; sourceTree = "<group>"; }; @@ -2092,6 +2074,7 @@ 0F4CED5D18CEA7AB00802FE0 /* PolymorphicGetByIdList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolymorphicGetByIdList.h; sourceTree = "<group>"; }; 0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStaticExecutionCountEstimationPhase.cpp; path = dfg/DFGStaticExecutionCountEstimationPhase.cpp; sourceTree = "<group>"; }; 0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStaticExecutionCountEstimationPhase.h; path = dfg/DFGStaticExecutionCountEstimationPhase.h; sourceTree = "<group>"; }; + 0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureClobberState.h; path = dfg/DFGStructureClobberState.h; sourceTree = "<group>"; }; 0F5541AF1613C1FB00CE3E25 /* SpecialPointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpecialPointer.cpp; sourceTree = "<group>"; }; 0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpecialPointer.h; sourceTree = "<group>"; }; 0F55989717C86C5600A1E543 /* ToNativeFromValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToNativeFromValue.h; sourceTree = "<group>"; }; @@ -2102,6 +2085,10 @@ 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutionCounter.cpp; sourceTree = "<group>"; }; 0F572D4D16879FDB00E57FBD /* ThunkGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThunkGenerator.h; sourceTree = "<group>"; }; 0F5780A118FE1E98001E72D9 /* PureNaN.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureNaN.h; sourceTree = "<group>"; }; + 0F5874EB194FEB1200AAB2C1 /* DFGMayExit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMayExit.cpp; path = dfg/DFGMayExit.cpp; sourceTree = "<group>"; }; + 0F5874EC194FEB1200AAB2C1 /* DFGMayExit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMayExit.h; path = dfg/DFGMayExit.h; sourceTree = "<group>"; }; + 0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDoesGC.cpp; path = dfg/DFGDoesGC.cpp; sourceTree = "<group>"; }; + 0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDoesGC.h; path = dfg/DFGDoesGC.h; sourceTree = "<group>"; }; 0F5A52CF17ADD717008ECB2D /* CopyToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyToken.h; sourceTree = "<group>"; }; 0F5A6281188C98D40072C9DF /* FTLValueRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLValueRange.cpp; path = ftl/FTLValueRange.cpp; sourceTree = "<group>"; }; 0F5A6282188C98D40072C9DF /* FTLValueRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLValueRange.h; path = ftl/FTLValueRange.h; sourceTree = "<group>"; }; @@ -2111,6 +2098,8 @@ 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAbstractValue.h; path = dfg/DFGAbstractValue.h; sourceTree = "<group>"; }; 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBasicBlock.h; path = dfg/DFGBasicBlock.h; sourceTree = "<group>"; }; 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessData.h; path = dfg/DFGVariableAccessData.h; sourceTree = "<group>"; }; + 0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPhantomInsertionPhase.cpp; path = dfg/DFGPhantomInsertionPhase.cpp; sourceTree = "<group>"; }; + 0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPhantomInsertionPhase.h; path = dfg/DFGPhantomInsertionPhase.h; sourceTree = "<group>"; }; 0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGTypeCheckHoistingPhase.cpp; path = dfg/DFGTypeCheckHoistingPhase.cpp; sourceTree = "<group>"; }; 0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGTypeCheckHoistingPhase.h; path = dfg/DFGTypeCheckHoistingPhase.h; sourceTree = "<group>"; }; 0F63945115D07051006A597C /* ArrayProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayProfile.cpp; sourceTree = "<group>"; }; @@ -2118,14 +2107,20 @@ 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureAbstractValue.h; path = dfg/DFGStructureAbstractValue.h; sourceTree = "<group>"; }; 0F63948115E48114006A597C /* DFGArrayMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGArrayMode.cpp; path = dfg/DFGArrayMode.cpp; sourceTree = "<group>"; }; 0F63948215E48114006A597C /* DFGArrayMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayMode.h; path = dfg/DFGArrayMode.h; sourceTree = "<group>"; }; + 0F64B26F1A784BAF006E4E66 /* BinarySwitch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BinarySwitch.cpp; sourceTree = "<group>"; }; + 0F64B2701A784BAF006E4E66 /* BinarySwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BinarySwitch.h; sourceTree = "<group>"; }; + 0F64B2771A7957B2006E4E66 /* CallEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallEdge.cpp; sourceTree = "<group>"; }; + 0F64B2781A7957B2006E4E66 /* CallEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallEdge.h; sourceTree = "<group>"; }; 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeLivenessAnalysisInlines.h; sourceTree = "<group>"; }; 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullBytecodeLiveness.h; sourceTree = "<group>"; }; 0F666EC21835672B00D017F1 /* DFGAvailability.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAvailability.cpp; path = dfg/DFGAvailability.cpp; sourceTree = "<group>"; }; 0F666EC31835672B00D017F1 /* DFGAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAvailability.h; path = dfg/DFGAvailability.h; sourceTree = "<group>"; }; - 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGResurrectionForValidationPhase.cpp; path = dfg/DFGResurrectionForValidationPhase.cpp; sourceTree = "<group>"; }; - 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGResurrectionForValidationPhase.h; path = dfg/DFGResurrectionForValidationPhase.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>"; }; + 0F682FB019BCB36400FA3BAD /* DFGSSACalculator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSSACalculator.cpp; path = dfg/DFGSSACalculator.cpp; sourceTree = "<group>"; }; + 0F682FB119BCB36400FA3BAD /* DFGSSACalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSSACalculator.h; path = dfg/DFGSSACalculator.h; sourceTree = "<group>"; }; + 0F69CC86193AC60A0045759E /* DFGFrozenValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFrozenValue.cpp; path = dfg/DFGFrozenValue.cpp; sourceTree = "<group>"; }; + 0F69CC87193AC60A0045759E /* DFGFrozenValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFrozenValue.h; path = dfg/DFGFrozenValue.h; sourceTree = "<group>"; }; 0F6B1CB3185FC9E900845D97 /* FTLJSCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLJSCall.cpp; path = ftl/FTLJSCall.cpp; sourceTree = "<group>"; }; 0F6B1CB4185FC9E900845D97 /* FTLJSCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLJSCall.h; path = ftl/FTLJSCall.h; sourceTree = "<group>"; }; 0F6B1CB71861244C00845D97 /* ArityCheckMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArityCheckMode.h; sourceTree = "<group>"; }; @@ -2138,13 +2133,15 @@ 0F6B1CC21862C47800845D97 /* FTLUnwindInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLUnwindInfo.h; path = ftl/FTLUnwindInfo.h; sourceTree = "<group>"; }; 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArityCheckFailReturnThunks.cpp; sourceTree = "<group>"; }; 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArityCheckFailReturnThunks.h; sourceTree = "<group>"; }; + 0F6C734E1AC9F99F00BE1682 /* VariableWriteFireDetail.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableWriteFireDetail.cpp; sourceTree = "<group>"; }; + 0F6C734F1AC9F99F00BE1682 /* VariableWriteFireDetail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableWriteFireDetail.h; sourceTree = "<group>"; }; 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessData.cpp; path = dfg/DFGVariableAccessData.cpp; sourceTree = "<group>"; }; + 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexGetStatus.cpp; sourceTree = "<group>"; }; + 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexGetStatus.h; sourceTree = "<group>"; }; 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitCompilerCommon.cpp; path = dfg/DFGOSRExitCompilerCommon.cpp; sourceTree = "<group>"; }; 0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitCompilerCommon.h; path = dfg/DFGOSRExitCompilerCommon.h; sourceTree = "<group>"; }; 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBackwardsPropagationPhase.cpp; path = dfg/DFGBackwardsPropagationPhase.cpp; sourceTree = "<group>"; }; 0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBackwardsPropagationPhase.h; path = dfg/DFGBackwardsPropagationPhase.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>"; }; 0F7576D018E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessorCallJITStubRoutine.cpp; sourceTree = "<group>"; }; 0F7576D118E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessorCallJITStubRoutine.h; sourceTree = "<group>"; }; 0F766D1C15A5028D008F363E /* JITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutine.h; sourceTree = "<group>"; }; @@ -2157,11 +2154,20 @@ 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureStubClearingWatchpoint.h; sourceTree = "<group>"; }; 0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; }; 0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; }; + 0F79085319A290B200F6310C /* DFGStructureRegistrationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStructureRegistrationPhase.cpp; path = dfg/DFGStructureRegistrationPhase.cpp; sourceTree = "<group>"; }; + 0F79085419A290B200F6310C /* DFGStructureRegistrationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStructureRegistrationPhase.h; path = dfg/DFGStructureRegistrationPhase.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>"; }; 0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeUseDef.h; sourceTree = "<group>"; }; + 0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStructureAbstractValue.cpp; path = dfg/DFGStructureAbstractValue.cpp; sourceTree = "<group>"; }; + 0F898F2F1B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGIntegerRangeOptimizationPhase.cpp; path = dfg/DFGIntegerRangeOptimizationPhase.cpp; sourceTree = "<group>"; }; + 0F898F301B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGIntegerRangeOptimizationPhase.h; path = dfg/DFGIntegerRangeOptimizationPhase.h; sourceTree = "<group>"; }; + 0F8F142F1ADF090100ED792C /* DFGEpoch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGEpoch.cpp; path = dfg/DFGEpoch.cpp; sourceTree = "<group>"; }; + 0F8F14301ADF090100ED792C /* DFGEpoch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEpoch.h; path = dfg/DFGEpoch.h; sourceTree = "<group>"; }; + 0F8F14311ADF090100ED792C /* DFGMovHintRemovalPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMovHintRemovalPhase.cpp; path = dfg/DFGMovHintRemovalPhase.cpp; sourceTree = "<group>"; }; + 0F8F14321ADF090100ED792C /* DFGMovHintRemovalPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMovHintRemovalPhase.h; path = dfg/DFGMovHintRemovalPhase.h; sourceTree = "<group>"; }; 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = FTLLink.cpp; path = ftl/FTLLink.cpp; sourceTree = "<group>"; }; 0F8F2B94172E049E007DBDA5 /* FTLLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLLink.h; path = ftl/FTLLink.h; sourceTree = "<group>"; }; 0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredIdentifiers.cpp; path = dfg/DFGDesiredIdentifiers.cpp; sourceTree = "<group>"; }; @@ -2173,7 +2179,6 @@ 0F8F943F1667632D00D61971 /* CodeType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeType.cpp; sourceTree = "<group>"; }; 0F8F94431667635200D61971 /* JITCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITCode.cpp; sourceTree = "<group>"; }; 0F8F9445166764EE00D61971 /* CodeOrigin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeOrigin.cpp; sourceTree = "<group>"; }; - 0F9181C618415CA50057B669 /* VariableWatchpointSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableWatchpointSet.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>"; }; @@ -2190,9 +2195,12 @@ 0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = "<group>"; }; 0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdVariant.cpp; sourceTree = "<group>"; }; 0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdVariant.h; sourceTree = "<group>"; }; + 0F952ABA1B487A7700C367C5 /* TrackedReferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackedReferences.cpp; sourceTree = "<group>"; }; + 0F952ABB1B487A7700C367C5 /* TrackedReferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackedReferences.h; sourceTree = "<group>"; }; 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = "<group>"; }; 0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockWithJITType.h; sourceTree = "<group>"; }; 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCellInlines.h; sourceTree = "<group>"; }; + 0F978B3A1AAEA71D007C7369 /* ConstantMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConstantMode.cpp; sourceTree = "<group>"; }; 0F98205D16BFE37F00240D02 /* PreciseJumpTargets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreciseJumpTargets.cpp; sourceTree = "<group>"; }; 0F98205E16BFE37F00240D02 /* PreciseJumpTargets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreciseJumpTargets.h; sourceTree = "<group>"; }; 0F9C5E5C18E35F5E00D431C3 /* FTLDWARFRegister.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLDWARFRegister.cpp; path = ftl/FTLDWARFRegister.cpp; sourceTree = "<group>"; }; @@ -2202,6 +2210,10 @@ 0F9D339517FFC4E60073C2BC /* DFGFlushedAt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFlushedAt.h; path = dfg/DFGFlushedAt.h; sourceTree = "<group>"; }; 0F9D33981803ADB70073C2BC /* FTLStackMaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLStackMaps.cpp; path = ftl/FTLStackMaps.cpp; sourceTree = "<group>"; }; 0F9D33991803ADB70073C2BC /* FTLStackMaps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLStackMaps.h; path = ftl/FTLStackMaps.h; sourceTree = "<group>"; }; + 0F9D36921AE9CC33000D4DFB /* DFGCleanUpPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCleanUpPhase.cpp; path = dfg/DFGCleanUpPhase.cpp; sourceTree = "<group>"; }; + 0F9D36931AE9CC33000D4DFB /* DFGCleanUpPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCleanUpPhase.h; path = dfg/DFGCleanUpPhase.h; sourceTree = "<group>"; }; + 0F9E32611B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStoreBarrierInsertionPhase.cpp; path = dfg/DFGStoreBarrierInsertionPhase.cpp; sourceTree = "<group>"; }; + 0F9E32621B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStoreBarrierInsertionPhase.h; path = dfg/DFGStoreBarrierInsertionPhase.h; sourceTree = "<group>"; }; 0F9FB4F217FCB91700CB67F8 /* DFGStackLayoutPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStackLayoutPhase.cpp; path = dfg/DFGStackLayoutPhase.cpp; sourceTree = "<group>"; }; 0F9FB4F317FCB91700CB67F8 /* DFGStackLayoutPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStackLayoutPhase.h; path = dfg/DFGStackLayoutPhase.h; sourceTree = "<group>"; }; 0F9FC8BF14E1B5FB00D52AE0 /* PolymorphicPutByIdList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolymorphicPutByIdList.cpp; sourceTree = "<group>"; }; @@ -2215,6 +2227,7 @@ 0FA7A8E918B413C80052371D /* Reg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Reg.cpp; sourceTree = "<group>"; }; 0FA7A8EA18B413C80052371D /* Reg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reg.h; sourceTree = "<group>"; }; 0FA7A8ED18CE4FD80052371D /* ScratchRegisterAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchRegisterAllocator.cpp; sourceTree = "<group>"; }; + 0FAA3E0819D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPromoteHeapAccess.h; path = dfg/DFGPromoteHeapAccess.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>"; }; 0FB105821675480C00F8AB6E /* ExitKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExitKind.cpp; sourceTree = "<group>"; }; @@ -2227,6 +2240,11 @@ 0FB14E1D18124ACE009B6B4D /* JITInlineCacheGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlineCacheGenerator.h; sourceTree = "<group>"; }; 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInlineCacheWrapper.h; path = dfg/DFGInlineCacheWrapper.h; sourceTree = "<group>"; }; 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInlineCacheWrapperInlines.h; path = dfg/DFGInlineCacheWrapperInlines.h; sourceTree = "<group>"; }; + 0FB1765C196B8F9E0091052A /* DFGHeapLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGHeapLocation.cpp; path = dfg/DFGHeapLocation.cpp; sourceTree = "<group>"; }; + 0FB1765D196B8F9E0091052A /* DFGHeapLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGHeapLocation.h; path = dfg/DFGHeapLocation.h; sourceTree = "<group>"; }; + 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPureValue.cpp; path = dfg/DFGPureValue.cpp; sourceTree = "<group>"; }; + 0FB1765F196B8F9E0091052A /* DFGPureValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPureValue.h; path = dfg/DFGPureValue.h; sourceTree = "<group>"; }; + 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureSet.cpp; sourceTree = "<group>"; }; 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedID.h; path = dfg/DFGMinifiedID.h; sourceTree = "<group>"; }; 0FB4B51916B62772003F696B /* DFGAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAllocator.h; path = dfg/DFGAllocator.h; sourceTree = "<group>"; }; 0FB4B51A16B62772003F696B /* DFGCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCommon.cpp; path = dfg/DFGCommon.cpp; sourceTree = "<group>"; }; @@ -2254,12 +2272,15 @@ 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGExitProfile.cpp; sourceTree = "<group>"; }; 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGExitProfile.h; sourceTree = "<group>"; }; 0FBD7E671447998F00481315 /* CodeOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeOrigin.h; sourceTree = "<group>"; }; + 0FBDB9AC1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCallCreateDirectArgumentsSlowPathGenerator.h; path = dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h; sourceTree = "<group>"; }; 0FBE0F6B16C1DB010082C5E8 /* DFGCPSRethreadingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCPSRethreadingPhase.cpp; path = dfg/DFGCPSRethreadingPhase.cpp; sourceTree = "<group>"; }; 0FBE0F6C16C1DB010082C5E8 /* DFGCPSRethreadingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCPSRethreadingPhase.h; path = dfg/DFGCPSRethreadingPhase.h; sourceTree = "<group>"; }; 0FBE0F6D16C1DB010082C5E8 /* DFGPredictionInjectionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPredictionInjectionPhase.cpp; path = dfg/DFGPredictionInjectionPhase.cpp; sourceTree = "<group>"; }; 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPredictionInjectionPhase.h; path = dfg/DFGPredictionInjectionPhase.h; sourceTree = "<group>"; }; 0FBE0F6F16C1DB010082C5E8 /* DFGUnificationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGUnificationPhase.cpp; path = dfg/DFGUnificationPhase.cpp; sourceTree = "<group>"; }; 0FBE0F7016C1DB010082C5E8 /* DFGUnificationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGUnificationPhase.h; path = dfg/DFGUnificationPhase.h; sourceTree = "<group>"; }; + 0FBF158A19B7A53100695DD0 /* DFGBlockSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBlockSet.cpp; path = dfg/DFGBlockSet.cpp; sourceTree = "<group>"; }; + 0FBF158B19B7A53100695DD0 /* DFGBlockSetInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBlockSetInlines.h; path = dfg/DFGBlockSetInlines.h; sourceTree = "<group>"; }; 0FC097681468A6EF00CF2442 /* DFGOSRExit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExit.h; path = dfg/DFGOSRExit.h; sourceTree = "<group>"; }; 0FC0976F14693AEF00CF2442 /* DFGOSRExitCompiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitCompiler.h; path = dfg/DFGOSRExitCompiler.h; sourceTree = "<group>"; }; 0FC0977014693AEF00CF2442 /* DFGOSRExitCompiler64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitCompiler64.cpp; path = dfg/DFGOSRExitCompiler64.cpp; sourceTree = "<group>"; }; @@ -2276,6 +2297,13 @@ 0FC314101814559100033232 /* RegisterSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterSet.h; sourceTree = "<group>"; }; 0FC314111814559100033232 /* TempRegisterSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TempRegisterSet.cpp; sourceTree = "<group>"; }; 0FC3141418146D7000033232 /* RegisterSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterSet.cpp; sourceTree = "<group>"; }; + 0FC3CCF519ADA410006AC72A /* DFGBlockMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBlockMap.h; path = dfg/DFGBlockMap.h; sourceTree = "<group>"; }; + 0FC3CCF619ADA410006AC72A /* DFGBlockMapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBlockMapInlines.h; path = dfg/DFGBlockMapInlines.h; sourceTree = "<group>"; }; + 0FC3CCF719ADA410006AC72A /* DFGBlockSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBlockSet.h; path = dfg/DFGBlockSet.h; sourceTree = "<group>"; }; + 0FC3CCF819ADA410006AC72A /* DFGBlockWorklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBlockWorklist.cpp; path = dfg/DFGBlockWorklist.cpp; sourceTree = "<group>"; }; + 0FC3CCF919ADA410006AC72A /* DFGBlockWorklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBlockWorklist.h; path = dfg/DFGBlockWorklist.h; sourceTree = "<group>"; }; + 0FC3CCFA19ADA410006AC72A /* DFGNaiveDominators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNaiveDominators.cpp; path = dfg/DFGNaiveDominators.cpp; sourceTree = "<group>"; }; + 0FC3CCFB19ADA410006AC72A /* DFGNaiveDominators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNaiveDominators.h; path = dfg/DFGNaiveDominators.h; sourceTree = "<group>"; }; 0FC712DC17CD8778008CC93C /* DeferredCompilationCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DeferredCompilationCallback.cpp; sourceTree = "<group>"; }; 0FC712DD17CD8778008CC93C /* DeferredCompilationCallback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeferredCompilationCallback.h; sourceTree = "<group>"; }; 0FC712E017CD878F008CC93C /* JITToDFGDeferredCompilationCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JITToDFGDeferredCompilationCallback.cpp; sourceTree = "<group>"; }; @@ -2284,8 +2312,6 @@ 0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WriteBarrierSupport.h; sourceTree = "<group>"; }; 0FC97F2F182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeBlockJettisoningWatchpoint.cpp; sourceTree = "<group>"; }; 0FC97F30182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockJettisoningWatchpoint.h; sourceTree = "<group>"; }; - 0FC97F31182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProfiledCodeBlockJettisoningWatchpoint.cpp; sourceTree = "<group>"; }; - 0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfiledCodeBlockJettisoningWatchpoint.h; sourceTree = "<group>"; }; 0FC97F3718202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGInvalidationPointInjectionPhase.cpp; path = dfg/DFGInvalidationPointInjectionPhase.cpp; sourceTree = "<group>"; }; 0FC97F3818202119002C9B26 /* DFGInvalidationPointInjectionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInvalidationPointInjectionPhase.h; path = dfg/DFGInvalidationPointInjectionPhase.h; sourceTree = "<group>"; }; 0FC97F3918202119002C9B26 /* DFGJumpReplacement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGJumpReplacement.cpp; path = dfg/DFGJumpReplacement.cpp; sourceTree = "<group>"; }; @@ -2297,7 +2323,6 @@ 0FCEFAA91804C13E00472CE4 /* FTLSaveRestore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLSaveRestore.cpp; path = ftl/FTLSaveRestore.cpp; sourceTree = "<group>"; }; 0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSaveRestore.h; path = ftl/FTLSaveRestore.h; sourceTree = "<group>"; }; 0FCEFAAE1805CA6D00472CE4 /* InitializeLLVM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitializeLLVM.h; path = llvm/InitializeLLVM.h; sourceTree = "<group>"; }; - 0FCEFAAF1805CA6D00472CE4 /* InitializeLLVMMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = InitializeLLVMMac.mm; path = llvm/InitializeLLVMMac.mm; sourceTree = "<group>"; }; 0FCEFAB61805D61600472CE4 /* libllvmForJSC.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libllvmForJSC.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 0FCEFABE1805D86900472CE4 /* LLVMForJSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = LLVMForJSC.xcconfig; sourceTree = "<group>"; }; 0FCEFAC01805D94100472CE4 /* LLVMOverrides.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LLVMOverrides.cpp; sourceTree = "<group>"; }; @@ -2313,6 +2338,10 @@ 0FCEFADB18064A1400472CE4 /* config_llvm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_llvm.h; sourceTree = "<group>"; }; 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLLocation.cpp; path = ftl/FTLLocation.cpp; sourceTree = "<group>"; }; 0FCEFADE180738C000472CE4 /* FTLLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLLocation.h; path = ftl/FTLLocation.h; sourceTree = "<group>"; }; + 0FD1202D1A8AED12000F5280 /* FTLJSCallBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLJSCallBase.cpp; path = ftl/FTLJSCallBase.cpp; sourceTree = "<group>"; }; + 0FD1202E1A8AED12000F5280 /* FTLJSCallBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLJSCallBase.h; path = ftl/FTLJSCallBase.h; sourceTree = "<group>"; }; + 0FD120311A8C85BD000F5280 /* FTLJSCallVarargs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLJSCallVarargs.cpp; path = ftl/FTLJSCallVarargs.cpp; sourceTree = "<group>"; }; + 0FD120321A8C85BD000F5280 /* FTLJSCallVarargs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLJSCallVarargs.h; path = ftl/FTLJSCallVarargs.h; sourceTree = "<group>"; }; 0FD2C92316D01EE900C7803F /* StructureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureInlines.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>"; }; @@ -2340,6 +2369,10 @@ 0FD8A32217D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGToFTLDeferredCompilationCallback.h; path = dfg/DFGToFTLDeferredCompilationCallback.h; sourceTree = "<group>"; }; 0FD8A32317D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGToFTLForOSREntryDeferredCompilationCallback.cpp; path = dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp; sourceTree = "<group>"; }; 0FD8A32417D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGToFTLForOSREntryDeferredCompilationCallback.h; path = dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h; sourceTree = "<group>"; }; + 0FD9497E1A97DB9600E28966 /* JSCatchScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCatchScope.cpp; sourceTree = "<group>"; }; + 0FD9497F1A97DB9600E28966 /* JSCatchScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCatchScope.h; sourceTree = "<group>"; }; + 0FD949801A97DB9600E28966 /* JSFunctionNameScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFunctionNameScope.cpp; sourceTree = "<group>"; }; + 0FD949811A97DB9600E28966 /* JSFunctionNameScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFunctionNameScope.h; sourceTree = "<group>"; }; 0FDB2CC7173DA51E007B3C1B /* FTLAbbreviatedTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLAbbreviatedTypes.h; path = ftl/FTLAbbreviatedTypes.h; sourceTree = "<group>"; }; 0FDB2CC8173DA51E007B3C1B /* FTLValueFromBlock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FTLValueFromBlock.h; path = ftl/FTLValueFromBlock.h; sourceTree = "<group>"; }; 0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGWorklist.cpp; path = dfg/DFGWorklist.cpp; sourceTree = "<group>"; }; @@ -2347,8 +2380,32 @@ 0FDB2CE9174896C7007B3C1B /* ConcurrentJITLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConcurrentJITLock.h; sourceTree = "<group>"; }; 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = "<group>"; }; 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; }; + 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgumentsMode.h; sourceTree = "<group>"; }; + 0FE0500D1AA9091100D33B33 /* DirectArgumentsOffset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectArgumentsOffset.cpp; sourceTree = "<group>"; }; + 0FE0500E1AA9091100D33B33 /* DirectArgumentsOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectArgumentsOffset.h; sourceTree = "<group>"; }; + 0FE0500F1AA9091100D33B33 /* DirectArguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectArguments.cpp; sourceTree = "<group>"; }; + 0FE050101AA9091100D33B33 /* DirectArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectArguments.h; sourceTree = "<group>"; }; + 0FE050111AA9091100D33B33 /* GenericArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericArguments.h; sourceTree = "<group>"; }; + 0FE050121AA9091100D33B33 /* GenericArgumentsInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericArgumentsInlines.h; sourceTree = "<group>"; }; + 0FE050131AA9091100D33B33 /* GenericOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericOffset.h; sourceTree = "<group>"; }; + 0FE0501C1AA9095600D33B33 /* ClonedArguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClonedArguments.cpp; sourceTree = "<group>"; }; + 0FE0501D1AA9095600D33B33 /* ClonedArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClonedArguments.h; sourceTree = "<group>"; }; + 0FE0501E1AA9095600D33B33 /* ScopedArguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedArguments.cpp; sourceTree = "<group>"; }; + 0FE0501F1AA9095600D33B33 /* ScopedArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopedArguments.h; sourceTree = "<group>"; }; + 0FE050201AA9095600D33B33 /* ScopedArgumentsTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopedArgumentsTable.h; sourceTree = "<group>"; }; + 0FE050211AA9095600D33B33 /* ScopeOffset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopeOffset.cpp; sourceTree = "<group>"; }; + 0FE050221AA9095600D33B33 /* ScopeOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopeOffset.h; sourceTree = "<group>"; }; + 0FE050231AA9095600D33B33 /* VarOffset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VarOffset.cpp; sourceTree = "<group>"; }; + 0FE050241AA9095600D33B33 /* VarOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VarOffset.h; sourceTree = "<group>"; }; + 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedArgumentsTable.cpp; sourceTree = "<group>"; }; 0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; }; 0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; }; + 0FE254F41ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVarargsForwardingPhase.cpp; path = dfg/DFGVarargsForwardingPhase.cpp; sourceTree = "<group>"; }; + 0FE254F51ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVarargsForwardingPhase.h; path = dfg/DFGVarargsForwardingPhase.h; sourceTree = "<group>"; }; + 0FE7211B193B9C590031F6ED /* DFGTransition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGTransition.cpp; path = dfg/DFGTransition.cpp; sourceTree = "<group>"; }; + 0FE7211C193B9C590031F6ED /* DFGTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGTransition.h; path = dfg/DFGTransition.h; sourceTree = "<group>"; }; + 0FE834151A6EF97B00D04847 /* PolymorphicCallStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PolymorphicCallStubRoutine.cpp; sourceTree = "<group>"; }; + 0FE834161A6EF97B00D04847 /* PolymorphicCallStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolymorphicCallStubRoutine.h; sourceTree = "<group>"; }; 0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredWatchpoints.cpp; path = dfg/DFGDesiredWatchpoints.cpp; sourceTree = "<group>"; }; 0FE8534A1723CDA500B618F5 /* DFGDesiredWatchpoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredWatchpoints.h; path = dfg/DFGDesiredWatchpoints.h; sourceTree = "<group>"; }; 0FE95F7718B5694700B531FB /* FTLDataSection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLDataSection.cpp; path = ftl/FTLDataSection.cpp; sourceTree = "<group>"; }; @@ -2381,8 +2438,14 @@ 0FEA0A2F170D40BF00BB722C /* DFGJITCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGJITCode.cpp; path = dfg/DFGJITCode.cpp; sourceTree = "<group>"; }; 0FEA0A30170D40BF00BB722C /* DFGJITCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGJITCode.h; path = dfg/DFGJITCode.h; sourceTree = "<group>"; }; 0FEB3ECE16237F6700AB67AD /* MacroAssembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssembler.cpp; sourceTree = "<group>"; }; + 0FED67B71B26256D0066CE15 /* DFGConstantHoistingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGConstantHoistingPhase.cpp; path = dfg/DFGConstantHoistingPhase.cpp; sourceTree = "<group>"; }; + 0FED67B81B26256D0066CE15 /* DFGConstantHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGConstantHoistingPhase.h; path = dfg/DFGConstantHoistingPhase.h; sourceTree = "<group>"; }; + 0FEE98401A8865B600754E93 /* SetupVarargsFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetupVarargsFrame.h; sourceTree = "<group>"; }; + 0FEE98421A89227500754E93 /* SetupVarargsFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetupVarargsFrame.cpp; sourceTree = "<group>"; }; 0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitJumpPlaceholder.cpp; path = dfg/DFGOSRExitJumpPlaceholder.cpp; sourceTree = "<group>"; }; 0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitJumpPlaceholder.h; path = dfg/DFGOSRExitJumpPlaceholder.h; sourceTree = "<group>"; }; + 0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocationFuzz.cpp; sourceTree = "<group>"; }; + 0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableAllocationFuzz.h; sourceTree = "<group>"; }; 0FF4272F158EBD44004CB9FF /* Disassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Disassembler.h; path = disassembler/Disassembler.h; sourceTree = "<group>"; }; 0FF42730158EBD44004CB9FF /* UDis86Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UDis86Disassembler.cpp; path = disassembler/UDis86Disassembler.cpp; sourceTree = "<group>"; }; 0FF42734158EBD94004CB9FF /* udis86_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = udis86_decode.c; path = disassembler/udis86/udis86_decode.c; sourceTree = "<group>"; }; @@ -2421,7 +2484,11 @@ 0FF729A0166AD347000F5BA3 /* ProfilerOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOrigin.h; path = profiler/ProfilerOrigin.h; sourceTree = "<group>"; }; 0FF729A1166AD347000F5BA3 /* ProfilerOriginStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerOriginStack.cpp; path = profiler/ProfilerOriginStack.cpp; sourceTree = "<group>"; }; 0FF729A2166AD347000F5BA3 /* ProfilerOriginStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOriginStack.h; path = profiler/ProfilerOriginStack.h; sourceTree = "<group>"; }; + 0FF8BDE81AD4CF7100DFE884 /* InferredValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InferredValue.cpp; sourceTree = "<group>"; }; + 0FF8BDE91AD4CF7100DFE884 /* InferredValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InferredValue.h; sourceTree = "<group>"; }; 0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; }; + 0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypeofType.cpp; sourceTree = "<group>"; }; + 0FFB6C371AF48DDC00DB1BF7 /* TypeofType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeofType.h; sourceTree = "<group>"; }; 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantMode.h; sourceTree = "<group>"; }; 0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBufferNeuteringWatchpoint.cpp; sourceTree = "<group>"; }; 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayBufferNeuteringWatchpoint.h; sourceTree = "<group>"; }; @@ -2452,7 +2519,7 @@ 1429D8830ED21C3D00B89619 /* SamplingTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingTool.cpp; sourceTree = "<group>"; }; 1429D8840ED21C3D00B89619 /* SamplingTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingTool.h; sourceTree = "<group>"; }; 1429D8DB0ED2205B00B89619 /* CallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallFrame.cpp; sourceTree = "<group>"; }; - 1429D8DC0ED2205B00B89619 /* CallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrame.h; sourceTree = "<group>"; }; + 1429D8DC0ED2205B00B89619 /* CallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = CallFrame.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 1429D92D0ED22D7000B89619 /* JIT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JIT.cpp; sourceTree = "<group>"; }; 1429D92E0ED22D7000B89619 /* JIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JIT.h; sourceTree = "<group>"; }; 142D3938103E4560007DCB52 /* NumericStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumericStrings.h; sourceTree = "<group>"; }; @@ -2495,8 +2562,6 @@ 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BatchedTransitionOptimizer.h; sourceTree = "<group>"; }; 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutPropertySlot.h; sourceTree = "<group>"; }; 1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerCallFrame.h; sourceTree = "<group>"; }; - 14816E19154CC56C00B8054C /* BlockAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlockAllocator.cpp; sourceTree = "<group>"; }; - 14816E1A154CC56C00B8054C /* BlockAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockAllocator.h; sourceTree = "<group>"; }; 1482B6EA0A4300B300517CFC /* JSValueRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueRef.h; sourceTree = "<group>"; }; 1482B74B0A43032800517CFC /* JSStringRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringRef.h; sourceTree = "<group>"; }; 1482B74C0A43032800517CFC /* JSStringRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringRef.cpp; sourceTree = "<group>"; }; @@ -2539,8 +2604,8 @@ 14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrototypeMap.cpp; sourceTree = "<group>"; }; 14D844A316AA2C7000A65AF0 /* PrototypeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrototypeMap.h; sourceTree = "<group>"; }; 14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/tests/testapi.js; sourceTree = "<group>"; }; - 14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = "<group>"; }; - 14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSActivation.cpp; sourceTree = "<group>"; }; + 14DA818E0D99FD2000B0A4FB /* JSLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSLexicalEnvironment.h; sourceTree = "<group>"; }; + 14DA818F0D99FD2000B0A4FB /* JSLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSLexicalEnvironment.cpp; sourceTree = "<group>"; }; 14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = JSGlobalObject.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticPropertyAnalysis.h; sourceTree = "<group>"; }; 14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakBlock.cpp; sourceTree = "<group>"; }; @@ -2548,7 +2613,7 @@ 14E84F9B14EE1ACC00D6D5D4 /* WeakSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakSet.cpp; sourceTree = "<group>"; }; 14E84F9C14EE1ACC00D6D5D4 /* WeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakSet.h; sourceTree = "<group>"; }; 14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakImpl.h; sourceTree = "<group>"; }; - 14F252560D08DD8D004ECFFF /* JSVariableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVariableObject.h; sourceTree = "<group>"; }; + 14F252560D08DD8D004ECFFF /* JSEnvironmentRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSEnvironmentRecord.h; sourceTree = "<group>"; }; 14F7256314EE265E00B1652B /* WeakHandleOwner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakHandleOwner.cpp; sourceTree = "<group>"; }; 14F7256414EE265E00B1652B /* WeakHandleOwner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakHandleOwner.h; sourceTree = "<group>"; }; 14F97446138C853E00DA1C67 /* HeapRootVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapRootVisitor.h; sourceTree = "<group>"; }; @@ -2560,15 +2625,12 @@ 1C9051450BA9E8A70081E9D0 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; }; 1CAA8B4A0D32C39A0041BCFF /* JavaScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScript.h; sourceTree = "<group>"; }; 1CAA8B4B0D32C39A0041BCFF /* JavaScriptCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCore.h; sourceTree = "<group>"; }; - 1CAA9A1C18F4997F000A369D /* InspectorProfilerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorProfilerAgent.cpp; sourceTree = "<group>"; }; - 1CAA9A1D18F4997F000A369D /* InspectorProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorProfilerAgent.h; sourceTree = "<group>"; }; - 1CAA9A2018F4A220000A369D /* JSGlobalObjectProfilerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObjectProfilerAgent.cpp; sourceTree = "<group>"; }; - 1CAA9A2118F4A220000A369D /* JSGlobalObjectProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObjectProfilerAgent.h; sourceTree = "<group>"; }; 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringJoiner.cpp; sourceTree = "<group>"; }; 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringJoiner.h; sourceTree = "<group>"; }; + 2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameEnumerator.cpp; sourceTree = "<group>"; }; + 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameEnumerator.h; sourceTree = "<group>"; }; 2A111243192FCE79005EE18D /* CustomGetterSetter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomGetterSetter.cpp; sourceTree = "<group>"; }; 2A111244192FCE79005EE18D /* CustomGetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomGetterSetter.h; sourceTree = "<group>"; }; - 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedReleaseScope.h; sourceTree = "<group>"; }; 2A343F7418A1748B0039B085 /* GCSegmentedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCSegmentedArray.h; sourceTree = "<group>"; }; 2A343F7718A1749D0039B085 /* GCSegmentedArrayInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCSegmentedArrayInlines.h; sourceTree = "<group>"; }; 2A4BB7F218A41179008A0FCD /* JSManagedValueInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSManagedValueInternal.h; sourceTree = "<group>"; }; @@ -2590,20 +2652,33 @@ 2AAD964918569417001F93BE /* RecursiveAllocationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursiveAllocationScope.h; sourceTree = "<group>"; }; 2AC922B918A16182003CE0FB /* FTLDWARFDebugLineInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLDWARFDebugLineInfo.cpp; path = ftl/FTLDWARFDebugLineInfo.cpp; sourceTree = "<group>"; }; 2AC922BA18A16182003CE0FB /* FTLDWARFDebugLineInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLDWARFDebugLineInfo.h; path = ftl/FTLDWARFDebugLineInfo.h; sourceTree = "<group>"; }; - 2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStoreBarrierElisionPhase.cpp; path = dfg/DFGStoreBarrierElisionPhase.cpp; sourceTree = "<group>"; }; - 2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStoreBarrierElisionPhase.h; path = dfg/DFGStoreBarrierElisionPhase.h; sourceTree = "<group>"; }; + 2AD2EDFA19799E38004D6478 /* EnumerationMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnumerationMode.h; sourceTree = "<group>"; }; 2AD8932917E3868F00668276 /* HeapIterationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapIterationScope.h; sourceTree = "<group>"; }; 2ADFA26218EF3540004F9FCC /* GCLogging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCLogging.cpp; sourceTree = "<group>"; }; 2AF7382A18BBBF92008A5A37 /* StructureIDTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureIDTable.cpp; sourceTree = "<group>"; }; 2AF7382B18BBBF92008A5A37 /* StructureIDTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureIDTable.h; sourceTree = "<group>"; }; 371D842C17C98B6E00ECF994 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 4340A4821A9051AF00D73CCA /* MathCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathCommon.cpp; sourceTree = "<group>"; }; + 4340A4831A9051AF00D73CCA /* MathCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathCommon.h; sourceTree = "<group>"; }; 449097EE0F8F81B50076A327 /* FeatureDefines.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FeatureDefines.xcconfig; sourceTree = "<group>"; }; 451539B812DC994500EF7AC4 /* Yarr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Yarr.h; path = yarr/Yarr.h; sourceTree = "<group>"; }; 45E12D8806A49B0F00E9DF84 /* jsc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsc.cpp; sourceTree = "<group>"; tabWidth = 4; }; 51F0EB6105C86C6B00E6DF1B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; }; 51F0EC0705C86C9A00E6DF1B /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = /usr/lib/libobjc.dylib; sourceTree = "<absolute>"; }; + 52678F8C1A031009006A306D /* BasicBlockLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicBlockLocation.cpp; sourceTree = "<group>"; }; + 52678F8D1A031009006A306D /* BasicBlockLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BasicBlockLocation.h; sourceTree = "<group>"; }; + 52678F901A04177C006A306D /* ControlFlowProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ControlFlowProfiler.h; sourceTree = "<group>"; }; + 527773DD1AAF83AC00BDE7E8 /* RuntimeType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RuntimeType.cpp; sourceTree = "<group>"; }; + 52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FunctionHasExecutedCache.h; sourceTree = "<group>"; }; + 52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionHasExecutedCache.cpp; sourceTree = "<group>"; }; + 52B310FE1975B4240080857C /* TypeLocationCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLocationCache.cpp; sourceTree = "<group>"; }; + 52B311001975B4670080857C /* TypeLocationCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeLocationCache.h; sourceTree = "<group>"; }; + 52B717B41A0597E1007AF4F3 /* ControlFlowProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ControlFlowProfiler.cpp; sourceTree = "<group>"; }; + 52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeType.h; sourceTree = "<group>"; }; + 52C952B619A289850069B386 /* TypeProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeProfiler.h; sourceTree = "<group>"; }; + 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeProfiler.cpp; sourceTree = "<group>"; }; 5540758418F4A37500602A5D /* CompileRuntimeToLLVMIR.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = CompileRuntimeToLLVMIR.xcconfig; sourceTree = "<group>"; }; - 55407AC818DA58AD00EFF7F2 /* libCompileRuntimeToLLVMIR.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCompileRuntimeToLLVMIR.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 593D43CCA0BBE06D89C59707 /* MapDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapDataInlines.h; sourceTree = "<group>"; }; 5D53726D0E1C546B0021E549 /* Tracing.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Tracing.d; sourceTree = "<group>"; }; 5D53726E0E1C54880021E549 /* Tracing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tracing.h; sourceTree = "<group>"; }; 5D53727D0E1C55EC0021E549 /* TracingDtrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TracingDtrace.h; sourceTree = "<group>"; }; @@ -2611,6 +2686,10 @@ 5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = JSC.xcconfig; sourceTree = "<group>"; }; 5DDDF44614FEE72200B4FB4D /* LLIntDesiredOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntDesiredOffsets.h; path = LLIntOffsets/LLIntDesiredOffsets.h; sourceTree = BUILT_PRODUCTS_DIR; }; 5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitAvailability.h; sourceTree = "<group>"; }; + 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyNode.cpp; path = dfg/DFGLazyNode.cpp; sourceTree = "<group>"; }; + 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyNode.h; path = dfg/DFGLazyNode.h; sourceTree = "<group>"; }; + 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionRareData.cpp; sourceTree = "<group>"; }; + 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionRareData.h; sourceTree = "<group>"; }; 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypeInfo.h; sourceTree = "<group>"; }; 651122E5140469BA002B101D /* testRegExp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = testRegExp.cpp; sourceTree = "<group>"; }; 6511230514046A4C002B101D /* testRegExp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testRegExp; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2622,15 +2701,23 @@ 652A3A221651C69700A80AFE /* A64DOpcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = A64DOpcode.cpp; path = disassembler/ARM64/A64DOpcode.cpp; sourceTree = "<group>"; }; 652A3A231651C69700A80AFE /* A64DOpcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = A64DOpcode.h; path = disassembler/ARM64/A64DOpcode.h; sourceTree = "<group>"; }; 65303D631447B9E100D3F904 /* ParserTokens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParserTokens.h; sourceTree = "<group>"; }; - 65400C0F0A69BAF200509887 /* PropertyNameArray.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyNameArray.cpp; sourceTree = "<group>"; }; 65400C100A69BAF200509887 /* PropertyNameArray.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PropertyNameArray.h; sourceTree = "<group>"; }; + 6546F51F1A32A59C006F07D5 /* NullGetterFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = NullGetterFunction.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 6546F5201A32A59C006F07D5 /* NullGetterFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NullGetterFunction.h; sourceTree = "<group>"; }; + 65525FC31A6DD3B3007B5495 /* NullSetterFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NullSetterFunction.cpp; sourceTree = "<group>"; }; + 65525FC41A6DD3B3007B5495 /* NullSetterFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NullSetterFunction.h; sourceTree = "<group>"; }; 6553A32F17A1F1EE008CF6F3 /* CommonSlowPathsExceptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommonSlowPathsExceptions.cpp; sourceTree = "<group>"; }; 6553A33017A1F1EE008CF6F3 /* CommonSlowPathsExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPathsExceptions.h; sourceTree = "<group>"; }; + 65570F581AA4C00A009B3C23 /* Regress141275.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Regress141275.h; path = API/tests/Regress141275.h; sourceTree = "<group>"; }; + 65570F591AA4C00A009B3C23 /* Regress141275.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Regress141275.mm; path = API/tests/Regress141275.mm; sourceTree = "<group>"; }; 655EB29A10CE2581001A990E /* NodesCodegen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodesCodegen.cpp; sourceTree = "<group>"; }; 6560A4CF04B3B3E7008AE952 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; }; 65621E6B089E859700760F35 /* PropertySlot.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertySlot.cpp; sourceTree = "<group>"; tabWidth = 8; }; 65621E6C089E859700760F35 /* PropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = PropertySlot.h; sourceTree = "<group>"; tabWidth = 8; }; + 657CF45619BF6662004ACBF2 /* JSCallee.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCallee.cpp; sourceTree = "<group>"; }; + 657CF45719BF6662004ACBF2 /* JSCallee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallee.h; sourceTree = "<group>"; }; 65860177185A8F5E00030EEE /* MaxFrameExtentForSlowPathCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MaxFrameExtentForSlowPathCall.h; sourceTree = "<group>"; }; + 658D3A5519638268003C45D6 /* VMEntryRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VMEntryRecord.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 65987F2C167FE84B003C2F8D /* DFGOSRExitCompilationInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitCompilationInfo.h; path = dfg/DFGOSRExitCompilationInfo.h; sourceTree = "<group>"; }; 65987F2F16828A7E003C2F8D /* UnusedPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnusedPointer.h; sourceTree = "<group>"; }; 65C0284F171795E200351E35 /* ARMv7Disassembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ARMv7Disassembler.cpp; path = disassembler/ARMv7Disassembler.cpp; sourceTree = "<group>"; }; @@ -2647,13 +2734,42 @@ 65EA73630BAE35D1001BB560 /* CommonIdentifiers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CommonIdentifiers.h; sourceTree = "<group>"; }; 65FB5115184EE8F800C12B70 /* ProtoCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtoCallFrame.h; sourceTree = "<group>"; }; 65FB5116184EE9BC00C12B70 /* ProtoCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProtoCallFrame.cpp; sourceTree = "<group>"; }; + 6AD2CB4C19B9140100065719 /* DebuggerEvalEnabler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerEvalEnabler.h; sourceTree = "<group>"; }; + 70113D491A8DB093003848C4 /* IteratorOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IteratorOperations.cpp; sourceTree = "<group>"; }; + 70113D4A1A8DB093003848C4 /* IteratorOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IteratorOperations.h; sourceTree = "<group>"; }; + 7013CA891B491A9400CAE613 /* JSJob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSJob.cpp; sourceTree = "<group>"; }; + 7013CA8A1B491A9400CAE613 /* JSJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSJob.h; sourceTree = "<group>"; }; 704FD35305697E6D003DBED9 /* BooleanObject.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = BooleanObject.h; sourceTree = "<group>"; tabWidth = 8; }; - 7C008CD0186F8A9300955C24 /* JSPromiseFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = JSPromiseFunctions.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - 7C008CD1186F8A9300955C24 /* JSPromiseFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPromiseFunctions.h; sourceTree = "<group>"; }; + 705B41A31A6E501E00716757 /* Symbol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Symbol.cpp; sourceTree = "<group>"; }; + 705B41A41A6E501E00716757 /* Symbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Symbol.h; sourceTree = "<group>"; }; + 705B41A51A6E501E00716757 /* SymbolConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolConstructor.cpp; sourceTree = "<group>"; }; + 705B41A61A6E501E00716757 /* SymbolConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolConstructor.h; sourceTree = "<group>"; }; + 705B41A71A6E501E00716757 /* SymbolObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolObject.cpp; sourceTree = "<group>"; }; + 705B41A81A6E501E00716757 /* SymbolObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolObject.h; sourceTree = "<group>"; }; + 705B41A91A6E501E00716757 /* SymbolPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolPrototype.cpp; sourceTree = "<group>"; }; + 705B41AA1A6E501E00716757 /* SymbolPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolPrototype.h; sourceTree = "<group>"; }; + 7094C4DC1AE439530041A2EE /* BytecodeIntrinsicRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeIntrinsicRegistry.cpp; sourceTree = "<group>"; }; + 7094C4DD1AE439530041A2EE /* BytecodeIntrinsicRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeIntrinsicRegistry.h; sourceTree = "<group>"; }; + 709FB8611AE335C60039D069 /* JSWeakSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWeakSet.cpp; sourceTree = "<group>"; }; + 709FB8621AE335C60039D069 /* JSWeakSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakSet.h; sourceTree = "<group>"; }; + 709FB8631AE335C60039D069 /* WeakSetConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakSetConstructor.cpp; sourceTree = "<group>"; }; + 709FB8641AE335C60039D069 /* WeakSetConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakSetConstructor.h; sourceTree = "<group>"; }; + 709FB8651AE335C60039D069 /* WeakSetPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakSetPrototype.cpp; sourceTree = "<group>"; }; + 709FB8661AE335C60039D069 /* WeakSetPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakSetPrototype.h; sourceTree = "<group>"; }; + 70B0A9D01A9B66200001306A /* RuntimeFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeFlags.h; sourceTree = "<group>"; }; + 70DC3E071B2DF2C700054299 /* IteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IteratorPrototype.cpp; sourceTree = "<group>"; }; + 70DC3E081B2DF2C700054299 /* IteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IteratorPrototype.h; sourceTree = "<group>"; }; + 70EC0EBC1AA0D7DA00B6AAFA /* JSStringIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringIterator.cpp; sourceTree = "<group>"; }; + 70EC0EBD1AA0D7DA00B6AAFA /* JSStringIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringIterator.h; sourceTree = "<group>"; }; + 70EC0EC01AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringIteratorPrototype.cpp; sourceTree = "<group>"; }; + 70EC0EC11AA0D7DA00B6AAFA /* StringIteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringIteratorPrototype.h; sourceTree = "<group>"; }; + 70ECA6001AFDBEA200449739 /* JSTemplateRegistryKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTemplateRegistryKey.cpp; sourceTree = "<group>"; }; + 70ECA6011AFDBEA200449739 /* JSTemplateRegistryKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTemplateRegistryKey.h; sourceTree = "<group>"; }; + 70ECA6021AFDBEA200449739 /* TemplateRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateRegistry.cpp; sourceTree = "<group>"; }; + 70ECA6031AFDBEA200449739 /* TemplateRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateRegistry.h; sourceTree = "<group>"; }; + 70ECA6041AFDBEA200449739 /* TemplateRegistryKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateRegistryKey.h; sourceTree = "<group>"; }; 7C008CD8187124BB00955C24 /* JSPromiseDeferred.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPromiseDeferred.cpp; sourceTree = "<group>"; }; 7C008CD9187124BB00955C24 /* JSPromiseDeferred.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPromiseDeferred.h; sourceTree = "<group>"; }; - 7C008CDC1871258D00955C24 /* JSPromiseReaction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPromiseReaction.cpp; sourceTree = "<group>"; }; - 7C008CDD1871258D00955C24 /* JSPromiseReaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPromiseReaction.h; sourceTree = "<group>"; }; 7C008CE5187631B600955C24 /* Microtask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Microtask.h; sourceTree = "<group>"; }; 7C184E1817BEDBD3007CB63A /* JSPromise.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPromise.cpp; sourceTree = "<group>"; }; 7C184E1917BEDBD3007CB63A /* JSPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPromise.h; sourceTree = "<group>"; }; @@ -2666,14 +2782,13 @@ 7CFBAC1C18B535E500D00750 /* Promise.prototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = Promise.prototype.js; sourceTree = "<group>"; }; 7E4EE7080EBB7963005934AA /* StructureChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureChain.h; sourceTree = "<group>"; }; 7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureChain.cpp; sourceTree = "<group>"; }; - 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeInfo.h; sourceTree = "<group>"; }; 860161DF0F3A83C100F84710 /* AbstractMacroAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractMacroAssembler.h; sourceTree = "<group>"; }; 860161E00F3A83C100F84710 /* MacroAssemblerX86.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerX86.h; sourceTree = "<group>"; }; 860161E10F3A83C100F84710 /* MacroAssemblerX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerX86_64.h; sourceTree = "<group>"; }; 860161E20F3A83C100F84710 /* MacroAssemblerX86Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerX86Common.h; sourceTree = "<group>"; }; 8603CEF214C7546400AE59E3 /* CodeProfiling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeProfiling.cpp; sourceTree = "<group>"; }; 8603CEF314C7546400AE59E3 /* CodeProfiling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeProfiling.h; sourceTree = "<group>"; }; - 8604F4F2143A6C4400B295F5 /* ChangeLog */ = {isa = PBXFileReference; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; }; + 8604F4F2143A6C4400B295F5 /* ChangeLog */ = {isa = PBXFileReference; lastKnownFileType = text; lineEnding = 0; path = ChangeLog; sourceTree = "<group>"; }; 8606DDE918DA44AB00A383D0 /* IdentifierInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdentifierInlines.h; sourceTree = "<group>"; }; 8612E4CB1522918400C836BE /* MatchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatchResult.h; sourceTree = "<group>"; }; 86158AB2155C8B3F00B45C9C /* PropertyName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyName.h; sourceTree = "<group>"; }; @@ -2702,8 +2817,8 @@ 868916A9155F285400CB2B9A /* PrivateName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivateName.h; sourceTree = "<group>"; }; 869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; }; 86A054461556451B00445157 /* LowLevelInterpreter.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter.asm; path = llint/LowLevelInterpreter.asm; sourceTree = "<group>"; }; - 86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter32_64.asm; path = llint/LowLevelInterpreter32_64.asm; sourceTree = "<group>"; }; - 86A054481556451B00445157 /* LowLevelInterpreter64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter64.asm; path = llint/LowLevelInterpreter64.asm; sourceTree = "<group>"; }; + 86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; lineEnding = 0; name = LowLevelInterpreter32_64.asm; path = llint/LowLevelInterpreter32_64.asm; sourceTree = "<group>"; }; + 86A054481556451B00445157 /* LowLevelInterpreter64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; lineEnding = 0; name = LowLevelInterpreter64.asm; path = llint/LowLevelInterpreter64.asm; sourceTree = "<group>"; }; 86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic.cpp; sourceTree = "<group>"; }; 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; }; 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerARMv7.h; sourceTree = "<group>"; }; @@ -2746,12 +2861,6 @@ 86E3C610167BAB87006D760A /* JSVirtualMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSVirtualMachine.mm; sourceTree = "<group>"; }; 86E3C611167BAB87006D760A /* JSVirtualMachineInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVirtualMachineInternal.h; sourceTree = "<group>"; }; 86E85538111B9968001AF51E /* JSStringBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringBuilder.h; sourceTree = "<group>"; }; - 86EBF2F91560F036008E9222 /* NameConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NameConstructor.cpp; sourceTree = "<group>"; }; - 86EBF2FA1560F036008E9222 /* NameConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NameConstructor.h; sourceTree = "<group>"; }; - 86EBF2FB1560F036008E9222 /* NameInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NameInstance.cpp; sourceTree = "<group>"; }; - 86EBF2FC1560F036008E9222 /* NameInstance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NameInstance.h; sourceTree = "<group>"; }; - 86EBF2FD1560F036008E9222 /* NamePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NamePrototype.cpp; sourceTree = "<group>"; }; - 86EBF2FE1560F036008E9222 /* NamePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NamePrototype.h; sourceTree = "<group>"; }; 86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGByteCodeParser.cpp; path = dfg/DFGByteCodeParser.cpp; sourceTree = "<group>"; }; 86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGByteCodeParser.h; path = dfg/DFGByteCodeParser.h; sourceTree = "<group>"; }; 86EC9DB61328DF82002B2AD7 /* DFGGenerationInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGGenerationInfo.h; path = dfg/DFGGenerationInfo.h; sourceTree = "<group>"; }; @@ -2834,6 +2943,12 @@ 99E45A2118A1B2590026D88F /* EncodedValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EncodedValue.h; sourceTree = "<group>"; }; 99E45A2218A1B2590026D88F /* InputCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputCursor.h; sourceTree = "<group>"; }; 99E45A2318A1B2590026D88F /* NondeterministicInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NondeterministicInput.h; sourceTree = "<group>"; }; + 9B4954E81A6640DB002815A6 /* ParserFunctionInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserFunctionInfo.h; sourceTree = "<group>"; }; + 9E729409190F0306001A91B5 /* BundlePath.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BundlePath.mm; sourceTree = "<group>"; }; + 9E72940A190F0514001A91B5 /* BundlePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BundlePath.h; sourceTree = "<group>"; }; + 9EA5C7A0190F05D200508EBE /* InitializeLLVMMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitializeLLVMMac.cpp; path = llvm/InitializeLLVMMac.cpp; sourceTree = "<group>"; }; + A12BBFF11B044A8B00664B69 /* IntlObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlObject.h; sourceTree = "<group>"; }; + A12BBFF31B044A9800664B69 /* IntlObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlObject.cpp; sourceTree = "<group>"; }; A1712B3A11C7B212007A5315 /* RegExpCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegExpCache.cpp; sourceTree = "<group>"; }; A1712B3E11C7B228007A5315 /* RegExpCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpCache.h; sourceTree = "<group>"; }; A1712B4011C7B235007A5315 /* RegExpKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpKey.h; sourceTree = "<group>"; }; @@ -2870,18 +2985,16 @@ A513E5C9185F9624007E95AD /* InjectedScriptManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptManager.h; sourceTree = "<group>"; }; A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedScriptBase.cpp; sourceTree = "<group>"; }; A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptBase.h; sourceTree = "<group>"; }; - A532438118568317002ED692 /* InspectorJSBackendDispatchers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorJSBackendDispatchers.cpp; sourceTree = "<group>"; }; - A532438218568317002ED692 /* InspectorJSBackendDispatchers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorJSBackendDispatchers.h; sourceTree = "<group>"; }; - A532438318568317002ED692 /* InspectorJSFrontendDispatchers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorJSFrontendDispatchers.cpp; sourceTree = "<group>"; }; - A532438418568317002ED692 /* InspectorJSFrontendDispatchers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorJSFrontendDispatchers.h; sourceTree = "<group>"; }; - A532438518568317002ED692 /* InspectorJSTypeBuilders.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorJSTypeBuilders.cpp; sourceTree = "<group>"; }; - A532438618568317002ED692 /* InspectorJSTypeBuilders.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorJSTypeBuilders.h; sourceTree = "<group>"; }; + A532438118568317002ED692 /* InspectorBackendDispatchers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorBackendDispatchers.cpp; sourceTree = "<group>"; }; + A532438218568317002ED692 /* InspectorBackendDispatchers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorBackendDispatchers.h; sourceTree = "<group>"; }; + A532438318568317002ED692 /* InspectorFrontendDispatchers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorFrontendDispatchers.cpp; sourceTree = "<group>"; }; + A532438418568317002ED692 /* InspectorFrontendDispatchers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorFrontendDispatchers.h; sourceTree = "<group>"; }; + A532438518568317002ED692 /* InspectorProtocolObjects.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorProtocolObjects.cpp; sourceTree = "<group>"; }; + A532438618568317002ED692 /* InspectorProtocolObjects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorProtocolObjects.h; sourceTree = "<group>"; }; A532438D185696CA002ED692 /* protocol */ = {isa = PBXFileReference; lastKnownFileType = folder; path = protocol; sourceTree = "<group>"; }; - A532438F185696E6002ED692 /* CodeGeneratorInspector.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = CodeGeneratorInspector.py; sourceTree = "<group>"; }; - A5324390185696E6002ED692 /* CodeGeneratorInspectorStrings.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = CodeGeneratorInspectorStrings.py; sourceTree = "<group>"; }; A5324391185696E6002ED692 /* generate-combined-inspector-json.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "generate-combined-inspector-json.py"; sourceTree = "<group>"; }; - A53243951856A475002ED692 /* InspectorJS.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = InspectorJS.json; sourceTree = "<group>"; }; - A53243961856A475002ED692 /* InspectorJSBackendCommands.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InspectorJSBackendCommands.js; sourceTree = "<group>"; }; + A53243951856A475002ED692 /* CombinedDomains.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = CombinedDomains.json; sourceTree = "<group>"; }; + A53243961856A475002ED692 /* InspectorBackendCommands.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InspectorBackendCommands.js; sourceTree = "<group>"; }; A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConsolePrototype.cpp; sourceTree = "<group>"; }; A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsolePrototype.h; sourceTree = "<group>"; }; A53CE08318BC1A5600BEDF76 /* JSConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSConsole.cpp; sourceTree = "<group>"; }; @@ -2894,9 +3007,11 @@ A54CF2F3184EAB2400237F19 /* ScriptValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptValue.h; sourceTree = "<group>"; }; A54CF2F7184EAEDA00237F19 /* ScriptObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptObject.cpp; sourceTree = "<group>"; }; A54CF2F8184EAEDA00237F19 /* ScriptObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptObject.h; sourceTree = "<group>"; }; + A552C37D1ADDB8FE00139726 /* JSRemoteInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSRemoteInspector.cpp; sourceTree = "<group>"; }; + A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRemoteInspector.h; sourceTree = "<group>"; }; A55D93A3185012A800400DED /* ScriptFunctionCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptFunctionCall.cpp; sourceTree = "<group>"; }; A55D93A4185012A800400DED /* ScriptFunctionCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptFunctionCall.h; sourceTree = "<group>"; }; - A55D93AB18514F7900400DED /* InspectorTypeBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorTypeBuilder.h; sourceTree = "<group>"; }; + A55D93AB18514F7900400DED /* InspectorProtocolTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorProtocolTypes.h; sourceTree = "<group>"; }; A57D23E31890CEBF0031C7FA /* InspectorDebuggerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorDebuggerAgent.cpp; sourceTree = "<group>"; }; A57D23E41890CEBF0031C7FA /* InspectorDebuggerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDebuggerAgent.h; sourceTree = "<group>"; }; A57D23E71891B0770031C7FA /* JSGlobalObjectDebuggerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObjectDebuggerAgent.cpp; sourceTree = "<group>"; }; @@ -2931,12 +3046,27 @@ A5BA15E6182340B300A82E69 /* RemoteInspectorXPCConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorXPCConnection.h; sourceTree = "<group>"; }; A5BA15E7182340B300A82E69 /* RemoteInspectorXPCConnection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RemoteInspectorXPCConnection.mm; sourceTree = "<group>"; }; A5BA15EF182345AF00A82E69 /* RemoteInspectorDebuggable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorDebuggable.h; sourceTree = "<group>"; }; - A5C3A1A318C0490200C9593A /* JSConsoleClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSConsoleClient.cpp; sourceTree = "<group>"; }; - A5C3A1A418C0490200C9593A /* JSConsoleClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSConsoleClient.h; sourceTree = "<group>"; }; + A5C3A1A318C0490200C9593A /* JSGlobalObjectConsoleClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObjectConsoleClient.cpp; sourceTree = "<group>"; }; + A5C3A1A418C0490200C9593A /* JSGlobalObjectConsoleClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObjectConsoleClient.h; sourceTree = "<group>"; }; A5CEEE12187F3BAD00E55C99 /* InspectorAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorAgent.cpp; sourceTree = "<group>"; }; A5CEEE13187F3BAD00E55C99 /* InspectorAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorAgent.h; sourceTree = "<group>"; }; A5D0A1BA1862301B00C7B496 /* InspectorEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorEnvironment.h; sourceTree = "<group>"; }; A5D2E664195E173800A518E7 /* JSContextRefInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSContextRefInternal.h; sourceTree = "<group>"; }; + A5EA70E419F5B1010098F5EC /* AugmentableInspectorController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AugmentableInspectorController.h; sourceTree = "<group>"; }; + A5EA70E519F5B1010098F5EC /* AugmentableInspectorControllerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AugmentableInspectorControllerClient.h; sourceTree = "<group>"; }; + A5EA70E619F5B1010098F5EC /* AlternateDispatchableAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlternateDispatchableAgent.h; sourceTree = "<group>"; }; + A5EA70EA19F5B3D50098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_alternate_backend_dispatcher_header.py; sourceTree = "<group>"; }; + A5EA70ED19F5B5C40098F5EC /* JSContextRefInspectorSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSContextRefInspectorSupport.h; sourceTree = "<group>"; }; + A5EA70EF19F6DE5A0098F5EC /* generate_objc_backend_dispatcher_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_backend_dispatcher_header.py; sourceTree = "<group>"; }; + A5EA70F019F6DE5A0098F5EC /* generate_objc_backend_dispatcher_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_backend_dispatcher_implementation.py; sourceTree = "<group>"; }; + A5EA70F119F6DE5A0098F5EC /* generate_objc_configuration_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_configuration_header.py; sourceTree = "<group>"; }; + A5EA70F219F6DE5A0098F5EC /* generate_objc_configuration_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_configuration_implementation.py; sourceTree = "<group>"; }; + A5EA70F319F6DE5A0098F5EC /* generate_objc_conversion_helpers.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_conversion_helpers.py; sourceTree = "<group>"; }; + A5EA70F419F6DE5A0098F5EC /* generate_objc_frontend_dispatcher_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_frontend_dispatcher_implementation.py; sourceTree = "<group>"; }; + A5EA70F519F6DE5A0098F5EC /* generate_objc_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_header.py; sourceTree = "<group>"; }; + A5EA70F619F6DE5A0098F5EC /* generate_objc_internal_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_internal_header.py; sourceTree = "<group>"; }; + A5EA70F819F6DE5A0098F5EC /* objc_generator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = objc_generator.py; sourceTree = "<group>"; }; + A5EA710D19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorAlternateBackendDispatchers.h; sourceTree = "<group>"; }; A5FD0065189AFE9C00633231 /* ScriptArguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptArguments.cpp; sourceTree = "<group>"; }; A5FD0066189AFE9C00633231 /* ScriptArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptArguments.h; sourceTree = "<group>"; }; A5FD0069189B00A900633231 /* ScriptCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptCallFrame.cpp; sourceTree = "<group>"; }; @@ -2970,8 +3100,6 @@ A704D90217A0BAA8006BA554 /* DFGMergeMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMergeMode.h; path = dfg/DFGMergeMode.h; sourceTree = "<group>"; }; A709F2EF17A0AC0400512E98 /* SlowPathCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlowPathCall.h; sourceTree = "<group>"; }; A709F2F117A0AC2A00512E98 /* CommonSlowPaths.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommonSlowPaths.cpp; sourceTree = "<group>"; }; - A70B083017A0B79B00DAF14B /* DFGBinarySwitch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBinarySwitch.cpp; path = dfg/DFGBinarySwitch.cpp; sourceTree = "<group>"; }; - A70B083117A0B79B00DAF14B /* DFGBinarySwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBinarySwitch.h; path = dfg/DFGBinarySwitch.h; sourceTree = "<group>"; }; A71236E41195F33C00BD2174 /* JITOpcodes32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITOpcodes32_64.cpp; sourceTree = "<group>"; }; A718F61A11754A21002465A7 /* RegExpJitTables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpJitTables.h; sourceTree = "<group>"; }; A718F8211178EB4B002465A7 /* create_regex_tables */ = {isa = PBXFileReference; explicitFileType = text.script.python; fileEncoding = 4; path = create_regex_tables; sourceTree = "<group>"; }; @@ -2982,8 +3110,6 @@ A72700770DAC605600E548D7 /* JSNotAnObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSNotAnObject.h; sourceTree = "<group>"; }; A72700780DAC605600E548D7 /* JSNotAnObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNotAnObject.cpp; sourceTree = "<group>"; }; A72701B30DADE94900E548D7 /* ExceptionHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionHelpers.h; sourceTree = "<group>"; }; - A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; }; - A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; }; A729009B17976C6000317298 /* MacroAssemblerARMv7.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssemblerARMv7.cpp; sourceTree = "<group>"; }; A7299D9B17D12837005F5FF9 /* JSSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSet.cpp; sourceTree = "<group>"; }; A7299D9C17D12837005F5FF9 /* JSSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSet.h; sourceTree = "<group>"; }; @@ -3001,27 +3127,16 @@ A7386553118697B400540279 /* ThunkGenerators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThunkGenerators.h; sourceTree = "<group>"; }; A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyJSValue.cpp; path = dfg/DFGLazyJSValue.cpp; sourceTree = "<group>"; }; A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyJSValue.h; path = dfg/DFGLazyJSValue.h; sourceTree = "<group>"; }; - A73E132C179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDesiredStructureChains.cpp; path = dfg/DFGDesiredStructureChains.cpp; sourceTree = "<group>"; }; - A73E132D179624CD00E4DEA8 /* DFGDesiredStructureChains.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredStructureChains.h; path = dfg/DFGDesiredStructureChains.h; sourceTree = "<group>"; }; A741017E179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSaneStringGetByValSlowPathGenerator.h; path = dfg/DFGSaneStringGetByValSlowPathGenerator.h; sourceTree = "<group>"; }; A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakObjectMapRefPrivate.h; sourceTree = "<group>"; }; A7482B7A1166CDEA003B0712 /* JSWeakObjectMapRefPrivate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWeakObjectMapRefPrivate.cpp; sourceTree = "<group>"; }; A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakObjectMapRefInternal.h; sourceTree = "<group>"; }; - A74DE1CB120B86D600D40D5B /* ARMv7Assembler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ARMv7Assembler.cpp; sourceTree = "<group>"; }; - A74DEF8B182D991400522C22 /* MapIteratorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapIteratorConstructor.cpp; sourceTree = "<group>"; }; - A74DEF8C182D991400522C22 /* MapIteratorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapIteratorConstructor.h; sourceTree = "<group>"; }; A74DEF8D182D991400522C22 /* MapIteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapIteratorPrototype.cpp; sourceTree = "<group>"; }; A74DEF8E182D991400522C22 /* MapIteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapIteratorPrototype.h; sourceTree = "<group>"; }; A74DEF8F182D991400522C22 /* JSMapIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMapIterator.cpp; sourceTree = "<group>"; }; A74DEF90182D991400522C22 /* JSMapIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMapIterator.h; sourceTree = "<group>"; }; A75706DD118A2BCF0057F88F /* JITArithmetic32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic32_64.cpp; sourceTree = "<group>"; }; A75EE9B018AAB7E200AAD043 /* BuiltinNames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BuiltinNames.h; sourceTree = "<group>"; }; - A76140C7182982CB00750624 /* ArgumentsIteratorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArgumentsIteratorConstructor.cpp; sourceTree = "<group>"; }; - A76140C8182982CB00750624 /* ArgumentsIteratorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgumentsIteratorConstructor.h; sourceTree = "<group>"; }; - A76140C9182982CB00750624 /* ArgumentsIteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = ArgumentsIteratorPrototype.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - A76140CA182982CB00750624 /* ArgumentsIteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArgumentsIteratorPrototype.h; sourceTree = "<group>"; }; - A76140CB182982CB00750624 /* JSArgumentsIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSArgumentsIterator.cpp; sourceTree = "<group>"; }; - A76140CC182982CB00750624 /* JSArgumentsIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSArgumentsIterator.h; sourceTree = "<group>"; }; A767B5B317A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLoopPreHeaderCreationPhase.cpp; path = dfg/DFGLoopPreHeaderCreationPhase.cpp; sourceTree = "<group>"; }; A767B5B417A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLoopPreHeaderCreationPhase.h; path = dfg/DFGLoopPreHeaderCreationPhase.h; sourceTree = "<group>"; }; A76C51741182748D00715B05 /* JSInterfaceJIT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInterfaceJIT.h; sourceTree = "<group>"; }; @@ -3036,7 +3151,6 @@ A77F181F164088B200640A47 /* CodeCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeCache.cpp; sourceTree = "<group>"; }; A77F1820164088B200640A47 /* CodeCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeCache.h; sourceTree = "<group>"; }; A77F18241641925400640A47 /* ParserModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserModes.h; sourceTree = "<group>"; }; - A78507D417CBC6FD0011F6E7 /* MapData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapData.cpp; sourceTree = "<group>"; }; A78507D517CBC6FD0011F6E7 /* MapData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapData.h; sourceTree = "<group>"; }; A78853F717972629001440E4 /* IntendedStructureChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntendedStructureChain.cpp; sourceTree = "<group>"; }; A78853F817972629001440E4 /* IntendedStructureChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntendedStructureChain.h; sourceTree = "<group>"; }; @@ -3051,8 +3165,6 @@ A78A977C179738D5009DF744 /* FTLGeneratedFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLGeneratedFunction.h; path = ftl/FTLGeneratedFunction.h; sourceTree = "<group>"; }; A78A977D179738D5009DF744 /* FTLJITFinalizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLJITFinalizer.cpp; path = ftl/FTLJITFinalizer.cpp; sourceTree = "<group>"; }; A78A977E179738D5009DF744 /* FTLJITFinalizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLJITFinalizer.h; path = ftl/FTLJITFinalizer.h; sourceTree = "<group>"; }; - A790DD65182F499700588807 /* SetIteratorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetIteratorConstructor.cpp; sourceTree = "<group>"; }; - A790DD66182F499700588807 /* SetIteratorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetIteratorConstructor.h; sourceTree = "<group>"; }; A790DD67182F499700588807 /* SetIteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SetIteratorPrototype.cpp; sourceTree = "<group>"; }; A790DD68182F499700588807 /* SetIteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetIteratorPrototype.h; sourceTree = "<group>"; }; A790DD69182F499700588807 /* JSSetIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSetIterator.cpp; sourceTree = "<group>"; }; @@ -3082,8 +3194,6 @@ A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableAllocator.h; sourceTree = "<group>"; }; A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocator.cpp; sourceTree = "<group>"; }; A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSExportMacros.h; sourceTree = "<group>"; }; - A7BDAEC017F4EA1400F6140C /* ArrayIteratorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayIteratorConstructor.cpp; sourceTree = "<group>"; }; - A7BDAEC117F4EA1400F6140C /* ArrayIteratorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayIteratorConstructor.h; sourceTree = "<group>"; }; A7BDAEC217F4EA1400F6140C /* ArrayIteratorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = ArrayIteratorPrototype.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; A7BDAEC317F4EA1400F6140C /* ArrayIteratorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayIteratorPrototype.h; sourceTree = "<group>"; }; A7BDAEC417F4EA1400F6140C /* JSArrayIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = JSArrayIterator.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -3094,7 +3204,7 @@ A7C1E8C8112E701C00A37F98 /* JITPropertyAccess32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITPropertyAccess32_64.cpp; sourceTree = "<group>"; }; A7C1EAEA17987AB600299DB2 /* CallFrameInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameInlines.h; sourceTree = "<group>"; }; A7C1EAEB17987AB600299DB2 /* JSStackInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStackInlines.h; sourceTree = "<group>"; }; - A7C1EAEC17987AB600299DB2 /* StackVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackVisitor.cpp; sourceTree = "<group>"; }; + A7C1EAEC17987AB600299DB2 /* StackVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = StackVisitor.cpp; sourceTree = "<group>"; }; A7C1EAED17987AB600299DB2 /* StackVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackVisitor.h; sourceTree = "<group>"; }; A7C225CC139981F100FF1662 /* KeywordLookupGenerator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = KeywordLookupGenerator.py; sourceTree = "<group>"; }; A7C225CD1399849C00FF1662 /* KeywordLookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeywordLookup.h; sourceTree = "<group>"; }; @@ -3153,6 +3263,7 @@ A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; }; A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; }; AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyTable.cpp; sourceTree = "<group>"; }; + AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakGCMapInlines.h; sourceTree = "<group>"; }; ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueRootSet.h; sourceTree = "<group>"; }; B59F89371891AD3300D5CCDC /* UnlinkedInstructionStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkedInstructionStream.h; sourceTree = "<group>"; }; B59F89381891ADB500D5CCDC /* UnlinkedInstructionStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnlinkedInstructionStream.cpp; sourceTree = "<group>"; }; @@ -3182,13 +3293,10 @@ BC18C3C50E16EE3300B34460 /* StringPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringPrototype.cpp; sourceTree = "<group>"; }; BC18C3C60E16EE3300B34460 /* StringPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringPrototype.h; sourceTree = "<group>"; }; BC18C5230E16FC8A00B34460 /* ArrayPrototype.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayPrototype.lut.h; sourceTree = "<group>"; }; - BC18C52B0E16FCD200B34460 /* RegExpObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpObject.lut.h; sourceTree = "<group>"; }; BC18C52D0E16FCE100B34460 /* Lexer.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lexer.lut.h; sourceTree = "<group>"; }; BC22A3980E16E14800AF21C8 /* JSObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSObject.cpp; sourceTree = "<group>"; }; BC22A3990E16E14800AF21C8 /* JSObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObject.h; sourceTree = "<group>"; }; - BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSVariableObject.cpp; sourceTree = "<group>"; }; - BC257DE50E1F51C50016B6C9 /* Arguments.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Arguments.cpp; sourceTree = "<group>"; }; - BC257DE60E1F51C50016B6C9 /* Arguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Arguments.h; sourceTree = "<group>"; }; + BC22A39A0E16E14800AF21C8 /* JSEnvironmentRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSEnvironmentRecord.cpp; sourceTree = "<group>"; }; BC2680C00E16D4E900A06E92 /* FunctionConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionConstructor.cpp; sourceTree = "<group>"; }; BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionConstructor.h; sourceTree = "<group>"; }; BC2680C20E16D4E900A06E92 /* NumberConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NumberConstructor.cpp; sourceTree = "<group>"; }; @@ -3201,9 +3309,7 @@ BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototype.h; sourceTree = "<group>"; }; BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumberConstructor.lut.h; sourceTree = "<group>"; }; BC3046060E1F497F003232CF /* Error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Error.h; sourceTree = "<group>"; }; - BC3135620F302FA3003DFD3A /* DebuggerActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerActivation.h; sourceTree = "<group>"; }; - BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerActivation.cpp; sourceTree = "<group>"; }; - BC337BDE0E1AF0B80076918A /* GetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetterSetter.h; sourceTree = "<group>"; }; + BC337BDE0E1AF0B80076918A /* GetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GetterSetter.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; BC337BEA0E1B00CB0076918A /* Error.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Error.cpp; sourceTree = "<group>"; }; BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassInfo.h; sourceTree = "<group>"; }; BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObjectFunctions.cpp; sourceTree = "<group>"; }; @@ -3244,7 +3350,6 @@ BCFD8C910EEB2EE700283848 /* JumpTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpTable.h; sourceTree = "<group>"; }; C203281E1981979D0088B499 /* CustomGlobalObjectClassTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CustomGlobalObjectClassTest.c; path = API/tests/CustomGlobalObjectClassTest.c; sourceTree = "<group>"; }; C203281F1981979D0088B499 /* CustomGlobalObjectClassTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomGlobalObjectClassTest.h; path = API/tests/CustomGlobalObjectClassTest.h; sourceTree = "<group>"; }; - C20B25981706536200C21F4E /* Region.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Region.h; sourceTree = "<group>"; }; C20BA92C16BB1C1500B3AEA2 /* StructureRareDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureRareDataInlines.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>"; }; @@ -3283,12 +3388,9 @@ C2C0F7CC17BBFC5B00464FE4 /* DFGDesiredTransitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDesiredTransitions.h; path = dfg/DFGDesiredTransitions.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>"; }; C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSAPIWrapperObject.mm; sourceTree = "<group>"; }; C2CF39C016E15A8100DD69BE /* JSAPIWrapperObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAPIWrapperObject.h; sourceTree = "<group>"; }; C2DA778218E259990066FCB6 /* HeapInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapInlines.h; sourceTree = "<group>"; }; - C2DF442D1707AC0100A5CA96 /* SuperRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SuperRegion.cpp; sourceTree = "<group>"; }; - C2DF442E1707AC0100A5CA96 /* SuperRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuperRegion.h; sourceTree = "<group>"; }; C2E526BB1590EF000054E48D /* HeapTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapTimer.cpp; sourceTree = "<group>"; }; C2E526BC1590EF000054E48D /* HeapTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapTimer.h; sourceTree = "<group>"; }; C2EAA3F8149A830800FCE112 /* CopiedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpace.h; sourceTree = "<group>"; }; @@ -3300,14 +3402,31 @@ C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeLivenessAnalysis.cpp; sourceTree = "<group>"; }; C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeLivenessAnalysis.h; sourceTree = "<group>"; }; C2FE18A316BAEC4000AF3061 /* StructureRareData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureRareData.h; sourceTree = "<group>"; }; + C4703CBF192844960013FBEA /* generate-inspector-protocol-bindings.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "generate-inspector-protocol-bindings.py"; sourceTree = "<group>"; }; + C4703CC2192844CC0013FBEA /* __init__.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = __init__.py; sourceTree = "<group>"; }; + C4703CC3192844CC0013FBEA /* generate_js_backend_commands.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_js_backend_commands.py; sourceTree = "<group>"; }; + C4703CCA192844CC0013FBEA /* generator_templates.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generator_templates.py; sourceTree = "<group>"; }; + C4703CCB192844CC0013FBEA /* generator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generator.py; sourceTree = "<group>"; }; + C4703CCC192844CC0013FBEA /* models.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = models.py; sourceTree = "<group>"; }; + C4F4B6CF1A05C76F005CAB76 /* cpp_generator_templates.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = cpp_generator_templates.py; sourceTree = "<group>"; }; + C4F4B6D01A05C76F005CAB76 /* cpp_generator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = cpp_generator.py; sourceTree = "<group>"; }; + C4F4B6D11A05C76F005CAB76 /* generate_cpp_backend_dispatcher_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_backend_dispatcher_header.py; sourceTree = "<group>"; }; + C4F4B6D21A05C76F005CAB76 /* generate_cpp_backend_dispatcher_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_backend_dispatcher_implementation.py; sourceTree = "<group>"; }; + C4F4B6D31A05C76F005CAB76 /* generate_cpp_frontend_dispatcher_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_frontend_dispatcher_header.py; sourceTree = "<group>"; }; + C4F4B6D41A05C76F005CAB76 /* generate_cpp_frontend_dispatcher_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_frontend_dispatcher_implementation.py; sourceTree = "<group>"; }; + C4F4B6D51A05C76F005CAB76 /* generate_cpp_protocol_types_header.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_protocol_types_header.py; sourceTree = "<group>"; }; + C4F4B6D61A05C76F005CAB76 /* generate_cpp_protocol_types_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_cpp_protocol_types_implementation.py; sourceTree = "<group>"; }; + C4F4B6D71A05C76F005CAB76 /* generate_objc_protocol_types_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_objc_protocol_types_implementation.py; sourceTree = "<group>"; }; + C4F4B6D81A05C76F005CAB76 /* objc_generator_templates.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = objc_generator_templates.py; sourceTree = "<group>"; }; D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; }; D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; }; + DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = "<group>"; }; E124A8F50E555775003091F1 /* OpaqueJSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueJSString.h; sourceTree = "<group>"; }; E124A8F60E555775003091F1 /* OpaqueJSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpaqueJSString.cpp; sourceTree = "<group>"; }; E178633F0D9BEC0000D74E75 /* InitializeThreading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeThreading.h; sourceTree = "<group>"; }; E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeThreading.cpp; sourceTree = "<group>"; }; - E18E3A560DF9278C00D90B34 /* VM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VM.h; sourceTree = "<group>"; }; - E18E3A570DF9278C00D90B34 /* VM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VM.cpp; sourceTree = "<group>"; }; + E18E3A560DF9278C00D90B34 /* VM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VM.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + E18E3A570DF9278C00D90B34 /* VM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VM.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceProviderCacheItem.h; sourceTree = "<group>"; }; E49DC15112EF272200184A1F /* SourceProviderCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceProviderCache.h; sourceTree = "<group>"; }; E49DC15512EF277200184A1F /* SourceProviderCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SourceProviderCache.cpp; sourceTree = "<group>"; }; @@ -3342,13 +3461,27 @@ F692A87D0255597D01FF60F7 /* RegExp.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegExp.cpp; sourceTree = "<group>"; tabWidth = 8; }; F692A87E0255597D01FF60F7 /* RegExp.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = RegExp.h; sourceTree = "<group>"; tabWidth = 8; }; F692A8870255597D01FF60F7 /* JSCJSValue.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCJSValue.cpp; sourceTree = "<group>"; tabWidth = 8; }; + FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExecutionTimeLimitTest.cpp; path = API/tests/ExecutionTimeLimitTest.cpp; sourceTree = "<group>"; }; + FE0D4A051AB8DD0A002F54BF /* ExecutionTimeLimitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionTimeLimitTest.h; path = API/tests/ExecutionTimeLimitTest.h; sourceTree = "<group>"; }; + FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GlobalContextWithFinalizerTest.cpp; path = API/tests/GlobalContextWithFinalizerTest.cpp; sourceTree = "<group>"; }; + FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalContextWithFinalizerTest.h; path = API/tests/GlobalContextWithFinalizerTest.h; sourceTree = "<group>"; }; + FE1C0FFC1B193E9800B53FCA /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = "<group>"; }; + FE1C0FFE1B194FD100B53FCA /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Exception.cpp; sourceTree = "<group>"; }; FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = "<group>"; }; FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; }; - FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMInspector.cpp; sourceTree = "<group>"; }; - FE4A331E15BD2E07006F54F3 /* VMInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMInspector.h; sourceTree = "<group>"; }; - FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableWatchpointSetInlines.h; sourceTree = "<group>"; }; + FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVM.cpp; sourceTree = "<group>"; }; + FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDollarVM.h; sourceTree = "<group>"; }; + FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVMPrototype.cpp; sourceTree = "<group>"; }; + FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDollarVMPrototype.h; sourceTree = "<group>"; }; + FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionOverrides.cpp; sourceTree = "<group>"; }; + FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionOverrides.h; sourceTree = "<group>"; }; + FE4D55B71AE716CA0052E459 /* IterationStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IterationStatus.h; sourceTree = "<group>"; }; + FE5068641AE246390009DAB7 /* DeferredSourceDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeferredSourceDump.h; sourceTree = "<group>"; }; + FE5068661AE25E280009DAB7 /* DeferredSourceDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeferredSourceDump.cpp; sourceTree = "<group>"; }; FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMEntryScope.cpp; sourceTree = "<group>"; }; FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMEntryScope.h; sourceTree = "<group>"; }; + FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapVerifier.cpp; sourceTree = "<group>"; }; + FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapVerifier.h; sourceTree = "<group>"; }; FEA0861E182B7A0400F6D851 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpoint.h; sourceTree = "<group>"; }; FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerPrimitives.h; sourceTree = "<group>"; }; FEB51F6A1A97B688001F921C /* Regress141809.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Regress141809.h; path = API/tests/Regress141809.h; sourceTree = "<group>"; }; @@ -3359,7 +3492,8 @@ FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Watchdog.cpp; sourceTree = "<group>"; }; FED94F2C171E3E2300BE77A4 /* Watchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Watchdog.h; sourceTree = "<group>"; }; FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WatchdogMac.cpp; sourceTree = "<group>"; }; - FEE7D5A00D99AC04005351F6 /* iOS.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = iOS.xcconfig; sourceTree = "<group>"; }; + FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompareAndSwapTest.cpp; path = API/tests/CompareAndSwapTest.cpp; sourceTree = "<group>"; }; + FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompareAndSwapTest.h; path = API/tests/CompareAndSwapTest.h; sourceTree = "<group>"; }; FEF6835A174343CC00A32E25 /* JITStubsARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsARM.h; sourceTree = "<group>"; }; FEF6835B174343CC00A32E25 /* JITStubsARMv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsARMv7.h; sourceTree = "<group>"; }; FEF6835C174343CC00A32E25 /* JITStubsX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubsX86_64.h; sourceTree = "<group>"; }; @@ -3443,7 +3577,6 @@ 141211200A48793C00480255 /* minidom */, 14BD59BF0A3E8F9000BAF59C /* testapi */, 6511230514046A4C002B101D /* testRegExp */, - 55407AC818DA58AD00EFF7F2 /* libCompileRuntimeToLLVMIR.a */, ); name = Products; sourceTree = "<group>"; @@ -3543,10 +3676,10 @@ 0FCEFAAD1805CA4400472CE4 /* llvm */ = { isa = PBXGroup; children = ( + 9EA5C7A0190F05D200508EBE /* InitializeLLVMMac.cpp */, 0FCEFABF1805D94100472CE4 /* library */, 0FCEFAC41805E75500472CE4 /* InitializeLLVM.cpp */, 0FCEFAAE1805CA6D00472CE4 /* InitializeLLVM.h */, - 0FCEFAAF1805CA6D00472CE4 /* InitializeLLVMMac.mm */, 0FCEFAC51805E75500472CE4 /* InitializeLLVMPOSIX.cpp */, 0FCEFAC61805E75500472CE4 /* InitializeLLVMPOSIX.h */, 0FCEFAC71805E75500472CE4 /* LLVMAPI.cpp */, @@ -3597,8 +3730,12 @@ 0F235BBF17178E1C00690C7F /* FTLExitArgumentForOperand.cpp */, 0F235BC017178E1C00690C7F /* FTLExitArgumentForOperand.h */, 0F235BC117178E1C00690C7F /* FTLExitArgumentList.h */, + 0F2B9CEE19D0BAC100B1D1B5 /* FTLExitPropertyValue.cpp */, + 0F2B9CEF19D0BAC100B1D1B5 /* FTLExitPropertyValue.h */, 0F235BC217178E1C00690C7F /* FTLExitThunkGenerator.cpp */, 0F235BC317178E1C00690C7F /* FTLExitThunkGenerator.h */, + 0F2B9CF019D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.cpp */, + 0F2B9CF119D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h */, 0F235BC417178E1C00690C7F /* FTLExitValue.cpp */, 0F235BC517178E1C00690C7F /* FTLExitValue.h */, A7F2996917A0BB670010417A /* FTLFail.cpp */, @@ -3618,6 +3755,10 @@ A78A977E179738D5009DF744 /* FTLJITFinalizer.h */, 0F6B1CB3185FC9E900845D97 /* FTLJSCall.cpp */, 0F6B1CB4185FC9E900845D97 /* FTLJSCall.h */, + 0FD1202D1A8AED12000F5280 /* FTLJSCallBase.cpp */, + 0FD1202E1A8AED12000F5280 /* FTLJSCallBase.h */, + 0FD120311A8C85BD000F5280 /* FTLJSCallVarargs.cpp */, + 0FD120321A8C85BD000F5280 /* FTLJSCallVarargs.h */, 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */, 0F8F2B94172E049E007DBDA5 /* FTLLink.h */, 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */, @@ -3625,6 +3766,8 @@ 0FEA0A04170513DB00BB722C /* FTLLowerDFGToLLVM.cpp */, 0FEA0A05170513DB00BB722C /* FTLLowerDFGToLLVM.h */, A7D89D0117A0B90400773AD8 /* FTLLoweredNodeValue.h */, + 0F2B9CF219D0BAC100B1D1B5 /* FTLOperations.cpp */, + 0F2B9CF319D0BAC100B1D1B5 /* FTLOperations.h */, 0FD8A31717D51F2200CA2C40 /* FTLOSREntry.cpp */, 0FD8A31817D51F2200CA2C40 /* FTLOSREntry.h */, 0F235BC617178E1C00690C7F /* FTLOSRExit.cpp */, @@ -3707,14 +3850,22 @@ 141211000A48772600480255 /* tests */ = { isa = PBXGroup; children = ( + FEF040501AAE662D00BD28B0 /* CompareAndSwapTest.cpp */, + FEF040521AAEC4ED00BD28B0 /* CompareAndSwapTest.h */, C203281E1981979D0088B499 /* CustomGlobalObjectClassTest.c */, C203281F1981979D0088B499 /* CustomGlobalObjectClassTest.h */, C29ECB021804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.h */, C29ECB011804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.mm */, C288B2DC18A54D3E007BE40B /* DateTests.h */, C288B2DD18A54D3E007BE40B /* DateTests.mm */, + FE0D4A041AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp */, + FE0D4A051AB8DD0A002F54BF /* ExecutionTimeLimitTest.h */, + FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */, + FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */, C2181FC018A948FB0025A235 /* JSExportTests.h */, C2181FC118A948FB0025A235 /* JSExportTests.mm */, + 65570F581AA4C00A009B3C23 /* Regress141275.h */, + 65570F591AA4C00A009B3C23 /* Regress141275.mm */, FEB51F6A1A97B688001F921C /* Regress141809.h */, FEB51F6B1A97B688001F921C /* Regress141809.mm */, 144005170A531CB50005F061 /* minidom */, @@ -3731,6 +3882,7 @@ 1429D77A0ED20D7300B89619 /* interpreter */ = { isa = PBXGroup; children = ( + 658D3A5519638268003C45D6 /* VMEntryRecord.h */, 0F55F0F114D1063600AC7649 /* AbstractPC.cpp */, 0F55F0F214D1063600AC7649 /* AbstractPC.h */, A7F8690E0F9584A100558697 /* CachedCall.h */, @@ -3748,8 +3900,6 @@ 149B24FF0D8AF6D1009CB8C7 /* Register.h */, A7C1EAEC17987AB600299DB2 /* StackVisitor.cpp */, A7C1EAED17987AB600299DB2 /* StackVisitor.h */, - FE4A331D15BD2E07006F54F3 /* VMInspector.cpp */, - FE4A331E15BD2E07006F54F3 /* VMInspector.h */, ); path = interpreter; sourceTree = "<group>"; @@ -3757,15 +3907,17 @@ 1429D92C0ED22D7000B89619 /* jit */ = { isa = PBXGroup; children = ( + 0FF054F71AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp */, + 0FF054F81AC35B4400E5BE57 /* ExecutableAllocationFuzz.h */, 0F7576D018E1FEE9002EF4CD /* AccessorCallJITStubRoutine.cpp */, 0F7576D118E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h */, 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */, 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */, 0F24E53B17EA9F5900ABB217 /* AssemblyHelpers.cpp */, 0F24E53C17EA9F5900ABB217 /* AssemblyHelpers.h */, + 0F64B26F1A784BAF006E4E66 /* BinarySwitch.cpp */, + 0F64B2701A784BAF006E4E66 /* BinarySwitch.h */, 0F24E53D17EA9F5900ABB217 /* CCallHelpers.h */, - 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */, - 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */, 0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */, A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */, A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */, @@ -3804,8 +3956,8 @@ 14A6581A0F4E36F4000150FD /* JITStubs.h */, FEF6835A174343CC00A32E25 /* JITStubsARM.h */, FEF6835B174343CC00A32E25 /* JITStubsARMv7.h */, - FEF6835D174343CC00A32E25 /* JITStubsX86.h */, FEF6835C174343CC00A32E25 /* JITStubsX86_64.h */, + FEF6835D174343CC00A32E25 /* JITStubsX86.h */, A7A4AE0C17973B4D005612B1 /* JITStubsX86Common.h */, 0F5EF91B16878F78003E5C25 /* JITThunks.cpp */, 0F5EF91C16878F78003E5C25 /* JITThunks.h */, @@ -3813,6 +3965,10 @@ 0FC712E117CD878F008CC93C /* JITToDFGDeferredCompilationCallback.h */, A76F54A213B28AAB00EF2BCE /* JITWriteBarrier.h */, A76C51741182748D00715B05 /* JSInterfaceJIT.h */, + 0FEE98421A89227500754E93 /* SetupVarargsFrame.cpp */, + 0FEE98401A8865B600754E93 /* SetupVarargsFrame.h */, + 0FE834151A6EF97B00D04847 /* PolymorphicCallStubRoutine.cpp */, + 0FE834161A6EF97B00D04847 /* PolymorphicCallStubRoutine.h */, 0FA7A8E918B413C80052371D /* Reg.cpp */, 0FA7A8EA18B413C80052371D /* Reg.h */, 0F6B1CBB1861246A00845D97 /* RegisterPreservationWrapperGenerator.cpp */, @@ -3839,12 +3995,12 @@ 142E312A134FF0A600AFADB5 /* heap */ = { isa = PBXGroup; children = ( + FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */, + FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */, C2DA778218E259990066FCB6 /* HeapInlines.h */, ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */, 2AACE63A18CA5A0300ED0191 /* GCActivityCallback.cpp */, 2AACE63B18CA5A0300ED0191 /* GCActivityCallback.h */, - 14816E19154CC56C00B8054C /* BlockAllocator.cpp */, - 14816E1A154CC56C00B8054C /* BlockAllocator.h */, 0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */, 0FD8A31217D4326C00CA2C40 /* CodeBlockSet.h */, 146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */, @@ -3863,7 +4019,6 @@ 2A68295A1875F80500B6C3E2 /* CopyWriteBarrier.h */, 2A7A58EE1808A4C40020BDF7 /* DeferGC.cpp */, 0F136D4B174AD69B0075B354 /* DeferGC.h */, - 2A2825CF18341F2D0087FBA9 /* DelayedReleaseScope.h */, BCBE2CAD14E985AA000593AD /* GCAssertions.h */, 0F2B66A817B6B53D00A7AE3F /* GCIncomingRefCounted.h */, 0F2B66A917B6B53D00A7AE3F /* GCIncomingRefCountedInlines.h */, @@ -3885,7 +4040,6 @@ 146FA5A81378F6B0003627A3 /* HandleTypes.h */, 14BA7A9513AADFF8005B7C2C /* Heap.cpp */, 14BA7A9613AADFF8005B7C2C /* Heap.h */, - C2C8D02F14A3CEFC00578E65 /* HeapBlock.h */, 2AD8932917E3868F00668276 /* HeapIterationScope.h */, 2A6F462517E959CE00C45C98 /* HeapOperation.h */, 14F97446138C853E00DA1C67 /* HeapRootVisitor.h */, @@ -3912,14 +4066,11 @@ 142D6F0E13539A4100B02E86 /* MarkStack.cpp */, 142D6F0F13539A4100B02E86 /* MarkStack.h */, 2AAD964918569417001F93BE /* RecursiveAllocationScope.h */, - C20B25981706536200C21F4E /* Region.h */, C225494215F7DBAA0065E898 /* SlotVisitor.cpp */, 14BA78F013AAB88F005B7C2C /* SlotVisitor.h */, 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */, 142E3132134FF0A600AFADB5 /* Strong.h */, 145722851437E140005FDE26 /* StrongInlines.h */, - C2DF442D1707AC0100A5CA96 /* SuperRegion.cpp */, - C2DF442E1707AC0100A5CA96 /* SuperRegion.h */, 141448CC13A1783700F5BA1A /* TinyBloomFilter.h */, 0F5F08CE146C762F000472A9 /* UnconditionalFinalizer.h */, 1ACF7376171CA6FB00C9BB1E /* Weak.cpp */, @@ -3977,11 +4128,14 @@ 86E3C609167BAB87006D760A /* JSContextInternal.h */, 14BD5A290A3E91F600BAF59C /* JSContextRef.cpp */, 14BD5A2A0A3E91F600BAF59C /* JSContextRef.h */, + A5EA70ED19F5B5C40098F5EC /* JSContextRefInspectorSupport.h */, A5D2E664195E173800A518E7 /* JSContextRefInternal.h */, 148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */, A72028B41797601E0098028C /* JSCTestRunnerUtils.cpp */, A72028B51797601E0098028C /* JSCTestRunnerUtils.h */, 86E3C60A167BAB87006D760A /* JSExport.h */, + A552C37D1ADDB8FE00139726 /* JSRemoteInspector.cpp */, + A552C37E1ADDB8FE00139726 /* JSRemoteInspector.h */, C25D709A16DE99F400FCA6BC /* JSManagedValue.h */, C25D709916DE99F400FCA6BC /* JSManagedValue.mm */, 2A4BB7F218A41179008A0FCD /* JSManagedValueInternal.h */, @@ -4047,11 +4201,12 @@ FEA0861E182B7A0400F6D851 /* Breakpoint.h */, F692A8580255597D01FF60F7 /* Debugger.cpp */, F692A8590255597D01FF60F7 /* Debugger.h */, - BC3135630F302FA3003DFD3A /* DebuggerActivation.cpp */, - BC3135620F302FA3003DFD3A /* DebuggerActivation.h */, 149559ED0DDCDDF700648087 /* DebuggerCallFrame.cpp */, 1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */, + 6AD2CB4C19B9140100065719 /* DebuggerEvalEnabler.h */, FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */, + 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */, + 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */, ); path = debugger; sourceTree = "<group>"; @@ -4063,7 +4218,6 @@ 1C9051450BA9E8A70081E9D0 /* Base.xcconfig */, 1C9051440BA9E8A70081E9D0 /* DebugRelease.xcconfig */, 449097EE0F8F81B50076A327 /* FeatureDefines.xcconfig */, - FEE7D5A00D99AC04005351F6 /* iOS.xcconfig */, 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */, 5DAFD6CB146B686300FBEFB4 /* JSC.xcconfig */, 0FCEFABE1805D86900472CE4 /* LLVMForJSC.xcconfig */, @@ -4080,17 +4234,18 @@ children = ( BC18C5230E16FC8A00B34460 /* ArrayPrototype.lut.h */, 6514F21718B3E1670098FF8B /* Bytecodes.h */, + A53243951856A475002ED692 /* CombinedDomains.json */, BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */, 6514F21818B3E1670098FF8B /* InitBytecodes.asm */, A513E5C6185F9436007E95AD /* InjectedScriptSource.h */, - A53243951856A475002ED692 /* InspectorJS.json */, - A53243961856A475002ED692 /* InspectorJSBackendCommands.js */, - A532438118568317002ED692 /* InspectorJSBackendDispatchers.cpp */, - A532438218568317002ED692 /* InspectorJSBackendDispatchers.h */, - A532438318568317002ED692 /* InspectorJSFrontendDispatchers.cpp */, - A532438418568317002ED692 /* InspectorJSFrontendDispatchers.h */, - A532438518568317002ED692 /* InspectorJSTypeBuilders.cpp */, - A532438618568317002ED692 /* InspectorJSTypeBuilders.h */, + A5EA710D19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h */, + A53243961856A475002ED692 /* InspectorBackendCommands.js */, + A532438118568317002ED692 /* InspectorBackendDispatchers.cpp */, + A532438218568317002ED692 /* InspectorBackendDispatchers.h */, + A532438318568317002ED692 /* InspectorFrontendDispatchers.cpp */, + A532438418568317002ED692 /* InspectorFrontendDispatchers.h */, + A532438518568317002ED692 /* InspectorProtocolObjects.cpp */, + A532438618568317002ED692 /* InspectorProtocolObjects.h */, A7D801A61880D6A80026C39B /* JSCBuiltins.cpp */, A7D801A71880D6A80026C39B /* JSCBuiltins.h */, BC87CDB810712ACA000614CF /* JSONObject.lut.h */, @@ -4103,7 +4258,6 @@ BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */, BCD202D50E170708002C7E82 /* RegExpConstructor.lut.h */, A718F61A11754A21002465A7 /* RegExpJitTables.h */, - BC18C52B0E16FCD200B34460 /* RegExpObject.lut.h */, 5D53727D0E1C55EC0021E549 /* TracingDtrace.h */, ); name = "Derived Sources"; @@ -4154,7 +4308,6 @@ F692A8650255597D01FF60F7 /* Lexer.cpp */, F692A8660255597D01FF60F7 /* Lexer.h */, 930DAD030FB1EB1A0082D205 /* NodeConstructors.h */, - 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */, F692A86D0255597D01FF60F7 /* Nodes.cpp */, F692A86E0255597D01FF60F7 /* Nodes.h */, 93F0B3A909BB4DC00068FCE3 /* Parser.cpp */, @@ -4162,6 +4315,7 @@ 93052C320FB792190048FDC3 /* ParserArena.cpp */, 93052C330FB792190048FDC3 /* ParserArena.h */, 0FCCAE4316D0CF6E00D0C65B /* ParserError.h */, + 9B4954E81A6640DB002815A6 /* ParserFunctionInfo.h */, A77F18241641925400640A47 /* ParserModes.h */, 65303D631447B9E100D3F904 /* ParserTokens.h */, 869EBCB60E8C6D4A008722CC /* ResultType.h */, @@ -4182,12 +4336,7 @@ children = ( BCF605110E203EF800B9A64D /* ArgList.cpp */, BCF605120E203EF800B9A64D /* ArgList.h */, - BC257DE50E1F51C50016B6C9 /* Arguments.cpp */, - BC257DE60E1F51C50016B6C9 /* Arguments.h */, - A76140C7182982CB00750624 /* ArgumentsIteratorConstructor.cpp */, - A76140C8182982CB00750624 /* ArgumentsIteratorConstructor.h */, - A76140C9182982CB00750624 /* ArgumentsIteratorPrototype.cpp */, - A76140CA182982CB00750624 /* ArgumentsIteratorPrototype.h */, + 0FE0500C1AA9091100D33B33 /* ArgumentsMode.h */, 0F6B1CB71861244C00845D97 /* ArityCheckMode.h */, A7A8AF2517ADB5F2005AB174 /* ArrayBuffer.cpp */, A7A8AF2617ADB5F3005AB174 /* ArrayBuffer.h */, @@ -4198,13 +4347,13 @@ BC7952060E15E8A800A898AB /* ArrayConstructor.cpp */, BC7952070E15E8A800A898AB /* ArrayConstructor.h */, 0FB7F38915ED8E3800F167B2 /* ArrayConventions.h */, - A7BDAEC017F4EA1400F6140C /* ArrayIteratorConstructor.cpp */, - A7BDAEC117F4EA1400F6140C /* ArrayIteratorConstructor.h */, A7BDAEC217F4EA1400F6140C /* ArrayIteratorPrototype.cpp */, A7BDAEC317F4EA1400F6140C /* ArrayIteratorPrototype.h */, F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */, F692A84E0255597D01FF60F7 /* ArrayPrototype.h */, 0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */, + 52678F8C1A031009006A306D /* BasicBlockLocation.cpp */, + 52678F8D1A031009006A306D /* BasicBlockLocation.h */, 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */, 866739D013BFDE710023D87C /* BigInteger.h */, BC7952320E15EB5600A898AB /* BooleanConstructor.cpp */, @@ -4213,11 +4362,15 @@ 704FD35305697E6D003DBED9 /* BooleanObject.h */, BC7952340E15EB5600A898AB /* BooleanPrototype.cpp */, BC7952350E15EB5600A898AB /* BooleanPrototype.h */, + 9E72940A190F0514001A91B5 /* BundlePath.h */, + 9E729409190F0306001A91B5 /* BundlePath.mm */, 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */, 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */, BCA62DFE0E2826230004F30D /* CallData.cpp */, 145C507F0D9DF63B0088F6B9 /* CallData.h */, BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */, + 0FE0501C1AA9095600D33B33 /* ClonedArguments.cpp */, + 0FE0501D1AA9095600D33B33 /* ClonedArguments.h */, A77F181F164088B200640A47 /* CodeCache.cpp */, A77F1820164088B200640A47 /* CodeCache.h */, 0F8F943A1667631100D61971 /* CodeSpecializationKind.cpp */, @@ -4238,9 +4391,14 @@ A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */, A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */, A5FD0071189B038C00633231 /* ConsoleTypes.h */, + 0F978B3A1AAEA71D007C7369 /* ConstantMode.cpp */, 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */, BCA62DFF0E2826310004F30D /* ConstructData.cpp */, BC8F3CCF0DAF17BA00577A80 /* ConstructData.h */, + 52B717B41A0597E1007AF4F3 /* ControlFlowProfiler.cpp */, + 52678F901A04177C006A306D /* ControlFlowProfiler.h */, + 2A111243192FCE79005EE18D /* CustomGetterSetter.cpp */, + 2A111244192FCE79005EE18D /* CustomGetterSetter.h */, 0F2B66B017B6B5AB00A7AE3F /* DataView.cpp */, 0F2B66B117B6B5AB00A7AE3F /* DataView.h */, BCD203450E17135E002C7E82 /* DateConstructor.cpp */, @@ -4252,8 +4410,13 @@ 14A1563010966365006FA260 /* DateInstanceCache.h */, BCD203470E17135E002C7E82 /* DatePrototype.cpp */, BCD203480E17135E002C7E82 /* DatePrototype.h */, + 0FE0500F1AA9091100D33B33 /* DirectArguments.cpp */, + 0FE050101AA9091100D33B33 /* DirectArguments.h */, + 0FE0500D1AA9091100D33B33 /* DirectArgumentsOffset.cpp */, + 0FE0500E1AA9091100D33B33 /* DirectArgumentsOffset.h */, A70447EB17A0BD7000F5898E /* DumpContext.cpp */, A70447EC17A0BD7000F5898E /* DumpContext.h */, + 2AD2EDFA19799E38004D6478 /* EnumerationMode.h */, BC337BEA0E1B00CB0076918A /* Error.cpp */, BC3046060E1F497F003232CF /* Error.h */, BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */, @@ -4264,6 +4427,10 @@ BC02E98B0E183E38000F9297 /* ErrorInstance.h */, BC02E9060E1839DB000F9297 /* ErrorPrototype.cpp */, BC02E9070E1839DB000F9297 /* ErrorPrototype.h */, + FE1C0FFC1B193E9800B53FCA /* Exception.h */, + FE1C0FFE1B194FD100B53FCA /* Exception.cpp */, + 0F12DE0D1979D5FD0006FF4E /* ExceptionFuzz.cpp */, + 0F12DE0E1979D5FD0006FF4E /* ExceptionFuzz.h */, 1429D8770ED21ACD00B89619 /* ExceptionHelpers.cpp */, A72701B30DADE94900E548D7 /* ExceptionHelpers.h */, 86CA032D1038E8440028A609 /* Executable.cpp */, @@ -4274,8 +4441,15 @@ BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */, 0FB4B52116B6278D003F696B /* FunctionExecutableDump.cpp */, 0FB4B52216B6278D003F696B /* FunctionExecutableDump.h */, + 52B310FC1974AE870080857C /* FunctionHasExecutedCache.cpp */, + 52B310FA1974AE610080857C /* FunctionHasExecutedCache.h */, F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */, F692A85D0255597D01FF60F7 /* FunctionPrototype.h */, + 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */, + 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */, + 0FE050111AA9091100D33B33 /* GenericArguments.h */, + 0FE050121AA9091100D33B33 /* GenericArgumentsInlines.h */, + 0FE050131AA9091100D33B33 /* GenericOffset.h */, 0F2B66B217B6B5AB00A7AE3F /* GenericTypedArrayView.h */, 0F2B66B317B6B5AB00A7AE3F /* GenericTypedArrayViewInlines.h */, BC02E9B80E184545000F9297 /* GetterSetter.cpp */, @@ -4287,20 +4461,25 @@ 0FB7F38E15ED8E3800F167B2 /* IndexingHeaderInlines.h */, 0F13E04C16164A1B00DC8DE7 /* IndexingType.cpp */, 0FB7F38F15ED8E3800F167B2 /* IndexingType.h */, + 0FF8BDE81AD4CF7100DFE884 /* InferredValue.cpp */, + 0FF8BDE91AD4CF7100DFE884 /* InferredValue.h */, E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */, E178633F0D9BEC0000D74E75 /* InitializeThreading.h */, + A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */, A7A8AF2C17ADB5F3005AB174 /* Int16Array.h */, A7A8AF2D17ADB5F3005AB174 /* Int32Array.h */, - A7A8AF2B17ADB5F3005AB174 /* Int8Array.h */, A78853F717972629001440E4 /* IntendedStructureChain.cpp */, A78853F817972629001440E4 /* IntendedStructureChain.h */, BC9BB95B0E19680600DF8855 /* InternalFunction.cpp */, BC11667A0E199C05008066DD /* InternalFunction.h */, + A12BBFF31B044A9800664B69 /* IntlObject.cpp */, + A12BBFF11B044A8B00664B69 /* IntlObject.h */, 86BF642A148DB2B5004DE36A /* Intrinsic.h */, - 14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */, - 14DA818E0D99FD2000B0A4FB /* JSActivation.h */, - A76140CB182982CB00750624 /* JSArgumentsIterator.cpp */, - A76140CC182982CB00750624 /* JSArgumentsIterator.h */, + FE4D55B71AE716CA0052E459 /* IterationStatus.h */, + 70113D491A8DB093003848C4 /* IteratorOperations.cpp */, + 70113D4A1A8DB093003848C4 /* IteratorOperations.h */, + 70DC3E071B2DF2C700054299 /* IteratorPrototype.cpp */, + 70DC3E081B2DF2C700054299 /* IteratorPrototype.h */, 93ADFCE60CCBD7AC00D30B08 /* JSArray.cpp */, 938772E5038BFE19008635CE /* JSArray.h */, 0F2B66B417B6B5AB00A7AE3F /* JSArrayBuffer.cpp */, @@ -4316,6 +4495,10 @@ A7BDAEC517F4EA1400F6140C /* JSArrayIterator.h */, 86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */, 86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */, + 657CF45619BF6662004ACBF2 /* JSCallee.cpp */, + 657CF45719BF6662004ACBF2 /* JSCallee.h */, + 0FD9497E1A97DB9600E28966 /* JSCatchScope.cpp */, + 0FD9497F1A97DB9600E28966 /* JSCatchScope.h */, BC7F8FBA0E19D1EF008632C0 /* JSCell.cpp */, BC1167D80E19BCC9008066DD /* JSCell.h */, 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */, @@ -4332,12 +4515,16 @@ 9788FC221471AD0C0068CE2D /* JSDateMath.cpp */, 9788FC231471AD0C0068CE2D /* JSDateMath.h */, C2A7F687160432D400F76B98 /* JSDestructibleObject.h */, + BC22A39A0E16E14800AF21C8 /* JSEnvironmentRecord.cpp */, + 14F252560D08DD8D004ECFFF /* JSEnvironmentRecord.h */, A7B4ACAE1484C9CE00B38A36 /* JSExportMacros.h */, 0F2B66C117B6B5AB00A7AE3F /* JSFloat32Array.h */, 0F2B66C217B6B5AB00A7AE3F /* JSFloat64Array.h */, F692A85E0255597D01FF60F7 /* JSFunction.cpp */, F692A85F0255597D01FF60F7 /* JSFunction.h */, A72028B91797603D0098028C /* JSFunctionInlines.h */, + 0FD949801A97DB9600E28966 /* JSFunctionNameScope.cpp */, + 0FD949811A97DB9600E28966 /* JSFunctionNameScope.h */, 0F2B66C317B6B5AB00A7AE3F /* JSGenericTypedArrayView.h */, 0F2B66C417B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h */, 0F2B66C517B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h */, @@ -4350,9 +4537,13 @@ A59455911824744700CC3843 /* JSGlobalObjectDebuggable.h */, BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */, BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */, + 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */, 0F2B66CA17B6B5AB00A7AE3F /* JSInt16Array.h */, 0F2B66CB17B6B5AB00A7AE3F /* JSInt32Array.h */, - 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */, + 7013CA891B491A9400CAE613 /* JSJob.cpp */, + 7013CA8A1B491A9400CAE613 /* JSJob.h */, + 14DA818F0D99FD2000B0A4FB /* JSLexicalEnvironment.cpp */, + 14DA818E0D99FD2000B0A4FB /* JSLexicalEnvironment.h */, 65EA4C99092AF9E20093D800 /* JSLock.cpp */, 65EA4C9A092AF9E20093D800 /* JSLock.h */, A700873F17CBE8EB00C3E643 /* JSMap.cpp */, @@ -4373,14 +4564,10 @@ 7C184E2117BEE240007CB63A /* JSPromiseConstructor.h */, 7C008CD8187124BB00955C24 /* JSPromiseDeferred.cpp */, 7C008CD9187124BB00955C24 /* JSPromiseDeferred.h */, - 7C008CD0186F8A9300955C24 /* JSPromiseFunctions.cpp */, - 7C008CD1186F8A9300955C24 /* JSPromiseFunctions.h */, 7C184E1C17BEE22E007CB63A /* JSPromisePrototype.cpp */, 7C184E1D17BEE22E007CB63A /* JSPromisePrototype.h */, - 7C008CDC1871258D00955C24 /* JSPromiseReaction.cpp */, - 7C008CDD1871258D00955C24 /* JSPromiseReaction.h */, - A727FF660DA3053B00E548D7 /* JSPropertyNameIterator.cpp */, - A727FF650DA3053B00E548D7 /* JSPropertyNameIterator.h */, + 2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */, + 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */, 862553CE16136AA5009F17D0 /* JSProxy.cpp */, 862553CF16136AA5009F17D0 /* JSProxy.h */, 14874AE115EBDE4A002E3587 /* JSScope.cpp */, @@ -4394,10 +4581,14 @@ BC02E9B60E1842FA000F9297 /* JSString.cpp */, F692A8620255597D01FF60F7 /* JSString.h */, 86E85538111B9968001AF51E /* JSStringBuilder.h */, + 70EC0EBC1AA0D7DA00B6AAFA /* JSStringIterator.cpp */, + 70EC0EBD1AA0D7DA00B6AAFA /* JSStringIterator.h */, 2600B5A4152BAAA70091EE5F /* JSStringJoiner.cpp */, 2600B5A5152BAAA70091EE5F /* JSStringJoiner.h */, 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */, 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */, + 70ECA6001AFDBEA200449739 /* JSTemplateRegistryKey.cpp */, + 70ECA6011AFDBEA200449739 /* JSTemplateRegistryKey.h */, 14ABB454099C2A0F00E2A24F /* JSType.h */, 0F2B66CC17B6B5AB00A7AE3F /* JSTypedArrayConstructors.cpp */, 0F2B66CD17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h */, @@ -4406,14 +4597,14 @@ 0F2B66D017B6B5AB00A7AE3F /* JSTypedArrays.cpp */, 0F2B66D117B6B5AB00A7AE3F /* JSTypedArrays.h */, 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */, - 0F2B66D417B6B5AB00A7AE3F /* JSUint16Array.h */, - 0F2B66D517B6B5AB00A7AE3F /* JSUint32Array.h */, 0F2B66D217B6B5AB00A7AE3F /* JSUint8Array.h */, 0F2B66D317B6B5AB00A7AE3F /* JSUint8ClampedArray.h */, - BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */, - 14F252560D08DD8D004ECFFF /* JSVariableObject.h */, + 0F2B66D417B6B5AB00A7AE3F /* JSUint16Array.h */, + 0F2B66D517B6B5AB00A7AE3F /* JSUint32Array.h */, A7CA3AE117DA41AE006538AF /* JSWeakMap.cpp */, A7CA3AE217DA41AE006538AF /* JSWeakMap.h */, + 709FB8611AE335C60039D069 /* JSWeakSet.cpp */, + 709FB8621AE335C60039D069 /* JSWeakSet.h */, 1442565F15EDE98D0066A49B /* JSWithScope.cpp */, 1442566015EDE98D0066A49B /* JSWithScope.h */, 65C7A1710A8EAACB00FA37EA /* JSWrapperObject.cpp */, @@ -4424,30 +4615,28 @@ F692A8690255597D01FF60F7 /* Lookup.h */, A700873717CBE85300C3E643 /* MapConstructor.cpp */, A700873817CBE85300C3E643 /* MapConstructor.h */, - A78507D417CBC6FD0011F6E7 /* MapData.cpp */, A78507D517CBC6FD0011F6E7 /* MapData.h */, - A74DEF8B182D991400522C22 /* MapIteratorConstructor.cpp */, - A74DEF8C182D991400522C22 /* MapIteratorConstructor.h */, + 593D43CCA0BBE06D89C59707 /* MapDataInlines.h */, A74DEF8D182D991400522C22 /* MapIteratorPrototype.cpp */, A74DEF8E182D991400522C22 /* MapIteratorPrototype.h */, A700873B17CBE8D300C3E643 /* MapPrototype.cpp */, A700873C17CBE8D300C3E643 /* MapPrototype.h */, 8612E4CB1522918400C836BE /* MatchResult.h */, + 4340A4821A9051AF00D73CCA /* MathCommon.cpp */, + 4340A4831A9051AF00D73CCA /* MathCommon.h */, F692A86A0255597D01FF60F7 /* MathObject.cpp */, F692A86B0255597D01FF60F7 /* MathObject.h */, 90213E3B123A40C200D422F3 /* MemoryStatistics.cpp */, 90213E3C123A40C200D422F3 /* MemoryStatistics.h */, 7C008CE5187631B600955C24 /* Microtask.h */, - 86EBF2F91560F036008E9222 /* NameConstructor.cpp */, - 86EBF2FA1560F036008E9222 /* NameConstructor.h */, - 86EBF2FB1560F036008E9222 /* NameInstance.cpp */, - 86EBF2FC1560F036008E9222 /* NameInstance.h */, - 86EBF2FD1560F036008E9222 /* NamePrototype.cpp */, - 86EBF2FE1560F036008E9222 /* NamePrototype.h */, BC02E9080E1839DB000F9297 /* NativeErrorConstructor.cpp */, BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */, BC02E90A0E1839DB000F9297 /* NativeErrorPrototype.cpp */, BC02E90B0E1839DB000F9297 /* NativeErrorPrototype.h */, + 6546F51F1A32A59C006F07D5 /* NullGetterFunction.cpp */, + 6546F5201A32A59C006F07D5 /* NullGetterFunction.h */, + 65525FC31A6DD3B3007B5495 /* NullSetterFunction.cpp */, + 65525FC41A6DD3B3007B5495 /* NullSetterFunction.h */, BC2680C20E16D4E900A06E92 /* NumberConstructor.cpp */, BC2680C30E16D4E900A06E92 /* NumberConstructor.h */, F692A8700255597D01FF60F7 /* NumberObject.cpp */, @@ -4468,7 +4657,6 @@ A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */, BC95437C0EBA70FD0072B6D3 /* PropertyMapHashTable.h */, 86158AB2155C8B3F00B45C9C /* PropertyName.h */, - 65400C0F0A69BAF200509887 /* PropertyNameArray.cpp */, 65400C100A69BAF200509887 /* PropertyNameArray.h */, 0FF7168A15A3B231008F5DAA /* PropertyOffset.h */, 65621E6B089E859700760F35 /* PropertySlot.cpp */, @@ -4498,12 +4686,19 @@ BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */, 0F6B1CB81861244C00845D97 /* RegisterPreservationMode.h */, 0FB7F39115ED8E3800F167B2 /* Reject.h */, + 70B0A9D01A9B66200001306A /* RuntimeFlags.h */, + 527773DD1AAF83AC00BDE7E8 /* RuntimeType.cpp */, + 52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */, 0F7700911402FF280078EB39 /* SamplingCounter.cpp */, 0F77008E1402FDD60078EB39 /* SamplingCounter.h */, + 0FE0501E1AA9095600D33B33 /* ScopedArguments.cpp */, + 0FE0501F1AA9095600D33B33 /* ScopedArguments.h */, + 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */, + 0FE050201AA9095600D33B33 /* ScopedArgumentsTable.h */, + 0FE050211AA9095600D33B33 /* ScopeOffset.cpp */, + 0FE050221AA9095600D33B33 /* ScopeOffset.h */, A7299DA317D12858005F5FF9 /* SetConstructor.cpp */, A7299DA417D12858005F5FF9 /* SetConstructor.h */, - A790DD65182F499700588807 /* SetIteratorConstructor.cpp */, - A790DD66182F499700588807 /* SetIteratorConstructor.h */, A790DD67182F499700588807 /* SetIteratorPrototype.cpp */, A790DD68182F499700588807 /* SetIteratorPrototype.h */, A7299D9F17D12848005F5FF9 /* SetPrototype.cpp */, @@ -4519,6 +4714,8 @@ A730B6101250068F009D25B1 /* StrictEvalActivation.h */, BC18C3C00E16EE3300B34460 /* StringConstructor.cpp */, BC18C3C10E16EE3300B34460 /* StringConstructor.h */, + 70EC0EC01AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp */, + 70EC0EC11AA0D7DA00B6AAFA /* StringIteratorPrototype.h */, BC18C3C20E16EE3300B34460 /* StringObject.cpp */, BC18C3C30E16EE3300B34460 /* StringObject.h */, BC18C3C50E16EE3300B34460 /* StringPrototype.cpp */, @@ -4537,8 +4734,19 @@ C2FE18A316BAEC4000AF3061 /* StructureRareData.h */, C20BA92C16BB1C1500B3AEA2 /* StructureRareDataInlines.h */, BC9041470EB9250900FE26FA /* StructureTransitionTable.h */, + 705B41A31A6E501E00716757 /* Symbol.cpp */, + 705B41A41A6E501E00716757 /* Symbol.h */, + 705B41A51A6E501E00716757 /* SymbolConstructor.cpp */, + 705B41A61A6E501E00716757 /* SymbolConstructor.h */, + 705B41A71A6E501E00716757 /* SymbolObject.cpp */, + 705B41A81A6E501E00716757 /* SymbolObject.h */, + 705B41A91A6E501E00716757 /* SymbolPrototype.cpp */, + 705B41AA1A6E501E00716757 /* SymbolPrototype.h */, 0F919D2715856770004A4E7D /* SymbolTable.cpp */, 14A396A60CD2933100B5B4FF /* SymbolTable.h */, + 70ECA6021AFDBEA200449739 /* TemplateRegistry.cpp */, + 70ECA6031AFDBEA200449739 /* TemplateRegistry.h */, + 70ECA6041AFDBEA200449739 /* TemplateRegistryKey.h */, 0FA2C17917D7CF84009D015F /* TestRunnerUtils.cpp */, 0FA2C17A17D7CF84009D015F /* TestRunnerUtils.h */, 0F55989717C86C5600A1E543 /* ToNativeFromValue.h */, @@ -4551,11 +4759,23 @@ 0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */, 0F2B66DC17B6B5AB00A7AE3F /* TypedArrayType.cpp */, 0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */, + 52B310FE1975B4240080857C /* TypeLocationCache.cpp */, + 52B311001975B4670080857C /* TypeLocationCache.h */, + 0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */, + 0FFB6C371AF48DDC00DB1BF7 /* TypeofType.h */, + 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */, + 52C952B619A289850069B386 /* TypeProfiler.h */, + 0F2D4DDF19832D91007D4B19 /* TypeProfilerLog.cpp */, + 0F2D4DE019832D91007D4B19 /* TypeProfilerLog.h */, + 0F2D4DE319832D91007D4B19 /* TypeSet.cpp */, + 0F2D4DE419832D91007D4B19 /* TypeSet.h */, + A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */, + A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */, A7A8AF3217ADB5F3005AB174 /* Uint16Array.h */, 866739D113BFDE710023D87C /* Uint16WithFraction.h */, A7A8AF3317ADB5F3005AB174 /* Uint32Array.h */, - A7A8AF3017ADB5F3005AB174 /* Uint8Array.h */, - A7A8AF3117ADB5F3005AB174 /* Uint8ClampedArray.h */, + 0FE050231AA9095600D33B33 /* VarOffset.cpp */, + 0FE050241AA9095600D33B33 /* VarOffset.h */, E18E3A570DF9278C00D90B34 /* VM.cpp */, E18E3A560DF9278C00D90B34 /* VM.h */, FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */, @@ -4564,6 +4784,7 @@ FED94F2C171E3E2300BE77A4 /* Watchdog.h */, FED94F2D171E3E2300BE77A4 /* WatchdogMac.cpp */, 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */, + AD86A93D1AA4D87C002FE77F /* WeakGCMapInlines.h */, A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */, A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */, A7CA3AE917DA5168006538AF /* WeakMapData.cpp */, @@ -4571,10 +4792,12 @@ A7CA3ADF17DA41AE006538AF /* WeakMapPrototype.cpp */, A7CA3AE017DA41AE006538AF /* WeakMapPrototype.h */, 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */, + 709FB8631AE335C60039D069 /* WeakSetConstructor.cpp */, + 709FB8641AE335C60039D069 /* WeakSetConstructor.h */, + 709FB8651AE335C60039D069 /* WeakSetPrototype.cpp */, + 709FB8661AE335C60039D069 /* WeakSetPrototype.h */, A7DCB77912E3D90500911940 /* WriteBarrier.h */, C2B6D75218A33793004A9301 /* WriteBarrierInlines.h */, - 2A111243192FCE79005EE18D /* CustomGetterSetter.cpp */, - 2A111244192FCE79005EE18D /* CustomGetterSetter.h */, ); path = runtime; sourceTree = "<group>"; @@ -4586,6 +4809,12 @@ 86B5822F14D2373B00A9C306 /* CodeProfile.h */, 8603CEF214C7546400AE59E3 /* CodeProfiling.cpp */, 8603CEF314C7546400AE59E3 /* CodeProfiling.h */, + FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */, + FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */, + FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */, + FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */, + FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */, + FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */, 86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */, 86B5826A14D35D5100A9C306 /* TieredMMapArray.h */, ); @@ -4627,8 +4856,10 @@ 0FB4B51916B62772003F696B /* DFGAllocator.h */, A73781091799EA2E00817533 /* DFGAnalysis.h */, 0F1E3A431534CBAD000F9456 /* DFGArgumentPosition.h */, - 0F16015A156198BF00C2587C /* DFGArgumentsSimplificationPhase.cpp */, - 0F16015B156198BF00C2587C /* DFGArgumentsSimplificationPhase.h */, + 0F2DD80C1AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.cpp */, + 0F2DD80D1AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.h */, + 0F2DD80E1AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.cpp */, + 0F2DD80F1AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.h */, 0F48531F187750560083B687 /* DFGArithMode.cpp */, 0F485320187750560083B687 /* DFGArithMode.h */, 0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */, @@ -4638,29 +4869,41 @@ A7D9A29017A0BC7400EE2618 /* DFGAtTailAbstractState.h */, 0F666EC21835672B00D017F1 /* DFGAvailability.cpp */, 0F666EC31835672B00D017F1 /* DFGAvailability.h */, + 0F2B9CD619D0BA7D00B1D1B5 /* DFGAvailabilityMap.cpp */, + 0F2B9CD719D0BA7D00B1D1B5 /* DFGAvailabilityMap.h */, 0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */, 0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */, A7D89CE317A0B8CC00773AD8 /* DFGBasicBlock.cpp */, 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */, 0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */, - A70B083017A0B79B00DAF14B /* DFGBinarySwitch.cpp */, - A70B083117A0B79B00DAF14B /* DFGBinarySwitch.h */, A7D89CE417A0B8CC00773AD8 /* DFGBlockInsertionSet.cpp */, A7D89CE517A0B8CC00773AD8 /* DFGBlockInsertionSet.h */, + 0FC3CCF519ADA410006AC72A /* DFGBlockMap.h */, + 0FC3CCF619ADA410006AC72A /* DFGBlockMapInlines.h */, + 0FBF158A19B7A53100695DD0 /* DFGBlockSet.cpp */, + 0FC3CCF719ADA410006AC72A /* DFGBlockSet.h */, + 0FBF158B19B7A53100695DD0 /* DFGBlockSetInlines.h */, + 0FC3CCF819ADA410006AC72A /* DFGBlockWorklist.cpp */, + 0FC3CCF919ADA410006AC72A /* DFGBlockWorklist.h */, 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */, 86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */, 86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */, 0F256C341627B0AA007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h */, + 0FBDB9AC1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h */, 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */, 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */, 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */, 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */, 0F3B3A241544C991003ED0FF /* DFGCFGSimplificationPhase.cpp */, 0F3B3A251544C991003ED0FF /* DFGCFGSimplificationPhase.h */, + 0F9D36921AE9CC33000D4DFB /* DFGCleanUpPhase.cpp */, + 0F9D36931AE9CC33000D4DFB /* DFGCleanUpPhase.h */, A77A423817A0BBFD00A8DB81 /* DFGClobberize.cpp */, A77A423917A0BBFD00A8DB81 /* DFGClobberize.h */, A77A423A17A0BBFD00A8DB81 /* DFGClobberSet.cpp */, A77A423B17A0BBFD00A8DB81 /* DFGClobberSet.h */, + 0F04396B1B03DC0B009598B7 /* DFGCombinedLiveness.cpp */, + 0F04396C1B03DC0B009598B7 /* DFGCombinedLiveness.h */, 0FB4B51A16B62772003F696B /* DFGCommon.cpp */, 0FC0977E1469EBC400CF2442 /* DFGCommon.h */, 0FEA0A2D170D40BF00BB722C /* DFGCommonData.cpp */, @@ -4671,6 +4914,8 @@ 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */, 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */, 0F3B3A18153E68EF003ED0FF /* DFGConstantFoldingPhase.h */, + 0FED67B71B26256D0066CE15 /* DFGConstantHoistingPhase.cpp */, + 0FED67B81B26256D0066CE15 /* DFGConstantHoistingPhase.h */, 0FBE0F6B16C1DB010082C5E8 /* DFGCPSRethreadingPhase.cpp */, 0FBE0F6C16C1DB010082C5E8 /* DFGCPSRethreadingPhase.h */, A7D89CE617A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.cpp */, @@ -4681,8 +4926,6 @@ 0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */, 0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */, 0F8F2B98172F04FD007DBDA5 /* DFGDesiredIdentifiers.h */, - A73E132C179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp */, - A73E132D179624CD00E4DEA8 /* DFGDesiredStructureChains.h */, C2C0F7CB17BBFC5B00464FE4 /* DFGDesiredTransitions.cpp */, C2C0F7CC17BBFC5B00464FE4 /* DFGDesiredTransitions.h */, 0FE853491723CDA500B618F5 /* DFGDesiredWatchpoints.cpp */, @@ -4693,6 +4936,8 @@ C2981FDB17BAFF4400A3BC98 /* DFGDesiredWriteBarriers.h */, 0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */, 0FF427621591A1C9004CB9FF /* DFGDisassembler.h */, + 0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */, + 0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */, 0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */, 0FD81AD0154FB4EB00983E72 /* DFGDominators.h */, 0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */, @@ -4702,6 +4947,8 @@ 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */, A7D9A29117A0BC7400EE2618 /* DFGEdgeDominates.h */, A7986D5617A0BB1E00A95DD0 /* DFGEdgeUsesStructure.h */, + 0F8F142F1ADF090100ED792C /* DFGEpoch.cpp */, + 0F8F14301ADF090100ED792C /* DFGEpoch.h */, A78A976C179738B8009DF744 /* DFGFailedFinalizer.cpp */, A78A976D179738B8009DF744 /* DFGFailedFinalizer.h */, A7BFF3BF179868940002F462 /* DFGFiltrationResult.h */, @@ -4713,18 +4960,29 @@ 0F9D339517FFC4E60073C2BC /* DFGFlushedAt.h */, A7D89CE817A0B8CC00773AD8 /* DFGFlushFormat.cpp */, A7D89CE917A0B8CC00773AD8 /* DFGFlushFormat.h */, + 0F2DD8101AB3D8BE00BBB8E8 /* DFGForAllKills.h */, + 0F69CC86193AC60A0045759E /* DFGFrozenValue.cpp */, + 0F69CC87193AC60A0045759E /* DFGFrozenValue.h */, + 2A88067619107D5500CB0BBB /* DFGFunctionWhitelist.cpp */, + 2A88067719107D5500CB0BBB /* DFGFunctionWhitelist.h */, 86EC9DB61328DF82002B2AD7 /* DFGGenerationInfo.h */, 86EC9DB71328DF82002B2AD7 /* DFGGraph.cpp */, 86EC9DB81328DF82002B2AD7 /* DFGGraph.h */, 0F2FCCF218A60070001A27F8 /* DFGGraphSafepoint.cpp */, 0F2FCCF318A60070001A27F8 /* DFGGraphSafepoint.h */, + 0FB1765C196B8F9E0091052A /* DFGHeapLocation.cpp */, + 0FB1765D196B8F9E0091052A /* DFGHeapLocation.h */, 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */, 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */, A704D90017A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp */, A704D90117A0BAA8006BA554 /* DFGInPlaceAbstractState.h */, 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */, + 0F2B9CD819D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.cpp */, + 0F2B9CD919D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.h */, 0F300B7918AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp */, 0F300B7A18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.h */, + 0F898F2F1B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp */, + 0F898F301B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h */, 0FC97F3718202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp */, 0FC97F3818202119002C9B26 /* DFGInvalidationPointInjectionPhase.h */, 0FEA0A2F170D40BF00BB722C /* DFGJITCode.cpp */, @@ -4737,6 +4995,8 @@ 0FC97F3A18202119002C9B26 /* DFGJumpReplacement.h */, A73A53581799CD5D00170C19 /* DFGLazyJSValue.cpp */, A73A53591799CD5D00170C19 /* DFGLazyJSValue.h */, + 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */, + 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */, A7D9A29217A0BC7400EE2618 /* DFGLICMPhase.cpp */, A7D9A29317A0BC7400EE2618 /* DFGLICMPhase.h */, A7D89CEC17A0B8CC00773AD8 /* DFGLivenessAnalysisPhase.cpp */, @@ -4745,11 +5005,18 @@ 0FB4B51D16B62772003F696B /* DFGLongLivedState.h */, A767B5B317A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.cpp */, A767B5B417A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.h */, + 0F5874EB194FEB1200AAB2C1 /* DFGMayExit.cpp */, + 0F5874EC194FEB1200AAB2C1 /* DFGMayExit.h */, A704D90217A0BAA8006BA554 /* DFGMergeMode.h */, + 0F1725FE1B48719A00AC3A55 /* DFGMinifiedGraph.cpp */, 0F2BDC3D1522801700CD8910 /* DFGMinifiedGraph.h */, 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */, 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */, 0F2BDC3E1522801700CD8910 /* DFGMinifiedNode.h */, + 0F8F14311ADF090100ED792C /* DFGMovHintRemovalPhase.cpp */, + 0F8F14321ADF090100ED792C /* DFGMovHintRemovalPhase.h */, + 0FC3CCFA19ADA410006AC72A /* DFGNaiveDominators.cpp */, + 0FC3CCFB19ADA410006AC72A /* DFGNaiveDominators.h */, A737810A1799EA2E00817533 /* DFGNaturalLoops.cpp */, A737810B1799EA2E00817533 /* DFGNaturalLoops.h */, 0FB4B51E16B62772003F696B /* DFGNode.cpp */, @@ -4759,6 +5026,10 @@ 0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */, 0F300B7718AB051100A6D72E /* DFGNodeOrigin.h */, 0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */, + 0F2B9CDA19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.cpp */, + 0F2B9CDB19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.h */, + 0F2B9CDC19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.cpp */, + 0F2B9CDD19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.h */, 86EC9DBF1328DF82002B2AD7 /* DFGOperations.cpp */, 86EC9DC01328DF82002B2AD7 /* DFGOperations.h */, A7D89CEE17A0B8CC00773AD8 /* DFGOSRAvailabilityAnalysisPhase.cpp */, @@ -4778,21 +5049,35 @@ 0FC0977014693AEF00CF2442 /* DFGOSRExitCompiler64.cpp */, 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */, 0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */, + 0F392C871B46188400844728 /* DFGOSRExitFuzz.cpp */, + 0F392C881B46188400844728 /* DFGOSRExitFuzz.h */, 0FEFC9A71681A3B000567F53 /* DFGOSRExitJumpPlaceholder.cpp */, 0FEFC9A81681A3B000567F53 /* DFGOSRExitJumpPlaceholder.h */, 0F235BE917178E7300690C7F /* DFGOSRExitPreparation.cpp */, 0F235BEA17178E7300690C7F /* DFGOSRExitPreparation.h */, + 0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */, + 0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */, 0FFFC94F14EF909500C72532 /* DFGPhase.cpp */, 0FFFC95014EF909500C72532 /* DFGPhase.h */, + 0F2B9CDE19D0BA7D00B1D1B5 /* DFGPhiChildren.cpp */, + 0F2B9CDF19D0BA7D00B1D1B5 /* DFGPhiChildren.h */, A78A9772179738B8009DF744 /* DFGPlan.cpp */, A78A9773179738B8009DF744 /* DFGPlan.h */, + DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */, 0FBE0F6D16C1DB010082C5E8 /* DFGPredictionInjectionPhase.cpp */, 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */, 0FFFC95114EF909500C72532 /* DFGPredictionPropagationPhase.cpp */, 0FFFC95214EF909500C72532 /* DFGPredictionPropagationPhase.h */, + 0F3E01A819D353A500F61B7F /* DFGPrePostNumbering.cpp */, + 0F3E01A919D353A500F61B7F /* DFGPrePostNumbering.h */, + 0F2B9CE019D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.cpp */, + 0F2B9CE119D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.h */, + 0FAA3E0819D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h */, + 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */, + 0FB1765F196B8F9E0091052A /* DFGPureValue.h */, + 0F3A1BF71A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp */, + 0F3A1BF81A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h */, 86EC9DC11328DF82002B2AD7 /* DFGRegisterBank.h */, - 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */, - 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */, 0F2FCCF418A60070001A27F8 /* DFGSafepoint.cpp */, 0F2FCCF518A60070001A27F8 /* DFGSafepoint.h */, A77A423C17A0BBFD00A8DB81 /* DFGSafeToExecute.h */, @@ -4805,6 +5090,8 @@ 86EC9DC31328DF82002B2AD7 /* DFGSpeculativeJIT.h */, 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */, 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */, + 0F682FB019BCB36400FA3BAD /* DFGSSACalculator.cpp */, + 0F682FB119BCB36400FA3BAD /* DFGSSACalculator.h */, A7D89CF017A0B8CC00773AD8 /* DFGSSAConversionPhase.cpp */, A7D89CF117A0B8CC00773AD8 /* DFGSSAConversionPhase.h */, 0FC20CB718556A3500C9E954 /* DFGSSALoweringPhase.cpp */, @@ -4813,11 +5100,15 @@ 0F9FB4F317FCB91700CB67F8 /* DFGStackLayoutPhase.h */, 0F4F29DD18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp */, 0F4F29DE18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h */, - 2ACCF3DC185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp */, - 2ACCF3DD185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h */, + 0F9E32611B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.cpp */, + 0F9E32621B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.h */, 0FC20CB31852E2C600C9E954 /* DFGStrengthReductionPhase.cpp */, 0FC20CB41852E2C600C9E954 /* DFGStrengthReductionPhase.h */, + 0F893BDA1936E23C001211F4 /* DFGStructureAbstractValue.cpp */, 0F63947615DCE347006A597C /* DFGStructureAbstractValue.h */, + 0F50AF3B193E8B3900674EE8 /* DFGStructureClobberState.h */, + 0F79085319A290B200F6310C /* DFGStructureRegistrationPhase.cpp */, + 0F79085419A290B200F6310C /* DFGStructureRegistrationPhase.h */, 0F2FCCF718A60070001A27F8 /* DFGThreadData.cpp */, 0F2FCCF818A60070001A27F8 /* DFGThreadData.h */, 0FC0979F146B28C700CF2442 /* DFGThunks.cpp */, @@ -4828,6 +5119,8 @@ 0FD8A32217D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h */, 0FD8A32317D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp */, 0FD8A32417D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h */, + 0FE7211B193B9C590031F6ED /* DFGTransition.cpp */, + 0FE7211C193B9C590031F6ED /* DFGTransition.h */, 0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */, 0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */, 0FBE0F6F16C1DB010082C5E8 /* DFGUnificationPhase.cpp */, @@ -4836,9 +5129,12 @@ 0F34B14816D4200E001CDA5A /* DFGUseKind.h */, 0F3B3A2915474FF4003ED0FF /* DFGValidate.cpp */, 0F3B3A2A15474FF4003ED0FF /* DFGValidate.h */, - 0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */, 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */, 0F2BDC401522801700CD8910 /* DFGValueSource.h */, + 0F0123301944EA1B00843A0C /* DFGValueStrength.cpp */, + 0F0123311944EA1B00843A0C /* DFGValueStrength.h */, + 0FE254F41ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp */, + 0FE254F51ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.h */, 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */, 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */, 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */, @@ -4853,8 +5149,6 @@ 0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */, 0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */, 0FDB2CE6174830A2007B3C1B /* DFGWorklist.h */, - 2A88067619107D5500CB0BBB /* DFGFunctionWhitelist.cpp */, - 2A88067719107D5500CB0BBB /* DFGFunctionWhitelist.h */, ); name = dfg; sourceTree = "<group>"; @@ -4922,7 +5216,6 @@ 8640923B156EED3B00566CB2 /* ARM64Assembler.h */, 86D3B2BF10156BDE002865E7 /* ARMAssembler.cpp */, 86D3B2C010156BDE002865E7 /* ARMAssembler.h */, - A74DE1CB120B86D600D40D5B /* ARMv7Assembler.cpp */, 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */, 9688CB130ED12B4E001D649F /* AssemblerBuffer.h */, 86D3B2C110156BDE002865E7 /* AssemblerBufferWithConstantPool.h */, @@ -4962,17 +5255,24 @@ C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */, C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */, 0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */, + 7094C4DC1AE439530041A2EE /* BytecodeIntrinsicRegistry.cpp */, + 7094C4DD1AE439530041A2EE /* BytecodeIntrinsicRegistry.h */, + 0F2DD80A1AB3D85800BBB8E8 /* BytecodeKills.h */, 6529FB3118B2D99900C61102 /* BytecodeList.json */, C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */, C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */, 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */, 0F885E101849A3BE00F1E3FA /* BytecodeUseDef.h */, 0F8023E91613832300A0BA45 /* ByValInfo.h */, + 0F64B2771A7957B2006E4E66 /* CallEdge.cpp */, + 0F64B2781A7957B2006E4E66 /* CallEdge.h */, 0F0B83AE14BCF71400885B4F /* CallLinkInfo.cpp */, 0F0B83AF14BCF71400885B4F /* CallLinkInfo.h */, 0F93329314CA7DC10085F3C6 /* CallLinkStatus.cpp */, 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */, 0F0B83B814BCF95B00885B4F /* CallReturnOffsetToBytecodeOffset.h */, + 0F3B7E2419A11B8000D9BC56 /* CallVariant.cpp */, + 0F3B7E2519A11B8000D9BC56 /* CallVariant.h */, 969A07900ED1D3AE00F1F681 /* CodeBlock.cpp */, 969A07910ED1D3AE00F1F681 /* CodeBlock.h */, 0F8F943D1667632D00D61971 /* CodeBlockHash.cpp */, @@ -4984,9 +5284,15 @@ 0FBD7E671447998F00481315 /* CodeOrigin.h */, 0F8F943F1667632D00D61971 /* CodeType.cpp */, 0F0B83A514BCF50400885B4F /* CodeType.h */, + 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */, + 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */, + 0F3D0BBA194A414300FC9CF9 /* ConstantStructureCheck.cpp */, + 0F3D0BBB194A414300FC9CF9 /* ConstantStructureCheck.h */, 0F426A4A1460CD6B00131F8F /* DataFormat.h */, 0FC712DC17CD8778008CC93C /* DeferredCompilationCallback.cpp */, 0FC712DD17CD8778008CC93C /* DeferredCompilationCallback.h */, + FE5068661AE25E280009DAB7 /* DeferredSourceDump.cpp */, + FE5068641AE246390009DAB7 /* DeferredSourceDump.h */, 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */, 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */, 969A07920ED1D3AE00F1F681 /* EvalCodeCache.h */, @@ -5025,8 +5331,6 @@ 0F9FC8C014E1B5FB00D52AE0 /* PolymorphicPutByIdList.h */, 0F98205D16BFE37F00240D02 /* PreciseJumpTargets.cpp */, 0F98205E16BFE37F00240D02 /* PreciseJumpTargets.h */, - 0FC97F31182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp */, - 0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */, 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */, 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */, 0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */, @@ -5040,11 +5344,17 @@ 0F5541B01613C1FB00CE3E25 /* SpecialPointer.h */, 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */, 0FD82E4F141DAEA100179C94 /* SpeculatedType.h */, + 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */, 0F93329B14CA7DC10085F3C6 /* StructureSet.h */, 0F766D3615AE4A1A008F363E /* StructureStubClearingWatchpoint.cpp */, 0F766D3715AE4A1A008F363E /* StructureStubClearingWatchpoint.h */, BCCF0D0B0EF0B8A500413C8F /* StructureStubInfo.cpp */, BCCF0D070EF0AAB900413C8F /* StructureStubInfo.h */, + 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */, + 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */, + 0F952ABA1B487A7700C367C5 /* TrackedReferences.cpp */, + 0F952ABB1B487A7700C367C5 /* TrackedReferences.h */, + 0F2D4DE719832DAC007D4B19 /* TypeLocation.h */, A79E781E15EECBA80047C855 /* UnlinkedCodeBlock.cpp */, A79E781F15EECBA80047C855 /* UnlinkedCodeBlock.h */, B59F89381891ADB500D5CCDC /* UnlinkedInstructionStream.cpp */, @@ -5052,8 +5362,9 @@ 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */, 0F24E55717F74EDB00ABB217 /* ValueRecovery.cpp */, 0F426A451460CBAB00131F8F /* ValueRecovery.h */, - 0F9181C618415CA50057B669 /* VariableWatchpointSet.h */, - FE5248F8191442D900B7FDE4 /* VariableWatchpointSetInlines.h */, + 0F6C734E1AC9F99F00BE1682 /* VariableWriteFireDetail.cpp */, + 0F6C734F1AC9F99F00BE1682 /* VariableWriteFireDetail.h */, + 0F20C2581A8013AB00DA3229 /* VirtualRegister.cpp */, 0F426A461460CBAB00131F8F /* VirtualRegister.h */, 0F919D2215853CDE004A4E7D /* Watchpoint.cpp */, 0F919D2315853CDE004A4E7D /* Watchpoint.h */, @@ -5093,16 +5404,12 @@ A5FD0080189B191A00633231 /* InspectorConsoleAgent.h */, A57D23E31890CEBF0031C7FA /* InspectorDebuggerAgent.cpp */, A57D23E41890CEBF0031C7FA /* InspectorDebuggerAgent.h */, - 1CAA9A1C18F4997F000A369D /* InspectorProfilerAgent.cpp */, - 1CAA9A1D18F4997F000A369D /* InspectorProfilerAgent.h */, A50E4B5D18809DD50068A46D /* InspectorRuntimeAgent.cpp */, A50E4B5E18809DD50068A46D /* InspectorRuntimeAgent.h */, A5FD0083189B1B7E00633231 /* JSGlobalObjectConsoleAgent.cpp */, A5FD0084189B1B7E00633231 /* JSGlobalObjectConsoleAgent.h */, A57D23E71891B0770031C7FA /* JSGlobalObjectDebuggerAgent.cpp */, A57D23E81891B0770031C7FA /* JSGlobalObjectDebuggerAgent.h */, - 1CAA9A2018F4A220000A369D /* JSGlobalObjectProfilerAgent.cpp */, - 1CAA9A2118F4A220000A369D /* JSGlobalObjectProfilerAgent.h */, A50E4B5F18809DD50068A46D /* JSGlobalObjectRuntimeAgent.cpp */, A50E4B6018809DD50068A46D /* JSGlobalObjectRuntimeAgent.h */, ); @@ -5112,10 +5419,10 @@ A532438E185696CE002ED692 /* scripts */ = { isa = PBXGroup; children = ( - A532438F185696E6002ED692 /* CodeGeneratorInspector.py */, - A5324390185696E6002ED692 /* CodeGeneratorInspectorStrings.py */, + C4703CC1192844A40013FBEA /* codegen */, A5840E26187C980700843B10 /* cssmin.py */, A5324391185696E6002ED692 /* generate-combined-inspector-json.py */, + C4703CBF192844960013FBEA /* generate-inspector-protocol-bindings.py */, A5840E28187CA5B800843B10 /* inline-and-minify-stylesheets-and-scripts.py */, A513E5C4185F92DC007E95AD /* jsmin.py */, A513E5C5185F92F0007E95AD /* xxd.pl */, @@ -5140,6 +5447,7 @@ isa = PBXGroup; children = ( A513E5CC185FB992007E95AD /* agents */, + A5EA70E319F5B0E20098F5EC /* augmentable */, A532438D185696CA002ED692 /* protocol */, A5BA15E01823409D00A82E69 /* remote */, A532438E185696CE002ED692 /* scripts */, @@ -5169,13 +5477,13 @@ A593CF7B1840360300BFCE27 /* InspectorBackendDispatcher.h */, A5D0A1BA1862301B00C7B496 /* InspectorEnvironment.h */, A5945594182479EB00CC3843 /* InspectorFrontendChannel.h */, - A55D93AB18514F7900400DED /* InspectorTypeBuilder.h */, + A55D93AB18514F7900400DED /* InspectorProtocolTypes.h */, A593CF801840377100BFCE27 /* InspectorValues.cpp */, A593CF811840377100BFCE27 /* InspectorValues.h */, A503FA13188E0FAF00110F14 /* JavaScriptCallFrame.cpp */, A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */, - A5C3A1A318C0490200C9593A /* JSConsoleClient.cpp */, - A5C3A1A418C0490200C9593A /* JSConsoleClient.h */, + A5C3A1A318C0490200C9593A /* JSGlobalObjectConsoleClient.cpp */, + A5C3A1A418C0490200C9593A /* JSGlobalObjectConsoleClient.h */, A51007BE187CC3C600B38879 /* JSGlobalObjectInspectorController.cpp */, A51007BF187CC3C600B38879 /* JSGlobalObjectInspectorController.h */, A503FA27188F105900110F14 /* JSGlobalObjectScriptDebugServer.cpp */, @@ -5220,6 +5528,16 @@ path = remote; sourceTree = "<group>"; }; + A5EA70E319F5B0E20098F5EC /* augmentable */ = { + isa = PBXGroup; + children = ( + A5EA70E419F5B1010098F5EC /* AugmentableInspectorController.h */, + A5EA70E519F5B1010098F5EC /* AugmentableInspectorControllerClient.h */, + A5EA70E619F5B1010098F5EC /* AlternateDispatchableAgent.h */, + ); + path = augmentable; + sourceTree = "<group>"; + }; A7D8019F1880D66E0026C39B /* builtins */ = { isa = PBXGroup; children = ( @@ -5233,6 +5551,38 @@ path = builtins; sourceTree = "<group>"; }; + C4703CC1192844A40013FBEA /* codegen */ = { + isa = PBXGroup; + children = ( + C4703CC2192844CC0013FBEA /* __init__.py */, + C4F4B6CF1A05C76F005CAB76 /* cpp_generator_templates.py */, + C4F4B6D01A05C76F005CAB76 /* cpp_generator.py */, + A5EA70EA19F5B3D50098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py */, + C4F4B6D11A05C76F005CAB76 /* generate_cpp_backend_dispatcher_header.py */, + C4F4B6D21A05C76F005CAB76 /* generate_cpp_backend_dispatcher_implementation.py */, + C4F4B6D31A05C76F005CAB76 /* generate_cpp_frontend_dispatcher_header.py */, + C4F4B6D41A05C76F005CAB76 /* generate_cpp_frontend_dispatcher_implementation.py */, + C4F4B6D51A05C76F005CAB76 /* generate_cpp_protocol_types_header.py */, + C4F4B6D61A05C76F005CAB76 /* generate_cpp_protocol_types_implementation.py */, + C4703CC3192844CC0013FBEA /* generate_js_backend_commands.py */, + A5EA70EF19F6DE5A0098F5EC /* generate_objc_backend_dispatcher_header.py */, + A5EA70F019F6DE5A0098F5EC /* generate_objc_backend_dispatcher_implementation.py */, + A5EA70F119F6DE5A0098F5EC /* generate_objc_configuration_header.py */, + A5EA70F219F6DE5A0098F5EC /* generate_objc_configuration_implementation.py */, + A5EA70F319F6DE5A0098F5EC /* generate_objc_conversion_helpers.py */, + A5EA70F419F6DE5A0098F5EC /* generate_objc_frontend_dispatcher_implementation.py */, + A5EA70F519F6DE5A0098F5EC /* generate_objc_header.py */, + A5EA70F619F6DE5A0098F5EC /* generate_objc_internal_header.py */, + C4F4B6D71A05C76F005CAB76 /* generate_objc_protocol_types_implementation.py */, + C4703CCA192844CC0013FBEA /* generator_templates.py */, + C4703CCB192844CC0013FBEA /* generator.py */, + C4703CCC192844CC0013FBEA /* models.py */, + C4F4B6D81A05C76F005CAB76 /* objc_generator_templates.py */, + A5EA70F819F6DE5A0098F5EC /* objc_generator.py */, + ); + path = codegen; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -5259,267 +5609,71 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5540756C18DA58AD00EFF7F2 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 5540757318DA58AD00EFF7F2 /* Arguments.h in Headers */, - 5540757418DA58AD00EFF7F2 /* ArgumentsIteratorConstructor.h in Headers */, - 5540757518DA58AD00EFF7F2 /* ArgumentsIteratorPrototype.h in Headers */, - 5540758618DA58AD00EFF7F2 /* ArrayConstructor.h in Headers */, - 5540758818DA58AD00EFF7F2 /* ArrayIteratorConstructor.h in Headers */, - 5540758918DA58AD00EFF7F2 /* ArrayIteratorPrototype.h in Headers */, - 5540759318DA58AD00EFF7F2 /* BatchedTransitionOptimizer.h in Headers */, - 5540759418DA58AD00EFF7F2 /* BigInteger.h in Headers */, - 554075BB18DA58AD00EFF7F2 /* CommonSlowPathsExceptions.h in Headers */, - 554075BE18DA58AD00EFF7F2 /* JSConsole.h in Headers */, - 554075D618DA58AD00EFF7F2 /* DateConstructor.h in Headers */, - 554075D718DA58AD00EFF7F2 /* DateConversion.h in Headers */, - 554075DA18DA58AD00EFF7F2 /* DatePrototype.h in Headers */, - 5540767118DA58AD00EFF7F2 /* ErrorConstructor.h in Headers */, - 5540769118DA58AD00EFF7F2 /* ConsolePrototype.h in Headers */, - 5540771818DA58AD00EFF7F2 /* JSActivation.h in Headers */, - 5540771B18DA58AD00EFF7F2 /* JSArgumentsIterator.h in Headers */, - 5540772218DA58AD00EFF7F2 /* JSArrayIterator.h in Headers */, - 5540772518DA58AD00EFF7F2 /* (null) in Headers */, - 5540774818DA58AD00EFF7F2 /* JSGlobalObjectDebuggable.h in Headers */, - 5540774A18DA58AD00EFF7F2 /* JSGlobalObjectFunctions.h in Headers */, - 5540775918DA58AD00EFF7F2 /* JSMapIterator.h in Headers */, - 5540776318DA58AD00EFF7F2 /* JSPromiseConstructor.h in Headers */, - 5540776618DA58AD00EFF7F2 /* JSPromisePrototype.h in Headers */, - 5540776718DA58AD00EFF7F2 /* JSPromiseReaction.h in Headers */, - 5540776F18DA58AD00EFF7F2 /* JSSetIterator.h in Headers */, - 5540777118DA58AD00EFF7F2 /* JSStackInlines.h in Headers */, - 5540777318DA58AD00EFF7F2 /* JSStringBuilder.h in Headers */, - 5540777418DA58AD00EFF7F2 /* JSStringJoiner.h in Headers */, - 5540778818DA58AD00EFF7F2 /* JSWeakMap.h in Headers */, - 5540779818DA58AD00EFF7F2 /* LiteralParser.h in Headers */, - 554077B718DA58AD00EFF7F2 /* MapConstructor.h in Headers */, - 554077B918DA58AD00EFF7F2 /* MapIteratorConstructor.h in Headers */, - 554077BA18DA58AD00EFF7F2 /* MapIteratorPrototype.h in Headers */, - 554077BB18DA58AD00EFF7F2 /* MapPrototype.h in Headers */, - 554077C718DA58AD00EFF7F2 /* NameConstructor.h in Headers */, - 554077C818DA58AD00EFF7F2 /* NameInstance.h in Headers */, - 554077C918DA58AD00EFF7F2 /* NamePrototype.h in Headers */, - 554077CA18DA58AD00EFF7F2 /* NativeErrorConstructor.h in Headers */, - 554077CB18DA58AD00EFF7F2 /* NativeErrorPrototype.h in Headers */, - 554077D118DA58AD00EFF7F2 /* NumberConstructor.h in Headers */, - 5540757C18DA58AD00EFF7F2 /* StructureIDBlob.h in Headers */, - 5540758318DA58AD00EFF7F2 /* ArrayBuffer.h in Headers */, - 5540758418DA58AD00EFF7F2 /* ArrayBufferNeuteringWatchpoint.h in Headers */, - 5540758518DA58AD00EFF7F2 /* ArrayBufferView.h in Headers */, - 5540758718DA58AD00EFF7F2 /* ArrayConventions.h in Headers */, - 5540758B18DA58AD00EFF7F2 /* ArrayPrototype.h in Headers */, - 5540758D18DA58AD00EFF7F2 /* StructureIDTable.h in Headers */, - 5540758E18DA58AD00EFF7F2 /* ArrayStorage.h in Headers */, - 5540759618DA58AD00EFF7F2 /* BooleanObject.h in Headers */, - 5540759A18DA58AD00EFF7F2 /* Butterfly.h in Headers */, - 5540759B18DA58AD00EFF7F2 /* ButterflyInlines.h in Headers */, - 554075A318DA58AD00EFF7F2 /* CallData.h in Headers */, - 554075AB18DA58AD00EFF7F2 /* ClassInfo.h in Headers */, - 554075B218DA58AD00EFF7F2 /* CodeCache.h in Headers */, - 554075B718DA58AD00EFF7F2 /* CodeSpecializationKind.h in Headers */, - 554075B918DA58AD00EFF7F2 /* CommonIdentifiers.h in Headers */, - 554075BA18DA58AD00EFF7F2 /* CommonSlowPaths.h in Headers */, - 554075BD18DA58AD00EFF7F2 /* CompilationResult.h in Headers */, - 554075BF18DA58AD00EFF7F2 /* Completion.h in Headers */, - 554075C018DA58AD00EFF7F2 /* ConcurrentJITLock.h in Headers */, - 554075C418DA58AD00EFF7F2 /* ConsoleTypes.h in Headers */, - 554075C518DA58AD00EFF7F2 /* ConstantMode.h in Headers */, - 554075C618DA58AD00EFF7F2 /* ConstructData.h in Headers */, - 554075D518DA58AD00EFF7F2 /* DataView.h in Headers */, - 554075D818DA58AD00EFF7F2 /* DateInstance.h in Headers */, - 554075D918DA58AD00EFF7F2 /* DateInstanceCache.h in Headers */, - 554075DC18DA58AD00EFF7F2 /* Debugger.h in Headers */, - 5540766D18DA58AD00EFF7F2 /* DumpContext.h in Headers */, - 5540767018DA58AD00EFF7F2 /* Error.h in Headers */, - 5540767218DA58AD00EFF7F2 /* ErrorHandlingScope.h in Headers */, - 5540767318DA58AD00EFF7F2 /* ErrorInstance.h in Headers */, - 5540767418DA58AD00EFF7F2 /* ErrorPrototype.h in Headers */, - 5540767718DA58AD00EFF7F2 /* ExceptionHelpers.h in Headers */, - 5540767818DA58AD00EFF7F2 /* Executable.h in Headers */, - 5540767E18DA58AD00EFF7F2 /* Float32Array.h in Headers */, - 5540767F18DA58AD00EFF7F2 /* Float64Array.h in Headers */, - 5540768318DA58AD00EFF7F2 /* ConsoleClient.h in Headers */, - 554076B618DA58AD00EFF7F2 /* FunctionConstructor.h in Headers */, - 554076B718DA58AD00EFF7F2 /* FunctionExecutableDump.h in Headers */, - 554076B818DA58AD00EFF7F2 /* FunctionPrototype.h in Headers */, - 554076C218DA58AD00EFF7F2 /* GenericTypedArrayView.h in Headers */, - 554076C318DA58AD00EFF7F2 /* GenericTypedArrayViewInlines.h in Headers */, - 554076D618DA58AD00EFF7F2 /* Identifier.h in Headers */, - 554076DA18DA58AD00EFF7F2 /* IndexingHeader.h in Headers */, - 554076DB18DA58AD00EFF7F2 /* IndexingHeaderInlines.h in Headers */, - 554076DC18DA58AD00EFF7F2 /* IndexingType.h in Headers */, - 554076DF18DA58AD00EFF7F2 /* InitializeThreading.h in Headers */, - 554076F818DA58AD00EFF7F2 /* Int16Array.h in Headers */, - 554076F918DA58AD00EFF7F2 /* Int32Array.h in Headers */, - 554076FA18DA58AD00EFF7F2 /* Int8Array.h in Headers */, - 554076FB18DA58AD00EFF7F2 /* IntendedStructureChain.h in Headers */, - 554076FC18DA58AD00EFF7F2 /* InternalFunction.h in Headers */, - 554076FE18DA58AD00EFF7F2 /* Intrinsic.h in Headers */, - 5540771918DA58AD00EFF7F2 /* JSAPIValueWrapper.h in Headers */, - 5540771C18DA58AD00EFF7F2 /* JSArray.h in Headers */, - 5540771D18DA58AD00EFF7F2 /* JSArrayBuffer.h in Headers */, - 5540771E18DA58AD00EFF7F2 /* JSArrayBufferConstructor.h in Headers */, - 5540771F18DA58AD00EFF7F2 /* JSArrayBufferPrototype.h in Headers */, - 5540772018DA58AD00EFF7F2 /* JSArrayBufferView.h in Headers */, - 5540772118DA58AD00EFF7F2 /* JSArrayBufferViewInlines.h in Headers */, - 5540772B18DA58AD00EFF7F2 /* JSCell.h in Headers */, - 5540772C18DA58AD00EFF7F2 /* JSCellInlines.h in Headers */, - 5540772D18DA58AD00EFF7F2 /* JSCInlines.h in Headers */, - 5540772E18DA58AD00EFF7F2 /* JSCJSValue.h in Headers */, - 5540772F18DA58AD00EFF7F2 /* JSCJSValueInlines.h in Headers */, - 5540773618DA58AD00EFF7F2 /* JSDataView.h in Headers */, - 5540773718DA58AD00EFF7F2 /* JSDataViewPrototype.h in Headers */, - 5540773818DA58AD00EFF7F2 /* JSDateMath.h in Headers */, - 5540773918DA58AD00EFF7F2 /* JSDestructibleObject.h in Headers */, - 5540773B18DA58AD00EFF7F2 /* JSExportMacros.h in Headers */, - 5540773C18DA58AD00EFF7F2 /* JSFloat32Array.h in Headers */, - 5540773D18DA58AD00EFF7F2 /* JSFloat64Array.h in Headers */, - 5540773E18DA58AD00EFF7F2 /* JSFunction.h in Headers */, - 5540773F18DA58AD00EFF7F2 /* JSFunctionInlines.h in Headers */, - 5540774018DA58AD00EFF7F2 /* JSGenericTypedArrayView.h in Headers */, - 5540774118DA58AD00EFF7F2 /* JSGenericTypedArrayViewConstructor.h in Headers */, - 5540774218DA58AD00EFF7F2 /* JSGenericTypedArrayViewConstructorInlines.h in Headers */, - 5540774318DA58AD00EFF7F2 /* JSGenericTypedArrayViewInlines.h in Headers */, - 5540774418DA58AD00EFF7F2 /* JSGenericTypedArrayViewPrototype.h in Headers */, - 5540774518DA58AD00EFF7F2 /* JSGenericTypedArrayViewPrototypeInlines.h in Headers */, - 5540774618DA58AD00EFF7F2 /* JSGlobalObject.h in Headers */, - 5540775018DA58AD00EFF7F2 /* JSInt16Array.h in Headers */, - 5540775118DA58AD00EFF7F2 /* JSInt32Array.h in Headers */, - 5540775218DA58AD00EFF7F2 /* JSInt8Array.h in Headers */, - 5540775518DA58AD00EFF7F2 /* JSLock.h in Headers */, - 5540775818DA58AD00EFF7F2 /* JSMap.h in Headers */, - 5540775B18DA58AD00EFF7F2 /* JSNameScope.h in Headers */, - 5540775C18DA58AD00EFF7F2 /* JSObject.h in Headers */, - 5540775F18DA58AD00EFF7F2 /* JSONObject.h in Headers */, - 5540776218DA58AD00EFF7F2 /* JSPromise.h in Headers */, - 5540776418DA58AD00EFF7F2 /* JSPromiseDeferred.h in Headers */, - 5540776518DA58AD00EFF7F2 /* JSPromiseFunctions.h in Headers */, - 5540776818DA58AD00EFF7F2 /* JSProxy.h in Headers */, - 5540776B18DA58AD00EFF7F2 /* JSScope.h in Headers */, - 5540776D18DA58AD00EFF7F2 /* JSSegmentedVariableObject.h in Headers */, - 5540776E18DA58AD00EFF7F2 /* JSSet.h in Headers */, - 5540777218DA58AD00EFF7F2 /* JSString.h in Headers */, - 5540777818DA58AD00EFF7F2 /* JSSymbolTableObject.h in Headers */, - 5540777918DA58AD00EFF7F2 /* JSType.h in Headers */, - 5540777A18DA58AD00EFF7F2 /* JSTypedArrayConstructors.h in Headers */, - 5540777B18DA58AD00EFF7F2 /* JSTypedArrayPrototypes.h in Headers */, - 5540777C18DA58AD00EFF7F2 /* JSTypedArrays.h in Headers */, - 5540777D18DA58AD00EFF7F2 /* JSTypeInfo.h in Headers */, - 5540777E18DA58AD00EFF7F2 /* JSUint16Array.h in Headers */, - 5540777F18DA58AD00EFF7F2 /* JSUint32Array.h in Headers */, - 5540778018DA58AD00EFF7F2 /* JSUint8Array.h in Headers */, - 5540778118DA58AD00EFF7F2 /* JSUint8ClampedArray.h in Headers */, - 5540778518DA58AD00EFF7F2 /* JSVariableObject.h in Headers */, - 5540778B18DA58AD00EFF7F2 /* JSWithScope.h in Headers */, - 5540778D18DA58AD00EFF7F2 /* JSWrapperObject.h in Headers */, - 554077A918DA58AD00EFF7F2 /* Lookup.h in Headers */, - 554077B818DA58AD00EFF7F2 /* MapData.h in Headers */, - 554077C118DA58AD00EFF7F2 /* MatchResult.h in Headers */, - 554077C218DA58AD00EFF7F2 /* MathObject.h in Headers */, - 554077C318DA58AD00EFF7F2 /* MemoryStatistics.h in Headers */, - 554077C518DA58AD00EFF7F2 /* Microtask.h in Headers */, - 554077D318DA58AD00EFF7F2 /* NumberObject.h in Headers */, - 554077D418DA58AD00EFF7F2 /* NumberPrototype.h in Headers */, - 554077D618DA58AD00EFF7F2 /* NumericStrings.h in Headers */, - 554077DA18DA58AD00EFF7F2 /* ObjectConstructor.h in Headers */, - 554077DB18DA58AD00EFF7F2 /* ObjectPrototype.h in Headers */, - 554077E018DA58AD00EFF7F2 /* Operations.h in Headers */, - 554077E118DA58AD00EFF7F2 /* Options.h in Headers */, - 554077EA18DA58AD00EFF7F2 /* PrivateName.h in Headers */, - 554077FD18DA58AD00EFF7F2 /* PropertyDescriptor.h in Headers */, - 554077FE18DA58AD00EFF7F2 /* PropertyMapHashTable.h in Headers */, - 554077FF18DA58AD00EFF7F2 /* PropertyName.h in Headers */, - 5540780018DA58AD00EFF7F2 /* PropertyNameArray.h in Headers */, - 5540780118DA58AD00EFF7F2 /* PropertyOffset.h in Headers */, - 5540780318DA58AD00EFF7F2 /* PropertySlot.h in Headers */, - 5540780418DA58AD00EFF7F2 /* PropertyStorage.h in Headers */, - 5540780518DA58AD00EFF7F2 /* Protect.h in Headers */, - 5540780618DA58AD00EFF7F2 /* PrototypeMap.h in Headers */, - 5540780818DA58AD00EFF7F2 /* PutDirectIndexMode.h in Headers */, - 5540780A18DA58AD00EFF7F2 /* PutPropertySlot.h in Headers */, - 5540780E18DA58AD00EFF7F2 /* RegExp.h in Headers */, - 5540780F18DA58AD00EFF7F2 /* RegExpCache.h in Headers */, - 5540781218DA58AD00EFF7F2 /* RegExpKey.h in Headers */, - 5540781318DA58AD00EFF7F2 /* RegExpObject.h in Headers */, - 5540781918DA58AD00EFF7F2 /* RegisterPreservationMode.h in Headers */, - 5540781D18DA58AD00EFF7F2 /* Reject.h in Headers */, - 5540782618DA58AD00EFF7F2 /* SamplingCounter.h in Headers */, - 5540783818DA58AD00EFF7F2 /* SimpleTypedArrayController.h in Headers */, - 5540783C18DA58AD00EFF7F2 /* SmallStrings.h in Headers */, - 5540784118DA58AD00EFF7F2 /* SparseArrayValueMap.h in Headers */, - 5540784518DA58AD00EFF7F2 /* StackAlignment.h in Headers */, - 5540784B18DA58AD00EFF7F2 /* StringObject.h in Headers */, - 5540784C18DA58AD00EFF7F2 /* StringPrototype.h in Headers */, - 5540784F18DA58AD00EFF7F2 /* Structure.h in Headers */, - 5540785018DA58AD00EFF7F2 /* StructureChain.h in Headers */, - 5540785118DA58AD00EFF7F2 /* StructureInlines.h in Headers */, - 5540785218DA58AD00EFF7F2 /* StructureRareData.h in Headers */, - 5540785318DA58AD00EFF7F2 /* StructureRareDataInlines.h in Headers */, - 5540785718DA58AD00EFF7F2 /* StructureTransitionTable.h in Headers */, - 5540785918DA58AD00EFF7F2 /* SymbolTable.h in Headers */, - 5540785C18DA58AD00EFF7F2 /* TestRunnerUtils.h in Headers */, - 5540786018DA58AD00EFF7F2 /* ToNativeFromValue.h in Headers */, - 5540786218DA58AD00EFF7F2 /* TypedArrayAdaptors.h in Headers */, - 5540786318DA58AD00EFF7F2 /* TypedArrayController.h in Headers */, - 5540786418DA58AD00EFF7F2 /* TypedArrayInlines.h in Headers */, - 5540786518DA58AD00EFF7F2 /* TypedArrays.h in Headers */, - 5540786618DA58AD00EFF7F2 /* TypedArrayType.h in Headers */, - 5540786E18DA58AD00EFF7F2 /* Uint16Array.h in Headers */, - 5540787018DA58AD00EFF7F2 /* Uint32Array.h in Headers */, - 5540787118DA58AD00EFF7F2 /* Uint8Array.h in Headers */, - 5540787218DA58AD00EFF7F2 /* Uint8ClampedArray.h in Headers */, - 5540787A18DA58AD00EFF7F2 /* VM.h in Headers */, - 5540787B18DA58AD00EFF7F2 /* VMEntryScope.h in Headers */, - 5540787D18DA58AD00EFF7F2 /* Watchdog.h in Headers */, - 5540788118DA58AD00EFF7F2 /* WeakGCMap.h in Headers */, - 5540788818DA58AD00EFF7F2 /* WeakRandom.h in Headers */, - 5540788D18DA58AD00EFF7F2 /* WriteBarrier.h in Headers */, - 5540788F18DA58AD00EFF7F2 /* WriteBarrierInlines.h in Headers */, - 5540757718DA58AD00EFF7F2 /* ArityCheckMode.h in Headers */, - 5540757218DA58AD00EFF7F2 /* ArgList.h in Headers */, - 5510502618EB827500001F3E /* JSCallbackFunction.h in Headers */, - 5540781018DA58AD00EFF7F2 /* RegExpConstructor.h in Headers */, - 5540781518DA58AD00EFF7F2 /* RegExpPrototype.h in Headers */, - 5540783318DA58AD00EFF7F2 /* SetConstructor.h in Headers */, - 5540783418DA58AD00EFF7F2 /* SetIteratorConstructor.h in Headers */, - 5540783518DA58AD00EFF7F2 /* SetIteratorPrototype.h in Headers */, - 5540783618DA58AD00EFF7F2 /* SetPrototype.h in Headers */, - 5540784918DA58AD00EFF7F2 /* StrictEvalActivation.h in Headers */, - 5540784A18DA58AD00EFF7F2 /* StringConstructor.h in Headers */, - 5540786118DA58AD00EFF7F2 /* Tracing.h in Headers */, - 5540786F18DA58AD00EFF7F2 /* Uint16WithFraction.h in Headers */, - 5540788518DA58AD00EFF7F2 /* WeakMapConstructor.h in Headers */, - 5540788618DA58AD00EFF7F2 /* WeakMapData.h in Headers */, - 5540788718DA58AD00EFF7F2 /* WeakMapPrototype.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 932F5B3F0822A1C700736975 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 0FFA549816B8835300B3A982 /* A64DOpcode.h in Headers */, 860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */, + 0FE050291AA9095600D33B33 /* ScopedArgumentsTable.h in Headers */, 0F55F0F514D1063C00AC7649 /* AbstractPC.h in Headers */, 2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */, BC18C3E50E16F5CD00B34460 /* APICast.h in Headers */, BCF605140E203EF800B9A64D /* ArgList.h in Headers */, 2A88067919107D5500CB0BBB /* DFGFunctionWhitelist.h in Headers */, - BC257DE80E1F51C50016B6C9 /* Arguments.h in Headers */, - A76140CE182982CB00750624 /* ArgumentsIteratorConstructor.h in Headers */, - A76140D0182982CB00750624 /* ArgumentsIteratorPrototype.h in Headers */, 0F6B1CCA18641DF800845D97 /* ArityCheckFailReturnThunks.h in Headers */, 0F6B1CB91861244C00845D97 /* ArityCheckMode.h in Headers */, A1A009C11831A26E00CF8711 /* ARM64Assembler.h in Headers */, + 0F898F321B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.h in Headers */, 86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */, + 0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */, + 52C0611F1AA51E1C00B4ADBA /* RuntimeType.h in Headers */, + FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */, + FE5068651AE246390009DAB7 /* DeferredSourceDump.h in Headers */, + C442CB251A6CDB8C005D3D7C /* JSInputs.json in Headers */, + FE1C0FFD1B193E9800B53FCA /* Exception.h in Headers */, + 52678F911A04177C006A306D /* ControlFlowProfiler.h in Headers */, + 52678F8F1A031009006A306D /* BasicBlockLocation.h in Headers */, + A5EA710E19F6DF810098F5EC /* InspectorAlternateBackendDispatchers.h in Headers */, + A5EA70EC19F5B3EA0098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py in Headers */, + C4F4B6F31A05C944005CAB76 /* cpp_generator_templates.py in Headers */, + A5EF9B151A1D43FA00702E90 /* generate_cpp_backend_dispatcher_implementation.py in Headers */, + FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */, + FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */, + 6AD2CB4D19B9140100065719 /* DebuggerEvalEnabler.h in Headers */, + 658D3A5619638268003C45D6 /* VMEntryRecord.h in Headers */, + A5EF9B161A1D440000702E90 /* generate_cpp_frontend_dispatcher_header.py in Headers */, + 2AD2EDFB19799E38004D6478 /* EnumerationMode.h in Headers */, + A5EF9B181A1D440600702E90 /* generate_cpp_protocol_types_header.py in Headers */, + A5EF9B191A1D440700702E90 /* generate_cpp_protocol_types_implementation.py in Headers */, + C4F4B6F61A05C984005CAB76 /* objc_generator_templates.py in Headers */, + 70DC3E0A1B2DF2C700054299 /* IteratorPrototype.h in Headers */, + A5EF9B171A1D440300702E90 /* generate_cpp_frontend_dispatcher_implementation.py in Headers */, 147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */, 2A111246192FCE79005EE18D /* CustomGetterSetter.h in Headers */, + C4F4B6F51A05C984005CAB76 /* generate_objc_protocol_types_implementation.py in Headers */, A584032018BFFBE1005A0811 /* InspectorAgent.h in Headers */, 2AABCDE718EF294200002096 /* GCLogging.h in Headers */, - FE5248F9191442D900B7FDE4 /* VariableWatchpointSetInlines.h in Headers */, + FE7BA6101A1A7CEC00F1F7B4 /* HeapVerifier.h in Headers */, + A5EF9B141A1D43F600702E90 /* generate_cpp_backend_dispatcher_header.py in Headers */, C2DA778318E259990066FCB6 /* HeapInlines.h in Headers */, + C4F4B6F41A05C944005CAB76 /* cpp_generator.py in Headers */, + A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */, + A5840E27187C981E00843B10 /* cssmin.py in Headers */, + A5EA710419F6DE720098F5EC /* generate_objc_backend_dispatcher_implementation.py in Headers */, + C4703CD5192844CC0013FBEA /* generator_templates.py in Headers */, + A5EA710519F6DE740098F5EC /* generate_objc_configuration_header.py in Headers */, + A5EA710619F6DE760098F5EC /* generate_objc_configuration_implementation.py in Headers */, + A5EA710719F6DE780098F5EC /* generate_objc_conversion_helpers.py in Headers */, + A5EA710819F6DE7A0098F5EC /* generate_objc_frontend_dispatcher_implementation.py in Headers */, + A5EA710A19F6DE7E0098F5EC /* generate_objc_internal_header.py in Headers */, + A5EA710C19F6DE820098F5EC /* objc_generator.py in Headers */, + A5EA710919F6DE7C0098F5EC /* generate_objc_header.py in Headers */, + C4703CD6192844CC0013FBEA /* generator.py in Headers */, + C4703CC0192844960013FBEA /* generate-inspector-protocol-bindings.py in Headers */, + C4703CCE192844CC0013FBEA /* generate_js_backend_commands.py in Headers */, + C4703CD7192844CC0013FBEA /* models.py in Headers */, + A5EA710319F6DE6F0098F5EC /* generate_objc_backend_dispatcher_header.py in Headers */, 2AACE63D18CA5A0300ED0191 /* GCActivityCallback.h in Headers */, 2A83638618D7D0EE0000EBCC /* EdenGCActivityCallback.h in Headers */, 2A83638A18D7D0FE0000EBCC /* FullGCActivityCallback.h in Headers */, @@ -5530,12 +5684,12 @@ 6514F21918B3E1670098FF8B /* Bytecodes.h in Headers */, 65C0285D1717966800351E35 /* ARMv7DOpcode.h in Headers */, 0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */, + 0FD120341A8C85BD000F5280 /* FTLJSCallVarargs.h in Headers */, A7A8AF3517ADB5F3005AB174 /* ArrayBuffer.h in Headers */, 0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h in Headers */, A7A8AF3717ADB5F3005AB174 /* ArrayBufferView.h in Headers */, BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */, 0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */, - A7BDAEC717F4EA1400F6140C /* ArrayIteratorConstructor.h in Headers */, A7BDAEC917F4EA1400F6140C /* ArrayIteratorPrototype.h in Headers */, 0F63945515D07057006A597C /* ArrayProfile.h in Headers */, BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */, @@ -5547,44 +5701,47 @@ 0F24E54117EA9F5900ABB217 /* AssemblyHelpers.h in Headers */, A784A26111D16622005776AC /* ASTBuilder.h in Headers */, 866739D213BFDE710023D87C /* BigInteger.h in Headers */, - 14816E1C154CC56C00B8054C /* BlockAllocator.h in Headers */, BC18C3EC0E16F5CD00B34460 /* BooleanObject.h in Headers */, FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */, A5D2E665195E174000A518E7 /* JSContextRefInternal.h in Headers */, A7D801A51880D66E0026C39B /* BuiltinExecutables.h in Headers */, A75EE9B218AAB7E200AAD043 /* BuiltinNames.h in Headers */, + 0F2B9CF719D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h in Headers */, 0FB7F39715ED8E4600F167B2 /* Butterfly.h in Headers */, 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */, + 62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */, C2FCAE1117A9C24E0034C735 /* BytecodeBasicBlock.h in Headers */, 0F21C27F14BEAA8200ADC64B /* BytecodeConventions.h in Headers */, 969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */, C2FCAE1317A9C24E0034C735 /* BytecodeLivenessAnalysis.h in Headers */, 0F666EC0183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h in Headers */, + 0F8F14361ADF090100ED792C /* DFGMovHintRemovalPhase.h in Headers */, 0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */, 0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */, BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */, + AD86A93E1AA4D88D002FE77F /* WeakGCMapInlines.h in Headers */, 1429D8DE0ED2205B00B89619 /* CallFrame.h in Headers */, A7C1EAEF17987AB600299DB2 /* CallFrameInlines.h in Headers */, 95E3BC050E1AE68200B2D1C1 /* CallIdentifier.h in Headers */, 0F0B83B114BCF71800885B4F /* CallLinkInfo.h in Headers */, 0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */, 0F0B83B914BCF95F00885B4F /* CallReturnOffsetToBytecodeOffset.h in Headers */, + 0F69CC89193AC60A0045759E /* DFGFrozenValue.h in Headers */, 0F24E54217EA9F5900ABB217 /* CCallHelpers.h in Headers */, BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */, - 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */, 969A07970ED1D3AE00F1F681 /* CodeBlock.h in Headers */, 0F8F94411667633200D61971 /* CodeBlockHash.h in Headers */, 0FC97F34182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.h in Headers */, + 70ECA6081AFDBEA200449739 /* TemplateRegistry.h in Headers */, 0FD8A31417D4326C00CA2C40 /* CodeBlockSet.h in Headers */, 0F96EBB316676EF6008BADE3 /* CodeBlockWithJITType.h in Headers */, A77F1822164088B200640A47 /* CodeCache.h in Headers */, - A532439218569709002ED692 /* CodeGeneratorInspector.py in Headers */, - A532439318569709002ED692 /* CodeGeneratorInspectorStrings.py in Headers */, 86E116B10FE75AC800B512BC /* CodeLocation.h in Headers */, 0FBD7E691447999600481315 /* CodeOrigin.h in Headers */, 0F21C27D14BE727A00ADC64B /* CodeSpecializationKind.h in Headers */, 0F0B83A714BCF50700885B4F /* CodeType.h in Headers */, BC18C3F30E16F5CD00B34460 /* CommonIdentifiers.h in Headers */, + 709FB86C1AE335C60039D069 /* WeakSetPrototype.h in Headers */, 0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */, 6553A33217A1F1EE008CF6F3 /* CommonSlowPathsExceptions.h in Headers */, 0FD82E39141AB14D00179C94 /* CompactJITCodeMap.h in Headers */, @@ -5593,6 +5750,7 @@ BC18C3F40E16F5CD00B34460 /* Completion.h in Headers */, 0FDB2CEA174896C7007B3C1B /* ConcurrentJITLock.h in Headers */, BC18C3F50E16F5CD00B34460 /* config.h in Headers */, + 0FFB6C391AF48DDC00DB1BF7 /* TypeofType.h in Headers */, 144836E7132DA7BE005BE785 /* ConservativeRoots.h in Headers */, A5FD007A189B051000633231 /* ConsoleMessage.h in Headers */, A5FD0074189B038C00633231 /* ConsoleTypes.h in Headers */, @@ -5602,40 +5760,43 @@ C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */, C2C8D03014A3CEFC00578E65 /* CopiedBlock.h in Headers */, C2FC9BD316644DFB00810D33 /* CopiedBlockInlines.h in Headers */, + A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */, C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */, C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */, + 0FEE98411A8865B700754E93 /* SetupVarargsFrame.h in Headers */, + 0FC3CCFD19ADA410006AC72A /* DFGBlockMapInlines.h in Headers */, 0F5A52D017ADD717008ECB2D /* CopyToken.h in Headers */, C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */, C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */, C218D1401655CFD50062BB81 /* CopyWorkList.h in Headers */, 2A68295B1875F80500B6C3E2 /* CopyWriteBarrier.h in Headers */, 5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */, - A5840E27187C981E00843B10 /* cssmin.py in Headers */, 0F426A4B1460CD6E00131F8F /* DataFormat.h in Headers */, + 0F2B9CE519D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.h in Headers */, 0F2B66DF17B6B5AB00A7AE3F /* DataView.h in Headers */, BCD2034A0E17135E002C7E82 /* DateConstructor.h in Headers */, 41359CF30FDD89AD00206180 /* DateConversion.h in Headers */, BC1166020E1997B4008066DD /* DateInstance.h in Headers */, + 0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */, 14A1563210966365006FA260 /* DateInstanceCache.h in Headers */, BCD2034C0E17135E002C7E82 /* DatePrototype.h in Headers */, BCD203E80E1718F4002C7E82 /* DatePrototype.lut.h in Headers */, BC18C3FA0E16F5CD00B34460 /* Debugger.h in Headers */, - BC3135640F302FA3003DFD3A /* DebuggerActivation.h in Headers */, BC18C3FB0E16F5CD00B34460 /* DebuggerCallFrame.h in Headers */, FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */, 0F136D4D174AD69E0075B354 /* DeferGC.h in Headers */, 0FC712DF17CD877C008CC93C /* DeferredCompilationCallback.h in Headers */, - 2A2825D018341F2D0087FBA9 /* DelayedReleaseScope.h in Headers */, A77A423E17A0BBFD00A8DB81 /* DFGAbstractHeap.h in Headers */, + A5EA70E819F5B1010098F5EC /* AugmentableInspectorControllerClient.h in Headers */, A704D90317A0BAA8006BA554 /* DFGAbstractInterpreter.h in Headers */, A704D90417A0BAA8006BA554 /* DFGAbstractInterpreterInlines.h in Headers */, 0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */, + 0FF054FA1AC35B4400E5BE57 /* ExecutableAllocationFuzz.h in Headers */, 0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */, 0FFB921816D02EB20055A5DB /* DFGAllocator.h in Headers */, A737810C1799EA2E00817533 /* DFGAnalysis.h in Headers */, 0F1E3A461534CBAF000F9456 /* DFGArgumentPosition.h in Headers */, - A5C3A1A618C0490200C9593A /* JSConsoleClient.h in Headers */, - 0F16015E156198C900C2587C /* DFGArgumentsSimplificationPhase.h in Headers */, + A5C3A1A618C0490200C9593A /* JSGlobalObjectConsoleClient.h in Headers */, 0F485322187750560083B687 /* DFGArithMode.h in Headers */, 0F05C3B41683CF9200BAF45B /* DFGArrayifySlowPathGenerator.h in Headers */, 0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */, @@ -5644,13 +5805,13 @@ 0F714CA516EA92F200F3EBEB /* DFGBackwardsPropagationPhase.h in Headers */, 0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */, 0FFB921A16D02EC50055A5DB /* DFGBasicBlockInlines.h in Headers */, - A70B083317A0B79B00DAF14B /* DFGBinarySwitch.h in Headers */, A7D89CF417A0B8CC00773AD8 /* DFGBlockInsertionSet.h in Headers */, 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */, 86EC9DC51328DF82002B2AD7 /* DFGByteCodeParser.h in Headers */, 0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */, 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */, 0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */, + 0F2DD80B1AB3D85800BBB8E8 /* BytecodeKills.h in Headers */, 0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */, A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */, A77A424217A0BBFD00A8DB81 /* DFGClobberSet.h in Headers */, @@ -5664,7 +5825,6 @@ 0FFFC95A14EF90A900C72532 /* DFGCSEPhase.h in Headers */, 0F2FC77316E12F740038D976 /* DFGDCEPhase.h in Headers */, 0F8F2B9A172F0501007DBDA5 /* DFGDesiredIdentifiers.h in Headers */, - A73E1331179624CD00E4DEA8 /* DFGDesiredStructureChains.h in Headers */, C2C0F7CE17BBFC5B00464FE4 /* DFGDesiredTransitions.h in Headers */, 0FE8534C1723CDA500B618F5 /* DFGDesiredWatchpoints.h in Headers */, C2981FD917BAEE4B00A3BC98 /* DFGDesiredWeakReferences.h in Headers */, @@ -5675,12 +5835,14 @@ 0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */, 0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */, A7D9A29617A0BC7400EE2618 /* DFGEdgeDominates.h in Headers */, + 0FBF158D19B7A53100695DD0 /* DFGBlockSetInlines.h in Headers */, A7986D5717A0BB1E00A95DD0 /* DFGEdgeUsesStructure.h in Headers */, 0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */, A78A9775179738B8009DF744 /* DFGFailedFinalizer.h in Headers */, A7BFF3C0179868940002F462 /* DFGFiltrationResult.h in Headers */, A78A9777179738B8009DF744 /* DFGFinalizer.h in Headers */, 0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */, + 0FC3CCFC19ADA410006AC72A /* DFGBlockMap.h in Headers */, 0F9D339717FFC4E60073C2BC /* DFGFlushedAt.h in Headers */, A7D89CF817A0B8CC00773AD8 /* DFGFlushFormat.h in Headers */, 86EC9DC61328DF82002B2AD7 /* DFGGenerationInfo.h in Headers */, @@ -5688,6 +5850,7 @@ 0F2FCCFA18A60070001A27F8 /* DFGGraphSafepoint.h in Headers */, 0FB14E211812570B009B6B4D /* DFGInlineCacheWrapper.h in Headers */, 0FB14E2318130955009B6B4D /* DFGInlineCacheWrapperInlines.h in Headers */, + 0F79085619A290B200F6310C /* DFGStructureRegistrationPhase.h in Headers */, A704D90617A0BAA8006BA554 /* DFGInPlaceAbstractState.h in Headers */, 0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */, 0F300B7C18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.h in Headers */, @@ -5697,11 +5860,15 @@ A78A9779179738B8009DF744 /* DFGJITFinalizer.h in Headers */, 0FC97F4018202119002C9B26 /* DFGJumpReplacement.h in Headers */, A73A535B1799CD5D00170C19 /* DFGLazyJSValue.h in Headers */, + 0F2B9CE919D0BA7D00B1D1B5 /* DFGObjectMaterializationData.h in Headers */, A7D9A29817A0BC7400EE2618 /* DFGLICMPhase.h in Headers */, A7D89CFC17A0B8CC00773AD8 /* DFGLivenessAnalysisPhase.h in Headers */, 0FF0F19B16B729FA005DF95B /* DFGLongLivedState.h in Headers */, + 709FB8681AE335C60039D069 /* JSWeakSet.h in Headers */, A767B5B617A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.h in Headers */, + 0F2B9CED19D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.h in Headers */, A704D90717A0BAA8006BA554 /* DFGMergeMode.h in Headers */, + 0FB17663196B8F9E0091052A /* DFGPureValue.h in Headers */, 0F2BDC451522801B00CD8910 /* DFGMinifiedGraph.h in Headers */, 0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */, 0F2BDC461522802000CD8910 /* DFGMinifiedNode.h in Headers */, @@ -5715,24 +5882,27 @@ A7D89CFE17A0B8CC00773AD8 /* DFGOSRAvailabilityAnalysisPhase.h in Headers */, 0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */, 0FD8A32617D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.h in Headers */, + 62F2AA381B0BEDE300610C7A /* DFGLazyNode.h in Headers */, 0FC0976A1468A6F700CF2442 /* DFGOSRExit.h in Headers */, 0F235BEC17178E7300690C7F /* DFGOSRExitBase.h in Headers */, 0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */, 0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */, 0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */, + 0FD949851A97DB9600E28966 /* JSFunctionNameScope.h in Headers */, 0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */, 0F4CED5F18CEA7AB00802FE0 /* PolymorphicGetByIdList.h in Headers */, 0F235BEE17178E7300690C7F /* DFGOSRExitPreparation.h in Headers */, 0FFFC95C14EF90AF00C72532 /* DFGPhase.h in Headers */, + A5EA70EE19F5B5C40098F5EC /* JSContextRefInspectorSupport.h in Headers */, A78A977B179738B8009DF744 /* DFGPlan.h in Headers */, 0FBE0F7516C1DB0B0082C5E8 /* DFGPredictionInjectionPhase.h in Headers */, 0FFFC95E14EF90B700C72532 /* DFGPredictionPropagationPhase.h in Headers */, 86EC9DD11328DF82002B2AD7 /* DFGRegisterBank.h in Headers */, - 0F666ECD1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h in Headers */, 0F2FCCFC18A60070001A27F8 /* DFGSafepoint.h in Headers */, A77A424317A0BBFD00A8DB81 /* DFGSafeToExecute.h in Headers */, A741017F179DAF80002EB8BA /* DFGSaneStringGetByValSlowPathGenerator.h in Headers */, 0F2FCCFD18A60070001A27F8 /* DFGScannable.h in Headers */, + 0F2DD8141AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.h in Headers */, 86ECA3FA132DF25A002B2AD7 /* DFGScoreBoard.h in Headers */, 0F1E3A67153A21E2000F9456 /* DFGSilentRegisterSavePlan.h in Headers */, 0FFB921D16D02F300055A5DB /* DFGSlowPathGenerator.h in Headers */, @@ -5740,8 +5910,8 @@ A7D89D0017A0B8CC00773AD8 /* DFGSSAConversionPhase.h in Headers */, 0FC20CBA18556A3500C9E954 /* DFGSSALoweringPhase.h in Headers */, 0F9FB4F517FCB91700CB67F8 /* DFGStackLayoutPhase.h in Headers */, + 0F9E32641B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.h in Headers */, 0F4F29E018B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.h in Headers */, - 2ACCF3DF185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.h in Headers */, 0FC20CB61852E2C600C9E954 /* DFGStrengthReductionPhase.h in Headers */, 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */, 0F2FCCFF18A60070001A27F8 /* DFGThreadData.h in Headers */, @@ -5753,9 +5923,9 @@ 0FBE0F7716C1DB120082C5E8 /* DFGUnificationPhase.h in Headers */, 0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */, 0F3B3A2C15475002003ED0FF /* DFGValidate.h in Headers */, - 0F2BDC471522802500CD8910 /* DFGValueRecoveryOverride.h in Headers */, 0F2BDC481522802900CD8910 /* DFGValueSource.h in Headers */, 0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */, + 0FAA3E0919D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h in Headers */, 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */, 0F2BDC491522809600CD8910 /* DFGVariableEvent.h in Headers */, 0F2BDC4B1522809D00CD8910 /* DFGVariableEventStream.h in Headers */, @@ -5766,6 +5936,7 @@ A70447EE17A0BD7000F5898E /* DumpContext.h in Headers */, 99E45A2418A1B2590026D88F /* EmptyInputCursor.h in Headers */, 99E45A2618A1B2590026D88F /* EncodedValue.h in Headers */, + 0F5874EE194FEB1200AAB2C1 /* DFGMayExit.h in Headers */, BC3046070E1F497F003232CF /* Error.h in Headers */, BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */, FEB58C15187B8B160098EF0B /* ErrorHandlingScope.h in Headers */, @@ -5783,10 +5954,13 @@ A7A8AF3817ADB5F3005AB174 /* Float32Array.h in Headers */, A7A8AF3917ADB5F3005AB174 /* Float64Array.h in Headers */, 0F24E54317EA9F5900ABB217 /* FPRInfo.h in Headers */, + 7094C4DF1AE439530041A2EE /* BytecodeIntrinsicRegistry.h in Headers */, 0FDB2CC9173DA520007B3C1B /* FTLAbbreviatedTypes.h in Headers */, 0FEA0A08170513DB00BB722C /* FTLAbbreviations.h in Headers */, A53CE08A18BC21C300BEDF76 /* ConsoleClient.h in Headers */, + 0FE050191AA9091100D33B33 /* GenericArguments.h in Headers */, 0FEA0A1D1708B00700BB722C /* FTLAbstractHeap.h in Headers */, + DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */, 0FEA0A1F1708B00700BB722C /* FTLAbstractHeapRepository.h in Headers */, 0F485328187DFDEC0083B687 /* FTLAvailableRecovery.h in Headers */, 0FEA0A0A170513DB00BB722C /* FTLCapabilities.h in Headers */, @@ -5798,6 +5972,7 @@ 0F235BD617178E1C00690C7F /* FTLExitArgumentForOperand.h in Headers */, 0F235BD717178E1C00690C7F /* FTLExitArgumentList.h in Headers */, 0F235BD917178E1C00690C7F /* FTLExitThunkGenerator.h in Headers */, + 0F9D36951AE9CC33000D4DFB /* DFGCleanUpPhase.h in Headers */, 0F235BDB17178E1C00690C7F /* FTLExitValue.h in Headers */, A53CE08618BC1A5600BEDF76 /* ConsolePrototype.h in Headers */, A7F2996C17A0BB670010417A /* FTLFail.h in Headers */, @@ -5809,6 +5984,7 @@ 0FEA0A241709606900BB722C /* FTLIntrinsicRepository.h in Headers */, 0FEA0A0E170513DB00BB722C /* FTLJITCode.h in Headers */, A78A9781179738D5009DF744 /* FTLJITFinalizer.h in Headers */, + 0FED67BA1B26256D0066CE15 /* DFGConstantHoistingPhase.h in Headers */, 0F6B1CB6185FC9E900845D97 /* FTLJSCall.h in Headers */, 0F8F2B96172E04A3007DBDA5 /* FTLLink.h in Headers */, 0FCEFAE0180738C000472CE4 /* FTLLocation.h in Headers */, @@ -5818,7 +5994,9 @@ 0F235BDD17178E1C00690C7F /* FTLOSRExit.h in Headers */, 0F235BDE17178E1C00690C7F /* FTLOSRExitCompilationInfo.h in Headers */, 0F235BE017178E1C00690C7F /* FTLOSRExitCompiler.h in Headers */, + 52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */, 0FEA0A11170513DB00BB722C /* FTLOutput.h in Headers */, + 9E72940B190F0514001A91B5 /* BundlePath.h in Headers */, 0F48532A187DFDEC0083B687 /* FTLRecoveryOpcode.h in Headers */, 0F6B1CC41862C47800845D97 /* FTLRegisterAtOffset.h in Headers */, 0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */, @@ -5832,6 +6010,7 @@ 0F6B1CC61862C47800845D97 /* FTLUnwindInfo.h in Headers */, 0F235BE417178E1C00690C7F /* FTLValueFormat.h in Headers */, 0FDB2CCA173DA523007B3C1B /* FTLValueFromBlock.h in Headers */, + 0FE7211E193B9C590031F6ED /* DFGTransition.h in Headers */, 0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */, 0F0332C618B53FA9005F979A /* FTLWeight.h in Headers */, 0F0332C818B546EC005F979A /* FTLWeightedTarget.h in Headers */, @@ -5841,13 +6020,13 @@ BC18C4050E16F5CD00B34460 /* FunctionPrototype.h in Headers */, BCBE2CAE14E985AA000593AD /* GCAssertions.h in Headers */, 0F766D3015A8DCE2008F363E /* GCAwareJITStubRoutine.h in Headers */, + 70EC0EC71AA0D7DA00B6AAFA /* StringIteratorPrototype.h in Headers */, 0F2B66AC17B6B53F00A7AE3F /* GCIncomingRefCounted.h in Headers */, 0F2B66AD17B6B54500A7AE3F /* GCIncomingRefCountedInlines.h in Headers */, 0F2B66AE17B6B54500A7AE3F /* GCIncomingRefCountedSet.h in Headers */, 0F2B66AF17B6B54500A7AE3F /* GCIncomingRefCountedSetInlines.h in Headers */, C2239D1B16262BDD005AC5FD /* GCThread.h in Headers */, C21122E215DD9AB300790E3A /* GCThreadSharedData.h in Headers */, - A532439418569709002ED692 /* generate-combined-inspector-json.py in Headers */, 0F2B66E017B6B5AB00A7AE3F /* GenericTypedArrayView.h in Headers */, 0F1FE51C1922A3BC006987C5 /* AbortReason.h in Headers */, 0F2B66E117B6B5AB00A7AE3F /* GenericTypedArrayViewInlines.h in Headers */, @@ -5858,20 +6037,21 @@ C283190016FE4B7D00157BFD /* HandleBlock.h in Headers */, C283190216FE533E00157BFD /* HandleBlockInlines.h in Headers */, 0F0B83A914BCF56200885B4F /* HandlerInfo.h in Headers */, + 0F2D4DEC19832DC4007D4B19 /* TypeProfilerLog.h in Headers */, 142E3136134FF0A600AFADB5 /* HandleSet.h in Headers */, 142E3138134FF0A600AFADB5 /* HandleStack.h in Headers */, 1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */, 14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */, - C2C8D03114A3CEFC00578E65 /* HeapBlock.h in Headers */, 2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */, 2A6F462617E959CE00C45C98 /* HeapOperation.h in Headers */, + 0FE050141AA9091100D33B33 /* ArgumentsMode.h in Headers */, 14F97447138C853E00DA1C67 /* HeapRootVisitor.h in Headers */, C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */, C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */, 0F4680D514BBD24B00BFE272 /* HostCallReturnValue.h in Headers */, BC18C40F0E16F5CD00B34460 /* Identifier.h in Headers */, A5FD0076189B038C00633231 /* IdentifiersFactory.h in Headers */, - 996231E918D1804200C03FDA /* InspectorJSBackendCommands.js in Headers */, + 996231E918D1804200C03FDA /* InspectorBackendCommands.js in Headers */, C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */, 0FB7F39915ED8E4600F167B2 /* IndexingHeader.h in Headers */, 0FB7F39A15ED8E4600F167B2 /* IndexingHeaderInlines.h in Headers */, @@ -5885,23 +6065,27 @@ A513E5CB185F9624007E95AD /* InjectedScriptManager.h in Headers */, A5840E21187B7B8600843B10 /* InjectedScriptModule.h in Headers */, A513E5C7185F9446007E95AD /* InjectedScriptSource.h in Headers */, + 0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */, A5840E29187CA5E600843B10 /* inline-and-minify-stylesheets-and-scripts.py in Headers */, 0F24E55617F0B71C00ABB217 /* InlineCallFrameSet.h in Headers */, 99E45A2718A1B2590026D88F /* InputCursor.h in Headers */, + 0F952ABD1B487A7700C367C5 /* TrackedReferences.h in Headers */, A593CF7F1840362C00BFCE27 /* InspectorAgentBase.h in Headers */, + 0F3E01AB19D353A500F61B7F /* DFGPrePostNumbering.h in Headers */, A593CF87184038CA00BFCE27 /* InspectorAgentRegistry.h in Headers */, + 0FE050261AA9095600D33B33 /* ClonedArguments.h in Headers */, A593CF7D1840360300BFCE27 /* InspectorBackendDispatcher.h in Headers */, A5FD0082189B191A00633231 /* InspectorConsoleAgent.h in Headers */, A57D23E61890CEBF0031C7FA /* InspectorDebuggerAgent.h in Headers */, A5D0A1BB1862301B00C7B496 /* InspectorEnvironment.h in Headers */, A5945595182479EB00CC3843 /* InspectorFrontendChannel.h in Headers */, - A53243981856A489002ED692 /* InspectorJS.json in Headers */, - A532438818568335002ED692 /* InspectorJSBackendDispatchers.h in Headers */, - A532438A18568335002ED692 /* InspectorJSFrontendDispatchers.h in Headers */, + A53243981856A489002ED692 /* CombinedDomains.json in Headers */, + A532438818568335002ED692 /* InspectorBackendDispatchers.h in Headers */, + A532438A18568335002ED692 /* InspectorFrontendDispatchers.h in Headers */, 8606DDEA18DA44AB00A383D0 /* IdentifierInlines.h in Headers */, - A532438C18568335002ED692 /* InspectorJSTypeBuilders.h in Headers */, + A532438C18568335002ED692 /* InspectorProtocolObjects.h in Headers */, A50E4B6218809DD50068A46D /* InspectorRuntimeAgent.h in Headers */, - A55D93AC18514F7900400DED /* InspectorTypeBuilder.h in Headers */, + A55D93AC18514F7900400DED /* InspectorProtocolTypes.h in Headers */, A593CF831840377100BFCE27 /* InspectorValues.h in Headers */, 969A07990ED1D3AE00F1F681 /* Instruction.h in Headers */, A7A8AF3B17ADB5F3005AB174 /* Int16Array.h in Headers */, @@ -5911,11 +6095,15 @@ BC11667B0E199C05008066DD /* InternalFunction.h in Headers */, 1429D77C0ED20D7300B89619 /* Interpreter.h in Headers */, 860BD801148EA6F200112B2F /* Intrinsic.h in Headers */, + 70113D4C1A8DB093003848C4 /* IteratorOperations.h in Headers */, BC18C4130E16F5CD00B34460 /* JavaScript.h in Headers */, + 0F2B9CF519D0BAC100B1D1B5 /* FTLExitPropertyValue.h in Headers */, + A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */, A503FA1A188E0FB000110F14 /* JavaScriptCallFrame.h in Headers */, BC18C4140E16F5CD00B34460 /* JavaScriptCore.h in Headers */, BC18C4150E16F5CD00B34460 /* JavaScriptCorePrefix.h in Headers */, 1429D9300ED22D7000B89619 /* JIT.h in Headers */, + A5EA70E919F5B1010098F5EC /* AlternateDispatchableAgent.h in Headers */, 86CCEFDE0F413F8900FD7F9E /* JITCode.h in Headers */, 0F0776BF14FF002B00102332 /* JITCompilationEffort.h in Headers */, 0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */, @@ -5926,6 +6114,7 @@ 0F766D3115AA8112008F363E /* JITStubRoutine.h in Headers */, 0F766D2C15A8CC3A008F363E /* JITStubRoutineSet.h in Headers */, 14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */, + 0F3B7E2B19A11B8000D9BC56 /* CallVariant.h in Headers */, FEF6835E174343CC00A32E25 /* JITStubsARM.h in Headers */, FEF6835F174343CC00A32E25 /* JITStubsARMv7.h in Headers */, FEF68361174343CC00A32E25 /* JITStubsX86.h in Headers */, @@ -5935,30 +6124,33 @@ 0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */, 0FC712E317CD8793008CC93C /* JITToDFGDeferredCompilationCallback.h in Headers */, A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */, - BC18C4160E16F5CD00B34460 /* JSActivation.h in Headers */, + BC18C4160E16F5CD00B34460 /* JSLexicalEnvironment.h in Headers */, 840480131021A1D9008E7F01 /* JSAPIValueWrapper.h in Headers */, C2CF39C216E15A8100DD69BE /* JSAPIWrapperObject.h in Headers */, - A76140D2182982CB00750624 /* JSArgumentsIterator.h in Headers */, BC18C4170E16F5CD00B34460 /* JSArray.h in Headers */, 0F2B66E317B6B5AB00A7AE3F /* JSArrayBuffer.h in Headers */, - 1CAA9A2318F4A220000A369D /* JSGlobalObjectProfilerAgent.h in Headers */, 0F2B66E517B6B5AB00A7AE3F /* JSArrayBufferConstructor.h in Headers */, 0F2B66E717B6B5AB00A7AE3F /* JSArrayBufferPrototype.h in Headers */, 0F2B66E917B6B5AB00A7AE3F /* JSArrayBufferView.h in Headers */, 0F2B66EA17B6B5AB00A7AE3F /* JSArrayBufferViewInlines.h in Headers */, A7BDAECB17F4EA1400F6140C /* JSArrayIterator.h in Headers */, BC18C4180E16F5CD00B34460 /* JSBase.h in Headers */, + 0F2D4DE919832DAC007D4B19 /* ToThisStatus.h in Headers */, 140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */, 86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */, + 657CF45919BF6662004ACBF2 /* JSCallee.h in Headers */, BC18C4190E16F5CD00B34460 /* JSCallbackConstructor.h in Headers */, BC18C41A0E16F5CD00B34460 /* JSCallbackFunction.h in Headers */, + 0F2B9CF919D0BAC100B1D1B5 /* FTLOperations.h in Headers */, BC18C41B0E16F5CD00B34460 /* JSCallbackObject.h in Headers */, BC18C41C0E16F5CD00B34460 /* JSCallbackObjectFunctions.h in Headers */, A7D801A91880D6A80026C39B /* JSCBuiltins.h in Headers */, BC1167DA0E19BCC9008066DD /* JSCell.h in Headers */, 0F9749711687ADE400A4FF6A /* JSCellInlines.h in Headers */, 0F1DD84A18A945BE0026F3FA /* JSCInlines.h in Headers */, + 0FE0501A1AA9091100D33B33 /* GenericArgumentsInlines.h in Headers */, BC18C42B0E16F5CD00B34460 /* JSCJSValue.h in Headers */, + 0F64B2721A784BAF006E4E66 /* BinarySwitch.h in Headers */, 865A30F1135007E100CDB49E /* JSCJSValueInlines.h in Headers */, BC18C41D0E16F5CD00B34460 /* JSClassRef.h in Headers */, 86E3C613167BABD7006D760A /* JSContext.h in Headers */, @@ -5968,7 +6160,6 @@ A72028B81797601E0098028C /* JSCTestRunnerUtils.h in Headers */, 0F7576D318E1FEE9002EF4CD /* AccessorCallJITStubRoutine.h in Headers */, 0F2B66EC17B6B5AB00A7AE3F /* JSDataView.h in Headers */, - 1CAA9A1F18F4997F000A369D /* InspectorProfilerAgent.h in Headers */, 0F2B66EE17B6B5AB00A7AE3F /* JSDataViewPrototype.h in Headers */, 978801411471AD920041B016 /* JSDateMath.h in Headers */, C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */, @@ -5982,6 +6173,7 @@ 0F2B66F217B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h in Headers */, 0F2B66F317B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructorInlines.h in Headers */, 0F2B66F417B6B5AB00A7AE3F /* JSGenericTypedArrayViewInlines.h in Headers */, + 0F5A1274192D9FDF008764A3 /* DFGDoesGC.h in Headers */, 0F2B66F517B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototype.h in Headers */, 0F2B66F617B6B5AB00A7AE3F /* JSGenericTypedArrayViewPrototypeInlines.h in Headers */, BC18C4210E16F5CD00B34460 /* JSGlobalObject.h in Headers */, @@ -6007,6 +6199,7 @@ A5840E2B187CA75B00843B10 /* jsmin.py in Headers */, 14874AE415EBDE4A002E3587 /* JSNameScope.h in Headers */, BC18C4240E16F5CD00B34460 /* JSObject.h in Headers */, + 709FB86A1AE335C60039D069 /* WeakSetConstructor.h in Headers */, BC18C4250E16F5CD00B34460 /* JSObjectRef.h in Headers */, A7280A2811557E3000D56957 /* JSObjectRefPrivate.h in Headers */, A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */, @@ -6015,9 +6208,7 @@ 7C184E1B17BEDBD3007CB63A /* JSPromise.h in Headers */, 7C184E2317BEE240007CB63A /* JSPromiseConstructor.h in Headers */, 7C008CDB187124BB00955C24 /* JSPromiseDeferred.h in Headers */, - 7C008CD3186F8A9300955C24 /* JSPromiseFunctions.h in Headers */, 7C184E1F17BEE22E007CB63A /* JSPromisePrototype.h in Headers */, - 7C008CDF1871258D00955C24 /* JSPromiseReaction.h in Headers */, 862553D216136E1A009F17D0 /* JSProxy.h in Headers */, 9928FF3C18AC4AEC00B8CF12 /* JSReplayInputs.h in Headers */, BC18C4260E16F5CD00B34460 /* JSRetainPtr.h in Headers */, @@ -6036,28 +6227,35 @@ 1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */, 0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */, BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */, + 0FE050161AA9091100D33B33 /* DirectArgumentsOffset.h in Headers */, 0F2B66FB17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h in Headers */, 0F2B66FD17B6B5AB00A7AE3F /* JSTypedArrayPrototypes.h in Headers */, 0F2B66FF17B6B5AB00A7AE3F /* JSTypedArrays.h in Headers */, 6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */, 0F2B670217B6B5AB00A7AE3F /* JSUint16Array.h in Headers */, 0F2B670317B6B5AB00A7AE3F /* JSUint32Array.h in Headers */, + 0F2D4DF019832DD6007D4B19 /* TypeSet.h in Headers */, 0F2B670017B6B5AB00A7AE3F /* JSUint8Array.h in Headers */, + 0FE0502D1AA9095600D33B33 /* VarOffset.h in Headers */, 0F2B670117B6B5AB00A7AE3F /* JSUint8ClampedArray.h in Headers */, 86E3C612167BABD7006D760A /* JSValue.h in Headers */, 86E3C61B167BABEE006D760A /* JSValueInternal.h in Headers */, + 7013CA8C1B491A9400CAE613 /* JSJob.h in Headers */, BC18C42C0E16F5CD00B34460 /* JSValueRef.h in Headers */, - BC18C42D0E16F5CD00B34460 /* JSVariableObject.h in Headers */, + BC18C42D0E16F5CD00B34460 /* JSEnvironmentRecord.h in Headers */, 86E3C615167BABD7006D760A /* JSVirtualMachine.h in Headers */, 86E3C61D167BABEE006D760A /* JSVirtualMachineInternal.h in Headers */, + 0F2B9CE719D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.h in Headers */, A7CA3AE817DA41AE006538AF /* JSWeakMap.h in Headers */, A7482E93116A7CAD003B0712 /* JSWeakObjectMapRefInternal.h in Headers */, + 0FD949831A97DB9600E28966 /* JSCatchScope.h in Headers */, A7482B9311671147003B0712 /* JSWeakObjectMapRefPrivate.h in Headers */, 1442566215EDE98D0066A49B /* JSWithScope.h in Headers */, 86E3C619167BABEE006D760A /* JSWrapperMap.h in Headers */, BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */, BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */, A72FFD64139985A800E5365A /* KeywordLookup.h in Headers */, + 0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */, 969A072A0ED1CE6900F1F681 /* Label.h in Headers */, 960097A60EBABB58007A7297 /* LabelScope.h in Headers */, 0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */, @@ -6068,8 +6266,12 @@ 0F431738146BAC69007E3890 /* ListableHandler.h in Headers */, A7E2EA6B0FB460CF00601F06 /* LiteralParser.h in Headers */, 0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */, + 0FC3CD0019ADA410006AC72A /* DFGBlockWorklist.h in Headers */, + 0FE050181AA9091100D33B33 /* DirectArguments.h in Headers */, FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */, + 0F04396E1B03DC0B009598B7 /* DFGCombinedLiveness.h in Headers */, 0F4680CA14BBB16C00BFE272 /* LLIntCommon.h in Headers */, + 0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */, 0F4680D314BBD16700BFE272 /* LLIntData.h in Headers */, 0F38B01217CF078300B144D3 /* LLIntEntrypoint.h in Headers */, 0F4680A314BA7F8D00BFE272 /* LLIntExceptions.h in Headers */, @@ -6077,8 +6279,10 @@ FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */, 0F4680A514BA7F8D00BFE272 /* LLIntSlowPaths.h in Headers */, 0F0B839D14BCF46600885B4F /* LLIntThunks.h in Headers */, + 0F0123331944EA1B00843A0C /* DFGValueStrength.h in Headers */, 0FCEFACE1805E75500472CE4 /* LLVMAPI.h in Headers */, 0FCEFACF1805E75500472CE4 /* LLVMAPIFunctions.h in Headers */, + 0FC3CCFE19ADA410006AC72A /* DFGBlockSet.h in Headers */, A7E5AB381799E4B200D2833D /* LLVMDisassembler.h in Headers */, 0FCEFAD31805EDCC00472CE4 /* LLVMHeaders.h in Headers */, 142E3139134FF0A600AFADB5 /* Local.h in Headers */, @@ -6099,7 +6303,8 @@ 0F93B4AA18B92C4D00178A3F /* PutByIdVariant.h in Headers */, A700873A17CBE85300C3E643 /* MapConstructor.h in Headers */, A78507D717CBC6FD0011F6E7 /* MapData.h in Headers */, - A74DEF92182D991400522C22 /* MapIteratorConstructor.h in Headers */, + 0A6441519420A6C61AD1882E /* MapDataInlines.h in Headers */, + FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */, A74DEF94182D991400522C22 /* MapIteratorPrototype.h in Headers */, A700873E17CBE8D300C3E643 /* MapPrototype.h in Headers */, C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */, @@ -6111,18 +6316,17 @@ BC18C43C0E16F5CD00B34460 /* MathObject.h in Headers */, 90213E3E123A40C200D422F3 /* MemoryStatistics.h in Headers */, 0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */, + 0F3D0BBD194A414300FC9CF9 /* ConstantStructureCheck.h in Headers */, 7C008CE7187631B600955C24 /* Microtask.h in Headers */, 86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */, - 86EBF3001560F06A008E9222 /* NameConstructor.h in Headers */, - 86EBF3021560F06A008E9222 /* NameInstance.h in Headers */, - 86EBF3041560F06A008E9222 /* NamePrototype.h in Headers */, BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */, BC02E9130E1839DB000F9297 /* NativeErrorPrototype.h in Headers */, 99CC0B6318BE9950006CEBCC /* CodeGeneratorReplayInputs.py in Headers */, 0FFB922016D033B70055A5DB /* NodeConstructors.h in Headers */, - 7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */, + 70ECA6091AFDBEA200449739 /* TemplateRegistryKey.h in Headers */, BC18C43F0E16F5CD00B34460 /* Nodes.h in Headers */, 99E45A2818A1B2590026D88F /* NondeterministicInput.h in Headers */, + 0FC3CD0219ADA411006AC72A /* DFGNaiveDominators.h in Headers */, BC18C4410E16F5CD00B34460 /* NumberConstructor.h in Headers */, 0F5780A218FE1E98001E72D9 /* PureNaN.h in Headers */, BC18C4420E16F5CD00B34460 /* NumberConstructor.lut.h in Headers */, @@ -6139,7 +6343,9 @@ 969A079B0ED1D3AE00F1F681 /* Opcode.h in Headers */, 0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */, A70447EA17A0BD4600F5898E /* OperandsInlines.h in Headers */, + 0F2D4DDE19832D34007D4B19 /* DebuggerScope.h in Headers */, BC18C4480E16F5CD00B34460 /* Operations.h in Headers */, + 0FE0501B1AA9091100D33B33 /* GenericOffset.h in Headers */, 0FE228ED1436AB2700196C48 /* Options.h in Headers */, BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */, 93052C350FB792190048FDC3 /* ParserArena.h in Headers */, @@ -6148,10 +6354,12 @@ 65303D641447B9E100D3F904 /* ParserTokens.h in Headers */, 0F34B14C16D43E0D001CDA5A /* PolymorphicAccessStructureList.h in Headers */, 0F9FC8C414E1B60000D52AE0 /* PolymorphicPutByIdList.h in Headers */, + 0F8F14341ADF090100ED792C /* DFGEpoch.h in Headers */, 0F98206116BFE38300240D02 /* PreciseJumpTargets.h in Headers */, + 0F2DD8151AB3D8BE00BBB8E8 /* DFGForAllKills.h in Headers */, 868916B0155F286300CB2B9A /* PrivateName.h in Headers */, + A5EA70E719F5B1010098F5EC /* AugmentableInspectorController.h in Headers */, BC18C4500E16F5CD00B34460 /* Profile.h in Headers */, - 0FC97F36182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h in Headers */, 95CD45770E1C4FDD0085358E /* ProfileGenerator.h in Headers */, BC18C4510E16F5CD00B34460 /* ProfileNode.h in Headers */, 0FF729A5166AD351000F5BA3 /* ProfilerBytecode.h in Headers */, @@ -6159,10 +6367,14 @@ 0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */, 0FF729BA166AD360000F5BA3 /* ProfilerCompilation.h in Headers */, 0FF729BB166AD360000F5BA3 /* ProfilerCompilationKind.h in Headers */, + 0F2B9CE319D0BA7D00B1D1B5 /* DFGAvailabilityMap.h in Headers */, 0FF729BC166AD360000F5BA3 /* ProfilerCompiledBytecode.h in Headers */, 0FF729BD166AD360000F5BA3 /* ProfilerDatabase.h in Headers */, + 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */, + 52B311011975B4670080857C /* TypeLocationCache.h in Headers */, 0FF729BE166AD360000F5BA3 /* ProfilerExecutionCounter.h in Headers */, 0F190CAD189D82F6000AE5F0 /* ProfilerJettisonReason.h in Headers */, + 52C952B719A289850069B386 /* TypeProfiler.h in Headers */, 0FF729BF166AD360000F5BA3 /* ProfilerOrigin.h in Headers */, 0FF729C0166AD360000F5BA3 /* ProfilerOriginStack.h in Headers */, 0FB1058C1675483300F8AB6E /* ProfilerOSRExit.h in Headers */, @@ -6176,6 +6388,8 @@ A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */, BC18C4550E16F5CD00B34460 /* PropertySlot.h in Headers */, 0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */, + 0F6FC751196110A800E1D02D /* ComplexGetStatus.h in Headers */, + 0F12DE101979D5FD0006FF4E /* ExceptionFuzz.h in Headers */, BC18C4560E16F5CD00B34460 /* Protect.h in Headers */, 1474C33B16AA2D950062F01D /* PrototypeMap.h in Headers */, 0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */, @@ -6184,23 +6398,27 @@ 147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */, 2AAD964A18569417001F93BE /* RecursiveAllocationScope.h in Headers */, 0FF60AC216740F8300029779 /* ReduceWhitespace.h in Headers */, + 0FD120301A8AED12000F5280 /* FTLJSCallBase.h in Headers */, 0FA7A8EC18B413C80052371D /* Reg.h in Headers */, BC18C45A0E16F5CD00B34460 /* RegExp.h in Headers */, A1712B3F11C7B228007A5315 /* RegExpCache.h in Headers */, + 4340A4851A9051AF00D73CCA /* MathCommon.h in Headers */, BCD202C20E1706A7002C7E82 /* RegExpConstructor.h in Headers */, BCD202D60E170708002C7E82 /* RegExpConstructor.lut.h in Headers */, A1712B4111C7B235007A5315 /* RegExpKey.h in Headers */, BC18C45B0E16F5CD00B34460 /* RegExpObject.h in Headers */, - BC18C52C0E16FCD200B34460 /* RegExpObject.lut.h in Headers */, + 70ECA6061AFDBEA200449739 /* JSTemplateRegistryKey.h in Headers */, BCD202C40E1706A7002C7E82 /* RegExpPrototype.h in Headers */, - C20B25991706536200C21F4E /* Region.h in Headers */, BC18C45D0E16F5CD00B34460 /* Register.h in Headers */, 969A072B0ED1CE6900F1F681 /* RegisterID.h in Headers */, 0F6B1CBA1861244C00845D97 /* RegisterPreservationMode.h in Headers */, 0F6B1CBE1861246A00845D97 /* RegisterPreservationWrapperGenerator.h in Headers */, 0FC314121814559100033232 /* RegisterSet.h in Headers */, + 0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */, A57D23EE1891B5540031C7FA /* RegularExpression.h in Headers */, + 0F682FB319BCB36400FA3BAD /* DFGSSACalculator.h in Headers */, 0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */, + 0F2D4DEA19832DAC007D4B19 /* TypeLocation.h in Headers */, A5BA15E8182340B300A82E69 /* RemoteInspector.h in Headers */, A5BA15EA182340B400A82E69 /* RemoteInspectorConstants.h in Headers */, A5BA15F0182345AF00A82E69 /* RemoteInspectorDebuggable.h in Headers */, @@ -6211,6 +6429,7 @@ 869EBCB70E8C6D4A008722CC /* ResultType.h in Headers */, C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */, 1429D8860ED21C3D00B89619 /* SamplingTool.h in Headers */, + 0FE254F71ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.h in Headers */, 0F24E55217EE274900ABB217 /* ScratchRegisterAllocator.h in Headers */, A5FD0068189AFE9C00633231 /* ScriptArguments.h in Headers */, A503FA21188EFF6800110F14 /* ScriptBreakpoint.h in Headers */, @@ -6224,17 +6443,20 @@ A54CF2FA184EAEDA00237F19 /* ScriptObject.h in Headers */, A54CF2F6184EAB2400237F19 /* ScriptValue.h in Headers */, A7299DA617D12858005F5FF9 /* SetConstructor.h in Headers */, - A790DD6C182F499700588807 /* SetIteratorConstructor.h in Headers */, A790DD6E182F499700588807 /* SetIteratorPrototype.h in Headers */, A7299DA217D12848005F5FF9 /* SetPrototype.h in Headers */, 86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */, + 0FF8BDEB1AD4CF7100DFE884 /* InferredValue.h in Headers */, 0F2B670517B6B5AB00A7AE3F /* SimpleTypedArrayController.h in Headers */, 14BA78F113AAB88F005B7C2C /* SlotVisitor.h in Headers */, + 0FB17661196B8F9E0091052A /* DFGHeapLocation.h in Headers */, C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */, A709F2F017A0AC0400512E98 /* SlowPathCall.h in Headers */, 933040040E6A749400786E6A /* SmallStrings.h in Headers */, BC18C4640E16F5CD00B34460 /* SourceCode.h in Headers */, + 0F6C73511AC9F99F00BE1682 /* VariableWriteFireDetail.h in Headers */, BC18C4630E16F5CD00B34460 /* SourceProvider.h in Headers */, + 70EC0EC31AA0D7DA00B6AAFA /* JSStringIterator.h in Headers */, E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */, E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */, 0FB7F39E15ED8E4600F167B2 /* SparseArrayValueMap.h in Headers */, @@ -6256,11 +6478,15 @@ 0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */, C2FE18A416BAEC4000AF3061 /* StructureRareData.h in Headers */, C20BA92D16BB1C1500B3AEA2 /* StructureRareDataInlines.h in Headers */, + 0F2B9CEB19D0BA7D00B1D1B5 /* DFGPhiChildren.h in Headers */, 0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */, 0F766D3915AE4A1F008F363E /* StructureStubClearingWatchpoint.h in Headers */, BCCF0D080EF0AAB900413C8F /* StructureStubInfo.h in Headers */, BC9041480EB9250900FE26FA /* StructureTransitionTable.h in Headers */, - C2DF44301707AC0100A5CA96 /* SuperRegion.h in Headers */, + 705B41AC1A6E501E00716757 /* Symbol.h in Headers */, + 705B41AE1A6E501E00716757 /* SymbolConstructor.h in Headers */, + 705B41B01A6E501E00716757 /* SymbolObject.h in Headers */, + 705B41B21A6E501E00716757 /* SymbolPrototype.h in Headers */, BC18C46B0E16F5CD00B34460 /* SymbolTable.h in Headers */, A784A26411D16622005776AC /* SyntaxChecker.h in Headers */, 0F24E54F17EE274900ABB217 /* TempRegisterSet.h in Headers */, @@ -6281,8 +6507,11 @@ 0FF42744158EBE91004CB9FF /* udis86_input.h in Headers */, 0FF42748158EBE91004CB9FF /* udis86_syn.h in Headers */, 0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */, + 70B0A9D11A9B66460001306A /* RuntimeFlags.h in Headers */, A7E5AB391799E4B200D2833D /* UDis86Disassembler.h in Headers */, + 0FE0502B1AA9095600D33B33 /* ScopeOffset.h in Headers */, A7A8AF4117ADB5F3005AB174 /* Uint16Array.h in Headers */, + 0FE834181A6EF97B00D04847 /* PolymorphicCallStubRoutine.h in Headers */, 866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */, A7A8AF4217ADB5F3005AB174 /* Uint32Array.h in Headers */, A7A8AF3F17ADB5F3005AB174 /* Uint8Array.h in Headers */, @@ -6292,12 +6521,10 @@ 0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */, 0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */, 0F426A481460CBB300131F8F /* ValueRecovery.h in Headers */, - 0F9181C718415CA50057B669 /* VariableWatchpointSet.h in Headers */, 0F9C5E5F18E35F5E00D431C3 /* FTLDWARFRegister.h in Headers */, 0F426A491460CBB700131F8F /* VirtualRegister.h in Headers */, BC18C4200E16F5CD00B34460 /* VM.h in Headers */, FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */, - FE4A332015BD2E07006F54F3 /* VMInspector.h in Headers */, FED94F2F171E3E2300BE77A4 /* Watchdog.h in Headers */, 0F919D2615853CE3004A4E7D /* Watchpoint.h in Headers */, 142E313C134FF0A600AFADB5 /* Weak.h in Headers */, @@ -6305,6 +6532,7 @@ 14BFCE6910CDB1FC00364CCE /* WeakGCMap.h in Headers */, 14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */, 14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */, + 0F2DD8121AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.h in Headers */, 14BE7D3317135CF400D1807A /* WeakInlines.h in Headers */, A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */, A7CA3AEC17DA5168006538AF /* WeakMapData.h in Headers */, @@ -6320,6 +6548,7 @@ 0FC8150A14043BF500CFA603 /* WriteBarrierSupport.h in Headers */, 9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */, A5840E2A187CA75900843B10 /* xxd.pl in Headers */, + 0F3A1BFA1A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h in Headers */, 451539B912DC994500EF7AC4 /* Yarr.h in Headers */, 86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */, 86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */, @@ -6404,26 +6633,6 @@ productReference = 14BD59BF0A3E8F9000BAF59C /* testapi */; productType = "com.apple.product-type.tool"; }; - 5540756218DA58AD00EFF7F2 /* Compile Runtime to LLVM IR */ = { - isa = PBXNativeTarget; - buildConfigurationList = 55407AC318DA58AD00EFF7F2 /* Build configuration list for PBXNativeTarget "Compile Runtime to LLVM IR" */; - buildPhases = ( - 5540756C18DA58AD00EFF7F2 /* Headers */, - 5540789A18DA58AD00EFF7F2 /* Sources */, - 559CD06A18F487A800F9ADC0 /* Copy LLVM IR */, - ); - buildRules = ( - ); - dependencies = ( - 5540756318DA58AD00EFF7F2 /* PBXTargetDependency */, - 5540756518DA58AD00EFF7F2 /* PBXTargetDependency */, - 5540756718DA58AD00EFF7F2 /* PBXTargetDependency */, - ); - name = "Compile Runtime to LLVM IR"; - productName = JavaScriptCore; - productReference = 55407AC818DA58AD00EFF7F2 /* libCompileRuntimeToLLVMIR.a */; - productType = "com.apple.product-type.library.static"; - }; 651122F714046A4C002B101D /* testRegExp */ = { isa = PBXNativeTarget; buildConfigurationList = 6511230014046A4C002B101D /* Build configuration list for PBXNativeTarget "testRegExp" */; @@ -6455,12 +6664,11 @@ 5D29D8BE0E9860B400C3D2D0 /* Check For Weak VTables and Externals */, 3713F014142905240036387F /* Check For Inappropriate Objective-C Class Names */, A55DEAA416703DF7003DB841 /* Check For Inappropriate Macros in External Headers */, - 55850CA118F4842000F81829 /* Build Symbol Index Table */, + 1A02D9A81B34A882000D1522 /* Add Symlink in /System/Library/PrivateFrameworks */, ); buildRules = ( ); dependencies = ( - 55F8FC2C18EB937B00783E6E /* PBXTargetDependency */, 0FCEFABD1805D66300472CE4 /* PBXTargetDependency */, 65788AAD18B40A7B00C189FF /* PBXTargetDependency */, 65FB3F7E09D11EF300F49DEB /* PBXTargetDependency */, @@ -6496,7 +6704,8 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 0500; + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; }; buildConfigurationList = 149C277108902AFE008A9EFC /* Build configuration list for PBXProject "JavaScriptCore" */; compatibilityVersion = "Xcode 3.2"; @@ -6514,7 +6723,6 @@ projectRoot = ""; targets = ( 932F5BE30822A1C700736975 /* All */, - 5540756218DA58AD00EFF7F2 /* Compile Runtime to LLVM IR */, 932F5B3E0822A1C700736975 /* JavaScriptCore */, 0FCEFAB51805D61600472CE4 /* llvmForJSC */, 0F4680A914BA7FD900BFE272 /* LLInt Offsets */, @@ -6548,15 +6756,13 @@ files = ( ); inputPaths = ( - "$(SRCROOT)/llint/LowLevelAssembler.asm", ); name = "Generate Derived Sources"; outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/LLIntOffsets/LLIntDesiredOffsets.h", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nmkdir -p \"${BUILT_PRODUCTS_DIR}/LLIntOffsets/\"\n\n/usr/bin/env ruby \"${SRCROOT}/offlineasm/generate_offset_extractor.rb\" \"-I${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\" \"${SRCROOT}/llint/LowLevelInterpreter.asm\" \"${BUILT_PRODUCTS_DIR}/LLIntOffsets/LLIntDesiredOffsets.h\"\n"; + shellScript = "set -e\n\nmkdir -p \"${BUILT_PRODUCTS_DIR}/LLIntOffsets/\"\n\n/usr/bin/env ruby \"${SRCROOT}/offlineasm/generate_offset_extractor.rb\" \"-I${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\" \"${SRCROOT}/llint/LowLevelInterpreter.asm\" \"${BUILT_PRODUCTS_DIR}/LLIntOffsets/LLIntDesiredOffsets.h\" \"X86,X86_64,ARMv7,ARMv7s,ARM64,C_LOOP\"\n"; }; 0FCEFAD91806191800472CE4 /* Copy LLVM Library Into Framework */ = { isa = PBXShellScriptBuildPhase; @@ -6573,6 +6779,20 @@ shellPath = /bin/sh; shellScript = "set -e\n\nif [[ $ENABLE_FTL_JIT != \"ENABLE_FTL_JIT\" ]]\nthen\n exit 0\nfi\n\nif [[ ${CONFIGURATION:=Debug} != \"Production\" ]]\nthen\n # Copy the llvmForJSC library into the framework.\n ditto \"${BUILT_PRODUCTS_DIR}/libllvmForJSC.dylib\" \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Libraries/libllvmForJSC.dylib\"\nfi\n\nif [[ $PLATFORM_NAME != \"macosx\" ]]\nthen\n exit 0\nfi\n\nif [ ! -e \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Libraries\" ]\nthen\n ln -fs \"Versions/Current/Libraries\" \"${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/Libraries\"\nfi"; }; + 1A02D9A81B34A882000D1522 /* Add Symlink in /System/Library/PrivateFrameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + name = "Add Symlink in /System/Library/PrivateFrameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "if [[ ${PLATFORM_NAME} != \"iphoneos\" ]]; then\n exit 0\nfi\n\nif [[ ! -d \"${INSTALL_ROOT}/${SYSTEM_LIBRARY_DIR}/PrivateFrameworks\" ]]; then\n mkdir -p \"${INSTALL_ROOT}/${SYSTEM_LIBRARY_DIR}/PrivateFrameworks\"\nfi\n\nln -s -h -f ../Frameworks/JavaScriptCore.framework \"${INSTALL_ROOT}/${SYSTEM_LIBRARY_DIR}/PrivateFrameworks/JavaScriptCore.framework\""; + }; 3713F014142905240036387F /* Check For Inappropriate Objective-C Class Names */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -6608,35 +6828,6 @@ shellPath = /bin/sh; shellScript = "exec ${SRCROOT}/postprocess-headers.sh"; }; - 55850CA118F4842000F81829 /* Build Symbol Index Table */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Build Symbol Index Table"; - outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(JAVASCRIPTCORE_RESOURCES_DIR)/Runtime.symtbl", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "${SRCROOT}/build-symbol-table-index.sh"; - }; - 559CD06A18F487A800F9ADC0 /* Copy LLVM IR */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Copy LLVM IR"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "${SRCROOT}/copy-llvm-ir-to-derived-sources.sh"; - }; 5D29D8BE0E9860B400C3D2D0 /* Check For Weak VTables and Externals */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -6682,7 +6873,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nTRACING_D=\"$SRCROOT/runtime/Tracing.d\";\nTRACING_H=\"$BUILT_PRODUCTS_DIR/DerivedSources/JavaScriptCore/TracingDtrace.h\";\n\nif [[ \"$HAVE_DTRACE\" = \"1\" && \"$TRACING_D\" -nt \"$TRACING_H\" ]];\nthen\n\tdtrace -h -o \"$TRACING_H\" -s \"$TRACING_D\";\nfi;\n"; + shellScript = "set -e\n\nTRACING_D=\"$SRCROOT/runtime/Tracing.d\";\nTRACING_H=\"$BUILT_PRODUCTS_DIR/DerivedSources/JavaScriptCore/TracingDtrace.h\";\n\nif [[ \"$TRACING_D\" -nt \"$TRACING_H\" ]];\nthen\n\tdtrace -h -o \"$TRACING_H\" -s \"$TRACING_D\";\nfi;\n"; }; 5D5D8ABF0E0D0B0300F9C692 /* Create /usr/local/bin/jsc symlink */ = { isa = PBXShellScriptBuildPhase; @@ -6744,7 +6935,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [[ \"${ACTION}\" == \"installhdrs\" ]]; then\n exit 0\nfi\n\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\"\n\n/usr/bin/env ruby JavaScriptCore/offlineasm/asm.rb -I${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore JavaScriptCore/llint/LowLevelInterpreter.asm ${BUILT_PRODUCTS_DIR}/JSCLLIntOffsetsExtractor LLIntAssembly.h || exit 1"; + shellScript = "if [[ \"${ACTION}\" == \"installhdrs\" ]]; then\n exit 0\nfi\n\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\"\n\n/usr/bin/env ruby JavaScriptCore/offlineasm/asm.rb \"-I${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCore\" JavaScriptCore/llint/LowLevelInterpreter.asm \"${BUILT_PRODUCTS_DIR}/JSCLLIntOffsetsExtractor\" LLIntAssembly.h || exit 1"; }; 65FB3F6509D11E9100F49DEB /* Generate Derived Sources */ = { isa = PBXShellScriptBuildPhase; @@ -6812,24 +7003,17 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */, + 65570F5A1AA4C3EA009B3C23 /* Regress141275.mm in Sources */, C29ECB031804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.mm in Sources */, FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */, C20328201981979D0088B499 /* CustomGlobalObjectClassTest.c in Sources */, C288B2DE18A54D3E007BE40B /* DateTests.mm in Sources */, C2181FC218A948FB0025A235 /* JSExportTests.mm in Sources */, + FEF040511AAE662D00BD28B0 /* CompareAndSwapTest.cpp in Sources */, 1440F6100A4F85670005F061 /* testapi.c in Sources */, 86D2221A167EF9440024C804 /* testapi.mm in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 5540789A18DA58AD00EFF7F2 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 554078AB18DA58AD00EFF7F2 /* ArrayConstructor.cpp in Sources */, - 554078AF18DA58AD00EFF7F2 /* ArrayPrototype.cpp in Sources */, - 55407A3818DA58AD00EFF7F2 /* NumberConstructor.cpp in Sources */, - 55407A3A18DA58AD00EFF7F2 /* NumberPrototype.cpp in Sources */, + FE0D4A061AB8DD0A002F54BF /* ExecutionTimeLimitTest.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6845,29 +7029,31 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9EA5C7A2190F088700508EBE /* InitializeLLVMMac.cpp in Sources */, + 9EA5C7A1190F084200508EBE /* BundlePath.mm in Sources */, + 52B310FF1975B4240080857C /* TypeLocationCache.cpp in Sources */, + 9E729408190F021E001A91B5 /* InitializeLLVMPOSIX.cpp in Sources */, + 9E729407190F01A5001A91B5 /* InitializeThreading.cpp in Sources */, 0FFA549716B8835000B3A982 /* A64DOpcode.cpp in Sources */, + 0FE050151AA9091100D33B33 /* DirectArgumentsOffset.cpp in Sources */, 0F55F0F414D1063900AC7649 /* AbstractPC.cpp in Sources */, 147F39BD107EC37600427A48 /* ArgList.cpp in Sources */, - 147F39BE107EC37600427A48 /* Arguments.cpp in Sources */, - A76140CD182982CB00750624 /* ArgumentsIteratorConstructor.cpp in Sources */, - A76140CF182982CB00750624 /* ArgumentsIteratorPrototype.cpp in Sources */, 0F6B1CC918641DF800845D97 /* ArityCheckFailReturnThunks.cpp in Sources */, 0F743BAA16B88249009F9277 /* ARM64Disassembler.cpp in Sources */, 86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */, - A74DE1D0120B875600D40D5B /* ARMv7Assembler.cpp in Sources */, 65C02850171795E200351E35 /* ARMv7Disassembler.cpp in Sources */, 65C0285C1717966800351E35 /* ARMv7DOpcode.cpp in Sources */, 0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */, A7A8AF3417ADB5F3005AB174 /* ArrayBuffer.cpp in Sources */, 0FFC99D4184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp in Sources */, A7A8AF3617ADB5F3005AB174 /* ArrayBufferView.cpp in Sources */, + 0F12DE0F1979D5FD0006FF4E /* ExceptionFuzz.cpp in Sources */, 147F39BF107EC37600427A48 /* ArrayConstructor.cpp in Sources */, - A7BDAEC617F4EA1400F6140C /* ArrayIteratorConstructor.cpp in Sources */, A7BDAEC817F4EA1400F6140C /* ArrayIteratorPrototype.cpp in Sources */, 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */, 147F39C0107EC37600427A48 /* ArrayPrototype.cpp in Sources */, 0F24E54017EA9F5900ABB217 /* AssemblyHelpers.cpp in Sources */, - 14816E1B154CC56C00B8054C /* BlockAllocator.cpp in Sources */, + 0F69CC88193AC60A0045759E /* DFGFrozenValue.cpp in Sources */, 14280863107EC11A0013E7B2 /* BooleanConstructor.cpp in Sources */, 14280864107EC11A0013E7B2 /* BooleanObject.cpp in Sources */, 14280865107EC11A0013E7B2 /* BooleanPrototype.cpp in Sources */, @@ -6879,7 +7065,7 @@ 1429D8DD0ED2205B00B89619 /* CallFrame.cpp in Sources */, 0F0B83B014BCF71600885B4F /* CallLinkInfo.cpp in Sources */, 0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */, - 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */, + 0F2B9CE419D0BA7D00B1D1B5 /* DFGInsertOSRHintsForUpdate.cpp in Sources */, 969A07960ED1D3AE00F1F681 /* CodeBlock.cpp in Sources */, 0F8F94401667633000D61971 /* CodeBlockHash.cpp in Sources */, 0FC97F33182020D7002C9B26 /* CodeBlockJettisoningWatchpoint.cpp in Sources */, @@ -6887,6 +7073,7 @@ A77F1821164088B200640A47 /* CodeCache.cpp in Sources */, 0F8F9446166764F100D61971 /* CodeOrigin.cpp in Sources */, 86B5826714D2796C00A9C306 /* CodeProfile.cpp in Sources */, + 0F6C73501AC9F99F00BE1682 /* VariableWriteFireDetail.cpp in Sources */, 86B5826914D2797000A9C306 /* CodeProfiling.cpp in Sources */, 0F8F943C1667631300D61971 /* CodeSpecializationKind.cpp in Sources */, 0F8F94421667633500D61971 /* CodeType.cpp in Sources */, @@ -6894,6 +7081,8 @@ 0F9C5E5E18E35F5E00D431C3 /* FTLDWARFRegister.cpp in Sources */, A709F2F217A0AC2A00512E98 /* CommonSlowPaths.cpp in Sources */, 6553A33117A1F1EE008CF6F3 /* CommonSlowPathsExceptions.cpp in Sources */, + 0F64B2791A7957B2006E4E66 /* CallEdge.cpp in Sources */, + 0FE254F61ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp in Sources */, A7E5A3A71797432D00E893C0 /* CompilationResult.cpp in Sources */, 147F39C2107EC37600427A48 /* Completion.cpp in Sources */, 146B16D812EB5B59001BEC1B /* ConservativeRoots.cpp in Sources */, @@ -6905,29 +7094,32 @@ 2AACE63C18CA5A0300ED0191 /* GCActivityCallback.cpp in Sources */, C2239D1716262BDD005AC5FD /* CopyVisitor.cpp in Sources */, 0F2B66DE17B6B5AB00A7AE3F /* DataView.cpp in Sources */, + 0F682FB219BCB36400FA3BAD /* DFGSSACalculator.cpp in Sources */, 147F39C3107EC37600427A48 /* DateConstructor.cpp in Sources */, 147F39C4107EC37600427A48 /* DateConversion.cpp in Sources */, 147F39C5107EC37600427A48 /* DateInstance.cpp in Sources */, + 7094C4DE1AE439530041A2EE /* BytecodeIntrinsicRegistry.cpp in Sources */, 147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */, 14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */, - BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */, 149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */, 2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */, 0FC712DE17CD8779008CC93C /* DeferredCompilationCallback.cpp in Sources */, A77A423D17A0BBFD00A8DB81 /* DFGAbstractHeap.cpp in Sources */, 0F55C19417276E4600CEABFD /* DFGAbstractValue.cpp in Sources */, - 0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */, 0F485321187750560083B687 /* DFGArithMode.cpp in Sources */, + 0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */, 0F63948415E48118006A597C /* DFGArrayMode.cpp in Sources */, A7D9A29417A0BC7400EE2618 /* DFGAtTailAbstractState.cpp in Sources */, 0F666EC61835672B00D017F1 /* DFGAvailability.cpp in Sources */, 0F714CA416EA92F000F3EBEB /* DFGBackwardsPropagationPhase.cpp in Sources */, + 0F2B9CEC19D0BA7D00B1D1B5 /* DFGPromotedHeapLocation.cpp in Sources */, A7D89CF217A0B8CC00773AD8 /* DFGBasicBlock.cpp in Sources */, - A70B083217A0B79B00DAF14B /* DFGBinarySwitch.cpp in Sources */, 2A88067819107D5500CB0BBB /* DFGFunctionWhitelist.cpp in Sources */, + 0F2DD8131AB3D8BE00BBB8E8 /* DFGArgumentsUtilities.cpp in Sources */, A7D89CF317A0B8CC00773AD8 /* DFGBlockInsertionSet.cpp in Sources */, 86EC9DC41328DF82002B2AD7 /* DFGByteCodeParser.cpp in Sources */, 0FD82E2114172CE300179C94 /* DFGCapabilities.cpp in Sources */, + 0F2B9CE619D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.cpp in Sources */, 0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */, 0F3B3A271544C995003ED0FF /* DFGCFGSimplificationPhase.cpp in Sources */, A77A423F17A0BBFD00A8DB81 /* DFGClobberize.cpp in Sources */, @@ -6939,10 +7131,10 @@ 0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */, 0FBE0F7216C1DB030082C5E8 /* DFGCPSRethreadingPhase.cpp in Sources */, A7D89CF517A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.cpp in Sources */, + FE384EE71ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp in Sources */, 0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */, 0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */, 0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */, - A73E1330179624CD00E4DEA8 /* DFGDesiredStructureChains.cpp in Sources */, C2C0F7CD17BBFC5B00464FE4 /* DFGDesiredTransitions.cpp in Sources */, 0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */, C2981FD817BAEE4B00A3BC98 /* DFGDesiredWeakReferences.cpp in Sources */, @@ -6950,21 +7142,28 @@ 0FF427641591A1CC004CB9FF /* DFGDisassembler.cpp in Sources */, 0FD81AD2154FB4EE00983E72 /* DFGDominators.cpp in Sources */, 0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */, + 0F2B9CE219D0BA7D00B1D1B5 /* DFGAvailabilityMap.cpp in Sources */, + 0F2B9CE819D0BA7D00B1D1B5 /* DFGObjectMaterializationData.cpp in Sources */, 0FF0F19E16B72A0B005DF95B /* DFGEdge.cpp in Sources */, 0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */, + 0F0123321944EA1B00843A0C /* DFGValueStrength.cpp in Sources */, A78A9774179738B8009DF744 /* DFGFailedFinalizer.cpp in Sources */, A78A9776179738B8009DF744 /* DFGFinalizer.cpp in Sources */, 0F2BDC15151C5D4D00CD8910 /* DFGFixupPhase.cpp in Sources */, + 0FD120331A8C85BD000F5280 /* FTLJSCallVarargs.cpp in Sources */, 0F9D339617FFC4E60073C2BC /* DFGFlushedAt.cpp in Sources */, + 0F9D36941AE9CC33000D4DFB /* DFGCleanUpPhase.cpp in Sources */, A7D89CF717A0B8CC00773AD8 /* DFGFlushFormat.cpp in Sources */, + 0F3A1BF91A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp in Sources */, 86EC9DC71328DF82002B2AD7 /* DFGGraph.cpp in Sources */, 0F2FCCF918A60070001A27F8 /* DFGGraphSafepoint.cpp in Sources */, A704D90517A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp in Sources */, 0F300B7B18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp in Sources */, 0FC97F3D18202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp in Sources */, - A5C3A1A518C0490200C9593A /* JSConsoleClient.cpp in Sources */, + A5C3A1A518C0490200C9593A /* JSGlobalObjectConsoleClient.cpp in Sources */, 0FEA0A33170D40BF00BB722C /* DFGJITCode.cpp in Sources */, 86EC9DCB1328DF82002B2AD7 /* DFGJITCompiler.cpp in Sources */, + 0FE0502A1AA9095600D33B33 /* ScopeOffset.cpp in Sources */, A78A9778179738B8009DF744 /* DFGJITFinalizer.cpp in Sources */, 0FC97F3F18202119002C9B26 /* DFGJumpReplacement.cpp in Sources */, A73A535A1799CD5D00170C19 /* DFGLazyJSValue.cpp in Sources */, @@ -6980,12 +7179,16 @@ A7D89CFD17A0B8CC00773AD8 /* DFGOSRAvailabilityAnalysisPhase.cpp in Sources */, 0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */, 0FD8A32517D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.cpp in Sources */, + FE5068671AE25E280009DAB7 /* DeferredSourceDump.cpp in Sources */, 0FC09791146A6F7100CF2442 /* DFGOSRExit.cpp in Sources */, + 70ECA6071AFDBEA200449739 /* TemplateRegistry.cpp in Sources */, 0F235BEB17178E7300690C7F /* DFGOSRExitBase.cpp in Sources */, 0FC09792146A6F7300CF2442 /* DFGOSRExitCompiler.cpp in Sources */, 0FC09776146943B000CF2442 /* DFGOSRExitCompiler32_64.cpp in Sources */, 0FC0977214693AF900CF2442 /* DFGOSRExitCompiler64.cpp in Sources */, + 70EC0EC21AA0D7DA00B6AAFA /* JSStringIterator.cpp in Sources */, 0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */, + A12BBFF41B044A9800664B69 /* IntlObject.cpp in Sources */, 0FEFC9AA1681A3B300567F53 /* DFGOSRExitJumpPlaceholder.cpp in Sources */, 0F235BED17178E7300690C7F /* DFGOSRExitPreparation.cpp in Sources */, 0FFFC95B14EF90AD00C72532 /* DFGPhase.cpp in Sources */, @@ -6993,32 +7196,39 @@ A78A977A179738B8009DF744 /* DFGPlan.cpp in Sources */, 0FBE0F7416C1DB090082C5E8 /* DFGPredictionInjectionPhase.cpp in Sources */, 0FFFC95D14EF90B300C72532 /* DFGPredictionPropagationPhase.cpp in Sources */, - 0F666ECC1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp in Sources */, 0F2FCCFB18A60070001A27F8 /* DFGSafepoint.cpp in Sources */, 86EC9DD21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp in Sources */, 86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */, 86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */, A7D89CFF17A0B8CC00773AD8 /* DFGSSAConversionPhase.cpp in Sources */, + 2A05ABD51961DF2400341750 /* JSPropertyNameEnumerator.cpp in Sources */, 0FC20CB918556A3500C9E954 /* DFGSSALoweringPhase.cpp in Sources */, + 52B717B51A0597E1007AF4F3 /* ControlFlowProfiler.cpp in Sources */, + 0FC3CD0119ADA411006AC72A /* DFGNaiveDominators.cpp in Sources */, 0F9FB4F417FCB91700CB67F8 /* DFGStackLayoutPhase.cpp in Sources */, 0F4F29DF18B6AD1C0057BC15 /* DFGStaticExecutionCountEstimationPhase.cpp in Sources */, - 2ACCF3DE185FE26B0083E2AD /* DFGStoreBarrierElisionPhase.cpp in Sources */, + 0FE7211D193B9C590031F6ED /* DFGTransition.cpp in Sources */, 0FC20CB51852E2C600C9E954 /* DFGStrengthReductionPhase.cpp in Sources */, 0F2FCCFE18A60070001A27F8 /* DFGThreadData.cpp in Sources */, 0FC097A1146B28CA00CF2442 /* DFGThunks.cpp in Sources */, 0F93B4A918B92C4D00178A3F /* PutByIdVariant.cpp in Sources */, + 709FB8671AE335C60039D069 /* JSWeakSet.cpp in Sources */, 0FD8A32717D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.cpp in Sources */, 0FD8A32917D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.cpp in Sources */, + 0FB17662196B8F9E0091052A /* DFGPureValue.cpp in Sources */, 0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */, 0F63944015C75F1D006A597C /* DFGTypeCheckHoistingPhase.cpp in Sources */, 0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */, 0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */, 0F3B3A2B15475000003ED0FF /* DFGValidate.cpp in Sources */, + 0FB17660196B8F9E0091052A /* DFGHeapLocation.cpp in Sources */, 0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */, 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */, + 0F5874ED194FEB1200AAB2C1 /* DFGMayExit.cpp in Sources */, 0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */, 0F2BDC4A1522809A00CD8910 /* DFGVariableEventStream.cpp in Sources */, 0FFFC95F14EF90BB00C72532 /* DFGVirtualRegisterAllocationPhase.cpp in Sources */, + 0F9E32631B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.cpp in Sources */, 0FC97F4118202119002C9B26 /* DFGWatchpointCollectionPhase.cpp in Sources */, 0FDB2CE7174830A2007B3C1B /* DFGWorklist.cpp in Sources */, 0F9D3370165DBB90005AD387 /* Disassembler.cpp in Sources */, @@ -7034,10 +7244,16 @@ 86CA032E1038E8440028A609 /* Executable.cpp in Sources */, A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */, 86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */, + 0F2DD8111AB3D8BE00BBB8E8 /* DFGArgumentsEliminationPhase.cpp in Sources */, 0F56A1D515001CF4002992B1 /* ExecutionCounter.cpp in Sources */, + 52678F8E1A031009006A306D /* BasicBlockLocation.cpp in Sources */, + 0F2D4DEB19832DC4007D4B19 /* TypeProfilerLog.cpp in Sources */, 0F0332C018ADFAE1005F979A /* ExitingJITType.cpp in Sources */, 0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */, 0FEA0A1C1708B00700BB722C /* FTLAbstractHeap.cpp in Sources */, + 0F978B3B1AAEA71D007C7369 /* ConstantMode.cpp in Sources */, + 0FE050251AA9095600D33B33 /* ClonedArguments.cpp in Sources */, + 0F79085519A290B200F6310C /* DFGStructureRegistrationPhase.cpp in Sources */, 0FEA0A1E1708B00700BB722C /* FTLAbstractHeapRepository.cpp in Sources */, 0F485327187DFDEC0083B687 /* FTLAvailableRecovery.cpp in Sources */, 0FEA0A09170513DB00BB722C /* FTLCapabilities.cpp in Sources */, @@ -7050,11 +7266,15 @@ 0F235BD817178E1C00690C7F /* FTLExitThunkGenerator.cpp in Sources */, 0F235BDA17178E1C00690C7F /* FTLExitValue.cpp in Sources */, A7F2996B17A0BB670010417A /* FTLFail.cpp in Sources */, + 0FE834171A6EF97B00D04847 /* PolymorphicCallStubRoutine.cpp in Sources */, 0FD8A31917D51F2200CA2C40 /* FTLForOSREntryJITCode.cpp in Sources */, 0F25F1AF181635F300522F39 /* FTLInlineCacheSize.cpp in Sources */, 0FEA0A281709623B00BB722C /* FTLIntrinsicRepository.cpp in Sources */, + 0FC3CCFF19ADA410006AC72A /* DFGBlockWorklist.cpp in Sources */, 0FEA0A0D170513DB00BB722C /* FTLJITCode.cpp in Sources */, A78A9780179738D5009DF744 /* FTLJITFinalizer.cpp in Sources */, + 0F2B9CF419D0BAC100B1D1B5 /* FTLExitPropertyValue.cpp in Sources */, + 62F2AA371B0BEDE300610C7A /* DFGLazyNode.cpp in Sources */, 0F6B1CB5185FC9E900845D97 /* FTLJSCall.cpp in Sources */, 0F8F2B95172E04A0007DBDA5 /* FTLLink.cpp in Sources */, 0FCEFADF180738C000472CE4 /* FTLLocation.cpp in Sources */, @@ -7066,7 +7286,6 @@ 0F485329187DFDEC0083B687 /* FTLRecoveryOpcode.cpp in Sources */, 0F6B1CC31862C47800845D97 /* FTLRegisterAtOffset.cpp in Sources */, 0FCEFAAB1804C13E00472CE4 /* FTLSaveRestore.cpp in Sources */, - 1CAA9A2218F4A220000A369D /* JSGlobalObjectProfilerAgent.cpp in Sources */, 0F25F1B1181635F300522F39 /* FTLSlowPathCall.cpp in Sources */, 0F25F1B3181635F300522F39 /* FTLSlowPathCallKey.cpp in Sources */, 0F9D339A1803ADB70073C2BC /* FTLStackMaps.cpp in Sources */, @@ -7074,11 +7293,14 @@ 0F235BE117178E1C00690C7F /* FTLThunks.cpp in Sources */, 0F6B1CC51862C47800845D97 /* FTLUnwindInfo.cpp in Sources */, 0F235BE317178E1C00690C7F /* FTLValueFormat.cpp in Sources */, + 0F5A1273192D9FDF008764A3 /* DFGDoesGC.cpp in Sources */, A53CE08718BC1A5600BEDF76 /* JSConsole.cpp in Sources */, 0F5A6283188C98D40072C9DF /* FTLValueRange.cpp in Sources */, 147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */, 0FF0F19F16B72A17005DF95B /* FunctionExecutableDump.cpp in Sources */, + 52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */, 147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */, + 0F64B2711A784BAF006E4E66 /* BinarySwitch.cpp in Sources */, 0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */, C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */, C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */, @@ -7096,29 +7318,32 @@ C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */, 0F13E04E16164A1F00DC8DE7 /* IndexingType.cpp in Sources */, 0FCEFACA1805E75500472CE4 /* InitializeLLVM.cpp in Sources */, - 0FCEFAB11805CA6D00472CE4 /* InitializeLLVMMac.mm in Sources */, - 0FCEFACB1805E75500472CE4 /* InitializeLLVMPOSIX.cpp in Sources */, - E178636D0D9BEEC300D74E75 /* InitializeThreading.cpp in Sources */, + 527773DE1AAF83AC00BDE7E8 /* RuntimeType.cpp in Sources */, A513E5B7185B8BD3007E95AD /* InjectedScript.cpp in Sources */, + 0FBF158C19B7A53100695DD0 /* DFGBlockSet.cpp in Sources */, A514B2C2185A684400F3C7CB /* InjectedScriptBase.cpp in Sources */, A58E35911860DECF001F24FE /* InjectedScriptHost.cpp in Sources */, A513E5CA185F9624007E95AD /* InjectedScriptManager.cpp in Sources */, A5840E20187B7B8600843B10 /* InjectedScriptModule.cpp in Sources */, 0F24E55517F0B71C00ABB217 /* InlineCallFrameSet.cpp in Sources */, + FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */, A5CEEE14187F3BAD00E55C99 /* InspectorAgent.cpp in Sources */, A593CF86184038CA00BFCE27 /* InspectorAgentRegistry.cpp in Sources */, + 0F2B9CF619D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.cpp in Sources */, A593CF7C1840360300BFCE27 /* InspectorBackendDispatcher.cpp in Sources */, 2AF7382C18BBBF92008A5A37 /* StructureIDTable.cpp in Sources */, A5FD0081189B191A00633231 /* InspectorConsoleAgent.cpp in Sources */, A57D23E51890CEBF0031C7FA /* InspectorDebuggerAgent.cpp in Sources */, - A532438718568335002ED692 /* InspectorJSBackendDispatchers.cpp in Sources */, - A532438918568335002ED692 /* InspectorJSFrontendDispatchers.cpp in Sources */, - A532438B18568335002ED692 /* InspectorJSTypeBuilders.cpp in Sources */, + A532438718568335002ED692 /* InspectorBackendDispatchers.cpp in Sources */, + 709FB8691AE335C60039D069 /* WeakSetConstructor.cpp in Sources */, + A532438918568335002ED692 /* InspectorFrontendDispatchers.cpp in Sources */, + A532438B18568335002ED692 /* InspectorProtocolObjects.cpp in Sources */, A50E4B6118809DD50068A46D /* InspectorRuntimeAgent.cpp in Sources */, A593CF821840377100BFCE27 /* InspectorValues.cpp in Sources */, A78853F917972629001440E4 /* IntendedStructureChain.cpp in Sources */, 147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */, 1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */, + 70113D4B1A8DB093003848C4 /* IteratorOperations.cpp in Sources */, A503FA19188E0FB000110F14 /* JavaScriptCallFrame.cpp in Sources */, 1429D92F0ED22D7000B89619 /* JIT.cpp in Sources */, 86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */, @@ -7137,13 +7362,13 @@ A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */, 0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */, 0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */, + FE4BFF2B1AD476E700088F87 /* FunctionOverrides.cpp in Sources */, 14A23D750F4E1ABB0023CDAD /* JITStubs.cpp in Sources */, 0F5EF91E16878F7A003E5C25 /* JITThunks.cpp in Sources */, 0FC712E217CD8791008CC93C /* JITToDFGDeferredCompilationCallback.cpp in Sources */, - 140B7D1D0DC69AF7009C42B8 /* JSActivation.cpp in Sources */, + 140B7D1D0DC69AF7009C42B8 /* JSLexicalEnvironment.cpp in Sources */, 140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */, C2CF39C116E15A8100DD69BE /* JSAPIWrapperObject.mm in Sources */, - A76140D1182982CB00750624 /* JSArgumentsIterator.cpp in Sources */, 147F39D0107EC37600427A48 /* JSArray.cpp in Sources */, 0F2B66E217B6B5AB00A7AE3F /* JSArrayBuffer.cpp in Sources */, 0F2B66E417B6B5AB00A7AE3F /* JSArrayBufferConstructor.cpp in Sources */, @@ -7151,20 +7376,27 @@ 0F2B66E817B6B5AB00A7AE3F /* JSArrayBufferView.cpp in Sources */, A7BDAECA17F4EA1400F6140C /* JSArrayIterator.cpp in Sources */, 1421359B0A677F4F00A8195E /* JSBase.cpp in Sources */, + 0F898F311B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp in Sources */, 86FA9E91142BBB2E001773B7 /* JSBoundFunction.cpp in Sources */, 1440F8AF0A508D200005F061 /* JSCallbackConstructor.cpp in Sources */, 1440F8920A508B100005F061 /* JSCallbackFunction.cpp in Sources */, 14ABDF600A437FEF00ECCA01 /* JSCallbackObject.cpp in Sources */, A7D801A81880D6A80026C39B /* JSCBuiltins.cpp in Sources */, + 657CF45819BF6662004ACBF2 /* JSCallee.cpp in Sources */, 147F39D1107EC37600427A48 /* JSCell.cpp in Sources */, 147F39D6107EC37600427A48 /* JSCJSValue.cpp in Sources */, 1440FCE40A51E46B0005F061 /* JSClassRef.cpp in Sources */, 86E3C616167BABEE006D760A /* JSContext.mm in Sources */, 14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */, + 70DC3E091B2DF2C700054299 /* IteratorPrototype.cpp in Sources */, + 0FD949821A97DB9600E28966 /* JSCatchScope.cpp in Sources */, A72028B61797601E0098028C /* JSCTestRunnerUtils.cpp in Sources */, 0F2B66EB17B6B5AB00A7AE3F /* JSDataView.cpp in Sources */, 0F2B66ED17B6B5AB00A7AE3F /* JSDataViewPrototype.cpp in Sources */, + 0F2D4DE819832DAC007D4B19 /* ToThisStatus.cpp in Sources */, + FE384EE51ADDB7AD0055DE2C /* JSDollarVM.cpp in Sources */, 978801401471AD920041B016 /* JSDateMath.cpp in Sources */, + 0FE050171AA9091100D33B33 /* DirectArguments.cpp in Sources */, 140566D6107EC271005DBC8D /* JSFunction.cpp in Sources */, 147F39D2107EC37600427A48 /* JSGlobalObject.cpp in Sources */, A5FD0085189B1B7E00633231 /* JSGlobalObjectConsoleAgent.cpp in Sources */, @@ -7180,6 +7412,7 @@ A503FA1B188E0FB000110F14 /* JSJavaScriptCallFrame.cpp in Sources */, A503FA1D188E0FB000110F14 /* JSJavaScriptCallFramePrototype.cpp in Sources */, 14280875107EC13E0013E7B2 /* JSLock.cpp in Sources */, + 0F3D0BBC194A414300FC9CF9 /* ConstantStructureCheck.cpp in Sources */, C25D709B16DE99F400FCA6BC /* JSManagedValue.mm in Sources */, A700874117CBE8EB00C3E643 /* JSMap.cpp in Sources */, A74DEF95182D991400522C22 /* JSMapIterator.cpp in Sources */, @@ -7188,24 +7421,28 @@ 147F39D4107EC37600427A48 /* JSObject.cpp in Sources */, 1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */, A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */, + 0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */, 95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */, 7C184E1A17BEDBD3007CB63A /* JSPromise.cpp in Sources */, 7C184E2217BEE240007CB63A /* JSPromiseConstructor.cpp in Sources */, + A552C37F1ADDB8FE00139726 /* JSRemoteInspector.cpp in Sources */, + 0F893BDB1936E23C001211F4 /* DFGStructureAbstractValue.cpp in Sources */, 7C008CDA187124BB00955C24 /* JSPromiseDeferred.cpp in Sources */, - 7C008CD2186F8A9300955C24 /* JSPromiseFunctions.cpp in Sources */, 7C184E1E17BEE22E007CB63A /* JSPromisePrototype.cpp in Sources */, - 7C008CDE1871258D00955C24 /* JSPromiseReaction.cpp in Sources */, - A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */, + FE1C0FFF1B194FD100B53FCA /* Exception.cpp in Sources */, + 709FB86B1AE335C60039D069 /* WeakSetPrototype.cpp in Sources */, 862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */, 9928FF3B18AC4AEC00B8CF12 /* JSReplayInputs.cpp in Sources */, 14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */, A7C0C4AD1681067E0017011D /* JSScriptRef.cpp in Sources */, 0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */, A7299D9D17D12837005F5FF9 /* JSSet.cpp in Sources */, + 0F20C2591A8013AB00DA3229 /* VirtualRegister.cpp in Sources */, A790DD6F182F499700588807 /* JSSetIterator.cpp in Sources */, 2A83638918D7D0FE0000EBCC /* FullGCActivityCallback.cpp in Sources */, 1428083A107EC0750013E7B2 /* JSStack.cpp in Sources */, 147F39D5107EC37600427A48 /* JSString.cpp in Sources */, + 0FB438A319270B1D00E1FBC9 /* StructureSet.cpp in Sources */, 2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */, 1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */, 146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */, @@ -7213,13 +7450,17 @@ 0F2B66FA17B6B5AB00A7AE3F /* JSTypedArrayConstructors.cpp in Sources */, 0F2B66FC17B6B5AB00A7AE3F /* JSTypedArrayPrototypes.cpp in Sources */, 0F2B66FE17B6B5AB00A7AE3F /* JSTypedArrays.cpp in Sources */, + 0FF054F91AC35B4400E5BE57 /* ExecutableAllocationFuzz.cpp in Sources */, 86E3C61A167BABEE006D760A /* JSValue.mm in Sources */, + 0FF8BDEA1AD4CF7100DFE884 /* InferredValue.cpp in Sources */, + 0F8F14351ADF090100ED792C /* DFGMovHintRemovalPhase.cpp in Sources */, 14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */, - 147F39D7107EC37600427A48 /* JSVariableObject.cpp in Sources */, + 147F39D7107EC37600427A48 /* JSEnvironmentRecord.cpp in Sources */, 86E3C61C167BABEE006D760A /* JSVirtualMachine.mm in Sources */, A7CA3AE717DA41AE006538AF /* JSWeakMap.cpp in Sources */, A7482B9411671147003B0712 /* JSWeakObjectMapRefPrivate.cpp in Sources */, 1442566115EDE98D0066A49B /* JSWithScope.cpp in Sources */, + 0FEE98431A89227500754E93 /* SetupVarargsFrame.cpp in Sources */, 86E3C618167BABEE006D760A /* JSWrapperMap.mm in Sources */, 14280870107EC1340013E7B2 /* JSWrapperObject.cpp in Sources */, BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */, @@ -7231,7 +7472,9 @@ FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */, 0F4680D214BBD16500BFE272 /* LLIntData.cpp in Sources */, 0F38B01117CF078000B144D3 /* LLIntEntrypoint.cpp in Sources */, + 0F392C891B46188400844728 /* DFGOSRExitFuzz.cpp in Sources */, 0F4680A814BA7FAB00BFE272 /* LLIntExceptions.cpp in Sources */, + 0FD949841A97DB9600E28966 /* JSFunctionNameScope.cpp in Sources */, 0F4680A414BA7F8D00BFE272 /* LLIntSlowPaths.cpp in Sources */, 0F0B839C14BCF46300885B4F /* LLIntThunks.cpp in Sources */, 0FCEFACD1805E75500472CE4 /* LLVMAPI.cpp in Sources */, @@ -7247,8 +7490,6 @@ A7A4AE0817973B26005612B1 /* MacroAssemblerX86Common.cpp in Sources */, A5B6A74D18C6DBA600F11E91 /* ConsoleClient.cpp in Sources */, A700873917CBE85300C3E643 /* MapConstructor.cpp in Sources */, - A78507D617CBC6FD0011F6E7 /* MapData.cpp in Sources */, - A74DEF91182D991400522C22 /* MapIteratorConstructor.cpp in Sources */, A74DEF93182D991400522C22 /* MapIteratorPrototype.cpp in Sources */, A700873D17CBE8D300C3E643 /* MapPrototype.cpp in Sources */, C2B916C514DA040C00CBAC86 /* MarkedAllocator.cpp in Sources */, @@ -7258,13 +7499,13 @@ 14469DDF107EC7E700650446 /* MathObject.cpp in Sources */, 90213E3D123A40C200D422F3 /* MemoryStatistics.cpp in Sources */, 0FB5467D14F5CFD6002C2989 /* MethodOfGettingAValueProfile.cpp in Sources */, - 86EBF2FF1560F06A008E9222 /* NameConstructor.cpp in Sources */, - 86EBF3011560F06A008E9222 /* NameInstance.cpp in Sources */, - 86EBF3031560F06A008E9222 /* NamePrototype.cpp in Sources */, 14469DE0107EC7E700650446 /* NativeErrorConstructor.cpp in Sources */, 14469DE1107EC7E700650446 /* NativeErrorPrototype.cpp in Sources */, 148F21B7107EC5470042EC2C /* Nodes.cpp in Sources */, 655EB29B10CE2581001A990E /* NodesCodegen.cpp in Sources */, + 6546F5211A32B313006F07D5 /* NullGetterFunction.cpp in Sources */, + 65525FC51A6DD801007B5495 /* NullSetterFunction.cpp in Sources */, + 0F1725FF1B48719A00AC3A55 /* DFGMinifiedGraph.cpp in Sources */, 14469DE2107EC7E700650446 /* NumberConstructor.cpp in Sources */, 14469DE3107EC7E700650446 /* NumberObject.cpp in Sources */, 14469DE4107EC7E700650446 /* NumberPrototype.cpp in Sources */, @@ -7273,6 +7514,7 @@ 14469DE6107EC7E700650446 /* ObjectPrototype.cpp in Sources */, E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */, 969A079A0ED1D3AE00F1F681 /* Opcode.cpp in Sources */, + 0FED67B91B26256D0066CE15 /* DFGConstantHoistingPhase.cpp in Sources */, 14280850107EC0D70013E7B2 /* Operations.cpp in Sources */, 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */, 148F21BC107EC54D0042EC2C /* Parser.cpp in Sources */, @@ -7280,14 +7522,14 @@ 0F9FC8C314E1B5FE00D52AE0 /* PolymorphicPutByIdList.cpp in Sources */, 0F98206016BFE38100240D02 /* PreciseJumpTargets.cpp in Sources */, 95742F650DD11F5A000917FB /* Profile.cpp in Sources */, - 0FC97F35182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.cpp in Sources */, + 0F2B9CF819D0BAC100B1D1B5 /* FTLOperations.cpp in Sources */, 95CD45760E1C4FDD0085358E /* ProfileGenerator.cpp in Sources */, 95AB83560DA43C3000BC83F3 /* ProfileNode.cpp in Sources */, 0FF729AD166AD35C000F5BA3 /* ProfilerBytecode.cpp in Sources */, 0FF729AE166AD35C000F5BA3 /* ProfilerBytecodes.cpp in Sources */, + 0F6237971AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp in Sources */, 0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */, 0FF729AF166AD35C000F5BA3 /* ProfilerCompilation.cpp in Sources */, - 1CAA9A1E18F4997F000A369D /* InspectorProfilerAgent.cpp in Sources */, 0FF729B0166AD35C000F5BA3 /* ProfilerCompilationKind.cpp in Sources */, 0FF729B1166AD35C000F5BA3 /* ProfilerCompiledBytecode.cpp in Sources */, 0FF729B2166AD35C000F5BA3 /* ProfilerDatabase.cpp in Sources */, @@ -7297,17 +7539,19 @@ 0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */, 0FB1058D1675483700F8AB6E /* ProfilerOSRExitSite.cpp in Sources */, 0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */, + 70ECA6051AFDBEA200449739 /* JSTemplateRegistryKey.cpp in Sources */, A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */, - 14469DE7107EC7E700650446 /* PropertyNameArray.cpp in Sources */, 14469DE8107EC7E700650446 /* PropertySlot.cpp in Sources */, ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */, 65FB5117184EEE7000C12B70 /* ProtoCallFrame.cpp in Sources */, 1474C33C16AA2D9B0062F01D /* PrototypeMap.cpp in Sources */, 0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */, + 0F3E01AA19D353A500F61B7F /* DFGPrePostNumbering.cpp in Sources */, 0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */, 0FA7A8EB18B413C80052371D /* Reg.cpp in Sources */, 14280841107EC0930013E7B2 /* RegExp.cpp in Sources */, A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */, + 0FE0502C1AA9095600D33B33 /* VarOffset.cpp in Sources */, 8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */, 14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */, 8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */, @@ -7322,10 +7566,13 @@ A5BA15EC182340B400A82E69 /* RemoteInspectorDebuggableConnection.mm in Sources */, A5BA15EE182340B400A82E69 /* RemoteInspectorXPCConnection.mm in Sources */, 0F24E55017EE274900ABB217 /* Repatch.cpp in Sources */, + 62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */, 0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */, 1429D8850ED21C3D00B89619 /* SamplingTool.cpp in Sources */, + 70EC0EC61AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp in Sources */, A5FD0067189AFE9C00633231 /* ScriptArguments.cpp in Sources */, A5FD006D189B00AA00633231 /* ScriptCallFrame.cpp in Sources */, + 0F04396D1B03DC0B009598B7 /* DFGCombinedLiveness.cpp in Sources */, A5FD006F189B00AA00633231 /* ScriptCallStack.cpp in Sources */, A5FD007D189B0B4C00633231 /* ScriptCallStackFactory.cpp in Sources */, A503FA25188EFFFD00110F14 /* ScriptDebugServer.cpp in Sources */, @@ -7333,7 +7580,8 @@ A54CF2F9184EAEDA00237F19 /* ScriptObject.cpp in Sources */, A54CF2F5184EAB2400237F19 /* ScriptValue.cpp in Sources */, A7299DA517D12858005F5FF9 /* SetConstructor.cpp in Sources */, - A790DD6B182F499700588807 /* SetIteratorConstructor.cpp in Sources */, + 0FD1202F1A8AED12000F5280 /* FTLJSCallBase.cpp in Sources */, + 0F952ABC1B487A7700C367C5 /* TrackedReferences.cpp in Sources */, A790DD6D182F499700588807 /* SetIteratorPrototype.cpp in Sources */, A7299DA117D12848005F5FF9 /* SetPrototype.cpp in Sources */, 0F2B670417B6B5AB00A7AE3F /* SimpleTypedArrayController.cpp in Sources */, @@ -7349,20 +7597,27 @@ A730B6131250068F009D25B1 /* StrictEvalActivation.cpp in Sources */, 14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */, 14469DEC107EC7E700650446 /* StringObject.cpp in Sources */, + 0F8F14331ADF090100ED792C /* DFGEpoch.cpp in Sources */, 14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */, + 0F2D4DEF19832DD3007D4B19 /* TypeSet.cpp in Sources */, 9335F24D12E6765B002B5553 /* StringRecursionChecker.cpp in Sources */, BCDE3B430E6C832D001453A7 /* Structure.cpp in Sources */, 7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */, C2F0F2D116BAEEE900187C19 /* StructureRareData.cpp in Sources */, + 7013CA8B1B491A9400CAE613 /* JSJob.cpp in Sources */, 0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */, BCCF0D0C0EF0B8A500413C8F /* StructureStubInfo.cpp in Sources */, - C2DF442F1707AC0100A5CA96 /* SuperRegion.cpp in Sources */, + 705B41AB1A6E501E00716757 /* Symbol.cpp in Sources */, + 705B41AD1A6E501E00716757 /* SymbolConstructor.cpp in Sources */, + 705B41AF1A6E501E00716757 /* SymbolObject.cpp in Sources */, + 705B41B11A6E501E00716757 /* SymbolPrototype.cpp in Sources */, 0F919D2815856773004A4E7D /* SymbolTable.cpp in Sources */, 0FC314131814559100033232 /* TempRegisterSet.cpp in Sources */, 0FA2C17B17D7CF84009D015F /* TestRunnerUtils.cpp in Sources */, A7386555118697B400540279 /* ThunkGenerators.cpp in Sources */, 0F2B670717B6B5AB00A7AE3F /* TypedArrayController.cpp in Sources */, 0F2B670A17B6B5AB00A7AE3F /* TypedArrayType.cpp in Sources */, + 52C952B919A28A1C0069B386 /* TypeProfiler.cpp in Sources */, 0FF4274A158EBE91004CB9FF /* udis86.c in Sources */, 0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */, 0FF42743158EBE91004CB9FF /* udis86_input.c in Sources */, @@ -7370,6 +7625,7 @@ 0FF42745158EBE91004CB9FF /* udis86_syn-att.c in Sources */, 0FF42746158EBE91004CB9FF /* udis86_syn-intel.c in Sources */, 0FF42747158EBE91004CB9FF /* udis86_syn.c in Sources */, + 0F2B9CEA19D0BA7D00B1D1B5 /* DFGPhiChildren.cpp in Sources */, 0FF42732158EBD58004CB9FF /* UDis86Disassembler.cpp in Sources */, A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */, B59F89391891F29F00D5CCDC /* UnlinkedInstructionStream.cpp in Sources */, @@ -7377,21 +7633,25 @@ 0F24E55817F74EDB00ABB217 /* ValueRecovery.cpp in Sources */, E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */, FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */, - FE4A331F15BD2E07006F54F3 /* VMInspector.cpp in Sources */, FED94F2E171E3E2300BE77A4 /* Watchdog.cpp in Sources */, FED94F30171E3E2300BE77A4 /* WatchdogMac.cpp in Sources */, 0F919D2515853CE0004A4E7D /* Watchpoint.cpp in Sources */, 1ACF7377171CA6FB00C9BB1E /* Weak.cpp in Sources */, + 0F6FC750196110A800E1D02D /* ComplexGetStatus.cpp in Sources */, 14E84F9E14EE1ACC00D6D5D4 /* WeakBlock.cpp in Sources */, 14F7256514EE265E00B1652B /* WeakHandleOwner.cpp in Sources */, A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */, A7CA3AEB17DA5168006538AF /* WeakMapData.cpp in Sources */, + 4340A4841A9051AF00D73CCA /* MathCommon.cpp in Sources */, A7CA3AE517DA41AE006538AF /* WeakMapPrototype.cpp in Sources */, 14E84FA014EE1ACC00D6D5D4 /* WeakSet.cpp in Sources */, 2A4EC90B1860D6C20094F782 /* WriteBarrierBuffer.cpp in Sources */, 0FC8150B14043C0E00CFA603 /* WriteBarrierSupport.cpp in Sources */, + 0FE050271AA9095600D33B33 /* ScopedArguments.cpp in Sources */, + 0F3B7E2A19A11B8000D9BC56 /* CallVariant.cpp in Sources */, A7E5AB3A1799E4B200D2833D /* X86Disassembler.cpp in Sources */, 863C6D9C1521111A00585E4E /* YarrCanonicalizeUCS2.cpp in Sources */, + 0FE0502F1AAA806900D33B33 /* ScopedArgumentsTable.cpp in Sources */, 86704B8412DBA33700A9FE7B /* YarrInterpreter.cpp in Sources */, 86704B8612DBA33700A9FE7B /* YarrJIT.cpp in Sources */, 86704B8912DBA33700A9FE7B /* YarrPattern.cpp in Sources */, @@ -7420,26 +7680,6 @@ target = 0F4680A914BA7FD900BFE272 /* LLInt Offsets */; targetProxy = 0FF922D214F46B2F0041A24E /* PBXContainerItemProxy */; }; - 5540756318DA58AD00EFF7F2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0FCEFAB51805D61600472CE4 /* llvmForJSC */; - targetProxy = 5540756418DA58AD00EFF7F2 /* PBXContainerItemProxy */; - }; - 5540756518DA58AD00EFF7F2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 65788A9D18B409EB00C189FF /* Offline Assembler */; - targetProxy = 5540756618DA58AD00EFF7F2 /* PBXContainerItemProxy */; - }; - 5540756718DA58AD00EFF7F2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 65FB3F6609D11E9100F49DEB /* Derived Sources */; - targetProxy = 5540756818DA58AD00EFF7F2 /* PBXContainerItemProxy */; - }; - 55F8FC2C18EB937B00783E6E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 5540756218DA58AD00EFF7F2 /* Compile Runtime to LLVM IR */; - targetProxy = 55F8FC2B18EB937B00783E6E /* PBXContainerItemProxy */; - }; 5D69E912152BE5470028D720 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 932F5BDA0822A1C700736975 /* jsc */; @@ -7612,7 +7852,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */; buildSettings = { - INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)"; }; name = Debug; }; @@ -7620,7 +7859,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */; buildSettings = { - INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)"; }; name = Release; }; @@ -7721,34 +7959,6 @@ }; name = Production; }; - 55407AC418DA58AD00EFF7F2 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5540758418F4A37500602A5D /* CompileRuntimeToLLVMIR.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 55407AC518DA58AD00EFF7F2 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5540758418F4A37500602A5D /* CompileRuntimeToLLVMIR.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 55407AC618DA58AD00EFF7F2 /* Profiling */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5540758418F4A37500602A5D /* CompileRuntimeToLLVMIR.xcconfig */; - buildSettings = { - }; - name = Profiling; - }; - 55407AC718DA58AD00EFF7F2 /* Production */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5540758418F4A37500602A5D /* CompileRuntimeToLLVMIR.xcconfig */; - buildSettings = { - }; - name = Production; - }; 5D6B2A48152B9E17005231DE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -7884,7 +8094,6 @@ isa = XCBuildConfiguration; baseConfigurationReference = 1C9051430BA9E8A70081E9D0 /* JavaScriptCore.xcconfig */; buildSettings = { - INSTALL_PATH = "$(BUILT_PRODUCTS_DIR)"; }; name = Profiling; }; @@ -8019,17 +8228,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Production; }; - 55407AC318DA58AD00EFF7F2 /* Build configuration list for PBXNativeTarget "Compile Runtime to LLVM IR" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 55407AC418DA58AD00EFF7F2 /* Debug */, - 55407AC518DA58AD00EFF7F2 /* Release */, - 55407AC618DA58AD00EFF7F2 /* Profiling */, - 55407AC718DA58AD00EFF7F2 /* Production */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Production; - }; 5D6B2A4C152B9E17005231DE /* Build configuration list for PBXAggregateTarget "Test Tools" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/KeywordLookupGenerator.py b/KeywordLookupGenerator.py index 17bcc2d..d13daba 100644 --- a/KeywordLookupGenerator.py +++ b/KeywordLookupGenerator.py @@ -141,7 +141,7 @@ class Trie: str = makePadding(indent) if self.value != None: - print(str + "if (!isIdentPart(code[%d])) {" % (len(self.fullPrefix))) + print(str + "if (!isIdentPartIncludingEscape(code+%d, m_codeEnd)) {" % (len(self.fullPrefix))) print(str + " internalShift<%d>();" % len(self.fullPrefix)) print(str + " if (shouldCreateIdentifier)") print(str + (" data->ident = &m_vm->propertyNames->%sKeyword;" % self.fullPrefix)) @@ -184,8 +184,8 @@ class Trie: def printAsC(self): print("namespace JSC {") print("") - print("static ALWAYS_INLINE bool isIdentPart(LChar c);") - print("static ALWAYS_INLINE bool isIdentPart(UChar c);") + print("static ALWAYS_INLINE bool isIdentPartIncludingEscape(const LChar* code, const LChar* codeEnd);") + print("static ALWAYS_INLINE bool isIdentPartIncludingEscape(const UChar* code, const UChar* codeEnd);") # max length + 1 so we don't need to do any bounds checking at all print("static const int maxTokenLength = %d;" % (self.maxLength() + 1)) print("") diff --git a/PlatformEfl.cmake b/PlatformEfl.cmake index 978c37f..6cc8c0e 100644 --- a/PlatformEfl.cmake +++ b/PlatformEfl.cmake @@ -3,3 +3,14 @@ list(APPEND JavaScriptCore_INCLUDE_DIRECTORIES ${EINA_INCLUDE_DIRS} ${EO_INCLUDE_DIRS} ) +add_definitions(-DSTATICALLY_LINKED_WITH_WTF) + +install(FILES API/JavaScript.h + API/JSBase.h + API/JSContextRef.h + API/JSObjectRef.h + API/JSStringRef.h + API/JSValueRef.h + API/WebKitAvailability.h + DESTINATION "${HEADER_INSTALL_DIR}/JavaScriptCore" +) diff --git a/PlatformGTK.cmake b/PlatformGTK.cmake index be016ec..6f94a29 100644 --- a/PlatformGTK.cmake +++ b/PlatformGTK.cmake @@ -1,3 +1,5 @@ +set(JavaScriptCore_OUTPUT_NAME javascriptcoregtk-${WEBKITGTK_API_VERSION}) + configure_file(javascriptcoregtk.pc.in ${CMAKE_BINARY_DIR}/Source/JavaScriptCore/javascriptcoregtk-${WEBKITGTK_API_VERSION}.pc @ONLY) configure_file(JavaScriptCore.gir.in ${CMAKE_BINARY_DIR}/JavaScriptCore-${WEBKITGTK_API_VERSION}.gir @ONLY) @@ -23,9 +25,20 @@ install(FILES API/JavaScript.h DESTINATION "${WEBKITGTK_HEADER_INSTALL_DIR}/JavaScriptCore" ) -install(FILES ${CMAKE_BINARY_DIR}/JavaScriptCore-${WEBKITGTK_API_VERSION}.gir - DESTINATION ${INTROSPECTION_INSTALL_GIRDIR} +if (ENABLE_INTROSPECTION) + install(FILES ${CMAKE_BINARY_DIR}/JavaScriptCore-${WEBKITGTK_API_VERSION}.gir + DESTINATION ${INTROSPECTION_INSTALL_GIRDIR} + ) + install(FILES ${CMAKE_BINARY_DIR}/JavaScriptCore-${WEBKITGTK_API_VERSION}.typelib + DESTINATION ${INTROSPECTION_INSTALL_TYPELIBDIR} + ) +endif () + +add_definitions(-DSTATICALLY_LINKED_WITH_WTF) + +list(APPEND JavaScriptCore_LIBRARIES + ${GLIB_LIBRARIES} ) -install(FILES ${CMAKE_BINARY_DIR}/JavaScriptCore-${WEBKITGTK_API_VERSION}.typelib - DESTINATION ${INTROSPECTION_INSTALL_TYPELIBDIR} +list(APPEND JavaScriptCore_SYSTEM_INCLUDE_DIRECTORIES + ${GLIB_INCLUDE_DIRS} ) diff --git a/PlatformMac.cmake b/PlatformMac.cmake new file mode 100644 index 0000000..b747df7 --- /dev/null +++ b/PlatformMac.cmake @@ -0,0 +1,41 @@ +find_library(COCOA_LIBRARY Cocoa) +find_library(COREFOUNDATION_LIBRARY CoreFoundation) +find_library(READLINE_LIBRARY Readline) +list(APPEND JavaScriptCore_LIBRARIES + ${COREFOUNDATION_LIBRARY} + ${COCOA_LIBRARY} + ${READLINE_LIBRARY} + libicucore.dylib +) + +list(APPEND JavaScriptCore_SOURCES + API/JSAPIWrapperObject.mm + API/JSContext.mm + API/JSManagedValue.mm + API/JSStringRefCF.cpp + API/JSValue.mm + API/JSVirtualMachine.mm + API/JSWrapperMap.mm + API/ObjCCallbackFunction.mm + + inspector/remote/RemoteInspector.mm + inspector/remote/RemoteInspectorDebuggable.cpp + inspector/remote/RemoteInspectorDebuggableConnection.mm + inspector/remote/RemoteInspectorXPCConnection.mm +) +add_definitions(-DSTATICALLY_LINKED_WITH_WTF) + +add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/TracingDtrace.h + DEPENDS ${JAVASCRIPTCORE_DIR}/runtime/Tracing.d + WORKING_DIRECTORY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR} + COMMAND dtrace -h -o "${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/TracingDtrace.h" -s "${JAVASCRIPTCORE_DIR}/runtime/Tracing.d"; + VERBATIM) + +list(APPEND JavaScriptCore_INCLUDE_DIRECTORIES + ${JAVASCRIPTCORE_DIR}/disassembler/udis86 + ${JAVASCRIPTCORE_DIR}/icu +) +list(APPEND JavaScriptCore_HEADERS + ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/TracingDtrace.h +) diff --git a/PlatformWin.cmake b/PlatformWin.cmake new file mode 100644 index 0000000..9575a16 --- /dev/null +++ b/PlatformWin.cmake @@ -0,0 +1,29 @@ +list(APPEND JavaScriptCore_SOURCES + API/JSStringRefBSTR.cpp + API/JSStringRefCF.cpp +) + +if (WTF_PLATFORM_WIN_CAIRO) + list(APPEND JavaScriptCore_LIBRARIES + CFLite + ) +else () + list(APPEND JavaScriptCore_LIBRARIES + CoreFoundation + ) +endif () + +if (MSVC AND "${JavaScriptCore_LIBRARY_TYPE}" MATCHES "SHARED") + get_property(WTF_LIBRARY_LOCATION TARGET WTF PROPERTY LOCATION) + + add_custom_command( + OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/forwarded-exports.cpp + DEPENDS WTF + COMMAND ${PYTHON_EXECUTABLE} ${TOOLS_DIR}/Scripts/generate-win32-export-forwards ${WTF_LIBRARY_LOCATION} ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/forwarded-exports.cpp + VERBATIM) + list(APPEND JavaScriptCore_SOURCES ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/forwarded-exports.cpp) +endif () + +list(REMOVE_ITEM JavaScriptCore_SOURCES + inspector/JSGlobalObjectInspectorController.cpp +) diff --git a/UpdateContents.py b/UpdateContents.py new file mode 100644 index 0000000..52f9532 --- /dev/null +++ b/UpdateContents.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# Copyright (C) 2015 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. +# 3. Neither the name of Apple puter, Inc. ("Apple") nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import sys +import os + +assert(len(sys.argv) == 3) + +comp = sys.argv[1] +filename = sys.argv[2] + +t = False + +if os.path.isfile(filename): + f = open(filename, 'r') + comparator = f.read() + f.close() + t = True + +if (not t or comp != comparator): + f = open(filename, 'w') + f.write(comp) + f.close() diff --git a/assembler/ARM64Assembler.h b/assembler/ARM64Assembler.h index d511814..68f3ed0 100644 --- a/assembler/ARM64Assembler.h +++ b/assembler/ARM64Assembler.h @@ -624,9 +624,9 @@ public: JumpType m_type : 8; JumpLinkType m_linkType : 8; Condition m_condition : 4; - bool m_is64Bit : 1; unsigned m_bitNumber : 6; - RegisterID m_compareRegister : 5; + RegisterID m_compareRegister : 6; + bool m_is64Bit : 1; } realTypes; struct CopyTypes { uint64_t content[3]; @@ -947,6 +947,7 @@ public: { ASSERT(!(offset & 0xfff)); insn(pcRelative(true, offset >> 12, rd)); + nopCortexA53Fix843419(); } template<int datasize, SetFlags setFlags = DontSetFlags> @@ -1568,6 +1569,7 @@ public: ALWAYS_INLINE void madd(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra) { CHECK_DATASIZE(); + nopCortexA53Fix835769<datasize>(); insn(dataProcessing3Source(DATASIZE, DataOp_MADD, rm, ra, rn, rd)); } @@ -1620,6 +1622,7 @@ public: ALWAYS_INLINE void msub(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra) { CHECK_DATASIZE(); + nopCortexA53Fix835769<datasize>(); insn(dataProcessing3Source(DATASIZE, DataOp_MSUB, rm, ra, rn, rd)); } @@ -1806,6 +1809,7 @@ public: ALWAYS_INLINE void smaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra) { + nopCortexA53Fix835769<64>(); insn(dataProcessing3Source(Datasize_64, DataOp_SMADDL, rm, ra, rn, rd)); } @@ -1816,6 +1820,7 @@ public: ALWAYS_INLINE void smsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra) { + nopCortexA53Fix835769<64>(); insn(dataProcessing3Source(Datasize_64, DataOp_SMSUBL, rm, ra, rn, rd)); } @@ -1958,7 +1963,13 @@ public: template<int datasize, SetFlags setFlags = DontSetFlags> ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm) { - sub<datasize, setFlags>(rd, rn, rm, LSL, 0); + ASSERT_WITH_MESSAGE(!isSp(rd) || setFlags == DontSetFlags, "SUBS with shifted register does not support SP for Xd, it uses XZR for the register 31. SUBS with extended register support SP for Xd, but only if SetFlag is not used, otherwise register 31 is Xd."); + ASSERT_WITH_MESSAGE(!isSp(rm), "No encoding of SUBS supports SP for the third operand."); + + if (isSp(rd) || isSp(rn)) + sub<datasize, setFlags>(rd, rn, rm, UXTX, 0); + else + sub<datasize, setFlags>(rd, rn, rm, LSL, 0); } template<int datasize, SetFlags setFlags = DontSetFlags> @@ -1972,12 +1983,8 @@ public: ALWAYS_INLINE void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftType shift, int amount) { CHECK_DATASIZE(); - if (isSp(rd) || isSp(rn)) { - ASSERT(shift == LSL); - ASSERT(!isSp(rm)); - sub<datasize, setFlags>(rd, rn, rm, UXTX, amount); - } else - insn(addSubtractShiftedRegister(DATASIZE, AddOp_SUB, setFlags, shift, rm, amount, rn, rd)); + ASSERT(!isSp(rd) && !isSp(rn) && !isSp(rm)); + insn(addSubtractShiftedRegister(DATASIZE, AddOp_SUB, setFlags, shift, rm, amount, rn, rd)); } template<int datasize> @@ -2057,6 +2064,7 @@ public: ALWAYS_INLINE void umaddl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra) { + nopCortexA53Fix835769<64>(); insn(dataProcessing3Source(Datasize_64, DataOp_UMADDL, rm, ra, rn, rd)); } @@ -2067,6 +2075,7 @@ public: ALWAYS_INLINE void umsubl(RegisterID rd, RegisterID rn, RegisterID rm, RegisterID ra) { + nopCortexA53Fix835769<64>(); insn(dataProcessing3Source(Datasize_64, DataOp_UMSUBL, rm, ra, rn, rd)); } @@ -3229,7 +3238,7 @@ private: int insn = *static_cast<int*>(address); op = (insn >> 24) & 0x1; imm14 = (insn << 13) >> 18; - bitNumber = static_cast<unsigned>((((insn >> 26) & 0x20)) | ((insn > 19) & 0x1f)); + bitNumber = static_cast<unsigned>((((insn >> 26) & 0x20)) | ((insn >> 19) & 0x1f)); rt = static_cast<RegisterID>(insn & 0x1f); return (insn & 0x7e000000) == 0x36000000; @@ -3627,6 +3636,37 @@ private: return (0xd6000000 | opc << 21 | op2 << 16 | op3 << 10 | xOrZr(rn) << 5 | op4); } + // Workaround for Cortex-A53 erratum (835769). Emit an extra nop if the + // last instruction in the buffer is a load, store or prefetch. Needed + // before 64-bit multiply-accumulate instructions. + template<int datasize> + ALWAYS_INLINE void nopCortexA53Fix835769() + { +#if CPU(ARM64_CORTEXA53) + CHECK_DATASIZE(); + if (datasize == 64) { + if (LIKELY(m_buffer.codeSize() >= sizeof(int32_t))) { + // From ARMv8 Reference Manual, Section C4.1: the encoding of the + // instructions in the Loads and stores instruction group is: + // ---- 1-0- ---- ---- ---- ---- ---- ---- + if (UNLIKELY((*reinterpret_cast_ptr<int32_t*>(reinterpret_cast_ptr<char*>(m_buffer.data()) + m_buffer.codeSize() - sizeof(int32_t)) & 0x0a000000) == 0x08000000)) + nop(); + } + } +#endif + } + + // Workaround for Cortex-A53 erratum (843419). Emit extra nops to avoid + // wrong address access after ADRP instruction. + ALWAYS_INLINE void nopCortexA53Fix843419() + { +#if CPU(ARM64_CORTEXA53) + nop(); + nop(); + nop(); +#endif + } + AssemblerBuffer m_buffer; Vector<LinkRecord, 0, UnsafeVectorOverflow> m_jumpsToLink; int m_indexOfLastWatchpoint; diff --git a/assembler/ARMAssembler.h b/assembler/ARMAssembler.h index 087d31c..f18f0fe 100644 --- a/assembler/ARMAssembler.h +++ b/assembler/ARMAssembler.h @@ -36,62 +36,6 @@ namespace JSC { typedef uint32_t ARMWord; - namespace ARMRegisters { - typedef enum { - r0 = 0, - r1, - r2, - r3, - r4, - r5, - r6, S0 = r6, - r7, - r8, - r9, - r10, - r11, fp = r11, // frame pointer - r12, ip = r12, S1 = r12, - r13, sp = r13, - r14, lr = r14, - r15, pc = r15 - } RegisterID; - - typedef enum { - d0, - d1, - d2, - d3, - d4, - d5, - d6, - d7, SD0 = d7, /* Same as thumb assembler. */ - d8, - d9, - d10, - d11, - d12, - d13, - d14, - d15, - d16, - d17, - d18, - d19, - d20, - d21, - d22, - d23, - d24, - d25, - d26, - d27, - d28, - d29, - d30, - d31 - } FPRegisterID; - -#if USE(MASM_PROBE) #define FOR_EACH_CPU_REGISTER(V) \ FOR_EACH_CPU_GPREGISTER(V) \ FOR_EACH_CPU_SPECIAL_REGISTER(V) \ @@ -109,11 +53,11 @@ namespace JSC { V(void*, r8) \ V(void*, r9) \ V(void*, r10) \ - V(void*, r11) \ + V(void*, fp) \ V(void*, ip) \ V(void*, sp) \ V(void*, lr) \ - V(void*, pc) + V(void*, pc) \ #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \ V(void*, apsr) \ @@ -135,8 +79,49 @@ namespace JSC { V(double, d12) \ V(double, d13) \ V(double, d14) \ - V(double, d15) -#endif // USE(MASM_PROBE) + V(double, d15) \ + V(double, d16) \ + V(double, d17) \ + V(double, d18) \ + V(double, d19) \ + V(double, d20) \ + V(double, d21) \ + V(double, d22) \ + V(double, d23) \ + V(double, d24) \ + V(double, d25) \ + V(double, d26) \ + V(double, d27) \ + V(double, d28) \ + V(double, d29) \ + V(double, d30) \ + V(double, d31) \ + + namespace ARMRegisters { + + typedef enum { + #define DECLARE_REGISTER(_type, _regName) _regName, + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + + // Pseudonyms for some of the registers. + S0 = r6, + r11 = fp, // frame pointer + r12 = ip, S1 = ip, + r13 = sp, + r14 = lr, + r15 = pc + } RegisterID; + + typedef enum { + #define DECLARE_REGISTER(_type, _regName) _regName, + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + + // Pseudonyms for some of the registers. + SD0 = d7, /* Same as thumb assembler. */ + } FPRegisterID; + } // namespace ARMRegisters class ARMAssembler { @@ -231,6 +216,10 @@ namespace JSC { #endif NOP = 0xe1a00000, DMB_SY = 0xf57ff05f, +#if HAVE(ARM_IDIV_INSTRUCTIONS) + SDIV = 0x0710f010, + UDIV = 0x0730f010, +#endif }; enum { @@ -492,6 +481,26 @@ namespace JSC { m_buffer.putInt(toARMWord(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); } +#if HAVE(ARM_IDIV_INSTRUCTIONS) + template<int datasize> + void sdiv(int rd, int rn, int rm, Condition cc = AL) + { + static_assert(datasize == 32, "sdiv datasize must be 32 for armv7s"); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(rm != ARMRegisters::pc); + m_buffer.putInt(toARMWord(cc) | SDIV | RN(rd) | RM(rn) | RS(rm)); + } + + void udiv(int rd, int rn, int rm, Condition cc = AL) + { + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); + ASSERT(rm != ARMRegisters::pc); + m_buffer.putInt(toARMWord(cc) | UDIV | RN(rd) | RM(rn) | RS(rm)); + } +#endif + void vmov_f64(int dd, int dm, Condition cc = AL) { emitDoublePrecisionInstruction(toARMWord(cc) | VMOV_F64, dd, 0, dm); @@ -1119,8 +1128,6 @@ namespace JSC { linuxPageFlush(current, current + page); linuxPageFlush(current, end); -#elif OS(WINCE) - CacheRangeFlush(code, size, CACHE_SYNC_ALL); #else #error "The cacheFlush support is missing on this platform." #endif diff --git a/assembler/ARMv7Assembler.h b/assembler/ARMv7Assembler.h index ce079d9..1d731f9 100644 --- a/assembler/ARMv7Assembler.h +++ b/assembler/ARMv7Assembler.h @@ -38,23 +38,83 @@ namespace JSC { namespace ARMRegisters { + + #define FOR_EACH_CPU_REGISTER(V) \ + FOR_EACH_CPU_GPREGISTER(V) \ + FOR_EACH_CPU_SPECIAL_REGISTER(V) \ + FOR_EACH_CPU_FPREGISTER(V) + + // The following are defined as pairs of the following value: + // 1. type of the storage needed to save the register value by the JIT probe. + // 2. name of the register. + #define FOR_EACH_CPU_GPREGISTER(V) \ + V(void*, r0) \ + V(void*, r1) \ + V(void*, r2) \ + V(void*, r3) \ + V(void*, r4) \ + V(void*, r5) \ + V(void*, r6) \ + V(void*, r7) \ + V(void*, r8) \ + V(void*, r9) \ + V(void*, r10) \ + V(void*, r11) \ + V(void*, ip) \ + V(void*, sp) \ + V(void*, lr) \ + V(void*, pc) + + #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \ + V(void*, apsr) \ + V(void*, fpscr) \ + + #define FOR_EACH_CPU_FPREGISTER(V) \ + V(double, d0) \ + V(double, d1) \ + V(double, d2) \ + V(double, d3) \ + V(double, d4) \ + V(double, d5) \ + V(double, d6) \ + V(double, d7) \ + V(double, d8) \ + V(double, d9) \ + V(double, d10) \ + V(double, d11) \ + V(double, d12) \ + V(double, d13) \ + V(double, d14) \ + V(double, d15) \ + V(double, d16) \ + V(double, d17) \ + V(double, d18) \ + V(double, d19) \ + V(double, d20) \ + V(double, d21) \ + V(double, d22) \ + V(double, d23) \ + V(double, d24) \ + V(double, d25) \ + V(double, d26) \ + V(double, d27) \ + V(double, d28) \ + V(double, d29) \ + V(double, d30) \ + V(double, d31) + typedef enum { - r0, - r1, - r2, - r3, - r4, - r5, - r6, - r7, fp = r7, // frame pointer - r8, - r9, sb = r9, // static base - r10, sl = r10, // stack limit - r11, - r12, ip = r12, - r13, sp = r13, - r14, lr = r14, - r15, pc = r15, + #define DECLARE_REGISTER(_type, _regName) _regName, + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + + fp = r7, // frame pointer + sb = r9, // static base + sl = r10, // stack limit + r12 = ip, + r13 = sp, + r14 = lr, + r15 = pc } RegisterID; typedef enum { @@ -93,38 +153,9 @@ namespace ARMRegisters { } FPSingleRegisterID; typedef enum { - d0, - d1, - d2, - d3, - d4, - d5, - d6, - d7, - d8, - d9, - d10, - d11, - d12, - d13, - d14, - d15, - d16, - d17, - d18, - d19, - d20, - d21, - d22, - d23, - d24, - d25, - d26, - d27, - d28, - d29, - d30, - d31, + #define DECLARE_REGISTER(_type, _regName) _regName, + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER } FPDoubleRegisterID; typedef enum { @@ -174,77 +205,7 @@ namespace ARMRegisters { return (FPDoubleRegisterID)(reg >> 1); } -#if USE(MASM_PROBE) - #define FOR_EACH_CPU_REGISTER(V) \ - FOR_EACH_CPU_GPREGISTER(V) \ - FOR_EACH_CPU_SPECIAL_REGISTER(V) \ - FOR_EACH_CPU_FPREGISTER(V) - - #define FOR_EACH_CPU_GPREGISTER(V) \ - V(void*, r0) \ - V(void*, r1) \ - V(void*, r2) \ - V(void*, r3) \ - V(void*, r4) \ - V(void*, r5) \ - V(void*, r6) \ - V(void*, r7) \ - V(void*, r8) \ - V(void*, r9) \ - V(void*, r10) \ - V(void*, r11) \ - V(void*, ip) \ - V(void*, sp) \ - V(void*, lr) \ - V(void*, pc) - - #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \ - V(void*, apsr) \ - V(void*, fpscr) \ - - #define FOR_EACH_CPU_FPREGISTER(V) \ - V(double, d0) \ - V(double, d1) \ - V(double, d2) \ - V(double, d3) \ - V(double, d4) \ - V(double, d5) \ - V(double, d6) \ - V(double, d7) \ - V(double, d8) \ - V(double, d9) \ - V(double, d10) \ - V(double, d11) \ - V(double, d12) \ - V(double, d13) \ - V(double, d14) \ - V(double, d15) \ - FOR_EACH_CPU_FPREGISTER_EXTENSION(V) - -#if CPU(APPLE_ARMV7S) - #define FOR_EACH_CPU_FPREGISTER_EXTENSION(V) \ - V(double, d16) \ - V(double, d17) \ - V(double, d18) \ - V(double, d19) \ - V(double, d20) \ - V(double, d21) \ - V(double, d22) \ - V(double, d23) \ - V(double, d24) \ - V(double, d25) \ - V(double, d26) \ - V(double, d27) \ - V(double, d28) \ - V(double, d29) \ - V(double, d30) \ - V(double, d31) -#else - #define FOR_EACH_CPU_FPREGISTER_EXTENSION(V) // Nothing to add. -#endif // CPU(APPLE_ARMV7S) - -#endif // USE(MASM_PROBE) -} +} // namespace ARMRegisters class ARMv7Assembler; class ARMThumbImmediate { @@ -747,7 +708,7 @@ private: OP_ROR_reg_T2 = 0xFA60, OP_CLZ = 0xFAB0, OP_SMULL_T1 = 0xFB80, -#if CPU(APPLE_ARMV7S) +#if HAVE(ARM_IDIV_INSTRUCTIONS) OP_SDIV_T1 = 0xFB90, OP_UDIV_T1 = 0xFBB0, #endif @@ -1538,7 +1499,7 @@ public: m_formatter.twoWordOp16Imm16(OP_PUSH_T2, registerList); } -#if CPU(APPLE_ARMV7S) +#if HAVE(ARM_IDIV_INSTRUCTIONS) template<int datasize> ALWAYS_INLINE void sdiv(RegisterID rd, RegisterID rn, RegisterID rm) { @@ -1687,8 +1648,8 @@ public: ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isUInt12()); - if (!((rt | rn) & 8) && imm.isUInt7()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STRH_imm_T1, imm.getUInt7() >> 2, rn, rt); + if (!((rt | rn) & 8) && imm.isUInt6()) + m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STRH_imm_T1, imm.getUInt6() >> 1, rn, rt); else m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STRH_imm_T2, rn, rt, imm.getUInt12()); } @@ -1886,7 +1847,7 @@ public: m_formatter.twoWordOp12Reg40Imm3Reg4Imm20Imm5(OP_UBFX_T1, rd, rn, (lsb & 0x1c) << 10, (lsb & 0x3) << 6, (width - 1) & 0x1f); } -#if CPU(APPLE_ARMV7S) +#if HAVE(ARM_IDIV_INSTRUCTIONS) ALWAYS_INLINE void udiv(RegisterID rd, RegisterID rn, RegisterID rm) { ASSERT(!BadReg(rd)); @@ -2411,8 +2372,6 @@ public: linuxPageFlush(current, current + page); linuxPageFlush(current, end); -#elif OS(WINCE) - CacheRangeFlush(code, size, CACHE_SYNC_ALL); #else #error "The cacheFlush support is missing on this platform." #endif diff --git a/assembler/AbortReason.h b/assembler/AbortReason.h index 34c345b..1a5f068 100644 --- a/assembler/AbortReason.h +++ b/assembler/AbortReason.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -57,6 +57,7 @@ enum AbortReason { DFGSlowPathGeneratorFellThrough = 210, DFGUnreachableBasicBlock = 220, DFGUnreasonableOSREntryJumpDestination = 230, + DFGVarargsThrowingPathDidNotThrow = 235, JITDivOperandsAreNotNumbers = 240, JITGetByValResultIsNotEmpty = 250, JITNotSupported = 260, diff --git a/assembler/AbstractMacroAssembler.h b/assembler/AbstractMacroAssembler.h index a209900..6e82dcc 100644 --- a/assembler/AbstractMacroAssembler.h +++ b/assembler/AbstractMacroAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,9 +39,9 @@ namespace JSC { -inline bool isARMv7s() +inline bool isARMv7IDIVSupported() { -#if CPU(APPLE_ARMV7S) +#if HAVE(ARM_IDIV_INSTRUCTIONS) return true; #else return false; @@ -66,9 +66,9 @@ inline bool isX86() #endif } -inline bool optimizeForARMv7s() +inline bool optimizeForARMv7IDIVSupported() { - return isARMv7s() && Options::enableArchitectureSpecificOptimizations(); + return isARMv7IDIVSupported() && Options::enableArchitectureSpecificOptimizations(); } inline bool optimizeForARM64() @@ -88,10 +88,11 @@ namespace DFG { struct OSRExit; } -template <class AssemblerType> +template <class AssemblerType, class MacroAssemblerType> class AbstractMacroAssembler { public: friend class JITWriteBarrierBase; + typedef AbstractMacroAssembler<AssemblerType, MacroAssemblerType> AbstractMacroAssemblerType; typedef AssemblerType AssemblerType_T; typedef MacroAssemblerCodePtr CodePtr; @@ -204,6 +205,11 @@ public: RegisterID index; Scale scale; int32_t offset; + + BaseIndex withOffset(int32_t additionalOffset) + { + return BaseIndex(base, index, scale, offset + additionalOffset); + } }; // AbsoluteAddress: @@ -355,7 +361,7 @@ public: // A Label records a point in the generated instruction stream, typically such that // it may be used as a destination for a jump. class Label { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; friend struct DFG::OSRExit; friend class Jump; @@ -368,7 +374,7 @@ public: { } - Label(AbstractMacroAssembler<AssemblerType>* masm) + Label(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { masm->invalidateAllTempRegisters(); @@ -390,7 +396,7 @@ public: // // addPtr(TrustedImmPtr(i), a, b) class ConvertibleLoadLabel { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; friend class LinkBuffer; @@ -399,7 +405,7 @@ public: { } - ConvertibleLoadLabel(AbstractMacroAssembler<AssemblerType>* masm) + ConvertibleLoadLabel(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.labelIgnoringWatchpoints()) { } @@ -414,7 +420,7 @@ public: // A DataLabelPtr is used to refer to a location in the code containing a pointer to be // patched after the code has been generated. class DataLabelPtr { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; friend class LinkBuffer; public: @@ -422,7 +428,7 @@ public: { } - DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm) + DataLabelPtr(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { } @@ -438,7 +444,7 @@ public: // A DataLabel32 is used to refer to a location in the code containing a 32-bit constant to be // patched after the code has been generated. class DataLabel32 { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; friend class LinkBuffer; public: @@ -446,7 +452,7 @@ public: { } - DataLabel32(AbstractMacroAssembler<AssemblerType>* masm) + DataLabel32(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { } @@ -462,7 +468,7 @@ public: // A DataLabelCompact is used to refer to a location in the code containing a // compact immediate to be patched after the code has been generated. class DataLabelCompact { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; friend class LinkBuffer; public: @@ -470,7 +476,7 @@ public: { } - DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm) + DataLabelCompact(AbstractMacroAssemblerType* masm) : m_label(masm->m_assembler.label()) { } @@ -493,7 +499,7 @@ public: // relative offset such that when executed it will call to the desired // destination. class Call { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; public: @@ -537,7 +543,7 @@ public: // relative offset such that when executed it will jump to the desired // destination. class Jump { - template<class TemplateAssemblerType> + template<class TemplateAssemblerType, class TemplateMacroAssemblerType> friend class AbstractMacroAssembler; friend class Call; friend struct DFG::OSRExit; @@ -602,7 +608,7 @@ public: return result; } - void link(AbstractMacroAssembler<AssemblerType>* masm) const + void link(AbstractMacroAssemblerType* masm) const { masm->invalidateAllTempRegisters(); @@ -626,7 +632,7 @@ public: #endif } - void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const + void linkTo(Label label, AbstractMacroAssemblerType* masm) const { #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION) masm->checkRegisterAllocationAgainstBranchRange(label.m_label.m_offset, m_label.m_offset); @@ -698,7 +704,7 @@ public: append(jump); } - void link(AbstractMacroAssembler<AssemblerType>* masm) + void link(AbstractMacroAssemblerType* masm) { size_t size = m_jumps.size(); for (size_t i = 0; i < size; ++i) @@ -706,7 +712,7 @@ public: m_jumps.clear(); } - void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) + void linkTo(Label label, AbstractMacroAssemblerType* masm) { size_t size = m_jumps.size(); for (size_t i = 0; i < size; ++i) @@ -836,6 +842,188 @@ public: AssemblerType::cacheFlush(code, size); } +#if ENABLE(MASM_PROBE) + + struct CPUState { + #define DECLARE_REGISTER(_type, _regName) \ + _type _regName; + FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + + static const char* registerName(RegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case RegisterID::_regName: \ + return #_regName; + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + static const char* registerName(FPRegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case FPRegisterID::_regName: \ + return #_regName; + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + void* registerValue(RegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case RegisterID::_regName: \ + return _regName; + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + double registerValue(FPRegisterID regID) + { + switch (regID) { + #define DECLARE_REGISTER(_type, _regName) \ + case FPRegisterID::_regName: \ + return _regName; + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER + } + RELEASE_ASSERT_NOT_REACHED(); + } + + }; + + struct ProbeContext; + typedef void (*ProbeFunction)(struct ProbeContext*); + + struct ProbeContext { + ProbeFunction probeFunction; + void* arg1; + void* arg2; + CPUState cpu; + + void print(int indentation = 0) + { + #define INDENT MacroAssemblerType::printIndent(indentation) + + INDENT, dataLogF("ProbeContext %p {\n", this); + indentation++; + { + INDENT, dataLogF("probeFunction: %p\n", probeFunction); + INDENT, dataLogF("arg1: %p %llu\n", arg1, reinterpret_cast<int64_t>(arg1)); + INDENT, dataLogF("arg2: %p %llu\n", arg2, reinterpret_cast<int64_t>(arg2)); + MacroAssemblerType::printCPU(cpu, indentation); + } + indentation--; + INDENT, dataLog("}\n"); + + #undef INDENT + } + }; + + static void printIndent(int indentation) + { + for (; indentation > 0; indentation--) + dataLog(" "); + } + + static void printCPU(CPUState& cpu, int indentation = 0) + { + #define INDENT printIndent(indentation) + + INDENT, dataLog("cpu: {\n"); + MacroAssemblerType::printCPURegisters(cpu, indentation + 1); + INDENT, dataLog("}\n"); + + #undef INDENT + } + + // This is a marker type only used with print(). See print() below for details. + struct AllRegisters { }; + + // Emits code which will print debugging info at runtime. The type of values that + // can be printed is encapsulated in the PrintArg struct below. Here are some + // examples: + // + // print("Hello world\n"); // Emits code to print the string. + // + // CodeBlock* cb = ...; + // print(cb); // Emits code to print the pointer value. + // + // RegisterID regID = ...; + // print(regID); // Emits code to print the register value (not the id). + // + // // Emits code to print all registers. Unlike other items, this prints + // // multiple lines as follows: + // // cpu { + // // eax: 0x123456789 + // // ebx: 0x000000abc + // // ... + // // } + // print(AllRegisters()); + // + // // Print multiple things at once. This incurs the probe overhead only once + // // to print all the items. + // print("cb:", cb, " regID:", regID, " cpu:\n", AllRegisters()); + + template<typename... Arguments> + void print(Arguments... args) + { + printInternal(static_cast<MacroAssemblerType*>(this), args...); + } + + // This function will be called by printCPU() to print the contents of the + // target specific registers which are saved away in the CPUState struct. + // printCPURegisters() should make use of printIndentation() to print the + // registers with the appropriate amount of indentation. + // + // Note: printCPURegisters() should be implemented by the target specific + // MacroAssembler. This prototype is only provided here to document the + // interface. + + static void printCPURegisters(CPUState&, int indentation = 0); + + // This function will be called by print() to print the contents of a + // specific register (from the CPUState) in line with other items in the + // print stream. Hence, no indentation is needed. + // + // Note: printRegister() should be implemented by the target specific + // MacroAssembler. These prototypes are only provided here to document their + // interface. + + static void printRegister(CPUState&, RegisterID); + static void printRegister(CPUState&, FPRegisterID); + + // This function emits code to preserve the CPUState (e.g. registers), + // call a user supplied probe function, and restore the CPUState before + // continuing with other JIT generated code. + // + // The user supplied probe function will be called with a single pointer to + // a ProbeContext struct (defined above) which contains, among other things, + // the preserved CPUState. This allows the user probe function to inspect + // the CPUState at that point in the JIT generated code. + // + // If the user probe function alters the register values in the ProbeContext, + // the altered values will be loaded into the CPU registers when the probe + // returns. + // + // The ProbeContext is stack allocated and is only valid for the duration + // of the call to the user probe function. + // + // Note: probe() should be implemented by the target specific MacroAssembler. + // This prototype is only provided here to document the interface. + + void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); + +#endif // ENABLE(MASM_PROBE) + AssemblerType m_assembler; protected: @@ -877,7 +1065,7 @@ protected: friend class Label; public: - CachedTempRegister(AbstractMacroAssembler<AssemblerType>* masm, RegisterID registerID) + CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID) : m_masm(masm) , m_registerID(registerID) , m_value(0) @@ -905,7 +1093,7 @@ protected: ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); } private: - AbstractMacroAssembler<AssemblerType>* m_masm; + AbstractMacroAssemblerType* m_masm; RegisterID m_registerID; intptr_t m_value; unsigned m_validBit; @@ -995,7 +1183,143 @@ protected: { AssemblerType::replaceWithAddressComputation(label.dataLocation()); } -}; + +private: + +#if ENABLE(MASM_PROBE) + + struct PrintArg { + + enum class Type { + AllRegisters, + RegisterID, + FPRegisterID, + ConstCharPtr, + ConstVoidPtr, + IntptrValue, + UintptrValue, + }; + + PrintArg(AllRegisters&) + : type(Type::AllRegisters) + { + } + + PrintArg(RegisterID regID) + : type(Type::RegisterID) + { + u.gpRegisterID = regID; + } + + PrintArg(FPRegisterID regID) + : type(Type::FPRegisterID) + { + u.fpRegisterID = regID; + } + + PrintArg(const char* ptr) + : type(Type::ConstCharPtr) + { + u.constCharPtr = ptr; + } + + PrintArg(const void* ptr) + : type(Type::ConstVoidPtr) + { + u.constVoidPtr = ptr; + } + + PrintArg(int value) + : type(Type::IntptrValue) + { + u.intptrValue = value; + } + + PrintArg(unsigned value) + : type(Type::UintptrValue) + { + u.intptrValue = value; + } + + PrintArg(intptr_t value) + : type(Type::IntptrValue) + { + u.intptrValue = value; + } + + PrintArg(uintptr_t value) + : type(Type::UintptrValue) + { + u.uintptrValue = value; + } + + Type type; + union { + RegisterID gpRegisterID; + FPRegisterID fpRegisterID; + const char* constCharPtr; + const void* constVoidPtr; + intptr_t intptrValue; + uintptr_t uintptrValue; + } u; + }; + + typedef Vector<PrintArg> PrintArgsList; + + template<typename FirstArg, typename... Arguments> + static void appendPrintArg(PrintArgsList* argsList, FirstArg& firstArg, Arguments... otherArgs) + { + argsList->append(PrintArg(firstArg)); + appendPrintArg(argsList, otherArgs...); + } + + static void appendPrintArg(PrintArgsList*) { } + + + template<typename... Arguments> + static void printInternal(MacroAssemblerType* masm, Arguments... args) + { + auto argsList = std::make_unique<PrintArgsList>(); + appendPrintArg(argsList.get(), args...); + masm->probe(printCallback, argsList.release()); + } + + static void printCallback(ProbeContext* context) + { + typedef PrintArg Arg; + PrintArgsList& argsList = + *reinterpret_cast<PrintArgsList*>(context->arg1); + for (size_t i = 0; i < argsList.size(); i++) { + auto& arg = argsList[i]; + switch (arg.type) { + case Arg::Type::AllRegisters: + MacroAssemblerType::printCPU(context->cpu); + break; + case Arg::Type::RegisterID: + MacroAssemblerType::printRegister(context->cpu, arg.u.gpRegisterID); + break; + case Arg::Type::FPRegisterID: + MacroAssemblerType::printRegister(context->cpu, arg.u.fpRegisterID); + break; + case Arg::Type::ConstCharPtr: + dataLog(arg.u.constCharPtr); + break; + case Arg::Type::ConstVoidPtr: + dataLogF("%p", arg.u.constVoidPtr); + break; + case Arg::Type::IntptrValue: + dataLog(arg.u.intptrValue); + break; + case Arg::Type::UintptrValue: + dataLog(arg.u.uintptrValue); + break; + } + } + } + +#endif // ENABLE(MASM_PROBE) + +}; // class AbstractMacroAssembler } // namespace JSC diff --git a/assembler/AssemblerBuffer.h b/assembler/AssemblerBuffer.h index 1c33fe1..3632a5b 100644 --- a/assembler/AssemblerBuffer.h +++ b/assembler/AssemblerBuffer.h @@ -69,7 +69,7 @@ namespace JSC { AssemblerData(unsigned initialCapacity) { - m_capacity = fastMallocGoodSize(initialCapacity); + m_capacity = initialCapacity; m_buffer = static_cast<char*>(fastMalloc(m_capacity)); } @@ -101,7 +101,7 @@ namespace JSC { void grow(unsigned extraCapacity = 0) { - m_capacity = fastMallocGoodSize(m_capacity + m_capacity / 2 + extraCapacity); + m_capacity = m_capacity + m_capacity / 2 + extraCapacity; m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity)); } diff --git a/assembler/LinkBuffer.cpp b/assembler/LinkBuffer.cpp index a66541d..d53ef45 100644 --- a/assembler/LinkBuffer.cpp +++ b/assembler/LinkBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -59,19 +59,28 @@ LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, { CodeRef result = finalizeCodeWithoutDisassembly(); -#if ENABLE(DISASSEMBLER) - dataLogF("Generated JIT code for "); + if (m_alreadyDisassembled) + return result; + + StringPrintStream out; + out.printf("Generated JIT code for "); va_list argList; va_start(argList, format); - WTF::dataLogFV(format, argList); + out.vprintf(format, argList); va_end(argList); - dataLogF(":\n"); + out.printf(":\n"); + + out.printf(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size()); + + CString header = out.toCString(); - dataLogF(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size()); + if (Options::asyncDisassembly()) { + disassembleAsynchronously(header, result, m_size, " "); + return result; + } + + dataLog(header); disassemble(result.code(), m_size, " ", WTF::dataFile()); -#else - UNUSED_PARAM(format); -#endif // ENABLE(DISASSEMBLER) return result; } diff --git a/assembler/LinkBuffer.h b/assembler/LinkBuffer.h index 516e456..9b0d4c4 100644 --- a/assembler/LinkBuffer.h +++ b/assembler/LinkBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -254,6 +254,9 @@ public: { return m_size; } + + bool wasAlreadyDisassembled() const { return m_alreadyDisassembled; } + void didAlreadyDisassemble() { m_alreadyDisassembled = true; } private: #if ENABLE(BRANCH_COMPACTION) @@ -310,6 +313,7 @@ private: #ifndef NDEBUG bool m_completed; #endif + bool m_alreadyDisassembled { false }; }; #define FINALIZE_CODE_IF(condition, linkBufferReference, dataLogFArgumentsForHeading) \ @@ -320,7 +324,7 @@ private: bool shouldShowDisassemblyFor(CodeBlock*); #define FINALIZE_CODE_FOR(codeBlock, linkBufferReference, dataLogFArgumentsForHeading) \ - FINALIZE_CODE_IF(shouldShowDisassemblyFor(codeBlock), linkBufferReference, dataLogFArgumentsForHeading) + FINALIZE_CODE_IF(shouldShowDisassemblyFor(codeBlock) || Options::asyncDisassembly(), linkBufferReference, dataLogFArgumentsForHeading) // Use this to finalize code, like so: // @@ -339,10 +343,10 @@ bool shouldShowDisassemblyFor(CodeBlock*); // is true, so you can hide expensive disassembly-only computations inside there. #define FINALIZE_CODE(linkBufferReference, dataLogFArgumentsForHeading) \ - FINALIZE_CODE_IF(JSC::Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading) + FINALIZE_CODE_IF(JSC::Options::asyncDisassembly() || JSC::Options::showDisassembly(), linkBufferReference, dataLogFArgumentsForHeading) #define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \ - FINALIZE_CODE_IF((JSC::Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading) + FINALIZE_CODE_IF(JSC::Options::asyncDisassembly() || JSC::Options::showDisassembly() || Options::showDFGDisassembly(), linkBufferReference, dataLogFArgumentsForHeading) } // namespace JSC diff --git a/assembler/MacroAssembler.h b/assembler/MacroAssembler.h index c70f2b7..fd4c5bb 100644 --- a/assembler/MacroAssembler.h +++ b/assembler/MacroAssembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -471,6 +471,16 @@ public: { lshift32(trustedImm32ForShift(imm), srcDest); } + + void rshiftPtr(Imm32 imm, RegisterID srcDest) + { + rshift32(trustedImm32ForShift(imm), srcDest); + } + + void urshiftPtr(Imm32 imm, RegisterID srcDest) + { + urshift32(trustedImm32ForShift(imm), srcDest); + } void negPtr(RegisterID dest) { @@ -750,6 +760,16 @@ public: lshift64(trustedImm32ForShift(imm), srcDest); } + void rshiftPtr(Imm32 imm, RegisterID srcDest) + { + rshift64(trustedImm32ForShift(imm), srcDest); + } + + void urshiftPtr(Imm32 imm, RegisterID srcDest) + { + urshift64(trustedImm32ForShift(imm), srcDest); + } + void negPtr(RegisterID dest) { neg64(dest); diff --git a/assembler/MacroAssemblerARM.cpp b/assembler/MacroAssemblerARM.cpp index a6f3e65..2500d84 100644 --- a/assembler/MacroAssemblerARM.cpp +++ b/assembler/MacroAssemblerARM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. + * Copyright (C) 2013, 2014 Apple Inc. * Copyright (C) 2009 University of Szeged * All rights reserved. * @@ -31,10 +31,6 @@ #include "MacroAssemblerARM.h" -#if USE(MASM_PROBE) -#include <wtf/StdLibExtras.h> -#endif - #if OS(LINUX) #include <sys/types.h> #include <sys/stat.h> @@ -50,7 +46,7 @@ static bool isVFPPresent() { #if OS(LINUX) int fd = open("/proc/self/auxv", O_RDONLY); - if (fd > 0) { + if (fd != -1) { Elf32_auxv_t aux; while (read(fd, &aux, sizeof(Elf32_auxv_t))) { if (aux.a_type == AT_HWCAP) { @@ -99,51 +95,58 @@ void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, Register } #endif // CPU(ARMV5_OR_LOWER) -#if USE(MASM_PROBE) +#if ENABLE(MASM_PROBE) + +#define INDENT printIndent(indentation) -void MacroAssemblerARM::ProbeContext::dumpCPURegisters(const char* indentation) +void MacroAssemblerARM::printCPURegisters(CPUState& cpu, int indentation) { - #define DUMP_GPREGISTER(_type, _regName) { \ + #define PRINT_GPREGISTER(_type, _regName) { \ int32_t value = reinterpret_cast<int32_t>(cpu._regName); \ - dataLogF("%s %5s: 0x%08x %d\n", indentation, #_regName, value, value) ; \ + INDENT, dataLogF("%5s: 0x%08x %d\n", #_regName, value, value) ; \ } - FOR_EACH_CPU_GPREGISTER(DUMP_GPREGISTER) - FOR_EACH_CPU_SPECIAL_REGISTER(DUMP_GPREGISTER) - #undef DUMP_GPREGISTER + FOR_EACH_CPU_GPREGISTER(PRINT_GPREGISTER) + FOR_EACH_CPU_SPECIAL_REGISTER(PRINT_GPREGISTER) + #undef PRINT_GPREGISTER - #define DUMP_FPREGISTER(_type, _regName) { \ - uint32_t* u = reinterpret_cast<uint32_t*>(&cpu._regName); \ + #define PRINT_FPREGISTER(_type, _regName) { \ + uint64_t* u = reinterpret_cast<uint64_t*>(&cpu._regName); \ double* d = reinterpret_cast<double*>(&cpu._regName); \ - dataLogF("%s %5s: 0x %08x %08x %12g\n", \ - indentation, #_regName, u[1], u[0], d[0]); \ + INDENT, dataLogF("%5s: 0x%016llx %.13g\n", #_regName, *u, *d); \ } - FOR_EACH_CPU_FPREGISTER(DUMP_FPREGISTER) - #undef DUMP_FPREGISTER + FOR_EACH_CPU_FPREGISTER(PRINT_FPREGISTER) + #undef PRINT_FPREGISTER } -void MacroAssemblerARM::ProbeContext::dump(const char* indentation) -{ - if (!indentation) - indentation = ""; - - dataLogF("%sProbeContext %p {\n", indentation, this); - dataLogF("%s probeFunction: %p\n", indentation, probeFunction); - dataLogF("%s arg1: %p %llu\n", indentation, arg1, reinterpret_cast<int64_t>(arg1)); - dataLogF("%s arg2: %p %llu\n", indentation, arg2, reinterpret_cast<int64_t>(arg2)); - dataLogF("%s cpu: {\n", indentation); +#undef INDENT - dumpCPURegisters(indentation); - - dataLogF("%s }\n", indentation); - dataLogF("%s}\n", indentation); +void MacroAssemblerARM::printRegister(MacroAssemblerARM::CPUState& cpu, RegisterID regID) +{ + const char* name = CPUState::registerName(regID); + union { + void* voidPtr; + intptr_t intptrValue; + } u; + u.voidPtr = cpu.registerValue(regID); + dataLogF("%s:<%p %ld>", name, u.voidPtr, u.intptrValue); } +void MacroAssemblerARM::printRegister(MacroAssemblerARM::CPUState& cpu, FPRegisterID regID) +{ + const char* name = CPUState::registerName(regID); + union { + double doubleValue; + uint64_t uint64Value; + } u; + u.doubleValue = cpu.registerValue(regID); + dataLogF("%s:<0x%016llx %.13g>", name, u.uint64Value, u.doubleValue); +} extern "C" void ctiMasmProbeTrampoline(); // For details on "What code is emitted for the probe?" and "What values are in -// the saved registers?", see comment for MacroAssemblerX86::probe() in -// MacroAssemblerX86_64.h. +// the saved registers?", see comment for MacroAssemblerX86Common::probe() in +// MacroAssemblerX86Common.cpp. void MacroAssemblerARM::probe(MacroAssemblerARM::ProbeFunction function, void* arg1, void* arg2) { @@ -160,7 +163,7 @@ void MacroAssemblerARM::probe(MacroAssemblerARM::ProbeFunction function, void* a m_assembler.blx(RegisterID::S0); } -#endif // USE(MASM_PROBE) +#endif // ENABLE(MASM_PROBE) } // namespace JSC diff --git a/assembler/MacroAssemblerARM.h b/assembler/MacroAssemblerARM.h index 82c8056..6cda896 100644 --- a/assembler/MacroAssemblerARM.h +++ b/assembler/MacroAssemblerARM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2013 Apple Inc. + * Copyright (C) 2008, 2013, 2014 Apple Inc. * Copyright (C) 2009, 2010 University of Szeged * All rights reserved. * @@ -35,7 +35,7 @@ namespace JSC { -class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> { +class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler, MacroAssemblerARM> { static const int DoubleConditionMask = 0x0f; static const int DoubleConditionBitSpecial = 0x10; COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); @@ -370,7 +370,7 @@ public: m_assembler.dataTransfer32(ARMAssembler::LoadUint8, dest, ARMRegisters::S0, 0); } - void load8Signed(BaseIndex address, RegisterID dest) + void load8SignedExtendTo32(BaseIndex address, RegisterID dest) { m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); } @@ -385,7 +385,7 @@ public: m_assembler.baseIndexTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); } - void load16Signed(BaseIndex address, RegisterID dest) + void load16SignedExtendTo32(BaseIndex address, RegisterID dest) { m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); } @@ -942,7 +942,7 @@ public: void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest) { if (mask.m_value == -1) - m_assembler.cmp(0, reg); + m_assembler.tst(reg, reg); else m_assembler.tst(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); m_assembler.mov(dest, ARMAssembler::getOp2Byte(0)); @@ -1432,31 +1432,14 @@ public: UNREACHABLE_FOR_PLATFORM(); } -#if USE(MASM_PROBE) - struct CPUState { - #define DECLARE_REGISTER(_type, _regName) \ - _type _regName; - FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) - #undef DECLARE_REGISTER - }; - - struct ProbeContext; - typedef void (*ProbeFunction)(struct ProbeContext*); - - struct ProbeContext { - ProbeFunction probeFunction; - void* arg1; - void* arg2; - CPUState cpu; - - void dump(const char* indentation = 0); - private: - void dumpCPURegisters(const char* indentation); - }; - - // For details about probe(), see comment in MacroAssemblerX86_64.h. +#if ENABLE(MASM_PROBE) + // Methods required by the MASM_PROBE mechanism as defined in + // AbstractMacroAssembler.h. + static void printCPURegisters(CPUState&, int indentation = 0); + static void printRegister(CPUState&, RegisterID); + static void printRegister(CPUState&, FPRegisterID); void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); -#endif // USE(MASM_PROBE) +#endif // ENABLE(MASM_PROBE) protected: ARMAssembler::Condition ARMCondition(RelationalCondition cond) @@ -1513,7 +1496,7 @@ private: ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); } -#if USE(MASM_PROBE) +#if ENABLE(MASM_PROBE) inline TrustedImm32 trustedImm32FromPtr(void* ptr) { return TrustedImm32(TrustedImmPtr(ptr)); diff --git a/assembler/MacroAssemblerARM64.h b/assembler/MacroAssemblerARM64.h index 830b58e..661fc0a 100644 --- a/assembler/MacroAssemblerARM64.h +++ b/assembler/MacroAssemblerARM64.h @@ -34,7 +34,7 @@ namespace JSC { -class MacroAssemblerARM64 : public AbstractMacroAssembler<ARM64Assembler> { +class MacroAssemblerARM64 : public AbstractMacroAssembler<ARM64Assembler, MacroAssemblerARM64> { static const RegisterID dataTempRegister = ARM64Registers::ip0; static const RegisterID memoryTempRegister = ARM64Registers::ip1; static const ARM64Registers::FPRegisterID fpTempRegister = ARM64Registers::q31; @@ -689,6 +689,26 @@ public: urshift32(dest, imm, dest); } + void urshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest) + { + m_assembler.lsr<64>(dest, src, shiftAmount); + } + + void urshift64(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.lsr<64>(dest, src, imm.m_value & 0x1f); + } + + void urshift64(RegisterID shiftAmount, RegisterID dest) + { + urshift64(dest, shiftAmount, dest); + } + + void urshift64(TrustedImm32 imm, RegisterID dest) + { + urshift64(dest, imm, dest); + } + void xor32(RegisterID src, RegisterID dest) { xor32(dest, src, dest); @@ -898,16 +918,16 @@ public: load16(address, dest); } - void load16Signed(BaseIndex address, RegisterID dest) + void load16SignedExtendTo32(BaseIndex address, RegisterID dest) { if (!address.offset && (!address.scale || address.scale == 1)) { - m_assembler.ldrsh<64>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale); + m_assembler.ldrsh<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale); return; } signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate()); m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale); - m_assembler.ldrsh<64>(dest, address.base, memoryTempRegister); + m_assembler.ldrsh<32>(dest, address.base, memoryTempRegister); } void load8(ImplicitAddress address, RegisterID dest) @@ -939,16 +959,16 @@ public: m_cachedMemoryTempRegister.invalidate(); } - void load8Signed(BaseIndex address, RegisterID dest) + void load8SignedExtendTo32(BaseIndex address, RegisterID dest) { if (!address.offset && !address.scale) { - m_assembler.ldrsb<64>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale); + m_assembler.ldrsb<32>(dest, address.base, address.index, ARM64Assembler::UXTX, address.scale); return; } signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate()); m_assembler.add<64>(memoryTempRegister, memoryTempRegister, address.index, ARM64Assembler::UXTX, address.scale); - m_assembler.ldrsb<64>(dest, address.base, memoryTempRegister); + m_assembler.ldrsb<32>(dest, address.base, memoryTempRegister); } void store64(RegisterID src, ImplicitAddress address) @@ -1193,9 +1213,14 @@ public: m_assembler.scvtf<64, 32>(fpTempRegister, dest); failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister)); - // If the result is zero, it might have been -0.0, and the double comparison won't catch this! - if (negZeroCheck) - failureCases.append(branchTest32(Zero, dest)); + // Test for negative zero. + if (negZeroCheck) { + Jump valueIsNonZero = branchTest32(NonZero, dest); + RegisterID scratch = getCachedMemoryTempRegisterIDAndInvalidate(); + m_assembler.fmov<64>(scratch, src); + failureCases.append(makeTestBitAndBranch(scratch, 63, IsNonZero)); + valueIsNonZero.link(this); + } } Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) @@ -1651,6 +1676,16 @@ public: Jump branch64(RelationalCondition cond, RegisterID left, RegisterID right) { + if (right == ARM64Registers::sp) { + if (cond == Equal && left != ARM64Registers::sp) { + // CMP can only use SP for the left argument, since we are testing for equality, the order + // does not matter here. + std::swap(left, right); + } else { + move(right, getCachedDataTempRegisterIDAndInvalidate()); + right = dataTempRegister; + } + } m_assembler.cmp<64>(left, right); return Jump(makeBranch(cond)); } diff --git a/assembler/MacroAssemblerARMv7.cpp b/assembler/MacroAssemblerARMv7.cpp index 3132e31..6651fff 100644 --- a/assembler/MacroAssemblerARMv7.cpp +++ b/assembler/MacroAssemblerARMv7.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,57 +28,60 @@ #if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) #include "MacroAssemblerARMv7.h" -#if USE(MASM_PROBE) -#include <wtf/StdLibExtras.h> -#endif - namespace JSC { -#if USE(MASM_PROBE) +#if ENABLE(MASM_PROBE) + +#define INDENT printIndent(indentation) -void MacroAssemblerARMv7::ProbeContext::dumpCPURegisters(const char* indentation) +void MacroAssemblerARMv7::printCPURegisters(CPUState& cpu, int indentation) { - #define DUMP_GPREGISTER(_type, _regName) { \ + #define PRINT_GPREGISTER(_type, _regName) { \ int32_t value = reinterpret_cast<int32_t>(cpu._regName); \ - dataLogF("%s %5s: 0x%08x %d\n", indentation, #_regName, value, value) ; \ + INDENT, dataLogF("%5s: 0x%08x %d\n", #_regName, value, value) ; \ } - FOR_EACH_CPU_GPREGISTER(DUMP_GPREGISTER) - FOR_EACH_CPU_SPECIAL_REGISTER(DUMP_GPREGISTER) - #undef DUMP_GPREGISTER + FOR_EACH_CPU_GPREGISTER(PRINT_GPREGISTER) + FOR_EACH_CPU_SPECIAL_REGISTER(PRINT_GPREGISTER) + #undef PRINT_GPREGISTER - #define DUMP_FPREGISTER(_type, _regName) { \ - uint32_t* u = reinterpret_cast<uint32_t*>(&cpu._regName); \ + #define PRINT_FPREGISTER(_type, _regName) { \ + uint64_t* u = reinterpret_cast<uint64_t*>(&cpu._regName); \ double* d = reinterpret_cast<double*>(&cpu._regName); \ - dataLogF("%s %5s: 0x %08x %08x %12g\n", \ - indentation, #_regName, u[1], u[0], d[0]); \ + INDENT, dataLogF("%5s: 0x%016llx %.13g\n", #_regName, *u, *d); \ } - FOR_EACH_CPU_FPREGISTER(DUMP_FPREGISTER) - #undef DUMP_FPREGISTER + FOR_EACH_CPU_FPREGISTER(PRINT_FPREGISTER) + #undef PRINT_FPREGISTER } -void MacroAssemblerARMv7::ProbeContext::dump(const char* indentation) -{ - if (!indentation) - indentation = ""; - - dataLogF("%sProbeContext %p {\n", indentation, this); - dataLogF("%s probeFunction: %p\n", indentation, probeFunction); - dataLogF("%s arg1: %p %llu\n", indentation, arg1, reinterpret_cast<int64_t>(arg1)); - dataLogF("%s arg2: %p %llu\n", indentation, arg2, reinterpret_cast<int64_t>(arg2)); - dataLogF("%s cpu: {\n", indentation); +#undef INDENT - dumpCPURegisters(indentation); - - dataLogF("%s }\n", indentation); - dataLogF("%s}\n", indentation); +void MacroAssemblerARMv7::printRegister(MacroAssemblerARMv7::CPUState& cpu, RegisterID regID) +{ + const char* name = CPUState::registerName(regID); + union { + void* voidPtr; + intptr_t intptrValue; + } u; + u.voidPtr = cpu.registerValue(regID); + dataLogF("%s:<%p %ld>", name, u.voidPtr, u.intptrValue); } +void MacroAssemblerARMv7::printRegister(MacroAssemblerARMv7::CPUState& cpu, FPRegisterID regID) +{ + const char* name = CPUState::registerName(regID); + union { + double doubleValue; + uint64_t uint64Value; + } u; + u.doubleValue = cpu.registerValue(regID); + dataLogF("%s:<0x%016llx %.13g>", name, u.uint64Value, u.doubleValue); +} extern "C" void ctiMasmProbeTrampoline(); // For details on "What code is emitted for the probe?" and "What values are in -// the saved registers?", see comment for MacroAssemblerX86::probe() in -// MacroAssemblerX86_64.h. +// the saved registers?", see comment for MacroAssemblerX86Common::probe() in +// MacroAssemblerX86Common.cpp. void MacroAssemblerARMv7::probe(MacroAssemblerARMv7::ProbeFunction function, void* arg1, void* arg2) { @@ -96,7 +99,7 @@ void MacroAssemblerARMv7::probe(MacroAssemblerARMv7::ProbeFunction function, voi move(trustedImm32FromPtr(ctiMasmProbeTrampoline), RegisterID::ip); m_assembler.blx(RegisterID::ip); } -#endif // USE(MASM_PROBE) +#endif // ENABLE(MASM_PROBE) } // namespace JSC diff --git a/assembler/MacroAssemblerARMv7.h b/assembler/MacroAssemblerARMv7.h index 80d17eb..2e71e61 100644 --- a/assembler/MacroAssemblerARMv7.h +++ b/assembler/MacroAssemblerARMv7.h @@ -34,7 +34,7 @@ namespace JSC { -class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { +class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler, MacroAssemblerARMv7> { static const RegisterID dataTempRegister = ARMRegisters::ip; static const RegisterID addressTempRegister = ARMRegisters::r6; @@ -546,7 +546,7 @@ private: } } - void load16Signed(ArmAddress address, RegisterID dest) + void load16SignedExtendTo32(ArmAddress address, RegisterID dest) { ASSERT(address.type == ArmAddress::HasIndex); m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale); @@ -566,7 +566,7 @@ private: } } - void load8Signed(ArmAddress address, RegisterID dest) + void load8SignedExtendTo32(ArmAddress address, RegisterID dest) { ASSERT(address.type == ArmAddress::HasIndex); m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale); @@ -668,7 +668,7 @@ public: load8(setupArmAddress(address), dest); } - void load8Signed(ImplicitAddress, RegisterID) + void load8SignedExtendTo32(ImplicitAddress, RegisterID) { UNREACHABLE_FOR_PLATFORM(); } @@ -678,9 +678,9 @@ public: load8(setupArmAddress(address), dest); } - void load8Signed(BaseIndex address, RegisterID dest) + void load8SignedExtendTo32(BaseIndex address, RegisterID dest) { - load8Signed(setupArmAddress(address), dest); + load8SignedExtendTo32(setupArmAddress(address), dest); } void load8(const void* address, RegisterID dest) @@ -714,9 +714,9 @@ public: m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); } - void load16Signed(BaseIndex address, RegisterID dest) + void load16SignedExtendTo32(BaseIndex address, RegisterID dest) { - load16Signed(setupArmAddress(address), dest); + load16SignedExtendTo32(setupArmAddress(address), dest); } void load16(ImplicitAddress address, RegisterID dest) @@ -730,7 +730,7 @@ public: } } - void load16Signed(ImplicitAddress, RegisterID) + void load16SignedExtendTo32(ImplicitAddress, RegisterID) { UNREACHABLE_FOR_PLATFORM(); } @@ -1901,31 +1901,14 @@ public: UNREACHABLE_FOR_PLATFORM(); } -#if USE(MASM_PROBE) - struct CPUState { - #define DECLARE_REGISTER(_type, _regName) \ - _type _regName; - FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) - #undef DECLARE_REGISTER - }; - - struct ProbeContext; - typedef void (*ProbeFunction)(struct ProbeContext*); - - struct ProbeContext { - ProbeFunction probeFunction; - void* arg1; - void* arg2; - CPUState cpu; - - void dump(const char* indentation = 0); - private: - void dumpCPURegisters(const char* indentation); - }; - - // For details about probe(), see comment in MacroAssemblerX86_64.h. +#if ENABLE(MASM_PROBE) + // Methods required by the MASM_PROBE mechanism as defined in + // AbstractMacroAssembler.h. + static void printCPURegisters(CPUState&, int indentation = 0); + static void printRegister(CPUState&, RegisterID); + static void printRegister(CPUState&, FPRegisterID); void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); -#endif // USE(MASM_PROBE) +#endif // ENABLE(MASM_PROBE) protected: ALWAYS_INLINE Jump jump() @@ -2037,7 +2020,7 @@ private: ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); } -#if USE(MASM_PROBE) +#if ENABLE(MASM_PROBE) inline TrustedImm32 trustedImm32FromPtr(void* ptr) { return TrustedImm32(TrustedImmPtr(ptr)); diff --git a/assembler/MacroAssemblerCodeRef.h b/assembler/MacroAssemblerCodeRef.h index 5795126..b4d6c0b 100644 --- a/assembler/MacroAssemblerCodeRef.h +++ b/assembler/MacroAssemblerCodeRef.h @@ -132,6 +132,12 @@ public: ASSERT_VALID_CODE_POINTER(m_value); } + template<typename returnType, typename argType1, typename argType2, typename argType3, typename argType4, typename argType5, typename argType6> + FunctionPtr(returnType(*value)(argType1, argType2, argType3, argType4, argType5, argType6)) + : m_value((void*)value) + { + ASSERT_VALID_CODE_POINTER(m_value); + } // MSVC doesn't seem to treat functions with different calling conventions as // different types; these methods already defined for fastcall, below. #if CALLING_CONVENTION_IS_STDCALL && !OS(WINDOWS) @@ -312,11 +318,7 @@ public: void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; } #endif - typedef void* (MacroAssemblerCodePtr::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const - { - return !!m_value ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; - } + explicit operator bool() const { return m_value; } bool operator==(const MacroAssemblerCodePtr& other) const { @@ -436,11 +438,7 @@ public: return JSC::tryToDisassemble(m_codePtr, size(), prefix, WTF::dataFile()); } - typedef void* (MacroAssemblerCodeRef::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const - { - return !!m_codePtr ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; - } + explicit operator bool() const { return !!m_codePtr; } void dump(PrintStream& out) const { diff --git a/assembler/MacroAssemblerMIPS.h b/assembler/MacroAssemblerMIPS.h index 71b5fa9..1a93128 100644 --- a/assembler/MacroAssemblerMIPS.h +++ b/assembler/MacroAssemblerMIPS.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,7 @@ namespace JSC { -class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> { +class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler, MacroAssemblerMIPS> { public: typedef MIPSRegisters::FPRegisterID FPRegisterID; @@ -707,7 +707,7 @@ public: m_assembler.lbu(dest, addrTempRegister, 0); } - void load8Signed(BaseIndex address, RegisterID dest) + void load8SignedExtendTo32(BaseIndex address, RegisterID dest) { if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) { @@ -919,7 +919,7 @@ public: } } - void load16Signed(BaseIndex address, RegisterID dest) + void load16SignedExtendTo32(BaseIndex address, RegisterID dest) { if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) { @@ -2120,6 +2120,16 @@ public: return temp; } + Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) + { + m_fixedWidth = true; + load32(left, dataTempRegister); + dataLabel = moveWithPatch(initialRightValue, immTempRegister); + Jump temp = branch32(cond, dataTempRegister, immTempRegister); + m_fixedWidth = false; + return temp; + } + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { m_fixedWidth = true; diff --git a/assembler/MacroAssemblerSH4.h b/assembler/MacroAssemblerSH4.h index 0e9c4db..6857c60 100644 --- a/assembler/MacroAssemblerSH4.h +++ b/assembler/MacroAssemblerSH4.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2013 Cisco Systems, Inc. All rights reserved. * Copyright (C) 2009-2011 STMicroelectronics. All rights reserved. - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,7 +36,7 @@ namespace JSC { -class MacroAssemblerSH4 : public AbstractMacroAssembler<SH4Assembler> { +class MacroAssemblerSH4 : public AbstractMacroAssembler<SH4Assembler, MacroAssemblerSH4> { public: typedef SH4Assembler::FPRegisterID FPRegisterID; @@ -718,13 +718,13 @@ public: m_assembler.extub(dest, dest); } - void load8Signed(BaseIndex address, RegisterID dest) + void load8SignedExtendTo32(BaseIndex address, RegisterID dest) { RegisterID scr = claimScratch(); move(address.index, scr); lshift32(TrustedImm32(address.scale), scr); add32(address.base, scr); - load8Signed(scr, address.offset, dest); + load8SignedExtendTo32(scr, address.offset, dest); releaseScratch(scr); } @@ -770,7 +770,7 @@ public: releaseScratch(scr); } - void load8Signed(RegisterID base, int offset, RegisterID dest) + void load8SignedExtendTo32(RegisterID base, int offset, RegisterID dest) { if (!offset) { m_assembler.movbMemReg(base, dest); @@ -798,7 +798,7 @@ public: void load8(RegisterID base, int offset, RegisterID dest) { - load8Signed(base, offset, dest); + load8SignedExtendTo32(base, offset, dest); m_assembler.extub(dest, dest); } @@ -858,14 +858,14 @@ public: m_assembler.extuw(dest, dest); } - void load16Signed(RegisterID src, RegisterID dest) + void load16SignedExtendTo32(RegisterID src, RegisterID dest) { m_assembler.movwMemReg(src, dest); } void load16(BaseIndex address, RegisterID dest) { - load16Signed(address, dest); + load16SignedExtendTo32(address, dest); m_assembler.extuw(dest, dest); } @@ -875,7 +875,7 @@ public: m_assembler.extuw(dest, dest); } - void load16Signed(BaseIndex address, RegisterID dest) + void load16SignedExtendTo32(BaseIndex address, RegisterID dest) { RegisterID scr = claimScratch(); @@ -887,7 +887,7 @@ public: m_assembler.movwR0mr(scr, dest); else { add32(address.base, scr); - load16Signed(scr, dest); + load16SignedExtendTo32(scr, dest); } releaseScratch(scr); @@ -931,6 +931,19 @@ public: releaseScratch(srcval); } + void store8(TrustedImm32 imm, Address address) + { + ASSERT((imm.m_value >= -128) && (imm.m_value <= 127)); + RegisterID dstptr = claimScratch(); + move(address.base, dstptr); + add32(TrustedImm32(address.offset), dstptr); + RegisterID srcval = claimScratch(); + move(imm, srcval); + m_assembler.movbRegMem(srcval, dstptr); + releaseScratch(dstptr); + releaseScratch(srcval); + } + void store16(RegisterID src, BaseIndex address) { RegisterID scr = claimScratch(); @@ -1733,6 +1746,14 @@ public: return dataLabel; } + DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest) + { + m_assembler.ensureSpace(m_assembler.maxInstructionSize, sizeof(uint32_t)); + DataLabel32 dataLabel(this); + m_assembler.loadConstantUnReusable(static_cast<uint32_t>(initialValue.m_value), dest); + return dataLabel; + } + void move(RegisterID src, RegisterID dest) { if (src != dest) @@ -2140,6 +2161,29 @@ public: return result ? branchTrue() : branchFalse(); } + Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == PositiveOrZero) || (cond == Zero) || (cond == NonZero)); + + if (cond == Overflow) { + RegisterID srcVal = claimScratch(); + load32(src, srcVal); + m_assembler.addvlRegReg(srcVal, dest); + releaseScratch(srcVal); + return branchTrue(); + } + + add32(src, dest); + + if ((cond == Signed) || (cond == PositiveOrZero)) { + m_assembler.cmppz(dest); + return (cond == Signed) ? branchFalse() : branchTrue(); + } + + compare32(0, dest, Equal); + return (cond == NonZero) ? branchFalse() : branchTrue(); + } + Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); @@ -2419,6 +2463,23 @@ public: return branchTrue(); } + Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) + { + RegisterID scr = claimScratch(); + + m_assembler.loadConstant(left.offset, scr); + m_assembler.addlRegReg(left.base, scr); + m_assembler.movlMemReg(scr, scr); + RegisterID scr1 = claimScratch(); + m_assembler.ensureSpace(m_assembler.maxInstructionSize + 10, 2 * sizeof(uint32_t)); + dataLabel = moveWithPatch(initialRightValue, scr1); + m_assembler.cmplRegReg(scr1, scr, SH4Condition(cond)); + releaseScratch(scr); + releaseScratch(scr1); + + return (cond == NotEqual) ? branchFalse() : branchTrue(); + } + void ret() { m_assembler.ret(); @@ -2468,6 +2529,18 @@ public: m_assembler.synco(); } + void abortWithReason(AbortReason reason) + { + move(TrustedImm32(reason), SH4Registers::r0); + breakpoint(); + } + + void abortWithReason(AbortReason reason, intptr_t misc) + { + move(TrustedImm32(misc), SH4Registers::r1); + abortWithReason(reason); + } + static FunctionPtr readCallTarget(CodeLocationCall call) { return FunctionPtr(reinterpret_cast<void(*)()>(SH4Assembler::readCallTarget(call.dataLocation()))); @@ -2485,6 +2558,8 @@ public: static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; } + static bool canJumpReplacePatchableBranch32WithPatch() { return false; } + static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) { return label.labelAtOffset(0); @@ -2501,11 +2576,22 @@ public: return CodeLocationLabel(); } + static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32) + { + UNREACHABLE_FOR_PLATFORM(); + return CodeLocationLabel(); + } + static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*) { UNREACHABLE_FOR_PLATFORM(); } + static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t) + { + UNREACHABLE_FOR_PLATFORM(); + } + protected: SH4Assembler::Condition SH4Condition(RelationalCondition cond) { diff --git a/assembler/MacroAssemblerX86.h b/assembler/MacroAssemblerX86.h index 5641685..bdd9e57 100644 --- a/assembler/MacroAssemblerX86.h +++ b/assembler/MacroAssemblerX86.h @@ -30,10 +30,6 @@ #include "MacroAssemblerX86Common.h" -#if USE(MASM_PROBE) -#include <wtf/StdLibExtras.h> -#endif - namespace JSC { class MacroAssemblerX86 : public MacroAssemblerX86Common { @@ -168,14 +164,14 @@ public: m_assembler.movb_i8m(imm.m_value, address); } - // Possibly clobbers src. - // FIXME: Don't do that. - // https://bugs.webkit.org/show_bug.cgi?id=131690 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2) { + ASSERT(isSSE2Present()); + m_assembler.pextrw_irr(3, src, dest1); + m_assembler.pextrw_irr(2, src, dest2); + lshift32(TrustedImm32(16), dest1); + or32(dest1, dest2); movePackedToInt32(src, dest1); - rshiftPacked(TrustedImm32(32), src); - movePackedToInt32(src, dest2); } void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch) @@ -287,7 +283,6 @@ public: } static bool supportsFloatingPoint() { return isSSE2Present(); } - // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() static bool supportsFloatingPointTruncate() { return isSSE2Present(); } static bool supportsFloatingPointSqrt() { return isSSE2Present(); } static bool supportsFloatingPointAbs() { return isSSE2Present(); } @@ -350,11 +345,6 @@ public: X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), initialValue, 0, address.base); } -#if USE(MASM_PROBE) - // For details about probe(), see comment in MacroAssemblerX86_64.h. - void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); -#endif // USE(MASM_PROBE) - private: friend class LinkBuffer; friend class RepatchBuffer; @@ -373,46 +363,8 @@ private: { X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); } - -#if USE(MASM_PROBE) - inline TrustedImm32 trustedImm32FromPtr(void* ptr) - { - return TrustedImm32(TrustedImmPtr(ptr)); - } - - inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function) - { - return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); - } - - inline TrustedImm32 trustedImm32FromPtr(void (*function)()) - { - return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); - } -#endif }; -#if USE(MASM_PROBE) - -extern "C" void ctiMasmProbeTrampoline(); - -// For details on "What code is emitted for the probe?" and "What values are in -// the saved registers?", see comment for MacroAssemblerX86::probe() in -// MacroAssemblerX86_64.h. - -inline void MacroAssemblerX86::probe(MacroAssemblerX86::ProbeFunction function, void* arg1, void* arg2) -{ - push(RegisterID::esp); - push(RegisterID::eax); - push(trustedImm32FromPtr(arg2)); - push(trustedImm32FromPtr(arg1)); - push(trustedImm32FromPtr(function)); - - move(trustedImm32FromPtr(ctiMasmProbeTrampoline), RegisterID::eax); - call(RegisterID::eax); -} -#endif // USE(MASM_PROBE) - } // namespace JSC #endif // ENABLE(ASSEMBLER) diff --git a/assembler/MacroAssemblerX86Common.cpp b/assembler/MacroAssemblerX86Common.cpp index 0fab05f..0108ef4 100644 --- a/assembler/MacroAssemblerX86Common.cpp +++ b/assembler/MacroAssemblerX86Common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,53 +30,120 @@ namespace JSC { -#if USE(MASM_PROBE) +#if ENABLE(MASM_PROBE) -void MacroAssemblerX86Common::ProbeContext::dumpCPURegisters(const char* indentation) +#define INDENT printIndent(indentation) + +void MacroAssemblerX86Common::printCPURegisters(MacroAssemblerX86Common::CPUState& cpu, int indentation) { #if CPU(X86) - #define DUMP_GPREGISTER(_type, _regName) { \ + #define PRINT_GPREGISTER(_type, _regName) { \ int32_t value = reinterpret_cast<int32_t>(cpu._regName); \ - dataLogF("%s %6s: 0x%08x %d\n", indentation, #_regName, value, value) ; \ + INDENT, dataLogF("%6s: 0x%08x %d\n", #_regName, value, value) ; \ } #elif CPU(X86_64) - #define DUMP_GPREGISTER(_type, _regName) { \ + #define PRINT_GPREGISTER(_type, _regName) { \ int64_t value = reinterpret_cast<int64_t>(cpu._regName); \ - dataLogF("%s %6s: 0x%016llx %lld\n", indentation, #_regName, value, value) ; \ + INDENT, dataLogF("%6s: 0x%016llx %lld\n", #_regName, value, value) ; \ } #endif - FOR_EACH_CPU_GPREGISTER(DUMP_GPREGISTER) - FOR_EACH_CPU_SPECIAL_REGISTER(DUMP_GPREGISTER) - #undef DUMP_GPREGISTER + FOR_EACH_CPU_GPREGISTER(PRINT_GPREGISTER) + FOR_EACH_CPU_SPECIAL_REGISTER(PRINT_GPREGISTER) + #undef PRINT_GPREGISTER - #define DUMP_FPREGISTER(_type, _regName) { \ - uint32_t* u = reinterpret_cast<uint32_t*>(&cpu._regName); \ + #define PRINT_FPREGISTER(_type, _regName) { \ + uint64_t* u = reinterpret_cast<uint64_t*>(&cpu._regName); \ double* d = reinterpret_cast<double*>(&cpu._regName); \ - dataLogF("%s %6s: 0x%08x%08x 0x%08x%08x %12g %12g\n", \ - indentation, #_regName, u[3], u[2], u[1], u[0], d[1], d[0]); \ + INDENT, dataLogF("%6s: 0x%016llx %.13g\n", #_regName, *u, *d); \ } - FOR_EACH_CPU_FPREGISTER(DUMP_FPREGISTER) - #undef DUMP_FPREGISTER + FOR_EACH_CPU_FPREGISTER(PRINT_FPREGISTER) + #undef PRINT_FPREGISTER } -void MacroAssemblerX86Common::ProbeContext::dump(const char* indentation) +#undef INDENT + +void MacroAssemblerX86Common::printRegister(MacroAssemblerX86Common::CPUState& cpu, RegisterID regID) { - if (!indentation) - indentation = ""; + const char* name = CPUState::registerName(regID); + union { + void* voidPtr; + intptr_t intptrValue; + } u; + u.voidPtr = cpu.registerValue(regID); + dataLogF("%s:<%p %ld>", name, u.voidPtr, u.intptrValue); +} - dataLogF("%sProbeContext %p {\n", indentation, this); - dataLogF("%s probeFunction: %p\n", indentation, probeFunction); - dataLogF("%s arg1: %p %llu\n", indentation, arg1, reinterpret_cast<int64_t>(arg1)); - dataLogF("%s arg2: %p %llu\n", indentation, arg2, reinterpret_cast<int64_t>(arg2)); - dataLogF("%s cpu: {\n", indentation); +void MacroAssemblerX86Common::printRegister(MacroAssemblerX86Common::CPUState& cpu, FPRegisterID regID) +{ + const char* name = CPUState::registerName(regID); + union { + double doubleValue; + uint64_t uint64Value; + } u; + u.doubleValue = cpu.registerValue(regID); + dataLogF("%s:<0x%016llx %.13g>", name, u.uint64Value, u.doubleValue); +} - dumpCPURegisters(indentation); +extern "C" void ctiMasmProbeTrampoline(); - dataLogF("%s }\n", indentation); - dataLogF("%s}\n", indentation); +// What code is emitted for the probe? +// ================================== +// We want to keep the size of the emitted probe invocation code as compact as +// possible to minimize the perturbation to the JIT generated code. However, +// we also need to preserve the CPU registers and set up the ProbeContext to be +// passed to the user probe function. +// +// Hence, we do only the minimum here to preserve a scratch register (i.e. rax +// in this case) and the stack pointer (i.e. rsp), and pass the probe arguments. +// We'll let the ctiMasmProbeTrampoline handle the rest of the probe invocation +// work i.e. saving the CPUState (and setting up the ProbeContext), calling the +// user probe function, and restoring the CPUState before returning to JIT +// generated code. +// +// What registers need to be saved? +// =============================== +// The registers are saved for 2 reasons: +// 1. To preserve their state in the JITted code. This means that all registers +// that are not callee saved needs to be saved. We also need to save the +// condition code registers because the probe can be inserted between a test +// and a branch. +// 2. To allow the probe to inspect the values of the registers for debugging +// purposes. This means all registers need to be saved. +// +// In summary, save everything. But for reasons stated above, we should do the +// minimum here and let ctiMasmProbeTrampoline do the heavy lifting to save the +// full set. +// +// What values are in the saved registers? +// ====================================== +// Conceptually, the saved registers should contain values as if the probe +// is not present in the JIT generated code. Hence, they should contain values +// that are expected at the start of the instruction immediately following the +// probe. +// +// Specifically, the saved stack pointer register will point to the stack +// position before we push the ProbeContext frame. The saved rip will point to +// the address of the instruction immediately following the probe. + +void MacroAssemblerX86Common::probe(MacroAssemblerX86Common::ProbeFunction function, void* arg1, void* arg2) +{ + push(RegisterID::esp); + push(RegisterID::eax); + move(TrustedImmPtr(arg2), RegisterID::eax); + push(RegisterID::eax); + move(TrustedImmPtr(arg1), RegisterID::eax); + push(RegisterID::eax); + move(TrustedImmPtr(reinterpret_cast<void*>(function)), RegisterID::eax); + push(RegisterID::eax); + move(TrustedImmPtr(reinterpret_cast<void*>(ctiMasmProbeTrampoline)), RegisterID::eax); + call(RegisterID::eax); } -#endif // USE(MASM_PROBE) +#endif // ENABLE(MASM_PROBE) + +#if CPU(X86) && !OS(MAC_OS_X) +MacroAssemblerX86Common::SSE2CheckState MacroAssemblerX86Common::s_sse2CheckState = NotCheckedSSE2; +#endif } // namespace JSC diff --git a/assembler/MacroAssemblerX86Common.h b/assembler/MacroAssemblerX86Common.h index 2466ac3..b3b5074 100644 --- a/assembler/MacroAssemblerX86Common.h +++ b/assembler/MacroAssemblerX86Common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,7 @@ namespace JSC { -class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> { +class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler, MacroAssemblerX86Common> { public: #if CPU(X86_64) static const X86Registers::RegisterID scratchRegister = X86Registers::r11; @@ -183,6 +183,18 @@ public: and32(imm, dest); } + void countLeadingZeros32(RegisterID src, RegisterID dst) + { + m_assembler.bsr_rr(src, dst); + Jump srcIsNonZero = m_assembler.jCC(x86Condition(NonZero)); + move(TrustedImm32(32), dst); + + Jump skipNonZeroCase = jump(); + srcIsNonZero.link(this); + xor32(TrustedImm32(0x1f), dst); + skipNonZeroCase.link(this); + } + void lshift32(RegisterID shift_amount, RegisterID dest) { ASSERT(shift_amount != dest); @@ -525,12 +537,12 @@ public: m_assembler.movzbl_mr(address.offset, address.base, dest); } - void load8Signed(BaseIndex address, RegisterID dest) + void load8SignedExtendTo32(BaseIndex address, RegisterID dest) { m_assembler.movsbl_mr(address.offset, address.base, address.index, address.scale, dest); } - void load8Signed(ImplicitAddress address, RegisterID dest) + void load8SignedExtendTo32(ImplicitAddress address, RegisterID dest) { m_assembler.movsbl_mr(address.offset, address.base, dest); } @@ -545,12 +557,12 @@ public: m_assembler.movzwl_mr(address.offset, address.base, dest); } - void load16Signed(BaseIndex address, RegisterID dest) + void load16SignedExtendTo32(BaseIndex address, RegisterID dest) { m_assembler.movswl_mr(address.offset, address.base, address.index, address.scale, dest); } - void load16Signed(Address address, RegisterID dest) + void load16SignedExtendTo32(Address address, RegisterID dest) { m_assembler.movswl_mr(address.offset, address.base, dest); } @@ -909,8 +921,17 @@ public: m_assembler.cvttsd2si_rr(src, dest); // If the result is zero, it might have been -0.0, and the double comparison won't catch this! +#if CPU(X86_64) + if (negZeroCheck) { + Jump valueIsNonZero = branchTest32(NonZero, dest); + m_assembler.movmskpd_rr(src, scratchRegister); + failureCases.append(branchTest32(NonZero, scratchRegister, TrustedImm32(1))); + valueIsNonZero.link(this); + } +#else if (negZeroCheck) failureCases.append(branchTest32(Zero, dest)); +#endif // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. convertInt32ToDouble(dest, fpTemp); @@ -1469,28 +1490,14 @@ public: return X86Assembler::maxJumpReplacementSize(); } -#if USE(MASM_PROBE) - struct CPUState { - #define DECLARE_REGISTER(_type, _regName) \ - _type _regName; - FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) - #undef DECLARE_REGISTER - }; - - struct ProbeContext; - typedef void (*ProbeFunction)(struct ProbeContext*); - - struct ProbeContext { - ProbeFunction probeFunction; - void* arg1; - void* arg2; - CPUState cpu; - - void dump(const char* indentation = 0); - private: - void dumpCPURegisters(const char* indentation); - }; -#endif // USE(MASM_PROBE) +#if ENABLE(MASM_PROBE) + // Methods required by the MASM_PROBE mechanism as defined in + // AbstractMacroAssembler.h. + static void printCPURegisters(CPUState&, int indentation = 0); + static void printRegister(CPUState&, RegisterID); + static void printRegister(CPUState&, FPRegisterID); + void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); +#endif // ENABLE(MASM_PROBE) protected: X86Assembler::Condition x86Condition(RelationalCondition cond) diff --git a/assembler/MacroAssemblerX86_64.h b/assembler/MacroAssemblerX86_64.h index 5f92261..920de74 100644 --- a/assembler/MacroAssemblerX86_64.h +++ b/assembler/MacroAssemblerX86_64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,10 +30,6 @@ #include "MacroAssemblerX86Common.h" -#if USE(MASM_PROBE) -#include <wtf/StdLibExtras.h> -#endif - #define REPTACH_OFFSET_CALL_R11 3 inline bool CAN_SIGN_EXTEND_32_64(int64_t value) { return value == (int64_t)(int32_t)value; } @@ -203,11 +199,11 @@ public: // Copy argument 5 load64(Address(X86Registers::esp, 4 * sizeof(int64_t)), scratchRegister); - store64(scratchRegister, Address(X86Registers::esp, -4 * sizeof(int64_t))); + store64(scratchRegister, Address(X86Registers::esp, -4 * static_cast<int32_t>(sizeof(int64_t)))); // Copy argument 6 load64(Address(X86Registers::esp, 5 * sizeof(int64_t)), scratchRegister); - store64(scratchRegister, Address(X86Registers::esp, -3 * sizeof(int64_t))); + store64(scratchRegister, Address(X86Registers::esp, -3 * static_cast<int32_t>(sizeof(int64_t)))); // We also need to allocate the shadow space on the stack for the 4 parameter registers. // Also, we should allocate 16 bytes for the frame pointer, and return address (not populated). @@ -295,7 +291,10 @@ public: void add64(TrustedImm32 imm, Address address) { - m_assembler.addq_im(imm.m_value, address.offset, address.base); + if (imm.m_value == 1) + m_assembler.incq_m(address.offset, address.base); + else + m_assembler.addq_im(imm.m_value, address.offset, address.base); } void add64(TrustedImm32 imm, AbsoluteAddress address) @@ -335,6 +334,11 @@ public: m_assembler.sarq_i8r(imm.m_value, dest); } + void urshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.shrq_i8r(imm.m_value, dest); + } + void mul64(RegisterID src, RegisterID dest) { m_assembler.imulq_rr(src, dest); @@ -780,7 +784,6 @@ public: } static bool supportsFloatingPoint() { return true; } - // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() static bool supportsFloatingPointTruncate() { return true; } static bool supportsFloatingPointSqrt() { return true; } static bool supportsFloatingPointAbs() { return true; } @@ -841,26 +844,6 @@ public: X86Assembler::revertJumpTo_movq_i64r(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), scratchRegister); } -#if USE(MASM_PROBE) - // This function emits code to preserve the CPUState (e.g. registers), - // call a user supplied probe function, and restore the CPUState before - // continuing with other JIT generated code. - // - // The user supplied probe function will be called with a single pointer to - // a ProbeContext struct (defined above) which contains, among other things, - // the preserved CPUState. This allows the user probe function to inspect - // the CPUState at that point in the JIT generated code. - // - // If the user probe function alters the register values in the ProbeContext, - // the altered values will be loaded into the CPU registers when the probe - // returns. - // - // The ProbeContext is stack allocated and is only valid for the duration - // of the call to the user probe function. - - void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); -#endif // USE(MASM_PROBE) - private: friend class LinkBuffer; friend class RepatchBuffer; @@ -882,69 +865,8 @@ private: { X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); } - -#if USE(MASM_PROBE) - inline TrustedImm64 trustedImm64FromPtr(void* ptr) - { - return TrustedImm64(TrustedImmPtr(ptr)); - } - - inline TrustedImm64 trustedImm64FromPtr(ProbeFunction function) - { - return TrustedImm64(TrustedImmPtr(reinterpret_cast<void*>(function))); - } - - inline TrustedImm64 trustedImm64FromPtr(void (*function)()) - { - return TrustedImm64(TrustedImmPtr(reinterpret_cast<void*>(function))); - } -#endif }; -#if USE(MASM_PROBE) - -extern "C" void ctiMasmProbeTrampoline(); - -// What code is emitted for the probe? -// ================================== -// We want to keep the size of the emitted probe invocation code as compact as -// possible to minimize the perturbation to the JIT generated code. However, -// we also need to preserve the CPU registers and set up the ProbeContext to be -// passed to the user probe function. -// -// Hence, we do only the minimum here to preserve a scratch register (i.e. rax -// in this case) and the stack pointer (i.e. rsp), and pass the probe arguments. -// We'll let the ctiMasmProbeTrampoline handle the rest of the probe invocation -// work i.e. saving the CPUState (and setting up the ProbeContext), calling the -// user probe function, and restoring the CPUState before returning to JIT -// generated code. -// -// What values are in the saved registers? -// ====================================== -// Conceptually, the saved registers should contain values as if the probe -// is not present in the JIT generated code. Hence, they should contain values -// that are expected at the start of the instruction immediately following the -// probe. -// -// Specifcally, the saved stack pointer register will point to the stack -// position before we push the ProbeContext frame. The saved rip will point to -// the address of the instruction immediately following the probe. - -inline void MacroAssemblerX86_64::probe(MacroAssemblerX86_64::ProbeFunction function, void* arg1, void* arg2) -{ - push(RegisterID::esp); - push(RegisterID::eax); - move(trustedImm64FromPtr(arg2), RegisterID::eax); - push(RegisterID::eax); - move(trustedImm64FromPtr(arg1), RegisterID::eax); - push(RegisterID::eax); - move(trustedImm64FromPtr(function), RegisterID::eax); - push(RegisterID::eax); - move(trustedImm64FromPtr(ctiMasmProbeTrampoline), RegisterID::eax); - call(RegisterID::eax); -} -#endif // USE(MASM_PROBE) - } // namespace JSC #endif // ENABLE(ASSEMBLER) diff --git a/assembler/X86Assembler.h b/assembler/X86Assembler.h index 4a01c72..da3181e 100644 --- a/assembler/X86Assembler.h +++ b/assembler/X86Assembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,105 +35,89 @@ #include <wtf/Assertions.h> #include <wtf/Vector.h> -#if USE(MASM_PROBE) -#include <xmmintrin.h> -#endif - namespace JSC { inline bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(signed char)value; } namespace X86Registers { - typedef enum { - eax, - ecx, - edx, - ebx, - esp, - ebp, - esi, - edi, -#if CPU(X86_64) - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, -#endif - } RegisterID; +#define FOR_EACH_CPU_REGISTER(V) \ + FOR_EACH_CPU_GPREGISTER(V) \ + FOR_EACH_CPU_SPECIAL_REGISTER(V) \ + FOR_EACH_CPU_FPREGISTER(V) + +// The following are defined as pairs of the following value: +// 1. type of the storage needed to save the register value by the JIT probe. +// 2. name of the register. +#define FOR_EACH_CPU_GPREGISTER(V) \ + V(void*, eax) \ + V(void*, ecx) \ + V(void*, edx) \ + V(void*, ebx) \ + V(void*, esp) \ + V(void*, ebp) \ + V(void*, esi) \ + V(void*, edi) \ + FOR_EACH_X86_64_CPU_GPREGISTER(V) + +#define FOR_EACH_CPU_SPECIAL_REGISTER(V) \ + V(void*, eip) \ + V(void*, eflags) \ + +// Note: the JITs only stores double values in the FP registers. +#define FOR_EACH_CPU_FPREGISTER(V) \ + V(double, xmm0) \ + V(double, xmm1) \ + V(double, xmm2) \ + V(double, xmm3) \ + V(double, xmm4) \ + V(double, xmm5) \ + V(double, xmm6) \ + V(double, xmm7) \ + FOR_EACH_X86_64_CPU_FPREGISTER(V) - typedef enum { - xmm0, - xmm1, - xmm2, - xmm3, - xmm4, - xmm5, - xmm6, - xmm7, +#if CPU(X86) -#if CPU(X86_64) - xmm8, - xmm9, - xmm10, - xmm11, - xmm12, - xmm13, - xmm14, - xmm15, -#endif - } XMMRegisterID; - -#if USE(MASM_PROBE) - #define FOR_EACH_CPU_REGISTER(V) \ - FOR_EACH_CPU_GPREGISTER(V) \ - FOR_EACH_CPU_SPECIAL_REGISTER(V) \ - FOR_EACH_CPU_FPREGISTER(V) - - #define FOR_EACH_CPU_GPREGISTER(V) \ - V(void*, eax) \ - V(void*, ebx) \ - V(void*, ecx) \ - V(void*, edx) \ - V(void*, esi) \ - V(void*, edi) \ - V(void*, ebp) \ - V(void*, esp) \ - FOR_EACH_X86_64_CPU_GPREGISTER(V) - - #define FOR_EACH_CPU_SPECIAL_REGISTER(V) \ - V(void*, eip) \ - V(void*, eflags) \ - - #define FOR_EACH_CPU_FPREGISTER(V) \ - V(__m128, xmm0) \ - V(__m128, xmm1) \ - V(__m128, xmm2) \ - V(__m128, xmm3) \ - V(__m128, xmm4) \ - V(__m128, xmm5) \ - V(__m128, xmm6) \ - V(__m128, xmm7) +#define FOR_EACH_X86_64_CPU_GPREGISTER(V) // Nothing to add. +#define FOR_EACH_X86_64_CPU_FPREGISTER(V) // Nothing to add. -#if CPU(X86) - #define FOR_EACH_X86_64_CPU_GPREGISTER(V) // Nothing to add. #elif CPU(X86_64) - #define FOR_EACH_X86_64_CPU_GPREGISTER(V) \ - V(void*, r8) \ - V(void*, r9) \ - V(void*, r10) \ - V(void*, r11) \ - V(void*, r12) \ - V(void*, r13) \ - V(void*, r14) \ - V(void*, r15) + +#define FOR_EACH_X86_64_CPU_GPREGISTER(V) \ + V(void*, r8) \ + V(void*, r9) \ + V(void*, r10) \ + V(void*, r11) \ + V(void*, r12) \ + V(void*, r13) \ + V(void*, r14) \ + V(void*, r15) + +#define FOR_EACH_X86_64_CPU_FPREGISTER(V) \ + V(double, xmm8) \ + V(double, xmm9) \ + V(double, xmm10) \ + V(double, xmm11) \ + V(double, xmm12) \ + V(double, xmm13) \ + V(double, xmm14) \ + V(double, xmm15) + #endif // CPU(X86_64) -#endif // USE(MASM_PROBE) -} + +typedef enum { + #define DECLARE_REGISTER(_type, _regName) _regName, + FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER +} RegisterID; + +typedef enum { + #define DECLARE_REGISTER(_type, _regName) _regName, + FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER) + #undef DECLARE_REGISTER +} XMMRegisterID; + +} // namespace X86Register class X86Assembler { public: @@ -269,6 +253,7 @@ private: OP2_CVTSS2SD_VsdWsd = 0x5A, OP2_SUBSD_VsdWsd = 0x5C, OP2_DIVSD_VsdWsd = 0x5E, + OP2_MOVMSKPD_VdEd = 0x50, OP2_SQRTSD_VsdWsd = 0x51, OP2_ANDNPD_VpdWpd = 0x55, OP2_XORPD_VpdWpd = 0x57, @@ -279,6 +264,7 @@ private: OP2_3BYTE_ESCAPE = 0xAE, OP2_IMUL_GvEv = 0xAF, OP2_MOVZX_GvEb = 0xB6, + OP2_BSR = 0xBD, OP2_MOVSX_GvEb = 0xBE, OP2_MOVZX_GvEw = 0xB7, OP2_MOVSX_GvEw = 0xBF, @@ -576,6 +562,11 @@ public: { m_formatter.oneByteOp64(OP_GROUP5_Ev, GROUP1_OP_ADD, dst); } + + void incq_m(int offset, RegisterID base) + { + m_formatter.oneByteOp64(OP_GROUP5_Ev, GROUP1_OP_ADD, base, offset); + } #endif // CPU(X86_64) void negl_r(RegisterID dst) @@ -831,6 +822,11 @@ public: #endif + void bsr_rr(RegisterID src, RegisterID dst) + { + m_formatter.twoByteOp(OP2_BSR, dst, src); + } + void sarl_i8r(int imm, RegisterID dst) { if (imm == 1) @@ -892,6 +888,16 @@ public: } } + void shrq_i8r(int imm, RegisterID dst) + { + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst); + m_formatter.immediate8(imm); + } + } + void shlq_i8r(int imm, RegisterID dst) { if (imm == 1) @@ -1800,6 +1806,12 @@ public: } #if CPU(X86_64) + void movmskpd_rr(XMMRegisterID src, RegisterID dst) + { + m_formatter.prefix(PRE_SSE_66); + m_formatter.twoByteOp64(OP2_MOVMSKPD_VdEd, dst, (RegisterID)src); + } + void movq_rr(XMMRegisterID src, RegisterID dst) { m_formatter.prefix(PRE_SSE_66); diff --git a/bindings/ScriptFunctionCall.cpp b/bindings/ScriptFunctionCall.cpp index 2df7876..f7254d9 100644 --- a/bindings/ScriptFunctionCall.cpp +++ b/bindings/ScriptFunctionCall.cpp @@ -121,7 +121,7 @@ Deprecated::ScriptValue ScriptFunctionCall::call(bool& hadException) JSLockHolder lock(m_exec); - JSValue function = thisObject->get(m_exec, Identifier(m_exec, m_name)); + JSValue function = thisObject->get(m_exec, Identifier::fromString(m_exec, m_name)); if (m_exec->hadException()) { hadException = true; return Deprecated::ScriptValue(); @@ -133,11 +133,11 @@ Deprecated::ScriptValue ScriptFunctionCall::call(bool& hadException) return Deprecated::ScriptValue(); JSValue result; - JSValue exception; + NakedPtr<Exception> exception; if (m_callHandler) - result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, &exception); + result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, exception); else - result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, &exception); + result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, exception); if (exception) { hadException = true; diff --git a/bindings/ScriptFunctionCall.h b/bindings/ScriptFunctionCall.h index 7c3e78c..25cdfb2 100644 --- a/bindings/ScriptFunctionCall.h +++ b/bindings/ScriptFunctionCall.h @@ -71,7 +71,7 @@ private: class JS_EXPORT_PRIVATE ScriptFunctionCall : public ScriptCallArgumentHandler { public: - typedef JSC::JSValue (*ScriptFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception); + typedef JSC::JSValue (*ScriptFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>&); ScriptFunctionCall(const ScriptObject& thisObject, const String& name, ScriptFunctionCallHandler handler = nullptr); ScriptValue call(bool& hadException); ScriptValue call(); diff --git a/bindings/ScriptValue.cpp b/bindings/ScriptValue.cpp index 004ff24..153b033 100644 --- a/bindings/ScriptValue.cpp +++ b/bindings/ScriptValue.cpp @@ -97,8 +97,7 @@ bool ScriptValue::isFunction() const return getCallData(m_value.get(), callData) != CallTypeNone; } -#if ENABLE(INSPECTOR) -static PassRefPtr<InspectorValue> jsToInspectorValue(ExecState* scriptState, JSValue value, int maxDepth) +static RefPtr<InspectorValue> jsToInspectorValue(ExecState* scriptState, JSValue value, int maxDepth) { if (!value) { ASSERT_NOT_REACHED(); @@ -114,14 +113,16 @@ static PassRefPtr<InspectorValue> jsToInspectorValue(ExecState* scriptState, JSV return InspectorValue::null(); if (value.isBoolean()) return InspectorBasicValue::create(value.asBoolean()); - if (value.isNumber()) + if (value.isNumber() && value.isDouble()) return InspectorBasicValue::create(value.asNumber()); + if (value.isNumber() && value.isMachineInt()) + return InspectorBasicValue::create(static_cast<int>(value.asMachineInt())); if (value.isString()) return InspectorString::create(value.getString(scriptState)); if (value.isObject()) { if (isJSArray(value)) { - RefPtr<InspectorArray> inspectorArray = InspectorArray::create(); + Ref<InspectorArray> inspectorArray = InspectorArray::create(); JSArray* array = asArray(value); unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { @@ -129,34 +130,33 @@ static PassRefPtr<InspectorValue> jsToInspectorValue(ExecState* scriptState, JSV RefPtr<InspectorValue> elementValue = jsToInspectorValue(scriptState, element, maxDepth); if (!elementValue) return nullptr; - inspectorArray->pushValue(elementValue); + inspectorArray->pushValue(WTF::move(elementValue)); } - return inspectorArray; + return WTF::move(inspectorArray); } - RefPtr<InspectorObject> inspectorObject = InspectorObject::create(); + Ref<InspectorObject> inspectorObject = InspectorObject::create(); JSObject* object = value.getObject(); PropertyNameArray propertyNames(scriptState); - object->methodTable()->getOwnPropertyNames(object, scriptState, propertyNames, ExcludeDontEnumProperties); + object->methodTable()->getOwnPropertyNames(object, scriptState, propertyNames, EnumerationMode()); for (size_t i = 0; i < propertyNames.size(); i++) { const Identifier& name = propertyNames[i]; JSValue propertyValue = object->get(scriptState, name); RefPtr<InspectorValue> inspectorValue = jsToInspectorValue(scriptState, propertyValue, maxDepth); if (!inspectorValue) return nullptr; - inspectorObject->setValue(name.string(), inspectorValue); + inspectorObject->setValue(name.string(), WTF::move(inspectorValue)); } - return inspectorObject; + return WTF::move(inspectorObject); } ASSERT_NOT_REACHED(); return nullptr; } -PassRefPtr<InspectorValue> ScriptValue::toInspectorValue(ExecState* scriptState) const +RefPtr<InspectorValue> ScriptValue::toInspectorValue(ExecState* scriptState) const { JSLockHolder holder(scriptState); return jsToInspectorValue(scriptState, m_value.get(), InspectorValue::maxDepth); } -#endif // ENABLE(INSPECTOR) } // namespace Deprecated diff --git a/bindings/ScriptValue.h b/bindings/ScriptValue.h index d5fade9..b7b521e 100644 --- a/bindings/ScriptValue.h +++ b/bindings/ScriptValue.h @@ -51,6 +51,7 @@ public: ScriptValue(JSC::VM& vm, JSC::JSValue value) : m_value(vm, value) { } virtual ~ScriptValue(); + operator JSC::JSValue() const { return jsValue(); } JSC::JSValue jsValue() const { return m_value.get(); } bool getString(JSC::ExecState*, String& result) const; String toString(JSC::ExecState*) const; @@ -65,9 +66,7 @@ public: bool operator==(const ScriptValue& other) const { return m_value == other.m_value; } -#if ENABLE(INSPECTOR) - PassRefPtr<Inspector::InspectorValue> toInspectorValue(JSC::ExecState*) const; -#endif + RefPtr<Inspector::InspectorValue> toInspectorValue(JSC::ExecState*) const; private: JSC::Strong<JSC::Unknown> m_value; diff --git a/build-symbol-table-index.py b/build-symbol-table-index.py index fe8469f..06ef030 100755 --- a/build-symbol-table-index.py +++ b/build-symbol-table-index.py @@ -1,9 +1,33 @@ #!/usr/bin/python +# Copyright (C) 2014 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. + import glob import os import subprocess import sys +from sets import Set from operator import itemgetter @@ -14,14 +38,15 @@ print("Building Index Table") if current_arch not in ("x86_64", "arm64"): sys.exit() -binary_file_directory = os.path.join(os.getenv("OBJECT_FILE_DIR_" + os.getenv("CURRENT_VARIANT")), current_arch) +bitcode_file_original_directory = os.path.join(os.getenv("TARGET_TEMP_DIR"), "Objects-" + os.getenv("CURRENT_VARIANT"), current_arch) -if not os.path.isdir(binary_file_directory): - print("Failed to build index table at " + binary_file_directory) +if not os.path.isdir(bitcode_file_original_directory): + print("Failed to build index table at " + bitcode_file_original_directory) sys.exit() framework_directory = os.path.join(os.getenv("BUILT_PRODUCTS_DIR"), os.getenv("JAVASCRIPTCORE_RESOURCES_DIR"), "Runtime", current_arch) + symbol_table_location = os.path.join(framework_directory, "Runtime.symtbl") symbol_table = {} @@ -33,23 +58,36 @@ symbol_table_modification_time = 0 if os.path.isfile(symbol_table_location): symbol_table_modification_time = os.path.getmtime(symbol_table_location) -file_suffix = "bc.gz" +file_suffix = "bc" file_suffix_length = len(file_suffix) +tested_symbols_location = "./tested-symbols.symlst" +include_symbol_table_location = os.path.join(os.getenv("SHARED_DERIVED_FILE_DIR"), "JavaScriptCore/InlineRuntimeSymbolTable.h") + +tested_symbols = Set([]) + +if os.path.isfile(tested_symbols_location): + with open(tested_symbols_location, 'r') as file: + print("Loading tested symbols") + for line in file: + tested_symbols.add(line[:-1]) + +print ("Original directory: " + bitcode_file_original_directory) + for bitcode_file in glob.iglob(os.path.join(framework_directory, "*." + file_suffix)): bitcode_basename = os.path.basename(bitcode_file) - binary_file = os.path.join(binary_file_directory, bitcode_basename[:-file_suffix_length] + "o") - if os.path.getmtime(binary_file) < symbol_table_modification_time: + bitcode_file_original = os.path.join(bitcode_file_original_directory, bitcode_basename[:-file_suffix_length] + "o") + if os.path.getmtime(bitcode_file_original) < symbol_table_modification_time: continue symbol_table_is_out_of_date = True print("Appending symbols from " + bitcode_basename) - lines = subprocess.check_output(["nm", "-U", "-j", binary_file]).splitlines() + lines = subprocess.check_output(["nm", "-U", "-j", bitcode_file]).splitlines() for symbol in lines: - if symbol[:2] == "__" and symbol[-3:] != ".eh": - symbol_table[symbol] = bitcode_basename[1:] + if symbol[:2] == "__" and symbol[-3:] != ".eh" and symbol in tested_symbols: + symbol_table[symbol[1:]] = bitcode_basename if not symbol_table_is_out_of_date: sys.exit() @@ -65,10 +103,14 @@ if os.path.isfile(symbol_table_location): symbol_list = symbol_table.items() -print("Writing symbol table") - -with open(symbol_table_location, "w") as file: - for symbol, location in symbol_list: - file.write("{} {}\n".format(symbol, location)) +print("Writing symbol table: " + symbol_table_location) +print("Writing inline file: " + include_symbol_table_location) +with open(symbol_table_location, "w") as symbol_file: + with open(include_symbol_table_location, "w") as include_file: + include_file.write("#define FOR_EACH_LIBRARY_SYMBOL(macro)") + for symbol, location in symbol_list: + symbol_file.write("{} {}\n".format(symbol, location)) + include_file.write(" \\\nmacro(\"{}\", \"{}\")".format(symbol, location)) + include_file.write("\n") print("Done") diff --git a/build-symbol-table-index.sh b/build-symbol-table-index.sh deleted file mode 100755 index 89610d2..0000000 --- a/build-symbol-table-index.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -# Copyright (C) 2014 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. - -RUNTIME_DERIVED_SOURCES_DIR=${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCoreRuntime -RUNTIME_INSTALL_DIR=${BUILT_PRODUCTS_DIR}/${JAVASCRIPTCORE_RESOURCES_DIR}/Runtime - -for arch in $ARCHS; -do - if [ -d "$RUNTIME_DERIVED_SOURCES_DIR/$arch" ]; - then - mkdir -p "$RUNTIME_INSTALL_DIR/$arch" - cp "$RUNTIME_DERIVED_SOURCES_DIR/$arch"/*.bc.gz "$RUNTIME_INSTALL_DIR/$arch"/. - ${SRCROOT}/build-symbol-table-index.py $arch - fi -done diff --git a/builtins/Array.prototype.js b/builtins/Array.prototype.js index 8566a18..af46dd8 100644 --- a/builtins/Array.prototype.js +++ b/builtins/Array.prototype.js @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,6 +24,80 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +function reduce(callback /*, initialValue */) +{ + "use strict"; + if (this === null) + throw new @TypeError("Array.prototype.reduce requires that |this| not be null"); + + if (this === undefined) + throw new @TypeError("Array.prototype.reduce requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.reduce callback must be a function"); + + if (length === 0 && arguments.length < 2) + throw new @TypeError("reduce of empty array with no initial value"); + + var accumulator, k = 0; + if (arguments.length > 1) + accumulator = arguments[1]; + else { + while (k < length && !(k in array)) + k += 1; + if (k >= length) + throw new @TypeError("reduce of empty array with no initial value"); + accumulator = array[k++]; + } + + while (k < length) { + if (k in array) + accumulator = callback.@call(undefined, accumulator, array[k], k, array); + k += 1; + } + return accumulator; +} + +function reduceRight(callback /*, initialValue */) +{ + "use strict"; + if (this === null) + throw new @TypeError("Array.prototype.reduceRight requires that |this| not be null"); + + if (this === undefined) + throw new @TypeError("Array.prototype.reduceRight requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.reduceRight callback must be a function"); + + if (length === 0 && arguments.length < 2) + throw new @TypeError("reduceRight of empty array with no initial value"); + + var accumulator, k = length - 1; + if (arguments.length > 1) + accumulator = arguments[1]; + else { + while (k >= 0 && !(k in array)) + k -= 1; + if (k < 0) + throw new @TypeError("reduceRight of empty array with no initial value"); + accumulator = array[k--]; + } + + while (k >= 0) { + if (k in array) + accumulator = callback.@call(undefined, accumulator, array[k], k, array); + k -= 1; + } + return accumulator; +} + function every(callback /*, thisArg */) { "use strict"; if (this === null) @@ -32,8 +107,8 @@ function every(callback /*, thisArg */) { throw new @TypeError("Array.prototype.every requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.every callback must be a function"); @@ -58,8 +133,8 @@ function forEach(callback /*, thisArg */) { throw new @TypeError("Array.prototype.forEach requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.forEach callback must be a function"); @@ -80,8 +155,8 @@ function filter(callback /*, thisArg */) { throw new @TypeError("Array.prototype.filter requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.filter callback must be a function"); @@ -92,8 +167,10 @@ function filter(callback /*, thisArg */) { if (!(i in array)) continue; var current = array[i] - if (callback.@call(thisArg, current, i, array)) - result[nextIndex++] = current; + if (callback.@call(thisArg, current, i, array)) { + @putByValDirect(result, nextIndex, current); + ++nextIndex; + } } return result; } @@ -107,8 +184,8 @@ function map(callback /*, thisArg */) { throw new @TypeError("Array.prototype.map requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.map callback must be a function"); @@ -119,7 +196,8 @@ function map(callback /*, thisArg */) { for (var i = 0; i < length; i++) { if (!(i in array)) continue; - result[i] = callback.@call(thisArg, array[i], i, array) + var mappedValue = callback.@call(thisArg, array[i], i, array); + @putByValDirect(result, i, mappedValue); } return result; } @@ -133,8 +211,8 @@ function some(callback /*, thisArg */) { throw new @TypeError("Array.prototype.some requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.some callback must be a function"); @@ -157,7 +235,7 @@ function fill(value /* [, start [, end]] */) if (this === undefined) throw new @TypeError("Array.prototype.fill requires that |this| not be undefined"); var O = @Object(this); - var len = O.length >>> 0; + var len = @toLength(O.length); var relativeStart = 0; if (arguments.length > 1 && arguments[1] !== undefined) relativeStart = arguments[1] | 0; @@ -198,17 +276,16 @@ function find(callback /*, thisArg */) { throw new @TypeError("Array.prototype.find requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.find callback must be a function"); var thisArg = arguments.length > 1 ? arguments[1] : undefined; for (var i = 0; i < length; i++) { - if (!(i in array)) - continue; - if (callback.@call(thisArg, array[i], i, array)) - return array[i]; + var kValue = array[i]; + if (callback.@call(thisArg, kValue, i, array)) + return kValue; } return undefined; } @@ -222,17 +299,346 @@ function findIndex(callback /*, thisArg */) { throw new @TypeError("Array.prototype.findIndex requires that |this| not be undefined"); var array = @Object(this); - var length = array.length >>> 0; - + var length = @toLength(array.length); + if (typeof callback !== "function") throw new @TypeError("Array.prototype.findIndex callback must be a function"); var thisArg = arguments.length > 1 ? arguments[1] : undefined; for (var i = 0; i < length; i++) { - if (!(i in array)) - continue; if (callback.@call(thisArg, array[i], i, array)) return i; } return -1; } + +function includes(searchElement /*, fromIndex*/) { + "use strict"; + if (this === null) + throw new @TypeError("Array.prototype.includes requires that |this| not be null"); + + if (this === undefined) + throw new @TypeError("Array.prototype.includes requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (length === 0) + return false; + + var fromIndex = 0; + if (arguments.length > 1 && arguments[1] !== undefined) + fromIndex = arguments[1] | 0; + + var index; + if (fromIndex >= 0) + index = fromIndex; + else + index = length + fromIndex; + + if (index < 0) + index = 0; + + var currentElement; + for (; index < length; ++index) { + currentElement = array[index]; + // Use SameValueZero comparison, rather than just StrictEquals. + if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement)) + return true; + } + return false; +} + +function sort(comparator) +{ + "use strict"; + + function min(a, b) + { + return a < b ? a : b; + } + + function stringComparator(a, b) + { + var aString = a.string; + var bString = b.string; + + var aLength = aString.length; + var bLength = bString.length; + var length = min(aLength, bLength); + + for (var i = 0; i < length; ++i) { + var aCharCode = aString.@charCodeAt(i); + var bCharCode = bString.@charCodeAt(i); + + if (aCharCode == bCharCode) + continue; + + return aCharCode - bCharCode; + } + + return aLength - bLength; + } + + // Move undefineds and holes to the end of a sparse array. Result is [values..., undefineds..., holes...]. + function compactSparse(array, dst, src, length) + { + var values = [ ]; + var seen = { }; + var valueCount = 0; + var undefinedCount = 0; + + // Clean up after the in-progress non-sparse compaction that failed. + for (var i = dst; i < src; ++i) + delete array[i]; + + for (var object = array; object; object = @Object.@getPrototypeOf(object)) { + var propertyNames = @Object.@getOwnPropertyNames(object); + for (var i = 0; i < propertyNames.length; ++i) { + var index = propertyNames[i]; + if (index < length) { // Exclude non-numeric properties and properties past length. + if (seen[index]) // Exclude duplicates. + continue; + seen[index] = 1; + + var value = array[index]; + delete array[index]; + + if (value === undefined) { + ++undefinedCount; + continue; + } + + array[valueCount++] = value; + } + } + } + + for (var i = valueCount; i < valueCount + undefinedCount; ++i) + array[i] = undefined; + + return valueCount; + } + + function compactSlow(array, length) + { + var holeCount = 0; + + for (var dst = 0, src = 0; src < length; ++src) { + if (!(src in array)) { + ++holeCount; + if (holeCount < 256) + continue; + return compactSparse(array, dst, src, length); + } + + var value = array[src]; + if (value === undefined) + continue; + + array[dst++] = value; + } + + var valueCount = dst; + var undefinedCount = length - valueCount - holeCount; + + for (var i = valueCount; i < valueCount + undefinedCount; ++i) + array[i] = undefined; + + for (var i = valueCount + undefinedCount; i < length; ++i) + delete array[i]; + + return valueCount; + } + + // Move undefineds and holes to the end of an array. Result is [values..., undefineds..., holes...]. + function compact(array, length) + { + for (var i = 0; i < array.length; ++i) { + if (array[i] === undefined) + return compactSlow(array, length); + } + + return length; + } + + function merge(dst, src, srcIndex, srcEnd, width, comparator) + { + var left = srcIndex; + var leftEnd = min(left + width, srcEnd); + var right = leftEnd; + var rightEnd = min(right + width, srcEnd); + + for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) { + if (right < rightEnd) { + if (left >= leftEnd || comparator(src[right], src[left]) < 0) { + dst[dstIndex] = src[right++]; + continue; + } + } + + dst[dstIndex] = src[left++]; + } + } + + function mergeSort(array, valueCount, comparator) + { + var buffer = [ ]; + buffer.length = valueCount; + + var dst = buffer; + var src = array; + for (var width = 1; width < valueCount; width *= 2) { + for (var srcIndex = 0; srcIndex < valueCount; srcIndex += 2 * width) + merge(dst, src, srcIndex, valueCount, width, comparator); + + var tmp = src; + src = dst; + dst = tmp; + } + + if (src != array) { + for(var i = 0; i < valueCount; i++) + array[i] = src[i]; + } + } + + function bucketSort(array, dst, bucket, depth) + { + if (bucket.length < 32 || depth > 32) { + mergeSort(bucket, bucket.length, stringComparator); + for (var i = 0; i < bucket.length; ++i) + array[dst++] = bucket[i].value; + return dst; + } + + var buckets = [ ]; + for (var i = 0; i < bucket.length; ++i) { + var entry = bucket[i]; + var string = entry.string; + if (string.length == depth) { + array[dst++] = entry.value; + continue; + } + + var c = string.@charCodeAt(depth); + if (!buckets[c]) + buckets[c] = [ ]; + buckets[c][buckets[c].length] = entry; + } + + for (var i = 0; i < buckets.length; ++i) { + if (!buckets[i]) + continue; + dst = bucketSort(array, dst, buckets[i], depth + 1); + } + + return dst; + } + + function comparatorSort(array, comparator) + { + var length = array.length >>> 0; + + // For compatibility with Firefox and Chrome, do nothing observable + // to the target array if it has 0 or 1 sortable properties. + if (length < 2) + return; + + var valueCount = compact(array, length); + mergeSort(array, valueCount, comparator); + } + + function stringSort(array) + { + var length = array.length >>> 0; + + // For compatibility with Firefox and Chrome, do nothing observable + // to the target array if it has 0 or 1 sortable properties. + if (length < 2) + return; + + var valueCount = compact(array, length); + + var strings = new @Array(valueCount); + for (var i = 0; i < valueCount; ++i) + strings[i] = { string: @toString(array[i]), value: array[i] }; + + bucketSort(array, 0, strings, 0); + } + + if (this === null) + throw new @TypeError("Array.prototype.sort requires that |this| not be null"); + + if (this === undefined) + throw new @TypeError("Array.prototype.sort requires that |this| not be undefined"); + + if (typeof this == "string") + throw new @TypeError("Attempted to assign to readonly property."); + + var array = @Object(this); + + if (typeof comparator == "function") + comparatorSort(array, comparator); + else + stringSort(array); + + return array; +} + +function copyWithin(target, start /*, end */) +{ + "use strict"; + + function maxWithPositives(a, b) + { + return (a < b) ? b : a; + } + + function minWithMaybeNegativeZeroAndPositive(maybeNegativeZero, positive) + { + return (maybeNegativeZero < positive) ? maybeNegativeZero : positive; + } + + if (this === null || this === undefined) + throw new @TypeError("Array.copyWithin requires that |this| not be null or undefined"); + var thisObject = @Object(this); + + var length = @toLength(thisObject.length); + + var relativeTarget = @toInteger(target); + var to = (relativeTarget < 0) ? maxWithPositives(length + relativeTarget, 0) : minWithMaybeNegativeZeroAndPositive(relativeTarget, length); + + var relativeStart = @toInteger(start); + var from = (relativeStart < 0) ? maxWithPositives(length + relativeStart, 0) : minWithMaybeNegativeZeroAndPositive(relativeStart, length); + + var relativeEnd; + if (arguments.length >= 3) { + var end = arguments[2]; + if (end === undefined) + relativeEnd = length; + else + relativeEnd = @toInteger(end); + } else + relativeEnd = length; + + var finalValue = (relativeEnd < 0) ? maxWithPositives(length + relativeEnd, 0) : minWithMaybeNegativeZeroAndPositive(relativeEnd, length); + + var count = minWithMaybeNegativeZeroAndPositive(finalValue - from, length - to); + + var direction = 1; + if (from < to && to < from + count) { + direction = -1; + from = from + count - 1; + to = to + count - 1; + } + + for (var i = 0; i < count; ++i, from += direction, to += direction) { + if (from in thisObject) + thisObject[to] = thisObject[from]; + else + delete thisObject[to]; + } + + return thisObject; +} diff --git a/builtins/ArrayConstructor.js b/builtins/ArrayConstructor.js new file mode 100644 index 0000000..5a551f7 --- /dev/null +++ b/builtins/ArrayConstructor.js @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 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. + */ + +function of(/* items... */) +{ + "use strict"; + + var length = arguments.length; + // TODO: Need isConstructor(this) instead of typeof "function" check. + var array = typeof this === 'function' ? new this(length) : new @Array(length); + for (var k = 0; k < length; ++k) + @putByValDirect(array, k, arguments[k]); + array.length = length; + return array; +} + +function from(items /*, mapFn, thisArg */) { + "use strict"; + + var thisObj = this; + + var mapFn = arguments.length > 1 ? arguments[1] : undefined; + + var thisArg; + + if (mapFn !== undefined) { + if (typeof mapFn !== "function") + throw new @TypeError("Array.from requires that the second argument, when provided, be a function"); + + if (arguments.length > 2) + thisArg = arguments[2]; + } + + if (items == null) + throw new @TypeError("Array.from requires an array-like object - not null or undefined"); + + var iteratorMethod = items[@symbolIterator]; + if (iteratorMethod != null) { + if (typeof iteratorMethod !== "function") + throw new @TypeError("Array.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function"); + + // TODO: Need isConstructor(thisObj) instead of typeof "function" check. + var result = (typeof thisObj === "function") ? @Object(new thisObj()) : []; + + var k = 0; + var iterator = iteratorMethod.@call(items); + + // Since for-of loop once more looks up the @@iterator property of a given iterable, + // it could be observable if the user defines a getter for @@iterator. + // To avoid this situation, we define a wrapper object that @@iterator just returns a given iterator. + var wrapper = { + [@symbolIterator]() { + return iterator; + } + }; + + for (var value of wrapper) { + if (mapFn) + @putByValDirect(result, k, thisArg === undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k)); + else + @putByValDirect(result, k, value); + k += 1; + } + + result.length = k; + return result; + } + + var arrayLike = @Object(items); + var arrayLikeLength = @toLength(arrayLike.length); + + // TODO: Need isConstructor(thisObj) instead of typeof "function" check. + var result = (typeof thisObj === "function") ? @Object(new thisObj(arrayLikeLength)) : new @Array(arrayLikeLength); + + var k = 0; + while (k < arrayLikeLength) { + var value = arrayLike[k]; + if (mapFn) + @putByValDirect(result, k, thisArg === undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k)); + else + @putByValDirect(result, k, value); + k += 1; + } + + result.length = arrayLikeLength; + return result; +} diff --git a/builtins/ArrayIterator.prototype.js b/builtins/ArrayIterator.prototype.js new file mode 100644 index 0000000..82df528 --- /dev/null +++ b/builtins/ArrayIterator.prototype.js @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function next() { + "use strict"; + + if (this == null) + throw new @TypeError("%ArrayIteratorPrototype%.next requires that |this| not be null or undefined"); + + var itemKind = this.@arrayIterationKind; + if (itemKind === undefined) + throw new @TypeError("%ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance"); + + var done = true; + var value = undefined; + + var array = this.@iteratedObject; + if (array !== undefined) { + var index = this.@arrayIteratorNextIndex; + var length = array.length >>> 0; + if (index >= length) { + this.@iteratedObject = undefined; + } else { + this.@arrayIteratorNextIndex = index + 1; + done = false; + if (itemKind === @arrayIterationKindKey) { + value = index; + } else if (itemKind === @arrayIterationKindValue) { + value = array[index]; + } else { + value = [ index, array[index] ]; + } + } + } + + return {done, value}; +} diff --git a/builtins/BuiltinExecutables.cpp b/builtins/BuiltinExecutables.cpp index 70b43d5..245eff3 100644 --- a/builtins/BuiltinExecutables.cpp +++ b/builtins/BuiltinExecutables.cpp @@ -31,6 +31,7 @@ #include "Executable.h" #include "JSCInlines.h" #include "Parser.h" +#include <wtf/NeverDestroyed.h> namespace JSC { @@ -42,14 +43,39 @@ BuiltinExecutables::BuiltinExecutables(VM& vm) { } -UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const SourceCode& source, const Identifier& name) +UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name) +{ + static NeverDestroyed<const String> baseConstructorCode(ASCIILiteral("(function () { })")); + static NeverDestroyed<const String> derivedConstructorCode(ASCIILiteral("(function () { super(...arguments); })")); + + switch (constructorKind) { + case ConstructorKind::None: + break; + case ConstructorKind::Base: + return createExecutableInternal(makeSource(baseConstructorCode), name, constructorKind); + case ConstructorKind::Derived: + return createExecutableInternal(makeSource(derivedConstructorCode), name, constructorKind); + } + ASSERT_NOT_REACHED(); + return nullptr; +} + +UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const SourceCode& source, const Identifier& name, ConstructorKind constructorKind) { JSTextPosition positionBeforeLastNewline; ParserError error; - RefPtr<ProgramNode> program = parse<ProgramNode>(&m_vm, source, 0, Identifier(), JSParseBuiltin, JSParseProgramCode, error, &positionBeforeLastNewline); + bool isParsingDefaultConstructor = constructorKind != ConstructorKind::None; + JSParserBuiltinMode builtinMode = isParsingDefaultConstructor ? JSParserBuiltinMode::NotBuiltin : JSParserBuiltinMode::Builtin; + UnlinkedFunctionKind kind = isParsingDefaultConstructor ? UnlinkedNormalFunction : UnlinkedBuiltinFunction; + RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr; + std::unique_ptr<ProgramNode> program = parse<ProgramNode>( + &m_vm, source, 0, Identifier(), builtinMode, + JSParserStrictMode::NotStrict, + JSParserCodeType::Program, + error, &positionBeforeLastNewline, constructorKind); if (!program) { - dataLog("Fatal error compiling builtin function '", name.string(), "': ", error.m_message); + dataLog("Fatal error compiling builtin function '", name.string(), "': ", error.message()); CRASH(); } @@ -71,23 +97,27 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const So RELEASE_ASSERT(body); for (const auto& closedVariable : program->closedVariables()) { if (closedVariable == m_vm.propertyNames->arguments.impl()) - continue; + continue; if (closedVariable == m_vm.propertyNames->undefinedKeyword.impl()) continue; - RELEASE_ASSERT(closedVariable->isEmptyUnique()); } body->overrideName(name); - UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, UnlinkedBuiltinFunction); + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, kind, WTF::move(sourceOverride)); functionExecutable->m_nameValue.set(m_vm, functionExecutable, jsString(&m_vm, name.string())); return functionExecutable; } +void BuiltinExecutables::finalize(Handle<Unknown>, void* context) +{ + static_cast<Weak<UnlinkedFunctionExecutable>*>(context)->clear(); +} + #define DEFINE_BUILTIN_EXECUTABLES(name, functionName, length) \ UnlinkedFunctionExecutable* BuiltinExecutables::name##Executable() \ {\ if (!m_##name##Executable)\ - m_##name##Executable = createBuiltinExecutable(m_##name##Source, m_vm.propertyNames->builtinNames().functionName##PublicName());\ + m_##name##Executable = Weak<UnlinkedFunctionExecutable>(createBuiltinExecutable(m_##name##Source, m_vm.propertyNames->builtinNames().functionName##PublicName()), this, &m_##name##Executable);\ return m_##name##Executable.get();\ } JSC_FOREACH_BUILTIN(DEFINE_BUILTIN_EXECUTABLES) diff --git a/builtins/BuiltinExecutables.h b/builtins/BuiltinExecutables.h index d44bf4c..f0d5f4e 100644 --- a/builtins/BuiltinExecutables.h +++ b/builtins/BuiltinExecutables.h @@ -27,9 +27,10 @@ #define BuiltinExecutables_h #include "JSCBuiltins.h" +#include "ParserModes.h" #include "SourceCode.h" #include "Weak.h" -#include <wtf/PassOwnPtr.h> +#include "WeakHandleOwner.h" namespace JSC { @@ -37,25 +38,31 @@ class UnlinkedFunctionExecutable; class Identifier; class VM; -class BuiltinExecutables { +class BuiltinExecutables final: private WeakHandleOwner { WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<BuiltinExecutables> create(VM& vm) - { - return adoptPtr(new BuiltinExecutables(vm)); - } - + explicit BuiltinExecutables(VM&); + #define EXPOSE_BUILTIN_EXECUTABLES(name, functionName, length) \ UnlinkedFunctionExecutable* name##Executable(); \ const SourceCode& name##Source() { return m_##name##Source; } JSC_FOREACH_BUILTIN(EXPOSE_BUILTIN_EXECUTABLES) #undef EXPOSE_BUILTIN_SOURCES - + + UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name); + private: - BuiltinExecutables(VM&); + void finalize(Handle<Unknown>, void* context) override; + VM& m_vm; - UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode&, const Identifier&); + + UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode& code, const Identifier& name) + { + return createExecutableInternal(code, name, ConstructorKind::None); + } + UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind); + #define DECLARE_BUILTIN_SOURCE_MEMBERS(name, functionName, length)\ SourceCode m_##name##Source; \ Weak<UnlinkedFunctionExecutable> m_##name##Executable; diff --git a/builtins/BuiltinNames.h b/builtins/BuiltinNames.h index 67e1f56..5dc716c 100644 --- a/builtins/BuiltinNames.h +++ b/builtins/BuiltinNames.h @@ -31,12 +31,18 @@ namespace JSC { -#define INITIALISE_BUILTIN_NAMES(name) , m_##name(vm, #name), m_##name##PrivateName(Identifier::from(PrivateName())) -#define DECLARE_BUILTIN_NAMES(name) const Identifier m_##name; const Identifier m_##name##PrivateName;; +#define INITIALISE_BUILTIN_NAMES(name) , m_##name(Identifier::fromString(vm, #name)), m_##name##PrivateName(Identifier::fromUid(PrivateName())) +#define DECLARE_BUILTIN_NAMES(name) const Identifier m_##name; const Identifier m_##name##PrivateName; #define DECLARE_BUILTIN_IDENTIFIER_ACCESSOR(name) \ const Identifier& name##PublicName() const { return m_##name; } \ const Identifier& name##PrivateName() const { return m_##name##PrivateName; } +#define INITIALISE_BUILTIN_SYMBOLS(name) INITIALISE_BUILTIN_NAMES(name), m_##name##Symbol(Identifier::fromUid(PrivateName(PrivateName::Description, ASCIILiteral("Symbol." #name)))) +#define DECLARE_BUILTIN_SYMBOLS(name) DECLARE_BUILTIN_NAMES(name) const Identifier m_##name##Symbol; +#define DECLARE_BUILTIN_SYMBOL_ACCESSOR(name) \ + DECLARE_BUILTIN_IDENTIFIER_ACCESSOR(name) \ + const Identifier& name##Symbol() const { return m_##name##Symbol; } + #define INITIALISE_PRIVATE_TO_PUBLIC_ENTRY(name) m_privateToPublicMap.add(m_##name##PrivateName.impl(), &m_##name); #define INITIALISE_PUBLIC_TO_PRIVATE_ENTRY(name) m_publicToPrivateMap.add(m_##name.impl(), &m_##name##PrivateName); @@ -48,24 +54,32 @@ public: : m_emptyIdentifier(commonIdentifiers->emptyIdentifier) JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALISE_BUILTIN_NAMES) JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALISE_BUILTIN_NAMES) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALISE_BUILTIN_SYMBOLS) { JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALISE_PRIVATE_TO_PUBLIC_ENTRY) JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALISE_PRIVATE_TO_PUBLIC_ENTRY) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALISE_PRIVATE_TO_PUBLIC_ENTRY) JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALISE_PUBLIC_TO_PRIVATE_ENTRY) JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALISE_PUBLIC_TO_PRIVATE_ENTRY) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALISE_PUBLIC_TO_PRIVATE_ENTRY) } + bool isPrivateName(SymbolImpl& uid) const; + bool isPrivateName(UniquedStringImpl& uid) const; + bool isPrivateName(const Identifier&) const; const Identifier* getPrivateName(const Identifier&) const; const Identifier& getPublicName(const Identifier&) const; JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR) JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOL_ACCESSOR) private: Identifier m_emptyIdentifier; JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_NAMES) JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_NAMES) - typedef HashMap<RefPtr<StringImpl>, const Identifier*, IdentifierRepHash> BuiltinNamesMap; + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOLS) + typedef HashMap<RefPtr<UniquedStringImpl>, const Identifier*, IdentifierRepHash> BuiltinNamesMap; BuiltinNamesMap m_publicToPrivateMap; BuiltinNamesMap m_privateToPublicMap; }; @@ -73,7 +87,28 @@ private: #undef DECLARE_BUILTIN_NAMES #undef INITIALISE_BUILTIN_NAMES #undef DECLARE_BUILTIN_IDENTIFIER_ACCESSOR +#undef DECLARE_BUILTIN_SYMBOLS +#undef INITIALISE_BUILTIN_SYMBOLS +#undef DECLARE_BUILTIN_SYMBOL_ACCESSOR + +inline bool BuiltinNames::isPrivateName(SymbolImpl& uid) const +{ + return m_privateToPublicMap.contains(&uid); +} +inline bool BuiltinNames::isPrivateName(UniquedStringImpl& uid) const +{ + if (!uid.isSymbol()) + return false; + return m_privateToPublicMap.contains(&uid); +} + +inline bool BuiltinNames::isPrivateName(const Identifier& ident) const +{ + if (ident.isNull()) + return false; + return isPrivateName(*ident.impl()); +} inline const Identifier* BuiltinNames::getPrivateName(const Identifier& ident) const { @@ -91,7 +126,7 @@ inline const Identifier& BuiltinNames::getPublicName(const Identifier& ident) co return m_emptyIdentifier; } - + } #endif diff --git a/builtins/GlobalObject.js b/builtins/GlobalObject.js new file mode 100644 index 0000000..6adadef --- /dev/null +++ b/builtins/GlobalObject.js @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function toInteger(target) +{ + "use strict"; + + var numberValue = @Number(target); + + // isNaN(numberValue) + if (numberValue !== numberValue) + return 0; + + if (numberValue === 0 || !@isFinite(numberValue)) + return numberValue; + + return (numberValue > 0 ? 1 : -1) * @floor(@abs(numberValue)); +} + +function toLength(target) +{ + "use strict"; + + var maxSafeInteger = 0x1FFFFFFFFFFFFF; + var length = @toInteger(target); + // originally Math.min(Math.max(length, 0), maxSafeInteger)); + return length > 0 ? (length < maxSafeInteger ? length : maxSafeInteger) : 0; +} + +function isObject(object) +{ + "use strict"; + + return (object !== null && typeof object === "object") || typeof object === "function"; +} diff --git a/builtins/Iterator.prototype.js b/builtins/Iterator.prototype.js new file mode 100644 index 0000000..dc72a64 --- /dev/null +++ b/builtins/Iterator.prototype.js @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function SymbolIterator() +{ + 'use strict'; + return this; +} diff --git a/builtins/ObjectConstructor.js b/builtins/ObjectConstructor.js new file mode 100644 index 0000000..eeec196 --- /dev/null +++ b/builtins/ObjectConstructor.js @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 Jordan Harband. 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. + */ + +function assign(target/*[*/, /*...*/sources/*] */) { + "use strict"; + + if (target == null) + throw new @TypeError("can't convert " + target + " to object"); + + var objTarget = @Object(target); + var s, nextSource, from, i, keys, nextKey, desc; + for (s = 1; s < arguments.length; ++s) { + nextSource = arguments[s]; + if (nextSource != null) { + from = @Object(nextSource); + // TODO: replace @objectKeys + @objectGetOwnPropertySymbols with single @OwnPropertyKeys c++ operation + keys = @objectKeys(from); + for (i = 0; i < keys.length; ++i) { + nextKey = keys[i]; + desc = @objectGetOwnPropertyDescriptor(from, nextKey); + if (typeof desc !== "undefined" && desc.enumerable) { + objTarget[nextKey] = from[nextKey]; + } + } + keys = @objectGetOwnPropertySymbols(from); + for (i = 0; i < keys.length; ++i) { + nextKey = keys[i]; + desc = @objectGetOwnPropertyDescriptor(from, nextKey); + if (typeof desc !== "undefined" && desc.enumerable) { + objTarget[nextKey] = from[nextKey]; + } + } + } + } + return objTarget; +} diff --git a/builtins/Operations.Promise.js b/builtins/Operations.Promise.js new file mode 100644 index 0000000..80c57ab --- /dev/null +++ b/builtins/Operations.Promise.js @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function isPromise(promise) +{ + "use strict"; + + return @isObject(promise) && !!promise.@promiseState; +} + +function newPromiseReaction(capability, handler) +{ + "use strict"; + + return { + @capabilities: capability, + @handler: handler + }; +} + +function newPromiseDeferred() +{ + "use strict"; + + return @newPromiseCapability(@Promise); +} + +function newPromiseCapability(constructor) +{ + "use strict"; + + // FIXME: Check isConstructor(constructor). + if (typeof constructor !== "function") + throw new @TypeError("promise capability requires a constructor function"); + + var promiseCapability = { + @promise: undefined, + @resolve: undefined, + @reject: undefined + }; + + function executor(resolve, reject) + { + if (promiseCapability.@resolve !== undefined) + throw new @TypeError("resolve function is already set"); + if (promiseCapability.@reject !== undefined) + throw new @TypeError("reject function is already set"); + + promiseCapability.@resolve = resolve; + promiseCapability.@reject = reject; + } + + var promise = new constructor(executor); + + if (typeof promiseCapability.@resolve !== "function") + throw new @TypeError("executor did not take a resolve function"); + + if (typeof promiseCapability.@reject !== "function") + throw new @TypeError("executor did not take a reject function"); + + promiseCapability.@promise = promise; + + return promiseCapability; +} + +function triggerPromiseReactions(reactions, argument) +{ + "use strict"; + + for (var index = 0, length = reactions.length; index < length; ++index) + @enqueueJob(@promiseReactionJob, [reactions[index], argument]); +} + +function rejectPromise(promise, reason) +{ + "use strict"; + + var reactions = promise.@promiseRejectReactions; + promise.@promiseResult = reason; + promise.@promiseFulfillReactions = undefined; + promise.@promiseRejectReactions = undefined; + promise.@promiseState = @promiseRejected; + @triggerPromiseReactions(reactions, reason); +} + +function fulfillPromise(promise, value) +{ + "use strict"; + + var reactions = promise.@promiseFulfillReactions; + promise.@promiseResult = value; + promise.@promiseFulfillReactions = undefined; + promise.@promiseRejectReactions = undefined; + promise.@promiseState = @promiseFulfilled; + @triggerPromiseReactions(reactions, value); +} + +function createResolvingFunctions(promise) +{ + "use strict"; + + var alreadyResolved = false; + + var resolve = function (resolution) { + if (alreadyResolved) + return undefined; + alreadyResolved = true; + + if (resolution === promise) + return @rejectPromise(promise, new @TypeError("Resolve a promise with itself")); + + if (!@isObject(resolution)) + return @fulfillPromise(promise, resolution); + + var then; + try { + then = resolution.then; + } catch (error) { + return @rejectPromise(promise, error); + } + + if (typeof then !== 'function') + return @fulfillPromise(promise, resolution); + + @enqueueJob(@promiseResolveThenableJob, [promise, resolution, then]); + + return undefined; + }; + + var reject = function (reason) { + if (alreadyResolved) + return undefined; + alreadyResolved = true; + + return @rejectPromise(promise, reason); + }; + + return { + @resolve: resolve, + @reject: reject + }; +} + +function promiseReactionJob(reaction, argument) +{ + "use strict"; + + var promiseCapability = reaction.@capabilities; + + var result; + try { + result = reaction.@handler.@call(undefined, argument); + } catch (error) { + return promiseCapability.@reject.@call(undefined, error); + } + + return promiseCapability.@resolve.@call(undefined, result); +} + +function promiseResolveThenableJob(promiseToResolve, thenable, then) +{ + "use strict"; + + var resolvingFunctions = @createResolvingFunctions(promiseToResolve); + + try { + return then.@call(thenable, resolvingFunctions.@resolve, resolvingFunctions.@reject); + } catch (error) { + return resolvingFunctions.@reject.@call(undefined, error); + } +} + +function initializePromise(executor) +{ + "use strict"; + + if (typeof executor !== 'function') + throw new @TypeError("Promise constructor takes a function argument"); + + this.@promiseState = @promisePending; + this.@promiseFulfillReactions = []; + this.@promiseRejectReactions = []; + + var resolvingFunctions = @createResolvingFunctions(this); + try { + executor(resolvingFunctions.@resolve, resolvingFunctions.@reject); + } catch (error) { + return resolvingFunctions.@reject.@call(undefined, error); + } + + return this; +} diff --git a/builtins/Promise.prototype.js b/builtins/Promise.prototype.js index fbd53b0..8563df0 100644 --- a/builtins/Promise.prototype.js +++ b/builtins/Promise.prototype.js @@ -23,8 +23,44 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -function catch(onRejected) { +function catch(onRejected) +{ "use strict"; return this.then(undefined, onRejected); } + +function then(onFulfilled, onRejected) +{ + "use strict"; + + if (!@isPromise(this)) + throw new @TypeError("|this| is not a object"); + + // FIXME: Fix this code when @@species well-known symbol is landed. + // https://bugs.webkit.org/show_bug.cgi?id=146624 + var constructor = this.constructor; + + var resultCapability = @newPromiseCapability(constructor); + + if (typeof onFulfilled !== "function") + onFulfilled = function (argument) { return argument; }; + + if (typeof onRejected !== "function") + onRejected = function (argument) { throw argument; }; + + var fulfillReaction = @newPromiseReaction(resultCapability, onFulfilled); + var rejectReaction = @newPromiseReaction(resultCapability, onRejected); + + var state = this.@promiseState; + + if (state === @promisePending) { + @putByValDirect(this.@promiseFulfillReactions, this.@promiseFulfillReactions.length, fulfillReaction) + @putByValDirect(this.@promiseRejectReactions, this.@promiseRejectReactions.length, rejectReaction) + } else if (state === @promiseFulfilled) + @enqueueJob(@promiseReactionJob, [fulfillReaction, this.@promiseResult]); + else if (state === @promiseRejected) + @enqueueJob(@promiseReactionJob, [rejectReaction, this.@promiseResult]); + + return resultCapability.@promise; +} diff --git a/builtins/PromiseConstructor.js b/builtins/PromiseConstructor.js new file mode 100644 index 0000000..1f83b47 --- /dev/null +++ b/builtins/PromiseConstructor.js @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function all(iterable) +{ + "use strict"; + + if (!@isObject(this)) + throw new TypeError("|this| is not a object"); + + // FIXME: Fix this code when @@species well-known symbol is landed. + // https://bugs.webkit.org/show_bug.cgi?id=146624 + var constructor = this; + + var promiseCapability = @newPromiseCapability(constructor); + + var values = []; + var index = 0; + var remainingElementsCount = 1; + + function newResolveElement(index) + { + var alreadyCalled = false; + return function (argument) + { + if (alreadyCalled) + return undefined; + alreadyCalled = true; + + @putByValDirect(values, index, argument); + + --remainingElementsCount; + if (remainingElementsCount === 0) + return promiseCapability.@resolve.@call(undefined, values); + + return undefined; + } + } + + try { + for (var value of iterable) { + @putByValDirect(values, index, undefined); + var nextPromise = constructor.resolve(value); + var resolveElement = newResolveElement(index); + ++remainingElementsCount; + nextPromise.then(resolveElement, promiseCapability.@reject); + ++index; + } + + --remainingElementsCount; + if (remainingElementsCount === 0) + promiseCapability.@resolve.@call(undefined, values); + } catch (error) { + promiseCapability.@reject.@call(undefined, error); + } + + return promiseCapability.@promise; +} + +function race(iterable) +{ + "use strict"; + + if (!@isObject(this)) + throw new TypeError("|this| is not a object"); + + // FIXME: Fix this code when @@species well-known symbol is landed. + // https://bugs.webkit.org/show_bug.cgi?id=146624 + var constructor = this; + + var promiseCapability = @newPromiseCapability(constructor); + + try { + for (var value of iterable) { + var nextPromise = constructor.resolve(value); + nextPromise.then(promiseCapability.@resolve, promiseCapability.@reject); + } + } catch (error) { + promiseCapability.@reject.@call(undefined, error); + } + + return promiseCapability.@promise; +} + +function reject(reason) +{ + "use strict"; + + if (!@isObject(this)) + throw new TypeError("|this| is not a object"); + + var promiseCapability = @newPromiseCapability(this); + + promiseCapability.@reject.@call(undefined, reason); + + return promiseCapability.@promise; +} + +function resolve(value) +{ + "use strict"; + + if (!@isObject(this)) + throw new TypeError("|this| is not a object"); + + if (@isPromise(value)) { + var valueConstructor = value.constructor; + if (valueConstructor === this) + return value; + } + + var promiseCapability = @newPromiseCapability(this); + + promiseCapability.@resolve.@call(undefined, value); + + return promiseCapability.@promise; +} diff --git a/builtins/StringConstructor.js b/builtins/StringConstructor.js new file mode 100644 index 0000000..f8cd16b --- /dev/null +++ b/builtins/StringConstructor.js @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function raw(template) { + "use strict"; + + if (template === null || template === undefined) + throw new @TypeError("String.raw requires template not be null or undefined"); + var cookedSegments = @Object(template); + + var rawValue = cookedSegments.raw; + if (rawValue === null || rawValue === undefined) + throw new @TypeError("String.raw requires template.raw not be null or undefined"); + var rawSegments = @Object(rawValue); + + var numberOfSubstitutions = arguments.length - 1; + + var segmentCount = @toLength(rawSegments.length); + + if (segmentCount <= 0) + return ''; + + var stringElements = ''; + for (var i = 0; ; ++i) { + var segment = @toString(rawSegments[i]); + stringElements += segment; + + if ((i + 1) === segmentCount) + return stringElements; + + if (i < numberOfSubstitutions) { + var substitutionIndexInArguments = i + 1; + var next = @toString(arguments[substitutionIndexInArguments]); + stringElements += next; + } + } +} diff --git a/builtins/StringIterator.prototype.js b/builtins/StringIterator.prototype.js new file mode 100644 index 0000000..8810c7d --- /dev/null +++ b/builtins/StringIterator.prototype.js @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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. + */ + +function next() { + "use strict"; + + if (this == null) + throw new @TypeError("%StringIteratorPrototype%.next requires that |this| not be null or undefined"); + + var position = this.@stringIteratorNextIndex; + if (position === undefined) + throw new @TypeError("%StringIteratorPrototype%.next requires that |this| be a String Iterator instance"); + + var done = true; + var value = undefined; + + var string = this.@iteratedString; + if (string !== undefined) { + var length = string.length >>> 0; + if (position >= length) { + this.@iteratedString = undefined; + } else { + done = false; + + var first = string.@charCodeAt(position); + if (first < 0xD800 || first > 0xDBFF || position + 1 === length) + value = string[position]; + else { + var second = string.@charCodeAt(position + 1); + if (second < 0xDC00 || second > 0xDFFF) + value = string[position]; + else + value = string[position] + string[position + 1]; + } + + this.@stringIteratorNextIndex = position + value.length; + } + } + + return {done, value}; +} diff --git a/bytecode/ArrayProfile.cpp b/bytecode/ArrayProfile.cpp index ef49f20..b8ade22 100644 --- a/bytecode/ArrayProfile.cpp +++ b/bytecode/ArrayProfile.cpp @@ -73,14 +73,39 @@ void dumpArrayModes(PrintStream& out, ArrayModes arrayModes) out.print(comma, "ArrayWithArrayStorage"); if (arrayModes & asArrayModes(ArrayWithSlowPutArrayStorage)) out.print(comma, "ArrayWithSlowPutArrayStorage"); + + if (arrayModes & Int8ArrayMode) + out.print(comma, "Int8ArrayMode"); + if (arrayModes & Int16ArrayMode) + out.print(comma, "Int16ArrayMode"); + if (arrayModes & Int32ArrayMode) + out.print(comma, "Int32ArrayMode"); + if (arrayModes & Uint8ArrayMode) + out.print(comma, "Uint8ArrayMode"); + if (arrayModes & Uint8ClampedArrayMode) + out.print(comma, "Uint8ClampedArrayMode"); + if (arrayModes & Uint16ArrayMode) + out.print(comma, "Uint16ArrayMode"); + if (arrayModes & Uint32ArrayMode) + out.print(comma, "Uint32ArrayMode"); + if (arrayModes & Float32ArrayMode) + out.print(comma, "Float32ArrayMode"); + if (arrayModes & Float64ArrayMode) + out.print(comma, "Float64ArrayMode"); } -void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock* codeBlock) +void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker& locker, CodeBlock* codeBlock) { if (!m_lastSeenStructureID) return; Structure* lastSeenStructure = codeBlock->heap()->structureIDTable().get(m_lastSeenStructureID); + computeUpdatedPrediction(locker, codeBlock, lastSeenStructure); + m_lastSeenStructureID = 0; +} + +void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock* codeBlock, Structure* lastSeenStructure) +{ m_observedArrayModes |= arrayModeFromStructure(lastSeenStructure); if (!m_didPerformFirstRunPruning @@ -95,7 +120,6 @@ void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBloc if (!globalObject->isOriginalArrayStructure(lastSeenStructure) && !globalObject->isOriginalTypedArrayStructure(lastSeenStructure)) m_usesOriginalArrayStructures = false; - m_lastSeenStructureID = 0; } CString ArrayProfile::briefDescription(const ConcurrentJITLocker& locker, CodeBlock* codeBlock) diff --git a/bytecode/ArrayProfile.h b/bytecode/ArrayProfile.h index 302365f..66b295d 100644 --- a/bytecode/ArrayProfile.h +++ b/bytecode/ArrayProfile.h @@ -37,20 +37,44 @@ namespace JSC { class CodeBlock; class LLIntOffsetsExtractor; -// This is a bitfield where each bit represents an IndexingType that we have seen. -// There are 32 indexing types, so an unsigned is enough. +// This is a bitfield where each bit represents an type of array access that we have seen. +// There are 16 indexing types that use the lower bits. +// There are 9 typed array types taking the bits 16 to 25. typedef unsigned ArrayModes; +const ArrayModes Int8ArrayMode = 1 << 16; +const ArrayModes Int16ArrayMode = 1 << 17; +const ArrayModes Int32ArrayMode = 1 << 18; +const ArrayModes Uint8ArrayMode = 1 << 19; +const ArrayModes Uint8ClampedArrayMode = 1 << 20; +const ArrayModes Uint16ArrayMode = 1 << 21; +const ArrayModes Uint32ArrayMode = 1 << 22; +const ArrayModes Float32ArrayMode = 1 << 23; +const ArrayModes Float64ArrayMode = 1 << 24; + #define asArrayModes(type) \ (static_cast<unsigned>(1) << static_cast<unsigned>(type)) +#define ALL_TYPED_ARRAY_MODES \ + (Int8ArrayMode \ + | Int16ArrayMode \ + | Int32ArrayMode \ + | Uint8ArrayMode \ + | Uint8ClampedArrayMode \ + | Uint16ArrayMode \ + | Uint32ArrayMode \ + | Float32ArrayMode \ + | Float64ArrayMode \ + ) + #define ALL_NON_ARRAY_ARRAY_MODES \ (asArrayModes(NonArray) \ | asArrayModes(NonArrayWithInt32) \ | asArrayModes(NonArrayWithDouble) \ | asArrayModes(NonArrayWithContiguous) \ | asArrayModes(NonArrayWithArrayStorage) \ - | asArrayModes(NonArrayWithSlowPutArrayStorage)) + | asArrayModes(NonArrayWithSlowPutArrayStorage) \ + | ALL_TYPED_ARRAY_MODES) #define ALL_ARRAY_ARRAY_MODES \ (asArrayModes(ArrayClass) \ @@ -65,6 +89,29 @@ typedef unsigned ArrayModes; inline ArrayModes arrayModeFromStructure(Structure* structure) { + switch (structure->classInfo()->typedArrayStorageType) { + case TypeInt8: + return Int8ArrayMode; + case TypeUint8: + return Uint8ArrayMode; + case TypeUint8Clamped: + return Uint8ClampedArrayMode; + case TypeInt16: + return Int16ArrayMode; + case TypeUint16: + return Uint16ArrayMode; + case TypeInt32: + return Int32ArrayMode; + case TypeUint32: + return Uint32ArrayMode; + case TypeFloat32: + return Float32ArrayMode; + case TypeFloat64: + return Float64ArrayMode; + case TypeDataView: + case NotTypedArray: + break; + } return asArrayModes(structure->indexingType()); } @@ -162,6 +209,8 @@ public: StructureID* addressOfLastSeenStructureID() { return &m_lastSeenStructureID; } ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; } bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; } + + void setOutOfBounds() { m_outOfBounds = true; } bool* addressOfOutOfBounds() { return &m_outOfBounds; } void observeStructure(Structure* structure) @@ -170,6 +219,7 @@ public: } void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*); + void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*, Structure* lastSeenStructure); ArrayModes observedArrayModes(const ConcurrentJITLocker&) const { return m_observedArrayModes; } bool mayInterceptIndexedAccesses(const ConcurrentJITLocker&) const { return m_mayInterceptIndexedAccesses; } @@ -197,7 +247,7 @@ private: ArrayModes m_observedArrayModes; }; -typedef SegmentedVector<ArrayProfile, 4, 0> ArrayProfileVector; +typedef SegmentedVector<ArrayProfile, 4> ArrayProfileVector; } // namespace JSC diff --git a/bytecode/ByValInfo.h b/bytecode/ByValInfo.h index ebe587d..d988516 100644 --- a/bytecode/ByValInfo.h +++ b/bytecode/ByValInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,6 +41,8 @@ enum JITArrayMode { JITDouble, JITContiguous, JITArrayStorage, + JITDirectArguments, + JITScopedArguments, JITInt8Array, JITInt16Array, JITInt32Array, @@ -65,6 +67,17 @@ inline bool isOptimizableIndexingType(IndexingType indexingType) } } +inline bool hasOptimizableIndexingForJSType(JSType type) +{ + switch (type) { + case DirectArgumentsType: + case ScopedArgumentsType: + return true; + default: + return false; + } +} + inline bool hasOptimizableIndexingForClassInfo(const ClassInfo* classInfo) { return isTypedView(classInfo->typedArrayStorageType); @@ -73,6 +86,7 @@ inline bool hasOptimizableIndexingForClassInfo(const ClassInfo* classInfo) inline bool hasOptimizableIndexing(Structure* structure) { return isOptimizableIndexingType(structure->indexingType()) + || hasOptimizableIndexingForJSType(structure->typeInfo().type()) || hasOptimizableIndexingForClassInfo(structure->classInfo()); } @@ -93,6 +107,19 @@ inline JITArrayMode jitArrayModeForIndexingType(IndexingType indexingType) } } +inline JITArrayMode jitArrayModeForJSType(JSType type) +{ + switch (type) { + case DirectArgumentsType: + return JITDirectArguments; + case ScopedArgumentsType: + return JITScopedArguments; + default: + RELEASE_ASSERT_NOT_REACHED(); + return JITContiguous; + } +} + inline JITArrayMode jitArrayModeForClassInfo(const ClassInfo* classInfo) { switch (classInfo->typedArrayStorageType) { @@ -120,6 +147,19 @@ inline JITArrayMode jitArrayModeForClassInfo(const ClassInfo* classInfo) } } +inline bool jitArrayModePermitsPut(JITArrayMode mode) +{ + switch (mode) { + case JITDirectArguments: + case JITScopedArguments: + // We could support put_by_val on these at some point, but it's just not that profitable + // at the moment. + return false; + default: + return true; + } +} + inline TypedArrayType typedArrayTypeForJITArrayMode(JITArrayMode mode) { switch (mode) { @@ -152,6 +192,9 @@ inline JITArrayMode jitArrayModeForStructure(Structure* structure) if (isOptimizableIndexingType(structure->indexingType())) return jitArrayModeForIndexingType(structure->indexingType()); + if (hasOptimizableIndexingForJSType(structure->typeInfo().type())) + return jitArrayModeForJSType(structure->typeInfo().type()); + ASSERT(hasOptimizableIndexingForClassInfo(structure->classInfo())); return jitArrayModeForClassInfo(structure->classInfo()); } diff --git a/bytecode/BytecodeBasicBlock.cpp b/bytecode/BytecodeBasicBlock.cpp index 95a7472..961eadb 100644 --- a/bytecode/BytecodeBasicBlock.cpp +++ b/bytecode/BytecodeBasicBlock.cpp @@ -52,8 +52,6 @@ static bool isBranch(OpcodeID opcodeID) case op_switch_imm: case op_switch_char: case op_switch_string: - case op_get_pnames: - case op_next_pname: case op_check_has_instance: return true; default: @@ -75,7 +73,6 @@ static bool isTerminal(OpcodeID opcodeID) { switch (opcodeID) { case op_ret: - case op_ret_object_or_this: case op_end: return true; default: diff --git a/bytecode/BytecodeIntrinsicRegistry.cpp b/bytecode/BytecodeIntrinsicRegistry.cpp new file mode 100644 index 0000000..83f93c6 --- /dev/null +++ b/bytecode/BytecodeIntrinsicRegistry.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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 "BytecodeIntrinsicRegistry.h" + +#include "CommonIdentifiers.h" +#include "Nodes.h" + +namespace JSC { + +#define INITIALISE_BYTECODE_INTRINSIC_NAMES_TO_SET(name) m_bytecodeIntrinsicMap.add(propertyNames.name##PrivateName.impl(), &BytecodeIntrinsicNode::emit_intrinsic_##name); + +BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry(const CommonIdentifiers& propertyNames) + : m_propertyNames(propertyNames) + , m_bytecodeIntrinsicMap() +{ + JSC_COMMON_BYTECODE_INTRINSICS_EACH_NAME(INITIALISE_BYTECODE_INTRINSIC_NAMES_TO_SET) +} + +BytecodeIntrinsicNode::EmitterType BytecodeIntrinsicRegistry::lookup(const Identifier& ident) const +{ + if (!m_propertyNames.isPrivateName(ident)) + return nullptr; + auto iterator = m_bytecodeIntrinsicMap.find(ident.impl()); + if (iterator == m_bytecodeIntrinsicMap.end()) + return nullptr; + return iterator->value; +} + +} // namespace JSC + diff --git a/bytecode/BytecodeIntrinsicRegistry.h b/bytecode/BytecodeIntrinsicRegistry.h new file mode 100644 index 0000000..87a578c --- /dev/null +++ b/bytecode/BytecodeIntrinsicRegistry.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * 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 BytecodeIntrinsicRegistry_h +#define BytecodeIntrinsicRegistry_h + +#include "Identifier.h" +#include <wtf/HashTable.h> +#include <wtf/Noncopyable.h> + +namespace JSC { + +class CommonIdentifiers; +class BytecodeGenerator; +class BytecodeIntrinsicNode; +class RegisterID; + +class BytecodeIntrinsicRegistry { + WTF_MAKE_NONCOPYABLE(BytecodeIntrinsicRegistry); +public: + explicit BytecodeIntrinsicRegistry(const CommonIdentifiers&); + + typedef RegisterID* (BytecodeIntrinsicNode::* EmitterType)(BytecodeGenerator&, RegisterID*); + + EmitterType lookup(const Identifier&) const; + +private: + const CommonIdentifiers& m_propertyNames; + HashMap<RefPtr<UniquedStringImpl>, EmitterType, IdentifierRepHash> m_bytecodeIntrinsicMap; +}; + +} // namespace JSC + +#endif // BytecodeIntrinsicRegistry_h diff --git a/bytecode/BytecodeKills.h b/bytecode/BytecodeKills.h new file mode 100644 index 0000000..6e504a6 --- /dev/null +++ b/bytecode/BytecodeKills.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BytecodeKills_h +#define BytecodeKills_h + +#include "CodeBlock.h" +#include <wtf/FastBitVector.h> + +namespace JSC { + +class BytecodeLivenessAnalysis; + +class BytecodeKills { +public: + BytecodeKills() + : m_codeBlock(nullptr) + { + } + + // By convention, we say that non-local operands are never killed. + bool operandIsKilled(unsigned bytecodeIndex, int operand) const + { + ASSERT_WITH_SECURITY_IMPLICATION(bytecodeIndex < m_codeBlock->instructions().size()); + VirtualRegister reg(operand); + if (reg.isLocal()) + return m_killSets[bytecodeIndex].contains(operand); + return false; + } + + bool operandIsKilled(Instruction* instruction, int operand) const + { + return operandIsKilled(instruction - m_codeBlock->instructions().begin(), operand); + } + + template<typename Functor> + void forEachOperandKilledAt(unsigned bytecodeIndex, const Functor& functor) const + { + ASSERT_WITH_SECURITY_IMPLICATION(bytecodeIndex < m_codeBlock->instructions().size()); + m_killSets[bytecodeIndex].forEachLocal( + [&] (unsigned local) { + functor(virtualRegisterForLocal(local)); + }); + } + + template<typename Functor> + void forEachOperandKilledAt(Instruction* pc, const Functor& functor) const + { + forEachOperandKilledAt(pc - m_codeBlock->instructions().begin(), functor); + } + +private: + friend class BytecodeLivenessAnalysis; + + class KillSet { + public: + KillSet() + : m_word(0) + { + } + + ~KillSet() + { + if (hasVector()) + delete vector(); + } + + void add(unsigned local) + { + if (isEmpty()) { + setOneItem(local); + return; + } + if (hasOneItem()) { + ASSERT(oneItem() != local); + Vector<unsigned>* vector = new Vector<unsigned>(); + vector->append(oneItem()); + vector->append(local); + setVector(vector); + return; + } + ASSERT(!vector()->contains(local)); + vector()->append(local); + } + + template<typename Functor> + void forEachLocal(const Functor& functor) + { + if (isEmpty()) + return; + if (hasOneItem()) { + functor(oneItem()); + return; + } + for (unsigned local : *vector()) + functor(local); + } + + bool contains(unsigned expectedLocal) + { + if (isEmpty()) + return false; + if (hasOneItem()) + return oneItem() == expectedLocal; + for (unsigned local : *vector()) { + if (local == expectedLocal) + return true; + } + return false; + } + + private: + bool isEmpty() const + { + return !m_word; + } + + bool hasOneItem() const + { + return m_word & 1; + } + + unsigned oneItem() const + { + return m_word >> 1; + } + + void setOneItem(unsigned value) + { + m_word = (value << 1) | 1; + } + + bool hasVector() const + { + return !isEmpty() && !hasOneItem(); + } + + Vector<unsigned>* vector() + { + return bitwise_cast<Vector<unsigned>*>(m_word); + } + + void setVector(Vector<unsigned>* value) + { + m_word = bitwise_cast<uintptr_t>(value); + } + + uintptr_t m_word; + }; + + CodeBlock* m_codeBlock; + std::unique_ptr<KillSet[]> m_killSets; +}; + +} // namespace JSC + +#endif // BytecodeKills_h + diff --git a/bytecode/BytecodeList.json b/bytecode/BytecodeList.json index dce81e7..9a1fdd1 100644 --- a/bytecode/BytecodeList.json +++ b/bytecode/BytecodeList.json @@ -4,20 +4,20 @@ "macroNameComponent" : "BYTECODE", "asmPrefix" : "llint_", "bytecodes" : [ { "name" : "op_enter", "length" : 1 }, - { "name" : "op_create_activation", "length" : 2 }, - { "name" : "op_touch_entry", "length" : 1 }, - { "name" : "op_init_lazy_reg", "length" : 2 }, - { "name" : "op_create_arguments", "length" : 2 }, - { "name" : "op_create_this", "length" : 4 }, - { "name" : "op_get_callee", "length" : 3 }, - { "name" : "op_to_this", "length" : 3 }, + { "name" : "op_create_lexical_environment", "length" : 3 }, + { "name" : "op_get_scope", "length" : 2 }, + { "name" : "op_create_direct_arguments", "length" : 2 }, + { "name" : "op_create_scoped_arguments", "length" : 3 }, + { "name" : "op_create_out_of_band_arguments", "length" : 2 }, + { "name" : "op_create_this", "length" : 5 }, + { "name" : "op_to_this", "length" : 4 }, + { "name" : "op_check_tdz", "length" : 2 }, { "name" : "op_new_object", "length" : 4 }, { "name" : "op_new_array", "length" : 5 }, { "name" : "op_new_array_with_size", "length" : 4 }, { "name" : "op_new_array_buffer", "length" : 5 }, { "name" : "op_new_regexp", "length" : 3 }, { "name" : "op_mov", "length" : 3 }, - { "name" : "op_captured_mov", "length" : 4 }, { "name" : "op_not", "length" : 3 }, { "name" : "op_eq", "length" : 4 }, { "name" : "op_eq_null", "length" : 3 }, @@ -32,6 +32,7 @@ { "name" : "op_inc", "length" : 2 }, { "name" : "op_dec", "length" : 2 }, { "name" : "op_to_number", "length" : 3 }, + { "name" : "op_to_string", "length" : 3 }, { "name" : "op_negate", "length" : 3 }, { "name" : "op_add", "length" : 5 }, { "name" : "op_mul", "length" : 5 }, @@ -53,6 +54,7 @@ { "name" : "op_is_number", "length" : 3 }, { "name" : "op_is_string", "length" : 3 }, { "name" : "op_is_object", "length" : 3 }, + { "name" : "op_is_object_or_null", "length" : 3 }, { "name" : "op_is_function", "length" : 3 }, { "name" : "op_in", "length" : 4 }, { "name" : "op_init_global_const_nop", "length" : 5 }, @@ -60,7 +62,6 @@ { "name" : "op_get_by_id", "length" : 9 }, { "name" : "op_get_by_id_out_of_line", "length" : 9 }, { "name" : "op_get_array_length", "length" : 9 }, - { "name" : "op_get_arguments_length", "length" : 4 }, { "name" : "op_put_by_id", "length" : 9 }, { "name" : "op_put_by_id_out_of_line", "length" : 9 }, { "name" : "op_put_by_id_transition_direct", "length" : 9 }, @@ -69,12 +70,12 @@ { "name" : "op_put_by_id_transition_normal_out_of_line", "length" : 9 }, { "name" : "op_del_by_id", "length" : 4 }, { "name" : "op_get_by_val", "length" : 6 }, - { "name" : "op_get_argument_by_val", "length" : 6 }, - { "name" : "op_get_by_pname", "length" : 7 }, { "name" : "op_put_by_val", "length" : 5 }, { "name" : "op_put_by_val_direct", "length" : 5 }, { "name" : "op_del_by_val", "length" : 4 }, { "name" : "op_put_by_index", "length" : 4 }, + { "name" : "op_put_getter_by_id", "length" : 4 }, + { "name" : "op_put_setter_by_id", "length" : 4 }, { "name" : "op_put_getter_setter", "length" : 5 }, { "name" : "op_jmp", "length" : 2 }, { "name" : "op_jtrue", "length" : 3 }, @@ -95,34 +96,41 @@ { "name" : "op_switch_char", "length" : 4 }, { "name" : "op_switch_string", "length" : 4 }, { "name" : "op_new_func", "length" : 4 }, - { "name" : "op_new_captured_func", "length" : 4 }, - { "name" : "op_new_func_exp", "length" : 3 }, + { "name" : "op_new_func_exp", "length" : 4 }, { "name" : "op_call", "length" : 9 }, { "name" : "op_call_eval", "length" : 9 }, { "name" : "op_call_varargs", "length" : 9 }, - { "name" : "op_tear_off_activation", "length" : 2 }, - { "name" : "op_tear_off_arguments", "length" : 3 }, { "name" : "op_ret", "length" : 2 }, - { "name" : "op_ret_object_or_this", "length" : 3 }, { "name" : "op_construct", "length" : 9 }, { "name" : "op_construct_varargs", "length" : 9 }, { "name" : "op_strcat", "length" : 4 }, { "name" : "op_to_primitive", "length" : 3 }, - { "name" : "op_get_pnames", "length" : 6 }, - { "name" : "op_next_pname", "length" : 7 }, - { "name" : "op_resolve_scope", "length" : 6 }, + { "name" : "op_resolve_scope", "length" : 7 }, { "name" : "op_get_from_scope", "length" : 8 }, { "name" : "op_put_to_scope", "length" : 7 }, - { "name" : "op_push_with_scope", "length" : 2 }, - { "name" : "op_pop_scope", "length" : 1 }, - { "name" : "op_push_name_scope", "length" : 4 }, - { "name" : "op_catch", "length" : 2 }, + { "name" : "op_get_from_arguments", "length" : 5 }, + { "name" : "op_put_to_arguments", "length" : 4 }, + { "name" : "op_push_with_scope", "length" : 3 }, + { "name" : "op_pop_scope", "length" : 2 }, + { "name" : "op_push_name_scope", "length" : 5 }, + { "name" : "op_catch", "length" : 3 }, { "name" : "op_throw", "length" : 2 }, { "name" : "op_throw_static_error", "length" : 3 }, { "name" : "op_debug", "length" : 3 }, { "name" : "op_profile_will_call", "length" : 2 }, { "name" : "op_profile_did_call", "length" : 2 }, - { "name" : "op_end", "length" : 2 } + { "name" : "op_end", "length" : 2 }, + { "name" : "op_profile_type", "length" : 6 }, + { "name" : "op_profile_control_flow", "length" : 2 }, + { "name" : "op_get_enumerable_length", "length" : 3 }, + { "name" : "op_has_indexed_property", "length" : 5 }, + { "name" : "op_has_structure_property", "length" : 5 }, + { "name" : "op_has_generic_property", "length" : 4 }, + { "name" : "op_get_direct_pname", "length" : 7 }, + { "name" : "op_get_property_enumerator", "length" : 3 }, + { "name" : "op_enumerator_structure_pname", "length" : 4 }, + { "name" : "op_enumerator_generic_pname", "length" : 4 }, + { "name" : "op_to_index_string", "length" : 3 } ] }, { @@ -132,8 +140,8 @@ { "name" : "llint_entry" }, { "name" : "getHostCallReturnValue" }, { "name" : "llint_return_to_host" }, - { "name" : "llint_call_to_javascript" }, - { "name" : "llint_call_to_native_function" }, + { "name" : "llint_vm_entry_to_javascript" }, + { "name" : "llint_vm_entry_to_native" }, { "name" : "llint_cloop_did_return_from_js_1" }, { "name" : "llint_cloop_did_return_from_js_2" }, { "name" : "llint_cloop_did_return_from_js_3" }, diff --git a/bytecode/BytecodeLivenessAnalysis.cpp b/bytecode/BytecodeLivenessAnalysis.cpp index 926334c..80173ac 100644 --- a/bytecode/BytecodeLivenessAnalysis.cpp +++ b/bytecode/BytecodeLivenessAnalysis.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,6 +26,7 @@ #include "config.h" #include "BytecodeLivenessAnalysis.h" +#include "BytecodeKills.h" #include "BytecodeLivenessAnalysisInlines.h" #include "BytecodeUseDef.h" #include "CodeBlock.h" @@ -47,48 +48,9 @@ static bool isValidRegisterForLiveness(CodeBlock* codeBlock, int operand) return false; VirtualRegister virtualReg(operand); - if (!virtualReg.isLocal()) - return false; - - if (codeBlock->captureCount() - && operand <= codeBlock->captureStart() - && operand > codeBlock->captureEnd()) - return false; - - return true; -} - -static void setForOperand(CodeBlock* codeBlock, FastBitVector& bits, int operand) -{ - ASSERT(isValidRegisterForLiveness(codeBlock, operand)); - VirtualRegister virtualReg(operand); - if (virtualReg.offset() > codeBlock->captureStart()) - bits.set(virtualReg.toLocal()); - else - bits.set(virtualReg.toLocal() - codeBlock->captureCount()); + return virtualReg.isLocal(); } -namespace { - -class SetBit { -public: - SetBit(FastBitVector& bits) - : m_bits(bits) - { - } - - void operator()(CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) - { - if (isValidRegisterForLiveness(codeBlock, operand)) - setForOperand(codeBlock, m_bits, operand); - } - -private: - FastBitVector& m_bits; -}; - -} // anonymous namespace - static unsigned getLeaderOffsetForBasicBlock(RefPtr<BytecodeBasicBlock>* basicBlock) { return (*basicBlock)->leaderBytecodeOffset(); @@ -133,28 +95,63 @@ static BytecodeBasicBlock* findBasicBlockForBytecodeOffset(Vector<RefPtr<Bytecod return basicBlock[1].get(); } -static void stepOverInstruction(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& uses, FastBitVector& defs, FastBitVector& out) +// Simplified interface to bytecode use/def, which determines defs first and then uses, and includes +// exception handlers in the uses. +template<typename UseFunctor, typename DefFunctor> +static void stepOverInstruction(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def) { - uses.clearAll(); - defs.clearAll(); - - SetBit setUses(uses); - SetBit setDefs(defs); - computeUsesForBytecodeOffset(codeBlock, bytecodeOffset, setUses); - computeDefsForBytecodeOffset(codeBlock, bytecodeOffset, setDefs); - - out.exclude(defs); - out.merge(uses); + // This abstractly execute the instruction in reverse. Instructions logically first use operands and + // then define operands. This logical ordering is necessary for operations that use and def the same + // operand, like: + // + // op_add loc1, loc1, loc2 + // + // The use of loc1 happens before the def of loc1. That's a semantic requirement since the add + // operation cannot travel forward in time to read the value that it will produce after reading that + // value. Since we are executing in reverse, this means that we must do defs before uses (reverse of + // uses before defs). + // + // Since this is a liveness analysis, this ordering ends up being particularly important: if we did + // uses before defs, then the add operation above would appear to not have loc1 live, since we'd + // first add it to the out set (the use), and then we'd remove it (the def). + computeDefsForBytecodeOffset( + codeBlock, bytecodeOffset, + [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) { + if (isValidRegisterForLiveness(codeBlock, operand)) + def(VirtualRegister(operand).toLocal()); + }); + + computeUsesForBytecodeOffset( + codeBlock, bytecodeOffset, + [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) { + if (isValidRegisterForLiveness(codeBlock, operand)) + use(VirtualRegister(operand).toLocal()); + }); + // If we have an exception handler, we want the live-in variables of the // exception handler block to be included in the live-in of this particular bytecode. if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset)) { BytecodeBasicBlock* handlerBlock = findBasicBlockWithLeaderOffset(basicBlocks, handler->target); ASSERT(handlerBlock); - out.merge(handlerBlock->in()); + handlerBlock->in().forEachSetBit(use); } } +static void stepOverInstruction(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& out) +{ + stepOverInstruction( + codeBlock, basicBlocks, bytecodeOffset, + [&] (unsigned bitIndex) { + // This is the use functor, so we set the bit. + out.set(bitIndex); + }, + [&] (unsigned bitIndex) { + // This is the def functor, so we clear the bit. + out.clear(bitIndex); + }); +} + static void computeLocalLivenessForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<RefPtr<BytecodeBasicBlock> >& basicBlocks, unsigned targetOffset, FastBitVector& result) { ASSERT(!block->isExitBlock()); @@ -162,17 +159,12 @@ static void computeLocalLivenessForBytecodeOffset(CodeBlock* codeBlock, Bytecode FastBitVector out = block->out(); - FastBitVector uses; - FastBitVector defs; - uses.resize(out.numBits()); - defs.resize(out.numBits()); - for (int i = block->bytecodeOffsets().size() - 1; i >= 0; i--) { unsigned bytecodeOffset = block->bytecodeOffsets()[i]; if (targetOffset > bytecodeOffset) break; - stepOverInstruction(codeBlock, basicBlocks, bytecodeOffset, uses, defs, out); + stepOverInstruction(codeBlock, basicBlocks, bytecodeOffset, out); } result.set(out); @@ -188,8 +180,7 @@ static void computeLocalLivenessForBlock(CodeBlock* codeBlock, BytecodeBasicBloc void BytecodeLivenessAnalysis::runLivenessFixpoint() { UnlinkedCodeBlock* unlinkedCodeBlock = m_codeBlock->unlinkedCodeBlock(); - unsigned numberOfVariables = - unlinkedCodeBlock->m_numCalleeRegisters - m_codeBlock->captureCount(); + unsigned numberOfVariables = unlinkedCodeBlock->m_numCalleeRegisters; for (unsigned i = 0; i < m_basicBlocks.size(); i++) { BytecodeBasicBlock* block = m_basicBlocks[i].get(); @@ -204,7 +195,7 @@ void BytecodeLivenessAnalysis::runLivenessFixpoint() newOut.resize(m_basicBlocks.last()->out().numBits()); do { changed = false; - for (int i = m_basicBlocks.size() - 2; i >= 0; i--) { + for (unsigned i = m_basicBlocks.size() - 1; i--;) { BytecodeBasicBlock* block = m_basicBlocks[i].get(); newOut.clearAll(); for (unsigned j = 0; j < block->successors().size(); j++) @@ -216,7 +207,7 @@ void BytecodeLivenessAnalysis::runLivenessFixpoint() } while (changed); } -void BytecodeLivenessAnalysis::getLivenessInfoForNonCapturedVarsAtBytecodeOffset(unsigned bytecodeOffset, FastBitVector& result) +void BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset, FastBitVector& result) { BytecodeBasicBlock* block = findBasicBlockForBytecodeOffset(m_basicBlocks, bytecodeOffset); ASSERT(block); @@ -228,60 +219,47 @@ void BytecodeLivenessAnalysis::getLivenessInfoForNonCapturedVarsAtBytecodeOffset bool BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset(int operand, unsigned bytecodeOffset) { - if (operandIsAlwaysLive(m_codeBlock, operand)) + if (operandIsAlwaysLive(operand)) return true; FastBitVector result; - getLivenessInfoForNonCapturedVarsAtBytecodeOffset(bytecodeOffset, result); - return operandThatIsNotAlwaysLiveIsLive(m_codeBlock, result, operand); + getLivenessInfoAtBytecodeOffset(bytecodeOffset, result); + return operandThatIsNotAlwaysLiveIsLive(result, operand); } -FastBitVector getLivenessInfo(CodeBlock* codeBlock, const FastBitVector& out) +FastBitVector BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset) { - FastBitVector result; - - unsigned numCapturedVars = codeBlock->captureCount(); - if (numCapturedVars) { - int firstCapturedLocal = VirtualRegister(codeBlock->captureStart()).toLocal(); - result.resize(out.numBits() + numCapturedVars); - for (unsigned i = 0; i < numCapturedVars; ++i) - result.set(firstCapturedLocal + i); - } else - result.resize(out.numBits()); - - int outLength = out.numBits(); - ASSERT(outLength >= 0); - for (int i = 0; i < outLength; i++) { - if (!out.get(i)) - continue; - - if (!numCapturedVars) { - result.set(i); - continue; - } - - if (virtualRegisterForLocal(i).offset() > codeBlock->captureStart()) - result.set(i); - else - result.set(numCapturedVars + i); - } - return result; + FastBitVector out; + getLivenessInfoAtBytecodeOffset(bytecodeOffset, out); + return out; } -FastBitVector BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset) +void BytecodeLivenessAnalysis::computeFullLiveness(FullBytecodeLiveness& result) { FastBitVector out; - getLivenessInfoForNonCapturedVarsAtBytecodeOffset(bytecodeOffset, out); - return getLivenessInfo(m_codeBlock, out); + + result.m_map.resize(m_codeBlock->instructions().size()); + + for (unsigned i = m_basicBlocks.size(); i--;) { + BytecodeBasicBlock* block = m_basicBlocks[i].get(); + if (block->isEntryBlock() || block->isExitBlock()) + continue; + + out = block->out(); + + for (unsigned i = block->bytecodeOffsets().size(); i--;) { + unsigned bytecodeOffset = block->bytecodeOffsets()[i]; + stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, out); + result.m_map[bytecodeOffset] = out; + } + } } -void BytecodeLivenessAnalysis::computeFullLiveness(FullBytecodeLiveness& result) +void BytecodeLivenessAnalysis::computeKills(BytecodeKills& result) { FastBitVector out; - FastBitVector uses; - FastBitVector defs; result.m_codeBlock = m_codeBlock; - result.m_map.clear(); + result.m_killSets = std::make_unique<BytecodeKills::KillSet[]>(m_codeBlock->instructions().size()); for (unsigned i = m_basicBlocks.size(); i--;) { BytecodeBasicBlock* block = m_basicBlocks[i].get(); @@ -289,13 +267,22 @@ void BytecodeLivenessAnalysis::computeFullLiveness(FullBytecodeLiveness& result) continue; out = block->out(); - uses.resize(out.numBits()); - defs.resize(out.numBits()); for (unsigned i = block->bytecodeOffsets().size(); i--;) { unsigned bytecodeOffset = block->bytecodeOffsets()[i]; - stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, uses, defs, out); - result.m_map.add(bytecodeOffset, out); + stepOverInstruction( + m_codeBlock, m_basicBlocks, bytecodeOffset, + [&] (unsigned index) { + // This is for uses. + if (out.get(index)) + return; + result.m_killSets[bytecodeOffset].add(index); + out.set(index); + }, + [&] (unsigned index) { + // This is for defs. + out.clear(index); + }); } } } diff --git a/bytecode/BytecodeLivenessAnalysis.h b/bytecode/BytecodeLivenessAnalysis.h index 3499121..3f42c44 100644 --- a/bytecode/BytecodeLivenessAnalysis.h +++ b/bytecode/BytecodeLivenessAnalysis.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +33,7 @@ namespace JSC { +class BytecodeKills; class CodeBlock; class FullBytecodeLiveness; @@ -44,23 +45,22 @@ public: FastBitVector getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset); void computeFullLiveness(FullBytecodeLiveness& result); + void computeKills(BytecodeKills& result); private: void compute(); void runLivenessFixpoint(); void dumpResults(); - void getLivenessInfoForNonCapturedVarsAtBytecodeOffset(unsigned bytecodeOffset, FastBitVector&); + void getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset, FastBitVector&); CodeBlock* m_codeBlock; Vector<RefPtr<BytecodeBasicBlock> > m_basicBlocks; }; -inline bool operandIsAlwaysLive(CodeBlock*, int operand); -inline bool operandThatIsNotAlwaysLiveIsLive(CodeBlock*, const FastBitVector& out, int operand); -inline bool operandIsLive(CodeBlock*, const FastBitVector& out, int operand); - -FastBitVector getLivenessInfo(CodeBlock*, const FastBitVector& out); +inline bool operandIsAlwaysLive(int operand); +inline bool operandThatIsNotAlwaysLiveIsLive(const FastBitVector& out, int operand); +inline bool operandIsLive(const FastBitVector& out, int operand); } // namespace JSC diff --git a/bytecode/BytecodeLivenessAnalysisInlines.h b/bytecode/BytecodeLivenessAnalysisInlines.h index 6587cd2..9b5c755 100644 --- a/bytecode/BytecodeLivenessAnalysisInlines.h +++ b/bytecode/BytecodeLivenessAnalysisInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,27 +32,22 @@ namespace JSC { -inline bool operandIsAlwaysLive(CodeBlock* codeBlock, int operand) +inline bool operandIsAlwaysLive(int operand) { - if (VirtualRegister(operand).isArgument()) - return true; - return operand <= codeBlock->captureStart() && operand > codeBlock->captureEnd(); + return !VirtualRegister(operand).isLocal(); } -inline bool operandThatIsNotAlwaysLiveIsLive(CodeBlock* codeBlock, const FastBitVector& out, int operand) +inline bool operandThatIsNotAlwaysLiveIsLive(const FastBitVector& out, int operand) { - VirtualRegister virtualReg(operand); - if (virtualReg.offset() > codeBlock->captureStart()) - return out.get(virtualReg.toLocal()); - size_t index = virtualReg.toLocal() - codeBlock->captureCount(); - if (index >= out.numBits()) + unsigned local = VirtualRegister(operand).toLocal(); + if (local >= out.numBits()) return false; - return out.get(index); + return out.get(local); } -inline bool operandIsLive(CodeBlock* codeBlock, const FastBitVector& out, int operand) +inline bool operandIsLive(const FastBitVector& out, int operand) { - return operandIsAlwaysLive(codeBlock, operand) || operandThatIsNotAlwaysLiveIsLive(codeBlock, out, operand); + return operandIsAlwaysLive(operand) || operandThatIsNotAlwaysLiveIsLive(out, operand); } } // namespace JSC diff --git a/bytecode/BytecodeUseDef.h b/bytecode/BytecodeUseDef.h index 92449f9..250d322 100644 --- a/bytecode/BytecodeUseDef.h +++ b/bytecode/BytecodeUseDef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,7 @@ namespace JSC { template<typename Functor> void computeUsesForBytecodeOffset( - CodeBlock* codeBlock, unsigned bytecodeOffset, Functor& functor) + CodeBlock* codeBlock, unsigned bytecodeOffset, const Functor& functor) { Interpreter* interpreter = codeBlock->vm()->interpreter; Instruction* instructionsBegin = codeBlock->instructions().begin(); @@ -44,29 +44,24 @@ void computeUsesForBytecodeOffset( case op_new_array_buffer: case op_throw_static_error: case op_debug: - case op_resolve_scope: - case op_pop_scope: case op_jneq_ptr: - case op_new_func_exp: case op_loop_hint: case op_jmp: case op_new_object: - case op_init_lazy_reg: - case op_get_callee: case op_enter: case op_catch: - case op_touch_entry: + case op_profile_control_flow: + case op_create_direct_arguments: + case op_create_out_of_band_arguments: return; - case op_new_func: - case op_new_captured_func: - case op_create_activation: - case op_create_arguments: + case op_get_scope: case op_to_this: - case op_tear_off_activation: + case op_check_tdz: + case op_pop_scope: case op_profile_will_call: case op_profile_did_call: + case op_profile_type: case op_throw: - case op_push_with_scope: case op_end: case op_ret: case op_jtrue: @@ -78,7 +73,6 @@ void computeUsesForBytecodeOffset( functor(codeBlock, instruction, opcodeID, instruction[1].u.operand); return; } - case op_ret_object_or_this: case op_jlesseq: case op_jgreater: case op_jgreatereq: @@ -105,7 +99,10 @@ void computeUsesForBytecodeOffset( case op_put_by_id_transition_normal_out_of_line: case op_put_by_id_out_of_line: case op_put_by_id: - case op_put_to_scope: { + case op_put_getter_by_id: + case op_put_setter_by_id: + case op_put_to_scope: + case op_put_to_arguments: { functor(codeBlock, instruction, opcodeID, instruction[1].u.operand); functor(codeBlock, instruction, opcodeID, instruction[3].u.operand); return; @@ -116,39 +113,51 @@ void computeUsesForBytecodeOffset( functor(codeBlock, instruction, opcodeID, instruction[4].u.operand); return; } + case op_create_lexical_environment: + case op_get_property_enumerator: + case op_get_enumerable_length: + case op_new_func_exp: + case op_to_index_string: case op_init_global_const_nop: case op_init_global_const: case op_push_name_scope: + case op_push_with_scope: + case op_resolve_scope: case op_get_from_scope: case op_to_primitive: case op_get_by_id: case op_get_by_id_out_of_line: case op_get_array_length: - case op_get_arguments_length: case op_typeof: case op_is_undefined: case op_is_boolean: case op_is_number: case op_is_string: case op_is_object: + case op_is_object_or_null: case op_is_function: case op_to_number: + case op_to_string: case op_negate: case op_neq_null: case op_eq_null: case op_not: case op_mov: - case op_captured_mov: case op_new_array_with_size: case op_create_this: - case op_get_pnames: case op_del_by_id: - case op_unsigned: { + case op_unsigned: + case op_new_func: + case op_create_scoped_arguments: + case op_get_from_arguments: { functor(codeBlock, instruction, opcodeID, instruction[2].u.operand); return; } + case op_has_generic_property: + case op_has_indexed_property: + case op_enumerator_structure_pname: + case op_enumerator_generic_pname: case op_get_by_val: - case op_get_argument_by_val: case op_in: case op_instanceof: case op_check_has_instance: @@ -176,6 +185,7 @@ void computeUsesForBytecodeOffset( functor(codeBlock, instruction, opcodeID, instruction[3].u.operand); return; } + case op_has_structure_property: case op_construct_varargs: case op_call_varargs: { functor(codeBlock, instruction, opcodeID, instruction[2].u.operand); @@ -183,19 +193,11 @@ void computeUsesForBytecodeOffset( functor(codeBlock, instruction, opcodeID, instruction[4].u.operand); return; } - case op_next_pname: { - functor(codeBlock, instruction, opcodeID, instruction[2].u.operand); - functor(codeBlock, instruction, opcodeID, instruction[3].u.operand); - functor(codeBlock, instruction, opcodeID, instruction[4].u.operand); - functor(codeBlock, instruction, opcodeID, instruction[5].u.operand); - return; - } - case op_get_by_pname: { + case op_get_direct_pname: { functor(codeBlock, instruction, opcodeID, instruction[2].u.operand); functor(codeBlock, instruction, opcodeID, instruction[3].u.operand); functor(codeBlock, instruction, opcodeID, instruction[4].u.operand); functor(codeBlock, instruction, opcodeID, instruction[5].u.operand); - functor(codeBlock, instruction, opcodeID, instruction[6].u.operand); return; } case op_switch_string: @@ -219,16 +221,10 @@ void computeUsesForBytecodeOffset( int argCount = instruction[3].u.operand; int registerOffset = -instruction[4].u.operand; int lastArg = registerOffset + CallFrame::thisArgumentOffset(); - for (int i = opcodeID == op_construct ? 1 : 0; i < argCount; i++) + for (int i = 0; i < argCount; i++) functor(codeBlock, instruction, opcodeID, lastArg + i); return; } - case op_tear_off_arguments: { - functor(codeBlock, instruction, opcodeID, instruction[1].u.operand); - functor(codeBlock, instruction, opcodeID, unmodifiedArgumentsRegister(VirtualRegister(instruction[1].u.operand)).offset()); - functor(codeBlock, instruction, opcodeID, instruction[2].u.operand); - return; - } default: RELEASE_ASSERT_NOT_REACHED(); break; @@ -236,7 +232,7 @@ void computeUsesForBytecodeOffset( } template<typename Functor> -void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, Functor& functor) +void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, const Functor& functor) { Interpreter* interpreter = codeBlock->vm()->interpreter; Instruction* instructionsBegin = codeBlock->instructions().begin(); @@ -246,10 +242,7 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, // These don't define anything. case op_init_global_const: case op_init_global_const_nop: - case op_push_name_scope: - case op_push_with_scope: case op_put_to_scope: - case op_pop_scope: case op_end: case op_profile_will_call: case op_profile_did_call: @@ -257,7 +250,6 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, case op_throw_static_error: case op_debug: case op_ret: - case op_ret_object_or_this: case op_jmp: case op_jtrue: case op_jfalse: @@ -282,30 +274,41 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, case op_put_by_id_transition_direct_out_of_line: case op_put_by_id_transition_normal: case op_put_by_id_transition_normal_out_of_line: + case op_put_getter_by_id: + case op_put_setter_by_id: case op_put_getter_setter: case op_put_by_val: case op_put_by_val_direct: case op_put_by_index: - case op_tear_off_arguments: - case op_touch_entry: + case op_profile_type: + case op_profile_control_flow: + case op_put_to_arguments: #define LLINT_HELPER_OPCODES(opcode, length) case opcode: FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES); #undef LLINT_HELPER_OPCODES return; // These all have a single destination for the first argument. - case op_next_pname: + case op_to_index_string: + case op_get_enumerable_length: + case op_has_indexed_property: + case op_has_structure_property: + case op_has_generic_property: + case op_get_direct_pname: + case op_get_property_enumerator: + case op_enumerator_structure_pname: + case op_enumerator_generic_pname: + case op_pop_scope: + case op_push_name_scope: + case op_push_with_scope: case op_resolve_scope: case op_strcat: - case op_tear_off_activation: case op_to_primitive: - case op_catch: case op_create_this: case op_new_array: case op_new_array_buffer: case op_new_array_with_size: case op_new_regexp: case op_new_func: - case op_new_captured_func: case op_new_func_exp: case op_call_varargs: case op_construct_varargs: @@ -319,18 +322,17 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, case op_check_has_instance: case op_instanceof: case op_get_by_val: - case op_get_argument_by_val: - case op_get_by_pname: - case op_get_arguments_length: case op_typeof: case op_is_undefined: case op_is_boolean: case op_is_number: case op_is_string: case op_is_object: + case op_is_object_or_null: case op_is_function: case op_in: case op_to_number: + case op_to_string: case op_negate: case op_add: case op_mul: @@ -357,23 +359,24 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset, case op_eq_null: case op_not: case op_mov: - case op_captured_mov: case op_new_object: case op_to_this: - case op_get_callee: - case op_init_lazy_reg: - case op_create_activation: - case op_create_arguments: + case op_check_tdz: + case op_get_scope: + case op_create_direct_arguments: + case op_create_scoped_arguments: + case op_create_out_of_band_arguments: case op_del_by_id: case op_del_by_val: - case op_unsigned: { + case op_unsigned: + case op_get_from_arguments: { functor(codeBlock, instruction, opcodeID, instruction[1].u.operand); return; } - case op_get_pnames: { + case op_catch: + case op_create_lexical_environment: { functor(codeBlock, instruction, opcodeID, instruction[1].u.operand); - functor(codeBlock, instruction, opcodeID, instruction[3].u.operand); - functor(codeBlock, instruction, opcodeID, instruction[4].u.operand); + functor(codeBlock, instruction, opcodeID, instruction[2].u.operand); return; } case op_enter: { diff --git a/bytecode/CallEdge.cpp b/bytecode/CallEdge.cpp new file mode 100644 index 0000000..dffff6d --- /dev/null +++ b/bytecode/CallEdge.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 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 "CallEdge.h" + +namespace JSC { + +void CallEdge::dump(PrintStream& out) const +{ + out.print("<", m_callee, ", count: ", m_count, ">"); +} + +} // namespace JSC + diff --git a/bytecode/CallEdge.h b/bytecode/CallEdge.h new file mode 100644 index 0000000..3045209 --- /dev/null +++ b/bytecode/CallEdge.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014, 2015 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 CallEdge_h +#define CallEdge_h + +#include "CallVariant.h" + +namespace JSC { + +class CallEdge { +public: + CallEdge(); + CallEdge(CallVariant, uint32_t); + + bool operator!() const { return !m_callee; } + + CallVariant callee() const { return m_callee; } + uint32_t count() const { return m_count; } + + CallEdge despecifiedClosure() const + { + return CallEdge(m_callee.despecifiedClosure(), m_count); + } + + void dump(PrintStream&) const; + +private: + CallVariant m_callee; + uint32_t m_count; +}; + +inline CallEdge::CallEdge(CallVariant callee, uint32_t count) + : m_callee(callee) + , m_count(count) +{ +} + +inline CallEdge::CallEdge() + : CallEdge(CallVariant(), 0) +{ +} + +typedef Vector<CallEdge, 1> CallEdgeList; + +} // namespace JSC + +#endif // CallEdge_h + diff --git a/bytecode/CallLinkInfo.cpp b/bytecode/CallLinkInfo.cpp index 72575bd..d920098 100644 --- a/bytecode/CallLinkInfo.cpp +++ b/bytecode/CallLinkInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,28 +29,36 @@ #include "DFGOperations.h" #include "DFGThunks.h" #include "JSCInlines.h" +#include "Repatch.h" #include "RepatchBuffer.h" +#include <wtf/ListDump.h> #include <wtf/NeverDestroyed.h> #if ENABLE(JIT) namespace JSC { +void CallLinkInfo::clearStub() +{ + if (!stub()) + return; + + m_stub->clearCallNodesFor(this); + m_stub = nullptr; +} + void CallLinkInfo::unlink(RepatchBuffer& repatchBuffer) { - ASSERT(isLinked()); + if (!isLinked()) { + // We could be called even if we're not linked anymore because of how polymorphic calls + // work. Each callsite within the polymorphic call stub may separately ask us to unlink(). + RELEASE_ASSERT(!isOnList()); + return; + } - if (Options::showDisassembly()) - dataLog("Unlinking call from ", callReturnLocation, " to ", pointerDump(repatchBuffer.codeBlock()), "\n"); - - repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(RepatchBuffer::startOfBranchPtrWithPatchOnRegister(hotPathBegin), static_cast<MacroAssembler::RegisterID>(calleeGPR), 0); - repatchBuffer.relink( - callReturnLocation, - repatchBuffer.codeBlock()->vm()->getCTIStub(linkThunkGeneratorFor( - (callType == Construct || callType == ConstructVarargs)? CodeForConstruct : CodeForCall, - isFTL ? MustPreserveRegisters : RegisterPreservationNotRequired)).code()); - hasSeenShouldRepatch = false; - callee.clear(); - stub.clear(); + unlinkFor( + repatchBuffer, *this, + (m_callType == Construct || m_callType == ConstructVarargs)? CodeForConstruct : CodeForCall, + m_isFTL ? MustPreserveRegisters : RegisterPreservationNotRequired); // It will be on a list if the callee has a code block. if (isOnList()) @@ -59,31 +67,41 @@ void CallLinkInfo::unlink(RepatchBuffer& repatchBuffer) void CallLinkInfo::visitWeak(RepatchBuffer& repatchBuffer) { + auto handleSpecificCallee = [&] (JSFunction* callee) { + if (Heap::isMarked(callee->executable())) + m_hasSeenClosure = true; + else + m_clearedByGC = true; + }; + if (isLinked()) { - if (stub) { - if (!Heap::isMarked(stub->structure()) - || !Heap::isMarked(stub->executable())) { + if (stub()) { + if (!stub()->visitWeak(repatchBuffer)) { if (Options::verboseOSR()) { dataLog( "Clearing closure call from ", *repatchBuffer.codeBlock(), " to ", - stub->executable()->hashFor(specializationKind()), - ", stub routine ", RawPointer(stub.get()), ".\n"); + listDump(stub()->variants()), ", stub routine ", RawPointer(stub()), + ".\n"); } unlink(repatchBuffer); + m_clearedByGC = true; } - } else if (!Heap::isMarked(callee.get())) { + } else if (!Heap::isMarked(m_callee.get())) { if (Options::verboseOSR()) { dataLog( "Clearing call from ", *repatchBuffer.codeBlock(), " to ", - RawPointer(callee.get()), " (", - callee.get()->executable()->hashFor(specializationKind()), + RawPointer(m_callee.get()), " (", + m_callee.get()->executable()->hashFor(specializationKind()), ").\n"); } + handleSpecificCallee(m_callee.get()); unlink(repatchBuffer); } } - if (!!lastSeenCallee && !Heap::isMarked(lastSeenCallee.get())) - lastSeenCallee.clear(); + if (haveLastSeenCallee() && !Heap::isMarked(lastSeenCallee())) { + handleSpecificCallee(lastSeenCallee()); + clearLastSeenCallee(); + } } CallLinkInfo& CallLinkInfo::dummy() diff --git a/bytecode/CallLinkInfo.h b/bytecode/CallLinkInfo.h index 88094ff..0277ecf 100644 --- a/bytecode/CallLinkInfo.h +++ b/bytecode/CallLinkInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,12 +26,12 @@ #ifndef CallLinkInfo_h #define CallLinkInfo_h -#include "ClosureCallStubRoutine.h" #include "CodeLocation.h" #include "CodeSpecializationKind.h" #include "JITWriteBarrier.h" #include "JSFunction.h" #include "Opcode.h" +#include "PolymorphicCallStubRoutine.h" #include "WriteBarrier.h" #include <wtf/SentinelLinkedList.h> @@ -41,7 +41,8 @@ namespace JSC { class RepatchBuffer; -struct CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> { +class CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> { +public: enum CallType { None, Call, CallVarargs, Construct, ConstructVarargs }; static CallType callTypeFor(OpcodeID opcodeID) { @@ -54,62 +55,234 @@ struct CallLinkInfo : public BasicRawSentinelNode<CallLinkInfo> { ASSERT(opcodeID == op_call_varargs); return CallVarargs; } - + CallLinkInfo() - : isFTL(false) - , hasSeenShouldRepatch(false) - , hasSeenClosure(false) - , callType(None) - , slowPathCount(0) + : m_isFTL(false) + , m_hasSeenShouldRepatch(false) + , m_hasSeenClosure(false) + , m_clearedByGC(false) + , m_callType(None) + , m_maxNumArguments(0) + , m_slowPathCount(0) { } ~CallLinkInfo() { + clearStub(); + if (isOnList()) remove(); } - CodeSpecializationKind specializationKind() const + static CodeSpecializationKind specializationKindFor(CallType callType) { return specializationFromIsConstruct(callType == Construct || callType == ConstructVarargs); } + CodeSpecializationKind specializationKind() const + { + return specializationKindFor(static_cast<CallType>(m_callType)); + } - CodeLocationNearCall callReturnLocation; - CodeLocationDataLabelPtr hotPathBegin; - CodeLocationNearCall hotPathOther; - JITWriteBarrier<JSFunction> callee; - WriteBarrier<JSFunction> lastSeenCallee; - RefPtr<ClosureCallStubRoutine> stub; - bool isFTL : 1; - bool hasSeenShouldRepatch : 1; - bool hasSeenClosure : 1; - unsigned callType : 5; // CallType - unsigned calleeGPR : 8; - unsigned slowPathCount; - CodeOrigin codeOrigin; - - bool isLinked() { return stub || callee; } + bool isLinked() { return m_stub || m_callee; } void unlink(RepatchBuffer&); + void setUpCall(CallType callType, CodeOrigin codeOrigin, unsigned calleeGPR) + { + m_callType = callType; + m_codeOrigin = codeOrigin; + m_calleeGPR = calleeGPR; + } + + void setCallLocations(CodeLocationNearCall callReturnLocation, CodeLocationDataLabelPtr hotPathBegin, + CodeLocationNearCall hotPathOther) + { + m_callReturnLocation = callReturnLocation; + m_hotPathBegin = hotPathBegin; + m_hotPathOther = hotPathOther; + } + + void setUpCallFromFTL(CallType callType, CodeOrigin codeOrigin, + CodeLocationNearCall callReturnLocation, CodeLocationDataLabelPtr hotPathBegin, + CodeLocationNearCall hotPathOther, unsigned calleeGPR) + { + m_isFTL = true; + m_callType = callType; + m_codeOrigin = codeOrigin; + m_callReturnLocation = callReturnLocation; + m_hotPathBegin = hotPathBegin; + m_hotPathOther = hotPathOther; + m_calleeGPR = calleeGPR; + } + + CodeLocationNearCall callReturnLocation() + { + return m_callReturnLocation; + } + + CodeLocationDataLabelPtr hotPathBegin() + { + return m_hotPathBegin; + } + + CodeLocationNearCall hotPathOther() + { + return m_hotPathOther; + } + + void setCallee(VM& vm, CodeLocationDataLabelPtr location, JSCell* owner, JSFunction* callee) + { + m_callee.set(vm, location, owner, callee); + } + + void clearCallee() + { + m_callee.clear(); + } + + JSFunction* callee() + { + return m_callee.get(); + } + + void setLastSeenCallee(VM& vm, const JSCell* owner, JSFunction* callee) + { + m_lastSeenCallee.set(vm, owner, callee); + } + + void clearLastSeenCallee() + { + m_lastSeenCallee.clear(); + } + + JSFunction* lastSeenCallee() + { + return m_lastSeenCallee.get(); + } + + bool haveLastSeenCallee() + { + return !!m_lastSeenCallee; + } + + void setStub(PassRefPtr<PolymorphicCallStubRoutine> newStub) + { + clearStub(); + m_stub = newStub; + } + + void clearStub(); + + PolymorphicCallStubRoutine* stub() + { + return m_stub.get(); + } + bool seenOnce() { - return hasSeenShouldRepatch; + return m_hasSeenShouldRepatch; + } + + void clearSeen() + { + m_hasSeenShouldRepatch = false; } void setSeen() { - hasSeenShouldRepatch = true; + m_hasSeenShouldRepatch = true; } - + + bool hasSeenClosure() + { + return m_hasSeenClosure; + } + + void setHasSeenClosure() + { + m_hasSeenClosure = true; + } + + bool clearedByGC() + { + return m_clearedByGC; + } + + void setCallType(CallType callType) + { + m_callType = callType; + } + + CallType callType() + { + return static_cast<CallType>(m_callType); + } + + uint8_t* addressOfMaxNumArguments() + { + return &m_maxNumArguments; + } + + uint8_t maxNumArguments() + { + return m_maxNumArguments; + } + + static ptrdiff_t offsetOfSlowPathCount() + { + return OBJECT_OFFSETOF(CallLinkInfo, m_slowPathCount); + } + + void setCalleeGPR(unsigned calleeGPR) + { + m_calleeGPR = calleeGPR; + } + + unsigned calleeGPR() + { + return m_calleeGPR; + } + + uint32_t slowPathCount() + { + return m_slowPathCount; + } + + void setCodeOrigin(CodeOrigin codeOrigin) + { + m_codeOrigin = codeOrigin; + } + + CodeOrigin codeOrigin() + { + return m_codeOrigin; + } + void visitWeak(RepatchBuffer&); - + static CallLinkInfo& dummy(); + +private: + CodeLocationNearCall m_callReturnLocation; + CodeLocationDataLabelPtr m_hotPathBegin; + CodeLocationNearCall m_hotPathOther; + JITWriteBarrier<JSFunction> m_callee; + WriteBarrier<JSFunction> m_lastSeenCallee; + RefPtr<PolymorphicCallStubRoutine> m_stub; + bool m_isFTL : 1; + bool m_hasSeenShouldRepatch : 1; + bool m_hasSeenClosure : 1; + bool m_clearedByGC : 1; + unsigned m_callType : 4; // CallType + unsigned m_calleeGPR : 8; + uint8_t m_maxNumArguments; // Only used for varargs calls. + uint32_t m_slowPathCount; + CodeOrigin m_codeOrigin; }; inline CodeOrigin getCallLinkInfoCodeOrigin(CallLinkInfo& callLinkInfo) { - return callLinkInfo.codeOrigin; + return callLinkInfo.codeOrigin(); } typedef HashMap<CodeOrigin, CallLinkInfo*, CodeOriginApproximateHash> CallLinkInfoMap; diff --git a/bytecode/CallLinkStatus.cpp b/bytecode/CallLinkStatus.cpp index 29a9237..103a7f2 100644 --- a/bytecode/CallLinkStatus.cpp +++ b/bytecode/CallLinkStatus.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,57 +32,22 @@ #include "LLIntCallLinkInfo.h" #include "JSCInlines.h" #include <wtf/CommaPrinter.h> +#include <wtf/ListDump.h> namespace JSC { static const bool verbose = false; CallLinkStatus::CallLinkStatus(JSValue value) - : m_callTarget(value) - , m_executable(0) - , m_structure(0) - , m_couldTakeSlowPath(false) + : m_couldTakeSlowPath(false) , m_isProved(false) { - if (!value || !value.isCell()) + if (!value || !value.isCell()) { + m_couldTakeSlowPath = true; return; + } - m_structure = value.asCell()->structure(); - - if (!value.asCell()->inherits(JSFunction::info())) - return; - - m_executable = jsCast<JSFunction*>(value.asCell())->executable(); -} - -JSFunction* CallLinkStatus::function() const -{ - if (!m_callTarget || !m_callTarget.isCell()) - return 0; - - if (!m_callTarget.asCell()->inherits(JSFunction::info())) - return 0; - - return jsCast<JSFunction*>(m_callTarget.asCell()); -} - -InternalFunction* CallLinkStatus::internalFunction() const -{ - if (!m_callTarget || !m_callTarget.isCell()) - return 0; - - if (!m_callTarget.asCell()->inherits(InternalFunction::info())) - return 0; - - return jsCast<InternalFunction*>(m_callTarget.asCell()); -} - -Intrinsic CallLinkStatus::intrinsicFor(CodeSpecializationKind kind) const -{ - if (!m_executable) - return NoIntrinsic; - - return m_executable->intrinsicFor(kind); + m_variants.append(CallVariant(value.asCell())); } CallLinkStatus CallLinkStatus::computeFromLLInt(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex) @@ -90,7 +55,7 @@ CallLinkStatus CallLinkStatus::computeFromLLInt(const ConcurrentJITLocker& locke UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); #if ENABLE(DFG_JIT) - if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction))) { + if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCell))) { // We could force this to be a closure call, but instead we'll just assume that it // takes slow path. return takesSlowPath(); @@ -120,31 +85,59 @@ CallLinkStatus CallLinkStatus::computeFor( UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(map); #if ENABLE(DFG_JIT) - if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCacheWatchpoint)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable))) - return takesSlowPath(); + ExitSiteData exitSiteData = computeExitSiteData(locker, profiledBlock, bytecodeIndex); CallLinkInfo* callLinkInfo = map.get(CodeOrigin(bytecodeIndex)); - if (!callLinkInfo) - return computeFromLLInt(locker, profiledBlock, bytecodeIndex); - - CallLinkStatus result = computeFor(locker, *callLinkInfo); - if (!result) + if (!callLinkInfo) { + if (exitSiteData.m_takesSlowPath) + return takesSlowPath(); return computeFromLLInt(locker, profiledBlock, bytecodeIndex); + } - if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction))) - result.makeClosureCall(); - - return result; + return computeFor(locker, profiledBlock, *callLinkInfo, exitSiteData); #else return CallLinkStatus(); #endif } +CallLinkStatus::ExitSiteData CallLinkStatus::computeExitSiteData( + const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex) +{ + ExitSiteData exitSiteData; + +#if ENABLE(DFG_JIT) + exitSiteData.m_takesSlowPath = + profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType)) + || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable)); + exitSiteData.m_badFunction = + profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCell)); +#else + UNUSED_PARAM(locker); + UNUSED_PARAM(profiledBlock); + UNUSED_PARAM(bytecodeIndex); +#endif + + return exitSiteData; +} + #if ENABLE(JIT) -CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) +CallLinkStatus CallLinkStatus::computeFor( + const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo) +{ + // We don't really need this, but anytime we have to debug this code, it becomes indispensable. + UNUSED_PARAM(profiledBlock); + + CallLinkStatus result = computeFromCallLinkInfo(locker, callLinkInfo); + result.m_maxNumArguments = callLinkInfo.maxNumArguments(); + return result; +} + +CallLinkStatus CallLinkStatus::computeFromCallLinkInfo( + const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo) { + if (callLinkInfo.clearedByGC()) + return takesSlowPath(); + // Note that despite requiring that the locker is held, this code is racy with respect // to the CallLinkInfo: it may get cleared while this code runs! This is because // CallLinkInfo::unlink() may be called from a different CodeBlock than the one that owns @@ -158,20 +151,90 @@ CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkIn // that is still marginally valid (i.e. the pointers ain't stale). This kind of raciness // is probably OK for now. - if (callLinkInfo.slowPathCount >= Options::couldTakeSlowCaseMinimumCount()) - return takesSlowPath(); + // PolymorphicCallStubRoutine is a GCAwareJITStubRoutine, so if non-null, it will stay alive + // until next GC even if the CallLinkInfo is concurrently cleared. Also, the variants list is + // never mutated after the PolymorphicCallStubRoutine is instantiated. We have some conservative + // fencing in place to make sure that we see the variants list after construction. + if (PolymorphicCallStubRoutine* stub = callLinkInfo.stub()) { + WTF::loadLoadFence(); + + CallEdgeList edges = stub->edges(); + + // Now that we've loaded the edges list, there are no further concurrency concerns. We will + // just manipulate and prune this list to our liking - mostly removing entries that are too + // infrequent and ensuring that it's sorted in descending order of frequency. + + RELEASE_ASSERT(edges.size()); + + std::sort( + edges.begin(), edges.end(), + [] (CallEdge a, CallEdge b) { + return a.count() > b.count(); + }); + RELEASE_ASSERT(edges.first().count() >= edges.last().count()); + + double totalCallsToKnown = 0; + double totalCallsToUnknown = callLinkInfo.slowPathCount(); + CallVariantList variants; + for (size_t i = 0; i < edges.size(); ++i) { + CallEdge edge = edges[i]; + // If the call is at the tail of the distribution, then we don't optimize it and we + // treat it as if it was a call to something unknown. We define the tail as being either + // a call that doesn't belong to the N most frequent callees (N = + // maxPolymorphicCallVariantsForInlining) or that has a total call count that is too + // small. + if (i >= Options::maxPolymorphicCallVariantsForInlining() + || edge.count() < Options::frequentCallThreshold()) + totalCallsToUnknown += edge.count(); + else { + totalCallsToKnown += edge.count(); + variants.append(edge.callee()); + } + } + + // Bail if we didn't find any calls that qualified. + RELEASE_ASSERT(!!totalCallsToKnown == !!variants.size()); + if (variants.isEmpty()) + return takesSlowPath(); + + // We require that the distribution of callees is skewed towards a handful of common ones. + if (totalCallsToKnown / totalCallsToUnknown < Options::minimumCallToKnownRate()) + return takesSlowPath(); + + RELEASE_ASSERT(totalCallsToKnown); + RELEASE_ASSERT(variants.size()); + + CallLinkStatus result; + result.m_variants = variants; + result.m_couldTakeSlowPath = !!totalCallsToUnknown; + return result; + } - if (ClosureCallStubRoutine* stub = callLinkInfo.stub.get()) - return CallLinkStatus(stub->executable(), stub->structure()); + CallLinkStatus result; - JSFunction* target = callLinkInfo.lastSeenCallee.get(); - if (!target) - return CallLinkStatus(); + if (JSFunction* target = callLinkInfo.lastSeenCallee()) { + CallVariant variant(target); + if (callLinkInfo.hasSeenClosure()) + variant = variant.despecifiedClosure(); + result.m_variants.append(variant); + } - if (callLinkInfo.hasSeenClosure) - return CallLinkStatus(target->executable(), target->structure()); + result.m_couldTakeSlowPath = !!callLinkInfo.slowPathCount(); + + return result; +} - return CallLinkStatus(target); +CallLinkStatus CallLinkStatus::computeFor( + const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo, + ExitSiteData exitSiteData) +{ + CallLinkStatus result = computeFor(locker, profiledBlock, callLinkInfo); + if (exitSiteData.m_badFunction) + result.makeClosureCall(); + if (exitSiteData.m_takesSlowPath) + result.m_couldTakeSlowPath = true; + + return result; } #endif @@ -183,10 +246,7 @@ void CallLinkStatus::computeDFGStatuses( CodeBlock* baselineCodeBlock = dfgCodeBlock->alternative(); for (auto iter = dfgCodeBlock->callLinkInfosBegin(); !!iter; ++iter) { CallLinkInfo& info = **iter; - CodeOrigin codeOrigin = info.codeOrigin; - - bool takeSlowPath; - bool badFunction; + CodeOrigin codeOrigin = info.codeOrigin(); // Check if we had already previously made a terrible mistake in the FTL for this // code origin. Note that this is approximate because we could have a monovariant @@ -197,28 +257,16 @@ void CallLinkStatus::computeDFGStatuses( // InlineCallFrames. CodeBlock* currentBaseline = baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock); + ExitSiteData exitSiteData; { ConcurrentJITLocker locker(currentBaseline->m_lock); - takeSlowPath = - currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadCache, ExitFromFTL)) - || currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadCacheWatchpoint, ExitFromFTL)) - || currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadExecutable, ExitFromFTL)); - badFunction = - currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadFunction, ExitFromFTL)); + exitSiteData = computeExitSiteData( + locker, currentBaseline, codeOrigin.bytecodeIndex); } { ConcurrentJITLocker locker(dfgCodeBlock->m_lock); - if (takeSlowPath) - map.add(info.codeOrigin, takesSlowPath()); - else { - CallLinkStatus status = computeFor(locker, info); - if (status.isSet()) { - if (badFunction) - status.makeClosureCall(); - map.add(info.codeOrigin, status); - } - } + map.add(info.codeOrigin(), computeFor(locker, dfgCodeBlock, info, exitSiteData)); } } #else @@ -247,6 +295,27 @@ CallLinkStatus CallLinkStatus::computeFor( return computeFor(profiledBlock, codeOrigin.bytecodeIndex, baselineMap); } +void CallLinkStatus::setProvenConstantCallee(CallVariant variant) +{ + m_variants = CallVariantList{ variant }; + m_couldTakeSlowPath = false; + m_isProved = true; +} + +bool CallLinkStatus::isClosureCall() const +{ + for (unsigned i = m_variants.size(); i--;) { + if (m_variants[i].isClosureCall()) + return true; + } + return false; +} + +void CallLinkStatus::makeClosureCall() +{ + m_variants = despecifiedVariantList(m_variants); +} + void CallLinkStatus::dump(PrintStream& out) const { if (!isSet()) { @@ -262,17 +331,11 @@ void CallLinkStatus::dump(PrintStream& out) const if (m_couldTakeSlowPath) out.print(comma, "Could Take Slow Path"); - if (m_callTarget) - out.print(comma, "Known target: ", m_callTarget); - - if (m_executable) { - out.print(comma, "Executable/CallHash: ", RawPointer(m_executable)); - if (!isCompilationThread()) - out.print("/", m_executable->hashFor(CodeForCall)); - } + if (!m_variants.isEmpty()) + out.print(comma, listDump(m_variants)); - if (m_structure) - out.print(comma, "Structure: ", RawPointer(m_structure)); + if (m_maxNumArguments) + out.print(comma, "maxNumArguments = ", m_maxNumArguments); } } // namespace JSC diff --git a/bytecode/CallLinkStatus.h b/bytecode/CallLinkStatus.h index 99b2fdc..a307ca0 100644 --- a/bytecode/CallLinkStatus.h +++ b/bytecode/CallLinkStatus.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,9 +27,11 @@ #define CallLinkStatus_h #include "CallLinkInfo.h" +#include "CallVariant.h" #include "CodeOrigin.h" #include "CodeSpecializationKind.h" #include "ConcurrentJITLock.h" +#include "ExitingJITType.h" #include "Intrinsic.h" #include "JSCJSValue.h" @@ -40,14 +42,12 @@ class ExecutableBase; class InternalFunction; class JSFunction; class Structure; -struct CallLinkInfo; +class CallLinkInfo; class CallLinkStatus { public: CallLinkStatus() - : m_executable(0) - , m_structure(0) - , m_couldTakeSlowPath(false) + : m_couldTakeSlowPath(false) , m_isProved(false) { } @@ -61,28 +61,34 @@ public: explicit CallLinkStatus(JSValue); - CallLinkStatus(ExecutableBase* executable, Structure* structure) - : m_executable(executable) - , m_structure(structure) + CallLinkStatus(CallVariant variant) + : m_variants(1, variant) , m_couldTakeSlowPath(false) , m_isProved(false) { - ASSERT(!!executable == !!structure); - } - - CallLinkStatus& setIsProved(bool isProved) - { - m_isProved = isProved; - return *this; } static CallLinkStatus computeFor( CodeBlock*, unsigned bytecodeIndex, const CallLinkInfoMap&); + struct ExitSiteData { + ExitSiteData() + : m_takesSlowPath(false) + , m_badFunction(false) + { + } + + bool m_takesSlowPath; + bool m_badFunction; + }; + static ExitSiteData computeExitSiteData(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex); + #if ENABLE(JIT) // Computes the status assuming that we never took slow path and never previously // exited. - static CallLinkStatus computeFor(const ConcurrentJITLocker&, CallLinkInfo&); + static CallLinkStatus computeFor(const ConcurrentJITLocker&, CodeBlock*, CallLinkInfo&); + static CallLinkStatus computeFor( + const ConcurrentJITLocker&, CodeBlock*, CallLinkInfo&, ExitSiteData); #endif typedef HashMap<CodeOrigin, CallLinkStatus, CodeOriginApproximateHash> ContextMap; @@ -96,39 +102,40 @@ public: static CallLinkStatus computeFor( CodeBlock*, CodeOrigin, const CallLinkInfoMap&, const ContextMap&); - bool isSet() const { return m_callTarget || m_executable || m_couldTakeSlowPath; } + void setProvenConstantCallee(CallVariant); + + bool isSet() const { return !m_variants.isEmpty() || m_couldTakeSlowPath; } bool operator!() const { return !isSet(); } bool couldTakeSlowPath() const { return m_couldTakeSlowPath; } - bool isClosureCall() const { return m_executable && !m_callTarget; } - - JSValue callTarget() const { return m_callTarget; } - JSFunction* function() const; - InternalFunction* internalFunction() const; - Intrinsic intrinsicFor(CodeSpecializationKind) const; - ExecutableBase* executable() const { return m_executable; } - Structure* structure() const { return m_structure; } + + CallVariantList variants() const { return m_variants; } + unsigned size() const { return m_variants.size(); } + CallVariant at(unsigned i) const { return m_variants[i]; } + CallVariant operator[](unsigned i) const { return at(i); } bool isProved() const { return m_isProved; } - bool canOptimize() const { return (m_callTarget || m_executable) && !m_couldTakeSlowPath; } + bool canOptimize() const { return !m_variants.isEmpty(); } + + bool isClosureCall() const; // Returns true if any callee is a closure call. + + unsigned maxNumArguments() const { return m_maxNumArguments; } void dump(PrintStream&) const; private: - void makeClosureCall() - { - ASSERT(!m_isProved); - // Turn this into a closure call. - m_callTarget = JSValue(); - } + void makeClosureCall(); static CallLinkStatus computeFromLLInt(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex); +#if ENABLE(JIT) + static CallLinkStatus computeFromCallLinkInfo( + const ConcurrentJITLocker&, CallLinkInfo&); +#endif - JSValue m_callTarget; - ExecutableBase* m_executable; - Structure* m_structure; + CallVariantList m_variants; bool m_couldTakeSlowPath; bool m_isProved; + unsigned m_maxNumArguments; }; } // namespace JSC diff --git a/bytecode/CallVariant.cpp b/bytecode/CallVariant.cpp new file mode 100644 index 0000000..9745dde --- /dev/null +++ b/bytecode/CallVariant.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014, 2015 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 "CallVariant.h" + +#include "JSCInlines.h" +#include <wtf/ListDump.h> + +namespace JSC { + +void CallVariant::dump(PrintStream& out) const +{ + if (!*this) { + out.print("null"); + return; + } + + if (InternalFunction* internalFunction = this->internalFunction()) { + out.print("InternalFunction: ", JSValue(internalFunction)); + return; + } + + if (JSFunction* function = this->function()) { + out.print("(Function: ", JSValue(function), "; Executable: ", *executable(), ")"); + return; + } + + out.print("Executable: ", *executable()); +} + +CallVariantList variantListWithVariant(const CallVariantList& list, CallVariant variantToAdd) +{ + ASSERT(variantToAdd); + CallVariantList result; + for (CallVariant variant : list) { + ASSERT(variant); + if (!!variantToAdd) { + if (variant == variantToAdd) + variantToAdd = CallVariant(); + else if (variant.despecifiedClosure() == variantToAdd.despecifiedClosure()) { + variant = variant.despecifiedClosure(); + variantToAdd = CallVariant(); + } + } + result.append(variant); + } + if (!!variantToAdd) + result.append(variantToAdd); + + if (!ASSERT_DISABLED) { + for (unsigned i = 0; i < result.size(); ++i) { + for (unsigned j = i + 1; j < result.size(); ++j) { + if (result[i] != result[j]) + continue; + + dataLog("variantListWithVariant(", listDump(list), ", ", variantToAdd, ") failed: got duplicates in result: ", listDump(result), "\n"); + RELEASE_ASSERT_NOT_REACHED(); + } + } + } + + return result; +} + +CallVariantList despecifiedVariantList(const CallVariantList& list) +{ + CallVariantList result; + for (CallVariant variant : list) + result = variantListWithVariant(result, variant.despecifiedClosure()); + return result; +} + +} // namespace JSC + diff --git a/bytecode/CallVariant.h b/bytecode/CallVariant.h new file mode 100644 index 0000000..2514f72 --- /dev/null +++ b/bytecode/CallVariant.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2014, 2015 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 CallVariant_h +#define CallVariant_h + +#include "Executable.h" +#include "JSCell.h" +#include "JSFunction.h" + +namespace JSC { + +// The CallVariant class is meant to encapsulate a callee in a way that is useful for call linking +// and inlining. Because JavaScript has closures, and because JSC implements the notion of internal +// non-function objects that nevertheless provide call traps, the call machinery wants to see a +// callee in one of the following four forms: +// +// JSFunction callee: This means that we expect the callsite to always call a particular function +// instance, that is associated with a particular lexical environment. This pinpoints not +// just the code that will be called (i.e. the executable) but also the scope within which +// the code runs. +// +// Executable callee: This corresponds to a call to a closure. In this case, we know that the +// callsite will call a JSFunction, but we do not know which particular JSFunction. We do know +// what code will be called - i.e. we know the executable. +// +// InternalFunction callee: JSC supports a special kind of native functions that support bizarre +// semantics. These are always singletons. If we know that the callee is an InternalFunction +// then we know both the code that will be called and the scope; in fact the "scope" is really +// just the InternalFunction itself. +// +// Something else: It's possible call all manner of rubbish in JavaScript. This implicitly supports +// bizarre object callees, but it can't really tell you anything interesting about them other +// than the fact that they don't fall into any of the above categories. +// +// This class serves as a kind of union over these four things. It does so by just holding a +// JSCell*. We determine which of the modes its in by doing type checks on the cell. Note that we +// cannot use WriteBarrier<> here because this gets used inside the compiler. + +class CallVariant { +public: + explicit CallVariant(JSCell* callee = nullptr) + : m_callee(callee) + { + } + + CallVariant(WTF::HashTableDeletedValueType) + : m_callee(deletedToken()) + { + } + + bool operator!() const { return !m_callee; } + + // If this variant refers to a function, change it to refer to its executable. + ALWAYS_INLINE CallVariant despecifiedClosure() const + { + if (m_callee->type() == JSFunctionType) + return CallVariant(jsCast<JSFunction*>(m_callee)->executable()); + return *this; + } + + JSCell* rawCalleeCell() const { return m_callee; } + + InternalFunction* internalFunction() const + { + return jsDynamicCast<InternalFunction*>(m_callee); + } + + JSFunction* function() const + { + return jsDynamicCast<JSFunction*>(m_callee); + } + + bool isClosureCall() const { return !!jsDynamicCast<ExecutableBase*>(m_callee); } + + ExecutableBase* executable() const + { + if (JSFunction* function = this->function()) + return function->executable(); + return jsDynamicCast<ExecutableBase*>(m_callee); + } + + JSCell* nonExecutableCallee() const + { + RELEASE_ASSERT(!isClosureCall()); + return m_callee; + } + + Intrinsic intrinsicFor(CodeSpecializationKind kind) const + { + if (ExecutableBase* executable = this->executable()) + return executable->intrinsicFor(kind); + return NoIntrinsic; + } + + FunctionExecutable* functionExecutable() const + { + if (ExecutableBase* executable = this->executable()) + return jsDynamicCast<FunctionExecutable*>(executable); + return nullptr; + } + + void dump(PrintStream& out) const; + + bool isHashTableDeletedValue() const + { + return m_callee == deletedToken(); + } + + bool operator==(const CallVariant& other) const + { + return m_callee == other.m_callee; + } + + bool operator!=(const CallVariant& other) const + { + return !(*this == other); + } + + bool operator<(const CallVariant& other) const + { + return m_callee < other.m_callee; + } + + bool operator>(const CallVariant& other) const + { + return other < *this; + } + + bool operator<=(const CallVariant& other) const + { + return !(*this < other); + } + + bool operator>=(const CallVariant& other) const + { + return other <= *this; + } + + unsigned hash() const + { + return WTF::PtrHash<JSCell*>::hash(m_callee); + } + +private: + static JSCell* deletedToken() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); } + + JSCell* m_callee; +}; + +struct CallVariantHash { + static unsigned hash(const CallVariant& key) { return key.hash(); } + static bool equal(const CallVariant& a, const CallVariant& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +typedef Vector<CallVariant, 1> CallVariantList; + +// Returns a new variant list by attempting to either append the given variant or merge it with one +// of the variants we already have by despecifying closures. +CallVariantList variantListWithVariant(const CallVariantList&, CallVariant); + +// Returns a new list where every element is despecified, and the list is deduplicated. +CallVariantList despecifiedVariantList(const CallVariantList&); + +} // namespace JSC + +namespace WTF { + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::CallVariant> { + typedef JSC::CallVariantHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::CallVariant> : SimpleClassHashTraits<JSC::CallVariant> { }; + +} // namespace WTF + +#endif // CallVariant_h + diff --git a/bytecode/CodeBlock.cpp b/bytecode/CodeBlock.cpp index da60b48..3ad7527 100644 --- a/bytecode/CodeBlock.cpp +++ b/bytecode/CodeBlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008-2010, 2012-2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without @@ -30,6 +30,7 @@ #include "config.h" #include "CodeBlock.h" +#include "BasicBlockLocation.h" #include "BytecodeGenerator.h" #include "BytecodeUseDef.h" #include "CallLinkStatus.h" @@ -39,12 +40,13 @@ #include "DFGJITCode.h" #include "DFGWorklist.h" #include "Debugger.h" +#include "FunctionExecutableDump.h" #include "Interpreter.h" #include "JIT.h" #include "JITStubs.h" -#include "JSActivation.h" #include "JSCJSValue.h" #include "JSFunction.h" +#include "JSLexicalEnvironment.h" #include "JSNameScope.h" #include "LLIntEntrypoint.h" #include "LowLevelInterpreter.h" @@ -56,11 +58,15 @@ #include "Repatch.h" #include "RepatchBuffer.h" #include "SlotVisitorInlines.h" +#include "StackVisitor.h" +#include "TypeLocationCache.h" +#include "TypeProfiler.h" #include "UnlinkedInstructionStream.h" #include <wtf/BagToHashMap.h> #include <wtf/CommaPrinter.h> #include <wtf/StringExtras.h> #include <wtf/StringPrintStream.h> +#include <wtf/text/UniquedStringImpl.h> #if ENABLE(DFG_JIT) #include "DFGOperations.h" @@ -148,9 +154,11 @@ void CodeBlock::dumpAssumingJITType(PrintStream& out, JITCode::JITType jitType) out.print(specializationKind()); out.print(", ", instructionCount()); if (this->jitType() == JITCode::BaselineJIT && m_shouldAlwaysBeInlined) - out.print(" (SABI)"); + out.print(" (ShouldAlwaysBeInlined)"); if (ownerExecutable()->neverInline()) out.print(" (NeverInline)"); + if (ownerExecutable()->didTryToEnterInLoop()) + out.print(" (DidTryToEnterInLoop)"); if (ownerExecutable()->isStrictMode()) out.print(" (StrictMode)"); if (this->jitType() == JITCode::BaselineJIT && m_didFailFTLCompilation) @@ -165,11 +173,6 @@ void CodeBlock::dump(PrintStream& out) const dumpAssumingJITType(out, jitType()); } -static CString constantName(int k, JSValue value) -{ - return toCString(value, "(@k", k - FirstConstantRegisterIndex, ")"); -} - static CString idName(int id0, const Identifier& ident) { return toCString(ident.impl(), "(@id", id0, ")"); @@ -177,19 +180,16 @@ static CString idName(int id0, const Identifier& ident) CString CodeBlock::registerName(int r) const { - if (r == missingThisObjectMarker()) - return "<null>"; - if (isConstantRegisterIndex(r)) - return constantName(r, getConstant(r)); + return constantName(r); - if (operandIsArgument(r)) { - if (!VirtualRegister(r).toArgument()) - return "this"; - return toCString("arg", VirtualRegister(r).toArgument()); - } + return toCString(VirtualRegister(r)); +} - return toCString("loc", VirtualRegister(r).toLocal()); +CString CodeBlock::constantName(int index) const +{ + JSValue value = getConstant(index); + return toCString(value, "(", VirtualRegister(index), ")"); } static CString regexpToSourceString(RegExp* regExp) @@ -273,7 +273,9 @@ void CodeBlock::printGetByIdOp(PrintStream& out, ExecState* exec, int location, break; default: RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) op = 0; +#endif } int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -283,20 +285,19 @@ void CodeBlock::printGetByIdOp(PrintStream& out, ExecState* exec, int location, it += 4; // Increment up to the value profiler. } -static void dumpStructure(PrintStream& out, const char* name, ExecState* exec, Structure* structure, const Identifier& ident) +static void dumpStructure(PrintStream& out, const char* name, Structure* structure, const Identifier& ident) { if (!structure) return; out.printf("%s = %p", name, structure); - PropertyOffset offset = structure->getConcurrently(exec->vm(), ident.impl()); + PropertyOffset offset = structure->getConcurrently(ident.impl()); if (offset != invalidOffset) out.printf(" (offset = %d)", offset); } -#if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings -static void dumpChain(PrintStream& out, ExecState* exec, StructureChain* chain, const Identifier& ident) +static void dumpChain(PrintStream& out, StructureChain* chain, const Identifier& ident) { out.printf("chain = %p: [", chain); bool first = true; @@ -307,11 +308,10 @@ static void dumpChain(PrintStream& out, ExecState* exec, StructureChain* chain, first = false; else out.printf(", "); - dumpStructure(out, "struct", exec, currentStructure->get(), ident); + dumpStructure(out, "struct", currentStructure->get(), ident); } out.printf("]"); } -#endif void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int location, const StubInfoMap& map) { @@ -325,7 +325,7 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l out.printf(" llint(array_length)"); else if (Structure* structure = instruction[4].u.structure.get()) { out.printf(" llint("); - dumpStructure(out, "struct", exec, structure, ident); + dumpStructure(out, "struct", structure, ident); out.printf(")"); } @@ -348,11 +348,6 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l out.printf("self"); baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); break; - case access_get_by_id_chain: - out.printf("chain"); - baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get(); - chain = stubInfo.u.getByIdChain.chain.get(); - break; case access_get_by_id_list: out.printf("list"); list = stubInfo.u.getByIdList.list; @@ -367,17 +362,17 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l if (baseStructure) { out.printf(", "); - dumpStructure(out, "struct", exec, baseStructure, ident); + dumpStructure(out, "struct", baseStructure, ident); } if (prototypeStructure) { out.printf(", "); - dumpStructure(out, "prototypeStruct", exec, baseStructure, ident); + dumpStructure(out, "prototypeStruct", baseStructure, ident); } if (chain) { out.printf(", "); - dumpChain(out, exec, chain, ident); + dumpChain(out, chain, ident); } if (list) { @@ -386,10 +381,10 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l if (i) out.printf(", "); out.printf("("); - dumpStructure(out, "base", exec, list->at(i).structure(), ident); + dumpStructure(out, "base", list->at(i).structure(), ident); if (list->at(i).chain()) { out.printf(", "); - dumpChain(out, exec, list->at(i).chain(), ident); + dumpChain(out, list->at(i).chain(), ident); } out.printf(")"); } @@ -403,6 +398,118 @@ void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int l #endif } +void CodeBlock::printPutByIdCacheStatus(PrintStream& out, ExecState* exec, int location, const StubInfoMap& map) +{ + Instruction* instruction = instructions().begin() + location; + + const Identifier& ident = identifier(instruction[2].u.operand); + + UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations. + + if (Structure* structure = instruction[4].u.structure.get()) { + switch (exec->interpreter()->getOpcodeID(instruction[0].u.opcode)) { + case op_put_by_id: + case op_put_by_id_out_of_line: + out.print(" llint("); + dumpStructure(out, "struct", structure, ident); + out.print(")"); + break; + + case op_put_by_id_transition_direct: + case op_put_by_id_transition_normal: + case op_put_by_id_transition_direct_out_of_line: + case op_put_by_id_transition_normal_out_of_line: + out.print(" llint("); + dumpStructure(out, "prev", structure, ident); + out.print(", "); + dumpStructure(out, "next", instruction[6].u.structure.get(), ident); + if (StructureChain* chain = instruction[7].u.structureChain.get()) { + out.print(", "); + dumpChain(out, chain, ident); + } + out.print(")"); + break; + + default: + out.print(" llint(unknown)"); + break; + } + } + +#if ENABLE(JIT) + if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) { + StructureStubInfo& stubInfo = *stubPtr; + if (stubInfo.resetByGC) + out.print(" (Reset By GC)"); + + if (stubInfo.seen) { + out.printf(" jit("); + + switch (stubInfo.accessType) { + case access_put_by_id_replace: + out.print("replace, "); + dumpStructure(out, "struct", stubInfo.u.putByIdReplace.baseObjectStructure.get(), ident); + break; + case access_put_by_id_transition_normal: + case access_put_by_id_transition_direct: + out.print("transition, "); + dumpStructure(out, "prev", stubInfo.u.putByIdTransition.previousStructure.get(), ident); + out.print(", "); + dumpStructure(out, "next", stubInfo.u.putByIdTransition.structure.get(), ident); + if (StructureChain* chain = stubInfo.u.putByIdTransition.chain.get()) { + out.print(", "); + dumpChain(out, chain, ident); + } + break; + case access_put_by_id_list: { + out.printf("list = ["); + PolymorphicPutByIdList* list = stubInfo.u.putByIdList.list; + CommaPrinter comma; + for (unsigned i = 0; i < list->size(); ++i) { + out.print(comma, "("); + const PutByIdAccess& access = list->at(i); + + if (access.isReplace()) { + out.print("replace, "); + dumpStructure(out, "struct", access.oldStructure(), ident); + } else if (access.isSetter()) { + out.print("setter, "); + dumpStructure(out, "struct", access.oldStructure(), ident); + } else if (access.isCustom()) { + out.print("custom, "); + dumpStructure(out, "struct", access.oldStructure(), ident); + } else if (access.isTransition()) { + out.print("transition, "); + dumpStructure(out, "prev", access.oldStructure(), ident); + out.print(", "); + dumpStructure(out, "next", access.newStructure(), ident); + if (access.chain()) { + out.print(", "); + dumpChain(out, access.chain(), ident); + } + } else + out.print("unknown"); + + out.print(")"); + } + out.print("]"); + break; + } + case access_unset: + out.printf("unset"); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + out.printf(")"); + } + } +#else + UNUSED_PARAM(map); +#endif +} + void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap& map) { int dst = (++it)->u.operand; @@ -421,11 +528,13 @@ void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, con } #if ENABLE(JIT) if (CallLinkInfo* info = map.get(CodeOrigin(location))) { - JSFunction* target = info->lastSeenCallee.get(); + JSFunction* target = info->lastSeenCallee(); if (target) out.printf(" jit(%p, exec %p)", target, target->executable()); } - out.print(" status(", CallLinkStatus::computeFor(this, location, map), ")"); + + if (jitType() != JITCode::FTLJIT) + out.print(" status(", CallLinkStatus::computeFor(this, location, map), ")"); #else UNUSED_PARAM(map); #endif @@ -446,6 +555,31 @@ void CodeBlock::printPutByIdOp(PrintStream& out, ExecState* exec, int location, it += 5; } +void CodeBlock::dumpSource() +{ + dumpSource(WTF::dataFile()); +} + +void CodeBlock::dumpSource(PrintStream& out) +{ + ScriptExecutable* executable = ownerExecutable(); + if (executable->isFunctionExecutable()) { + FunctionExecutable* functionExecutable = reinterpret_cast<FunctionExecutable*>(executable); + String source = functionExecutable->source().provider()->getRange( + functionExecutable->parametersStartOffset(), + functionExecutable->typeProfilingEndOffset() + 1); // Type profiling end offset is the character before the '}'. + + out.print("function ", inferredName(), source); + return; + } + out.print(executable->source().toString()); +} + +void CodeBlock::dumpBytecode() +{ + dumpBytecode(WTF::dataFile()); +} + void CodeBlock::dumpBytecode(PrintStream& out) { // We only use the ExecState* for things that don't actually lead to JS execution, @@ -463,19 +597,8 @@ void CodeBlock::dumpBytecode(PrintStream& out) static_cast<unsigned long>(instructions().size()), static_cast<unsigned long>(instructions().size() * sizeof(Instruction)), m_numParameters, m_numCalleeRegisters, m_numVars); - if (symbolTable() && symbolTable()->captureCount()) { - out.printf( - "; %d captured var(s) (from r%d to r%d, inclusive)", - symbolTable()->captureCount(), symbolTable()->captureStart(), symbolTable()->captureEnd() + 1); - } - if (usesArguments()) { - out.printf( - "; uses arguments, in r%d, r%d", - argumentsRegister().offset(), - unmodifiedArgumentsRegister(argumentsRegister()).offset()); - } if (needsActivation() && codeType() == FunctionCode) - out.printf("; activation in r%d", activationRegister().offset()); + out.printf("; lexical environment in r%d", activationRegister().offset()); out.printf("\n"); StubInfoMap stubInfos; @@ -501,7 +624,19 @@ void CodeBlock::dumpBytecode(PrintStream& out) out.printf("\nConstants:\n"); size_t i = 0; do { - out.printf(" k%u = %s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data()); + const char* sourceCodeRepresentationDescription = nullptr; + switch (m_constantsSourceCodeRepresentation[i]) { + case SourceCodeRepresentation::Double: + sourceCodeRepresentationDescription = ": in source as double"; + break; + case SourceCodeRepresentation::Integer: + sourceCodeRepresentationDescription = ": in source as integer"; + break; + case SourceCodeRepresentation::Other: + sourceCodeRepresentationDescription = ""; + break; + } + out.printf(" k%u = %s%s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data(), sourceCodeRepresentationDescription); ++i; } while (i < m_constantRegisters.size()); } @@ -519,7 +654,9 @@ void CodeBlock::dumpBytecode(PrintStream& out) out.printf("\nException Handlers:\n"); unsigned i = 0; do { - out.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target, m_rareData->m_exceptionHandlers[i].scopeDepth); + HandlerInfo& handler = m_rareData->m_exceptionHandlers[i]; + out.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] } %s\n", + i + 1, handler.start, handler.end, handler.target, handler.scopeDepth, handler.typeName()); ++i; } while (i < m_rareData->m_exceptionHandlers.size()); } @@ -626,37 +763,44 @@ void CodeBlock::dumpBytecode( printLocationAndOp(out, exec, location, it, "enter"); break; } - case op_touch_entry: { - printLocationAndOp(out, exec, location, it, "touch_entry"); + case op_create_lexical_environment: { + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "create_lexical_environment"); + out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); break; } - case op_create_activation: { + case op_get_scope: { int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "create_activation", r0); + printLocationOpAndRegisterOperand(out, exec, location, it, "get_scope", r0); break; } - case op_create_arguments: { + case op_create_direct_arguments: { int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "create_arguments", r0); + printLocationAndOp(out, exec, location, it, "create_direct_arguments"); + out.printf("%s", registerName(r0).data()); break; } - case op_init_lazy_reg: { + case op_create_scoped_arguments: { int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "init_lazy_reg", r0); + int r1 = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "create_scoped_arguments"); + out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); break; } - case op_get_callee: { + case op_create_out_of_band_arguments: { int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "get_callee", r0); - ++it; + printLocationAndOp(out, exec, location, it, "create_out_of_band_arguments"); + out.printf("%s", registerName(r0).data()); break; } case op_create_this: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; unsigned inferredInlineCapacity = (++it)->u.operand; + unsigned cachedFunction = (++it)->u.operand; printLocationAndOp(out, exec, location, it, "create_this"); - out.printf("%s, %s, %u", registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity); + out.printf("%s, %s, %u, %u", registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity, cachedFunction); break; } case op_to_this: { @@ -664,7 +808,13 @@ void CodeBlock::dumpBytecode( printLocationOpAndRegisterOperand(out, exec, location, it, "to_this", r0); Structure* structure = (++it)->u.structure.get(); if (structure) - out.print(" cache(struct = ", RawPointer(structure), ")"); + out.print(", cache(struct = ", RawPointer(structure), ")"); + out.print(", ", (++it)->u.toThisStatus); + break; + } + case op_check_tdz: { + int r0 = (++it)->u.operand; + printLocationOpAndRegisterOperand(out, exec, location, it, "op_check_tdz", r0); break; } case op_new_object: { @@ -719,12 +869,20 @@ void CodeBlock::dumpBytecode( out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); break; } - case op_captured_mov: { + case op_profile_type: { int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - printLocationAndOp(out, exec, location, it, "captured_mov"); - out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); ++it; + ++it; + ++it; + ++it; + printLocationAndOp(out, exec, location, it, "op_profile_type"); + out.printf("%s", registerName(r0).data()); + break; + } + case op_profile_control_flow: { + BasicBlockLocation* basicBlockLocation = (++it)->u.basicBlockLocation; + printLocationAndOp(out, exec, location, it, "profile_control_flow"); + out.printf("[%d, %d]", basicBlockLocation->startOffset(), basicBlockLocation->endOffset()); break; } case op_not: { @@ -785,6 +943,10 @@ void CodeBlock::dumpBytecode( printUnaryOp(out, exec, location, it, "to_number"); break; } + case op_to_string: { + printUnaryOp(out, exec, location, it, "to_string"); + break; + } case op_negate: { printUnaryOp(out, exec, location, it, "negate"); break; @@ -885,6 +1047,10 @@ void CodeBlock::dumpBytecode( printUnaryOp(out, exec, location, it, "is_object"); break; } + case op_is_object_or_null: { + printUnaryOp(out, exec, location, it, "is_object_or_null"); + break; + } case op_is_function: { printUnaryOp(out, exec, location, it, "is_function"); break; @@ -902,10 +1068,10 @@ void CodeBlock::dumpBytecode( break; } case op_init_global_const: { - WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; + WriteBarrier<Unknown>* variablePointer = (++it)->u.variablePointer; int r0 = (++it)->u.operand; printLocationAndOp(out, exec, location, it, "init_global_const"); - out.printf("g%d(%p), %s", m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(r0).data()); + out.printf("g%d(%p), %s", m_globalObject->findVariableIndex(variablePointer).offset(), variablePointer, registerName(r0).data()); it++; it++; break; @@ -918,33 +1084,50 @@ void CodeBlock::dumpBytecode( dumpValueProfiling(out, it, hasPrintedProfiling); break; } - case op_get_arguments_length: { - printUnaryOp(out, exec, location, it, "get_arguments_length"); - it++; - break; - } case op_put_by_id: { printPutByIdOp(out, exec, location, it, "put_by_id"); + printPutByIdCacheStatus(out, exec, location, stubInfos); break; } case op_put_by_id_out_of_line: { printPutByIdOp(out, exec, location, it, "put_by_id_out_of_line"); + printPutByIdCacheStatus(out, exec, location, stubInfos); break; } case op_put_by_id_transition_direct: { printPutByIdOp(out, exec, location, it, "put_by_id_transition_direct"); + printPutByIdCacheStatus(out, exec, location, stubInfos); break; } case op_put_by_id_transition_direct_out_of_line: { printPutByIdOp(out, exec, location, it, "put_by_id_transition_direct_out_of_line"); + printPutByIdCacheStatus(out, exec, location, stubInfos); break; } case op_put_by_id_transition_normal: { printPutByIdOp(out, exec, location, it, "put_by_id_transition_normal"); + printPutByIdCacheStatus(out, exec, location, stubInfos); break; } case op_put_by_id_transition_normal_out_of_line: { printPutByIdOp(out, exec, location, it, "put_by_id_transition_normal_out_of_line"); + printPutByIdCacheStatus(out, exec, location, stubInfos); + break; + } + case op_put_getter_by_id: { + int r0 = (++it)->u.operand; + int id0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "put_getter_by_id"); + out.printf("%s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data()); + break; + } + case op_put_setter_by_id: { + int r0 = (++it)->u.operand; + int id0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "put_setter_by_id"); + out.printf("%s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data()); break; } case op_put_getter_setter: { @@ -974,27 +1157,6 @@ void CodeBlock::dumpBytecode( dumpValueProfiling(out, it, hasPrintedProfiling); break; } - case op_get_argument_by_val: { - int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - int r2 = (++it)->u.operand; - printLocationAndOp(out, exec, location, it, "get_argument_by_val"); - out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data()); - ++it; - dumpValueProfiling(out, it, hasPrintedProfiling); - break; - } - case op_get_by_pname: { - int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - int r2 = (++it)->u.operand; - int r3 = (++it)->u.operand; - int r4 = (++it)->u.operand; - int r5 = (++it)->u.operand; - printLocationAndOp(out, exec, location, it, "get_by_pname"); - out.printf("%s, %s, %s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), registerName(r4).data(), registerName(r5).data()); - break; - } case op_put_by_val: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -1153,25 +1315,18 @@ void CodeBlock::dumpBytecode( } case op_new_func: { int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; int f0 = (++it)->u.operand; - int shouldCheck = (++it)->u.operand; printLocationAndOp(out, exec, location, it, "new_func"); - out.printf("%s, f%d, %s", registerName(r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>"); - break; - } - case op_new_captured_func: { - int r0 = (++it)->u.operand; - int f0 = (++it)->u.operand; - printLocationAndOp(out, exec, location, it, "new_captured_func"); - out.printf("%s, f%d", registerName(r0).data(), f0); - ++it; + out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0); break; } case op_new_func_exp: { int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; int f0 = (++it)->u.operand; printLocationAndOp(out, exec, location, it, "new_func_exp"); - out.printf("%s, f%d", registerName(r0).data(), f0); + out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0); break; } case op_call: { @@ -1197,31 +1352,12 @@ void CodeBlock::dumpBytecode( dumpValueProfiling(out, it, hasPrintedProfiling); break; } - - case op_tear_off_activation: { - int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "tear_off_activation", r0); - break; - } - case op_tear_off_arguments: { - int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - printLocationAndOp(out, exec, location, it, "tear_off_arguments"); - out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); - break; - } + case op_ret: { int r0 = (++it)->u.operand; printLocationOpAndRegisterOperand(out, exec, location, it, "ret", r0); break; } - case op_ret_object_or_this: { - int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - printLocationAndOp(out, exec, location, it, "constructor_ret"); - out.printf("%s %s", registerName(r0).data(), registerName(r1).data()); - break; - } case op_construct: { printCallOp(out, exec, location, it, "construct", DumpCaches, hasPrintedProfiling, callLinkInfos); break; @@ -1241,49 +1377,116 @@ void CodeBlock::dumpBytecode( out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); break; } - case op_get_pnames: { - int r0 = it[1].u.operand; - int r1 = it[2].u.operand; - int r2 = it[3].u.operand; - int r3 = it[4].u.operand; - int offset = it[5].u.operand; - printLocationAndOp(out, exec, location, it, "get_pnames"); - out.printf("%s, %s, %s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), offset, location + offset); - it += OPCODE_LENGTH(op_get_pnames) - 1; + case op_get_enumerable_length: { + int dst = it[1].u.operand; + int base = it[2].u.operand; + printLocationAndOp(out, exec, location, it, "op_get_enumerable_length"); + out.printf("%s, %s", registerName(dst).data(), registerName(base).data()); + it += OPCODE_LENGTH(op_get_enumerable_length) - 1; + break; + } + case op_has_indexed_property: { + int dst = it[1].u.operand; + int base = it[2].u.operand; + int propertyName = it[3].u.operand; + ArrayProfile* arrayProfile = it[4].u.arrayProfile; + printLocationAndOp(out, exec, location, it, "op_has_indexed_property"); + out.printf("%s, %s, %s, %p", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), arrayProfile); + it += OPCODE_LENGTH(op_has_indexed_property) - 1; + break; + } + case op_has_structure_property: { + int dst = it[1].u.operand; + int base = it[2].u.operand; + int propertyName = it[3].u.operand; + int enumerator = it[4].u.operand; + printLocationAndOp(out, exec, location, it, "op_has_structure_property"); + out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(enumerator).data()); + it += OPCODE_LENGTH(op_has_structure_property) - 1; + break; + } + case op_has_generic_property: { + int dst = it[1].u.operand; + int base = it[2].u.operand; + int propertyName = it[3].u.operand; + printLocationAndOp(out, exec, location, it, "op_has_generic_property"); + out.printf("%s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data()); + it += OPCODE_LENGTH(op_has_generic_property) - 1; break; } - case op_next_pname: { - int dest = it[1].u.operand; + case op_get_direct_pname: { + int dst = it[1].u.operand; int base = it[2].u.operand; - int i = it[3].u.operand; - int size = it[4].u.operand; - int iter = it[5].u.operand; - int offset = it[6].u.operand; - printLocationAndOp(out, exec, location, it, "next_pname"); - out.printf("%s, %s, %s, %s, %s, %d(->%d)", registerName(dest).data(), registerName(base).data(), registerName(i).data(), registerName(size).data(), registerName(iter).data(), offset, location + offset); - it += OPCODE_LENGTH(op_next_pname) - 1; + int propertyName = it[3].u.operand; + int index = it[4].u.operand; + int enumerator = it[5].u.operand; + ValueProfile* profile = it[6].u.profile; + printLocationAndOp(out, exec, location, it, "op_get_direct_pname"); + out.printf("%s, %s, %s, %s, %s, %p", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(index).data(), registerName(enumerator).data(), profile); + it += OPCODE_LENGTH(op_get_direct_pname) - 1; + break; + + } + case op_get_property_enumerator: { + int dst = it[1].u.operand; + int base = it[2].u.operand; + printLocationAndOp(out, exec, location, it, "op_get_property_enumerator"); + out.printf("%s, %s", registerName(dst).data(), registerName(base).data()); + it += OPCODE_LENGTH(op_get_property_enumerator) - 1; + break; + } + case op_enumerator_structure_pname: { + int dst = it[1].u.operand; + int enumerator = it[2].u.operand; + int index = it[3].u.operand; + printLocationAndOp(out, exec, location, it, "op_enumerator_structure_pname"); + out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data()); + it += OPCODE_LENGTH(op_enumerator_structure_pname) - 1; + break; + } + case op_enumerator_generic_pname: { + int dst = it[1].u.operand; + int enumerator = it[2].u.operand; + int index = it[3].u.operand; + printLocationAndOp(out, exec, location, it, "op_enumerator_generic_pname"); + out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data()); + it += OPCODE_LENGTH(op_enumerator_generic_pname) - 1; + break; + } + case op_to_index_string: { + int dst = it[1].u.operand; + int index = it[2].u.operand; + printLocationAndOp(out, exec, location, it, "op_to_index_string"); + out.printf("%s, %s", registerName(dst).data(), registerName(index).data()); + it += OPCODE_LENGTH(op_to_index_string) - 1; break; } case op_push_with_scope: { - int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "push_with_scope", r0); + int dst = (++it)->u.operand; + int newScope = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "push_with_scope"); + out.printf("%s, %s", registerName(dst).data(), registerName(newScope).data()); break; } case op_pop_scope: { - printLocationAndOp(out, exec, location, it, "pop_scope"); + int r0 = (++it)->u.operand; + printLocationOpAndRegisterOperand(out, exec, location, it, "pop_scope", r0); break; } case op_push_name_scope: { - int id0 = (++it)->u.operand; + int dst = (++it)->u.operand; int r1 = (++it)->u.operand; - unsigned attributes = (++it)->u.operand; + int k0 = (++it)->u.operand; + JSNameScope::Type scopeType = (JSNameScope::Type)(++it)->u.operand; printLocationAndOp(out, exec, location, it, "push_name_scope"); - out.printf("%s, %s, %u", idName(id0, identifier(id0)).data(), registerName(r1).data(), attributes); + out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(r1).data(), constantName(k0).data(), (scopeType == JSNameScope::FunctionNameScope) ? "functionScope" : ((scopeType == JSNameScope::CatchScope) ? "catchScope" : "unknownScopeType")); break; } case op_catch: { int r0 = (++it)->u.operand; - printLocationOpAndRegisterOperand(out, exec, location, it, "catch", r0); + int r1 = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "catch"); + out.printf("%s, %s", registerName(r0).data(), registerName(r1).data()); break; } case op_throw: { @@ -1295,7 +1498,7 @@ void CodeBlock::dumpBytecode( int k0 = (++it)->u.operand; int k1 = (++it)->u.operand; printLocationAndOp(out, exec, location, it, "throw_static_error"); - out.printf("%s, %s", constantName(k0, getConstant(k0)).data(), k1 ? "true" : "false"); + out.printf("%s, %s", constantName(k0).data(), k1 ? "true" : "false"); break; } case op_debug: { @@ -1322,11 +1525,12 @@ void CodeBlock::dumpBytecode( } case op_resolve_scope: { int r0 = (++it)->u.operand; + int scope = (++it)->u.operand; int id0 = (++it)->u.operand; ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand); int depth = (++it)->u.operand; printLocationAndOp(out, exec, location, it, "resolve_scope"); - out.printf("%s, %s, %u<%s|%s>, %d", registerName(r0).data(), idName(id0, identifier(id0)).data(), + out.printf("%s, %s, %s, %u<%s|%s>, %d", registerName(r0).data(), registerName(scope).data(), idName(id0, identifier(id0)).data(), modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()), depth); ++it; @@ -1339,12 +1543,14 @@ void CodeBlock::dumpBytecode( ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand); ++it; // Structure int operand = (++it)->u.operand; // Operand - ++it; // Skip value profile. printLocationAndOp(out, exec, location, it, "get_from_scope"); - out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d", - registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(), - modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()), - operand); + out.print(registerName(r0), ", ", registerName(r1)); + if (static_cast<unsigned>(id0) == UINT_MAX) + out.print(", anonymous"); + else + out.print(", ", idName(id0, identifier(id0))); + out.print(", ", modeAndType.operand(), "<", resolveModeName(modeAndType.mode()), "|", resolveTypeName(modeAndType.type()), ">, ", operand); + dumpValueProfiling(out, it, hasPrintedProfiling); break; } case op_put_to_scope: { @@ -1355,10 +1561,29 @@ void CodeBlock::dumpBytecode( ++it; // Structure int operand = (++it)->u.operand; // Operand printLocationAndOp(out, exec, location, it, "put_to_scope"); - out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d", - registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(), - modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()), - operand); + out.print(registerName(r0)); + if (static_cast<unsigned>(id0) == UINT_MAX) + out.print(", anonymous"); + else + out.print(", ", idName(id0, identifier(id0))); + out.print(", ", registerName(r1), ", ", modeAndType.operand(), "<", resolveModeName(modeAndType.mode()), "|", resolveTypeName(modeAndType.type()), ">, <structure>, ", operand); + break; + } + case op_get_from_arguments: { + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + int offset = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "get_from_arguments"); + out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), offset); + dumpValueProfiling(out, it, hasPrintedProfiling); + break; + } + case op_put_to_arguments: { + int r0 = (++it)->u.operand; + int offset = (++it)->u.operand; + int r1 = (++it)->u.operand; + printLocationAndOp(out, exec, location, it, "put_to_arguments"); + out.printf("%s, %d, %s", registerName(r0).data(), offset, registerName(r1).data()); break; } default: @@ -1416,6 +1641,28 @@ static size_t sizeInBytes(const Vector<T>& vector) return vector.capacity() * sizeof(T); } +namespace { + +class PutToScopeFireDetail : public FireDetail { +public: + PutToScopeFireDetail(CodeBlock* codeBlock, const Identifier& ident) + : m_codeBlock(codeBlock) + , m_ident(ident) + { + } + + virtual void dump(PrintStream& out) const override + { + out.print("Linking put_to_scope in ", FunctionExecutableDump(jsCast<FunctionExecutable*>(m_codeBlock->ownerExecutable())), " for ", m_ident); + } + +private: + CodeBlock* m_codeBlock; + const Identifier& m_ident; +}; + +} // anonymous namespace + CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) : m_globalObject(other.m_globalObject) , m_heap(other.m_heap) @@ -1433,17 +1680,17 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) , m_vm(other.m_vm) , m_instructions(other.m_instructions) , m_thisRegister(other.m_thisRegister) - , m_argumentsRegister(other.m_argumentsRegister) - , m_activationRegister(other.m_activationRegister) + , m_scopeRegister(other.m_scopeRegister) + , m_lexicalEnvironmentRegister(other.m_lexicalEnvironmentRegister) , m_isStrictMode(other.m_isStrictMode) , m_needsActivation(other.m_needsActivation) , m_mayBeExecuting(false) - , m_visitAggregateHasBeenCalled(false) , m_source(other.m_source) , m_sourceOffset(other.m_sourceOffset) , m_firstLineColumnOffset(other.m_firstLineColumnOffset) , m_codeType(other.m_codeType) , m_constantRegisters(other.m_constantRegisters) + , m_constantsSourceCodeRepresentation(other.m_constantsSourceCodeRepresentation) , m_functionDecls(other.m_functionDecls) , m_functionExprs(other.m_functionExprs) , m_osrExitCounter(0) @@ -1454,8 +1701,11 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) , m_capabilityLevelState(DFG::CapabilityLevelNotSet) #endif { + m_visitAggregateHasBeenCalled.store(false, std::memory_order_relaxed); + ASSERT(m_heap->isDeferred()); - + ASSERT(m_scopeRegister.isLocal()); + if (SymbolTable* symbolTable = other.symbolTable()) m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable); @@ -1473,7 +1723,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) } m_heap->m_codeBlocks.add(this); - m_heap->reportExtraMemoryCost(sizeof(CodeBlock)); + m_heap->reportExtraMemoryAllocated(sizeof(CodeBlock)); } CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) @@ -1492,12 +1742,11 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin , m_ownerExecutable(m_globalObject->vm(), ownerExecutable, ownerExecutable) , m_vm(unlinkedCodeBlock->vm()) , m_thisRegister(unlinkedCodeBlock->thisRegister()) - , m_argumentsRegister(unlinkedCodeBlock->argumentsRegister()) - , m_activationRegister(unlinkedCodeBlock->activationRegister()) + , m_scopeRegister(unlinkedCodeBlock->scopeRegister()) + , m_lexicalEnvironmentRegister(unlinkedCodeBlock->activationRegister()) , m_isStrictMode(unlinkedCodeBlock->isStrictMode()) , m_needsActivation(unlinkedCodeBlock->hasActivationRegister() && unlinkedCodeBlock->codeType() == FunctionCode) , m_mayBeExecuting(false) - , m_visitAggregateHasBeenCalled(false) , m_source(sourceProvider) , m_sourceOffset(sourceOffset) , m_firstLineColumnOffset(firstLineColumnOffset) @@ -1509,13 +1758,21 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin , m_capabilityLevelState(DFG::CapabilityLevelNotSet) #endif { + m_visitAggregateHasBeenCalled.store(false, std::memory_order_relaxed); + ASSERT(m_heap->isDeferred()); + ASSERT(m_scopeRegister.isLocal()); bool didCloneSymbolTable = false; if (SymbolTable* symbolTable = unlinkedCodeBlock->symbolTable()) { - if (codeType() == FunctionCode && symbolTable->captureCount()) { - m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable->cloneCapturedNames(*m_vm)); + if (m_vm->typeProfiler()) { + ConcurrentJITLocker locker(symbolTable->m_lock); + symbolTable->prepareForTypeProfiling(locker); + } + + if (codeType() == FunctionCode && symbolTable->scopeSize()) { + m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable->cloneScopePart(*m_vm)); didCloneSymbolTable = true; } else m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable); @@ -1524,39 +1781,33 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin ASSERT(m_source); setNumParameters(unlinkedCodeBlock->numParameters()); - setConstantRegisters(unlinkedCodeBlock->constantRegisters()); + if (vm()->typeProfiler() || vm()->controlFlowProfiler()) + vm()->functionHasExecutedCache()->removeUnexecutedRange(m_ownerExecutable->sourceID(), m_ownerExecutable->typeProfilingStartOffset(), m_ownerExecutable->typeProfilingEndOffset()); + + setConstantRegisters(unlinkedCodeBlock->constantRegisters(), unlinkedCodeBlock->constantsSourceCodeRepresentation()); if (unlinkedCodeBlock->usesGlobalObject()) m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get()); + + for (unsigned i = 0; i < LinkTimeConstantCount; i++) { + LinkTimeConstant type = static_cast<LinkTimeConstant>(i); + if (unsigned registerIndex = unlinkedCodeBlock->registerIndexForLinkTimeConstant(type)) + m_constantRegisters[registerIndex].set(*m_vm, ownerExecutable, m_globalObject->jsCellForLinkTimeConstant(type)); + } + m_functionDecls.resizeToFit(unlinkedCodeBlock->numberOfFunctionDecls()); for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) { UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i); - unsigned lineCount = unlinkedExecutable->lineCount(); - unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset(); - bool startColumnIsOnOwnerStartLine = !unlinkedExecutable->firstLineOffset(); - unsigned startColumn = unlinkedExecutable->unlinkedBodyStartColumn() + (startColumnIsOnOwnerStartLine ? ownerExecutable->startColumn() : 1); - bool endColumnIsOnStartLine = !lineCount; - unsigned endColumn = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? startColumn : 1); - unsigned startOffset = sourceOffset + unlinkedExecutable->startOffset(); - unsigned sourceLength = unlinkedExecutable->sourceLength(); - SourceCode code(m_source, startOffset, startOffset + sourceLength, firstLine, startColumn); - FunctionExecutable* executable = FunctionExecutable::create(*m_vm, code, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumn); - m_functionDecls[i].set(*m_vm, ownerExecutable, executable); + if (vm()->typeProfiler() || vm()->controlFlowProfiler()) + vm()->functionHasExecutedCache()->insertUnexecutedRange(m_ownerExecutable->sourceID(), unlinkedExecutable->typeProfilingStartOffset(), unlinkedExecutable->typeProfilingEndOffset()); + m_functionDecls[i].set(*m_vm, ownerExecutable, unlinkedExecutable->link(*m_vm, ownerExecutable->source())); } m_functionExprs.resizeToFit(unlinkedCodeBlock->numberOfFunctionExprs()); for (size_t count = unlinkedCodeBlock->numberOfFunctionExprs(), i = 0; i < count; ++i) { UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionExpr(i); - unsigned lineCount = unlinkedExecutable->lineCount(); - unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset(); - bool startColumnIsOnOwnerStartLine = !unlinkedExecutable->firstLineOffset(); - unsigned startColumn = unlinkedExecutable->unlinkedBodyStartColumn() + (startColumnIsOnOwnerStartLine ? ownerExecutable->startColumn() : 1); - bool endColumnIsOnStartLine = !lineCount; - unsigned endColumn = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? startColumn : 1); - unsigned startOffset = sourceOffset + unlinkedExecutable->startOffset(); - unsigned sourceLength = unlinkedExecutable->sourceLength(); - SourceCode code(m_source, startOffset, startOffset + sourceLength, firstLine, startColumn); - FunctionExecutable* executable = FunctionExecutable::create(*m_vm, code, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumn); - m_functionExprs[i].set(*m_vm, ownerExecutable, executable); + if (vm()->typeProfiler() || vm()->controlFlowProfiler()) + vm()->functionHasExecutedCache()->insertUnexecutedRange(m_ownerExecutable->sourceID(), unlinkedExecutable->typeProfilingStartOffset(), unlinkedExecutable->typeProfilingEndOffset()); + m_functionExprs[i].set(*m_vm, ownerExecutable, unlinkedExecutable->link(*m_vm, ownerExecutable->source())); } if (unlinkedCodeBlock->hasRareData()) { @@ -1572,13 +1823,13 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin m_rareData->m_exceptionHandlers.resizeToFit(count); size_t nonLocalScopeDepth = scope->depth(); for (size_t i = 0; i < count; i++) { - const UnlinkedHandlerInfo& handler = unlinkedCodeBlock->exceptionHandler(i); - m_rareData->m_exceptionHandlers[i].start = handler.start; - m_rareData->m_exceptionHandlers[i].end = handler.end; - m_rareData->m_exceptionHandlers[i].target = handler.target; - m_rareData->m_exceptionHandlers[i].scopeDepth = nonLocalScopeDepth + handler.scopeDepth; + const UnlinkedHandlerInfo& unlinkedHandler = unlinkedCodeBlock->exceptionHandler(i); + HandlerInfo& handler = m_rareData->m_exceptionHandlers[i]; #if ENABLE(JIT) - m_rareData->m_exceptionHandlers[i].nativeCode = CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(op_catch))); + handler.initialize(unlinkedHandler, nonLocalScopeDepth, + CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(op_catch)))); +#else + handler.initialize(unlinkedHandler, nonLocalScopeDepth); #endif } } @@ -1636,17 +1887,25 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin instructions[i + j].u.operand = pc[j].u.operand; } switch (pc[0].u.opcode) { + case op_has_indexed_property: { + int arrayProfileIndex = pc[opLength - 1].u.operand; + m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); + + instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex]; + break; + } case op_call_varargs: case op_construct_varargs: - case op_get_by_val: - case op_get_argument_by_val: { + case op_get_by_val: { int arrayProfileIndex = pc[opLength - 2].u.operand; m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex]; FALLTHROUGH; } - case op_get_by_id: { + case op_get_direct_pname: + case op_get_by_id: + case op_get_from_arguments: { ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand]; ASSERT(profile->m_bytecodeOffset == -1); profile->m_bytecodeOffset = i; @@ -1716,19 +1975,20 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin break; instructions[i + 0] = vm()->interpreter->getOpcode(op_init_global_const); - instructions[i + 1] = &m_globalObject->registerAt(entry.getIndex()); + instructions[i + 1] = &m_globalObject->variableAt(entry.varOffset().scopeOffset()); break; } case op_resolve_scope: { - const Identifier& ident = identifier(pc[2].u.operand); - ResolveType type = static_cast<ResolveType>(pc[3].u.operand); + const Identifier& ident = identifier(pc[3].u.operand); + ResolveType type = static_cast<ResolveType>(pc[4].u.operand); + RELEASE_ASSERT(type != LocalClosureVar); - ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Get, type); - instructions[i + 3].u.operand = op.type; - instructions[i + 4].u.operand = op.depth; - if (op.activation) - instructions[i + 5].u.activation.set(*vm(), ownerExecutable, op.activation); + ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Get, type); + instructions[i + 4].u.operand = op.type; + instructions[i + 5].u.operand = op.depth; + if (op.lexicalEnvironment) + instructions[i + 6].u.symbolTable.set(*vm(), ownerExecutable, op.lexicalEnvironment->symbolTable()); break; } @@ -1739,9 +1999,16 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin instructions[i + opLength - 1] = profile; // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand - const Identifier& ident = identifier(pc[3].u.operand); + ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand); - ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Get, modeAndType.type()); + if (modeAndType.type() == LocalClosureVar) { + instructions[i + 4] = ResolveModeAndType(modeAndType.mode(), ClosureVar).operand(); + break; + } + + const Identifier& ident = identifier(pc[3].u.operand); + + ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Get, modeAndType.type()); instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand(); if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks) @@ -1754,35 +2021,130 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin case op_put_to_scope: { // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand - const Identifier& ident = identifier(pc[2].u.operand); ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand); - ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Put, modeAndType.type()); + if (modeAndType.type() == LocalClosureVar) { + // Only do watching if the property we're putting to is not anonymous. + if (static_cast<unsigned>(pc[2].u.operand) != UINT_MAX) { + RELEASE_ASSERT(didCloneSymbolTable); + const Identifier& ident = identifier(pc[2].u.operand); + ConcurrentJITLocker locker(m_symbolTable->m_lock); + SymbolTable::Map::iterator iter = m_symbolTable->find(locker, ident.impl()); + ASSERT(iter != m_symbolTable->end(locker)); + iter->value.prepareToWatch(); + instructions[i + 5].u.watchpointSet = iter->value.watchpointSet(); + } else + instructions[i + 5].u.watchpointSet = nullptr; + break; + } + + const Identifier& ident = identifier(pc[2].u.operand); + + ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Put, modeAndType.type()); instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand(); if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks) instructions[i + 5].u.watchpointSet = op.watchpointSet; else if (op.type == ClosureVar || op.type == ClosureVarWithVarInjectionChecks) { if (op.watchpointSet) - op.watchpointSet->invalidate(); + op.watchpointSet->invalidate(PutToScopeFireDetail(this, ident)); } else if (op.structure) instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure); instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand); + break; } - - case op_captured_mov: - case op_new_captured_func: { - if (pc[3].u.index == UINT_MAX) { - instructions[i + 3].u.watchpointSet = 0; + + case op_profile_type: { + RELEASE_ASSERT(vm()->typeProfiler()); + // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType? + size_t instructionOffset = i + opLength - 1; + unsigned divotStart, divotEnd; + GlobalVariableID globalVariableID = 0; + RefPtr<TypeSet> globalTypeSet; + bool shouldAnalyze = m_unlinkedCode->typeProfilerExpressionInfoForBytecodeOffset(instructionOffset, divotStart, divotEnd); + VirtualRegister profileRegister(pc[1].u.operand); + ProfileTypeBytecodeFlag flag = static_cast<ProfileTypeBytecodeFlag>(pc[3].u.operand); + SymbolTable* symbolTable = nullptr; + + switch (flag) { + case ProfileTypeBytecodePutToScope: + case ProfileTypeBytecodeGetFromScope: { + const Identifier& ident = identifier(pc[4].u.operand); + ResolveType type = static_cast<ResolveType>(pc[5].u.operand); + ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, (flag == ProfileTypeBytecodeGetFromScope ? Get : Put), type); + + // FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID + // https://bugs.webkit.org/show_bug.cgi?id=135184 + if (op.type == ClosureVar) + symbolTable = op.lexicalEnvironment->symbolTable(); + else if (op.type == GlobalVar) + symbolTable = m_globalObject.get()->symbolTable(); + + if (symbolTable) { + ConcurrentJITLocker locker(symbolTable->m_lock); + // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet. + symbolTable->prepareForTypeProfiling(locker); + globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm()); + globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm()); + } else + globalVariableID = TypeProfilerNoGlobalIDExists; + + break; + } + case ProfileTypeBytecodePutToLocalScope: + case ProfileTypeBytecodeGetFromLocalScope: { + const Identifier& ident = identifier(pc[4].u.operand); + symbolTable = m_symbolTable.get(); + ConcurrentJITLocker locker(symbolTable->m_lock); + // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet. + symbolTable->prepareForTypeProfiling(locker); + globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm()); + globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm()); + + break; + } + + case ProfileTypeBytecodeHasGlobalID: { + symbolTable = m_symbolTable.get(); + ConcurrentJITLocker locker(symbolTable->m_lock); + globalVariableID = symbolTable->uniqueIDForOffset(locker, VarOffset(profileRegister), *vm()); + globalTypeSet = symbolTable->globalTypeSetForOffset(locker, VarOffset(profileRegister), *vm()); break; } - StringImpl* uid = identifier(pc[3].u.index).impl(); - RELEASE_ASSERT(didCloneSymbolTable); - ConcurrentJITLocker locker(m_symbolTable->m_lock); - SymbolTable::Map::iterator iter = m_symbolTable->find(locker, uid); - ASSERT(iter != m_symbolTable->end(locker)); - iter->value.prepareToWatch(symbolTable()); - instructions[i + 3].u.watchpointSet = iter->value.watchpointSet(); + case ProfileTypeBytecodeDoesNotHaveGlobalID: + case ProfileTypeBytecodeFunctionArgument: { + globalVariableID = TypeProfilerNoGlobalIDExists; + break; + } + case ProfileTypeBytecodeFunctionReturnStatement: { + RELEASE_ASSERT(ownerExecutable->isFunctionExecutable()); + globalTypeSet = jsCast<FunctionExecutable*>(ownerExecutable)->returnStatementTypeSet(); + globalVariableID = TypeProfilerReturnStatement; + if (!shouldAnalyze) { + // Because a return statement can be added implicitly to return undefined at the end of a function, + // and these nodes don't emit expression ranges because they aren't in the actual source text of + // the user's program, give the type profiler some range to identify these return statements. + // Currently, the text offset that is used as identification is on the open brace of the function + // and is stored on TypeLocation's m_divotForFunctionOffsetIfReturnStatement member variable. + divotStart = divotEnd = m_sourceOffset; + shouldAnalyze = true; + } + break; + } + } + + std::pair<TypeLocation*, bool> locationPair = vm()->typeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID, + m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm()); + TypeLocation* location = locationPair.first; + bool isNewLocation = locationPair.second; + + if (flag == ProfileTypeBytecodeFunctionReturnStatement) + location->m_divotForFunctionOffsetIfReturnStatement = m_sourceOffset; + + if (shouldAnalyze && isNewLocation) + vm()->typeProfiler()->insertNewLocation(location); + + instructions[i + 2].u.location = location; break; } @@ -1797,6 +2159,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin } i += opLength; } + + if (vm()->controlFlowProfiler()) + insertBasicBlockBoundariesForControlFlowProfiler(instructions); + m_instructions = WTF::RefCountedArray<Instruction>(instructions); // Set optimization thresholds only after m_instructions is initialized, since these @@ -1814,7 +2180,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin dumpBytecode(); m_heap->m_codeBlocks.add(this); - m_heap->reportExtraMemoryCost(sizeof(CodeBlock) + m_instructions.size() * sizeof(Instruction)); + m_heap->reportExtraMemoryAllocated(sizeof(CodeBlock) + m_instructions.size() * sizeof(Instruction)); } CodeBlock::~CodeBlock() @@ -1836,6 +2202,8 @@ CodeBlock::~CodeBlock() // destructor will try to remove nodes from our (no longer valid) linked list. while (m_incomingCalls.begin() != m_incomingCalls.end()) m_incomingCalls.begin()->remove(); + while (m_incomingPolymorphicCalls.begin() != m_incomingPolymorphicCalls.end()) + m_incomingPolymorphicCalls.begin()->remove(); // Note that our outgoing calls will be removed from other CodeBlocks' // m_incomingCalls linked lists through the execution of the ~CallLinkInfo @@ -1876,26 +2244,11 @@ void CodeBlock::visitAggregate(SlotVisitor& visitor) { #if ENABLE(PARALLEL_GC) // I may be asked to scan myself more than once, and it may even happen concurrently. - // To this end, use a CAS loop to check if I've been called already. Only one thread - // may proceed past this point - whichever one wins the CAS race. - unsigned oldValue; - do { - oldValue = m_visitAggregateHasBeenCalled; - if (oldValue) { - // Looks like someone else won! Return immediately to ensure that we don't - // trace the same CodeBlock concurrently. Doing so is hazardous since we will - // be mutating the state of ValueProfiles, which contain JSValues, which can - // have word-tearing on 32-bit, leading to awesome timing-dependent crashes - // that are nearly impossible to track down. - - // Also note that it must be safe to return early as soon as we see the - // value true (well, (unsigned)1), since once a GC thread is in this method - // and has won the CAS race (i.e. was responsible for setting the value true) - // it will definitely complete the rest of this method before declaring - // termination. - return; - } - } while (!WTF::weakCompareAndSwap(&m_visitAggregateHasBeenCalled, 0, 1)); + // To this end, use an atomic operation to check (and set) if I've been called already. + // Only one thread may proceed past this point - whichever one wins the atomic set race. + bool setByMe = m_visitAggregateHasBeenCalled.compareExchangeStrong(false, true); + if (!setByMe) + return; #endif // ENABLE(PARALLEL_GC) if (!!m_alternative) @@ -1904,15 +2257,15 @@ void CodeBlock::visitAggregate(SlotVisitor& visitor) if (CodeBlock* otherBlock = specialOSREntryBlockOrNull()) otherBlock->visitAggregate(visitor); - visitor.reportExtraMemoryUsage(ownerExecutable(), sizeof(CodeBlock)); + visitor.reportExtraMemoryVisited(ownerExecutable(), sizeof(CodeBlock)); if (m_jitCode) - visitor.reportExtraMemoryUsage(ownerExecutable(), m_jitCode->size()); + visitor.reportExtraMemoryVisited(ownerExecutable(), m_jitCode->size()); if (m_instructions.size()) { // Divide by refCount() because m_instructions points to something that is shared // by multiple CodeBlocks, and we only want to count it towards the heap size once. // Having each CodeBlock report only its proportional share of the size is one way // of accomplishing this. - visitor.reportExtraMemoryUsage(ownerExecutable(), m_instructions.size() * sizeof(Instruction) / m_instructions.refCount()); + visitor.reportExtraMemoryVisited(ownerExecutable(), m_instructions.size() * sizeof(Instruction) / m_instructions.refCount()); } visitor.append(&m_unlinkedCode); @@ -2000,6 +2353,19 @@ bool CodeBlock::isKnownToBeLiveDuringGC() #endif } +#if ENABLE(DFG_JIT) +static bool shouldMarkTransition(DFG::WeakReferenceTransition& transition) +{ + if (transition.m_codeOrigin && !Heap::isMarked(transition.m_codeOrigin.get())) + return false; + + if (!Heap::isMarked(transition.m_from.get())) + return false; + + return true; +} +#endif // ENABLE(DFG_JIT) + void CodeBlock::propagateTransitions(SlotVisitor& visitor) { UNUSED_PARAM(visitor); @@ -2076,21 +2442,28 @@ void CodeBlock::propagateTransitions(SlotVisitor& visitor) #if ENABLE(DFG_JIT) if (JITCode::isOptimizingJIT(jitType())) { DFG::CommonData* dfgCommon = m_jitCode->dfgCommon(); + for (unsigned i = 0; i < dfgCommon->transitions.size(); ++i) { - if ((!dfgCommon->transitions[i].m_codeOrigin - || Heap::isMarked(dfgCommon->transitions[i].m_codeOrigin.get())) - && Heap::isMarked(dfgCommon->transitions[i].m_from.get())) { + if (shouldMarkTransition(dfgCommon->transitions[i])) { // If the following three things are live, then the target of the // transition is also live: + // // - This code block. We know it's live already because otherwise // we wouldn't be scanning ourselves. + // // - The code origin of the transition. Transitions may arise from // code that was inlined. They are not relevant if the user's // object that is required for the inlinee to run is no longer // live. + // // - The source of the transition. The transition checks if some // heap location holds the source, and if so, stores the target. // Hence the source must be live for the transition to be live. + // + // We also short-circuit the liveness if the structure is harmless + // to mark (i.e. its global object and prototype are both already + // live). + visitor.append(&dfgCommon->transitions[i].m_to); } else allAreMarkedSoFar = false; @@ -2125,6 +2498,14 @@ void CodeBlock::determineLiveness(SlotVisitor& visitor) break; } } + if (allAreLiveSoFar) { + for (unsigned i = 0; i < dfgCommon->weakStructureReferences.size(); ++i) { + if (!Heap::isMarked(dfgCommon->weakStructureReferences[i].get())) { + allAreLiveSoFar = false; + break; + } + } + } // If some weak references are dead, then this fixpoint iteration was // unsuccessful. @@ -2190,28 +2571,38 @@ void CodeBlock::finalizeUnconditionally() if (Options::verboseOSR()) dataLogF("Clearing LLInt to_this with structure %p.\n", curInstruction[2].u.structure.get()); curInstruction[2].u.structure.clear(); + curInstruction[3].u.toThisStatus = merge( + curInstruction[3].u.toThisStatus, ToThisClearedByGC); break; - case op_get_callee: - if (!curInstruction[2].u.jsCell || Heap::isMarked(curInstruction[2].u.jsCell.get())) + case op_create_this: { + auto& cacheWriteBarrier = curInstruction[4].u.jsCell; + if (!cacheWriteBarrier || cacheWriteBarrier.unvalidatedGet() == JSCell::seenMultipleCalleeObjects()) + break; + JSCell* cachedFunction = cacheWriteBarrier.get(); + if (Heap::isMarked(cachedFunction)) break; if (Options::verboseOSR()) - dataLogF("Clearing LLInt get callee with function %p.\n", curInstruction[2].u.jsCell.get()); - curInstruction[2].u.jsCell.clear(); + dataLogF("Clearing LLInt create_this with cached callee %p.\n", cachedFunction); + cacheWriteBarrier.clear(); break; + } case op_resolve_scope: { - WriteBarrierBase<JSActivation>& activation = curInstruction[5].u.activation; - if (!activation || Heap::isMarked(activation.get())) + // Right now this isn't strictly necessary. Any symbol tables that this will refer to + // are for outer functions, and we refer to those functions strongly, and they refer + // to the symbol table strongly. But it's nice to be on the safe side. + WriteBarrierBase<SymbolTable>& symbolTable = curInstruction[6].u.symbolTable; + if (!symbolTable || Heap::isMarked(symbolTable.get())) break; if (Options::verboseOSR()) - dataLogF("Clearing dead activation %p.\n", activation.get()); - activation.clear(); + dataLogF("Clearing dead symbolTable %p.\n", symbolTable.get()); + symbolTable.clear(); break; } case op_get_from_scope: case op_put_to_scope: { ResolveModeAndType modeAndType = ResolveModeAndType(curInstruction[4].u.operand); - if (modeAndType.type() == GlobalVar || modeAndType.type() == GlobalVarWithVarInjectionChecks) + if (modeAndType.type() == GlobalVar || modeAndType.type() == GlobalVarWithVarInjectionChecks || modeAndType.type() == LocalClosureVar) continue; WriteBarrierBase<Structure>& structure = curInstruction[5].u.structure; if (!structure || Heap::isMarked(structure.get())) @@ -2222,7 +2613,8 @@ void CodeBlock::finalizeUnconditionally() break; } default: - RELEASE_ASSERT_NOT_REACHED(); + OpcodeID opcodeID = interpreter->getOpcodeID(curInstruction[0].u.opcode); + ASSERT_WITH_MESSAGE_UNUSED(opcodeID, false, "Unhandled opcode in CodeBlock::finalizeUnconditionally, %s(%d) at bc %u", opcodeNames[opcodeID], opcodeID, propertyAccessInstructions[i]); } } @@ -2325,6 +2717,15 @@ StructureStubInfo* CodeBlock::addStubInfo() return m_stubInfos.add(); } +StructureStubInfo* CodeBlock::findStubInfo(CodeOrigin codeOrigin) +{ + for (StructureStubInfo* stubInfo : m_stubInfos) { + if (stubInfo->codeOrigin == codeOrigin) + return stubInfo; + } + return nullptr; +} + CallLinkInfo* CodeBlock::addCallLinkInfo() { ConcurrentJITLocker locker(m_lock); @@ -2375,7 +2776,7 @@ void CodeBlock::resetStubDuringGCInternal(RepatchBuffer& repatchBuffer, Structur CallLinkInfo* CodeBlock::getCallLinkInfoForBytecodeIndex(unsigned index) { for (auto iter = m_callLinkInfos.begin(); !!iter; ++iter) { - if ((*iter)->codeOrigin == CodeOrigin(index)) + if ((*iter)->codeOrigin() == CodeOrigin(index)) return *iter; } return nullptr; @@ -2400,6 +2801,13 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) #if ENABLE(DFG_JIT) if (JITCode::isOptimizingJIT(jitType())) { + // FIXME: This is an antipattern for two reasons. References introduced by the DFG + // that aren't in the original CodeBlock being compiled should be weakly referenced. + // Inline call frames aren't in the original CodeBlock, so they qualify as weak. Also, + // those weak references should already be tracked in the DFG as weak FrozenValues. So, + // there is probably no need for this. We already have assertions that this should be + // unnecessary. + // https://bugs.webkit.org/show_bug.cgi?id=146613 DFG::CommonData* dfgCommon = m_jitCode->dfgCommon(); if (dfgCommon->inlineCallFrames.get()) dfgCommon->inlineCallFrames->visitAggregate(visitor); @@ -2428,6 +2836,9 @@ void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor) for (unsigned i = 0; i < dfgCommon->weakReferences.size(); ++i) visitor.append(&dfgCommon->weakReferences[i]); + + for (unsigned i = 0; i < dfgCommon->weakStructureReferences.size(); ++i) + visitor.append(&dfgCommon->weakStructureReferences[i]); #endif } @@ -2476,64 +2887,7 @@ bool CodeBlock::hasOptimizedReplacement() } #endif -bool CodeBlock::isCaptured(VirtualRegister operand, InlineCallFrame* inlineCallFrame) const -{ - if (operand.isArgument()) - return operand.toArgument() && usesArguments(); - - if (inlineCallFrame) - return inlineCallFrame->capturedVars.get(operand.toLocal()); - - // The activation object isn't in the captured region, but it's "captured" - // in the sense that stores to its location can be observed indirectly. - if (needsActivation() && operand == activationRegister()) - return true; - - // Ditto for the arguments object. - if (usesArguments() && operand == argumentsRegister()) - return true; - if (usesArguments() && operand == unmodifiedArgumentsRegister(argumentsRegister())) - return true; - - // We're in global code so there are no locals to capture - if (!symbolTable()) - return false; - - return symbolTable()->isCaptured(operand.offset()); -} - -int CodeBlock::framePointerOffsetToGetActivationRegisters(int machineCaptureStart) -{ - // We'll be adding this to the stack pointer to get a registers pointer that looks - // like it would have looked in the baseline engine. For example, if bytecode would - // have put the first captured variable at offset -5 but we put it at offset -1, then - // we'll have an offset of 4. - int32_t offset = 0; - - // Compute where we put the captured variables. This offset will point the registers - // pointer directly at the first captured var. - offset += machineCaptureStart; - - // Now compute the offset needed to make the runtime see the captured variables at the - // same offset that the bytecode would have used. - offset -= symbolTable()->captureStart(); - - return offset; -} - -int CodeBlock::framePointerOffsetToGetActivationRegisters() -{ - if (!JITCode::isOptimizingJIT(jitType())) - return 0; -#if ENABLE(DFG_JIT) - return framePointerOffsetToGetActivationRegisters(jitCode()->dfgCommon()->machineCaptureStart); -#else - RELEASE_ASSERT_NOT_REACHED(); - return 0; -#endif -} - -HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) +HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler requiredHandler) { RELEASE_ASSERT(bytecodeOffset < instructions().size()); @@ -2542,10 +2896,14 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers; for (size_t i = 0; i < exceptionHandlers.size(); ++i) { + HandlerInfo& handler = exceptionHandlers[i]; + if ((requiredHandler == RequiredHandler::CatchHandler) && !handler.isCatchHandler()) + continue; + // Handlers are ordered innermost first, so the first handler we encounter // that contains the source address is the correct handler to use. - if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end > bytecodeOffset) - return &exceptionHandlers[i]; + if (handler.start <= bytecodeOffset && handler.end > bytecodeOffset) + return &handler; } return 0; @@ -2554,7 +2912,7 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) unsigned CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset) { RELEASE_ASSERT(bytecodeOffset < instructions().size()); - return m_ownerExecutable->lineNo() + m_unlinkedCode->lineNumberForBytecodeOffset(bytecodeOffset); + return m_ownerExecutable->firstLine() + m_unlinkedCode->lineNumberForBytecodeOffset(bytecodeOffset); } unsigned CodeBlock::columnNumberForBytecodeOffset(unsigned bytecodeOffset) @@ -2573,7 +2931,7 @@ void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& d m_unlinkedCode->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column); divot += m_sourceOffset; column += line ? 1 : firstLineColumnOffset(); - line += m_ownerExecutable->lineNo(); + line += m_ownerExecutable->firstLine(); } bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, unsigned column) @@ -2604,6 +2962,7 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) if (shrinkMode == EarlyShrink) { m_constantRegisters.shrinkToFit(); + m_constantsSourceCodeRepresentation.shrinkToFit(); if (m_rareData) { m_rareData->m_switchJumpTables.shrinkToFit(); @@ -2612,27 +2971,6 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) } // else don't shrink these, because we would have already pointed pointers into these tables. } -unsigned CodeBlock::addOrFindConstant(JSValue v) -{ - unsigned result; - if (findConstant(v, result)) - return result; - return addConstant(v); -} - -bool CodeBlock::findConstant(JSValue v, unsigned& index) -{ - unsigned numberOfConstants = numberOfConstantRegisters(); - for (unsigned i = 0; i < numberOfConstants; ++i) { - if (getConstant(FirstConstantRegisterIndex + i) == v) { - index = i; - return true; - } - } - index = numberOfConstants; - return false; -} - #if ENABLE(JIT) void CodeBlock::unlinkCalls() { @@ -2660,6 +2998,12 @@ void CodeBlock::linkIncomingCall(ExecState* callerFrame, CallLinkInfo* incoming) noticeIncomingCall(callerFrame); m_incomingCalls.push(incoming); } + +void CodeBlock::linkIncomingPolymorphicCall(ExecState* callerFrame, PolymorphicCallNode* incoming) +{ + noticeIncomingCall(callerFrame); + m_incomingPolymorphicCalls.push(incoming); +} #endif // ENABLE(JIT) void CodeBlock::unlinkIncomingCalls() @@ -2667,11 +3011,13 @@ void CodeBlock::unlinkIncomingCalls() while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end()) m_incomingLLIntCalls.begin()->unlink(); #if ENABLE(JIT) - if (m_incomingCalls.isEmpty()) + if (m_incomingCalls.isEmpty() && m_incomingPolymorphicCalls.isEmpty()) return; RepatchBuffer repatchBuffer(this); while (m_incomingCalls.begin() != m_incomingCalls.end()) m_incomingCalls.begin()->unlink(repatchBuffer); + while (m_incomingPolymorphicCalls.begin() != m_incomingPolymorphicCalls.end()) + m_incomingPolymorphicCalls.begin()->unlink(repatchBuffer); #endif // ENABLE(JIT) } @@ -2702,18 +3048,6 @@ PassRefPtr<CodeBlock> CodeBlock::newReplacement() return ownerExecutable()->newReplacementCodeBlockFor(specializationKind()); } -const SlowArgument* CodeBlock::machineSlowArguments() -{ - if (!JITCode::isOptimizingJIT(jitType())) - return symbolTable()->slowArguments(); - -#if ENABLE(DFG_JIT) - return jitCode()->dfgCommon()->slowArguments.get(); -#else // ENABLE(DFG_JIT) - return 0; -#endif // ENABLE(DFG_JIT) -} - #if ENABLE(JIT) CodeBlock* ProgramCodeBlock::replacement() { @@ -2748,7 +3082,7 @@ DFG::CapabilityLevel FunctionCodeBlock::capabilityLevelInternal() } #endif -void CodeBlock::jettison(Profiler::JettisonReason reason, ReoptimizationMode mode) +void CodeBlock::jettison(Profiler::JettisonReason reason, ReoptimizationMode mode, const FireDetail* detail) { RELEASE_ASSERT(reason != Profiler::NotJettisoned); @@ -2757,14 +3091,17 @@ void CodeBlock::jettison(Profiler::JettisonReason reason, ReoptimizationMode mod dataLog("Jettisoning ", *this); if (mode == CountReoptimization) dataLog(" and counting reoptimization"); - dataLog(" due to ", reason, ".\n"); + dataLog(" due to ", reason); + if (detail) + dataLog(", ", *detail); + dataLog(".\n"); } DeferGCForAWhile deferGC(*m_heap); RELEASE_ASSERT(JITCode::isOptimizingJIT(jitType())); if (Profiler::Compilation* compilation = jitCode()->dfgCommon()->compilation.get()) - compilation->setJettisonReason(reason); + compilation->setJettisonReason(reason, detail); // We want to accomplish two things here: // 1) Make sure that if this CodeBlock is on the stack right now, then if we return to it @@ -2805,6 +3142,7 @@ void CodeBlock::jettison(Profiler::JettisonReason reason, ReoptimizationMode mod dataLog(" Did install baseline version of ", *this, "\n"); #else // ENABLE(DFG_JIT) UNUSED_PARAM(mode); + UNUSED_PARAM(detail); UNREACHABLE_FOR_PLATFORM(); #endif // ENABLE(DFG_JIT) } @@ -2816,17 +3154,64 @@ JSGlobalObject* CodeBlock::globalObjectFor(CodeOrigin codeOrigin) return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->eitherCodeBlock()->globalObject(); } +class RecursionCheckFunctor { +public: + RecursionCheckFunctor(CallFrame* startCallFrame, CodeBlock* codeBlock, unsigned depthToCheck) + : m_startCallFrame(startCallFrame) + , m_codeBlock(codeBlock) + , m_depthToCheck(depthToCheck) + , m_foundStartCallFrame(false) + , m_didRecurse(false) + { } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + CallFrame* currentCallFrame = visitor->callFrame(); + + if (currentCallFrame == m_startCallFrame) + m_foundStartCallFrame = true; + + if (m_foundStartCallFrame) { + if (visitor->callFrame()->codeBlock() == m_codeBlock) { + m_didRecurse = true; + return StackVisitor::Done; + } + + if (!m_depthToCheck--) + return StackVisitor::Done; + } + + return StackVisitor::Continue; + } + + bool didRecurse() const { return m_didRecurse; } + +private: + CallFrame* m_startCallFrame; + CodeBlock* m_codeBlock; + unsigned m_depthToCheck; + bool m_foundStartCallFrame; + bool m_didRecurse; +}; + void CodeBlock::noticeIncomingCall(ExecState* callerFrame) { CodeBlock* callerCodeBlock = callerFrame->codeBlock(); if (Options::verboseCallLink()) - dataLog("Noticing call link from ", *callerCodeBlock, " to ", *this, "\n"); + dataLog("Noticing call link from ", pointerDump(callerCodeBlock), " to ", *this, "\n"); +#if ENABLE(DFG_JIT) if (!m_shouldAlwaysBeInlined) return; + + if (!callerCodeBlock) { + m_shouldAlwaysBeInlined = false; + if (Options::verboseCallLink()) + dataLog(" Clearing SABI because caller is native.\n"); + return; + } -#if ENABLE(DFG_JIT) if (!hasBaselineJITProfiling()) return; @@ -2854,6 +3239,13 @@ void CodeBlock::noticeIncomingCall(ExecState* callerFrame) return; } + if (JITCode::isOptimizingJIT(callerCodeBlock->jitType())) { + m_shouldAlwaysBeInlined = false; + if (Options::verboseCallLink()) + dataLog(" Clearing SABI bcause caller was already optimized.\n"); + return; + } + if (callerCodeBlock->codeType() != FunctionCode) { // If the caller is either eval or global code, assume that that won't be // optimized anytime soon. For eval code this is particularly true since we @@ -2863,21 +3255,22 @@ void CodeBlock::noticeIncomingCall(ExecState* callerFrame) dataLog(" Clearing SABI because caller is not a function.\n"); return; } - - ExecState* frame = callerFrame; - for (unsigned i = Options::maximumInliningDepth(); i--; frame = frame->callerFrame()) { - if (frame->isVMEntrySentinel()) - break; - if (frame->codeBlock() == this) { - // Recursive calls won't be inlined. - if (Options::verboseCallLink()) - dataLog(" Clearing SABI because recursion was detected.\n"); - m_shouldAlwaysBeInlined = false; - return; - } + + // Recursive calls won't be inlined. + RecursionCheckFunctor functor(callerFrame, this, Options::maximumInliningDepth()); + vm()->topCallFrame->iterate(functor); + + if (functor.didRecurse()) { + if (Options::verboseCallLink()) + dataLog(" Clearing SABI because recursion was detected.\n"); + m_shouldAlwaysBeInlined = false; + return; } - RELEASE_ASSERT(callerCodeBlock->m_capabilityLevelState != DFG::CapabilityLevelNotSet); + if (callerCodeBlock->m_capabilityLevelState == DFG::CapabilityLevelNotSet) { + dataLog("In call from ", *callerCodeBlock, " ", callerFrame->codeOrigin(), " to ", *this, ": caller's DFG capability level is not set.\n"); + CRASH(); + } if (canCompile(callerCodeBlock->m_capabilityLevelState)) return; @@ -3290,9 +3683,7 @@ void CodeBlock::tallyFrequentExitSites() DFG::JITCode* jitCode = m_jitCode->dfg(); for (unsigned i = 0; i < jitCode->osrExit.size(); ++i) { DFG::OSRExit& exit = jitCode->osrExit[i]; - - if (!exit.considerAddingAsFrequentExitSite(profiledBlock)) - continue; + exit.considerAddingAsFrequentExitSite(profiledBlock); } break; } @@ -3305,9 +3696,7 @@ void CodeBlock::tallyFrequentExitSites() FTL::JITCode* jitCode = m_jitCode->ftl(); for (unsigned i = 0; i < jitCode->osrExit.size(); ++i) { FTL::OSRExit& exit = jitCode->osrExit[i]; - - if (!exit.considerAddingAsFrequentExitSite(profiledBlock)) - continue; + exit.considerAddingAsFrequentExitSite(profiledBlock); } break; } @@ -3441,69 +3830,31 @@ String CodeBlock::nameForRegister(VirtualRegister virtualRegister) ConcurrentJITLocker locker(symbolTable()->m_lock); SymbolTable::Map::iterator end = symbolTable()->end(locker); for (SymbolTable::Map::iterator ptr = symbolTable()->begin(locker); ptr != end; ++ptr) { - if (ptr->value.getIndex() == virtualRegister.offset()) { + if (ptr->value.varOffset() == VarOffset(virtualRegister)) { // FIXME: This won't work from the compilation thread. // https://bugs.webkit.org/show_bug.cgi?id=115300 - return String(ptr->key); + return ptr->key.get(); } } - if (needsActivation() && virtualRegister == activationRegister()) - return ASCIILiteral("activation"); if (virtualRegister == thisRegister()) return ASCIILiteral("this"); - if (usesArguments()) { - if (virtualRegister == argumentsRegister()) - return ASCIILiteral("arguments"); - if (unmodifiedArgumentsRegister(argumentsRegister()) == virtualRegister) - return ASCIILiteral("real arguments"); - } if (virtualRegister.isArgument()) - return String::format("arguments[%3d]", virtualRegister.toArgument()).impl(); + return String::format("arguments[%3d]", virtualRegister.toArgument()); return ""; } -namespace { - -struct VerifyCapturedDef { - void operator()(CodeBlock* codeBlock, Instruction* instruction, OpcodeID opcodeID, int operand) - { - unsigned bytecodeOffset = instruction - codeBlock->instructions().begin(); - - if (codeBlock->isConstantRegisterIndex(operand)) { - codeBlock->beginValidationDidFail(); - dataLog(" At bc#", bytecodeOffset, " encountered a definition of a constant.\n"); - codeBlock->endValidationDidFail(); - return; - } - - switch (opcodeID) { - case op_enter: - case op_captured_mov: - case op_init_lazy_reg: - case op_create_arguments: - case op_new_captured_func: - return; - default: - break; - } - - VirtualRegister virtualReg(operand); - if (!virtualReg.isLocal()) - return; - - if (codeBlock->captureCount() && codeBlock->symbolTable()->isCaptured(operand)) { - codeBlock->beginValidationDidFail(); - dataLog(" At bc#", bytecodeOffset, " encountered invalid assignment to captured variable loc", virtualReg.toLocal(), ".\n"); - codeBlock->endValidationDidFail(); - return; - } - - return; - } -}; - -} // anonymous namespace +ValueProfile* CodeBlock::valueProfileForBytecodeOffset(int bytecodeOffset) +{ + ValueProfile* result = binarySearch<ValueProfile, int>( + m_valueProfiles, m_valueProfiles.size(), bytecodeOffset, + getValueProfileBytecodeOffset<ValueProfile>); + ASSERT(result->m_bytecodeOffset != -1); + ASSERT(instructions()[bytecodeOffset + opcodeLength( + m_vm->interpreter->getOpcodeID( + instructions()[bytecodeOffset].u.opcode)) - 1].u.profile == result); + return result; +} void CodeBlock::validate() { @@ -3520,38 +3871,15 @@ void CodeBlock::validate() } for (unsigned i = m_numCalleeRegisters; i--;) { - bool isCaptured = false; VirtualRegister reg = virtualRegisterForLocal(i); - if (captureCount()) - isCaptured = reg.offset() <= captureStart() && reg.offset() > captureEnd(); - - if (isCaptured) { - if (!liveAtHead.get(i)) { - beginValidationDidFail(); - dataLog(" Variable loc", i, " is expected to be live because it is captured, but it isn't live.\n"); - dataLog(" Result: ", liveAtHead, "\n"); - endValidationDidFail(); - } - } else { - if (liveAtHead.get(i)) { - beginValidationDidFail(); - dataLog(" Variable loc", i, " is expected to be dead.\n"); - dataLog(" Result: ", liveAtHead, "\n"); - endValidationDidFail(); - } + if (liveAtHead.get(i)) { + beginValidationDidFail(); + dataLog(" Variable ", reg, " is expected to be dead.\n"); + dataLog(" Result: ", liveAtHead, "\n"); + endValidationDidFail(); } } - - for (unsigned bytecodeOffset = 0; bytecodeOffset < instructions().size();) { - Instruction* currentInstruction = instructions().begin() + bytecodeOffset; - OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode); - - VerifyCapturedDef verifyCapturedDef; - computeDefsForBytecodeOffset(this, bytecodeOffset, verifyCapturedDef); - - bytecodeOffset += opcodeLength(opcodeID); - } } void CodeBlock::beginValidationDidFail() @@ -3600,4 +3928,71 @@ DFG::CapabilityLevel CodeBlock::capabilityLevel() } #endif +void CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler(Vector<Instruction, 0, UnsafeVectorOverflow>& instructions) +{ + const Vector<size_t>& bytecodeOffsets = unlinkedCodeBlock()->opProfileControlFlowBytecodeOffsets(); + for (size_t i = 0, offsetsLength = bytecodeOffsets.size(); i < offsetsLength; i++) { + // Because op_profile_control_flow is emitted at the beginning of every basic block, finding + // the next op_profile_control_flow will give us the text range of a single basic block. + size_t startIdx = bytecodeOffsets[i]; + RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[startIdx].u.opcode) == op_profile_control_flow); + int basicBlockStartOffset = instructions[startIdx + 1].u.operand; + int basicBlockEndOffset; + if (i + 1 < offsetsLength) { + size_t endIdx = bytecodeOffsets[i + 1]; + RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[endIdx].u.opcode) == op_profile_control_flow); + basicBlockEndOffset = instructions[endIdx + 1].u.operand - 1; + } else { + basicBlockEndOffset = m_sourceOffset + m_ownerExecutable->source().length() - 1; // Offset before the closing brace. + basicBlockStartOffset = std::min(basicBlockStartOffset, basicBlockEndOffset); // Some start offsets may be at the closing brace, ensure it is the offset before. + } + + // The following check allows for the same textual JavaScript basic block to have its bytecode emitted more + // than once and still play nice with the control flow profiler. When basicBlockStartOffset is larger than + // basicBlockEndOffset, it indicates that the bytecode generator has emitted code for the same AST node + // more than once (for example: ForInNode, Finally blocks in TryNode, etc). Though these are different + // basic blocks at the bytecode level, they are generated from the same textual basic block in the JavaScript + // program. The condition: + // (basicBlockEndOffset < basicBlockStartOffset) + // is encountered when op_profile_control_flow lies across the boundary of these duplicated bytecode basic + // blocks and the textual offset goes from the end of the duplicated block back to the beginning. These + // ranges are dummy ranges and are ignored. The duplicated bytecode basic blocks point to the same + // internal data structure, so if any of them execute, it will record the same textual basic block in the + // JavaScript program as executing. + // At the bytecode level, this situation looks like: + // j: op_profile_control_flow (from j->k, we have basicBlockEndOffset < basicBlockStartOffset) + // ... + // k: op_profile_control_flow (we want to skip over the j->k block and start fresh at offset k as the start of a new basic block k->m). + // ... + // m: op_profile_control_flow + if (basicBlockEndOffset < basicBlockStartOffset) { + RELEASE_ASSERT(i + 1 < offsetsLength); // We should never encounter dummy blocks at the end of a CodeBlock. + instructions[startIdx + 1].u.basicBlockLocation = vm()->controlFlowProfiler()->dummyBasicBlock(); + continue; + } + + BasicBlockLocation* basicBlockLocation = vm()->controlFlowProfiler()->getBasicBlockLocation(m_ownerExecutable->sourceID(), basicBlockStartOffset, basicBlockEndOffset); + + // Find all functions that are enclosed within the range: [basicBlockStartOffset, basicBlockEndOffset] + // and insert these functions' start/end offsets as gaps in the current BasicBlockLocation. + // This is necessary because in the original source text of a JavaScript program, + // function literals form new basic blocks boundaries, but they aren't represented + // inside the CodeBlock's instruction stream. + auto insertFunctionGaps = [basicBlockLocation, basicBlockStartOffset, basicBlockEndOffset] (const WriteBarrier<FunctionExecutable>& functionExecutable) { + const UnlinkedFunctionExecutable* executable = functionExecutable->unlinkedExecutable(); + int functionStart = executable->typeProfilingStartOffset(); + int functionEnd = executable->typeProfilingEndOffset(); + if (functionStart >= basicBlockStartOffset && functionEnd <= basicBlockEndOffset) + basicBlockLocation->insertGap(functionStart, functionEnd); + }; + + for (const WriteBarrier<FunctionExecutable>& executable : m_functionDecls) + insertFunctionGaps(executable); + for (const WriteBarrier<FunctionExecutable>& executable : m_functionExprs) + insertFunctionGaps(executable); + + instructions[startIdx + 1].u.basicBlockLocation = basicBlockLocation; + } +} + } // namespace JSC diff --git a/bytecode/CodeBlock.h b/bytecode/CodeBlock.h index 18ef0e3..65dab95 100644 --- a/bytecode/CodeBlock.h +++ b/bytecode/CodeBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008-2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without @@ -70,7 +70,6 @@ #include "Watchpoint.h" #include <wtf/Bag.h> #include <wtf/FastMalloc.h> -#include <wtf/PassOwnPtr.h> #include <wtf/RefCountedArray.h> #include <wtf/RefPtr.h> #include <wtf/SegmentedVector.h> @@ -82,10 +81,7 @@ namespace JSC { class ExecState; class LLIntOffsetsExtractor; class RepatchBuffer; - -inline VirtualRegister unmodifiedArgumentsRegister(VirtualRegister argumentsRegister) { return VirtualRegister(argumentsRegister.offset() + 1); } - -static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); } +class TypeLocation; enum ReoptimizationMode { DontCountReoptimization, CountReoptimization }; @@ -159,7 +155,11 @@ public: void visitAggregate(SlotVisitor&); - void dumpBytecode(PrintStream& = WTF::dataFile()); + void dumpSource(); + void dumpSource(PrintStream&); + + void dumpBytecode(); + void dumpBytecode(PrintStream&); void dumpBytecode( PrintStream&, unsigned bytecodeOffset, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); @@ -185,7 +185,11 @@ public: return index >= m_numVars; } - HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); + enum class RequiredHandler { + CatchHandler, + AnyHandler + }; + HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler); unsigned lineNumberForBytecodeOffset(unsigned bytecodeOffset); unsigned columnNumberForBytecodeOffset(unsigned bytecodeOffset); void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, @@ -201,6 +205,10 @@ public: StructureStubInfo* addStubInfo(); Bag<StructureStubInfo>::iterator stubInfoBegin() { return m_stubInfos.begin(); } Bag<StructureStubInfo>::iterator stubInfoEnd() { return m_stubInfos.end(); } + + // O(n) operation. Use getStubInfoMap() unless you really only intend to get one + // stub info. + StructureStubInfo* findStubInfo(CodeOrigin); void resetStub(StructureStubInfo&); @@ -225,18 +233,14 @@ public: void unlinkCalls(); void linkIncomingCall(ExecState* callerFrame, CallLinkInfo*); - - bool isIncomingCallAlreadyLinked(CallLinkInfo* incoming) - { - return m_incomingCalls.isOnList(incoming); - } + void linkIncomingPolymorphicCall(ExecState* callerFrame, PolymorphicCallNode*); #endif // ENABLE(JIT) void linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo*); - void setJITCodeMap(PassOwnPtr<CompactJITCodeMap> jitCodeMap) + void setJITCodeMap(std::unique_ptr<CompactJITCodeMap> jitCodeMap) { - m_jitCodeMap = jitCodeMap; + m_jitCodeMap = WTF::move(jitCodeMap); } CompactJITCodeMap* jitCodeMap() { @@ -249,8 +253,6 @@ public: return static_cast<Instruction*>(returnAddress) - instructions().begin(); } - bool isNumericCompareFunction() { return m_unlinkedCode->isNumericCompareFunction(); } - unsigned numberOfInstructions() const { return m_instructions.size(); } RefCountedArray<Instruction>& instructions() { return m_instructions; } const RefCountedArray<Instruction>& instructions() const { return m_instructions; } @@ -261,11 +263,6 @@ public: unsigned instructionCount() const { return m_instructions.size(); } - int argumentIndexAfterCapture(size_t argument); - - bool hasSlowArguments(); - const SlowArgument* machineSlowArguments(); - // Exactly equivalent to codeBlock->ownerExecutable()->installCode(codeBlock); void install(); @@ -275,7 +272,7 @@ public: void setJITCode(PassRefPtr<JITCode> code) { ASSERT(m_heap->isDeferred()); - m_heap->reportExtraMemoryCost(code->size()); + m_heap->reportExtraMemoryAllocated(code->size()); ConcurrentJITLocker locker(m_lock); WTF::storeStoreFence(); // This is probably not needed because the lock will also do something similar, but it's good to be paranoid. m_jitCode = code; @@ -306,7 +303,7 @@ public: bool hasOptimizedReplacement(); // the typeToReplace is my JITType #endif - void jettison(Profiler::JettisonReason, ReoptimizationMode = DontCountReoptimization); + void jettison(Profiler::JettisonReason, ReoptimizationMode = DontCountReoptimization, const FireDetail* = nullptr); ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); } @@ -318,73 +315,39 @@ public: bool usesEval() const { return m_unlinkedCode->usesEval(); } - void setArgumentsRegister(VirtualRegister argumentsRegister) + void setScopeRegister(VirtualRegister scopeRegister) { - ASSERT(argumentsRegister.isValid()); - m_argumentsRegister = argumentsRegister; - ASSERT(usesArguments()); + ASSERT(scopeRegister.isLocal() || !scopeRegister.isValid()); + m_scopeRegister = scopeRegister; } - VirtualRegister argumentsRegister() const - { - ASSERT(usesArguments()); - return m_argumentsRegister; - } - VirtualRegister uncheckedArgumentsRegister() + + VirtualRegister scopeRegister() const { - if (!usesArguments()) - return VirtualRegister(); - return argumentsRegister(); + return m_scopeRegister; } + void setActivationRegister(VirtualRegister activationRegister) { - m_activationRegister = activationRegister; + m_lexicalEnvironmentRegister = activationRegister; } VirtualRegister activationRegister() const { - ASSERT(m_activationRegister.isValid()); - return m_activationRegister; + ASSERT(m_lexicalEnvironmentRegister.isValid()); + return m_lexicalEnvironmentRegister; } VirtualRegister uncheckedActivationRegister() { - return m_activationRegister; + return m_lexicalEnvironmentRegister; } - bool usesArguments() const { return m_argumentsRegister.isValid(); } - bool needsActivation() const { - ASSERT(m_activationRegister.isValid() == m_needsActivation); + ASSERT(m_lexicalEnvironmentRegister.isValid() == m_needsActivation); return m_needsActivation; } - unsigned captureCount() const - { - if (!symbolTable()) - return 0; - return symbolTable()->captureCount(); - } - - int captureStart() const - { - if (!symbolTable()) - return 0; - return symbolTable()->captureStart(); - } - - int captureEnd() const - { - if (!symbolTable()) - return 0; - return symbolTable()->captureEnd(); - } - - bool isCaptured(VirtualRegister operand, InlineCallFrame* = 0) const; - - int framePointerOffsetToGetActivationRegisters(int machineCaptureStart); - int framePointerOffsetToGetActivationRegisters(); - CodeType codeType() const { return m_unlinkedCode->codeType(); } PutPropertySlot::Context putByIdContext() const { @@ -425,17 +388,7 @@ public: unsigned numberOfValueProfiles() { return m_valueProfiles.size(); } ValueProfile* valueProfile(int index) { return &m_valueProfiles[index]; } - ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset) - { - ValueProfile* result = binarySearch<ValueProfile, int>( - m_valueProfiles, m_valueProfiles.size(), bytecodeOffset, - getValueProfileBytecodeOffset<ValueProfile>); - ASSERT(result->m_bytecodeOffset != -1); - ASSERT(instructions()[bytecodeOffset + opcodeLength( - m_vm->interpreter->getOpcodeID( - instructions()[bytecodeOffset].u.opcode)) - 1].u.profile == result); - return result; - } + ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset); SpeculatedType valueProfilePredictionForBytecodeOffset(const ConcurrentJITLocker& locker, int bytecodeOffset) { return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction(locker); @@ -618,12 +571,13 @@ public: #endif Vector<WriteBarrier<Unknown>>& constants() { return m_constantRegisters; } - size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } + Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; } unsigned addConstant(JSValue v) { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier<Unknown>()); m_constantRegisters.last().set(m_globalObject->vm(), m_ownerExecutable.get(), v); + m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); return result; } @@ -631,19 +585,19 @@ public: { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier<Unknown>()); + m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); return result; } - bool findConstant(JSValue, unsigned& result); - unsigned addOrFindConstant(JSValue); WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } + ALWAYS_INLINE SourceCodeRepresentation constantSourceCodeRepresentation(int index) const { return m_constantsSourceCodeRepresentation[index - FirstConstantRegisterIndex]; } FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } int numberOfFunctionDecls() { return m_functionDecls.size(); } FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } - + RegExp* regexp(int index) const { return m_unlinkedCode->regexp(index); } unsigned numberOfConstantBuffers() const @@ -937,6 +891,21 @@ public: bool isKnownToBeLiveDuringGC(); // Will only return valid results when called during GC. Assumes that you've already established that the owner executable is live. + struct RareData { + WTF_MAKE_FAST_ALLOCATED; + public: + Vector<HandlerInfo> m_exceptionHandlers; + + // Buffers used for large array literals + Vector<Vector<JSValue>> m_constantBuffers; + + // Jump Tables + Vector<SimpleJumpTable> m_switchJumpTables; + Vector<StringJumpTable> m_stringSwitchJumpTables; + + EvalCodeCache m_evalCodeCache; + }; + protected: virtual void visitWeakReferences(SlotVisitor&) override; virtual void finalizeUnconditionally() override; @@ -956,18 +925,16 @@ private: double optimizationThresholdScalingFactor(); -#if ENABLE(JIT) - ClosureCallStubRoutine* findClosureCallForReturnPC(ReturnAddressPtr); -#endif - void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); - void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants) + void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants, const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation) { + ASSERT(constants.size() == constantsSourceCodeRepresentation.size()); size_t count = constants.size(); - m_constantRegisters.resize(count); + m_constantRegisters.resizeToFit(count); for (size_t i = 0; i < count; i++) m_constantRegisters[i].set(*m_vm, ownerExecutable(), constants[i].get()); + m_constantsSourceCodeRepresentation = constantsSourceCodeRepresentation; } void dumpBytecode( @@ -975,6 +942,7 @@ private: const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); CString registerName(int r) const; + CString constantName(int index) const; void printUnaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); void printBinaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); void printConditionalJump(PrintStream&, ExecState*, const Instruction*, const Instruction*&, int location, const char* op); @@ -983,6 +951,7 @@ private: enum CacheDumpMode { DumpCaches, DontDumpCaches }; void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&); void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); + void printPutByIdCacheStatus(PrintStream&, ExecState*, int location, const StubInfoMap&); void printLocationAndOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); void printLocationOpAndRegisterOperand(PrintStream&, ExecState*, int location, const Instruction*& it, const char* op, int operand); @@ -1002,9 +971,11 @@ private: void createRareDataIfNecessary() { if (!m_rareData) - m_rareData = adoptPtr(new RareData); + m_rareData = std::make_unique<RareData>(); } - + + void insertBasicBlockBoundariesForControlFlowProfiler(Vector<Instruction, 0, UnsafeVectorOverflow>&); + #if ENABLE(JIT) void resetStubInternal(RepatchBuffer&, StructureStubInfo&); void resetStubDuringGCInternal(RepatchBuffer&, StructureStubInfo&); @@ -1025,13 +996,13 @@ private: RefCountedArray<Instruction> m_instructions; WriteBarrier<SymbolTable> m_symbolTable; VirtualRegister m_thisRegister; - VirtualRegister m_argumentsRegister; - VirtualRegister m_activationRegister; + VirtualRegister m_scopeRegister; + VirtualRegister m_lexicalEnvironmentRegister; bool m_isStrictMode; bool m_needsActivation; bool m_mayBeExecuting; - uint8_t m_visitAggregateHasBeenCalled; + Atomic<bool> m_visitAggregateHasBeenCalled; RefPtr<SourceProvider> m_source; unsigned m_sourceOffset; @@ -1046,8 +1017,9 @@ private: Vector<ByValInfo> m_byValInfos; Bag<CallLinkInfo> m_callLinkInfos; SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo>> m_incomingCalls; + SentinelLinkedList<PolymorphicCallNode, BasicRawSentinelNode<PolymorphicCallNode>> m_incomingPolymorphicCalls; #endif - OwnPtr<CompactJITCodeMap> m_jitCodeMap; + std::unique_ptr<CompactJITCodeMap> m_jitCodeMap; #if ENABLE(DFG_JIT) // This is relevant to non-DFG code blocks that serve as the profiled code block // for DFG code blocks. @@ -1067,6 +1039,7 @@ private: // TODO: This could just be a pointer to m_unlinkedCodeBlock's data, but the DFG mutates // it, so we're stuck with it for now. Vector<WriteBarrier<Unknown>> m_constantRegisters; + Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; Vector<WriteBarrier<FunctionExecutable>> m_functionDecls; Vector<WriteBarrier<FunctionExecutable>> m_functionExprs; @@ -1084,24 +1057,7 @@ private: std::unique_ptr<BytecodeLivenessAnalysis> m_livenessAnalysis; - struct RareData { - WTF_MAKE_FAST_ALLOCATED; - public: - Vector<HandlerInfo> m_exceptionHandlers; - - // Buffers used for large array literals - Vector<Vector<JSValue>> m_constantBuffers; - - // Jump Tables - Vector<SimpleJumpTable> m_switchJumpTables; - Vector<StringJumpTable> m_stringSwitchJumpTables; - - EvalCodeCache m_evalCodeCache; - }; -#if COMPILER(MSVC) - friend void WTF::deleteOwnedPtr<RareData>(RareData*); -#endif - OwnPtr<RareData> m_rareData; + std::unique_ptr<RareData> m_rareData; #if ENABLE(JIT) DFG::CapabilityLevel m_capabilityLevelState; #endif @@ -1191,7 +1147,7 @@ inline CodeBlock* baselineCodeBlockForInlineCallFrame(InlineCallFrame* inlineCal RELEASE_ASSERT(inlineCallFrame); ExecutableBase* executable = inlineCallFrame->executable.get(); RELEASE_ASSERT(executable->structure()->classInfo() == FunctionExecutable::info()); - return static_cast<FunctionExecutable*>(executable)->baselineCodeBlockFor(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct); + return static_cast<FunctionExecutable*>(executable)->baselineCodeBlockFor(inlineCallFrame->specializationKind()); } inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock) @@ -1201,24 +1157,6 @@ inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigi return baselineCodeBlock; } -inline int CodeBlock::argumentIndexAfterCapture(size_t argument) -{ - if (argument >= static_cast<size_t>(symbolTable()->parameterCount())) - return CallFrame::argumentOffset(argument); - - const SlowArgument* slowArguments = symbolTable()->slowArguments(); - if (!slowArguments || slowArguments[argument].status == SlowArgument::Normal) - return CallFrame::argumentOffset(argument); - - ASSERT(slowArguments[argument].status == SlowArgument::Captured); - return slowArguments[argument].index; -} - -inline bool CodeBlock::hasSlowArguments() -{ - return !!symbolTable()->slowArguments(); -} - inline Register& ExecState::r(int index) { CodeBlock* codeBlock = this->codeBlock(); @@ -1227,21 +1165,20 @@ inline Register& ExecState::r(int index) return this[index]; } +inline Register& ExecState::r(VirtualRegister reg) +{ + return r(reg.offset()); +} + inline Register& ExecState::uncheckedR(int index) { RELEASE_ASSERT(index < FirstConstantRegisterIndex); return this[index]; } -inline JSValue ExecState::argumentAfterCapture(size_t argument) +inline Register& ExecState::uncheckedR(VirtualRegister reg) { - if (argument >= argumentCount()) - return jsUndefined(); - - if (!codeBlock()) - return this[argumentOffset(argument)].jsValue(); - - return this[codeBlock()->argumentIndexAfterCapture(argument)].jsValue(); + return uncheckedR(reg.offset()); } inline void CodeBlockSet::mark(void* candidateCodeBlock) @@ -1272,7 +1209,7 @@ inline void CodeBlockSet::mark(CodeBlock* codeBlock) codeBlock->m_mayBeExecuting = true; // We might not have cleared the marks for this CodeBlock, but we need to visit it. - codeBlock->m_visitAggregateHasBeenCalled = false; + codeBlock->m_visitAggregateHasBeenCalled.store(false, std::memory_order_relaxed); #if ENABLE(GGC) m_currentlyExecuting.append(codeBlock); #endif diff --git a/bytecode/CodeBlockJettisoningWatchpoint.cpp b/bytecode/CodeBlockJettisoningWatchpoint.cpp index 77ff647..177b243 100644 --- a/bytecode/CodeBlockJettisoningWatchpoint.cpp +++ b/bytecode/CodeBlockJettisoningWatchpoint.cpp @@ -32,12 +32,12 @@ namespace JSC { -void CodeBlockJettisoningWatchpoint::fireInternal() +void CodeBlockJettisoningWatchpoint::fireInternal(const FireDetail& detail) { if (DFG::shouldShowDisassembly()) dataLog("Firing watchpoint ", RawPointer(this), " on ", *m_codeBlock, "\n"); - m_codeBlock->jettison(Profiler::JettisonDueToUnprofiledWatchpoint, CountReoptimization); + m_codeBlock->jettison(Profiler::JettisonDueToUnprofiledWatchpoint, CountReoptimization, &detail); if (isOnList()) remove(); diff --git a/bytecode/CodeBlockJettisoningWatchpoint.h b/bytecode/CodeBlockJettisoningWatchpoint.h index 89d87f4..df4fe7b 100644 --- a/bytecode/CodeBlockJettisoningWatchpoint.h +++ b/bytecode/CodeBlockJettisoningWatchpoint.h @@ -45,7 +45,7 @@ public: } protected: - virtual void fireInternal() override; + virtual void fireInternal(const FireDetail&) override; private: CodeBlock* m_codeBlock; diff --git a/bytecode/CodeOrigin.cpp b/bytecode/CodeOrigin.cpp index 7ec1ce2..15f7591 100644 --- a/bytecode/CodeOrigin.cpp +++ b/bytecode/CodeOrigin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -74,7 +74,7 @@ bool CodeOrigin::isApproximatelyEqualTo(const CodeOrigin& other) const if (!a.inlineCallFrame) return true; - if (a.inlineCallFrame->executable != b.inlineCallFrame->executable) + if (a.inlineCallFrame->executable.get() != b.inlineCallFrame->executable.get()) return false; a = a.inlineCallFrame->caller; @@ -141,6 +141,27 @@ void CodeOrigin::dumpInContext(PrintStream& out, DumpContext*) const dump(out); } +JSFunction* InlineCallFrame::calleeConstant() const +{ + if (calleeRecovery.isConstant()) + return jsCast<JSFunction*>(calleeRecovery.constant()); + return nullptr; +} + +void InlineCallFrame::visitAggregate(SlotVisitor& visitor) +{ + // FIXME: This is an antipattern for two reasons. References introduced by the DFG + // that aren't in the original CodeBlock being compiled should be weakly referenced. + // Inline call frames aren't in the original CodeBlock, so they qualify as weak. Also, + // those weak references should already be tracked in the DFG as weak FrozenValues. So, + // there is probably no need for this. We already have assertions that this should be + // unnecessary. Finally, just marking the executable and not anything else in the inline + // call frame is almost certainly insufficient for what this method thought it was going + // to accomplish. + // https://bugs.webkit.org/show_bug.cgi?id=146613 + visitor.append(&executable); +} + JSFunction* InlineCallFrame::calleeForCallFrame(ExecState* exec) const { return jsCast<JSFunction*>(calleeRecovery.recover(exec)); @@ -178,14 +199,14 @@ void InlineCallFrame::dumpInContext(PrintStream& out, DumpContext* context) cons out.print(briefFunctionInformation(), ":<", RawPointer(executable.get())); if (executable->isStrictMode()) out.print(" (StrictMode)"); - out.print(", bc#", caller.bytecodeIndex, ", ", specializationKind()); + out.print(", bc#", caller.bytecodeIndex, ", ", kind); if (isClosureCall) out.print(", closure call"); else out.print(", known callee: ", inContext(calleeRecovery.constant(), context)); out.print(", numArgs+this = ", arguments.size()); - out.print(", stack < loc", VirtualRegister(stackOffset).toLocal()); - out.print(">"); + out.print(", stackOffset = ", stackOffset); + out.print(" (", virtualRegisterForLocal(0), " maps to ", virtualRegisterForLocal(0) + stackOffset, ")>"); } void InlineCallFrame::dump(PrintStream& out) const @@ -195,3 +216,32 @@ void InlineCallFrame::dump(PrintStream& out) const } // namespace JSC +namespace WTF { + +void printInternal(PrintStream& out, JSC::InlineCallFrame::Kind kind) +{ + switch (kind) { + case JSC::InlineCallFrame::Call: + out.print("Call"); + return; + case JSC::InlineCallFrame::Construct: + out.print("Construct"); + return; + case JSC::InlineCallFrame::CallVarargs: + out.print("CallVarargs"); + return; + case JSC::InlineCallFrame::ConstructVarargs: + out.print("ConstructVarargs"); + return; + case JSC::InlineCallFrame::GetterCall: + out.print("GetterCall"); + return; + case JSC::InlineCallFrame::SetterCall: + out.print("SetterCall"); + return; + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + diff --git a/bytecode/CodeOrigin.h b/bytecode/CodeOrigin.h index cffd4eb..d1879a3 100644 --- a/bytecode/CodeOrigin.h +++ b/bytecode/CodeOrigin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,6 @@ #include "CodeBlockHash.h" #include "CodeSpecializationKind.h" -#include "JSFunction.h" #include "ValueRecovery.h" #include "WriteBarrier.h" #include <wtf/BitVector.h> @@ -118,39 +117,97 @@ private: }; struct InlineCallFrame { + enum Kind { + Call, + Construct, + CallVarargs, + ConstructVarargs, + + // For these, the stackOffset incorporates the argument count plus the true return PC + // slot. + GetterCall, + SetterCall + }; + + static Kind kindFor(CodeSpecializationKind kind) + { + switch (kind) { + case CodeForCall: + return Call; + case CodeForConstruct: + return Construct; + } + RELEASE_ASSERT_NOT_REACHED(); + return Call; + } + + static Kind varargsKindFor(CodeSpecializationKind kind) + { + switch (kind) { + case CodeForCall: + return CallVarargs; + case CodeForConstruct: + return ConstructVarargs; + } + RELEASE_ASSERT_NOT_REACHED(); + return Call; + } + + static CodeSpecializationKind specializationKindFor(Kind kind) + { + switch (kind) { + case Call: + case CallVarargs: + case GetterCall: + case SetterCall: + return CodeForCall; + case Construct: + case ConstructVarargs: + return CodeForConstruct; + } + RELEASE_ASSERT_NOT_REACHED(); + return CodeForCall; + } + + static bool isVarargs(Kind kind) + { + switch (kind) { + case CallVarargs: + case ConstructVarargs: + return true; + default: + return false; + } + } + bool isVarargs() const + { + return isVarargs(static_cast<Kind>(kind)); + } + Vector<ValueRecovery> arguments; // Includes 'this'. WriteBarrier<ScriptExecutable> executable; ValueRecovery calleeRecovery; CodeOrigin caller; - BitVector capturedVars; // Indexed by the machine call frame's variable numbering. - signed stackOffset : 30; - bool isCall : 1; + + signed stackOffset : 28; + unsigned kind : 3; // real type is Kind bool isClosureCall : 1; // If false then we know that callee/scope are constants and the DFG won't treat them as variables, i.e. they have to be recovered manually. - VirtualRegister argumentsRegister; // This is only set if the code uses arguments. The unmodified arguments register follows the unmodifiedArgumentsRegister() convention (see CodeBlock.h). + VirtualRegister argumentCountRegister; // Only set when we inline a varargs call. // There is really no good notion of a "default" set of values for // InlineCallFrame's fields. This constructor is here just to reduce confusion if // we forgot to initialize explicitly. InlineCallFrame() : stackOffset(0) - , isCall(false) + , kind(Call) , isClosureCall(false) { } - CodeSpecializationKind specializationKind() const { return specializationFromIsCall(isCall); } - - JSFunction* calleeConstant() const - { - if (calleeRecovery.isConstant()) - return jsCast<JSFunction*>(calleeRecovery.constant()); - return 0; - } + CodeSpecializationKind specializationKind() const { return specializationKindFor(static_cast<Kind>(kind)); } - void visitAggregate(SlotVisitor& visitor) - { - visitor.append(&executable); - } + JSFunction* calleeConstant() const; + void visitAggregate(SlotVisitor&); // Get the callee given a machine call frame to which this InlineCallFrame belongs. JSFunction* calleeForCallFrame(ExecState*) const; @@ -161,6 +218,12 @@ struct InlineCallFrame { CodeBlock* baselineCodeBlock() const; + void setStackOffset(signed offset) + { + stackOffset = offset; + RELEASE_ASSERT(static_cast<signed>(stackOffset) == offset); + } + ptrdiff_t callerFrameOffset() const { return stackOffset * sizeof(Register) + CallFrame::callerFrameOffset(); } ptrdiff_t returnPCOffset() const { return stackOffset * sizeof(Register) + CallFrame::returnPCOffset(); } @@ -214,6 +277,8 @@ struct CodeOriginApproximateHash { namespace WTF { +void printInternal(PrintStream&, JSC::InlineCallFrame::Kind); + template<typename T> struct DefaultHash; template<> struct DefaultHash<JSC::CodeOrigin> { typedef JSC::CodeOriginHash Hash; diff --git a/bytecode/ComplexGetStatus.cpp b/bytecode/ComplexGetStatus.cpp new file mode 100644 index 0000000..d813a3d --- /dev/null +++ b/bytecode/ComplexGetStatus.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 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 "ComplexGetStatus.h" + +#include "JSCInlines.h" + +namespace JSC { + +ComplexGetStatus ComplexGetStatus::computeFor( + CodeBlock* profiledBlock, Structure* headStructure, StructureChain* chain, + unsigned chainCount, UniquedStringImpl* uid) +{ + // FIXME: We should assert that we never see a structure that + // hasImpureGetOwnPropertySlot() but for which we don't + // newImpurePropertyFiresWatchpoints(). We're not at a point where we can do + // that, yet. + // https://bugs.webkit.org/show_bug.cgi?id=131810 + + if (headStructure->takesSlowPathInDFGForImpureProperty()) + return takesSlowPath(); + + ComplexGetStatus result; + result.m_kind = Inlineable; + + if (chain && chainCount) { + result.m_chain = adoptRef(new IntendedStructureChain( + profiledBlock, headStructure, chain, chainCount)); + + if (!result.m_chain->isStillValid()) + return skip(); + + if (headStructure->takesSlowPathInDFGForImpureProperty() + || result.m_chain->takesSlowPathInDFGForImpureProperty()) + return takesSlowPath(); + + JSObject* currentObject = result.m_chain->terminalPrototype(); + Structure* currentStructure = result.m_chain->last(); + + ASSERT_UNUSED(currentObject, currentObject); + + result.m_offset = currentStructure->getConcurrently(uid, result.m_attributes); + } else { + result.m_offset = headStructure->getConcurrently(uid, result.m_attributes); + } + + if (!isValidOffset(result.m_offset)) + return takesSlowPath(); + + return result; +} + +} // namespace JSC + + diff --git a/bytecode/ComplexGetStatus.h b/bytecode/ComplexGetStatus.h new file mode 100644 index 0000000..2620405 --- /dev/null +++ b/bytecode/ComplexGetStatus.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2014 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 ComplexGetStatus_h +#define ComplexGetStatus_h + +#include "IntendedStructureChain.h" +#include "JSCJSValue.h" +#include "PropertyOffset.h" + +namespace JSC { + +class CodeBlock; +class StructureChain; + +// This class is useful for figuring out how to inline a cached get-like access. We +// say "get-like" because this is appropriate for loading the GetterSetter object in +// a put_by_id that hits a setter. Notably, this doesn't figure out how to call +// accessors, or even whether they should be called. What it gives us, is a way of +// determining how to load the value from the requested property (identified by a +// StringImpl* uid) from an object of the given structure in the given CodeBlock, +// assuming that such an access had already been cached by Repatch (and so Repatch had +// already done a bunch of safety checks). This doesn't reexecute any checks that +// Repatch would have executed, and for prototype chain accesses, it doesn't ask the +// objects in the prototype chain whether their getOwnPropertySlot would attempt to +// intercept the access - so this really is only appropriate if you already know that +// one of the JITOperations had OK'd this for caching and that Repatch concurred. +// +// The typical use pattern is something like: +// +// ComplexGetStatus status = ComplexGetStatus::computeFor(...); +// switch (status.kind()) { +// case ComplexGetStatus::ShouldSkip: +// // Handle the case where this kind of access is possibly safe but wouldn't +// // pass the required safety checks. For example, if an IC gives us a list of +// // accesses and one of them is ShouldSkip, then we should pretend as if it +// // wasn't even there. +// break; +// case ComplexGetStatus::TakesSlowPath: +// // This kind of access is not safe to inline. Bail out of any attempst to +// // inline. +// break; +// case ComplexGetStatus::Inlineable: +// // The good stuff goes here. If it's Inlineable then the other properties of +// // the 'status' object will tell you everything you need to know about how +// // to execute the get-like operation. +// break; +// } + +class ComplexGetStatus { +public: + enum Kind { + ShouldSkip, + TakesSlowPath, + Inlineable + }; + + ComplexGetStatus() + : m_kind(ShouldSkip) + , m_offset(invalidOffset) + , m_attributes(UINT_MAX) + { + } + + static ComplexGetStatus skip() + { + return ComplexGetStatus(); + } + + static ComplexGetStatus takesSlowPath() + { + ComplexGetStatus result; + result.m_kind = TakesSlowPath; + return result; + } + + static ComplexGetStatus computeFor( + CodeBlock* profiledBlock, Structure* headStructure, StructureChain* chain, + unsigned chainCount, UniquedStringImpl* uid); + + Kind kind() const { return m_kind; } + unsigned attributes() const { return m_attributes; } + JSValue specificValue() const { return m_specificValue; } + PropertyOffset offset() const { return m_offset; } + IntendedStructureChain* chain() const { return m_chain.get(); } + +private: + Kind m_kind; + PropertyOffset m_offset; + unsigned m_attributes; + JSValue m_specificValue; + RefPtr<IntendedStructureChain> m_chain; +}; + +} // namespace JSC + +#endif // ComplexGetStatus_h + diff --git a/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp b/bytecode/ConstantStructureCheck.cpp similarity index 51% rename from bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp rename to bytecode/ConstantStructureCheck.cpp index 5d77099..d755c06 100644 --- a/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp +++ b/bytecode/ConstantStructureCheck.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,45 +24,53 @@ */ #include "config.h" -#include "ProfiledCodeBlockJettisoningWatchpoint.h" +#include "ConstantStructureCheck.h" -#if ENABLE(DFG_JIT) - -#include "CodeBlock.h" -#include "DFGCommon.h" -#include "DFGExitProfile.h" #include "JSCInlines.h" namespace JSC { -void ProfiledCodeBlockJettisoningWatchpoint::fireInternal() +void ConstantStructureCheck::dumpInContext(PrintStream& out, DumpContext* context) const +{ + out.print( + "(Check if ", inContext(JSValue(m_constant), context), " has structure ", + pointerDumpInContext(m_structure, context), ")"); +} + +void ConstantStructureCheck::dump(PrintStream& out) const +{ + dumpInContext(out, nullptr); +} + +Structure* structureFor(const ConstantStructureCheckVector& vector, JSCell* constant) { - if (DFG::shouldShowDisassembly()) { - dataLog( - "Firing profiled watchpoint ", RawPointer(this), " on ", *m_codeBlock, " due to ", - m_exitKind, " at ", m_codeOrigin, "\n"); + for (unsigned i = vector.size(); i--;) { + if (vector[i].constant() == constant) + return vector[i].structure(); } - - // FIXME: Maybe this should call alternative(). - // https://bugs.webkit.org/show_bug.cgi?id=123677 - CodeBlock* machineBaselineCodeBlock = m_codeBlock->baselineAlternative(); - CodeBlock* sourceBaselineCodeBlock = - baselineCodeBlockForOriginAndBaselineCodeBlock( - m_codeOrigin, machineBaselineCodeBlock); - - if (sourceBaselineCodeBlock) { - sourceBaselineCodeBlock->addFrequentExitSite( - DFG::FrequentExitSite( - m_codeOrigin.bytecodeIndex, m_exitKind, - exitingJITTypeFor(m_codeBlock->jitType()))); + return nullptr; +} + +bool areCompatible(const ConstantStructureCheckVector& a, const ConstantStructureCheckVector& b) +{ + for (unsigned i = a.size(); i--;) { + Structure* otherStructure = structureFor(b, a[i].constant()); + if (!otherStructure) + continue; + if (a[i].structure() != otherStructure) + return false; + } + return true; +} + +void mergeInto(const ConstantStructureCheckVector& source, ConstantStructureCheckVector& target) +{ + for (unsigned i = source.size(); i--;) { + if (structureFor(target, source[i].constant())) + continue; + target.append(source[i]); } - - m_codeBlock->jettison(Profiler::JettisonDueToProfiledWatchpoint, CountReoptimization); - - if (isOnList()) - remove(); } } // namespace JSC -#endif // ENABLE(DFG_JIT) diff --git a/bytecode/ConstantStructureCheck.h b/bytecode/ConstantStructureCheck.h new file mode 100644 index 0000000..b200c95 --- /dev/null +++ b/bytecode/ConstantStructureCheck.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 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 ConstantStructureCheck_h +#define ConstantStructureCheck_h + +#include "DumpContext.h" +#include "JSCell.h" +#include "Structure.h" +#include <wtf/PrintStream.h> +#include <wtf/Vector.h> + +namespace JSC { + +class ConstantStructureCheck { +public: + ConstantStructureCheck() + : m_constant(nullptr) + , m_structure(nullptr) + { + } + + ConstantStructureCheck(JSCell* constant, Structure* structure) + : m_constant(constant) + , m_structure(structure) + { + ASSERT(!!m_constant == !!m_structure); + } + + bool operator!() const { return !m_constant; } + + JSCell* constant() const { return m_constant; } + Structure* structure() const { return m_structure; } + + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; + +private: + JSCell* m_constant; + Structure* m_structure; +}; + +typedef Vector<ConstantStructureCheck, 2> ConstantStructureCheckVector; + +Structure* structureFor(const ConstantStructureCheckVector& vector, JSCell* constant); +bool areCompatible(const ConstantStructureCheckVector&, const ConstantStructureCheckVector&); +void mergeInto(const ConstantStructureCheckVector& source, ConstantStructureCheckVector& target); + +} // namespace JSC + +#endif // ConstantStructureCheck_h + diff --git a/bytecode/DFGExitProfile.cpp b/bytecode/DFGExitProfile.cpp index 73ba88c..40a25ce 100644 --- a/bytecode/DFGExitProfile.cpp +++ b/bytecode/DFGExitProfile.cpp @@ -28,8 +28,6 @@ #if ENABLE(DFG_JIT) -#include <wtf/PassOwnPtr.h> - namespace JSC { namespace DFG { ExitProfile::ExitProfile() { } @@ -42,7 +40,7 @@ bool ExitProfile::add(const ConcurrentJITLocker&, const FrequentExitSite& site) // If we've never seen any frequent exits then create the list and put this site // into it. if (!m_frequentExitSites) { - m_frequentExitSites = adoptPtr(new Vector<FrequentExitSite>()); + m_frequentExitSites = std::make_unique<Vector<FrequentExitSite>>(); m_frequentExitSites->append(site); return true; } diff --git a/bytecode/DFGExitProfile.h b/bytecode/DFGExitProfile.h index 8e0df41..cdecbaf 100644 --- a/bytecode/DFGExitProfile.h +++ b/bytecode/DFGExitProfile.h @@ -32,7 +32,6 @@ #include "ExitKind.h" #include "ExitingJITType.h" #include <wtf/HashSet.h> -#include <wtf/OwnPtr.h> #include <wtf/Vector.h> namespace JSC { namespace DFG { @@ -183,7 +182,7 @@ public: private: friend class QueryableExitProfile; - OwnPtr<Vector<FrequentExitSite>> m_frequentExitSites; + std::unique_ptr<Vector<FrequentExitSite>> m_frequentExitSites; }; class QueryableExitProfile { diff --git a/bytecode/DataFormat.h b/bytecode/DataFormat.h index bb9da4c..6d7542e 100644 --- a/bytecode/DataFormat.h +++ b/bytecode/DataFormat.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -56,7 +56,6 @@ enum DataFormat { // Special data formats used only for OSR. DataFormatDead = 33, // Implies jsUndefined(). - DataFormatArguments = 34 // Implies that the arguments object must be reified. }; inline const char* dataFormatToString(DataFormat dataFormat) @@ -90,8 +89,6 @@ inline const char* dataFormatToString(DataFormat dataFormat) return "JSBoolean"; case DataFormatDead: return "Dead"; - case DataFormatArguments: - return "Arguments"; default: RELEASE_ASSERT_NOT_REACHED(); return "Unknown"; diff --git a/bytecode/DeferredCompilationCallback.cpp b/bytecode/DeferredCompilationCallback.cpp index 9d5acb9..761e95b 100644 --- a/bytecode/DeferredCompilationCallback.cpp +++ b/bytecode/DeferredCompilationCallback.cpp @@ -35,6 +35,8 @@ DeferredCompilationCallback::~DeferredCompilationCallback() { } void DeferredCompilationCallback::compilationDidComplete(CodeBlock* codeBlock, CompilationResult result) { + dumpCompiledSourcesIfNeeded(); + switch (result) { case CompilationFailed: case CompilationInvalidated: @@ -47,5 +49,25 @@ void DeferredCompilationCallback::compilationDidComplete(CodeBlock* codeBlock, C } } +Vector<DeferredSourceDump>& DeferredCompilationCallback::ensureDeferredSourceDump() +{ + if (!m_deferredSourceDump) + m_deferredSourceDump = std::make_unique<Vector<DeferredSourceDump>>(); + return *m_deferredSourceDump; +} + +void DeferredCompilationCallback::dumpCompiledSourcesIfNeeded() +{ + if (!m_deferredSourceDump) + return; + + ASSERT(Options::dumpSourceAtDFGTime()); + unsigned index = 0; + for (auto& info : *m_deferredSourceDump) { + dataLog("[", ++index, "] "); + info.dump(); + } +} + } // JSC diff --git a/bytecode/DeferredCompilationCallback.h b/bytecode/DeferredCompilationCallback.h index 5d252ca..37568d2 100644 --- a/bytecode/DeferredCompilationCallback.h +++ b/bytecode/DeferredCompilationCallback.h @@ -27,7 +27,9 @@ #define DeferredCompilationCallback_h #include "CompilationResult.h" +#include "DeferredSourceDump.h" #include <wtf/RefCounted.h> +#include <wtf/Vector.h> namespace JSC { @@ -42,6 +44,13 @@ public: virtual void compilationDidBecomeReadyAsynchronously(CodeBlock*) = 0; virtual void compilationDidComplete(CodeBlock*, CompilationResult); + + Vector<DeferredSourceDump>& ensureDeferredSourceDump(); + +private: + void dumpCompiledSourcesIfNeeded(); + + std::unique_ptr<Vector<DeferredSourceDump>> m_deferredSourceDump; }; } // namespace JSC diff --git a/bytecode/DeferredSourceDump.cpp b/bytecode/DeferredSourceDump.cpp new file mode 100644 index 0000000..48079db --- /dev/null +++ b/bytecode/DeferredSourceDump.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 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 "DeferredSourceDump.h" + +#include "CodeBlock.h" +#include "CodeBlockWithJITType.h" + +namespace JSC { + +DeferredSourceDump::DeferredSourceDump(CodeBlock* codeBlock) + : m_codeBlock(codeBlock) + , m_rootCodeBlock(nullptr) + , m_rootJITType(JITCode::None) +{ +} + +DeferredSourceDump::DeferredSourceDump(CodeBlock* codeBlock, CodeBlock* rootCodeBlock, JITCode::JITType rootJITType, CodeOrigin callerCodeOrigin) + : m_codeBlock(codeBlock) + , m_rootCodeBlock(rootCodeBlock) + , m_rootJITType(rootJITType) + , m_callerCodeOrigin(callerCodeOrigin) +{ +} + +void DeferredSourceDump::dump() +{ + bool isInlinedFrame = !!m_rootCodeBlock; + if (isInlinedFrame) + dataLog("Inlined "); + else + dataLog("Compiled "); + dataLog(*m_codeBlock); + + if (isInlinedFrame) + dataLog(" at ", CodeBlockWithJITType(m_rootCodeBlock, m_rootJITType), " ", m_callerCodeOrigin); + + dataLog("\n'''"); + m_codeBlock->dumpSource(); + dataLog("'''\n"); +} + +} // namespace JSC diff --git a/bytecode/DeferredSourceDump.h b/bytecode/DeferredSourceDump.h new file mode 100644 index 0000000..72cb6b3 --- /dev/null +++ b/bytecode/DeferredSourceDump.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 DeferredSourceDump_h +#define DeferredSourceDump_h + +#include "CodeOrigin.h" +#include "JITCode.h" + +namespace JSC { + +class CodeBlock; + +class DeferredSourceDump { +public: + DeferredSourceDump(CodeBlock*); + DeferredSourceDump(CodeBlock*, CodeBlock* rootCodeBlock, JITCode::JITType rootJITType, CodeOrigin callerCodeOrigin); + + void dump(); + +private: + CodeBlock* m_codeBlock; + CodeBlock* m_rootCodeBlock; + JITCode::JITType m_rootJITType; + CodeOrigin m_callerCodeOrigin; +}; + +} // namespace JSC + +#endif // DeferredSourceDump_h diff --git a/bytecode/EvalCodeCache.h b/bytecode/EvalCodeCache.h index 65deb94..b0e5aac 100644 --- a/bytecode/EvalCodeCache.h +++ b/bytecode/EvalCodeCache.h @@ -31,6 +31,7 @@ #include "Executable.h" #include "JSGlobalObject.h" +#include "Options.h" #include "SourceCode.h" #include <wtf/HashMap.h> #include <wtf/RefPtr.h> @@ -44,18 +45,18 @@ namespace JSC { public: EvalExecutable* tryGet(bool inStrictContext, const String& evalSource, JSScope* scope) { - if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && scope->begin()->isVariableObject()) + if (!inStrictContext && evalSource.length() < Options::maximumEvalCacheableSourceLength() && scope->begin()->isVariableObject()) return m_cacheMap.get(evalSource.impl()).get(); return 0; } - EvalExecutable* getSlow(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const String& evalSource, JSScope* scope) + EvalExecutable* getSlow(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const String& evalSource, JSScope* scope) { - EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext); + EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext, thisTDZMode); if (!evalExecutable) return 0; - if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && scope->begin()->isVariableObject() && m_cacheMap.size() < maxCacheEntries) + if (!inStrictContext && evalSource.length() < Options::maximumEvalCacheableSourceLength() && scope->begin()->isVariableObject() && m_cacheMap.size() < maxCacheEntries) m_cacheMap.set(evalSource.impl(), WriteBarrier<EvalExecutable>(exec->vm(), owner, evalExecutable)); return evalExecutable; @@ -71,7 +72,6 @@ namespace JSC { } private: - static const unsigned maxCacheableSourceLength = 256; static const int maxCacheEntries = 64; typedef HashMap<RefPtr<StringImpl>, WriteBarrier<EvalExecutable>> EvalCacheMap; diff --git a/bytecode/ExecutionCounter.cpp b/bytecode/ExecutionCounter.cpp index bacb49e..fe4e430 100644 --- a/bytecode/ExecutionCounter.cpp +++ b/bytecode/ExecutionCounter.cpp @@ -136,8 +136,6 @@ bool ExecutionCounter<countingVariant>::setThreshold(CodeBlock* codeBlock) return false; } - ASSERT(!m_activeThreshold || !hasCrossedThreshold(codeBlock)); - // Compute the true total count. double trueTotalCount = count(); diff --git a/bytecode/ExecutionCounter.h b/bytecode/ExecutionCounter.h index c6dab9c..5002c6c 100644 --- a/bytecode/ExecutionCounter.h +++ b/bytecode/ExecutionCounter.h @@ -110,7 +110,7 @@ public: // m_counter. float m_totalCount; - // This is the threshold we were originally targetting, without any correction for + // This is the threshold we were originally targeting, without any correction for // the memory usage heuristics. int32_t m_activeThreshold; }; diff --git a/bytecode/ExitKind.cpp b/bytecode/ExitKind.cpp index 350aa58..4f79f2c 100644 --- a/bytecode/ExitKind.cpp +++ b/bytecode/ExitKind.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,18 +38,14 @@ const char* exitKindToString(ExitKind kind) return "Unset"; case BadType: return "BadType"; - case BadFunction: - return "BadFunction"; + case BadCell: + return "BadCell"; case BadExecutable: return "BadExecutable"; case BadCache: return "BadCache"; - case BadCacheWatchpoint: - return "BadCacheWatchpoint"; - case BadWeakConstantCache: - return "BadWeakConstantCache"; - case BadWeakConstantCacheWatchpoint: - return "BadWeakConstantCacheWatchpoint"; + case BadConstantCache: + return "BadConstantCache"; case BadIndexingType: return "BadIndexingType"; case Overflow: @@ -68,12 +64,16 @@ const char* exitKindToString(ExitKind kind) return "InadequateCoverage"; case ArgumentsEscaped: return "ArgumentsEscaped"; + case ExoticObjectMode: + return "ExoticObjectMode"; case NotStringObject: return "NotStringObject"; + case VarargsOverflow: + return "VarargsOverflow"; + case TDZFailure: + return "TDZFailure"; case Uncountable: return "Uncountable"; - case UncountableWatchpoint: - return "UncountableWatchpoint"; case UncountableInvalidation: return "UncountableInvalidation"; case WatchdogTimerFired: @@ -92,7 +92,6 @@ bool exitKindIsCountable(ExitKind kind) RELEASE_ASSERT_NOT_REACHED(); case BadType: case Uncountable: - case UncountableWatchpoint: case LoadFromHole: // Already counted directly by the baseline JIT. case StoreToHole: // Already counted directly by the baseline JIT. case OutOfBounds: // Already counted directly by the baseline JIT. diff --git a/bytecode/ExitKind.h b/bytecode/ExitKind.h index 6ac78a2..59cbbf5 100644 --- a/bytecode/ExitKind.h +++ b/bytecode/ExitKind.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 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,12 +31,10 @@ namespace JSC { enum ExitKind : uint8_t { ExitKindUnset, BadType, // We exited because a type prediction was wrong. - BadFunction, // We exited because we made an incorrect assumption about what function we would see. + BadCell, // We exited because we made an incorrect assumption about what cell we would see. Usually used for function checks. BadExecutable, // We exited because we made an incorrect assumption about what executable we would see. BadCache, // We exited because an inline cache was wrong. - BadWeakConstantCache, // We exited because a cache on a weak constant (usually a prototype) was wrong. - BadCacheWatchpoint, // Same as BadCache but from a watchpoint. - BadWeakConstantCacheWatchpoint, // Same as BadWeakConstantCache but from a watchpoint. + BadConstantCache, // We exited because a cache on a weak constant (usually a prototype) was wrong. BadIndexingType, // We exited because an indexing type was wrong. Overflow, // We exited because of overflow. NegativeZero, // We exited because we encountered negative zero. @@ -46,10 +44,12 @@ enum ExitKind : uint8_t { OutOfBounds, // We had an out-of-bounds access to an array. InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage. ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to. + ExoticObjectMode, // We exited because some exotic object that we were accessing was in an exotic mode (like Arguments with slow arguments). NotStringObject, // We exited because we shouldn't have attempted to optimize string object access. + VarargsOverflow, // We exited because a varargs call passed more arguments than we expected. + TDZFailure, // We exited because we were in the TDZ and accessed the variable. Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME. UncountableInvalidation, // We exited because the code block was invalidated; this means that we've already counted the reasons why the code block was invalidated. - UncountableWatchpoint, // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves. WatchdogTimerFired, // We exited because we need to service the watchdog timer. DebuggerEvent // We exited because we need to service the debugger. }; @@ -57,18 +57,6 @@ enum ExitKind : uint8_t { const char* exitKindToString(ExitKind); bool exitKindIsCountable(ExitKind); -inline bool isWatchpoint(ExitKind kind) -{ - switch (kind) { - case BadCacheWatchpoint: - case BadWeakConstantCacheWatchpoint: - case UncountableWatchpoint: - return true; - default: - return false; - } -} - } // namespace JSC namespace WTF { diff --git a/bytecode/FullBytecodeLiveness.h b/bytecode/FullBytecodeLiveness.h index d343921..864af75 100644 --- a/bytecode/FullBytecodeLiveness.h +++ b/bytecode/FullBytecodeLiveness.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,32 +36,20 @@ typedef HashMap<unsigned, FastBitVector, WTF::IntHash<unsigned>, WTF::UnsignedWi class FullBytecodeLiveness { public: - FullBytecodeLiveness() : m_codeBlock(0) { } - - // We say "out" to refer to the bitvector that contains raw results for a bytecode - // instruction. - const FastBitVector& getOut(unsigned bytecodeIndex) const + const FastBitVector& getLiveness(unsigned bytecodeIndex) const { - BytecodeToBitmapMap::const_iterator iter = m_map.find(bytecodeIndex); - ASSERT(iter != m_map.end()); - return iter->value; + return m_map[bytecodeIndex]; } bool operandIsLive(int operand, unsigned bytecodeIndex) const { - return operandIsAlwaysLive(m_codeBlock, operand) || operandThatIsNotAlwaysLiveIsLive(m_codeBlock, getOut(bytecodeIndex), operand); - } - - FastBitVector getLiveness(unsigned bytecodeIndex) const - { - return getLivenessInfo(m_codeBlock, getOut(bytecodeIndex)); + return operandIsAlwaysLive(operand) || operandThatIsNotAlwaysLiveIsLive(getLiveness(bytecodeIndex), operand); } private: friend class BytecodeLivenessAnalysis; - CodeBlock* m_codeBlock; - BytecodeToBitmapMap m_map; + Vector<FastBitVector, 0, UnsafeVectorOverflow> m_map; }; } // namespace JSC diff --git a/bytecode/GetByIdStatus.cpp b/bytecode/GetByIdStatus.cpp index 235cdbd..7afaf92 100644 --- a/bytecode/GetByIdStatus.cpp +++ b/bytecode/GetByIdStatus.cpp @@ -26,7 +26,9 @@ #include "config.h" #include "GetByIdStatus.h" +#include "AccessorCallJITStubRoutine.h" #include "CodeBlock.h" +#include "ComplexGetStatus.h" #include "JSCInlines.h" #include "JSScope.h" #include "LLIntData.h" @@ -38,25 +40,33 @@ namespace JSC { bool GetByIdStatus::appendVariant(const GetByIdVariant& variant) { + // Attempt to merge this variant with an already existing variant. + for (unsigned i = 0; i < m_variants.size(); ++i) { + if (m_variants[i].attemptToMerge(variant)) + return true; + } + + // Make sure there is no overlap. We should have pruned out opportunities for + // overlap but it's possible that an inline cache got into a weird state. We are + // defensive and bail if we detect crazy. for (unsigned i = 0; i < m_variants.size(); ++i) { if (m_variants[i].structureSet().overlaps(variant.structureSet())) return false; } + m_variants.append(variant); return true; } #if ENABLE(DFG_JIT) -bool GetByIdStatus::hasExitSite(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex, ExitingJITType jitType) +bool GetByIdStatus::hasExitSite(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex) { - return profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache, jitType)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCacheWatchpoint, jitType)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadWeakConstantCache, jitType)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadWeakConstantCacheWatchpoint, jitType)); + return profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) + || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache)); } #endif -GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, StringImpl* uid) +GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, UniquedStringImpl* uid) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); @@ -74,69 +84,14 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned return GetByIdStatus(NoInformation, false); unsigned attributesIgnored; - JSCell* specificValue; - PropertyOffset offset = structure->getConcurrently( - *profiledBlock->vm(), uid, attributesIgnored, specificValue); - if (structure->isDictionary()) - specificValue = 0; + PropertyOffset offset = structure->getConcurrently(uid, attributesIgnored); if (!isValidOffset(offset)) return GetByIdStatus(NoInformation, false); - return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue)); -} - -bool GetByIdStatus::computeForChain(CodeBlock* profiledBlock, StringImpl* uid, PassRefPtr<IntendedStructureChain> passedChain) -{ -#if ENABLE(JIT) - RefPtr<IntendedStructureChain> chain = passedChain; - - // Validate the chain. If the chain is invalid, then currently the best thing - // we can do is to assume that TakesSlow is true. In the future, it might be - // worth exploring reifying the structure chain from the structure we've got - // instead of using the one from the cache, since that will do the right things - // if the structure chain has changed. But that may be harder, because we may - // then end up having a different type of access altogether. And it currently - // does not appear to be worth it to do so -- effectively, the heuristic we - // have now is that if the structure chain has changed between when it was - // cached on in the baseline JIT and when the DFG tried to inline the access, - // then we fall back on a polymorphic access. - if (!chain->isStillValid()) - return false; - - if (chain->head()->takesSlowPathInDFGForImpureProperty()) - return false; - size_t chainSize = chain->size(); - for (size_t i = 0; i < chainSize; i++) { - if (chain->at(i)->takesSlowPathInDFGForImpureProperty()) - return false; - } - - JSObject* currentObject = chain->terminalPrototype(); - Structure* currentStructure = chain->last(); - - ASSERT_UNUSED(currentObject, currentObject); - - unsigned attributesIgnored; - JSCell* specificValue; - - PropertyOffset offset = currentStructure->getConcurrently( - *profiledBlock->vm(), uid, attributesIgnored, specificValue); - if (currentStructure->isDictionary()) - specificValue = 0; - if (!isValidOffset(offset)) - return false; - - return appendVariant(GetByIdVariant(StructureSet(chain->head()), offset, specificValue, chain)); -#else // ENABLE(JIT) - UNUSED_PARAM(profiledBlock); - UNUSED_PARAM(uid); - UNUSED_PARAM(passedChain); - UNREACHABLE_FOR_PLATFORM(); - return false; -#endif // ENABLE(JIT) + return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset)); } -GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, StringImpl* uid) +GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid) { ConcurrentJITLocker locker(profiledBlock->m_lock); @@ -144,12 +99,12 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m #if ENABLE(DFG_JIT) result = computeForStubInfo( - locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid); + locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid, + CallLinkStatus::computeExitSiteData(locker, profiledBlock, bytecodeIndex)); if (!result.takesSlowPath() - && (hasExitSite(locker, profiledBlock, bytecodeIndex) - || profiledBlock->likelyToTakeSlowCase(bytecodeIndex))) - return GetByIdStatus(TakesSlowPath, true); + && hasExitSite(locker, profiledBlock, bytecodeIndex)) + return GetByIdStatus(result.makesCalls() ? MakesCalls : TakesSlowPath, true); #else UNUSED_PARAM(map); #endif @@ -162,37 +117,29 @@ GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m #if ENABLE(JIT) GetByIdStatus GetByIdStatus::computeForStubInfo( - const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, - StringImpl* uid) + const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, UniquedStringImpl* uid, + CallLinkStatus::ExitSiteData callExitSiteData) { - if (!stubInfo || !stubInfo->seen) + if (!stubInfo) + return GetByIdStatus(NoInformation); + + if (!stubInfo->seen) return GetByIdStatus(NoInformation); - if (stubInfo->resetByGC) - return GetByIdStatus(TakesSlowPath, true); - PolymorphicGetByIdList* list = 0; + State slowPathState = TakesSlowPath; if (stubInfo->accessType == access_get_by_id_list) { list = stubInfo->u.getByIdList.list; - bool makesCalls = false; - bool isWatched = false; for (unsigned i = 0; i < list->size(); ++i) { const GetByIdAccess& access = list->at(i); - if (access.doesCalls()) { - makesCalls = true; - break; - } - if (access.isWatched()) { - isWatched = true; - continue; - } + if (access.doesCalls()) + slowPathState = MakesCalls; } - if (makesCalls) - return GetByIdStatus(MakesCalls, true); - if (isWatched) - return GetByIdStatus(TakesSlowPath, true); } + if (stubInfo->tookSlowPath) + return GetByIdStatus(slowPathState); + // Finally figure out if we can derive an access strategy. GetByIdStatus result; result.m_state = Simple; @@ -204,103 +151,75 @@ GetByIdStatus GetByIdStatus::computeForStubInfo( case access_get_by_id_self: { Structure* structure = stubInfo->u.getByIdSelf.baseObjectStructure.get(); if (structure->takesSlowPathInDFGForImpureProperty()) - return GetByIdStatus(TakesSlowPath, true); + return GetByIdStatus(slowPathState, true); unsigned attributesIgnored; - JSCell* specificValue; GetByIdVariant variant; - variant.m_offset = structure->getConcurrently( - *profiledBlock->vm(), uid, attributesIgnored, specificValue); + variant.m_offset = structure->getConcurrently(uid, attributesIgnored); if (!isValidOffset(variant.m_offset)) - return GetByIdStatus(TakesSlowPath, true); - - if (structure->isDictionary()) - specificValue = 0; + return GetByIdStatus(slowPathState, true); variant.m_structureSet.add(structure); - variant.m_specificValue = JSValue(specificValue); - result.appendVariant(variant); + bool didAppend = result.appendVariant(variant); + ASSERT_UNUSED(didAppend, didAppend); return result; } case access_get_by_id_list: { for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) { - ASSERT(list->at(listIndex).isSimple()); - Structure* structure = list->at(listIndex).structure(); - // FIXME: We should assert that we never see a structure that - // hasImpureGetOwnPropertySlot() but for which we don't - // newImpurePropertyFiresWatchpoints(). We're not at a point where we can do - // that, yet. - // https://bugs.webkit.org/show_bug.cgi?id=131810 - - if (structure->takesSlowPathInDFGForImpureProperty()) - return GetByIdStatus(TakesSlowPath, true); - - if (list->at(listIndex).chain()) { - RefPtr<IntendedStructureChain> chain = adoptRef(new IntendedStructureChain( - profiledBlock, structure, list->at(listIndex).chain(), - list->at(listIndex).chainCount())); - if (!result.computeForChain(profiledBlock, uid, chain)) - return GetByIdStatus(TakesSlowPath, true); + ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor( + profiledBlock, structure, list->at(listIndex).chain(), + list->at(listIndex).chainCount(), uid); + + switch (complexGetStatus.kind()) { + case ComplexGetStatus::ShouldSkip: continue; - } - - unsigned attributesIgnored; - JSCell* specificValue; - PropertyOffset myOffset = structure->getConcurrently( - *profiledBlock->vm(), uid, attributesIgnored, specificValue); - if (structure->isDictionary()) - specificValue = 0; - - if (!isValidOffset(myOffset)) - return GetByIdStatus(TakesSlowPath, true); - - bool found = false; - for (unsigned variantIndex = 0; variantIndex < result.m_variants.size(); ++variantIndex) { - GetByIdVariant& variant = result.m_variants[variantIndex]; - if (variant.m_chain) - continue; - - if (variant.m_offset != myOffset) - continue; - - found = true; - if (variant.m_structureSet.contains(structure)) + + case ComplexGetStatus::TakesSlowPath: + return GetByIdStatus(slowPathState, true); + + case ComplexGetStatus::Inlineable: { + std::unique_ptr<CallLinkStatus> callLinkStatus; + switch (list->at(listIndex).type()) { + case GetByIdAccess::SimpleInline: + case GetByIdAccess::SimpleStub: { + break; + } + case GetByIdAccess::Getter: { + AccessorCallJITStubRoutine* stub = static_cast<AccessorCallJITStubRoutine*>( + list->at(listIndex).stubRoutine()); + callLinkStatus = std::make_unique<CallLinkStatus>( + CallLinkStatus::computeFor( + locker, profiledBlock, *stub->m_callLinkInfo, callExitSiteData)); break; - - if (variant.m_specificValue != JSValue(specificValue)) - variant.m_specificValue = JSValue(); - - variant.m_structureSet.add(structure); + } + case GetByIdAccess::SimpleMiss: + case GetByIdAccess::CustomGetter: + case GetByIdAccess::WatchedStub:{ + // FIXME: It would be totally sweet to support this at some point in the future. + // https://bugs.webkit.org/show_bug.cgi?id=133052 + return GetByIdStatus(slowPathState, true); + } + default: + RELEASE_ASSERT_NOT_REACHED(); + } + + GetByIdVariant variant( + StructureSet(structure), complexGetStatus.offset(), complexGetStatus.chain(), + WTF::move(callLinkStatus)); + + if (!result.appendVariant(variant)) + return GetByIdStatus(slowPathState, true); break; - } - - if (found) - continue; - - if (!result.appendVariant(GetByIdVariant(StructureSet(structure), myOffset, specificValue))) - return GetByIdStatus(TakesSlowPath, true); + } } } return result; } - case access_get_by_id_chain: { - if (!stubInfo->u.getByIdChain.isDirect) - return GetByIdStatus(MakesCalls, true); - RefPtr<IntendedStructureChain> chain = adoptRef(new IntendedStructureChain( - profiledBlock, - stubInfo->u.getByIdChain.baseObjectStructure.get(), - stubInfo->u.getByIdChain.chain.get(), - stubInfo->u.getByIdChain.count)); - if (result.computeForChain(profiledBlock, uid, chain)) - return result; - return GetByIdStatus(TakesSlowPath, true); - } - default: - return GetByIdStatus(TakesSlowPath, true); + return GetByIdStatus(slowPathState, true); } RELEASE_ASSERT_NOT_REACHED(); @@ -310,14 +229,22 @@ GetByIdStatus GetByIdStatus::computeForStubInfo( GetByIdStatus GetByIdStatus::computeFor( CodeBlock* profiledBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, - StubInfoMap& dfgMap, CodeOrigin codeOrigin, StringImpl* uid) + StubInfoMap& dfgMap, CodeOrigin codeOrigin, UniquedStringImpl* uid) { #if ENABLE(DFG_JIT) if (dfgBlock) { + CallLinkStatus::ExitSiteData exitSiteData; + { + ConcurrentJITLocker locker(profiledBlock->m_lock); + exitSiteData = CallLinkStatus::computeExitSiteData( + locker, profiledBlock, codeOrigin.bytecodeIndex); + } + GetByIdStatus result; { ConcurrentJITLocker locker(dfgBlock->m_lock); - result = computeForStubInfo(locker, dfgBlock, dfgMap.get(codeOrigin), uid); + result = computeForStubInfo( + locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData); } if (result.takesSlowPath()) @@ -325,7 +252,7 @@ GetByIdStatus GetByIdStatus::computeFor( { ConcurrentJITLocker locker(profiledBlock->m_lock); - if (hasExitSite(locker, profiledBlock, codeOrigin.bytecodeIndex, ExitFromFTL)) + if (hasExitSite(locker, profiledBlock, codeOrigin.bytecodeIndex)) return GetByIdStatus(TakesSlowPath, true); } @@ -340,34 +267,60 @@ GetByIdStatus GetByIdStatus::computeFor( return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid); } -GetByIdStatus GetByIdStatus::computeFor(VM& vm, Structure* structure, StringImpl* uid) +GetByIdStatus GetByIdStatus::computeFor(const StructureSet& set, UniquedStringImpl* uid) { // For now we only handle the super simple self access case. We could handle the // prototype case in the future. - if (!structure) - return GetByIdStatus(TakesSlowPath); + if (set.isEmpty()) + return GetByIdStatus(); - if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex) + if (parseIndex(*uid)) return GetByIdStatus(TakesSlowPath); - if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType) - return GetByIdStatus(TakesSlowPath); + GetByIdStatus result; + result.m_state = Simple; + result.m_wasSeenInJIT = false; + for (unsigned i = 0; i < set.size(); ++i) { + Structure* structure = set[i]; + if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType) + return GetByIdStatus(TakesSlowPath); + + if (!structure->propertyAccessesAreCacheable()) + return GetByIdStatus(TakesSlowPath); + + unsigned attributes; + PropertyOffset offset = structure->getConcurrently(uid, attributes); + if (!isValidOffset(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); // We could be smarter here, like strenght-reducing this to a Call. + + if (!result.appendVariant(GetByIdVariant(structure, offset))) + return GetByIdStatus(TakesSlowPath); + } - if (!structure->propertyAccessesAreCacheable()) - return GetByIdStatus(TakesSlowPath); + return result; +} - unsigned attributes; - JSCell* specificValue; - PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue); - if (!isValidOffset(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; - return GetByIdStatus( - Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue)); +bool GetByIdStatus::makesCalls() const +{ + switch (m_state) { + case NoInformation: + case TakesSlowPath: + return false; + case Simple: + for (unsigned i = m_variants.size(); i--;) { + if (m_variants[i].callLinkStatus()) + return true; + } + return false; + case MakesCalls: + return true; + } + RELEASE_ASSERT_NOT_REACHED(); + + return false; } void GetByIdStatus::dump(PrintStream& out) const diff --git a/bytecode/GetByIdStatus.h b/bytecode/GetByIdStatus.h index c350e2c..32372cd 100644 --- a/bytecode/GetByIdStatus.h +++ b/bytecode/GetByIdStatus.h @@ -26,6 +26,7 @@ #ifndef GetByIdStatus_h #define GetByIdStatus_h +#include "CallLinkStatus.h" #include "CodeOrigin.h" #include "ConcurrentJITLock.h" #include "ExitingJITType.h" @@ -66,10 +67,10 @@ public: m_variants.append(variant); } - static GetByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, StringImpl* uid); - static GetByIdStatus computeFor(VM&, Structure*, StringImpl* uid); + static GetByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, UniquedStringImpl* uid); + static GetByIdStatus computeFor(const StructureSet&, UniquedStringImpl* uid); - static GetByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, StringImpl* uid); + static GetByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, UniquedStringImpl* uid); State state() const { return m_state; } @@ -83,7 +84,7 @@ public: const GetByIdVariant& operator[](size_t index) const { return at(index); } bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } - bool makesCalls() const { return m_state == MakesCalls; } + bool makesCalls() const; bool wasSeenInJIT() const { return m_wasSeenInJIT; } @@ -91,13 +92,14 @@ public: private: #if ENABLE(DFG_JIT) - static bool hasExitSite(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex, ExitingJITType = ExitFromAnything); + static bool hasExitSite(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex); #endif #if ENABLE(JIT) - static GetByIdStatus computeForStubInfo(const ConcurrentJITLocker&, CodeBlock*, StructureStubInfo*, StringImpl* uid); + static GetByIdStatus computeForStubInfo( + const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo*, + UniquedStringImpl* uid, CallLinkStatus::ExitSiteData); #endif - bool computeForChain(CodeBlock*, StringImpl* uid, PassRefPtr<IntendedStructureChain>); - static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid); + static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, UniquedStringImpl* uid); bool appendVariant(const GetByIdVariant&); diff --git a/bytecode/GetByIdVariant.cpp b/bytecode/GetByIdVariant.cpp index b8bedce..dd8e8df 100644 --- a/bytecode/GetByIdVariant.cpp +++ b/bytecode/GetByIdVariant.cpp @@ -26,10 +26,79 @@ #include "config.h" #include "GetByIdVariant.h" +#include "CallLinkStatus.h" #include "JSCInlines.h" +#include <wtf/ListDump.h> namespace JSC { +GetByIdVariant::GetByIdVariant( + const StructureSet& structureSet, PropertyOffset offset, + const IntendedStructureChain* chain, std::unique_ptr<CallLinkStatus> callLinkStatus) + : m_structureSet(structureSet) + , m_alternateBase(nullptr) + , m_offset(offset) + , m_callLinkStatus(WTF::move(callLinkStatus)) +{ + if (!structureSet.size()) { + ASSERT(offset == invalidOffset); + ASSERT(!chain); + } + + if (chain && chain->size()) { + m_alternateBase = chain->terminalPrototype(); + chain->gatherChecks(m_constantChecks); + } +} + +GetByIdVariant::~GetByIdVariant() { } + +GetByIdVariant::GetByIdVariant(const GetByIdVariant& other) + : GetByIdVariant() +{ + *this = other; +} + +GetByIdVariant& GetByIdVariant::operator=(const GetByIdVariant& other) +{ + m_structureSet = other.m_structureSet; + m_constantChecks = other.m_constantChecks; + m_alternateBase = other.m_alternateBase; + m_offset = other.m_offset; + if (other.m_callLinkStatus) + m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus); + else + m_callLinkStatus = nullptr; + return *this; +} + +StructureSet GetByIdVariant::baseStructure() const +{ + if (!m_alternateBase) + return structureSet(); + + Structure* structure = structureFor(m_constantChecks, m_alternateBase); + RELEASE_ASSERT(structure); + return structure; +} + +bool GetByIdVariant::attemptToMerge(const GetByIdVariant& other) +{ + if (m_alternateBase != other.m_alternateBase) + return false; + if (m_offset != other.m_offset) + return false; + if (m_callLinkStatus || other.m_callLinkStatus) + return false; + if (!areCompatible(m_constantChecks, other.m_constantChecks)) + return false; + + mergeInto(other.m_constantChecks, m_constantChecks); + m_structureSet.merge(other.m_structureSet); + + return true; +} + void GetByIdVariant::dump(PrintStream& out) const { dumpInContext(out, 0); @@ -44,8 +113,13 @@ void GetByIdVariant::dumpInContext(PrintStream& out, DumpContext* context) const out.print( "<", inContext(structureSet(), context), ", ", - pointerDumpInContext(chain(), context), ", ", - inContext(specificValue(), context), ", ", offset(), ">"); + "[", listDumpInContext(m_constantChecks, context), "]"); + if (m_alternateBase) + out.print(", alternateBase = ", inContext(JSValue(m_alternateBase), context)); + out.print(", offset = ", offset()); + if (m_callLinkStatus) + out.print(", call = ", *m_callLinkStatus); + out.print(">"); } } // namespace JSC diff --git a/bytecode/GetByIdVariant.h b/bytecode/GetByIdVariant.h index f0201ee..8d1ade1 100644 --- a/bytecode/GetByIdVariant.h +++ b/bytecode/GetByIdVariant.h @@ -26,6 +26,8 @@ #ifndef GetByIdVariant_h #define GetByIdVariant_h +#include "CallLinkStatus.h" +#include "ConstantStructureCheck.h" #include "IntendedStructureChain.h" #include "JSCJSValue.h" #include "PropertyOffset.h" @@ -33,33 +35,33 @@ namespace JSC { +class CallLinkStatus; class GetByIdStatus; struct DumpContext; class GetByIdVariant { public: GetByIdVariant( - const StructureSet& structureSet = StructureSet(), - PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(), - PassRefPtr<IntendedStructureChain> chain = nullptr) - : m_structureSet(structureSet) - , m_chain(chain) - , m_specificValue(specificValue) - , m_offset(offset) - { - if (!structureSet.size()) { - ASSERT(offset == invalidOffset); - ASSERT(!specificValue); - ASSERT(!chain); - } - } + const StructureSet& structureSet = StructureSet(), PropertyOffset offset = invalidOffset, + const IntendedStructureChain* chain = nullptr, + std::unique_ptr<CallLinkStatus> callLinkStatus = nullptr); + + ~GetByIdVariant(); + + GetByIdVariant(const GetByIdVariant&); + GetByIdVariant& operator=(const GetByIdVariant&); bool isSet() const { return !!m_structureSet.size(); } bool operator!() const { return !isSet(); } const StructureSet& structureSet() const { return m_structureSet; } - IntendedStructureChain* chain() const { return const_cast<IntendedStructureChain*>(m_chain.get()); } - JSValue specificValue() const { return m_specificValue; } + StructureSet& structureSet() { return m_structureSet; } + const ConstantStructureCheckVector& constantChecks() const { return m_constantChecks; } + JSObject* alternateBase() const { return m_alternateBase; } + StructureSet baseStructure() const; PropertyOffset offset() const { return m_offset; } + CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); } + + bool attemptToMerge(const GetByIdVariant& other); void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; @@ -68,9 +70,10 @@ private: friend class GetByIdStatus; StructureSet m_structureSet; - RefPtr<IntendedStructureChain> m_chain; - JSValue m_specificValue; + ConstantStructureCheckVector m_constantChecks; + JSObject* m_alternateBase; PropertyOffset m_offset; + std::unique_ptr<CallLinkStatus> m_callLinkStatus; }; } // namespace JSC diff --git a/bytecode/HandlerInfo.h b/bytecode/HandlerInfo.h index ec075e7..cae7ed9 100644 --- a/bytecode/HandlerInfo.h +++ b/bytecode/HandlerInfo.h @@ -30,12 +30,70 @@ namespace JSC { -struct HandlerInfo { +enum class HandlerType { + Illegal = 0, + Catch = 1, + Finally = 2, + SynthesizedFinally = 3 +}; + +struct HandlerInfoBase { + HandlerType type() const { return static_cast<HandlerType>(typeBits); } + void setType(HandlerType type) { typeBits = static_cast<uint32_t>(type); } + + const char* typeName() + { + switch (type()) { + case HandlerType::Catch: + return "catch"; + case HandlerType::Finally: + return "finally"; + case HandlerType::SynthesizedFinally: + return "synthesized finally"; + default: + ASSERT_NOT_REACHED(); + } + return nullptr; + } + + bool isCatchHandler() const { return type() == HandlerType::Catch; } + uint32_t start; uint32_t end; uint32_t target; - uint32_t scopeDepth; + uint32_t scopeDepth : 30; + uint32_t typeBits : 2; // HandlerType +}; + +struct UnlinkedHandlerInfo : public HandlerInfoBase { + UnlinkedHandlerInfo(uint32_t start, uint32_t end, uint32_t target, uint32_t scopeDepth, HandlerType handlerType) + { + this->start = start; + this->end = end; + this->target = target; + this->scopeDepth = scopeDepth; + setType(handlerType); + ASSERT(type() == handlerType); + } +}; + +struct HandlerInfo : public HandlerInfoBase { + void initialize(const UnlinkedHandlerInfo& unlinkedInfo, size_t nonLocalScopeDepth) + { + start = unlinkedInfo.start; + end = unlinkedInfo.end; + target = unlinkedInfo.target; + scopeDepth = unlinkedInfo.scopeDepth + nonLocalScopeDepth; + typeBits = unlinkedInfo.typeBits; + } + #if ENABLE(JIT) + void initialize(const UnlinkedHandlerInfo& unlinkedInfo, size_t nonLocalScopeDepth, CodeLocationLabel label) + { + initialize(unlinkedInfo, nonLocalScopeDepth); + nativeCode = label; + } + CodeLocationLabel nativeCode; #endif }; diff --git a/bytecode/Instruction.h b/bytecode/Instruction.h index ca45775..c20a4f7 100644 --- a/bytecode/Instruction.h +++ b/bytecode/Instruction.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,12 +29,16 @@ #ifndef Instruction_h #define Instruction_h +#include "BasicBlockLocation.h" #include "MacroAssembler.h" #include "Opcode.h" +#include "SymbolTable.h" +#include "TypeLocation.h" #include "PropertySlot.h" #include "SpecialPointer.h" #include "Structure.h" #include "StructureChain.h" +#include "ToThisStatus.h" #include "VirtualRegister.h" #include <wtf/VectorTraits.h> @@ -43,7 +47,7 @@ namespace JSC { class ArrayAllocationProfile; class ArrayProfile; class ObjectAllocationProfile; -class VariableWatchpointSet; +class WatchpointSet; struct LLIntCallLinkInfo; struct ValueProfile; @@ -94,30 +98,33 @@ struct Instruction { Instruction(ArrayProfile* profile) { u.arrayProfile = profile; } Instruction(ArrayAllocationProfile* profile) { u.arrayAllocationProfile = profile; } Instruction(ObjectAllocationProfile* profile) { u.objectAllocationProfile = profile; } - Instruction(WriteBarrier<Unknown>* registerPointer) { u.registerPointer = registerPointer; } + Instruction(WriteBarrier<Unknown>* variablePointer) { u.variablePointer = variablePointer; } Instruction(Special::Pointer pointer) { u.specialPointer = pointer; } - Instruction(StringImpl* uid) { u.uid = uid; } + Instruction(UniquedStringImpl* uid) { u.uid = uid; } Instruction(bool* predicatePointer) { u.predicatePointer = predicatePointer; } union { Opcode opcode; int operand; WriteBarrierBase<Structure> structure; + WriteBarrierBase<SymbolTable> symbolTable; WriteBarrierBase<StructureChain> structureChain; WriteBarrierBase<JSCell> jsCell; - WriteBarrier<Unknown>* registerPointer; + WriteBarrier<Unknown>* variablePointer; Special::Pointer specialPointer; PropertySlot::GetValueFunc getterFunc; LLIntCallLinkInfo* callLinkInfo; - StringImpl* uid; + UniquedStringImpl* uid; ValueProfile* profile; ArrayProfile* arrayProfile; ArrayAllocationProfile* arrayAllocationProfile; ObjectAllocationProfile* objectAllocationProfile; - VariableWatchpointSet* watchpointSet; - WriteBarrierBase<JSActivation> activation; + WatchpointSet* watchpointSet; void* pointer; bool* predicatePointer; + ToThisStatus toThisStatus; + TypeLocation* location; + BasicBlockLocation* basicBlockLocation; } u; private: diff --git a/bytecode/LLIntCallLinkInfo.h b/bytecode/LLIntCallLinkInfo.h index bfb9510..2645dd5 100644 --- a/bytecode/LLIntCallLinkInfo.h +++ b/bytecode/LLIntCallLinkInfo.h @@ -45,7 +45,7 @@ struct LLIntCallLinkInfo : public BasicRawSentinelNode<LLIntCallLinkInfo> { remove(); } - bool isLinked() { return callee; } + bool isLinked() { return !!callee; } void unlink() { diff --git a/bytecode/LazyOperandValueProfile.cpp b/bytecode/LazyOperandValueProfile.cpp index e58420e..de654db 100644 --- a/bytecode/LazyOperandValueProfile.cpp +++ b/bytecode/LazyOperandValueProfile.cpp @@ -46,7 +46,7 @@ LazyOperandValueProfile* CompressedLazyOperandValueProfileHolder::add( const ConcurrentJITLocker&, const LazyOperandValueProfileKey& key) { if (!m_data) - m_data = adoptPtr(new LazyOperandValueProfile::List()); + m_data = std::make_unique<LazyOperandValueProfile::List>(); else { for (unsigned i = 0; i < m_data->size(); ++i) { if (m_data->at(i).key() == key) diff --git a/bytecode/LazyOperandValueProfile.h b/bytecode/LazyOperandValueProfile.h index 95ef941..74e4f33 100644 --- a/bytecode/LazyOperandValueProfile.h +++ b/bytecode/LazyOperandValueProfile.h @@ -31,7 +31,6 @@ #include "VirtualRegister.h" #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> #include <wtf/SegmentedVector.h> namespace JSC { @@ -161,7 +160,7 @@ public: private: friend class LazyOperandValueProfileParser; - OwnPtr<LazyOperandValueProfile::List> m_data; + std::unique_ptr<LazyOperandValueProfile::List> m_data; }; class LazyOperandValueProfileParser { diff --git a/bytecode/ObjectAllocationProfile.h b/bytecode/ObjectAllocationProfile.h index 9a9db0b..cb4148e 100644 --- a/bytecode/ObjectAllocationProfile.h +++ b/bytecode/ObjectAllocationProfile.h @@ -89,13 +89,23 @@ public: if (inlineCapacity > JSFinalObject::maxInlineCapacity()) inlineCapacity = JSFinalObject::maxInlineCapacity(); + Structure* structure = vm.prototypeMap.emptyObjectStructureForPrototype(prototype, inlineCapacity); + + // Ensure that if another thread sees the structure, it will see it properly created + WTF::storeStoreFence(); + m_allocator = allocator; - m_structure.set(vm, owner, - vm.prototypeMap.emptyObjectStructureForPrototype(prototype, inlineCapacity)); + m_structure.set(vm, owner, structure); } - Structure* structure() { return m_structure.get(); } - unsigned inlineCapacity() { return m_structure->inlineCapacity(); } + Structure* structure() + { + Structure* structure = m_structure.get(); + // Ensure that if we see the structure, it has been properly created + WTF::loadLoadFence(); + return structure; + } + unsigned inlineCapacity() { return structure()->inlineCapacity(); } void clear() { @@ -118,7 +128,7 @@ private: size_t count = 0; PropertyNameArray propertyNameArray(&vm); - prototype->structure()->getPropertyNamesFromStructure(vm, propertyNameArray, ExcludeDontEnumProperties); + prototype->structure()->getPropertyNamesFromStructure(vm, propertyNameArray, EnumerationMode()); PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArray.data()->propertyNameVector(); for (size_t i = 0; i < propertyNameVector.size(); ++i) { JSValue value = prototype->getDirect(vm, propertyNameVector[i]); diff --git a/bytecode/Operands.h b/bytecode/Operands.h index f21e05f..78ddaa5 100644 --- a/bytecode/Operands.h +++ b/bytecode/Operands.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,10 +52,10 @@ class Operands { public: Operands() { } - explicit Operands(size_t numArguments, size_t numLocals) + explicit Operands(size_t numArguments, size_t numLocals, const T& initialValue = Traits::defaultValue()) { - m_arguments.fill(Traits::defaultValue(), numArguments); - m_locals.fill(Traits::defaultValue(), numLocals); + m_arguments.fill(initialValue, numArguments); + m_locals.fill(initialValue, numLocals); } template<typename U, typename OtherTraits> @@ -96,7 +96,7 @@ public: return local(idx); } - void ensureLocals(size_t size) + void ensureLocals(size_t size, const T& ensuredValue = Traits::defaultValue()) { if (size <= m_locals.size()) return; @@ -104,7 +104,7 @@ public: size_t oldSize = m_locals.size(); m_locals.resize(size); for (size_t i = oldSize; i < m_locals.size(); ++i) - m_locals[i] = Traits::defaultValue(); + m_locals[i] = ensuredValue; } void setLocal(size_t idx, const T& value) @@ -149,6 +149,7 @@ public: } const T& operand(int operand) const { return const_cast<const T&>(const_cast<Operands*>(this)->operand(operand)); } + const T& operand(VirtualRegister operand) const { return const_cast<const T&>(const_cast<Operands*>(this)->operand(operand)); } bool hasOperand(int operand) const { @@ -209,6 +210,10 @@ public: return virtualRegisterForArgument(index).offset(); return virtualRegisterForLocal(index - numberOfArguments()).offset(); } + VirtualRegister virtualRegisterForIndex(size_t index) const + { + return VirtualRegister(operandForIndex(index)); + } size_t indexForOperand(int operand) const { if (operandIsArgument(operand)) @@ -252,11 +257,7 @@ public: } void dumpInContext(PrintStream& out, DumpContext* context) const; - - void dump(PrintStream& out) const - { - dumpInContext(out, 0); - } + void dump(PrintStream& out) const; private: Vector<T, 8> m_arguments; diff --git a/bytecode/OperandsInlines.h b/bytecode/OperandsInlines.h index 74ad60b..c9dee88 100644 --- a/bytecode/OperandsInlines.h +++ b/bytecode/OperandsInlines.h @@ -47,6 +47,22 @@ void Operands<T, Traits>::dumpInContext(PrintStream& out, DumpContext* context) } } +template<typename T, typename Traits> +void Operands<T, Traits>::dump(PrintStream& out) const +{ + CommaPrinter comma(" "); + for (size_t argumentIndex = numberOfArguments(); argumentIndex--;) { + if (Traits::isEmptyForDump(argument(argumentIndex))) + continue; + out.print(comma, "arg", argumentIndex, ":", argument(argumentIndex)); + } + for (size_t localIndex = 0; localIndex < numberOfLocals(); ++localIndex) { + if (Traits::isEmptyForDump(local(localIndex))) + continue; + out.print(comma, "loc", localIndex, ":", local(localIndex)); + } +} + } // namespace JSC #endif // OperandsInlines_h diff --git a/bytecode/PolymorphicGetByIdList.cpp b/bytecode/PolymorphicGetByIdList.cpp index c4005c0..c1e5e67 100644 --- a/bytecode/PolymorphicGetByIdList.cpp +++ b/bytecode/PolymorphicGetByIdList.cpp @@ -58,27 +58,11 @@ GetByIdAccess GetByIdAccess::fromStructureStubInfo(StructureStubInfo& stubInfo) GetByIdAccess result; - switch (stubInfo.accessType) { - case access_get_by_id_self: - result.m_type = SimpleInline; - result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure); - result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath); - break; - - case access_get_by_id_chain: - result.m_structure.copyFrom(stubInfo.u.getByIdChain.baseObjectStructure); - result.m_chain.copyFrom(stubInfo.u.getByIdChain.chain); - result.m_chainCount = stubInfo.u.getByIdChain.count; - result.m_stubRoutine = stubInfo.stubRoutine; - if (stubInfo.u.getByIdChain.isDirect) - result.m_type = SimpleStub; - else - result.m_type = Getter; - break; - - default: - RELEASE_ASSERT_NOT_REACHED(); - } + RELEASE_ASSERT(stubInfo.accessType == access_get_by_id_self); + + result.m_type = SimpleInline; + result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure); + result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath); return result; } @@ -109,7 +93,6 @@ PolymorphicGetByIdList* PolymorphicGetByIdList::from(StructureStubInfo& stubInfo ASSERT( stubInfo.accessType == access_get_by_id_self - || stubInfo.accessType == access_get_by_id_chain || stubInfo.accessType == access_unset); PolymorphicGetByIdList* result = new PolymorphicGetByIdList(stubInfo); @@ -133,7 +116,7 @@ void PolymorphicGetByIdList::addAccess(const GetByIdAccess& access) { ASSERT(!isFull()); // Make sure that the resizing optimizes for space, not time. - m_list.resize(m_list.size() + 1); + m_list.resizeToFit(m_list.size() + 1); m_list.last() = access; } diff --git a/bytecode/PolymorphicGetByIdList.h b/bytecode/PolymorphicGetByIdList.h index 265b0ad..4867d43 100644 --- a/bytecode/PolymorphicGetByIdList.h +++ b/bytecode/PolymorphicGetByIdList.h @@ -47,7 +47,8 @@ public: SimpleStub, // This is a stub. WatchedStub, Getter, - CustomGetter + CustomGetter, + SimpleMiss, }; GetByIdAccess() diff --git a/bytecode/PolymorphicPutByIdList.cpp b/bytecode/PolymorphicPutByIdList.cpp index 8605a50..91b87d4 100644 --- a/bytecode/PolymorphicPutByIdList.cpp +++ b/bytecode/PolymorphicPutByIdList.cpp @@ -138,7 +138,7 @@ void PolymorphicPutByIdList::addAccess(const PutByIdAccess& putByIdAccess) { ASSERT(!isFull()); // Make sure that the resizing optimizes for space, not time. - m_list.resize(m_list.size() + 1); + m_list.resizeToFit(m_list.size() + 1); m_list.last() = putByIdAccess; } diff --git a/bytecode/PolymorphicPutByIdList.h b/bytecode/PolymorphicPutByIdList.h index 15d7bde..2d35501 100644 --- a/bytecode/PolymorphicPutByIdList.h +++ b/bytecode/PolymorphicPutByIdList.h @@ -53,6 +53,7 @@ public: PutByIdAccess() : m_type(Invalid) + , m_chainCount(UINT_MAX) { } @@ -95,6 +96,7 @@ public: AccessType accessType, Structure* structure, StructureChain* chain, + unsigned chainCount, PutPropertySlot::PutValueFunc customSetter, PassRefPtr<JITStubRoutine> stubRoutine) { @@ -102,8 +104,10 @@ public: PutByIdAccess result; result.m_oldStructure.set(vm, owner, structure); result.m_type = accessType; - if (chain) + if (chain) { result.m_chain.set(vm, owner, chain); + result.m_chainCount = chainCount; + } result.m_customSetter = customSetter; result.m_stubRoutine = stubRoutine; return result; @@ -132,7 +136,7 @@ public: Structure* structure() const { - ASSERT(isReplace()); + ASSERT(isReplace() || isSetter() || isCustom()); return m_oldStructure.get(); } @@ -148,6 +152,12 @@ public: return m_chain.get(); } + unsigned chainCount() const + { + ASSERT(isSetter() || isCustom()); + return m_chainCount; + } + JITStubRoutine* stubRoutine() const { ASSERT(isTransition() || isReplace() || isSetter() || isCustom()); @@ -169,6 +179,7 @@ private: WriteBarrier<Structure> m_oldStructure; WriteBarrier<Structure> m_newStructure; WriteBarrier<StructureChain> m_chain; + unsigned m_chainCount; PutPropertySlot::PutValueFunc m_customSetter; RefPtr<JITStubRoutine> m_stubRoutine; }; diff --git a/bytecode/PreciseJumpTargets.cpp b/bytecode/PreciseJumpTargets.cpp index 87f2ceb..6bba492 100644 --- a/bytecode/PreciseJumpTargets.cpp +++ b/bytecode/PreciseJumpTargets.cpp @@ -73,12 +73,6 @@ static void getJumpTargetsForBytecodeOffset(CodeBlock* codeBlock, Interpreter* i out.append(bytecodeOffset + current[2].u.operand); break; } - case op_get_pnames: - out.append(bytecodeOffset + current[5].u.operand); - break; - case op_next_pname: - out.append(bytecodeOffset + current[6].u.operand); - break; case op_check_has_instance: out.append(bytecodeOffset + current[4].u.operand); break; diff --git a/bytecode/PutByIdStatus.cpp b/bytecode/PutByIdStatus.cpp index 5743750..9e219d2 100644 --- a/bytecode/PutByIdStatus.cpp +++ b/bytecode/PutByIdStatus.cpp @@ -26,7 +26,9 @@ #include "config.h" #include "PutByIdStatus.h" +#include "AccessorCallJITStubRoutine.h" #include "CodeBlock.h" +#include "ComplexGetStatus.h" #include "LLIntData.h" #include "LowLevelInterpreter.h" #include "JSCInlines.h" @@ -40,7 +42,11 @@ namespace JSC { bool PutByIdStatus::appendVariant(const PutByIdVariant& variant) { for (unsigned i = 0; i < m_variants.size(); ++i) { - if (m_variants[i].oldStructure() == variant.oldStructure()) + if (m_variants[i].attemptToMerge(variant)) + return true; + } + for (unsigned i = 0; i < m_variants.size(); ++i) { + if (m_variants[i].oldStructure().overlaps(variant.oldStructure())) return false; } m_variants.append(variant); @@ -48,17 +54,15 @@ bool PutByIdStatus::appendVariant(const PutByIdVariant& variant) } #if ENABLE(DFG_JIT) -bool PutByIdStatus::hasExitSite(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex, ExitingJITType exitType) +bool PutByIdStatus::hasExitSite(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex) { - return profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache, exitType)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCacheWatchpoint, exitType)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadWeakConstantCache, exitType)) - || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadWeakConstantCacheWatchpoint, exitType)); + return profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) + || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache)); } #endif -PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, StringImpl* uid) +PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, UniquedStringImpl* uid) { UNUSED_PARAM(profiledBlock); UNUSED_PARAM(bytecodeIndex); @@ -71,7 +75,7 @@ PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned if (instruction[0].u.opcode == LLInt::getOpcode(op_put_by_id) || instruction[0].u.opcode == LLInt::getOpcode(op_put_by_id_out_of_line)) { - PropertyOffset offset = structure->getConcurrently(*profiledBlock->vm(), uid); + PropertyOffset offset = structure->getConcurrently(uid); if (!isValidOffset(offset)) return PutByIdStatus(NoInformation); @@ -90,17 +94,18 @@ PutByIdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned ASSERT(newStructure); ASSERT(chain); - PropertyOffset offset = newStructure->getConcurrently(*profiledBlock->vm(), uid); + PropertyOffset offset = newStructure->getConcurrently(uid); if (!isValidOffset(offset)) return PutByIdStatus(NoInformation); - return PutByIdVariant::transition( - structure, newStructure, - chain ? adoptRef(new IntendedStructureChain(profiledBlock, structure, chain)) : 0, - offset); + RefPtr<IntendedStructureChain> intendedChain; + if (chain) + intendedChain = adoptRef(new IntendedStructureChain(profiledBlock, structure, chain)); + + return PutByIdVariant::transition(structure, newStructure, intendedChain.get(), offset); } -PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, StringImpl* uid) +PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid) { ConcurrentJITLocker locker(profiledBlock->m_lock); @@ -108,12 +113,13 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m UNUSED_PARAM(bytecodeIndex); UNUSED_PARAM(uid); #if ENABLE(DFG_JIT) - if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex) - || hasExitSite(locker, profiledBlock, bytecodeIndex)) + if (hasExitSite(locker, profiledBlock, bytecodeIndex)) return PutByIdStatus(TakesSlowPath); StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex)); - PutByIdStatus result = computeForStubInfo(locker, profiledBlock, stubInfo, uid); + PutByIdStatus result = computeForStubInfo( + locker, profiledBlock, stubInfo, uid, + CallLinkStatus::computeExitSiteData(locker, profiledBlock, bytecodeIndex)); if (!result) return computeFromLLInt(profiledBlock, bytecodeIndex, uid); @@ -125,14 +131,19 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& m } #if ENABLE(JIT) -PutByIdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, StringImpl* uid) +PutByIdStatus PutByIdStatus::computeForStubInfo( + const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, + UniquedStringImpl* uid, CallLinkStatus::ExitSiteData callExitSiteData) { - if (!stubInfo || !stubInfo->seen) + if (!stubInfo) return PutByIdStatus(); - if (stubInfo->resetByGC) + if (stubInfo->tookSlowPath) return PutByIdStatus(TakesSlowPath); - + + if (!stubInfo->seen) + return PutByIdStatus(); + switch (stubInfo->accessType) { case access_unset: // If the JIT saw it but didn't optimize it, then assume that this takes slow path. @@ -140,8 +151,7 @@ PutByIdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJITLocker&, Code case access_put_by_id_replace: { PropertyOffset offset = - stubInfo->u.putByIdReplace.baseObjectStructure->getConcurrently( - *profiledBlock->vm(), uid); + stubInfo->u.putByIdReplace.baseObjectStructure->getConcurrently(uid); if (isValidOffset(offset)) { return PutByIdVariant::replace( stubInfo->u.putByIdReplace.baseObjectStructure.get(), offset); @@ -153,16 +163,18 @@ PutByIdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJITLocker&, Code case access_put_by_id_transition_direct: { ASSERT(stubInfo->u.putByIdTransition.previousStructure->transitionWatchpointSetHasBeenInvalidated()); PropertyOffset offset = - stubInfo->u.putByIdTransition.structure->getConcurrently( - *profiledBlock->vm(), uid); + stubInfo->u.putByIdTransition.structure->getConcurrently(uid); if (isValidOffset(offset)) { + RefPtr<IntendedStructureChain> chain; + if (stubInfo->u.putByIdTransition.chain) { + chain = adoptRef(new IntendedStructureChain( + profiledBlock, stubInfo->u.putByIdTransition.previousStructure.get(), + stubInfo->u.putByIdTransition.chain.get())); + } return PutByIdVariant::transition( stubInfo->u.putByIdTransition.previousStructure.get(), stubInfo->u.putByIdTransition.structure.get(), - stubInfo->u.putByIdTransition.chain ? adoptRef(new IntendedStructureChain( - profiledBlock, stubInfo->u.putByIdTransition.previousStructure.get(), - stubInfo->u.putByIdTransition.chain.get())) : 0, - offset); + chain.get(), offset); } return PutByIdStatus(TakesSlowPath); } @@ -173,41 +185,89 @@ PutByIdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJITLocker&, Code PutByIdStatus result; result.m_state = Simple; + State slowPathState = TakesSlowPath; + for (unsigned i = 0; i < list->size(); ++i) { + const PutByIdAccess& access = list->at(i); + + switch (access.type()) { + case PutByIdAccess::Setter: + case PutByIdAccess::CustomSetter: + slowPathState = MakesCalls; + break; + default: + break; + } + } + for (unsigned i = 0; i < list->size(); ++i) { const PutByIdAccess& access = list->at(i); + PutByIdVariant variant; + switch (access.type()) { case PutByIdAccess::Replace: { Structure* structure = access.structure(); - PropertyOffset offset = structure->getConcurrently(*profiledBlock->vm(), uid); + PropertyOffset offset = structure->getConcurrently(uid); if (!isValidOffset(offset)) - return PutByIdStatus(TakesSlowPath); - if (!result.appendVariant(PutByIdVariant::replace(structure, offset))) - return PutByIdStatus(TakesSlowPath); + return PutByIdStatus(slowPathState); + variant = PutByIdVariant::replace(structure, offset); break; } case PutByIdAccess::Transition: { PropertyOffset offset = - access.newStructure()->getConcurrently(*profiledBlock->vm(), uid); + access.newStructure()->getConcurrently(uid); if (!isValidOffset(offset)) - return PutByIdStatus(TakesSlowPath); - bool ok = result.appendVariant(PutByIdVariant::transition( - access.oldStructure(), access.newStructure(), - access.chain() ? adoptRef(new IntendedStructureChain( - profiledBlock, access.oldStructure(), access.chain())) : 0, - offset)); - if (!ok) - return PutByIdStatus(TakesSlowPath); + return PutByIdStatus(slowPathState); + RefPtr<IntendedStructureChain> chain; + if (access.chain()) { + chain = adoptRef(new IntendedStructureChain( + profiledBlock, access.oldStructure(), access.chain())); + if (!chain->isStillValid()) + continue; + } + variant = PutByIdVariant::transition( + access.oldStructure(), access.newStructure(), chain.get(), offset); break; } - case PutByIdAccess::Setter: + + case PutByIdAccess::Setter: { + Structure* structure = access.structure(); + + ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor( + profiledBlock, structure, access.chain(), access.chainCount(), uid); + + switch (complexGetStatus.kind()) { + case ComplexGetStatus::ShouldSkip: + continue; + + case ComplexGetStatus::TakesSlowPath: + return PutByIdStatus(slowPathState); + + case ComplexGetStatus::Inlineable: { + AccessorCallJITStubRoutine* stub = static_cast<AccessorCallJITStubRoutine*>( + access.stubRoutine()); + std::unique_ptr<CallLinkStatus> callLinkStatus = + std::make_unique<CallLinkStatus>( + CallLinkStatus::computeFor( + locker, profiledBlock, *stub->m_callLinkInfo, callExitSiteData)); + + variant = PutByIdVariant::setter( + structure, complexGetStatus.offset(), complexGetStatus.chain(), + WTF::move(callLinkStatus)); + } } + break; + } + case PutByIdAccess::CustomSetter: return PutByIdStatus(MakesCalls); default: - return PutByIdStatus(TakesSlowPath); + return PutByIdStatus(slowPathState); } + + if (!result.appendVariant(variant)) + return PutByIdStatus(slowPathState); } return result; @@ -219,20 +279,24 @@ PutByIdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJITLocker&, Code } #endif -PutByIdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin codeOrigin, StringImpl* uid) +PutByIdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin codeOrigin, UniquedStringImpl* uid) { #if ENABLE(DFG_JIT) if (dfgBlock) { + CallLinkStatus::ExitSiteData exitSiteData; { ConcurrentJITLocker locker(baselineBlock->m_lock); - if (hasExitSite(locker, baselineBlock, codeOrigin.bytecodeIndex, ExitFromFTL)) + if (hasExitSite(locker, baselineBlock, codeOrigin.bytecodeIndex)) return PutByIdStatus(TakesSlowPath); + exitSiteData = CallLinkStatus::computeExitSiteData( + locker, baselineBlock, codeOrigin.bytecodeIndex); } PutByIdStatus result; { ConcurrentJITLocker locker(dfgBlock->m_lock); - result = computeForStubInfo(locker, dfgBlock, dfgMap.get(codeOrigin), uid); + result = computeForStubInfo( + locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData); } // We use TakesSlowPath in some cases where the stub was unset. That's weird and @@ -249,88 +313,109 @@ PutByIdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, CodeBlock* dfg return computeFor(baselineBlock, baselineMap, codeOrigin.bytecodeIndex, uid); } -PutByIdStatus PutByIdStatus::computeFor(VM& vm, JSGlobalObject* globalObject, Structure* structure, StringImpl* uid, bool isDirect) +PutByIdStatus PutByIdStatus::computeFor(JSGlobalObject* globalObject, const StructureSet& set, UniquedStringImpl* uid, bool isDirect) { - if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex) + if (parseIndex(*uid)) return PutByIdStatus(TakesSlowPath); - if (!structure) - return PutByIdStatus(TakesSlowPath); + if (set.isEmpty()) + return PutByIdStatus(); - if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType) - return PutByIdStatus(TakesSlowPath); + PutByIdStatus result; + result.m_state = Simple; + for (unsigned i = 0; i < set.size(); ++i) { + Structure* structure = set[i]; + + if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType) + return PutByIdStatus(TakesSlowPath); - if (!structure->propertyAccessesAreCacheable()) - return PutByIdStatus(TakesSlowPath); + if (!structure->propertyAccessesAreCacheable()) + return PutByIdStatus(TakesSlowPath); - unsigned attributes; - JSCell* specificValue; - PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue); - if (isValidOffset(offset)) { - if (attributes & CustomAccessor) - return PutByIdStatus(MakesCalls); + unsigned attributes; + PropertyOffset offset = structure->getConcurrently(uid, attributes); + if (isValidOffset(offset)) { + if (attributes & CustomAccessor) + return PutByIdStatus(MakesCalls); - if (attributes & (Accessor | ReadOnly)) - return PutByIdStatus(TakesSlowPath); - if (specificValue) { - // We need the PutById slow path to verify that we're storing the right value into - // the specialized slot. - return PutByIdStatus(TakesSlowPath); + if (attributes & (Accessor | ReadOnly)) + return PutByIdStatus(TakesSlowPath); + + WatchpointSet* replaceSet = structure->propertyReplacementWatchpointSet(offset); + if (!replaceSet || replaceSet->isStillValid()) { + // When this executes, it'll create, and fire, this replacement watchpoint set. + // That means that this has probably never executed or that something fishy is + // going on. Also, we cannot create or fire the watchpoint set from the concurrent + // JIT thread, so even if we wanted to do this, we'd need to have a lazy thingy. + // So, better leave this alone and take slow path. + return PutByIdStatus(TakesSlowPath); + } + + if (!result.appendVariant(PutByIdVariant::replace(structure, offset))) + return PutByIdStatus(TakesSlowPath); + continue; } - return PutByIdVariant::replace(structure, 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. + // 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); + // 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 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().isObject()) + return PutByIdStatus(TakesSlowPath); - RefPtr<IntendedStructureChain> chain; - if (!isDirect) { - chain = adoptRef(new IntendedStructureChain(globalObject, structure)); + RefPtr<IntendedStructureChain> chain; + if (!isDirect) { + chain = adoptRef(new IntendedStructureChain(globalObject, structure)); - // If the prototype chain has setters or read-only properties, then give up. - if (chain->mayInterceptStoreTo(vm, uid)) - return PutByIdStatus(TakesSlowPath); + // If the prototype chain has setters or read-only properties, then give up. + if (chain->mayInterceptStoreTo(uid)) + 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 (!chain->isNormalized()) + // 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 (structure->isProxy() || !chain->isNormalized()) + return PutByIdStatus(TakesSlowPath); + } + + // We only optimize if there is already a structure that the transition is cached to. + Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, offset); + if (!transition) + return PutByIdStatus(TakesSlowPath); + ASSERT(isValidOffset(offset)); + + bool didAppend = result.appendVariant( + PutByIdVariant::transition(structure, transition, chain.get(), offset)); + if (!didAppend) 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::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset); - if (!transition) - return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above. - ASSERT(!transition->transitionDidInvolveSpecificValue()); - ASSERT(isValidOffset(offset)); + return result; +} + +bool PutByIdStatus::makesCalls() const +{ + if (m_state == MakesCalls) + return true; + + if (m_state != Simple) + return false; + + for (unsigned i = m_variants.size(); i--;) { + if (m_variants[i].makesCalls()) + return true; + } - return PutByIdVariant::transition(structure, transition, chain.release(), offset); + return false; } void PutByIdStatus::dump(PrintStream& out) const diff --git a/bytecode/PutByIdStatus.h b/bytecode/PutByIdStatus.h index d2db7a6..652ccc1 100644 --- a/bytecode/PutByIdStatus.h +++ b/bytecode/PutByIdStatus.h @@ -26,6 +26,7 @@ #ifndef PutByIdStatus_h #define PutByIdStatus_h +#include "CallLinkStatus.h" #include "ExitingJITType.h" #include "PutByIdVariant.h" #include "StructureStubInfo.h" @@ -69,10 +70,10 @@ public: m_variants.append(variant); } - static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, StringImpl* uid); - static PutByIdStatus computeFor(VM&, JSGlobalObject*, Structure*, StringImpl* uid, bool isDirect); + static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, UniquedStringImpl* uid); + static PutByIdStatus computeFor(JSGlobalObject*, const StructureSet&, UniquedStringImpl* uid, bool isDirect); - static PutByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, StringImpl* uid); + static PutByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, UniquedStringImpl* uid); State state() const { return m_state; } @@ -80,7 +81,7 @@ public: bool operator!() const { return m_state == NoInformation; } bool isSimple() const { return m_state == Simple; } bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } - bool makesCalls() const { return m_state == MakesCalls; } + bool makesCalls() const; size_t numVariants() const { return m_variants.size(); } const Vector<PutByIdVariant, 1>& variants() const { return m_variants; } @@ -91,12 +92,14 @@ public: private: #if ENABLE(DFG_JIT) - static bool hasExitSite(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex, ExitingJITType = ExitFromAnything); + static bool hasExitSite(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex); #endif #if ENABLE(JIT) - static PutByIdStatus computeForStubInfo(const ConcurrentJITLocker&, CodeBlock*, StructureStubInfo*, StringImpl* uid); + static PutByIdStatus computeForStubInfo( + const ConcurrentJITLocker&, CodeBlock*, StructureStubInfo*, UniquedStringImpl* uid, + CallLinkStatus::ExitSiteData); #endif - static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid); + static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, UniquedStringImpl* uid); bool appendVariant(const PutByIdVariant&); diff --git a/bytecode/PutByIdVariant.cpp b/bytecode/PutByIdVariant.cpp index f83c102..e9d10df 100644 --- a/bytecode/PutByIdVariant.cpp +++ b/bytecode/PutByIdVariant.cpp @@ -26,8 +26,191 @@ #include "config.h" #include "PutByIdVariant.h" +#include "CallLinkStatus.h" +#include "JSCInlines.h" +#include <wtf/ListDump.h> + namespace JSC { +PutByIdVariant::PutByIdVariant(const PutByIdVariant& other) + : PutByIdVariant() +{ + *this = other; +} + +PutByIdVariant& PutByIdVariant::operator=(const PutByIdVariant& other) +{ + m_kind = other.m_kind; + m_oldStructure = other.m_oldStructure; + m_newStructure = other.m_newStructure; + m_constantChecks = other.m_constantChecks; + m_alternateBase = other.m_alternateBase; + m_offset = other.m_offset; + if (other.m_callLinkStatus) + m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus); + else + m_callLinkStatus = nullptr; + return *this; +} + +PutByIdVariant PutByIdVariant::replace(const StructureSet& structure, PropertyOffset offset) +{ + PutByIdVariant result; + result.m_kind = Replace; + result.m_oldStructure = structure; + result.m_offset = offset; + return result; +} + +PutByIdVariant PutByIdVariant::transition( + const StructureSet& oldStructure, Structure* newStructure, + const IntendedStructureChain* structureChain, PropertyOffset offset) +{ + PutByIdVariant result; + result.m_kind = Transition; + result.m_oldStructure = oldStructure; + result.m_newStructure = newStructure; + if (structureChain) + structureChain->gatherChecks(result.m_constantChecks); + result.m_offset = offset; + return result; +} + +PutByIdVariant PutByIdVariant::setter( + const StructureSet& structure, PropertyOffset offset, + IntendedStructureChain* chain, std::unique_ptr<CallLinkStatus> callLinkStatus) +{ + PutByIdVariant result; + result.m_kind = Setter; + result.m_oldStructure = structure; + if (chain) { + chain->gatherChecks(result.m_constantChecks); + result.m_alternateBase = chain->terminalPrototype(); + } + result.m_offset = offset; + result.m_callLinkStatus = WTF::move(callLinkStatus); + return result; +} + +Structure* PutByIdVariant::oldStructureForTransition() const +{ + ASSERT(kind() == Transition); + ASSERT(m_oldStructure.size() <= 2); + for (unsigned i = m_oldStructure.size(); i--;) { + Structure* structure = m_oldStructure[i]; + if (structure != m_newStructure) + return structure; + } + RELEASE_ASSERT_NOT_REACHED(); + + return nullptr; +} + +bool PutByIdVariant::writesStructures() const +{ + switch (kind()) { + case Transition: + case Setter: + return true; + default: + return false; + } +} + +bool PutByIdVariant::reallocatesStorage() const +{ + switch (kind()) { + case Transition: + return oldStructureForTransition()->outOfLineCapacity() != newStructure()->outOfLineCapacity(); + case Setter: + return true; + default: + return false; + } +} + +bool PutByIdVariant::makesCalls() const +{ + return kind() == Setter; +} + +StructureSet PutByIdVariant::baseStructure() const +{ + ASSERT(kind() == Setter); + + if (!m_alternateBase) + return structure(); + + Structure* structure = structureFor(m_constantChecks, m_alternateBase); + RELEASE_ASSERT(structure); + return structure; +} + +bool PutByIdVariant::attemptToMerge(const PutByIdVariant& other) +{ + if (m_offset != other.m_offset) + return false; + + switch (m_kind) { + case Replace: + switch (other.m_kind) { + case Replace: { + ASSERT(m_constantChecks.isEmpty()); + ASSERT(other.m_constantChecks.isEmpty()); + + m_oldStructure.merge(other.m_oldStructure); + return true; + } + + case Transition: { + PutByIdVariant newVariant = other; + if (newVariant.attemptToMergeTransitionWithReplace(*this)) { + *this = newVariant; + return true; + } + return false; + } + + default: + return false; + } + + case Transition: + switch (other.m_kind) { + case Replace: + return attemptToMergeTransitionWithReplace(other); + + default: + return false; + } + + default: + return false; + } +} + +bool PutByIdVariant::attemptToMergeTransitionWithReplace(const PutByIdVariant& replace) +{ + ASSERT(m_kind == Transition); + ASSERT(replace.m_kind == Replace); + ASSERT(m_offset == replace.m_offset); + ASSERT(!replace.writesStructures()); + ASSERT(!replace.reallocatesStorage()); + + // This sort of merging only works when we have one path along which we add a new field which + // transitions to structure S while the other path was already on structure S. This doesn't + // work if we need to reallocate anything or if the replace path is polymorphic. + + if (reallocatesStorage()) + return false; + + if (replace.m_oldStructure.onlyStructure() != m_newStructure) + return false; + + m_oldStructure.merge(m_newStructure); + return true; +} + void PutByIdVariant::dump(PrintStream& out) const { dumpInContext(out, 0); @@ -42,14 +225,25 @@ void PutByIdVariant::dumpInContext(PrintStream& out, DumpContext* context) const case Replace: out.print( - "<Replace: ", pointerDumpInContext(structure(), context), ", ", offset(), ">"); + "<Replace: ", inContext(structure(), context), ", offset = ", offset(), ">"); return; case Transition: out.print( - "<Transition: ", pointerDumpInContext(oldStructure(), context), " -> ", - pointerDumpInContext(newStructure(), context), ", ", - pointerDumpInContext(structureChain(), context), ", ", offset(), ">"); + "<Transition: ", inContext(oldStructure(), context), " -> ", + pointerDumpInContext(newStructure(), context), ", [", + listDumpInContext(constantChecks(), context), "], offset = ", offset(), ">"); + return; + + case Setter: + out.print( + "<Setter: ", inContext(structure(), context), ", [", + listDumpInContext(constantChecks(), context), "]"); + if (m_alternateBase) + out.print(", alternateBase = ", inContext(JSValue(m_alternateBase), context)); + out.print(", offset = ", m_offset); + out.print(", call = ", *m_callLinkStatus); + out.print(">"); return; } diff --git a/bytecode/PutByIdVariant.h b/bytecode/PutByIdVariant.h index eba95e8..9dfedbd 100644 --- a/bytecode/PutByIdVariant.h +++ b/bytecode/PutByIdVariant.h @@ -28,74 +28,81 @@ #include "IntendedStructureChain.h" #include "PropertyOffset.h" +#include "StructureSet.h" namespace JSC { +class CallLinkStatus; + class PutByIdVariant { public: enum Kind { NotSet, Replace, - Transition + Transition, + Setter }; PutByIdVariant() : m_kind(NotSet) - , m_oldStructure(0) - , m_newStructure(0) + , m_newStructure(nullptr) + , m_alternateBase(nullptr) , m_offset(invalidOffset) { } - static PutByIdVariant replace(Structure* structure, PropertyOffset offset) - { - PutByIdVariant result; - result.m_kind = Replace; - result.m_oldStructure = structure; - result.m_offset = offset; - return result; - } + PutByIdVariant(const PutByIdVariant&); + PutByIdVariant& operator=(const PutByIdVariant&); + + static PutByIdVariant replace( + const StructureSet& structure, PropertyOffset offset); static PutByIdVariant transition( - Structure* oldStructure, Structure* newStructure, - PassRefPtr<IntendedStructureChain> structureChain, PropertyOffset offset) - { - PutByIdVariant result; - result.m_kind = Transition; - result.m_oldStructure = oldStructure; - result.m_newStructure = newStructure; - result.m_structureChain = structureChain; - result.m_offset = offset; - return result; - } + const StructureSet& oldStructure, Structure* newStructure, + const IntendedStructureChain* structureChain, PropertyOffset offset); + + static PutByIdVariant setter( + const StructureSet& structure, PropertyOffset offset, + IntendedStructureChain* chain, std::unique_ptr<CallLinkStatus> callLinkStatus); Kind kind() const { return m_kind; } bool isSet() const { return kind() != NotSet; } bool operator!() const { return !isSet(); } - Structure* structure() const + const StructureSet& structure() const + { + ASSERT(kind() == Replace || kind() == Setter); + return m_oldStructure; + } + + const StructureSet& oldStructure() const { - ASSERT(kind() == Replace); + ASSERT(kind() == Transition || kind() == Replace || kind() == Setter); return m_oldStructure; } - Structure* oldStructure() const + StructureSet& oldStructure() { - ASSERT(kind() == Transition || kind() == Replace); + ASSERT(kind() == Transition || kind() == Replace || kind() == Setter); return m_oldStructure; } + Structure* oldStructureForTransition() const; + Structure* newStructure() const { ASSERT(kind() == Transition); return m_newStructure; } + + bool writesStructures() const; + bool reallocatesStorage() const; + bool makesCalls() const; - IntendedStructureChain* structureChain() const + const ConstantStructureCheckVector& constantChecks() const { - ASSERT(kind() == Transition); - return m_structureChain.get(); + return m_constantChecks; } PropertyOffset offset() const @@ -104,15 +111,35 @@ public: return m_offset; } + JSObject* alternateBase() const + { + ASSERT(kind() == Setter); + return m_alternateBase; + } + + StructureSet baseStructure() const; + + CallLinkStatus* callLinkStatus() const + { + ASSERT(kind() == Setter); + return m_callLinkStatus.get(); + } + + bool attemptToMerge(const PutByIdVariant& other); + void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; private: + bool attemptToMergeTransitionWithReplace(const PutByIdVariant& replace); + Kind m_kind; - Structure* m_oldStructure; + StructureSet m_oldStructure; Structure* m_newStructure; - RefPtr<IntendedStructureChain> m_structureChain; + ConstantStructureCheckVector m_constantChecks; + JSObject* m_alternateBase; PropertyOffset m_offset; + std::unique_ptr<CallLinkStatus> m_callLinkStatus; }; } // namespace JSC diff --git a/bytecode/SamplingTool.h b/bytecode/SamplingTool.h index 678af85..7d9c54f 100644 --- a/bytecode/SamplingTool.h +++ b/bytecode/SamplingTool.h @@ -271,7 +271,7 @@ namespace JSC { , m_sampleCount(0) , m_opcodeSampleCount(0) #if ENABLE(CODEBLOCK_SAMPLING) - , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap)) + , m_scopeSampleMap(std::make_unique<ScriptSampleRecordMap>) #endif { memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples)); @@ -338,7 +338,7 @@ namespace JSC { #if ENABLE(CODEBLOCK_SAMPLING) Mutex m_scriptSampleMapMutex; - OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap; + std::unique_ptr<ScriptSampleRecordMap> m_scopeSampleMap; #endif }; diff --git a/bytecode/SpecialPointer.h b/bytecode/SpecialPointer.h index c18a6e9..64fb23f 100644 --- a/bytecode/SpecialPointer.h +++ b/bytecode/SpecialPointer.h @@ -41,6 +41,11 @@ enum Pointer { }; } // namespace Special +enum class LinkTimeConstant { + DefinePropertyFunction, +}; +const unsigned LinkTimeConstantCount = 1; + inline bool pointerIsFunction(Special::Pointer pointer) { ASSERT_UNUSED(pointer, pointer < Special::TableSize); diff --git a/bytecode/SpeculatedType.cpp b/bytecode/SpeculatedType.cpp index 19aeab7..ca9514c 100644 --- a/bytecode/SpeculatedType.cpp +++ b/bytecode/SpeculatedType.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011-2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,13 +29,13 @@ #include "config.h" #include "SpeculatedType.h" -#include "Arguments.h" +#include "DirectArguments.h" #include "JSArray.h" #include "JSFunction.h" #include "JSCInlines.h" +#include "ScopedArguments.h" #include "StringObject.h" #include "ValueProfile.h" -#include <wtf/BoundsCheckedPointer.h> #include <wtf/StringPrintStream.h> namespace JSC { @@ -127,8 +127,13 @@ void dumpSpeculation(PrintStream& out, SpeculatedType value) else isTop = false; - if (value & SpecArguments) - myOut.print("Arguments"); + if (value & SpecDirectArguments) + myOut.print("Directarguments"); + else + isTop = false; + + if (value & SpecScopedArguments) + myOut.print("Scopedarguments"); else isTop = false; @@ -151,12 +156,26 @@ void dumpSpeculation(PrintStream& out, SpeculatedType value) else isTop = false; } + + if (value & SpecSymbol) + myOut.print("Symbol"); + else + isTop = false; } - if (value & SpecInt32) + if (value == SpecInt32) myOut.print("Int32"); - else - isTop = false; + else { + if (value & SpecBoolInt32) + myOut.print("Boolint32"); + else + isTop = false; + + if (value & SpecNonBoolInt32) + myOut.print("Nonboolint32"); + else + isTop = false; + } if (value & SpecInt52) myOut.print("Int52"); @@ -232,8 +251,10 @@ static const char* speculationToAbbreviatedString(SpeculatedType prediction) return "<Float32array>"; if (isFloat64ArraySpeculation(prediction)) return "<Float64array>"; - if (isArgumentsSpeculation(prediction)) - return "<Arguments>"; + if (isDirectArgumentsSpeculation(prediction)) + return "<DirectArguments>"; + if (isScopedArgumentsSpeculation(prediction)) + return "<ScopedArguments>"; if (isStringObjectSpeculation(prediction)) return "<StringObject>"; if (isStringOrStringObjectSpeculation(prediction)) @@ -242,6 +263,8 @@ static const char* speculationToAbbreviatedString(SpeculatedType prediction) return "<Object>"; if (isCellSpeculation(prediction)) return "<Cell>"; + if (isBoolInt32Speculation(prediction)) + return "<BoolInt32>"; if (isInt32Speculation(prediction)) return "<Int32>"; if (isInt52AsDoubleSpeculation(prediction)) @@ -305,8 +328,11 @@ SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo) if (classInfo == JSArray::info()) return SpecArray; - if (classInfo == Arguments::info()) - return SpecArguments; + if (classInfo == DirectArguments::info()) + return SpecDirectArguments; + + if (classInfo == ScopedArguments::info()) + return SpecScopedArguments; if (classInfo == StringObject::info()) return SpecStringObject; @@ -327,6 +353,8 @@ SpeculatedType speculationFromStructure(Structure* structure) { if (structure->typeInfo().type() == StringType) return SpecString; + if (structure->typeInfo().type() == SymbolType) + return SpecSymbol; return speculationFromClassInfo(structure->classInfo()); } @@ -346,8 +374,11 @@ SpeculatedType speculationFromValue(JSValue value) { if (value.isEmpty()) return SpecEmpty; - if (value.isInt32()) - return SpecInt32; + if (value.isInt32()) { + if (value.asInt32() & ~1) + return SpecNonBoolInt32; + return SpecBoolInt32; + } if (value.isDouble()) { double number = value.asNumber(); if (number != number) @@ -497,7 +528,7 @@ SpeculatedType typeOfDoubleAbs(SpeculatedType value) return typeOfDoubleNegation(value); } -SpeculatedType typeOfDoubleFRound(SpeculatedType value) +SpeculatedType typeOfDoubleRounding(SpeculatedType value) { // We might lose bits, which leads to a NaN being purified. if (value & SpecDoubleImpureNaN) @@ -508,6 +539,15 @@ SpeculatedType typeOfDoubleFRound(SpeculatedType value) return value; } +SpeculatedType typeOfDoublePow(SpeculatedType xValue, SpeculatedType yValue) +{ + // Math.pow() always return NaN if the exponent is NaN, unlike std::pow(). + // We always set a pure NaN in that case. + if (yValue & SpecDoubleNaN) + xValue |= SpecDoublePureNaN; + return polluteDouble(xValue); +} + SpeculatedType typeOfDoubleBinaryOp(SpeculatedType a, SpeculatedType b) { return polluteDouble(a | b); diff --git a/bytecode/SpeculatedType.h b/bytecode/SpeculatedType.h index 5e90635..bd045c3 100644 --- a/bytecode/SpeculatedType.h +++ b/bytecode/SpeculatedType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,20 +52,24 @@ static const SpeculatedType SpecUint32Array = 0x00000200; // It's definit static const SpeculatedType SpecFloat32Array = 0x00000400; // It's definitely an Uint16Array or one of its subclasses. static const SpeculatedType SpecFloat64Array = 0x00000800; // It's definitely an Uint16Array or one of its subclasses. static const SpeculatedType SpecTypedArrayView = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array; -static const SpeculatedType SpecArguments = 0x00001000; // It's definitely an Arguments object. -static const SpeculatedType SpecStringObject = 0x00002000; // It's definitely a StringObject. +static const SpeculatedType SpecDirectArguments = 0x00001000; // It's definitely a DirectArguments object. +static const SpeculatedType SpecScopedArguments = 0x00002000; // It's definitely a ScopedArguments object. +static const SpeculatedType SpecStringObject = 0x00004000; // It's definitely a StringObject. static const SpeculatedType SpecObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction. static const SpeculatedType SpecObject = 0x0000ffff; // Bitmask used for testing for any kind of object prediction. static const SpeculatedType SpecStringIdent = 0x00010000; // It's definitely a JSString, and it's an identifier. static const SpeculatedType SpecStringVar = 0x00020000; // It's definitely a JSString, and it's not an identifier. static const SpeculatedType SpecString = 0x00030000; // It's definitely a JSString. -static const SpeculatedType SpecCellOther = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. -static const SpeculatedType SpecCell = 0x0007ffff; // It's definitely a JSCell. -static const SpeculatedType SpecInt32 = 0x00200000; // It's definitely an Int32. +static const SpeculatedType SpecSymbol = 0x00040000; // It's definitely a Symbol. +static const SpeculatedType SpecCellOther = 0x00080000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078 +static const SpeculatedType SpecCell = 0x000fffff; // It's definitely a JSCell. +static const SpeculatedType SpecBoolInt32 = 0x00100000; // It's definitely an Int32 with value 0 or 1. +static const SpeculatedType SpecNonBoolInt32 = 0x00200000; // It's definitely an Int32 with value other than 0 or 1. +static const SpeculatedType SpecInt32 = 0x00300000; // It's definitely an Int32. static const SpeculatedType SpecInt52 = 0x00400000; // It's definitely an Int52 and we intend it to unbox it. -static const SpeculatedType SpecMachineInt = 0x00600000; // It's something that we can do machine int arithmetic on. +static const SpeculatedType SpecMachineInt = 0x00700000; // It's something that we can do machine int arithmetic on. static const SpeculatedType SpecInt52AsDouble = 0x00800000; // It's definitely an Int52 and it's inside a double. -static const SpeculatedType SpecInteger = 0x00e00000; // It's definitely some kind of integer. +static const SpeculatedType SpecInteger = 0x00f00000; // It's definitely some kind of integer. static const SpeculatedType SpecNonIntAsDouble = 0x01000000; // It's definitely not an Int52 but it's a real number and it's a double. static const SpeculatedType SpecDoubleReal = 0x01800000; // It's definitely a non-NaN double. static const SpeculatedType SpecDoublePureNaN = 0x02000000; // It's definitely a NaN that is sae to tag (i.e. pure). @@ -73,10 +77,10 @@ static const SpeculatedType SpecDoubleImpureNaN = 0x04000000; // It's definit static const SpeculatedType SpecDoubleNaN = 0x06000000; // It's definitely some kind of NaN. static const SpeculatedType SpecBytecodeDouble = 0x03800000; // It's either a non-NaN or a NaN double, but it's definitely not impure NaN. static const SpeculatedType SpecFullDouble = 0x07800000; // It's either a non-NaN or a NaN double. -static const SpeculatedType SpecBytecodeRealNumber = 0x01a00000; // It's either an Int32 or a DoubleReal. -static const SpeculatedType SpecFullRealNumber = 0x01e00000; // It's either an Int32 or a DoubleReal, or a Int52. -static const SpeculatedType SpecBytecodeNumber = 0x03a00000; // It's either an Int32 or a Double, and the Double cannot be an impure NaN. -static const SpeculatedType SpecFullNumber = 0x07e00000; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN. +static const SpeculatedType SpecBytecodeRealNumber = 0x01b00000; // It's either an Int32 or a DoubleReal. +static const SpeculatedType SpecFullRealNumber = 0x01f00000; // It's either an Int32 or a DoubleReal, or a Int52. +static const SpeculatedType SpecBytecodeNumber = 0x03b00000; // It's either an Int32 or a Double, and the Double cannot be an impure NaN. +static const SpeculatedType SpecFullNumber = 0x07f00000; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN. static const SpeculatedType SpecBoolean = 0x10000000; // It's definitely a Boolean. static const SpeculatedType SpecOther = 0x20000000; // It's definitely either Null or Undefined. static const SpeculatedType SpecMisc = 0x30000000; // It's definitely either a boolean, Null, or Undefined. @@ -98,6 +102,11 @@ inline bool isCellSpeculation(SpeculatedType value) return !!(value & SpecCell) && !(value & ~SpecCell); } +inline bool isNotCellSpeculation(SpeculatedType value) +{ + return !(value & SpecCell) && value; +} + inline bool isObjectSpeculation(SpeculatedType value) { return !!(value & SpecObject) && !(value & ~SpecObject); @@ -133,6 +142,11 @@ inline bool isStringSpeculation(SpeculatedType value) return !!value && (value & SpecString) == value; } +inline bool isSymbolSpeculation(SpeculatedType value) +{ + return value == SpecSymbol; +} + inline bool isArraySpeculation(SpeculatedType value) { return value == SpecArray; @@ -188,9 +202,14 @@ inline bool isFloat64ArraySpeculation(SpeculatedType value) return value == SpecFloat64Array; } -inline bool isArgumentsSpeculation(SpeculatedType value) +inline bool isDirectArgumentsSpeculation(SpeculatedType value) { - return !!value && (value & SpecArguments) == value; + return value == SpecDirectArguments; +} + +inline bool isScopedArgumentsSpeculation(SpeculatedType value) +{ + return value == SpecScopedArguments; } inline bool isActionableIntMutableArraySpeculation(SpeculatedType value) @@ -219,13 +238,14 @@ inline bool isActionableTypedMutableArraySpeculation(SpeculatedType value) inline bool isActionableMutableArraySpeculation(SpeculatedType value) { return isArraySpeculation(value) - || isArgumentsSpeculation(value) || isActionableTypedMutableArraySpeculation(value); } inline bool isActionableArraySpeculation(SpeculatedType value) { return isStringSpeculation(value) + || isDirectArgumentsSpeculation(value) + || isScopedArgumentsSpeculation(value) || isActionableMutableArraySpeculation(value); } @@ -244,9 +264,14 @@ inline bool isStringOrStringObjectSpeculation(SpeculatedType value) return !!value && !(value & ~(SpecString | SpecStringObject)); } +inline bool isBoolInt32Speculation(SpeculatedType value) +{ + return value == SpecBoolInt32; +} + inline bool isInt32Speculation(SpeculatedType value) { - return value == SpecInt32; + return value && !(value & ~SpecInt32); } inline bool isInt32OrBooleanSpeculation(SpeculatedType value) @@ -410,7 +435,8 @@ SpeculatedType typeOfDoubleQuotient(SpeculatedType, SpeculatedType); SpeculatedType typeOfDoubleMinMax(SpeculatedType, SpeculatedType); SpeculatedType typeOfDoubleNegation(SpeculatedType); SpeculatedType typeOfDoubleAbs(SpeculatedType); -SpeculatedType typeOfDoubleFRound(SpeculatedType); +SpeculatedType typeOfDoubleRounding(SpeculatedType); +SpeculatedType typeOfDoublePow(SpeculatedType, SpeculatedType); // This conservatively models the behavior of arbitrary double operations. SpeculatedType typeOfDoubleBinaryOp(SpeculatedType, SpeculatedType); diff --git a/bytecode/StructureSet.cpp b/bytecode/StructureSet.cpp new file mode 100644 index 0000000..40fea8d --- /dev/null +++ b/bytecode/StructureSet.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014, 2015 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 "StructureSet.h" + +#include "DFGAbstractValue.h" +#include "TrackedReferences.h" +#include <wtf/CommaPrinter.h> + +namespace JSC { + +#if ENABLE(DFG_JIT) + +void StructureSet::filter(const DFG::StructureAbstractValue& other) +{ + genericFilter([&] (Structure* structure) -> bool { return other.contains(structure); }); +} + +void StructureSet::filter(SpeculatedType type) +{ + genericFilter( + [&] (Structure* structure) -> bool { + return type & speculationFromStructure(structure); + }); +} + +void StructureSet::filterArrayModes(ArrayModes arrayModes) +{ + genericFilter( + [&] (Structure* structure) -> bool { + return arrayModes & arrayModeFromStructure(structure); + }); +} + +void StructureSet::filter(const DFG::AbstractValue& other) +{ + filter(other.m_structure); + filter(other.m_type); + filterArrayModes(other.m_arrayModes); +} + +#endif // ENABLE(DFG_JIT) + +SpeculatedType StructureSet::speculationFromStructures() const +{ + SpeculatedType result = SpecNone; + forEach( + [&] (Structure* structure) { + mergeSpeculation(result, speculationFromStructure(structure)); + }); + return result; +} + +ArrayModes StructureSet::arrayModesFromStructures() const +{ + ArrayModes result = 0; + forEach( + [&] (Structure* structure) { + mergeArrayModes(result, asArrayModes(structure->indexingType())); + }); + return result; +} + +void StructureSet::dumpInContext(PrintStream& out, DumpContext* context) const +{ + CommaPrinter comma; + out.print("["); + forEach([&] (Structure* structure) { out.print(comma, inContext(*structure, context)); }); + out.print("]"); +} + +void StructureSet::dump(PrintStream& out) const +{ + dumpInContext(out, nullptr); +} + +void StructureSet::validateReferences(const TrackedReferences& trackedReferences) const +{ + forEach( + [&] (Structure* structure) { + trackedReferences.check(structure); + }); +} + +} // namespace JSC + diff --git a/bytecode/StructureSet.h b/bytecode/StructureSet.h index d7087b9..df19ec5 100644 --- a/bytecode/StructureSet.h +++ b/bytecode/StructureSet.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,170 +27,60 @@ #define StructureSet_h #include "ArrayProfile.h" +#include "DumpContext.h" #include "SpeculatedType.h" #include "Structure.h" -#include "DumpContext.h" -#include <wtf/CommaPrinter.h> -#include <wtf/Vector.h> +#include <wtf/TinyPtrSet.h> namespace JSC { +class TrackedReferences; + namespace DFG { class StructureAbstractValue; +struct AbstractValue; } -class StructureSet { +class StructureSet : public TinyPtrSet<Structure*> { public: - StructureSet() { } - - StructureSet(Structure* structure) - { - ASSERT(structure); - m_structures.append(structure); - } - - void clear() - { - m_structures.clear(); - } - - void add(Structure* structure) - { - ASSERT(structure); - ASSERT(!contains(structure)); - m_structures.append(structure); - } - - bool addAll(const StructureSet& other) - { - bool changed = false; - for (size_t i = 0; i < other.size(); ++i) { - if (contains(other[i])) - continue; - add(other[i]); - changed = true; - } - return changed; - } - - void remove(Structure* structure) - { - for (size_t i = 0; i < m_structures.size(); ++i) { - if (m_structures[i] != structure) - continue; - - m_structures[i] = m_structures.last(); - m_structures.removeLast(); - return; - } - } - - bool contains(Structure* structure) const - { - for (size_t i = 0; i < m_structures.size(); ++i) { - if (m_structures[i] == structure) - return true; - } - return false; - } + // I really want to do this: + // using TinyPtrSet::TinyPtrSet; + // + // But I can't because Windows. - bool containsOnly(Structure* structure) const + StructureSet() { - if (size() != 1) - return false; - return singletonStructure() == structure; } - bool isSubsetOf(const StructureSet& other) const - { - for (size_t i = 0; i < m_structures.size(); ++i) { - if (!other.contains(m_structures[i])) - return false; - } - return true; - } - - bool isSupersetOf(const StructureSet& other) const - { - return other.isSubsetOf(*this); - } - - bool overlaps(const StructureSet& other) const - { - for (size_t i = 0; i < m_structures.size(); ++i) { - if (other.contains(m_structures[i])) - return true; - } - return false; - } - - size_t size() const { return m_structures.size(); } - - // Call this if you know that the structure set must consist of exactly - // one structure. - Structure* singletonStructure() const - { - ASSERT(m_structures.size() == 1); - return m_structures[0]; - } - - Structure* at(size_t i) const { return m_structures.at(i); } - - Structure* operator[](size_t i) const { return at(i); } - - Structure* last() const { return m_structures.last(); } - - SpeculatedType speculationFromStructures() const + StructureSet(Structure* structure) + : TinyPtrSet(structure) { - SpeculatedType result = SpecNone; - - for (size_t i = 0; i < m_structures.size(); ++i) - mergeSpeculation(result, speculationFromStructure(m_structures[i])); - - return result; } - ArrayModes arrayModesFromStructures() const + ALWAYS_INLINE StructureSet(const StructureSet& other) + : TinyPtrSet(other) { - ArrayModes result = 0; - - for (size_t i = 0; i < m_structures.size(); ++i) - mergeArrayModes(result, asArrayModes(m_structures[i]->indexingType())); - - return result; } - bool operator==(const StructureSet& other) const + Structure* onlyStructure() const { - if (m_structures.size() != other.m_structures.size()) - return false; - - for (size_t i = 0; i < m_structures.size(); ++i) { - if (!other.contains(m_structures[i])) - return false; - } - - return true; + return onlyEntry(); } - void dumpInContext(PrintStream& out, DumpContext* context) const - { - CommaPrinter comma; - out.print("["); - for (size_t i = 0; i < m_structures.size(); ++i) - out.print(comma, inContext(*m_structures[i], context)); - out.print("]"); - } +#if ENABLE(DFG_JIT) + void filter(const DFG::StructureAbstractValue&); + void filter(SpeculatedType); + void filterArrayModes(ArrayModes); + void filter(const DFG::AbstractValue&); +#endif // ENABLE(DFG_JIT) - void dump(PrintStream& out) const - { - dumpInContext(out, 0); - } + SpeculatedType speculationFromStructures() const; + ArrayModes arrayModesFromStructures() const; -private: - friend class DFG::StructureAbstractValue; + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; - Vector<Structure*, 2> m_structures; + void validateReferences(const TrackedReferences&) const; }; } // namespace JSC diff --git a/bytecode/StructureStubClearingWatchpoint.cpp b/bytecode/StructureStubClearingWatchpoint.cpp index 9521fec..f08460d 100644 --- a/bytecode/StructureStubClearingWatchpoint.cpp +++ b/bytecode/StructureStubClearingWatchpoint.cpp @@ -38,13 +38,13 @@ StructureStubClearingWatchpoint::~StructureStubClearingWatchpoint() { } StructureStubClearingWatchpoint* StructureStubClearingWatchpoint::push( WatchpointsOnStructureStubInfo& holder, - OwnPtr<StructureStubClearingWatchpoint>& head) + std::unique_ptr<StructureStubClearingWatchpoint>& head) { - head = adoptPtr(new StructureStubClearingWatchpoint(holder, head.release())); + head = std::make_unique<StructureStubClearingWatchpoint>(holder, WTF::move(head)); return head.get(); } -void StructureStubClearingWatchpoint::fireInternal() +void StructureStubClearingWatchpoint::fireInternal(const FireDetail&) { // This will implicitly cause my own demise: stub reset removes all watchpoints. // That works, because deleting a watchpoint removes it from the set's list, and diff --git a/bytecode/StructureStubClearingWatchpoint.h b/bytecode/StructureStubClearingWatchpoint.h index 07a66b6..528e3ba 100644 --- a/bytecode/StructureStubClearingWatchpoint.h +++ b/bytecode/StructureStubClearingWatchpoint.h @@ -32,8 +32,6 @@ #include <wtf/FastMalloc.h> #include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -55,9 +53,9 @@ public: StructureStubClearingWatchpoint( WatchpointsOnStructureStubInfo& holder, - PassOwnPtr<StructureStubClearingWatchpoint> next) + std::unique_ptr<StructureStubClearingWatchpoint> next) : m_holder(holder) - , m_next(next) + , m_next(WTF::move(next)) { } @@ -65,14 +63,14 @@ public: static StructureStubClearingWatchpoint* push( WatchpointsOnStructureStubInfo& holder, - OwnPtr<StructureStubClearingWatchpoint>& head); + std::unique_ptr<StructureStubClearingWatchpoint>& head); protected: - virtual void fireInternal() override; + virtual void fireInternal(const FireDetail&) override; private: WatchpointsOnStructureStubInfo& m_holder; - OwnPtr<StructureStubClearingWatchpoint> m_next; + std::unique_ptr<StructureStubClearingWatchpoint> m_next; }; class WatchpointsOnStructureStubInfo : public RefCounted<WatchpointsOnStructureStubInfo> { @@ -97,7 +95,7 @@ public: private: CodeBlock* m_codeBlock; StructureStubInfo* m_stubInfo; - OwnPtr<StructureStubClearingWatchpoint> m_head; + std::unique_ptr<StructureStubClearingWatchpoint> m_head; }; } // namespace JSC diff --git a/bytecode/StructureStubInfo.cpp b/bytecode/StructureStubInfo.cpp index 4615a3c..5ea530c 100644 --- a/bytecode/StructureStubInfo.cpp +++ b/bytecode/StructureStubInfo.cpp @@ -49,7 +49,6 @@ void StructureStubInfo::deref() return; } case access_get_by_id_self: - case access_get_by_id_chain: case access_put_by_id_transition_normal: case access_put_by_id_transition_direct: case access_put_by_id_replace: @@ -68,11 +67,6 @@ bool StructureStubInfo::visitWeakReferences(RepatchBuffer& repatchBuffer) if (!Heap::isMarked(u.getByIdSelf.baseObjectStructure.get())) return false; break; - case access_get_by_id_chain: - if (!Heap::isMarked(u.getByIdChain.baseObjectStructure.get()) - || !Heap::isMarked(u.getByIdChain.chain.get())) - return false; - break; case access_get_by_id_list: { if (!u.getByIdList.list->visitWeak(repatchBuffer)) return false; diff --git a/bytecode/StructureStubInfo.h b/bytecode/StructureStubInfo.h index 0089966..d402ace 100644 --- a/bytecode/StructureStubInfo.h +++ b/bytecode/StructureStubInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,7 +36,6 @@ #include "SpillRegistersMode.h" #include "Structure.h" #include "StructureStubClearingWatchpoint.h" -#include <wtf/OwnPtr.h> namespace JSC { @@ -47,7 +46,6 @@ class PolymorphicPutByIdList; enum AccessType { access_get_by_id_self, - access_get_by_id_chain, access_get_by_id_list, access_put_by_id_transition_normal, access_put_by_id_transition_direct, @@ -61,7 +59,6 @@ inline bool isGetByIdAccess(AccessType accessType) { switch (accessType) { case access_get_by_id_self: - case access_get_by_id_chain: case access_get_by_id_list: return true; default: @@ -97,6 +94,7 @@ struct StructureStubInfo { : accessType(access_unset) , seen(false) , resetByGC(false) + , tookSlowPath(false) { } @@ -107,16 +105,6 @@ struct StructureStubInfo { u.getByIdSelf.baseObjectStructure.set(vm, owner, baseObjectStructure); } - void initGetByIdChain(VM& vm, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect) - { - accessType = access_get_by_id_chain; - - u.getByIdChain.baseObjectStructure.set(vm, owner, baseObjectStructure); - u.getByIdChain.chain.set(vm, owner, chain); - u.getByIdChain.count = count; - u.getByIdChain.isDirect = isDirect; - } - void initGetByIdList(PolymorphicGetByIdList* list) { accessType = access_get_by_id_list; @@ -161,8 +149,8 @@ struct StructureStubInfo { { deref(); accessType = access_unset; - stubRoutine.clear(); - watchpoints.clear(); + stubRoutine = nullptr; + watchpoints = nullptr; } void deref(); @@ -196,6 +184,7 @@ struct StructureStubInfo { int8_t accessType; bool seen : 1; bool resetByGC : 1; + bool tookSlowPath : 1; CodeOrigin codeOrigin; diff --git a/jit/ClosureCallStubRoutine.cpp b/bytecode/ToThisStatus.cpp similarity index 61% rename from jit/ClosureCallStubRoutine.cpp rename to bytecode/ToThisStatus.cpp index 3e9b268..23d1e08 100644 --- a/jit/ClosureCallStubRoutine.cpp +++ b/bytecode/ToThisStatus.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,40 +24,49 @@ */ #include "config.h" -#include "ClosureCallStubRoutine.h" - -#if ENABLE(JIT) - -#include "Executable.h" -#include "Heap.h" -#include "VM.h" -#include "JSCInlines.h" -#include "SlotVisitor.h" -#include "Structure.h" +#include "ToThisStatus.h" namespace JSC { -ClosureCallStubRoutine::ClosureCallStubRoutine( - const MacroAssemblerCodeRef& code, VM& vm, const JSCell* owner, - Structure* structure, ExecutableBase* executable, const CodeOrigin& codeOrigin) - : GCAwareJITStubRoutine(code, vm) - , m_structure(vm, owner, structure) - , m_executable(vm, owner, executable) - , m_codeOrigin(codeOrigin) +ToThisStatus merge(ToThisStatus a, ToThisStatus b) { + switch (a) { + case ToThisOK: + return b; + case ToThisConflicted: + return ToThisConflicted; + case ToThisClearedByGC: + if (b == ToThisConflicted) + return ToThisConflicted; + return ToThisClearedByGC; + } + + RELEASE_ASSERT_NOT_REACHED(); + return ToThisConflicted; } -ClosureCallStubRoutine::~ClosureCallStubRoutine() -{ -} +} // namespace JSC -void ClosureCallStubRoutine::markRequiredObjectsInternal(SlotVisitor& visitor) +namespace WTF { + +using namespace JSC; + +void printInternal(PrintStream& out, ToThisStatus status) { - visitor.append(&m_structure); - visitor.append(&m_executable); + switch (status) { + case ToThisOK: + out.print("OK"); + return; + case ToThisConflicted: + out.print("Conflicted"); + return; + case ToThisClearedByGC: + out.print("ClearedByGC"); + return; + } + + RELEASE_ASSERT_NOT_REACHED(); } -} // namespace JSC - -#endif // ENABLE(JIT) +} // namespace WTF diff --git a/bytecode/ToThisStatus.h b/bytecode/ToThisStatus.h new file mode 100644 index 0000000..55d707c --- /dev/null +++ b/bytecode/ToThisStatus.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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 ToThisStatus_h +#define ToThisStatus_h + +#include <wtf/PrintStream.h> + +namespace JSC { + +enum ToThisStatus { + ToThisOK, + ToThisConflicted, + ToThisClearedByGC +}; + +ToThisStatus merge(ToThisStatus, ToThisStatus); + +} // namespace JSC + +namespace WTF { + +void printInternal(PrintStream&, JSC::ToThisStatus); + +} // namespace WTF + +#endif // ToThisStatus_h + diff --git a/bytecode/TrackedReferences.cpp b/bytecode/TrackedReferences.cpp new file mode 100644 index 0000000..d98fa97 --- /dev/null +++ b/bytecode/TrackedReferences.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 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 "TrackedReferences.h" + +#include "JSCInlines.h" +#include <wtf/CommaPrinter.h> + +namespace JSC { + +TrackedReferences::TrackedReferences() +{ +} + +TrackedReferences::~TrackedReferences() +{ +} + +void TrackedReferences::add(JSCell* cell) +{ + if (cell) + m_references.add(cell); +} + +void TrackedReferences::add(JSValue value) +{ + if (value.isCell()) + add(value.asCell()); +} + +void TrackedReferences::check(JSCell* cell) const +{ + if (!cell) + return; + + if (m_references.contains(cell)) + return; + + dataLog("Found untracked reference: ", RawPointer(cell), "\n"); + dataLog("All tracked references: ", *this, "\n"); + RELEASE_ASSERT_NOT_REACHED(); +} + +void TrackedReferences::check(JSValue value) const +{ + if (value.isCell()) + check(value.asCell()); +} + +void TrackedReferences::dump(PrintStream& out) const +{ + CommaPrinter comma; + for (JSCell* cell : m_references) + out.print(comma, RawPointer(cell)); +} + +} // namespace JSC + diff --git a/bytecode/TrackedReferences.h b/bytecode/TrackedReferences.h new file mode 100644 index 0000000..cc15e1e --- /dev/null +++ b/bytecode/TrackedReferences.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 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 TrackedReferences_h +#define TrackedReferences_h + +#include "JSCJSValue.h" +#include "JSCell.h" +#include <wtf/HashSet.h> +#include <wtf/PrintStream.h> + +namespace JSC { + +class TrackedReferences { +public: + TrackedReferences(); + ~TrackedReferences(); + + void add(JSCell*); + void add(JSValue); + + void check(JSCell*) const; + void check(JSValue) const; + + void dump(PrintStream&) const; + +private: + HashSet<JSCell*> m_references; +}; + +} // namespace JSC + +#endif // TrackedReferences_h + diff --git a/bytecode/TypeLocation.h b/bytecode/TypeLocation.h new file mode 100644 index 0000000..ec07656 --- /dev/null +++ b/bytecode/TypeLocation.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 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 TypeLocation_h +#define TypeLocation_h + +#include "TypeSet.h" + +namespace JSC { + +enum TypeProfilerGlobalIDFlags { + TypeProfilerNeedsUniqueIDGeneration = -1, + TypeProfilerNoGlobalIDExists = -2, + TypeProfilerReturnStatement = -3 +}; + +typedef intptr_t GlobalVariableID; + +class TypeLocation { +public: + TypeLocation() + : m_lastSeenType(TypeNothing) + , m_divotForFunctionOffsetIfReturnStatement(UINT_MAX) + , m_instructionTypeSet(TypeSet::create()) + , m_globalTypeSet(nullptr) + { + } + + GlobalVariableID m_globalVariableID; + RuntimeType m_lastSeenType; + intptr_t m_sourceID; + unsigned m_divotStart; + unsigned m_divotEnd; + unsigned m_divotForFunctionOffsetIfReturnStatement; + RefPtr<TypeSet> m_instructionTypeSet; + RefPtr<TypeSet> m_globalTypeSet; +}; + +} //namespace JSC + +#endif //TypeLocation_h diff --git a/bytecode/UnlinkedCodeBlock.cpp b/bytecode/UnlinkedCodeBlock.cpp index 5c2cc5f..e262bc5 100644 --- a/bytecode/UnlinkedCodeBlock.cpp +++ b/bytecode/UnlinkedCodeBlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2012, 2013, 2015 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 @@ #include "ClassInfo.h" #include "CodeCache.h" #include "Executable.h" +#include "FunctionOverrides.h" #include "JSString.h" #include "JSCInlines.h" #include "Parser.h" @@ -42,56 +43,49 @@ namespace JSC { -const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) }; -const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) }; -const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) }; -const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) }; -const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) }; -const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) }; +static_assert(sizeof(UnlinkedFunctionExecutable) <= 128, "UnlinkedFunctionExecutable should fit in a 128-byte cell."); -static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source, CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, UnlinkedFunctionKind functionKind, bool bodyIncludesBraces, ParserError& error) -{ - RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(&vm, source, executable->parameters(), executable->name(), executable->toStrictness(), JSParseFunctionCode, error, 0, bodyIncludesBraces); +const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) }; +const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) }; +const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) }; +const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) }; +const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) }; +const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) }; - if (!body) { - ASSERT(error.m_type != ParserError::ErrorNone); - return 0; +static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock( + VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source, + CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode, + UnlinkedFunctionKind functionKind, ParserError& error) +{ + JSParserBuiltinMode builtinMode = executable->isBuiltinFunction() ? JSParserBuiltinMode::Builtin : JSParserBuiltinMode::NotBuiltin; + JSParserStrictMode strictMode = executable->isInStrictContext() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict; + std::unique_ptr<FunctionNode> function = parse<FunctionNode>( + &vm, source, executable->parameters(), executable->name(), builtinMode, + strictMode, JSParserCodeType::Function, error, 0); + + if (!function) { + ASSERT(error.isValid()); + return nullptr; } - if (executable->forceUsesArguments()) - body->setUsesArguments(); - body->finishParsing(executable->parameters(), executable->name(), executable->functionMode()); - executable->recordParse(body->features(), body->hasCapturedVariables()); + function->finishParsing(executable->parameters(), executable->name(), executable->functionMode()); + executable->recordParse(function->features(), function->hasCapturedVariables()); - UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode, ExecutableInfo(body->needsActivation(), body->usesEval(), body->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction)); - OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, body.get(), result, debuggerMode, profilerMode))); + UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode, + ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind())); + auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode)); error = generator->generate(); - body->destroyData(); - if (error.m_type != ParserError::ErrorNone) - return 0; + if (error.isValid()) + return nullptr; return result; } -unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v) -{ - unsigned numberOfConstants = numberOfConstantRegisters(); - for (unsigned i = 0; i < numberOfConstants; ++i) { - if (getConstant(FirstConstantRegisterIndex + i) == v) - return i; - } - return addConstant(v); -} - -UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind kind) +UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode* node, UnlinkedFunctionKind kind) : Base(*vm, structure) - , m_numCapturedVariables(node->capturedVariableCount()) - , m_forceUsesArguments(node->usesArguments()) - , m_isInStrictContext(node->isStrictMode()) - , m_hasCapturedVariables(node->hasCapturedVariables()) - , m_isBuiltinFunction(kind == UnlinkedBuiltinFunction) , m_name(node->ident()) , m_inferredName(node->inferredName()) , m_parameters(node->parameters()) + , m_sourceOverride(WTF::move(sourceOverride)) , m_firstLineOffset(node->firstLine() - source.firstLine()) , m_lineCount(node->lastLine() - node->firstLine()) , m_unlinkedFunctionNameStart(node->functionNameStart() - source.startOffset()) @@ -99,9 +93,17 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct , m_unlinkedBodyEndColumn(m_lineCount ? node->endColumn() : node->endColumn() - node->startColumn()) , m_startOffset(node->source().startOffset() - source.startOffset()) , m_sourceLength(node->source().length()) - , m_features(node->features()) + , m_parametersStartOffset(node->parametersStart()) + , m_typeProfilingStartOffset(node->functionKeywordStart()) + , m_typeProfilingEndOffset(node->startStartOffset() + node->source().length() - 1) + , m_features(0) + , m_isInStrictContext(node->isInStrictContext()) + , m_hasCapturedVariables(false) + , m_isBuiltinFunction(kind == UnlinkedBuiltinFunction) + , m_constructorKind(static_cast<unsigned>(node->constructorKind())) , m_functionMode(node->functionMode()) { + ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind())); } size_t UnlinkedFunctionExecutable::parameterCount() const @@ -113,8 +115,6 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito { UnlinkedFunctionExecutable* thisObject = jsCast<UnlinkedFunctionExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_codeBlockForCall); visitor.append(&thisObject->m_codeBlockForConstruct); @@ -123,36 +123,72 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito visitor.append(&thisObject->m_symbolTableForConstruct); } -FunctionExecutable* UnlinkedFunctionExecutable::link(VM& vm, const SourceCode& source, size_t lineOffset) +FunctionExecutable* UnlinkedFunctionExecutable::link(VM& vm, const SourceCode& ownerSource, int overrideLineNumber) { - unsigned firstLine = lineOffset + m_firstLineOffset; + SourceCode source = m_sourceOverride ? SourceCode(m_sourceOverride) : ownerSource; + unsigned firstLine = source.firstLine() + m_firstLineOffset; + unsigned startOffset = source.startOffset() + m_startOffset; + unsigned lineCount = m_lineCount; + + // Adjust to one-based indexing. bool startColumnIsOnFirstSourceLine = !m_firstLineOffset; unsigned startColumn = m_unlinkedBodyStartColumn + (startColumnIsOnFirstSourceLine ? source.startColumn() : 1); - bool endColumnIsOnStartLine = !m_lineCount; + bool endColumnIsOnStartLine = !lineCount; unsigned endColumn = m_unlinkedBodyEndColumn + (endColumnIsOnStartLine ? startColumn : 1); - SourceCode code(source.provider(), m_startOffset, m_startOffset + m_sourceLength, firstLine, startColumn); - return FunctionExecutable::create(vm, code, this, firstLine, firstLine + m_lineCount, startColumn, endColumn); + + SourceCode code(source.provider(), startOffset, startOffset + m_sourceLength, firstLine, startColumn); + FunctionOverrides::OverrideInfo overrideInfo; + bool hasFunctionOverride = false; + + if (UNLIKELY(Options::functionOverrides())) { + hasFunctionOverride = FunctionOverrides::initializeOverrideFor(code, overrideInfo); + if (hasFunctionOverride) { + firstLine = overrideInfo.firstLine; + lineCount = overrideInfo.lineCount; + startColumn = overrideInfo.startColumn; + endColumn = overrideInfo.endColumn; + code = overrideInfo.sourceCode; + } + } + + FunctionExecutable* result = FunctionExecutable::create(vm, code, this, firstLine, firstLine + lineCount, startColumn, endColumn); + if (overrideLineNumber != -1) + result->setOverrideLineNumber(overrideLineNumber); + + if (UNLIKELY(hasFunctionOverride)) { + result->overrideParameterAndTypeProfilingStartEndOffsets( + overrideInfo.parametersStartOffset, + overrideInfo.typeProfilingStartOffset, + overrideInfo.typeProfilingEndOffset); + } + + return result; } -UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger*, const SourceCode& source, JSObject** exception) +UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode( + const Identifier& name, ExecState& exec, const SourceCode& source, + JSObject*& exception, int overrideLineNumber) { ParserError error; - VM& vm = exec->vm(); + VM& vm = exec.vm(); CodeCache* codeCache = vm.codeCache(); UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(vm, name, source, error); - if (exec->lexicalGlobalObject()->hasDebugger()) - exec->lexicalGlobalObject()->debugger()->sourceParsed(exec, source.provider(), error.m_line, error.m_message); + auto& globalObject = *exec.lexicalGlobalObject(); + if (globalObject.hasDebugger()) + globalObject.debugger()->sourceParsed(&exec, source.provider(), error.line(), error.message()); - if (error.m_type != ParserError::ErrorNone) { - *exception = error.toErrorObject(exec->lexicalGlobalObject(), source); - return 0; + if (error.isValid()) { + exception = error.toErrorObject(&globalObject, source, overrideLineNumber); + return nullptr; } return executable; } -UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, bool bodyIncludesBraces, ParserError& error) +UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor( + VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, + DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) { switch (specializationKind) { case CodeForCall: @@ -165,10 +201,13 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(VM& vm, cons break; } - UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(vm, this, source, specializationKind, debuggerMode, profilerMode, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, bodyIncludesBraces, error); + UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock( + vm, this, source, specializationKind, debuggerMode, profilerMode, + isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, + error); - if (error.m_type != ParserError::ErrorNone) - return 0; + if (error.isValid()) + return nullptr; switch (specializationKind) { case CodeForCall: @@ -183,33 +222,20 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(VM& vm, cons return result; } -String UnlinkedFunctionExecutable::paramString() const -{ - FunctionParameters& parameters = *m_parameters; - StringBuilder builder; - for (size_t pos = 0; pos < parameters.size(); ++pos) { - if (!builder.isEmpty()) - builder.appendLiteral(", "); - parameters.at(pos)->toString(builder); - } - return builder.toString(); -} - UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info) : Base(*vm, structure) , m_numVars(0) , m_numCalleeRegisters(0) , m_numParameters(0) , m_vm(vm) - , m_argumentsRegister(VirtualRegister()) , m_globalObjectRegister(VirtualRegister()) - , m_needsFullScopeChain(info.m_needsActivation) - , m_usesEval(info.m_usesEval) - , m_isNumericCompareFunction(false) - , m_isStrictMode(info.m_isStrictMode) - , m_isConstructor(info.m_isConstructor) + , m_needsFullScopeChain(info.needsActivation()) + , m_usesEval(info.usesEval()) + , m_isStrictMode(info.isStrictMode()) + , m_isConstructor(info.isConstructor()) , m_hasCapturedVariables(false) - , m_isBuiltinFunction(info.m_isBuiltinFunction) + , m_isBuiltinFunction(info.isBuiltinFunction()) + , m_constructorKind(static_cast<unsigned>(info.constructorKind())) , m_firstLine(0) , m_lineCount(0) , m_endColumn(UINT_MAX) @@ -224,15 +250,15 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code , m_bytecodeCommentIterator(0) #endif { - + for (auto& constantRegisterIndex : m_linkTimeConstants) + constantRegisterIndex = 0; + ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind())); } void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) { UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); visitor.append(&thisObject->m_symbolTable); for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr) @@ -404,15 +430,37 @@ void UnlinkedCodeBlock::addExpressionInfo(unsigned instructionOffset, m_expressionInfo.append(info); } +bool UnlinkedCodeBlock::typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot) +{ + static const bool verbose = false; + auto iter = m_typeProfilerInfoMap.find(bytecodeOffset); + if (iter == m_typeProfilerInfoMap.end()) { + if (verbose) + dataLogF("Don't have assignment info for offset:%u\n", bytecodeOffset); + startDivot = UINT_MAX; + endDivot = UINT_MAX; + return false; + } + + TypeProfilerExpressionRange& range = iter->value; + startDivot = range.m_startDivot; + endDivot = range.m_endDivot; + return true; +} + +void UnlinkedCodeBlock::addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot) +{ + TypeProfilerExpressionRange range; + range.m_startDivot = startDivot; + range.m_endDivot = endDivot; + m_typeProfilerInfoMap.set(instructionOffset, range); +} + void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) { UnlinkedProgramCodeBlock* thisObject = jsCast<UnlinkedProgramCodeBlock*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); - for (size_t i = 0, end = thisObject->m_functionDeclarations.size(); i != end; i++) - visitor.append(&thisObject->m_functionDeclarations[i].second); } UnlinkedCodeBlock::~UnlinkedCodeBlock() diff --git a/bytecode/UnlinkedCodeBlock.h b/bytecode/UnlinkedCodeBlock.h index 38e793d..7904424 100644 --- a/bytecode/UnlinkedCodeBlock.h +++ b/bytecode/UnlinkedCodeBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved. + * Copyright (C) 2012-2015 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,7 @@ #include "CodeSpecializationKind.h" #include "CodeType.h" #include "ExpressionRangeInfo.h" +#include "HandlerInfo.h" #include "Identifier.h" #include "JSCell.h" #include "JSString.h" @@ -39,7 +40,6 @@ #include "SymbolTable.h" #include "VirtualRegister.h" -#include <wtf/Compression.h> #include <wtf/RefCountedArray.h> #include <wtf/Vector.h> @@ -50,7 +50,7 @@ class FunctionBodyNode; class FunctionExecutable; class FunctionParameters; class JSScope; -struct ParserError; +class ParserError; class ScriptExecutable; class SourceCode; class SourceProvider; @@ -66,19 +66,31 @@ typedef unsigned UnlinkedObjectAllocationProfile; typedef unsigned UnlinkedLLIntCallLinkInfo; struct ExecutableInfo { - ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction) + ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind) : m_needsActivation(needsActivation) , m_usesEval(usesEval) , m_isStrictMode(isStrictMode) , m_isConstructor(isConstructor) , m_isBuiltinFunction(isBuiltinFunction) + , m_constructorKind(static_cast<unsigned>(constructorKind)) { + ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind)); } - bool m_needsActivation : 1; - bool m_usesEval : 1; - bool m_isStrictMode : 1; - bool m_isConstructor : 1; - bool m_isBuiltinFunction : 1; + + bool needsActivation() const { return m_needsActivation; } + bool usesEval() const { return m_usesEval; } + bool isStrictMode() const { return m_isStrictMode; } + bool isConstructor() const { return m_isConstructor; } + bool isBuiltinFunction() const { return m_isBuiltinFunction; } + ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); } + +private: + unsigned m_needsActivation : 1; + unsigned m_usesEval : 1; + unsigned m_isStrictMode : 1; + unsigned m_isConstructor : 1; + unsigned m_isBuiltinFunction : 1; + unsigned m_constructorKind : 2; }; enum UnlinkedFunctionKind { @@ -86,15 +98,19 @@ enum UnlinkedFunctionKind { UnlinkedBuiltinFunction, }; -class UnlinkedFunctionExecutable : public JSCell { +class UnlinkedFunctionExecutable final : public JSCell { public: friend class BuiltinExecutables; friend class CodeCache; friend class VM; + typedef JSCell Base; - static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind unlinkedFunctionKind) + static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; + + static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind unlinkedFunctionKind, RefPtr<SourceProvider>&& sourceOverride = nullptr) { - UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap)) UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind); + UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap)) + UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind); instance->finishCreation(*vm); return instance; } @@ -108,31 +124,27 @@ public: } size_t parameterCount() const; bool isInStrictContext() const { return m_isInStrictContext; } - FunctionMode functionMode() const { return m_functionMode; } - JSParserStrictness toStrictness() const - { - if (m_isBuiltinFunction) - return JSParseBuiltin; - if (m_isInStrictContext) - return JSParseStrict; - return JSParseNormal; - } + FunctionMode functionMode() const { return static_cast<FunctionMode>(m_functionMode); } + ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); } - unsigned firstLineOffset() const { return m_firstLineOffset; } - unsigned lineCount() const { return m_lineCount; } unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; } unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; } unsigned unlinkedBodyEndColumn() const { return m_unlinkedBodyEndColumn; } unsigned startOffset() const { return m_startOffset; } unsigned sourceLength() { return m_sourceLength; } + unsigned parametersStartOffset() const { return m_parametersStartOffset; } + unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } + unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } - String paramString() const; - - UnlinkedFunctionCodeBlock* codeBlockFor(VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, bool bodyIncludesBraces, ParserError&); + UnlinkedFunctionCodeBlock* codeBlockFor( + VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, + ParserError&); - static UnlinkedFunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); + static UnlinkedFunctionExecutable* fromGlobalCode( + const Identifier&, ExecState&, const SourceCode&, JSObject*& exception, + int overrideLineNumber); - FunctionExecutable* link(VM&, const SourceCode&, size_t lineOffset); + FunctionExecutable* link(VM&, const SourceCode&, int overrideLineNumber = -1); void clearCodeForRecompilation() { @@ -150,34 +162,27 @@ public: m_hasCapturedVariables = hasCapturedVariables; } - bool forceUsesArguments() const { return m_forceUsesArguments; } - CodeFeatures features() const { return m_features; } bool hasCapturedVariables() const { return m_hasCapturedVariables; } static const bool needsDestruction = true; - static const bool hasImmortalStructure = true; static void destroy(JSCell*); bool isBuiltinFunction() const { return m_isBuiltinFunction; } + bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; } private: - UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionBodyNode*, UnlinkedFunctionKind); + UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode*, UnlinkedFunctionKind); WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall; WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct; - unsigned m_numCapturedVariables : 29; - bool m_forceUsesArguments : 1; - bool m_isInStrictContext : 1; - bool m_hasCapturedVariables : 1; - bool m_isBuiltinFunction : 1; - Identifier m_name; Identifier m_inferredName; WriteBarrier<JSString> m_nameValue; WriteBarrier<SymbolTable> m_symbolTableForCall; WriteBarrier<SymbolTable> m_symbolTableForConstruct; RefPtr<FunctionParameters> m_parameters; + RefPtr<SourceProvider> m_sourceOverride; unsigned m_firstLineOffset; unsigned m_lineCount; unsigned m_unlinkedFunctionNameStart; @@ -185,10 +190,17 @@ private: unsigned m_unlinkedBodyEndColumn; unsigned m_startOffset; unsigned m_sourceLength; + unsigned m_parametersStartOffset; + unsigned m_typeProfilingStartOffset; + unsigned m_typeProfilingEndOffset; CodeFeatures m_features; - FunctionMode m_functionMode; + unsigned m_isInStrictContext : 1; + unsigned m_hasCapturedVariables : 1; + unsigned m_isBuiltinFunction : 1; + unsigned m_constructorKind : 2; + unsigned m_functionMode : 1; // FunctionMode protected: void finishCreation(VM& vm) @@ -205,8 +217,6 @@ public: return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedFunctionExecutableType, StructureFlags), info()); } - static const unsigned StructureFlags = OverridesVisitChildren | StructureIsImmortal | JSCell::StructureFlags; - DECLARE_EXPORT_INFO; }; @@ -237,13 +247,6 @@ struct UnlinkedSimpleJumpTable { } }; -struct UnlinkedHandlerInfo { - uint32_t start; - uint32_t end; - uint32_t target; - uint32_t scopeDepth; -}; - struct UnlinkedInstruction { UnlinkedInstruction() { u.operand = 0; } UnlinkedInstruction(OpcodeID opcode) { u.opcode = opcode; } @@ -258,8 +261,9 @@ struct UnlinkedInstruction { class UnlinkedCodeBlock : public JSCell { public: typedef JSCell Base; + static const unsigned StructureFlags = Base::StructureFlags; + static const bool needsDestruction = true; - static const bool hasImmortalStructure = true; enum { CallFunction, ApplyFunction }; @@ -272,16 +276,14 @@ public: void addExpressionInfo(unsigned instructionOffset, int divot, int startOffset, int endOffset, unsigned line, unsigned column); + void addTypeProfilerExpressionInfo(unsigned instructionOffset, unsigned startDivot, unsigned endDivot); + bool hasExpressionInfo() { return m_expressionInfo.size(); } // Special registers void setThisRegister(VirtualRegister thisRegister) { m_thisRegister = thisRegister; } - void setActivationRegister(VirtualRegister activationRegister) { m_activationRegister = activationRegister; } - - void setArgumentsRegister(VirtualRegister argumentsRegister) { m_argumentsRegister = argumentsRegister; } - bool usesArguments() const { return m_argumentsRegister.isValid(); } - VirtualRegister argumentsRegister() const { return m_argumentsRegister; } - + void setScopeRegister(VirtualRegister scopeRegister) { m_scopeRegister = scopeRegister; } + void setActivationRegister(VirtualRegister activationRegister) { m_lexicalEnvironmentRegister = activationRegister; } bool usesGlobalObject() const { return m_globalObjectRegister.isValid(); } void setGlobalObjectRegister(VirtualRegister globalObjectRegister) { m_globalObjectRegister = globalObjectRegister; } @@ -314,19 +316,35 @@ public: const Identifier& identifier(int index) const { return m_identifiers[index]; } const Vector<Identifier>& identifiers() const { return m_identifiers; } - size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } - unsigned addConstant(JSValue v) + unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other) { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier<Unknown>()); m_constantRegisters.last().set(*m_vm, this, v); + m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation); + return result; + } + unsigned addConstant(LinkTimeConstant type) + { + unsigned result = m_constantRegisters.size(); + ASSERT(result); + unsigned index = static_cast<unsigned>(type); + ASSERT(index < LinkTimeConstantCount); + m_linkTimeConstants[index] = result; + m_constantRegisters.append(WriteBarrier<Unknown>()); + m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); return result; } - unsigned addOrFindConstant(JSValue); + unsigned registerIndexForLinkTimeConstant(LinkTimeConstant type) + { + unsigned index = static_cast<unsigned>(type); + ASSERT(index < LinkTimeConstantCount); + return m_linkTimeConstants[index]; + } const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; } const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; } ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } - ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } + const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; } // Jumps size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } @@ -334,16 +352,16 @@ public: unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } unsigned lastJumpTarget() const { return m_jumpTargets.last(); } - void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } - bool isNumericCompareFunction() const { return m_isNumericCompareFunction; } - bool isBuiltinFunction() const { return m_isBuiltinFunction; } - + + ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); } + void shrinkToFit() { m_jumpTargets.shrinkToFit(); m_identifiers.shrinkToFit(); m_constantRegisters.shrinkToFit(); + m_constantsSourceCodeRepresentation.shrinkToFit(); m_functionDecls.shrinkToFit(); m_functionExprs.shrinkToFit(); m_propertyAccessInstructions.shrinkToFit(); @@ -400,7 +418,7 @@ public: // Exception handling support size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } - void addExceptionHandler(const UnlinkedHandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } + void addExceptionHandler(const UnlinkedHandlerInfo& handler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(handler); } UnlinkedHandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } SymbolTable* symbolTable() const { return m_symbolTable.get(); } @@ -423,8 +441,9 @@ public: CodeType codeType() const { return m_codeType; } VirtualRegister thisRegister() const { return m_thisRegister; } - VirtualRegister activationRegister() const { return m_activationRegister; } - bool hasActivationRegister() const { return m_activationRegister.isValid(); } + VirtualRegister scopeRegister() const { return m_scopeRegister; } + VirtualRegister activationRegister() const { return m_lexicalEnvironmentRegister; } + bool hasActivationRegister() const { return m_lexicalEnvironmentRegister.isValid(); } void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { @@ -457,13 +476,15 @@ public: return m_rareData->m_constantBuffers[index]; } - bool hasRareData() const { return m_rareData; } + bool hasRareData() const { return m_rareData.get(); } int lineNumberForBytecodeOffset(unsigned bytecodeOffset); void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column); + bool typeProfilerExpressionInfoForBytecodeOffset(unsigned bytecodeOffset, unsigned& startDivot, unsigned& endDivot); + void recordParse(CodeFeatures features, bool hasCapturedVariables, unsigned firstLine, unsigned lineCount, unsigned endColumn) { m_features = features; @@ -481,6 +502,9 @@ public: ALWAYS_INLINE unsigned startColumn() const { return 0; } unsigned endColumn() const { return m_endColumn; } + void addOpProfileControlFlowBytecodeOffset(size_t offset) { m_opProfileControlFlowBytecodeOffsets.append(offset); } + const Vector<size_t>& opProfileControlFlowBytecodeOffsets() const { return m_opProfileControlFlowBytecodeOffsets; } + void dumpExpressionRangeInfo(); // For debugging purpose only. protected: @@ -500,7 +524,7 @@ private: void createRareDataIfNecessary() { if (!m_rareData) - m_rareData = adoptPtr(new RareData); + m_rareData = std::make_unique<RareData>(); } void getLineAndColumn(ExpressionRangeInfo&, unsigned& line, unsigned& column); @@ -511,17 +535,18 @@ private: VM* m_vm; VirtualRegister m_thisRegister; - VirtualRegister m_argumentsRegister; - VirtualRegister m_activationRegister; + VirtualRegister m_scopeRegister; + VirtualRegister m_lexicalEnvironmentRegister; VirtualRegister m_globalObjectRegister; - bool m_needsFullScopeChain : 1; - bool m_usesEval : 1; - bool m_isNumericCompareFunction : 1; - bool m_isStrictMode : 1; - bool m_isConstructor : 1; - bool m_hasCapturedVariables : 1; - bool m_isBuiltinFunction : 1; + unsigned m_needsFullScopeChain : 1; + unsigned m_usesEval : 1; + unsigned m_isStrictMode : 1; + unsigned m_isConstructor : 1; + unsigned m_hasCapturedVariables : 1; + unsigned m_isBuiltinFunction : 1; + unsigned m_constructorKind : 2; + unsigned m_firstLine; unsigned m_lineCount; unsigned m_endColumn; @@ -534,6 +559,8 @@ private: // Constant Pools Vector<Identifier> m_identifiers; Vector<WriteBarrier<Unknown>> m_constantRegisters; + Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; + std::array<unsigned, LinkTimeConstantCount> m_linkTimeConstants; typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector; FunctionExpressionVector m_functionDecls; FunctionExpressionVector m_functionExprs; @@ -573,12 +600,16 @@ public: }; private: - OwnPtr<RareData> m_rareData; + std::unique_ptr<RareData> m_rareData; Vector<ExpressionRangeInfo> m_expressionInfo; + struct TypeProfilerExpressionRange { + unsigned m_startDivot; + unsigned m_endDivot; + }; + HashMap<unsigned, TypeProfilerExpressionRange> m_typeProfilerInfoMap; + Vector<size_t> m_opProfileControlFlowBytecodeOffsets; protected: - - static const unsigned StructureFlags = OverridesVisitChildren | StructureIsImmortal | Base::StructureFlags; static void visitChildren(JSCell*, SlotVisitor&); public: @@ -595,12 +626,10 @@ protected: { } - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - DECLARE_INFO; }; -class UnlinkedProgramCodeBlock : public UnlinkedGlobalCodeBlock { +class UnlinkedProgramCodeBlock final : public UnlinkedGlobalCodeBlock { private: friend class CodeCache; static UnlinkedProgramCodeBlock* create(VM* vm, const ExecutableInfo& info) @@ -612,12 +641,9 @@ private: public: typedef UnlinkedGlobalCodeBlock Base; - static void destroy(JSCell*); + static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - void addFunctionDeclaration(VM& vm, const Identifier& name, UnlinkedFunctionExecutable* functionExecutable) - { - m_functionDeclarations.append(std::make_pair(name, WriteBarrier<UnlinkedFunctionExecutable>(vm, this, functionExecutable))); - } + static void destroy(JSCell*); void addVariableDeclaration(const Identifier& name, bool isConstant) { @@ -625,10 +651,8 @@ public: } typedef Vector<std::pair<Identifier, bool>> VariableDeclations; - typedef Vector<std::pair<Identifier, WriteBarrier<UnlinkedFunctionExecutable>> > FunctionDeclations; const VariableDeclations& variableDeclarations() const { return m_varDeclarations; } - const FunctionDeclations& functionDeclarations() const { return m_functionDeclarations; } static void visitChildren(JSCell*, SlotVisitor&); @@ -639,7 +663,6 @@ private: } VariableDeclations m_varDeclarations; - FunctionDeclations m_functionDeclarations; public: static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) @@ -647,12 +670,10 @@ public: return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedProgramCodeBlockType, StructureFlags), info()); } - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - DECLARE_INFO; }; -class UnlinkedEvalCodeBlock : public UnlinkedGlobalCodeBlock { +class UnlinkedEvalCodeBlock final : public UnlinkedGlobalCodeBlock { private: friend class CodeCache; @@ -665,6 +686,8 @@ private: public: typedef UnlinkedGlobalCodeBlock Base; + static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; + static void destroy(JSCell*); const Identifier& variable(unsigned index) { return m_variables[index]; } @@ -689,13 +712,14 @@ public: return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedEvalCodeBlockType, StructureFlags), info()); } - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - DECLARE_INFO; }; -class UnlinkedFunctionCodeBlock : public UnlinkedCodeBlock { +class UnlinkedFunctionCodeBlock final : public UnlinkedCodeBlock { public: + typedef UnlinkedCodeBlock Base; + static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; + static UnlinkedFunctionCodeBlock* create(VM* vm, CodeType codeType, const ExecutableInfo& info) { UnlinkedFunctionCodeBlock* instance = new (NotNull, allocateCell<UnlinkedFunctionCodeBlock>(vm->heap)) UnlinkedFunctionCodeBlock(vm, vm->unlinkedFunctionCodeBlockStructure.get(), codeType, info); @@ -703,7 +727,6 @@ public: return instance; } - typedef UnlinkedCodeBlock Base; static void destroy(JSCell*); private: @@ -718,8 +741,6 @@ public: return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedFunctionCodeBlockType, StructureFlags), info()); } - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - DECLARE_INFO; }; diff --git a/bytecode/UnlinkedInstructionStream.cpp b/bytecode/UnlinkedInstructionStream.cpp index 2e952a4..568dbb6 100644 --- a/bytecode/UnlinkedInstructionStream.cpp +++ b/bytecode/UnlinkedInstructionStream.cpp @@ -75,7 +75,7 @@ static void append32(unsigned char*& ptr, unsigned value) *(ptr++) = (value >> 24) & 0xff; } -UnlinkedInstructionStream::UnlinkedInstructionStream(const Vector<UnlinkedInstruction>& instructions) +UnlinkedInstructionStream::UnlinkedInstructionStream(const Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions) : m_instructionCount(instructions.size()) { Vector<unsigned char> buffer; diff --git a/bytecode/UnlinkedInstructionStream.h b/bytecode/UnlinkedInstructionStream.h index 6649eca..6323c44 100644 --- a/bytecode/UnlinkedInstructionStream.h +++ b/bytecode/UnlinkedInstructionStream.h @@ -35,7 +35,7 @@ namespace JSC { class UnlinkedInstructionStream { WTF_MAKE_FAST_ALLOCATED; public: - explicit UnlinkedInstructionStream(const Vector<UnlinkedInstruction>&); + explicit UnlinkedInstructionStream(const Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>&); unsigned count() const { return m_instructionCount; } diff --git a/bytecode/ValueRecovery.cpp b/bytecode/ValueRecovery.cpp index b7de34b..996fd3b 100644 --- a/bytecode/ValueRecovery.cpp +++ b/bytecode/ValueRecovery.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -92,28 +92,31 @@ void ValueRecovery::dumpInContext(PrintStream& out, DumpContext* context) const return; #endif case DisplacedInJSStack: - out.printf("*%d", virtualRegister().offset()); + out.print("*", virtualRegister()); return; case Int32DisplacedInJSStack: - out.printf("*int32(%d)", virtualRegister().offset()); + out.print("*int32(", virtualRegister(), ")"); return; case Int52DisplacedInJSStack: - out.printf("*int52(%d)", virtualRegister().offset()); + out.print("*int52(", virtualRegister(), ")"); return; case StrictInt52DisplacedInJSStack: - out.printf("*strictInt52(%d)", virtualRegister().offset()); + out.print("*strictInt52(", virtualRegister(), ")"); return; case DoubleDisplacedInJSStack: - out.printf("*double(%d)", virtualRegister().offset()); + out.print("*double(", virtualRegister(), ")"); return; case CellDisplacedInJSStack: - out.printf("*cell(%d)", virtualRegister().offset()); + out.print("*cell(", virtualRegister(), ")"); return; case BooleanDisplacedInJSStack: - out.printf("*bool(%d)", virtualRegister().offset()); + out.print("*bool(", virtualRegister(), ")"); return; - case ArgumentsThatWereNotCreated: - out.printf("arguments"); + case DirectArgumentsThatWereNotCreated: + out.print("DirectArguments(", nodeID(), ")"); + return; + case ClonedArgumentsThatWereNotCreated: + out.print("ClonedArguments(", nodeID(), ")"); return; case Constant: out.print("[", inContext(constant(), context), "]"); diff --git a/bytecode/ValueRecovery.h b/bytecode/ValueRecovery.h index c30b97a..42651e2 100644 --- a/bytecode/ValueRecovery.h +++ b/bytecode/ValueRecovery.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,6 +26,7 @@ #ifndef ValueRecovery_h #define ValueRecovery_h +#include "DFGMinifiedID.h" #include "DataFormat.h" #if ENABLE(JIT) #include "GPRInfo.h" @@ -38,6 +39,7 @@ namespace JSC { struct DumpContext; +struct InlineCallFrame; // Describes how to recover a given bytecode virtual register at a given // code point. @@ -62,8 +64,9 @@ enum ValueRecoveryTechnique { DoubleDisplacedInJSStack, CellDisplacedInJSStack, BooleanDisplacedInJSStack, - // It's an Arguments object. - ArgumentsThatWereNotCreated, + // It's an Arguments object. This arises because of the simplified arguments simplification done by the DFG. + DirectArgumentsThatWereNotCreated, + ClonedArgumentsThatWereNotCreated, // It's a constant. Constant, // Don't know how to recover it. @@ -167,10 +170,19 @@ public: return result; } - static ValueRecovery argumentsThatWereNotCreated() + static ValueRecovery directArgumentsThatWereNotCreated(DFG::MinifiedID id) { ValueRecovery result; - result.m_technique = ArgumentsThatWereNotCreated; + result.m_technique = DirectArgumentsThatWereNotCreated; + result.m_source.nodeID = id.bits(); + return result; + } + + static ValueRecovery outOfBandArgumentsThatWereNotCreated(DFG::MinifiedID id) + { + ValueRecovery result; + result.m_technique = ClonedArgumentsThatWereNotCreated; + result.m_source.nodeID = id.bits(); return result; } @@ -256,6 +268,12 @@ public: return JSValue::decode(m_source.constant); } + DFG::MinifiedID nodeID() const + { + ASSERT(m_technique == DirectArgumentsThatWereNotCreated || m_technique == ClonedArgumentsThatWereNotCreated); + return DFG::MinifiedID::fromBits(m_source.nodeID); + } + JSValue recover(ExecState*) const; #if ENABLE(JIT) @@ -276,6 +294,7 @@ private: #endif int virtualReg; EncodedJSValue constant; + uintptr_t nodeID; } m_source; }; diff --git a/bytecode/VariableWatchpointSet.h b/bytecode/VariableWatchpointSet.h deleted file mode 100644 index 34cefa0..0000000 --- a/bytecode/VariableWatchpointSet.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2012-2014 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 VariableWatchpointSet_h -#define VariableWatchpointSet_h - -#include "Watchpoint.h" -#include "WriteBarrier.h" - -namespace JSC { - -class SymbolTable; - -class VariableWatchpointSet : public WatchpointSet { - friend class LLIntOffsetsExtractor; -public: - VariableWatchpointSet(SymbolTable& symbolTable) - : WatchpointSet(ClearWatchpoint) - , m_symbolTable(symbolTable) - { - } - - ~VariableWatchpointSet() { } - - // For the purpose of deciding whether or not to watch this variable, you only need - // to inspect inferredValue(). If this returns something other than the empty - // value, then it means that at all future safepoints, this watchpoint set will be - // in one of these states: - // - // IsWatched: in this case, the variable's value must still be the - // inferredValue. - // - // IsInvalidated: in this case the variable's value may be anything but you'll - // either notice that it's invalidated and not install the watchpoint, or - // you will have been notified that the watchpoint was fired. - JSValue inferredValue() const { return m_inferredValue.get(); } - - inline void notifyWrite(VM&, JSValue); - - void invalidate() - { - m_inferredValue.clear(); - WatchpointSet::invalidate(); - } - - void finalizeUnconditionally() - { - ASSERT(!!m_inferredValue == (state() == IsWatched)); - if (!m_inferredValue) - return; - JSValue inferredValue = m_inferredValue.get(); - if (!inferredValue.isCell()) - return; - JSCell* cell = inferredValue.asCell(); - if (Heap::isMarked(cell)) - return; - invalidate(); - } - - WriteBarrier<Unknown>* addressOfInferredValue() { return &m_inferredValue; } - -private: - SymbolTable& m_symbolTable; - WriteBarrier<Unknown> m_inferredValue; -}; - -} // namespace JSC - -#endif // VariableWatchpointSet_h - diff --git a/runtime/JSArgumentsIterator.cpp b/bytecode/VariableWriteFireDetail.cpp similarity index 77% rename from runtime/JSArgumentsIterator.cpp rename to bytecode/VariableWriteFireDetail.cpp index b902a3d..b483ab2 100644 --- a/runtime/JSArgumentsIterator.cpp +++ b/bytecode/VariableWriteFireDetail.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple, Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,19 +24,21 @@ */ #include "config.h" -#include "JSArgumentsIterator.h" +#include "VariableWriteFireDetail.h" -#include "Arguments.h" #include "JSCInlines.h" namespace JSC { -const ClassInfo JSArgumentsIterator::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArgumentsIterator) }; - -void JSArgumentsIterator::finishCreation(VM& vm, Arguments* arguments) +void VariableWriteFireDetail::dump(PrintStream& out) const { - Base::finishCreation(vm); - m_arguments.set(vm, this, arguments); + out.print("Write to ", m_name, " in ", JSValue(m_object)); } +void VariableWriteFireDetail::touch(WatchpointSet* set, JSObject* object, const PropertyName& name) +{ + set->touch(VariableWriteFireDetail(object, name)); } + +} // namespace JSC + diff --git a/bytecode/VariableWriteFireDetail.h b/bytecode/VariableWriteFireDetail.h new file mode 100644 index 0000000..664f69c --- /dev/null +++ b/bytecode/VariableWriteFireDetail.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 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 VariableWriteFireDetail_h +#define VariableWriteFireDetail_h + +#include "Watchpoint.h" + +namespace JSC { + +class JSObject; +class PropertyName; + +class VariableWriteFireDetail : public FireDetail { +public: + VariableWriteFireDetail(JSObject* object, const PropertyName& name) + : m_object(object) + , m_name(name) + { + } + + virtual void dump(PrintStream&) const override; + + JS_EXPORT_PRIVATE static void touch(WatchpointSet*, JSObject*, const PropertyName&); + +private: + JSObject* m_object; + const PropertyName& m_name; +}; + +} // namespace JSC + +#endif // VariableWriteFireDetail_h diff --git a/bytecode/VariableWatchpointSetInlines.h b/bytecode/VirtualRegister.cpp similarity index 66% rename from bytecode/VariableWatchpointSetInlines.h rename to bytecode/VirtualRegister.cpp index 7b3c569..57cdb62 100644 --- a/bytecode/VariableWatchpointSetInlines.h +++ b/bytecode/VirtualRegister.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,38 +23,43 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef VariableWatchpointSetInlines_h -#define VariableWatchpointSetInlines_h - -#include "SymbolTable.h" -#include "VariableWatchpointSet.h" +#include "config.h" +#include "VirtualRegister.h" namespace JSC { -inline void VariableWatchpointSet::notifyWrite(VM& vm, JSValue value) +void VirtualRegister::dump(PrintStream& out) const { - ASSERT(!!value); - switch (state()) { - case ClearWatchpoint: - m_inferredValue.set(vm, &m_symbolTable, value); - startWatching(); + if (!isValid()) { + out.print("<invalid>"); return; - - case IsWatched: - ASSERT(!!m_inferredValue); - if (value == m_inferredValue.get()) - return; - invalidate(); + } + + if (isHeader()) { + out.print("head", m_virtualRegister); return; - - case IsInvalidated: - ASSERT(!m_inferredValue); + } + + if (isConstant()) { + out.print("const", toConstantIndex()); return; } - - ASSERT_NOT_REACHED(); -} + if (isArgument()) { + if (!toArgument()) + out.print("this"); + else + out.print("arg", toArgument()); + return; + } + + if (isLocal()) { + out.print("loc", toLocal()); + return; + } + + RELEASE_ASSERT_NOT_REACHED(); +} + } // namespace JSC -#endif // VariableWatchpointSetInlines_h diff --git a/bytecode/VirtualRegister.h b/bytecode/VirtualRegister.h index 26e525d..613088e 100644 --- a/bytecode/VirtualRegister.h +++ b/bytecode/VirtualRegister.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -59,6 +59,7 @@ public: bool isValid() const { return (m_virtualRegister != s_invalidVirtualRegister); } bool isLocal() const { return operandIsLocal(m_virtualRegister); } bool isArgument() const { return operandIsArgument(m_virtualRegister); } + bool isHeader() const { return m_virtualRegister >= 0 && m_virtualRegister < JSStack::ThisArgument; } bool isConstant() const { return m_virtualRegister >= s_firstConstantRegisterIndex; } int toLocal() const { ASSERT(isLocal()); return operandToLocal(m_virtualRegister); } int toArgument() const { ASSERT(isArgument()); return operandToArgument(m_virtualRegister); } @@ -66,8 +67,39 @@ public: int offset() const { return m_virtualRegister; } int offsetInBytes() const { return m_virtualRegister * sizeof(Register); } - bool operator==(const VirtualRegister other) const { return m_virtualRegister == other.m_virtualRegister; } - bool operator!=(const VirtualRegister other) const { return m_virtualRegister != other.m_virtualRegister; } + bool operator==(VirtualRegister other) const { return m_virtualRegister == other.m_virtualRegister; } + bool operator!=(VirtualRegister other) const { return m_virtualRegister != other.m_virtualRegister; } + bool operator<(VirtualRegister other) const { return m_virtualRegister < other.m_virtualRegister; } + bool operator>(VirtualRegister other) const { return m_virtualRegister > other.m_virtualRegister; } + bool operator<=(VirtualRegister other) const { return m_virtualRegister <= other.m_virtualRegister; } + bool operator>=(VirtualRegister other) const { return m_virtualRegister >= other.m_virtualRegister; } + + VirtualRegister operator+(int value) const + { + return VirtualRegister(offset() + value); + } + VirtualRegister operator-(int value) const + { + return VirtualRegister(offset() - value); + } + VirtualRegister operator+(VirtualRegister value) const + { + return VirtualRegister(offset() + value.offset()); + } + VirtualRegister operator-(VirtualRegister value) const + { + return VirtualRegister(offset() - value.offset()); + } + VirtualRegister& operator+=(int value) + { + return *this = *this + value; + } + VirtualRegister& operator-=(int value) + { + return *this = *this - value; + } + + void dump(PrintStream& out) const; private: static const int s_invalidVirtualRegister = 0x3fffffff; @@ -95,13 +127,4 @@ inline VirtualRegister virtualRegisterForArgument(int argument, int offset = 0) } // namespace JSC -namespace WTF { - -inline void printInternal(PrintStream& out, JSC::VirtualRegister value) -{ - out.print(value.offset()); -} - -} // namespace WTF - #endif // VirtualRegister_h diff --git a/bytecode/Watchpoint.cpp b/bytecode/Watchpoint.cpp index 081654d..3c5f93a 100644 --- a/bytecode/Watchpoint.cpp +++ b/bytecode/Watchpoint.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 2014 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,11 @@ namespace JSC { +void StringFireDetail::dump(PrintStream& out) const +{ + out.print(m_string); +} + Watchpoint::~Watchpoint() { if (isOnList()) @@ -64,20 +69,25 @@ void WatchpointSet::add(Watchpoint* watchpoint) m_state = IsWatched; } -void WatchpointSet::fireAllSlow() +void WatchpointSet::fireAllSlow(const FireDetail& detail) { ASSERT(state() == IsWatched); WTF::storeStoreFence(); - fireAllWatchpoints(); + fireAllWatchpoints(detail); m_state = IsInvalidated; WTF::storeStoreFence(); } -void WatchpointSet::fireAllWatchpoints() +void WatchpointSet::fireAllSlow(const char* reason) +{ + fireAllSlow(StringFireDetail(reason)); +} + +void WatchpointSet::fireAllWatchpoints(const FireDetail& detail) { while (!m_set.isEmpty()) - m_set.begin()->fire(); + m_set.begin()->fire(detail); } void InlineWatchpointSet::add(Watchpoint* watchpoint) @@ -85,6 +95,11 @@ void InlineWatchpointSet::add(Watchpoint* watchpoint) inflate()->add(watchpoint); } +void InlineWatchpointSet::fireAll(const char* reason) +{ + fireAll(StringFireDetail(reason)); +} + WatchpointSet* InlineWatchpointSet::inflateSlow() { ASSERT(isThin()); diff --git a/bytecode/Watchpoint.h b/bytecode/Watchpoint.h index 7659c0d..8857317 100644 --- a/bytecode/Watchpoint.h +++ b/bytecode/Watchpoint.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,11 +27,40 @@ #define Watchpoint_h #include <wtf/Atomics.h> +#include <wtf/PrintStream.h> #include <wtf/SentinelLinkedList.h> #include <wtf/ThreadSafeRefCounted.h> namespace JSC { +class FireDetail { + void* operator new(size_t) = delete; + +public: + FireDetail() + { + } + + virtual ~FireDetail() + { + } + + virtual void dump(PrintStream&) const = 0; +}; + +class StringFireDetail : public FireDetail { +public: + StringFireDetail(const char* string) + : m_string(string) + { + } + + virtual void dump(PrintStream& out) const override; + +private: + const char* m_string; +}; + class Watchpoint : public BasicRawSentinelNode<Watchpoint> { public: Watchpoint() @@ -40,10 +69,10 @@ public: virtual ~Watchpoint(); - void fire() { fireInternal(); } + void fire(const FireDetail& detail) { fireInternal(detail); } protected: - virtual void fireInternal() = 0; + virtual void fireInternal(const FireDetail&) = 0; }; enum WatchpointState { @@ -60,6 +89,12 @@ public: JS_EXPORT_PRIVATE WatchpointSet(WatchpointState); JS_EXPORT_PRIVATE ~WatchpointSet(); // Note that this will not fire any of the watchpoints; if you need to know when a WatchpointSet dies then you need a separate mechanism for this. + // Fast way of getting the state, which only works from the main thread. + WatchpointState stateOnJSThread() const + { + return static_cast<WatchpointState>(m_state); + } + // It is safe to call this from another thread. It may return an old // state. Guarantees that if *first* read the state() of the thing being // watched and it returned IsWatched and *second* you actually read its @@ -98,39 +133,61 @@ public: // set watchpoints that we believe will actually be fired. void startWatching() { - ASSERT(state() != IsInvalidated); + ASSERT(m_state != IsInvalidated); + if (m_state == IsWatched) + return; + WTF::storeStoreFence(); m_state = IsWatched; + WTF::storeStoreFence(); } - void fireAll() + void fireAll(const FireDetail& detail) { - if (state() != IsWatched) + if (LIKELY(m_state != IsWatched)) return; - fireAllSlow(); + fireAllSlow(detail); } - void touch() + void fireAll(const char* reason) + { + if (LIKELY(m_state != IsWatched)) + return; + fireAllSlow(reason); + } + + void touch(const FireDetail& detail) { if (state() == ClearWatchpoint) startWatching(); else - fireAll(); + fireAll(detail); } - void invalidate() + void touch(const char* reason) + { + touch(StringFireDetail(reason)); + } + + void invalidate(const FireDetail& detail) { if (state() == IsWatched) - fireAll(); + fireAll(detail); m_state = IsInvalidated; } - + + void invalidate(const char* reason) + { + invalidate(StringFireDetail(reason)); + } + int8_t* addressOfState() { return &m_state; } int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; } - JS_EXPORT_PRIVATE void fireAllSlow(); // Call only if you've checked isWatched. + JS_EXPORT_PRIVATE void fireAllSlow(const FireDetail&); // Call only if you've checked isWatched. + JS_EXPORT_PRIVATE void fireAllSlow(const char* reason); // Ditto. private: - void fireAllWatchpoints(); + void fireAllWatchpoints(const FireDetail&); friend class InlineWatchpointSet; @@ -174,18 +231,34 @@ public: freeFat(); } + // Fast way of getting the state, which only works from the main thread. + WatchpointState stateOnJSThread() const + { + uintptr_t data = m_data; + if (isFat(data)) + return fat(data)->stateOnJSThread(); + return decodeState(data); + } + + // It is safe to call this from another thread. It may return a prior state, + // but that should be fine since you should only perform actions based on the + // state if you also add a watchpoint. + WatchpointState state() const + { + WTF::loadLoadFence(); + uintptr_t data = m_data; + WTF::loadLoadFence(); + if (isFat(data)) + return fat(data)->state(); + return decodeState(data); + } + // It is safe to call this from another thread. It may return false // even if the set actually had been invalidated, but that ought to happen // only in the case of races, and should be rare. bool hasBeenInvalidated() const { - WTF::loadLoadFence(); - uintptr_t data = m_data; - if (isFat(data)) { - WTF::loadLoadFence(); - return fat(data)->hasBeenInvalidated(); - } - return decodeState(data) == IsInvalidated; + return state() == IsInvalidated; } // Like hasBeenInvalidated(), may be called from another thread. @@ -206,10 +279,10 @@ public: m_data = encodeState(IsWatched); } - void fireAll() + void fireAll(const FireDetail& detail) { if (isFat()) { - fat()->fireAll(); + fat()->fireAll(detail); return; } if (decodeState(m_data) == ClearWatchpoint) @@ -218,19 +291,38 @@ public: WTF::storeStoreFence(); } - void touch() + void invalidate(const FireDetail& detail) + { + if (isFat()) + fat()->invalidate(detail); + else + m_data = encodeState(IsInvalidated); + } + + JS_EXPORT_PRIVATE void fireAll(const char* reason); + + void touch(const FireDetail& detail) { if (isFat()) { - fat()->touch(); + fat()->touch(detail); return; } - if (decodeState(m_data) == ClearWatchpoint) + uintptr_t data = m_data; + if (decodeState(data) == IsInvalidated) + return; + WTF::storeStoreFence(); + if (decodeState(data) == ClearWatchpoint) m_data = encodeState(IsWatched); else m_data = encodeState(IsInvalidated); WTF::storeStoreFence(); } + void touch(const char* reason) + { + touch(StringFireDetail(reason)); + } + private: static const uintptr_t IsThinFlag = 1; static const uintptr_t StateMask = 6; @@ -247,7 +339,7 @@ private: static uintptr_t encodeState(WatchpointState state) { - return (state << StateShift) | IsThinFlag; + return (static_cast<uintptr_t>(state) << StateShift) | IsThinFlag; } bool isThin() const { return isThin(m_data); } diff --git a/bytecompiler/BytecodeGenerator.cpp b/bytecompiler/BytecodeGenerator.cpp index 734546a..8b2f8e6 100644 --- a/bytecompiler/BytecodeGenerator.cpp +++ b/bytecompiler/BytecodeGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * Copyright (C) 2012 Igalia, S.L. * @@ -31,10 +31,12 @@ #include "config.h" #include "BytecodeGenerator.h" +#include "BuiltinExecutables.h" #include "Interpreter.h" -#include "JSActivation.h" #include "JSFunction.h" +#include "JSLexicalEnvironment.h" #include "JSNameScope.h" +#include "JSTemplateRegistryKey.h" #include "LowLevelInterpreter.h" #include "JSCInlines.h" #include "Options.h" @@ -55,7 +57,7 @@ void Label::setLocation(unsigned location) unsigned size = m_unresolvedJumps.size(); for (unsigned i = 0; i < size; ++i) - m_generator->m_instructions[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; + m_generator.instructions()[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; } ParserError BytecodeGenerator::generate() @@ -63,12 +65,36 @@ ParserError BytecodeGenerator::generate() SamplingRegion samplingRegion("Bytecode Generation"); m_codeBlock->setThisRegister(m_thisRegister.virtualRegister()); - for (size_t i = 0; i < m_deconstructedParameters.size(); i++) { - auto& entry = m_deconstructedParameters[i]; + + // If we have declared a variable named "arguments" and we are using arguments then we should + // perform that assignment now. + if (m_needToInitializeArguments) + initializeVariable(variable(propertyNames().arguments), m_argumentsRegister); + + for (size_t i = 0; i < m_destructuringParameters.size(); i++) { + auto& entry = m_destructuringParameters[i]; entry.second->bindValue(*this, entry.first.get()); } - m_scopeNode->emitBytecode(*this); + { + RefPtr<RegisterID> temp = newTemporary(); + RefPtr<RegisterID> globalScope = scopeRegister(); // FIXME: With lexical scoping, this won't always be the global object: https://bugs.webkit.org/show_bug.cgi?id=142944 + for (auto functionPair : m_functionsToInitialize) { + FunctionBodyNode* functionBody = functionPair.first; + FunctionVariableType functionType = functionPair.second; + emitNewFunction(temp.get(), functionBody); + if (functionType == NormalFunctionVariable) + initializeVariable(variable(functionBody->ident()) , temp.get()); + else if (functionType == GlobalFunctionVariable) + emitPutToScope(globalScope.get(), Variable(functionBody->ident()), temp.get(), ThrowIfNotFound); + else + RELEASE_ASSERT_NOT_REACHED(); + } + } + + bool callingClassConstructor = constructorKind() != ConstructorKind::None && !isConstructor(); + if (!callingClassConstructor) + m_scopeNode->emitBytecode(*this); m_staticPropertyAnalyzer.kill(); @@ -103,11 +129,10 @@ ParserError BytecodeGenerator::generate() continue; ASSERT(range.tryData->targetScopeDepth != UINT_MAX); - UnlinkedHandlerInfo info = { - static_cast<uint32_t>(start), static_cast<uint32_t>(end), - static_cast<uint32_t>(range.tryData->target->bind()), - range.tryData->targetScopeDepth - }; + ASSERT(range.tryData->handlerType != HandlerType::Illegal); + UnlinkedHandlerInfo info(static_cast<uint32_t>(start), static_cast<uint32_t>(end), + static_cast<uint32_t>(range.tryData->target->bind()), range.tryData->targetScopeDepth, + range.tryData->handlerType); m_codeBlock->addExceptionHandler(info); } @@ -115,86 +140,38 @@ ParserError BytecodeGenerator::generate() m_codeBlock->shrinkToFit(); - if (m_codeBlock->symbolTable()) - m_codeBlock->setSymbolTable(m_codeBlock->symbolTable()->cloneCapturedNames(*m_codeBlock->vm())); + if (m_codeBlock->symbolTable() && !m_codeBlock->vm()->typeProfiler()) + m_codeBlock->setSymbolTable(m_codeBlock->symbolTable()->cloneScopePart(*m_codeBlock->vm())); if (m_expressionTooDeep) return ParserError(ParserError::OutOfMemory); return ParserError(ParserError::ErrorNone); } -bool BytecodeGenerator::addVar( - const Identifier& ident, ConstantMode constantMode, WatchMode watchMode, RegisterID*& r0) -{ - ASSERT(static_cast<size_t>(m_codeBlock->m_numVars) == m_calleeRegisters.size()); - - ConcurrentJITLocker locker(symbolTable().m_lock); - int index = virtualRegisterForLocal(m_calleeRegisters.size()).offset(); - SymbolTableEntry newEntry(index, constantMode == IsConstant ? ReadOnly : 0); - SymbolTable::Map::AddResult result = symbolTable().add(locker, ident.impl(), newEntry); - - if (!result.isNewEntry) { - r0 = ®isterFor(result.iterator->value.getIndex()); - return false; - } - - if (watchMode == IsWatchable) { - while (m_watchableVariables.size() < static_cast<size_t>(m_codeBlock->m_numVars)) - m_watchableVariables.append(Identifier()); - m_watchableVariables.append(ident); - } - - r0 = addVar(); - - ASSERT(watchMode == NotWatchable || static_cast<size_t>(m_codeBlock->m_numVars) == m_watchableVariables.size()); - - return true; -} - -void BytecodeGenerator::preserveLastVar() -{ - if ((m_firstConstantIndex = m_calleeRegisters.size()) != 0) - m_lastVar = &m_calleeRegisters.last(); -} - BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) - , m_symbolTable(0) , m_scopeNode(programNode) , m_codeBlock(vm, codeBlock) , m_thisRegister(CallFrame::thisArgumentOffset()) - , m_activationRegister(0) - , m_emptyValueRegister(0) - , m_globalObjectRegister(0) - , m_finallyDepth(0) - , m_localScopeDepth(0) , m_codeType(GlobalCode) - , m_nextConstantOffset(0) - , m_globalConstantIndex(0) - , m_firstLazyFunction(0) - , m_lastLazyFunction(0) - , m_staticPropertyAnalyzer(&m_instructions) , m_vm(&vm) - , m_lastOpcodeID(op_end) -#ifndef NDEBUG - , m_lastOpcodePosition(0) -#endif - , m_usesExceptions(false) - , m_expressionTooDeep(false) - , m_isBuiltinFunction(false) { + for (auto& constantRegister : m_linkTimeConstantRegisters) + constantRegister = nullptr; + m_codeBlock->setNumParameters(1); // Allocate space for "this" emitOpcode(op_enter); + allocateAndEmitScope(); + const VarStack& varStack = programNode->varStack(); const FunctionStack& functionStack = programNode->functionStack(); for (size_t i = 0; i < functionStack.size(); ++i) { FunctionBodyNode* function = functionStack[i]; - UnlinkedFunctionExecutable* unlinkedFunction = makeFunction(function); - codeBlock->addFunctionDeclaration(*m_vm, function->ident(), unlinkedFunction); + m_functionsToInitialize.append(std::make_pair(function, GlobalFunctionVariable)); } for (size_t i = 0; i < varStack.size(); ++i) @@ -202,38 +179,25 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP } -BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) +BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode) : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) , m_symbolTable(codeBlock->symbolTable()) - , m_scopeNode(functionBody) + , m_scopeNode(functionNode) , m_codeBlock(vm, codeBlock) - , m_activationRegister(0) - , m_emptyValueRegister(0) - , m_globalObjectRegister(0) - , m_finallyDepth(0) - , m_localScopeDepth(0) , m_codeType(FunctionCode) - , m_nextConstantOffset(0) - , m_globalConstantIndex(0) - , m_firstLazyFunction(0) - , m_lastLazyFunction(0) - , m_staticPropertyAnalyzer(&m_instructions) , m_vm(&vm) - , m_lastOpcodeID(op_end) -#ifndef NDEBUG - , m_lastOpcodePosition(0) -#endif - , m_usesExceptions(false) - , m_expressionTooDeep(false) , m_isBuiltinFunction(codeBlock->isBuiltinFunction()) { + for (auto& constantRegister : m_linkTimeConstantRegisters) + constantRegister = nullptr; + if (m_isBuiltinFunction) m_shouldEmitDebugHooks = false; - + m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); Vector<Identifier> boundParameterProperties; - FunctionParameters& parameters = *functionBody->parameters(); + FunctionParameters& parameters = *functionNode->parameters(); for (size_t i = 0; i < parameters.size(); i++) { auto pattern = parameters.at(i); if (pattern->isBindingNode()) @@ -241,175 +205,295 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionBodyNode* functionBody, Unl pattern->collectBoundIdentifiers(boundParameterProperties); continue; } - m_symbolTable->setParameterCountIncludingThis(functionBody->parameters()->size() + 1); - emitOpcode(op_enter); - if (m_codeBlock->needsFullScopeChain() || m_shouldEmitDebugHooks) { - m_activationRegister = addVar(); - emitInitLazyRegister(m_activationRegister); - m_codeBlock->setActivationRegister(m_activationRegister->virtualRegister()); - } - - m_symbolTable->setCaptureStart(virtualRegisterForLocal(m_codeBlock->m_numVars).offset()); - - if (functionBody->usesArguments() || codeBlock->usesEval()) { // May reify arguments object. - RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code. - RegisterID* argumentsRegister = addVar(propertyNames().arguments, IsVariable, NotWatchable); // Can be changed by assigning to 'arguments'. + bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain(); + bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); + bool needsArguments = functionNode->usesArguments() || codeBlock->usesEval(); + + auto captures = [&] (UniquedStringImpl* uid) -> bool { + if (shouldCaptureAllOfTheThings) + return true; + if (!shouldCaptureSomeOfTheThings) + return false; + if (needsArguments && uid == propertyNames().arguments.impl()) { + // Actually, we only need to capture the arguments object when we "need full activation" + // because of name scopes. But historically we did it this way, so for now we just preserve + // the old behavior. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=143072 + return true; + } + return functionNode->captures(uid); + }; + auto varKind = [&] (UniquedStringImpl* uid) -> VarKind { + return captures(uid) ? VarKind::Scope : VarKind::Stack; + }; - // We can save a little space by hard-coding the knowledge that the two - // 'arguments' values are stored in consecutive registers, and storing - // only the index of the assignable one. - codeBlock->setArgumentsRegister(argumentsRegister->virtualRegister()); - ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->virtualRegister() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister())); + emitOpcode(op_enter); - emitInitLazyRegister(argumentsRegister); - emitInitLazyRegister(unmodifiedArgumentsRegister); - - if (shouldTearOffArgumentsEagerly()) { - emitOpcode(op_create_arguments); - instructions().append(argumentsRegister->index()); - } + allocateAndEmitScope(); + + m_calleeRegister.setIndex(JSStack::Callee); + + if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode()) + && functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode())) { + // When we do this, we should make our local scope stack know about the function name symbol + // table. Currently this works because bytecode linking creates a phony name scope. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141885 + // Also, we could create the scope once per JSFunction instance that needs it. That wouldn't + // be any more correct, but it would be more performant. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141887 + emitPushFunctionNameScope(m_scopeRegister, functionNode->ident(), &m_calleeRegister, ReadOnly | DontDelete); } - bool shouldCaptureAllTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); - + if (shouldCaptureSomeOfTheThings) { + m_lexicalEnvironmentRegister = addVar(); + m_codeBlock->setActivationRegister(m_lexicalEnvironmentRegister->virtualRegister()); + emitOpcode(op_create_lexical_environment); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(scopeRegister()->index()); + emitOpcode(op_mov); + instructions().append(scopeRegister()->index()); + instructions().append(m_lexicalEnvironmentRegister->index()); + } + + // Make sure the code block knows about all of our parameters, and make sure that parameters + // needing destructuring are noted. + m_parameters.grow(parameters.size() + 1); // reserve space for "this" + m_thisRegister.setIndex(initializeNextParameter()->index()); // this + for (unsigned i = 0; i < parameters.size(); ++i) { + auto pattern = parameters.at(i); + RegisterID* reg = initializeNextParameter(); + if (!pattern->isBindingNode()) + m_destructuringParameters.append(std::make_pair(reg, pattern)); + } + + // Figure out some interesting facts about our arguments. bool capturesAnyArgumentByName = false; - Vector<RegisterID*, 0, UnsafeVectorOverflow> capturedArguments; - if (functionBody->hasCapturedVariables() || shouldCaptureAllTheThings) { - FunctionParameters& parameters = *functionBody->parameters(); - capturedArguments.resize(parameters.size()); + if (functionNode->hasCapturedVariables()) { + FunctionParameters& parameters = *functionNode->parameters(); for (size_t i = 0; i < parameters.size(); ++i) { - capturedArguments[i] = 0; auto pattern = parameters.at(i); if (!pattern->isBindingNode()) continue; const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty(); - if (!functionBody->captures(ident) && !shouldCaptureAllTheThings) - continue; - capturesAnyArgumentByName = true; - capturedArguments[i] = addVar(); + capturesAnyArgumentByName |= captures(ident.impl()); } } - if (capturesAnyArgumentByName && !shouldTearOffArgumentsEagerly()) { - size_t parameterCount = m_symbolTable->parameterCount(); - auto slowArguments = std::make_unique<SlowArgument[]>(parameterCount); - for (size_t i = 0; i < parameterCount; ++i) { - if (!capturedArguments[i]) { - ASSERT(slowArguments[i].status == SlowArgument::Normal); - slowArguments[i].index = CallFrame::argumentOffset(i); - continue; - } - slowArguments[i].status = SlowArgument::Captured; - slowArguments[i].index = capturedArguments[i]->index(); - } - m_symbolTable->setSlowArguments(WTF::move(slowArguments)); + if (capturesAnyArgumentByName) + ASSERT(m_lexicalEnvironmentRegister); + + // Need to know what our functions are called. Parameters have some goofy behaviors when it + // comes to functions of the same name. + for (FunctionBodyNode* function : functionNode->functionStack()) + m_functions.add(function->ident().impl()); + + if (needsArguments) { + // Create the arguments object now. We may put the arguments object into the activation if + // it is captured. Either way, we create two arguments object variables: one is our + // private variable that is immutable, and another that is the user-visible variable. The + // immutable one is only used here, or during formal parameter resolutions if we opt for + // DirectArguments. + + m_argumentsRegister = addVar(); + m_argumentsRegister->ref(); } - - RegisterID* calleeRegister = resolveCallee(functionBody); // May push to the scope chain and/or add a captured var. - - const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack(); - const DeclarationStacks::VarStack& varStack = functionBody->varStack(); - IdentifierSet test; - - // Captured variables and functions go first so that activations don't have - // to step over the non-captured locals to mark them. - if (functionBody->hasCapturedVariables()) { - for (size_t i = 0; i < boundParameterProperties.size(); i++) { - const Identifier& ident = boundParameterProperties[i]; - if (functionBody->captures(ident)) - addVar(ident, IsVariable, IsWatchable); - } - for (size_t i = 0; i < functionStack.size(); ++i) { - FunctionBodyNode* function = functionStack[i]; - const Identifier& ident = function->ident(); - if (functionBody->captures(ident)) { - m_functions.add(ident.impl()); - emitNewFunction(addVar(ident, IsVariable, IsWatchable), IsCaptured, function); + + if (needsArguments && !codeBlock->isStrictMode()) { + // If we captured any formal parameter by name, then we use ScopedArguments. Otherwise we + // use DirectArguments. With ScopedArguments, we lift all of our arguments into the + // activation. + + if (capturesAnyArgumentByName) { + m_symbolTable->setArgumentsLength(vm, parameters.size()); + + // For each parameter, we have two possibilities: + // Either it's a binding node with no function overlap, in which case it gets a name + // in the symbol table - or it just gets space reserved in the symbol table. Either + // way we lift the value into the scope. + for (unsigned i = 0; i < parameters.size(); ++i) { + ScopeOffset offset = m_symbolTable->takeNextScopeOffset(); + m_symbolTable->setArgumentOffset(vm, i, offset); + if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i))) { + VarOffset varOffset(offset); + SymbolTableEntry entry(varOffset); + // Stores to these variables via the ScopedArguments object will not do + // notifyWrite(), since that would be cumbersome. Also, watching formal + // parameters when "arguments" is in play is unlikely to be super profitable. + // So, we just disable it. + entry.disableWatching(); + m_symbolTable->set(name, entry); + } + emitOpcode(op_put_to_scope); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(UINT_MAX); + instructions().append(virtualRegisterForArgument(1 + i).offset()); + instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); + instructions().append(0); + instructions().append(offset.offset()); } + + // This creates a scoped arguments object and copies the overflow arguments into the + // scope. It's the equivalent of calling ScopedArguments::createByCopying(). + emitOpcode(op_create_scoped_arguments); + instructions().append(m_argumentsRegister->index()); + instructions().append(m_lexicalEnvironmentRegister->index()); + } else { + // We're going to put all parameters into the DirectArguments object. First ensure + // that the symbol table knows that this is happening. + for (unsigned i = 0; i < parameters.size(); ++i) { + if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i))) + m_symbolTable->set(name, SymbolTableEntry(VarOffset(DirectArgumentsOffset(i)))); + } + + emitOpcode(op_create_direct_arguments); + instructions().append(m_argumentsRegister->index()); } - for (size_t i = 0; i < varStack.size(); ++i) { - const Identifier& ident = varStack[i].first; - if (functionBody->captures(ident)) - addVar(ident, (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, IsWatchable); + } else { + // Create the formal parameters the normal way. Any of them could be captured, or not. If + // captured, lift them into the scope. + for (unsigned i = 0; i < parameters.size(); ++i) { + UniquedStringImpl* name = visibleNameForParameter(parameters.at(i)); + if (!name) + continue; + + if (!captures(name)) { + // This is the easy case - just tell the symbol table about the argument. It will + // be accessed directly. + m_symbolTable->set(name, SymbolTableEntry(VarOffset(virtualRegisterForArgument(1 + i)))); + continue; + } + + ScopeOffset offset = m_symbolTable->takeNextScopeOffset(); + const Identifier& ident = + static_cast<const BindingNode*>(parameters.at(i))->boundProperty(); + m_symbolTable->set(name, SymbolTableEntry(VarOffset(offset))); + + emitOpcode(op_put_to_scope); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(addConstant(ident)); + instructions().append(virtualRegisterForArgument(1 + i).offset()); + instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); + instructions().append(0); + instructions().append(offset.offset()); } } - - m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset()); - - bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks; - m_firstLazyFunction = codeBlock->m_numVars; - for (size_t i = 0; i < functionStack.size(); ++i) { - FunctionBodyNode* function = functionStack[i]; + + if (needsArguments && codeBlock->isStrictMode()) { + // Allocate an out-of-bands arguments object. + emitOpcode(op_create_out_of_band_arguments); + instructions().append(m_argumentsRegister->index()); + } + + // Now declare all variables. + for (const Identifier& ident : boundParameterProperties) + createVariable(ident, varKind(ident.impl()), IsVariable); + for (FunctionBodyNode* function : functionNode->functionStack()) { const Identifier& ident = function->ident(); - if (!functionBody->captures(ident)) { - m_functions.add(ident.impl()); - RefPtr<RegisterID> reg = addVar(ident, IsVariable, NotWatchable); - // Don't lazily create functions that override the name 'arguments' - // as this would complicate lazy instantiation of actual arguments. - if (!canLazilyCreateFunctions || ident == propertyNames().arguments) - emitNewFunction(reg.get(), NotCaptured, function); - else { - emitInitLazyRegister(reg.get()); - m_lazyFunctions.set(reg->virtualRegister().toLocal(), function); - } - } + createVariable(ident, varKind(ident.impl()), IsVariable); + m_functionsToInitialize.append(std::make_pair(function, NormalFunctionVariable)); } - m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction; - for (size_t i = 0; i < boundParameterProperties.size(); i++) { - const Identifier& ident = boundParameterProperties[i]; - if (!functionBody->captures(ident)) - addVar(ident, IsVariable, IsWatchable); + for (auto& entry : functionNode->varStack()) { + ConstantMode constantMode = modeForIsConstant(entry.second & DeclarationStacks::IsConstant); + // Variables named "arguments" are never const. + if (entry.first == propertyNames().arguments) + constantMode = IsVariable; + createVariable(entry.first, varKind(entry.first.impl()), constantMode, IgnoreExisting); } - for (size_t i = 0; i < varStack.size(); ++i) { - const Identifier& ident = varStack[i].first; - if (!functionBody->captures(ident)) - addVar(ident, (varStack[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, NotWatchable); + + // There are some variables that need to be preinitialized to something other than Undefined: + // + // - "arguments": unless it's used as a function or parameter, this should refer to the + // arguments object. + // + // - callee: unless it's used as a var, function, or parameter, this should refer to the + // callee (i.e. our function). + // + // - functions: these always override everything else. + // + // The most logical way to do all of this is to initialize none of the variables until now, + // and then initialize them in BytecodeGenerator::generate() in such an order that the rules + // for how these things override each other end up holding. We would initialize the callee + // first, then "arguments", then all arguments, then the functions. + // + // But some arguments are already initialized by default, since if they aren't captured and we + // don't have "arguments" then we just point the symbol table at the stack slot of those + // arguments. We end up initializing the rest of the arguments that have an uncomplicated + // binding (i.e. don't involve destructuring) above when figuring out how to lay them out, + // because that's just the simplest thing. This means that when we initialize them, we have to + // watch out for the things that override arguments (namely, functions). + // + // We also initialize callee here as well, just because it's so weird. We know whether we want + // to do this because we can just check if it's in the symbol table. + if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode()) + && !functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode()) + && m_symbolTable->get(functionNode->ident().impl()).isNull()) { + if (captures(functionNode->ident().impl())) { + ScopeOffset offset; + { + ConcurrentJITLocker locker(m_symbolTable->m_lock); + offset = m_symbolTable->takeNextScopeOffset(locker); + m_symbolTable->add( + locker, functionNode->ident().impl(), + SymbolTableEntry(VarOffset(offset), ReadOnly)); + } + + emitOpcode(op_put_to_scope); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(addConstant(functionNode->ident())); + instructions().append(m_calleeRegister.index()); + instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); + instructions().append(0); + instructions().append(offset.offset()); + } else { + m_symbolTable->add( + functionNode->ident().impl(), + SymbolTableEntry(VarOffset(m_calleeRegister.virtualRegister()), ReadOnly)); + } } - - if (shouldCaptureAllTheThings) - m_symbolTable->setCaptureEnd(virtualRegisterForLocal(codeBlock->m_numVars).offset()); - - if (m_symbolTable->captureCount()) - emitOpcode(op_touch_entry); - m_parameters.grow(parameters.size() + 1); // reserve space for "this" - - // Add "this" as a parameter - int nextParameterIndex = CallFrame::thisArgumentOffset(); - m_thisRegister.setIndex(nextParameterIndex++); - m_codeBlock->addParameter(); - for (size_t i = 0; i < parameters.size(); ++i, ++nextParameterIndex) { - int index = nextParameterIndex; - auto pattern = parameters.at(i); - if (!pattern->isBindingNode()) { - m_codeBlock->addParameter(); - RegisterID& parameter = registerFor(index); - parameter.setIndex(index); - m_deconstructedParameters.append(std::make_pair(¶meter, pattern)); - continue; + // This is our final act of weirdness. "arguments" is overridden by everything except the + // callee. We add it to the symbol table if it's not already there and it's not an argument. + if (needsArguments) { + // If "arguments" is overridden by a function or destructuring parameter name, then it's + // OK for us to call createVariable() because it won't change anything. It's also OK for + // us to them tell BytecodeGenerator::generate() to write to it because it will do so + // before it initializes functions and destructuring parameters. But if "arguments" is + // overridden by a "simple" function parameter, then we have to bail: createVariable() + // would assert and BytecodeGenerator::generate() would write the "arguments" after the + // argument value had already been properly initialized. + + bool haveParameterNamedArguments = false; + for (unsigned i = 0; i < parameters.size(); ++i) { + UniquedStringImpl* name = visibleNameForParameter(parameters.at(i)); + if (name == propertyNames().arguments.impl()) { + haveParameterNamedArguments = true; + break; + } } - auto simpleParameter = static_cast<const BindingNode*>(pattern); - if (capturedArguments.size() && capturedArguments[i]) { - ASSERT((functionBody->hasCapturedVariables() && functionBody->captures(simpleParameter->boundProperty())) || shouldCaptureAllTheThings); - index = capturedArguments[i]->index(); - RegisterID original(nextParameterIndex); - emitMove(capturedArguments[i], &original); + + if (!haveParameterNamedArguments) { + createVariable( + propertyNames().arguments, varKind(propertyNames().arguments.impl()), IsVariable); + m_needToInitializeArguments = true; } - addParameter(simpleParameter->boundProperty(), index); } - preserveLastVar(); - - // We declare the callee's name last because it should lose to a var, function, and/or parameter declaration. - addCallee(functionBody, calleeRegister); - + if (isConstructor()) { - emitCreateThis(&m_thisRegister); - } else if (functionBody->usesThis() || codeBlock->usesEval()) { + if (constructorKind() == ConstructorKind::Derived) { + m_newTargetRegister = addVar(); + emitMove(m_newTargetRegister, &m_thisRegister); + emitMoveEmptyValue(&m_thisRegister); + } else + emitCreateThis(&m_thisRegister); + } else if (constructorKind() != ConstructorKind::None) { + emitThrowTypeError("Cannot call a class constructor"); + } else if (functionNode->usesThis() || codeBlock->usesEval()) { m_codeBlock->addPropertyAccessInstruction(instructions().size()); emitOpcode(op_to_this); instructions().append(kill(&m_thisRegister)); instructions().append(0); + instructions().append(0); } } @@ -420,31 +504,19 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod , m_scopeNode(evalNode) , m_codeBlock(vm, codeBlock) , m_thisRegister(CallFrame::thisArgumentOffset()) - , m_activationRegister(0) - , m_emptyValueRegister(0) - , m_globalObjectRegister(0) - , m_finallyDepth(0) - , m_localScopeDepth(0) , m_codeType(EvalCode) - , m_nextConstantOffset(0) - , m_globalConstantIndex(0) - , m_firstLazyFunction(0) - , m_lastLazyFunction(0) - , m_staticPropertyAnalyzer(&m_instructions) , m_vm(&vm) - , m_lastOpcodeID(op_end) -#ifndef NDEBUG - , m_lastOpcodePosition(0) -#endif - , m_usesExceptions(false) - , m_expressionTooDeep(false) - , m_isBuiltinFunction(false) { + for (auto& constantRegister : m_linkTimeConstantRegisters) + constantRegister = nullptr; + m_symbolTable->setUsesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()); m_codeBlock->setNumParameters(1); emitOpcode(op_enter); + allocateAndEmitScope(); + const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); for (size_t i = 0; i < functionStack.size(); ++i) m_codeBlock->addFunctionDecl(makeFunction(functionStack[i])); @@ -454,101 +526,33 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod Vector<Identifier, 0, UnsafeVectorOverflow> variables; variables.reserveCapacity(numVariables); for (size_t i = 0; i < numVariables; ++i) { - ASSERT(varStack[i].first.impl()->isAtomic()); + ASSERT(varStack[i].first.impl()->isAtomic() || varStack[i].first.impl()->isSymbol()); variables.append(varStack[i].first); } codeBlock->adoptVariables(variables); - preserveLastVar(); } BytecodeGenerator::~BytecodeGenerator() { } -RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg) -{ - emitOpcode(op_init_lazy_reg); - instructions().append(reg->index()); - ASSERT(!hasWatchableVariable(reg->index())); - return reg; -} - -RegisterID* BytecodeGenerator::resolveCallee(FunctionBodyNode* functionBodyNode) -{ - if (!functionNameIsInScope(functionBodyNode->ident(), functionBodyNode->functionMode())) - return 0; - - if (functionNameScopeIsDynamic(m_codeBlock->usesEval(), m_codeBlock->isStrictMode())) - return 0; - - m_calleeRegister.setIndex(JSStack::Callee); - if (functionBodyNode->captures(functionBodyNode->ident())) - return emitMove(addVar(), IsCaptured, &m_calleeRegister); - - return &m_calleeRegister; -} - -void BytecodeGenerator::addCallee(FunctionBodyNode* functionBodyNode, RegisterID* calleeRegister) -{ - if (!calleeRegister) - return; - - symbolTable().add(functionBodyNode->ident().impl(), SymbolTableEntry(calleeRegister->index(), ReadOnly)); -} - -void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex) +RegisterID* BytecodeGenerator::initializeNextParameter() { - // Parameters overwrite var declarations, but not function declarations. - StringImpl* rep = ident.impl(); - if (!m_functions.contains(rep)) { - symbolTable().set(rep, parameterIndex); - RegisterID& parameter = registerFor(parameterIndex); - parameter.setIndex(parameterIndex); - } - - // To maintain the calling convention, we have to allocate unique space for - // each parameter, even if the parameter doesn't make it into the symbol table. + VirtualRegister reg = virtualRegisterForArgument(m_codeBlock->numParameters()); + RegisterID& parameter = registerFor(reg); + parameter.setIndex(reg.offset()); m_codeBlock->addParameter(); + return ¶meter; } -bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) -{ - if (ident != propertyNames().arguments) - return false; - - if (!shouldOptimizeLocals()) - return false; - - SymbolTableEntry entry = symbolTable().get(ident.impl()); - if (entry.isNull()) - return false; - - if (m_codeBlock->usesArguments() && m_codeType == FunctionCode) - return true; - - return false; -} - -RegisterID* BytecodeGenerator::uncheckedRegisterForArguments() -{ - ASSERT(willResolveToArguments(propertyNames().arguments)); - - SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl()); - ASSERT(!entry.isNull()); - return ®isterFor(entry.getIndex()); -} - -RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg) +UniquedStringImpl* BytecodeGenerator::visibleNameForParameter(DestructuringPatternNode* pattern) { - if (!reg->virtualRegister().isLocal()) - return reg; - - int localVariableNumber = reg->virtualRegister().toLocal(); - - if (m_lastLazyFunction <= localVariableNumber || localVariableNumber < m_firstLazyFunction) - return reg; - emitLazyNewFunction(reg, m_lazyFunctions.get(localVariableNumber)); - return reg; + if (pattern->isBindingNode()) { + const Identifier& ident = static_cast<const BindingNode*>(pattern)->boundProperty(); + if (!m_functions.contains(ident.impl())) + return ident.impl(); + } + return nullptr; } RegisterID* BytecodeGenerator::newRegister() @@ -590,7 +594,7 @@ PassRefPtr<Label> BytecodeGenerator::newLabel() m_labels.removeLast(); // Allocate new label ID. - m_labels.append(this); + m_labels.append(*this); return &m_labels.last(); } @@ -948,9 +952,15 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond return target; } +bool BytecodeGenerator::hasConstant(const Identifier& ident) const +{ + UniquedStringImpl* rep = ident.impl(); + return m_identifierMap.contains(rep); +} + unsigned BytecodeGenerator::addConstant(const Identifier& ident) { - StringImpl* rep = ident.impl(); + UniquedStringImpl* rep = ident.impl(); IdentifierMap::AddResult result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers()); if (result.isNewEntry) m_codeBlock->addIdentifier(ident); @@ -972,42 +982,70 @@ RegisterID* BytecodeGenerator::addConstantEmptyValue() return m_emptyValueRegister; } -RegisterID* BytecodeGenerator::addConstantValue(JSValue v) +RegisterID* BytecodeGenerator::addConstantValue(JSValue v, SourceCodeRepresentation sourceCodeRepresentation) { if (!v) return addConstantEmptyValue(); int index = m_nextConstantOffset; - JSValueMap::AddResult result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset); + + EncodedJSValueWithRepresentation valueMapKey { JSValue::encode(v), sourceCodeRepresentation }; + JSValueMap::AddResult result = m_jsValueMap.add(valueMapKey, m_nextConstantOffset); if (result.isNewEntry) { m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); ++m_nextConstantOffset; - m_codeBlock->addConstant(v); + m_codeBlock->addConstant(v, sourceCodeRepresentation); } else index = result.iterator->value; return &m_constantPoolRegisters[index]; } +RegisterID* BytecodeGenerator::emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant type) +{ + unsigned constantIndex = static_cast<unsigned>(type); + if (!m_linkTimeConstantRegisters[constantIndex]) { + int index = m_nextConstantOffset; + m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); + ++m_nextConstantOffset; + m_codeBlock->addConstant(type); + m_linkTimeConstantRegisters[constantIndex] = &m_constantPoolRegisters[index]; + } + + emitOpcode(op_mov); + instructions().append(dst->index()); + instructions().append(m_linkTimeConstantRegisters[constantIndex]->index()); + + return dst; +} + unsigned BytecodeGenerator::addRegExp(RegExp* r) { return m_codeBlock->addRegExp(r); } -RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, CaptureMode captureMode, RegisterID* src) +RegisterID* BytecodeGenerator::emitMoveEmptyValue(RegisterID* dst) { - m_staticPropertyAnalyzer.mov(dst->index(), src->index()); + RefPtr<RegisterID> emptyValue = addConstantEmptyValue(); - emitOpcode(captureMode == IsCaptured ? op_captured_mov : op_mov); + emitOpcode(op_mov); instructions().append(dst->index()); - instructions().append(src->index()); - if (captureMode == IsCaptured) - instructions().append(watchableVariable(dst->index())); + instructions().append(emptyValue->index()); return dst; } RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src) { - return emitMove(dst, captureMode(dst->index()), src); + ASSERT(src != m_emptyValueRegister); + + m_staticPropertyAnalyzer.mov(dst->index(), src->index()); + emitOpcode(op_mov); + instructions().append(dst->index()); + instructions().append(src->index()); + + if (!dst->isTemporary() && vm()->typeProfiler()) + emitProfileType(dst, ProfileTypeBytecodeHasGlobalID, nullptr); + + return dst; } RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src) @@ -1089,7 +1127,7 @@ RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst } if (value == "object") { rewindUnaryOp(); - emitOpcode(op_is_object); + emitOpcode(op_is_object_or_null); instructions().append(dst->index()); instructions().append(srcIndex); return dst; @@ -1111,22 +1149,43 @@ RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst return dst; } -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b) +void BytecodeGenerator::emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot) { - return emitLoad(dst, jsBoolean(b)); + unsigned start = startDivot.offset; // Ranges are inclusive of their endpoints, AND 0 indexed. + unsigned end = endDivot.offset - 1; // End Ranges already go one past the inclusive range, so subtract 1. + unsigned instructionOffset = instructions().size() - 1; + m_codeBlock->addTypeProfilerExpressionInfo(instructionOffset, start, end); +} + +void BytecodeGenerator::emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag flag, const Identifier* identifier) +{ + if (flag == ProfileTypeBytecodeGetFromScope || flag == ProfileTypeBytecodePutToScope) + RELEASE_ASSERT(identifier); + + // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType? + emitOpcode(op_profile_type); + instructions().append(registerToProfile->index()); + instructions().append(0); + instructions().append(flag); + instructions().append(identifier ? addConstant(*identifier) : 0); + instructions().append(resolveType()); } -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number) +void BytecodeGenerator::emitProfileControlFlow(int textOffset) { - // FIXME: Our hash tables won't hold infinity, so we make a new JSValue each time. - // Later we can do the extra work to handle that like the other cases. They also don't - // work correctly with NaN as a key. - if (std::isnan(number) || number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number)) - return emitLoad(dst, jsNumber(number)); - JSValue& valueInMap = m_numberMap.add(number, JSValue()).iterator->value; - if (!valueInMap) - valueInMap = jsNumber(number); - return emitLoad(dst, valueInMap); + if (vm()->controlFlowProfiler()) { + RELEASE_ASSERT(textOffset >= 0); + size_t bytecodeOffset = instructions().size(); + m_codeBlock->addOpProfileControlFlowBytecodeOffset(bytecodeOffset); + + emitOpcode(op_profile_control_flow); + instructions().append(textOffset); + } +} + +RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b) +{ + return emitLoad(dst, jsBoolean(b)); } RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier) @@ -1137,9 +1196,9 @@ RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& ident return emitLoad(dst, JSValue(stringInMap)); } -RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v) +RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v, SourceCodeRepresentation sourceCodeRepresentation) { - RegisterID* constantID = addConstantValue(v); + RegisterID* constantID = addConstantValue(v, sourceCodeRepresentation); if (dst) return emitMove(dst, constantID); return constantID; @@ -1160,41 +1219,96 @@ RegisterID* BytecodeGenerator::emitLoadGlobalObject(RegisterID* dst) return m_globalObjectRegister; } -bool BytecodeGenerator::isCaptured(int operand) +Variable BytecodeGenerator::variable(const Identifier& property) { - return m_symbolTable && m_symbolTable->isCaptured(operand); -} - -Local BytecodeGenerator::local(const Identifier& property) -{ - if (property == propertyNames().thisIdentifier) - return Local(thisRegister(), ReadOnly, NotCaptured); + if (property == propertyNames().thisIdentifier) { + return Variable( + property, VarOffset(thisRegister()->virtualRegister()), thisRegister(), + ReadOnly, Variable::SpecialVariable); + } - if (property == propertyNames().arguments) - createArgumentsIfNecessary(); - if (!shouldOptimizeLocals()) - return Local(); + return Variable(property); + + SymbolTableEntry entry = symbolTable().get(property.impl()); + if (entry.isNull()) + return Variable(property); + + if (entry.varOffset().isScope() && m_localScopeDepth) { + // FIXME: We should be able to statically resolve through our local scopes. + // https://bugs.webkit.org/show_bug.cgi?id=141885 + return Variable(property); + } + + return variableForLocalEntry(property, entry); +} +Variable BytecodeGenerator::variablePerSymbolTable(const Identifier& property) +{ SymbolTableEntry entry = symbolTable().get(property.impl()); if (entry.isNull()) - return Local(); + return Variable(property); + + return variableForLocalEntry(property, entry); +} - RegisterID* local = createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); - return Local(local, entry.getAttributes(), captureMode(local->index())); +Variable BytecodeGenerator::variableForLocalEntry( + const Identifier& property, const SymbolTableEntry& entry) +{ + VarOffset offset = entry.varOffset(); + + RegisterID* local; + if (offset.isStack()) + local = ®isterFor(offset.stackOffset()); + else + local = nullptr; + + return Variable(property, offset, local, entry.getAttributes(), Variable::NormalVariable); } -Local BytecodeGenerator::constLocal(const Identifier& property) +void BytecodeGenerator::createVariable( + const Identifier& property, VarKind varKind, ConstantMode constantMode, + ExistingVariableMode existingVariableMode) { - if (m_codeType != FunctionCode) - return Local(); + ASSERT(property != propertyNames().thisIdentifier); + + ConcurrentJITLocker locker(symbolTable().m_lock); + SymbolTableEntry entry = symbolTable().get(locker, property.impl()); + + if (!entry.isNull()) { + if (existingVariableMode == IgnoreExisting) + return; + + // Do some checks to ensure that the variable we're being asked to create is sufficiently + // compatible with the one we have already created. - SymbolTableEntry entry = symbolTable().get(property.impl()); - if (entry.isNull()) - return Local(); + VarOffset offset = entry.varOffset(); + + // We can't change our minds about whether it's captured. + if (offset.kind() != varKind || constantMode != entry.constantMode()) { + dataLog( + "Trying to add variable called ", property, " as ", varKind, "/", constantMode, + " but it was already added as ", offset, "/", entry.constantMode(), ".\n"); + RELEASE_ASSERT_NOT_REACHED(); + } - RegisterID* local = createLazyRegisterIfNecessary(®isterFor(entry.getIndex())); - return Local(local, entry.getAttributes(), captureMode(local->index())); + return; + } + + VarOffset varOffset; + if (varKind == VarKind::Scope) + varOffset = VarOffset(symbolTable().takeNextScopeOffset(locker)); + else { + ASSERT(varKind == VarKind::Stack); + varOffset = VarOffset(virtualRegisterForLocal(m_calleeRegisters.size())); + } + SymbolTableEntry newEntry(varOffset, constantMode == IsConstant ? ReadOnly : 0); + symbolTable().add(locker, property.impl(), newEntry); + + if (varKind == VarKind::Stack) { + RegisterID* local = addVar(); + RELEASE_ASSERT(local->index() == varOffset.stackOffset().offset()); + } } void BytecodeGenerator::emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target) @@ -1218,55 +1332,147 @@ ResolveType BytecodeGenerator::resolveType() return GlobalProperty; } -RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Identifier& identifier) +RegisterID* BytecodeGenerator::emitResolveScope(RegisterID* dst, const Variable& variable) { - m_codeBlock->addPropertyAccessInstruction(instructions().size()); - - ASSERT(!m_symbolTable || !m_symbolTable->contains(identifier.impl()) || resolveType() == Dynamic); - - // resolve_scope dst, id, ResolveType, depth - emitOpcode(op_resolve_scope); - instructions().append(kill(dst)); - instructions().append(addConstant(identifier)); - instructions().append(resolveType()); - instructions().append(0); - instructions().append(0); - return dst; + switch (variable.offset().kind()) { + case VarKind::Stack: + return nullptr; + + case VarKind::DirectArgument: + return argumentsRegister(); + + case VarKind::Scope: + // This always refers to the activation that *we* allocated, and not the current scope that code + // lives in. Note that this will change once we have proper support for block scoping. Once that + // changes, it will be correct for this code to return scopeRegister(). The only reason why we + // don't do that already is that m_lexicalEnvironment is required by ConstDeclNode. ConstDeclNode + // requires weird things because it is a shameful pile of nonsense, but block scoping would make + // that code sensible and obviate the need for us to do bad things. + return m_lexicalEnvironmentRegister; + + case VarKind::Invalid: + // Indicates non-local resolution. + + ASSERT(!m_symbolTable || !m_symbolTable->contains(variable.ident().impl()) || resolveType() == Dynamic); + + m_codeBlock->addPropertyAccessInstruction(instructions().size()); + + // resolve_scope dst, id, ResolveType, depth + emitOpcode(op_resolve_scope); + dst = tempDestination(dst); + instructions().append(kill(dst)); + instructions().append(scopeRegister()->index()); + instructions().append(addConstant(variable.ident())); + instructions().append(resolveType()); + instructions().append(0); + instructions().append(0); + return dst; + } + + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; } -RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier& identifier, ResolveMode resolveMode) +RegisterID* BytecodeGenerator::emitGetFromScope(RegisterID* dst, RegisterID* scope, const Variable& variable, ResolveMode resolveMode) { - m_codeBlock->addPropertyAccessInstruction(instructions().size()); + switch (variable.offset().kind()) { + case VarKind::Stack: + return emitMove(dst, variable.local()); + + case VarKind::DirectArgument: { + UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_arguments); + instructions().append(kill(dst)); + instructions().append(scope->index()); + instructions().append(variable.offset().capturedArgumentsOffset().offset()); + instructions().append(profile); + return dst; + } + + case VarKind::Scope: + case VarKind::Invalid: { + m_codeBlock->addPropertyAccessInstruction(instructions().size()); + + // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand + UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_scope); + instructions().append(kill(dst)); + instructions().append(scope->index()); + instructions().append(addConstant(variable.ident())); + instructions().append(ResolveModeAndType(resolveMode, variable.offset().isScope() ? LocalClosureVar : resolveType()).operand()); + instructions().append(0); + instructions().append(variable.offset().isScope() ? variable.offset().scopeOffset().offset() : 0); + instructions().append(profile); + return dst; + } } + + RELEASE_ASSERT_NOT_REACHED(); +} - // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand - UnlinkedValueProfile profile = emitProfiledOpcode(op_get_from_scope); - instructions().append(kill(dst)); - instructions().append(scope->index()); - instructions().append(addConstant(identifier)); - instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand()); - instructions().append(0); - instructions().append(0); - instructions().append(profile); - return dst; +RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Variable& variable, RegisterID* value, ResolveMode resolveMode) +{ + switch (variable.offset().kind()) { + case VarKind::Stack: + emitMove(variable.local(), value); + return value; + + case VarKind::DirectArgument: + emitOpcode(op_put_to_arguments); + instructions().append(scope->index()); + instructions().append(variable.offset().capturedArgumentsOffset().offset()); + instructions().append(value->index()); + return value; + + case VarKind::Scope: + case VarKind::Invalid: { + m_codeBlock->addPropertyAccessInstruction(instructions().size()); + + // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand + emitOpcode(op_put_to_scope); + instructions().append(scope->index()); + instructions().append(addConstant(variable.ident())); + instructions().append(value->index()); + ScopeOffset offset; + if (variable.offset().isScope()) { + offset = variable.offset().scopeOffset(); + instructions().append(ResolveModeAndType(resolveMode, LocalClosureVar).operand()); + } else { + ASSERT(resolveType() != LocalClosureVar); + instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand()); + } + instructions().append(0); + instructions().append(!!offset ? offset.offset() : 0); + return value; + } } + + RELEASE_ASSERT_NOT_REACHED(); } -RegisterID* BytecodeGenerator::emitPutToScope(RegisterID* scope, const Identifier& identifier, RegisterID* value, ResolveMode resolveMode) +RegisterID* BytecodeGenerator::initializeVariable(const Variable& variable, RegisterID* value) { - m_codeBlock->addPropertyAccessInstruction(instructions().size()); + RegisterID* scope; + switch (variable.offset().kind()) { + case VarKind::Stack: + scope = nullptr; + break; + + case VarKind::DirectArgument: + scope = argumentsRegister(); + break; + + case VarKind::Scope: + scope = scopeRegister(); + break; + + default: + scope = nullptr; + RELEASE_ASSERT_NOT_REACHED(); + break; + } - // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand - emitOpcode(op_put_to_scope); - instructions().append(scope->index()); - instructions().append(addConstant(identifier)); - instructions().append(value->index()); - instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand()); - instructions().append(0); - instructions().append(0); - return value; + return emitPutToScope(scope, variable, value, ThrowIfNotFound); } RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype) -{ +{ emitOpcode(op_instanceof); instructions().append(dst->index()); instructions().append(value->index()); @@ -1301,16 +1507,6 @@ RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, co return dst; } -RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base) -{ - emitOpcode(op_get_arguments_length); - instructions().append(dst->index()); - ASSERT(base->virtualRegister() == m_codeBlock->argumentsRegister()); - instructions().append(base->index()); - instructions().append(addConstant(propertyNames().length)); - return dst; -} - RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value) { unsigned propertyIndex = addConstant(property); @@ -1328,11 +1524,13 @@ RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& p instructions().append(0); instructions().append(0); instructions().append(0); + return value; } -RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value) +RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType putType) { + ASSERT(!parseIndex(property)); unsigned propertyIndex = addConstant(property); m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); @@ -1347,12 +1545,32 @@ RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identif instructions().append(0); instructions().append(0); instructions().append(0); - instructions().append( - property != m_vm->propertyNames->underscoreProto - && PropertyName(property).asIndex() == PropertyName::NotAnIndex); + instructions().append(putType == PropertyNode::KnownDirect || property != m_vm->propertyNames->underscoreProto); return value; } +void BytecodeGenerator::emitPutGetterById(RegisterID* base, const Identifier& property, RegisterID* getter) +{ + unsigned propertyIndex = addConstant(property); + m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); + + emitOpcode(op_put_getter_by_id); + instructions().append(base->index()); + instructions().append(propertyIndex); + instructions().append(getter->index()); +} + +void BytecodeGenerator::emitPutSetterById(RegisterID* base, const Identifier& property, RegisterID* setter) +{ + unsigned propertyIndex = addConstant(property); + m_staticPropertyAnalyzer.putById(base->index(), propertyIndex); + + emitOpcode(op_put_setter_by_id); + instructions().append(base->index()); + instructions().append(propertyIndex); + instructions().append(setter->index()); +} + void BytecodeGenerator::emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter) { unsigned propertyIndex = addConstant(property); @@ -1375,34 +1593,33 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, return dst; } -RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property) -{ - UnlinkedArrayProfile arrayProfile = newArrayProfile(); - UnlinkedValueProfile profile = emitProfiledOpcode(op_get_argument_by_val); - instructions().append(kill(dst)); - ASSERT(base->virtualRegister() == m_codeBlock->argumentsRegister()); - instructions().append(base->index()); - instructions().append(property->index()); - instructions().append(arrayProfile); - instructions().append(profile); - return dst; -} - RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property) { for (size_t i = m_forInContextStack.size(); i > 0; i--) { - ForInContext& context = m_forInContextStack[i - 1]; - if (context.propertyRegister == property) { - emitOpcode(op_get_by_pname); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(property->index()); - instructions().append(context.expectedSubscriptRegister->index()); - instructions().append(context.iterRegister->index()); - instructions().append(context.indexRegister->index()); - return dst; + ForInContext* context = m_forInContextStack[i - 1].get(); + if (context->local() != property) + continue; + + if (!context->isValid()) + break; + + if (context->type() == ForInContext::IndexedForInContextType) { + property = static_cast<IndexedForInContext*>(context)->index(); + break; } + + ASSERT(context->type() == ForInContext::StructureForInContextType); + StructureForInContext* structureContext = static_cast<StructureForInContext*>(context); + UnlinkedValueProfile profile = emitProfiledOpcode(op_get_direct_pname); + instructions().append(kill(dst)); + instructions().append(base->index()); + instructions().append(property->index()); + instructions().append(structureContext->index()->index()); + instructions().append(structureContext->enumerator()->index()); + instructions().append(profile); + return dst; } + UnlinkedArrayProfile arrayProfile = newArrayProfile(); UnlinkedValueProfile profile = emitProfiledOpcode(op_get_by_val); instructions().append(kill(dst)); @@ -1416,14 +1633,12 @@ RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, R RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value) { UnlinkedArrayProfile arrayProfile = newArrayProfile(); - if (m_isBuiltinFunction) - emitOpcode(op_put_by_val_direct); - else - emitOpcode(op_put_by_val); + emitOpcode(op_put_by_val); instructions().append(base->index()); instructions().append(property->index()); instructions().append(value->index()); instructions().append(arrayProfile); + return value; } @@ -1457,24 +1672,25 @@ RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, } RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst) -{ - RefPtr<RegisterID> func = newTemporary(); - - m_codeBlock->addPropertyAccessInstruction(instructions().size()); - emitOpcode(op_get_callee); - instructions().append(func->index()); - instructions().append(0); - +{ size_t begin = instructions().size(); m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3); + m_codeBlock->addPropertyAccessInstruction(instructions().size()); emitOpcode(op_create_this); instructions().append(m_thisRegister.index()); - instructions().append(func->index()); + instructions().append(m_thisRegister.index()); + instructions().append(0); instructions().append(0); return dst; } +void BytecodeGenerator::emitTDZCheck(RegisterID* target) +{ + emitOpcode(op_check_tdz); + instructions().append(target->index()); +} + RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst) { size_t begin = instructions().size(); @@ -1502,6 +1718,16 @@ JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier) return stringInMap; } +JSTemplateRegistryKey* BytecodeGenerator::addTemplateRegistryKeyConstant(const TemplateRegistryKey& templateRegistryKey) +{ + JSTemplateRegistryKey*& templateRegistryKeyInMap = m_templateRegistryKeyMap.add(templateRegistryKey, nullptr).iterator->value; + if (!templateRegistryKeyInMap) { + templateRegistryKeyInMap = JSTemplateRegistryKey::create(*vm(), templateRegistryKey); + addConstantValue(templateRegistryKeyInMap); + } + return templateRegistryKeyInMap; +} + RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length) { #if !ASSERT_DISABLED @@ -1558,30 +1784,17 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen return dst; } -RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, CaptureMode captureMode, FunctionBodyNode* function) -{ - return emitNewFunctionInternal(dst, captureMode, m_codeBlock->addFunctionDecl(makeFunction(function)), false); -} - -RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function) +RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) { - FunctionOffsetMap::AddResult ptr = m_functionOffsets.add(function, 0); - if (ptr.isNewEntry) - ptr.iterator->value = m_codeBlock->addFunctionDecl(makeFunction(function)); - return emitNewFunctionInternal(dst, NotCaptured, ptr.iterator->value, true); + return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(function))); } -RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, CaptureMode captureMode, unsigned index, bool doNullCheck) +RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index) { - createActivationIfNecessary(); - emitOpcode(captureMode == IsCaptured ? op_new_captured_func : op_new_func); + emitOpcode(op_new_func); instructions().append(dst->index()); + instructions().append(scopeRegister()->index()); instructions().append(index); - if (captureMode == IsCaptured) { - ASSERT(!doNullCheck); - instructions().append(watchableVariable(dst->index())); - } else - instructions().append(doNullCheck); return dst; } @@ -1597,54 +1810,42 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExp { FunctionBodyNode* function = n->body(); unsigned index = m_codeBlock->addFunctionExpr(makeFunction(function)); - - createActivationIfNecessary(); + emitOpcode(op_new_func_exp); instructions().append(r0->index()); + instructions().append(scopeRegister()->index()); instructions().append(index); return r0; } -RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) -{ - return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd); -} - -void BytecodeGenerator::createArgumentsIfNecessary() +RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name) { - if (m_codeType != FunctionCode) - return; - - if (!m_codeBlock->usesArguments()) - return; + UnlinkedFunctionExecutable* executable = m_vm->builtinExecutables()->createDefaultConstructor(constructorKind, name); - if (shouldTearOffArgumentsEagerly()) - return; + unsigned index = m_codeBlock->addFunctionExpr(executable); - emitOpcode(op_create_arguments); - instructions().append(m_codeBlock->argumentsRegister().offset()); - ASSERT(!hasWatchableVariable(m_codeBlock->argumentsRegister().offset())); + emitOpcode(op_new_func_exp); + instructions().append(dst->index()); + instructions().append(scopeRegister()->index()); + instructions().append(index); + return dst; } -void BytecodeGenerator::createActivationIfNecessary() +RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) { - if (!m_activationRegister) - return; - emitOpcode(op_create_activation); - instructions().append(m_activationRegister->index()); + return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd); } RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) { - createActivationIfNecessary(); return emitCall(op_call_eval, dst, func, NoExpectedFunction, callArguments, divot, divotStart, divotEnd); } ExpectedFunction BytecodeGenerator::expectedFunctionForIdentifier(const Identifier& identifier) { - if (identifier == m_vm->propertyNames->Object) + if (identifier == m_vm->propertyNames->Object || identifier == m_vm->propertyNames->ObjectPrivateName) return ExpectObjectConstructor; - if (identifier == m_vm->propertyNames->Array) + if (identifier == m_vm->propertyNames->Array || identifier == m_vm->propertyNames->ArrayPrivateName) return ExpectArrayConstructor; return NoExpectedFunction; } @@ -1731,10 +1932,7 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi RELEASE_ASSERT(!n->m_next); auto expression = static_cast<SpreadExpressionNode*>(n->m_expr)->expression(); RefPtr<RegisterID> argumentRegister; - if (expression->isResolveNode() && willResolveToArguments(static_cast<ResolveNode*>(expression)->identifier()) && !symbolTable().slowArguments()) - argumentRegister = uncheckedRegisterForArguments(); - else - argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0)); + argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0)); RefPtr<RegisterID> thisRegister = emitMove(newTemporary(), callArguments.thisRegister()); return emitCallVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd); } @@ -1787,9 +1985,9 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func return emitCallVarargs(op_call_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd); } -RegisterID* BytecodeGenerator::emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) +RegisterID* BytecodeGenerator::emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) { - return emitCallVarargs(op_construct_varargs, dst, func, 0, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd); + return emitCallVarargs(op_construct_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd); } RegisterID* BytecodeGenerator::emitCallVarargs(OpcodeID opcode, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) @@ -1821,28 +2019,65 @@ RegisterID* BytecodeGenerator::emitCallVarargs(OpcodeID opcode, RegisterID* dst, return dst; } -RegisterID* BytecodeGenerator::emitReturn(RegisterID* src) +void BytecodeGenerator::emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister, + RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition& position) { - if (m_activationRegister) { - emitOpcode(op_tear_off_activation); - instructions().append(m_activationRegister->index()); - } + RefPtr<RegisterID> descriptorRegister = emitNewObject(newTemporary()); - if (m_codeBlock->usesArguments() && m_codeBlock->numParameters() != 1 && !isStrictMode()) { - emitOpcode(op_tear_off_arguments); - instructions().append(m_codeBlock->argumentsRegister().offset()); - instructions().append(m_activationRegister ? m_activationRegister->index() : emitLoad(0, JSValue())->index()); + RefPtr<RegisterID> trueRegister = emitLoad(newTemporary(), true); + if (options & PropertyConfigurable) + emitDirectPutById(descriptorRegister.get(), propertyNames().configurable, trueRegister.get(), PropertyNode::Unknown); + if (options & PropertyWritable) + emitDirectPutById(descriptorRegister.get(), propertyNames().writable, trueRegister.get(), PropertyNode::Unknown); + else if (valueRegister) { + RefPtr<RegisterID> falseRegister = emitLoad(newTemporary(), false); + emitDirectPutById(descriptorRegister.get(), propertyNames().writable, falseRegister.get(), PropertyNode::Unknown); } + if (options & PropertyEnumerable) + emitDirectPutById(descriptorRegister.get(), propertyNames().enumerable, trueRegister.get(), PropertyNode::Unknown); + + if (valueRegister) + emitDirectPutById(descriptorRegister.get(), propertyNames().value, valueRegister, PropertyNode::Unknown); + if (getterRegister) + emitDirectPutById(descriptorRegister.get(), propertyNames().get, getterRegister, PropertyNode::Unknown); + if (setterRegister) + emitDirectPutById(descriptorRegister.get(), propertyNames().set, setterRegister, PropertyNode::Unknown); + + RefPtr<RegisterID> definePropertyRegister = emitMoveLinkTimeConstant(newTemporary(), LinkTimeConstant::DefinePropertyFunction); + + CallArguments callArguments(*this, nullptr, 3); + emitLoad(callArguments.thisRegister(), jsUndefined()); + emitMove(callArguments.argumentRegister(0), newObj); + emitMove(callArguments.argumentRegister(1), propertyNameRegister); + emitMove(callArguments.argumentRegister(2), descriptorRegister.get()); + + emitCall(newTemporary(), definePropertyRegister.get(), NoExpectedFunction, callArguments, position, position, position); +} + +RegisterID* BytecodeGenerator::emitReturn(RegisterID* src) +{ + if (isConstructor()) { + bool derived = constructorKind() == ConstructorKind::Derived; + if (derived && src->index() == m_thisRegister.index()) + emitTDZCheck(src); + + RefPtr<Label> isObjectLabel = newLabel(); + emitJumpIfTrue(emitIsObject(newTemporary(), src), isObjectLabel.get()); + + if (derived) { + RefPtr<Label> isUndefinedLabel = newLabel(); + emitJumpIfTrue(emitIsUndefined(newTemporary(), src), isUndefinedLabel.get()); + emitThrowTypeError("Cannot return a non-object type in the constructor of a derived class."); + emitLabel(isUndefinedLabel.get()); + if (constructorKind() == ConstructorKind::Derived) + emitTDZCheck(&m_thisRegister); + } - // Constructors use op_ret_object_or_this to check the result is an - // object, unless we can trivially determine the check is not - // necessary (currently, if the return value is 'this'). - if (isConstructor() && (src->index() != m_thisRegister.index())) { - emitOpcode(op_ret_object_or_this); - instructions().append(src->index()); - instructions().append(m_thisRegister.index()); - return src; + emitUnaryNoDstOp(op_ret, &m_thisRegister); + + emitLabel(isObjectLabel.get()); } + return emitUnaryNoDstOp(op_ret, src); } @@ -1869,11 +2104,8 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, RELEASE_ASSERT(!n->m_next); auto expression = static_cast<SpreadExpressionNode*>(n->m_expr)->expression(); RefPtr<RegisterID> argumentRegister; - if (expression->isResolveNode() && willResolveToArguments(static_cast<ResolveNode*>(expression)->identifier()) && !symbolTable().slowArguments()) - argumentRegister = uncheckedRegisterForArguments(); - else - argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0)); - return emitConstructVarargs(dst, func, argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd); + argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0)); + return emitConstructVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd); } for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) @@ -1934,23 +2166,29 @@ void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src) instructions().append(src->index()); } -RegisterID* BytecodeGenerator::emitPushWithScope(RegisterID* scope) +void BytecodeGenerator::emitGetScope() +{ + emitOpcode(op_get_scope); + instructions().append(scopeRegister()->index()); +} + +RegisterID* BytecodeGenerator::emitPushWithScope(RegisterID* dst, RegisterID* scope) { ControlFlowContext context; context.isFinallyBlock = false; m_scopeContextStack.append(context); m_localScopeDepth++; - createActivationIfNecessary(); - return emitUnaryNoDstOp(op_push_with_scope, scope); + return emitUnaryOp(op_push_with_scope, dst, scope); } -void BytecodeGenerator::emitPopScope() +void BytecodeGenerator::emitPopScope(RegisterID* srcDst) { ASSERT(m_scopeContextStack.size()); ASSERT(!m_scopeContextStack.last().isFinallyBlock); emitOpcode(op_pop_scope); + instructions().append(srcDst->index()); m_scopeContextStack.removeLast(); m_localScopeDepth--; @@ -1982,6 +2220,33 @@ void BytecodeGenerator::pushFinallyContext(StatementNode* finallyBlock) scope.isFinallyBlock = true; FinallyContext context = { finallyBlock, + nullptr, + nullptr, + static_cast<unsigned>(m_scopeContextStack.size()), + static_cast<unsigned>(m_switchContextStack.size()), + static_cast<unsigned>(m_forInContextStack.size()), + static_cast<unsigned>(m_tryContextStack.size()), + static_cast<unsigned>(m_labelScopes.size()), + m_finallyDepth, + m_localScopeDepth + }; + scope.finallyContext = context; + m_scopeContextStack.append(scope); + m_finallyDepth++; +} + +void BytecodeGenerator::pushIteratorCloseContext(RegisterID* iterator, ThrowableExpressionData* node) +{ + // Reclaim free label scopes. + while (m_labelScopes.size() && !m_labelScopes.last().refCount()) + m_labelScopes.removeLast(); + + ControlFlowContext scope; + scope.isFinallyBlock = true; + FinallyContext context = { + nullptr, + iterator, + node, static_cast<unsigned>(m_scopeContextStack.size()), static_cast<unsigned>(m_switchContextStack.size()), static_cast<unsigned>(m_forInContextStack.size()), @@ -1999,6 +2264,21 @@ void BytecodeGenerator::popFinallyContext() { ASSERT(m_scopeContextStack.size()); ASSERT(m_scopeContextStack.last().isFinallyBlock); + ASSERT(m_scopeContextStack.last().finallyContext.finallyBlock); + ASSERT(!m_scopeContextStack.last().finallyContext.iterator); + ASSERT(!m_scopeContextStack.last().finallyContext.enumerationNode); + ASSERT(m_finallyDepth > 0); + m_scopeContextStack.removeLast(); + m_finallyDepth--; +} + +void BytecodeGenerator::popIteratorCloseContext() +{ + ASSERT(m_scopeContextStack.size()); + ASSERT(m_scopeContextStack.last().isFinallyBlock); + ASSERT(!m_scopeContextStack.last().finallyContext.finallyBlock); + ASSERT(m_scopeContextStack.last().finallyContext.iterator); + ASSERT(m_scopeContextStack.last().finallyContext.enumerationNode); ASSERT(m_finallyDepth > 0); m_scopeContextStack.removeLast(); m_finallyDepth--; @@ -2081,7 +2361,15 @@ LabelScopePtr BytecodeGenerator::continueTarget(const Identifier& name) return LabelScopePtr::null(); } -void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope) +void BytecodeGenerator::allocateAndEmitScope() +{ + m_scopeRegister = addVar(); + m_scopeRegister->ref(); + m_codeBlock->setScopeRegister(scopeRegister()->virtualRegister()); + emitGetScope(); +} + +void BytecodeGenerator::emitComplexPopScopes(RegisterID* scope, ControlFlowContext* topScope, ControlFlowContext* bottomScope) { while (topScope > bottomScope) { // First we count the number of dynamic scopes we need to remove to get @@ -2097,8 +2385,10 @@ void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, Contr if (nNormalScopes) { // We need to remove a number of dynamic scopes to get to the next // finally block - while (nNormalScopes--) + while (nNormalScopes--) { emitOpcode(op_pop_scope); + instructions().append(scope->index()); + } // If topScope == bottomScope then there isn't a finally block left to emit. if (topScope == bottomScope) @@ -2107,7 +2397,7 @@ void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, Contr Vector<ControlFlowContext> savedScopeContextStack; Vector<SwitchInfo> savedSwitchContextStack; - Vector<ForInContext> savedForInContextStack; + Vector<std::unique_ptr<ForInContext>> savedForInContextStack; Vector<TryContext> poppedTryContexts; LabelScopeStore savedLabelScopes; while (topScope > bottomScope && topScope->isFinallyBlock) { @@ -2134,7 +2424,7 @@ void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, Contr m_switchContextStack.shrink(finallyContext.switchContextStackSize); } if (flipForIns) { - savedForInContextStack = m_forInContextStack; + savedForInContextStack.swap(m_forInContextStack); m_forInContextStack.shrink(finallyContext.forInContextStackSize); } if (flipTries) { @@ -2160,9 +2450,15 @@ void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, Contr int savedDynamicScopeDepth = m_localScopeDepth; m_localScopeDepth = finallyContext.dynamicScopeDepth; - // Emit the finally block. - emitNode(finallyContext.finallyBlock); - + if (finallyContext.finallyBlock) { + // Emit the finally block. + emitNode(finallyContext.finallyBlock); + } else { + // Emit the IteratorClose block. + ASSERT(finallyContext.iterator); + emitIteratorClose(finallyContext.iterator, finallyContext.enumerationNode); + } + RefPtr<Label> afterFinally = emitLabel(newLabel().get()); // Restore the state of the world. @@ -2174,7 +2470,7 @@ void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, Contr if (flipSwitches) m_switchContextStack = savedSwitchContextStack; if (flipForIns) - m_forInContextStack = savedForInContextStack; + m_forInContextStack.swap(savedForInContextStack); if (flipTries) { ASSERT(m_tryContextStack.size() == finallyContext.tryContextStackSize); for (unsigned i = poppedTryContexts.size(); i--;) { @@ -2194,7 +2490,7 @@ void BytecodeGenerator::emitComplexPopScopes(ControlFlowContext* topScope, Contr } } -void BytecodeGenerator::emitPopScopes(int targetScopeDepth) +void BytecodeGenerator::emitPopScopes(RegisterID* scope, int targetScopeDepth) { ASSERT(scopeDepth() - targetScopeDepth >= 0); @@ -2204,39 +2500,14 @@ void BytecodeGenerator::emitPopScopes(int targetScopeDepth) return; if (!m_finallyDepth) { - while (scopeDelta--) + while (scopeDelta--) { emitOpcode(op_pop_scope); + instructions().append(scope->index()); + } return; } - emitComplexPopScopes(&m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); -} - -RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget) -{ - size_t begin = instructions().size(); - - emitOpcode(op_get_pnames); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(i->index()); - instructions().append(size->index()); - instructions().append(breakTarget->bind(begin, instructions().size())); - return dst; -} - -RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target) -{ - size_t begin = instructions().size(); - - emitOpcode(op_next_pname); - instructions().append(dst->index()); - instructions().append(base->index()); - instructions().append(i->index()); - instructions().append(size->index()); - instructions().append(iter->index()); - instructions().append(target->bind(begin, instructions().size())); - return dst; + emitComplexPopScopes(scope, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); } TryData* BytecodeGenerator::pushTry(Label* start) @@ -2244,6 +2515,7 @@ TryData* BytecodeGenerator::pushTry(Label* start) TryData tryData; tryData.target = newLabel(); tryData.targetScopeDepth = UINT_MAX; + tryData.handlerType = HandlerType::Illegal; m_tryData.append(tryData); TryData* result = &m_tryData.last(); @@ -2256,7 +2528,7 @@ TryData* BytecodeGenerator::pushTry(Label* start) return result; } -RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* targetRegister, Label* end) +void BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType handlerType) { m_usesExceptions = true; @@ -2271,40 +2543,48 @@ RegisterID* BytecodeGenerator::popTryAndEmitCatch(TryData* tryData, RegisterID* emitLabel(tryRange.tryData->target.get()); tryRange.tryData->targetScopeDepth = m_localScopeDepth; + tryRange.tryData->handlerType = handlerType; emitOpcode(op_catch); - instructions().append(targetRegister->index()); - return targetRegister; + instructions().append(exceptionRegister->index()); + instructions().append(thrownValueRegister->index()); } void BytecodeGenerator::emitThrowReferenceError(const String& message) { emitOpcode(op_throw_static_error); - instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, message)))->index()); + instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, message)))->index()); instructions().append(true); } -void BytecodeGenerator::emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes) +void BytecodeGenerator::emitThrowTypeError(const String& message) +{ + emitOpcode(op_throw_static_error); + instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, message)))->index()); + instructions().append(false); +} + +void BytecodeGenerator::emitPushFunctionNameScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes) { emitOpcode(op_push_name_scope); - instructions().append(addConstant(property)); + instructions().append(dst->index()); instructions().append(value->index()); - instructions().append(attributes); + instructions().append(addConstantValue(SymbolTable::createNameScopeTable(*vm(), property, attributes))->index()); + instructions().append(JSNameScope::FunctionNameScope); } -void BytecodeGenerator::emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes) +void BytecodeGenerator::emitPushCatchScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes) { - createActivationIfNecessary(); - ControlFlowContext context; context.isFinallyBlock = false; m_scopeContextStack.append(context); m_localScopeDepth++; emitOpcode(op_push_name_scope); - instructions().append(addConstant(property)); + instructions().append(dst->index()); instructions().append(value->index()); - instructions().append(attributes); + instructions().append(addConstantValue(SymbolTable::createNameScopeTable(*vm(), property, attributes))->index()); + instructions().append(JSNameScope::CatchScope); } void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type) @@ -2429,16 +2709,11 @@ RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException() return newTemporary(); } -void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction) -{ - m_codeBlock->setIsNumericCompareFunction(isNumericCompareFunction); -} - bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber) { - RegisterID* registerID = local(ident).get(); - if (!registerID || registerID->index() >= 0) - return 0; + RegisterID* registerID = variable(ident).local(); + if (!registerID) + return false; return registerID->index() == CallFrame::argumentOffset(argumentNumber); } @@ -2447,64 +2722,286 @@ void BytecodeGenerator::emitReadOnlyExceptionIfNeeded() if (!isStrictMode()) return; emitOpcode(op_throw_static_error); - instructions().append(addConstantValue(addStringConstant(Identifier(m_vm, StrictModeReadonlyPropertyWriteError)))->index()); + instructions().append(addConstantValue(addStringConstant(Identifier::fromString(m_vm, StrictModeReadonlyPropertyWriteError)))->index()); instructions().append(false); } void BytecodeGenerator::emitEnumeration(ThrowableExpressionData* node, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack) { - if (subjectNode->isResolveNode() - && willResolveToArguments(static_cast<ResolveNode*>(subjectNode)->identifier()) - && !symbolTable().slowArguments()) { - RefPtr<RegisterID> index = emitLoad(newTemporary(), jsNumber(0)); + RefPtr<RegisterID> subject = newTemporary(); + emitNode(subject.get(), subjectNode); + RefPtr<RegisterID> iterator = emitGetById(newTemporary(), subject.get(), propertyNames().iteratorSymbol); + { + CallArguments args(*this, nullptr); + emitMove(args.thisRegister(), subject.get()); + emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd()); + } + RefPtr<Label> loopDone = newLabel(); + // RefPtr<Register> iterator's lifetime must be longer than IteratorCloseContext. + pushIteratorCloseContext(iterator.get(), node); + { LabelScopePtr scope = newLabelScope(LabelScope::Loop); - RefPtr<RegisterID> value = emitLoad(newTemporary(), jsUndefined()); - - RefPtr<Label> loopCondition = newLabel(); + RefPtr<RegisterID> value = newTemporary(); + emitLoad(value.get(), jsUndefined()); + + emitJump(scope->continueTarget()); + RefPtr<Label> loopStart = newLabel(); - emitJump(loopCondition.get()); emitLabel(loopStart.get()); emitLoopHint(); - emitGetArgumentByVal(value.get(), uncheckedRegisterForArguments(), index.get()); + + RefPtr<Label> tryStartLabel = newLabel(); + emitLabel(tryStartLabel.get()); + TryData* tryData = pushTry(tryStartLabel.get()); callBack(*this, value.get()); - + emitJump(scope->continueTarget()); + + // IteratorClose sequence for throw-ed control flow. + { + RefPtr<Label> catchHere = emitLabel(newLabel().get()); + RefPtr<RegisterID> exceptionRegister = newTemporary(); + RefPtr<RegisterID> thrownValueRegister = newTemporary(); + popTryAndEmitCatch(tryData, exceptionRegister.get(), + thrownValueRegister.get(), catchHere.get(), HandlerType::SynthesizedFinally); + + RefPtr<Label> catchDone = newLabel(); + + RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword); + emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), catchDone.get()); + + RefPtr<Label> returnCallTryStart = newLabel(); + emitLabel(returnCallTryStart.get()); + TryData* returnCallTryData = pushTry(returnCallTryStart.get()); + + CallArguments returnArguments(*this, nullptr); + emitMove(returnArguments.thisRegister(), iterator.get()); + emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd()); + + emitLabel(catchDone.get()); + emitThrow(exceptionRegister.get()); + + // Absorb exception. + popTryAndEmitCatch(returnCallTryData, newTemporary(), + newTemporary(), catchDone.get(), HandlerType::SynthesizedFinally); + emitThrow(exceptionRegister.get()); + } + emitLabel(scope->continueTarget()); - emitInc(index.get()); - emitLabel(loopCondition.get()); - RefPtr<RegisterID> length = emitGetArgumentsLength(newTemporary(), uncheckedRegisterForArguments()); - emitJumpIfTrue(emitEqualityOp(op_less, newTemporary(), index.get(), length.get()), loopStart.get()); + { + emitIteratorNext(value.get(), iterator.get(), node); + emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get()); + emitGetById(value.get(), value.get(), propertyNames().value); + emitJump(loopStart.get()); + } + emitLabel(scope->breakTarget()); - return; } - LabelScopePtr scope = newLabelScope(LabelScope::Loop); - RefPtr<RegisterID> subject = newTemporary(); - emitNode(subject.get(), subjectNode); - RefPtr<RegisterID> iterator = emitGetById(newTemporary(), subject.get(), propertyNames().iteratorPrivateName); + // IteratorClose sequence for break-ed control flow. + popIteratorCloseContext(); + emitIteratorClose(iterator.get(), node); + emitLabel(loopDone.get()); +} + +#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) +RegisterID* BytecodeGenerator::emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode* taggedTemplate) +{ + TemplateRegistryKey::StringVector rawStrings; + TemplateRegistryKey::StringVector cookedStrings; + + TemplateStringListNode* templateString = taggedTemplate->templateLiteral()->templateStrings(); + for (; templateString; templateString = templateString->next()) { + rawStrings.append(templateString->value()->raw().impl()); + cookedStrings.append(templateString->value()->cooked().impl()); + } + + RefPtr<RegisterID> getTemplateObject = nullptr; + Variable var = variable(propertyNames().getTemplateObjectPrivateName); + if (RegisterID* local = var.local()) + getTemplateObject = emitMove(newTemporary(), local); + else { + getTemplateObject = newTemporary(); + RefPtr<RegisterID> scope = newTemporary(); + moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var)); + emitGetFromScope(getTemplateObject.get(), scope.get(), var, ThrowIfNotFound); + } + + CallArguments arguments(*this, nullptr); + emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(TemplateRegistryKey(rawStrings, cookedStrings)))); + return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd()); +} +#endif + +RegisterID* BytecodeGenerator::emitGetEnumerableLength(RegisterID* dst, RegisterID* base) +{ + emitOpcode(op_get_enumerable_length); + instructions().append(dst->index()); + instructions().append(base->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName) +{ + emitOpcode(op_has_generic_property); + instructions().append(dst->index()); + instructions().append(base->index()); + instructions().append(propertyName->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName) +{ + UnlinkedArrayProfile arrayProfile = newArrayProfile(); + emitOpcode(op_has_indexed_property); + instructions().append(dst->index()); + instructions().append(base->index()); + instructions().append(propertyName->index()); + instructions().append(arrayProfile); + return dst; +} + +RegisterID* BytecodeGenerator::emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator) +{ + emitOpcode(op_has_structure_property); + instructions().append(dst->index()); + instructions().append(base->index()); + instructions().append(propertyName->index()); + instructions().append(enumerator->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base) +{ + emitOpcode(op_get_property_enumerator); + instructions().append(dst->index()); + instructions().append(base->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index) +{ + emitOpcode(op_enumerator_structure_pname); + instructions().append(dst->index()); + instructions().append(enumerator->index()); + instructions().append(index->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index) +{ + emitOpcode(op_enumerator_generic_pname); + instructions().append(dst->index()); + instructions().append(enumerator->index()); + instructions().append(index->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitToIndexString(RegisterID* dst, RegisterID* index) +{ + emitOpcode(op_to_index_string); + instructions().append(dst->index()); + instructions().append(index->index()); + return dst; +} + + +RegisterID* BytecodeGenerator::emitIsObject(RegisterID* dst, RegisterID* src) +{ + emitOpcode(op_is_object); + instructions().append(dst->index()); + instructions().append(src->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitIsUndefined(RegisterID* dst, RegisterID* src) +{ + emitOpcode(op_is_undefined); + instructions().append(dst->index()); + instructions().append(src->index()); + return dst; +} + +RegisterID* BytecodeGenerator::emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node) +{ { - CallArguments args(*this, 0); - emitMove(args.thisRegister(), subject.get()); - emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd()); + RefPtr<RegisterID> next = emitGetById(newTemporary(), iterator, propertyNames().next); + CallArguments nextArguments(*this, nullptr); + emitMove(nextArguments.thisRegister(), iterator); + emitCall(dst, next.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd()); + } + { + RefPtr<Label> typeIsObject = newLabel(); + emitJumpIfTrue(emitIsObject(newTemporary(), dst), typeIsObject.get()); + emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object.")); + emitLabel(typeIsObject.get()); } - RefPtr<RegisterID> iteratorNext = emitGetById(newTemporary(), iterator.get(), propertyNames().iteratorNextPrivateName); + return dst; +} + +void BytecodeGenerator::emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node) +{ + RefPtr<Label> done = newLabel(); + RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator, propertyNames().returnKeyword); + emitJumpIfTrue(emitIsUndefined(newTemporary(), returnMethod.get()), done.get()); + RefPtr<RegisterID> value = newTemporary(); - emitLoad(value.get(), jsUndefined()); - - emitJump(scope->continueTarget()); - - RefPtr<Label> loopStart = newLabel(); - emitLabel(loopStart.get()); - emitLoopHint(); - callBack(*this, value.get()); - emitLabel(scope->continueTarget()); - CallArguments nextArguments(*this, 0, 1); - emitMove(nextArguments.thisRegister(), iterator.get()); - emitMove(nextArguments.argumentRegister(0), value.get()); - emitCall(value.get(), iteratorNext.get(), NoExpectedFunction, nextArguments, node->divot(), node->divotStart(), node->divotEnd()); - RefPtr<RegisterID> result = newTemporary(); - emitJumpIfFalse(emitEqualityOp(op_stricteq, result.get(), value.get(), emitLoad(0, JSValue(vm()->iterationTerminator.get()))), loopStart.get()); - emitLabel(scope->breakTarget()); + CallArguments returnArguments(*this, nullptr); + emitMove(returnArguments.thisRegister(), iterator); + emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd()); + emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), done.get()); + emitThrowTypeError(ASCIILiteral("Iterator result interface is not an object.")); + emitLabel(done.get()); +} + +void BytecodeGenerator::pushIndexedForInScope(RegisterID* localRegister, RegisterID* indexRegister) +{ + if (!localRegister) + return; + m_forInContextStack.append(std::make_unique<IndexedForInContext>(localRegister, indexRegister)); +} + +void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister) +{ + if (!localRegister) + return; + m_forInContextStack.removeLast(); +} + +void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister) +{ + if (!localRegister) + return; + m_forInContextStack.append(std::make_unique<StructureForInContext>(localRegister, indexRegister, propertyRegister, enumeratorRegister)); +} + +void BytecodeGenerator::popStructureForInScope(RegisterID* localRegister) +{ + if (!localRegister) + return; + m_forInContextStack.removeLast(); +} + +void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister) +{ + // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if + // either of the following conditions is true: + // + // (1) The loop iteration variable is re-assigned within the body of the loop. + // (2) The loop iteration variable is captured in the lexical scope of the function. + // + // These two situations occur sufficiently rarely that it's okay to use this style of + // "analysis" to make iteration faster. If we didn't want to do this, we would either have + // to perform some flow-sensitive analysis to see if/when the loop iteration variable was + // reassigned, or we'd have to resort to runtime checks to see if the variable had been + // reassigned from its original value. + for (size_t i = m_forInContextStack.size(); i > 0; i--) { + ForInContext* context = m_forInContextStack[i - 1].get(); + if (context->local() != localRegister) + continue; + context->invalidate(); + break; + } } } // namespace JSC diff --git a/bytecompiler/BytecodeGenerator.h b/bytecompiler/BytecodeGenerator.h index 5e5ed61..1a9771e 100644 --- a/bytecompiler/BytecodeGenerator.h +++ b/bytecompiler/BytecodeGenerator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * Copyright (C) 2012 Igalia, S.L. * @@ -43,6 +43,7 @@ #include "Debugger.h" #include "Nodes.h" #include "StaticPropertyAnalyzer.h" +#include "TemplateRegistryKey.h" #include "UnlinkedCodeBlock.h" #include <functional> @@ -55,7 +56,7 @@ namespace JSC { class Identifier; - class Label; + class JSTemplateRegistryKey; enum ExpectedFunction { NoExpectedFunction, @@ -83,6 +84,8 @@ namespace JSC { struct FinallyContext { StatementNode* finallyBlock; + RegisterID* iterator; + ThrowableExpressionData* enumerationNode; unsigned scopeContextStackSize; unsigned switchContextStackSize; unsigned forInContextStackSize; @@ -97,16 +100,82 @@ namespace JSC { FinallyContext finallyContext; }; - struct ForInContext { - RefPtr<RegisterID> expectedSubscriptRegister; - RefPtr<RegisterID> iterRegister; - RefPtr<RegisterID> indexRegister; - RefPtr<RegisterID> propertyRegister; + class ForInContext { + public: + ForInContext(RegisterID* localRegister) + : m_localRegister(localRegister) + , m_isValid(true) + { + } + + virtual ~ForInContext() + { + } + + bool isValid() const { return m_isValid; } + void invalidate() { m_isValid = false; } + + enum ForInContextType { + StructureForInContextType, + IndexedForInContextType + }; + virtual ForInContextType type() const = 0; + + RegisterID* local() const { return m_localRegister.get(); } + + private: + RefPtr<RegisterID> m_localRegister; + bool m_isValid; + }; + + class StructureForInContext : public ForInContext { + public: + StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister) + : ForInContext(localRegister) + , m_indexRegister(indexRegister) + , m_propertyRegister(propertyRegister) + , m_enumeratorRegister(enumeratorRegister) + { + } + + virtual ForInContextType type() const + { + return StructureForInContextType; + } + + RegisterID* index() const { return m_indexRegister.get(); } + RegisterID* property() const { return m_propertyRegister.get(); } + RegisterID* enumerator() const { return m_enumeratorRegister.get(); } + + private: + RefPtr<RegisterID> m_indexRegister; + RefPtr<RegisterID> m_propertyRegister; + RefPtr<RegisterID> m_enumeratorRegister; + }; + + class IndexedForInContext : public ForInContext { + public: + IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister) + : ForInContext(localRegister) + , m_indexRegister(indexRegister) + { + } + + virtual ForInContextType type() const + { + return IndexedForInContextType; + } + + RegisterID* index() const { return m_indexRegister.get(); } + + private: + RefPtr<RegisterID> m_indexRegister; }; struct TryData { RefPtr<Label> target; unsigned targetScopeDepth; + HandlerType handlerType; }; struct TryContext { @@ -114,39 +183,55 @@ namespace JSC { TryData* tryData; }; - enum CaptureMode { - NotCaptured, - IsCaptured - }; - - class Local { + class Variable { public: - Local() - : m_local(0) + enum VariableKind { NormalVariable, SpecialVariable }; + + Variable() + : m_offset() + , m_local(nullptr) + , m_attributes(0) + , m_kind(NormalVariable) + { + } + + Variable(const Identifier& ident) + : m_ident(ident) + , m_local(nullptr) , m_attributes(0) + , m_kind(NormalVariable) // This is somewhat meaningless here for this kind of Variable. { } - Local(RegisterID* local, unsigned attributes, CaptureMode captureMode) - : m_local(local) + Variable(const Identifier& ident, VarOffset offset, RegisterID* local, unsigned attributes, VariableKind kind) + : m_ident(ident) + , m_offset(offset) + , m_local(local) , m_attributes(attributes) - , m_isCaptured(captureMode == IsCaptured) + , m_kind(kind) { } - operator bool() { return m_local; } - - RegisterID* get() { return m_local; } - - bool isReadOnly() { return m_attributes & ReadOnly; } + // If it's unset, then it is a non-locally-scoped variable. If it is set, then it could be + // a stack variable, a scoped variable in the local scope, or a variable captured in the + // direct arguments object. + bool isResolved() const { return !!m_offset; } + + const Identifier& ident() const { return m_ident; } - bool isCaptured() { return m_isCaptured; } - CaptureMode captureMode() { return isCaptured() ? IsCaptured : NotCaptured; } + VarOffset offset() const { return m_offset; } + bool isLocal() const { return m_offset.isStack(); } + RegisterID* local() const { return m_local; } + + bool isReadOnly() const { return m_attributes & ReadOnly; } + bool isSpecial() const { return m_kind != NormalVariable; } private: + Identifier m_ident; + VarOffset m_offset; RegisterID* m_local; unsigned m_attributes; - bool m_isCaptured; + VariableKind m_kind; }; struct TryRange { @@ -155,40 +240,59 @@ namespace JSC { TryData* tryData; }; + enum ProfileTypeBytecodeFlag { + ProfileTypeBytecodePutToScope, + ProfileTypeBytecodeGetFromScope, + ProfileTypeBytecodePutToLocalScope, + ProfileTypeBytecodeGetFromLocalScope, + ProfileTypeBytecodeHasGlobalID, + ProfileTypeBytecodeDoesNotHaveGlobalID, + ProfileTypeBytecodeFunctionArgument, + ProfileTypeBytecodeFunctionReturnStatement + }; + class BytecodeGenerator { WTF_MAKE_FAST_ALLOCATED; + WTF_MAKE_NONCOPYABLE(BytecodeGenerator); public: typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); - BytecodeGenerator(VM&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); + BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); ~BytecodeGenerator(); VM* vm() const { return m_vm; } + ParserArena& parserArena() const { return m_scopeNode->parserArena(); } const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; } - bool isConstructor() { return m_codeBlock->isConstructor(); } + bool isConstructor() const { return m_codeBlock->isConstructor(); } +#if ENABLE(ES6_CLASS_SYNTAX) + ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); } +#else + ConstructorKind constructorKind() const { return ConstructorKind::None; } +#endif ParserError generate(); bool isArgumentNumber(const Identifier&, int); - void setIsNumericCompareFunction(bool isNumericCompareFunction); - - bool willResolveToArguments(const Identifier&); - RegisterID* uncheckedRegisterForArguments(); - - bool isCaptured(int operand); - CaptureMode captureMode(int operand) { return isCaptured(operand) ? IsCaptured : NotCaptured; } + Variable variable(const Identifier&); + + // Ignores the possibility of intervening scopes. + Variable variablePerSymbolTable(const Identifier&); + + enum ExistingVariableMode { VerifyExisting, IgnoreExisting }; + void createVariable(const Identifier&, VarKind, ConstantMode, ExistingVariableMode = VerifyExisting); // Creates the variable, or asserts that the already-created variable is sufficiently compatible. - Local local(const Identifier&); - Local constLocal(const Identifier&); - // Returns the register storing "this" RegisterID* thisRegister() { return &m_thisRegister; } + RegisterID* argumentsRegister() { return m_argumentsRegister; } + RegisterID* newTarget() { return m_newTargetRegister; } + + RegisterID* scopeRegister() { return m_scopeRegister; } // Returns the next available temporary register. Registers returned by // newTemporary require a modified form of reference counting: any @@ -244,8 +348,6 @@ namespace JSC { { // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); - // Should never store directly into a captured variable. - ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index())); if (!m_vm->isSafeToRecurse()) { emitThrowExpressionTooDeepException(); return; @@ -262,8 +364,6 @@ namespace JSC { { // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); - // Should never store directly into a captured variable. - ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index())); if (!m_vm->isSafeToRecurse()) return emitThrowExpressionTooDeepException(); return n->emitBytecode(*this, dst); @@ -316,6 +416,7 @@ namespace JSC { m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column); } + ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) { return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; @@ -332,10 +433,14 @@ namespace JSC { return emitNode(n); } + void emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot); + void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag, const Identifier*); + + void emitProfileControlFlow(int); + RegisterID* emitLoad(RegisterID* dst, bool); - RegisterID* emitLoad(RegisterID* dst, double); RegisterID* emitLoad(RegisterID* dst, const Identifier&); - RegisterID* emitLoad(RegisterID* dst, JSValue); + RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); RegisterID* emitLoadGlobalObject(RegisterID* dst); RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); @@ -344,19 +449,22 @@ namespace JSC { RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); RegisterID* emitCreateThis(RegisterID* dst); + void emitTDZCheck(RegisterID* target); RegisterID* emitNewObject(RegisterID* dst); RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision - RegisterID* emitNewFunction(RegisterID* dst, CaptureMode, FunctionBodyNode*); - RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body); - RegisterID* emitNewFunctionInternal(RegisterID* dst, CaptureMode, unsigned index, bool shouldNullCheck); + RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode*); + RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index); RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); + RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name); RegisterID* emitNewRegExp(RegisterID* dst, RegExp*); - RegisterID* emitMove(RegisterID* dst, CaptureMode, RegisterID* src); + RegisterID* emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant); + RegisterID* emitMoveEmptyValue(RegisterID* dst); RegisterID* emitMove(RegisterID* dst, RegisterID* src); RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); } + RegisterID* emitToString(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_string, dst, src); } RegisterID* emitInc(RegisterID* srcDst); RegisterID* emitDec(RegisterID* srcDst); @@ -368,9 +476,8 @@ namespace JSC { RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value); RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); - RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base); RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); - RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value); + RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType); RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); @@ -378,6 +485,9 @@ namespace JSC { RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); + + void emitPutGetterById(RegisterID* base, const Identifier& property, RegisterID* getter); + void emitPutSetterById(RegisterID* base, const Identifier& property, RegisterID* setter); void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter); ExpectedFunction expectedFunctionForIdentifier(const Identifier&); @@ -385,8 +495,20 @@ namespace JSC { RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); + enum PropertyDescriptorOption { + PropertyConfigurable = 1, + PropertyWritable = 1 << 1, + PropertyEnumerable = 1 << 2, + }; + void emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister, + RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition&); + void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack); - + +#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) + RegisterID* emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode*); +#endif + RegisterID* emitReturn(RegisterID* src); RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } @@ -395,9 +517,11 @@ namespace JSC { void emitToPrimitive(RegisterID* dst, RegisterID* src); ResolveType resolveType(); - RegisterID* emitResolveScope(RegisterID* dst, const Identifier&); - RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier&, ResolveMode); - RegisterID* emitPutToScope(RegisterID* scope, const Identifier&, RegisterID* value, ResolveMode); + RegisterID* emitResolveConstantLocal(RegisterID* dst, const Variable&); + RegisterID* emitResolveScope(RegisterID* dst, const Variable&); + RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Variable&, ResolveMode); + RegisterID* emitPutToScope(RegisterID* scope, const Variable&, RegisterID* value, ResolveMode); + RegisterID* initializeVariable(const Variable&, RegisterID* value); PassRefPtr<Label> emitLabel(Label*); void emitLoopHint(); @@ -406,17 +530,31 @@ namespace JSC { PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target); PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target); - void emitPopScopes(int targetScopeDepth); + void emitPopScopes(RegisterID* srcDst, int targetScopeDepth); - RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget); - RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); + RegisterID* emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName); + RegisterID* emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator); + RegisterID* emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName); + RegisterID* emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base); + RegisterID* emitGetEnumerableLength(RegisterID* dst, RegisterID* base); + RegisterID* emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length); + RegisterID* emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator); + RegisterID* emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index); + RegisterID* emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index); + RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index); + + RegisterID* emitIsObject(RegisterID* dst, RegisterID* src); + RegisterID* emitIsUndefined(RegisterID* dst, RegisterID* src); + + RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node); + void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node); void emitReadOnlyExceptionIfNeeded(); // Start a try block. 'start' must have been emitted. TryData* pushTry(Label* start); // End a try block. 'end' must have been emitted. - RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end); + void popTryAndEmitCatch(TryData*, RegisterID* exceptionRegister, RegisterID* thrownValueRegister, Label* end, HandlerType); void emitThrow(RegisterID* exc) { @@ -425,12 +563,14 @@ namespace JSC { } void emitThrowReferenceError(const String& message); + void emitThrowTypeError(const String& message); - void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes); - void emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes); + void emitPushFunctionNameScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes); + void emitPushCatchScope(RegisterID* dst, const Identifier& property, RegisterID* value, unsigned attributes); - RegisterID* emitPushWithScope(RegisterID* scope); - void emitPopScope(); + void emitGetScope(); + RegisterID* emitPushWithScope(RegisterID* dst, RegisterID* scope); + void emitPopScope(RegisterID* srcDst); void emitDebugHook(DebugHookID, unsigned line, unsigned charOffset, unsigned lineStart); @@ -439,17 +579,14 @@ namespace JSC { void pushFinallyContext(StatementNode* finallyBlock); void popFinallyContext(); + void pushIteratorCloseContext(RegisterID* iterator, ThrowableExpressionData* enumerationNode); + void popIteratorCloseContext(); - void pushOptimisedForIn(RegisterID* expectedSubscript, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister) - { - ForInContext context = { expectedSubscript, iter, index, propertyRegister }; - m_forInContextStack.append(context); - } - - void popOptimisedForIn() - { - m_forInContextStack.removeLast(); - } + void pushIndexedForInScope(RegisterID* local, RegisterID* index); + void popIndexedForInScope(RegisterID* local); + void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator); + void popStructureForInScope(RegisterID* local); + void invalidateForInContextForLocal(RegisterID* local); LabelScopePtr breakTarget(const Identifier&); LabelScopePtr continueTarget(const Identifier&); @@ -465,10 +602,12 @@ namespace JSC { bool isStrictMode() const { return m_codeBlock->isStrictMode(); } bool isBuiltinFunction() const { return m_isBuiltinFunction; } - + + OpcodeID lastOpcodeID() const { return m_lastOpcodeID; } + private: - friend class Label; - + Variable variableForLocalEntry(const Identifier&, const SymbolTableEntry&); + void emitOpcode(OpcodeID); UnlinkedArrayAllocationProfile newArrayAllocationProfile(); UnlinkedObjectAllocationProfile newObjectAllocationProfile(); @@ -486,10 +625,12 @@ namespace JSC { ALWAYS_INLINE void rewindBinaryOp(); ALWAYS_INLINE void rewindUnaryOp(); - void emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope); + void allocateAndEmitScope(); + void emitComplexPopScopes(RegisterID*, ControlFlowContext* topScope, ControlFlowContext* bottomScope); typedef HashMap<double, JSValue> NumberMap; - typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; + typedef HashMap<UniquedStringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; + typedef HashMap<TemplateRegistryKey, JSTemplateRegistryKey*> TemplateRegistryKeyMap; // Helper for emitCall() and emitConstruct(). This works because the set of // expected functions have identical behavior for both call and construct @@ -500,46 +641,35 @@ namespace JSC { RegisterID* newRegister(); - // Adds a var slot and maps it to the name ident in symbolTable(). - enum WatchMode { IsWatchable, NotWatchable }; - RegisterID* addVar(const Identifier& ident, ConstantMode constantMode, WatchMode watchMode) - { - RegisterID* local; - addVar(ident, constantMode, watchMode, local); - return local; - } - - // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. - bool addVar(const Identifier&, ConstantMode, WatchMode, RegisterID*&); - - // Adds an anonymous var slot. To give this slot a name, add it to symbolTable(). + // Adds an anonymous local var slot. To give this slot a name, add it to symbolTable(). RegisterID* addVar() { ++m_codeBlock->m_numVars; - return newRegister(); + RegisterID* result = newRegister(); + ASSERT(VirtualRegister(result->index()).toLocal() == m_codeBlock->m_numVars - 1); + result->ref(); // We should never free this slot. + return result; } - // Returns the index of the added var. - void addParameter(const Identifier&, int parameterIndex); - RegisterID* resolveCallee(FunctionBodyNode*); - void addCallee(FunctionBodyNode*, RegisterID*); - - void preserveLastVar(); - - RegisterID& registerFor(int index) + // Initializes the stack form the parameter; does nothing for the symbol table. + RegisterID* initializeNextParameter(); + UniquedStringImpl* visibleNameForParameter(DestructuringPatternNode*); + + RegisterID& registerFor(VirtualRegister reg) { - if (operandIsLocal(index)) - return m_calleeRegisters[VirtualRegister(index).toLocal()]; + if (reg.isLocal()) + return m_calleeRegisters[reg.toLocal()]; - if (index == JSStack::Callee) + if (reg.offset() == JSStack::Callee) return m_calleeRegister; ASSERT(m_parameters.size()); - return m_parameters[VirtualRegister(index).toArgument()]; + return m_parameters[reg.toArgument()]; } + bool hasConstant(const Identifier&) const; unsigned addConstant(const Identifier&); - RegisterID* addConstantValue(JSValue); + RegisterID* addConstantValue(JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); RegisterID* addConstantEmptyValue(); unsigned addRegExp(RegExp*); @@ -550,13 +680,12 @@ namespace JSC { return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction); } - RegisterID* emitInitLazyRegister(RegisterID*); - - RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); + RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); - + public: JSString* addStringConstant(const Identifier&); + JSTemplateRegistryKey* addTemplateRegistryKeyConstant(const TemplateRegistryKey&); Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } @@ -587,104 +716,79 @@ namespace JSC { return true; } - bool shouldTearOffArgumentsEagerly() - { - return m_codeType == FunctionCode && isStrictMode() && m_scopeNode->modifiesParameter(); - } - RegisterID* emitThrowExpressionTooDeepException(); - void createArgumentsIfNecessary(); - void createActivationIfNecessary(); - RegisterID* createLazyRegisterIfNecessary(RegisterID*); - - unsigned watchableVariable(int operand) - { - VirtualRegister reg(operand); - if (!reg.isLocal()) - return UINT_MAX; - if (static_cast<size_t>(reg.toLocal()) >= m_watchableVariables.size()) - return UINT_MAX; - Identifier& ident = m_watchableVariables[reg.toLocal()]; - if (ident.isNull()) - return UINT_MAX; - return addConstant(ident); - } - - bool hasWatchableVariable(int operand) - { - return watchableVariable(operand) != UINT_MAX; - } - + private: Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow> m_instructions; bool m_shouldEmitDebugHooks; bool m_shouldEmitProfileHooks; - SymbolTable* m_symbolTable; + SymbolTable* m_symbolTable { nullptr }; - ScopeNode* m_scopeNode; + ScopeNode* const m_scopeNode; Strong<UnlinkedCodeBlock> m_codeBlock; // Some of these objects keep pointers to one another. They are arranged // to ensure a sane destruction order that avoids references to freed memory. - HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions; + HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_functions; RegisterID m_ignoredResultRegister; RegisterID m_thisRegister; RegisterID m_calleeRegister; - RegisterID* m_activationRegister; - RegisterID* m_emptyValueRegister; - RegisterID* m_globalObjectRegister; - Vector<Identifier, 16> m_watchableVariables; + RegisterID* m_scopeRegister { nullptr }; + RegisterID* m_argumentsRegister { nullptr }; + RegisterID* m_lexicalEnvironmentRegister { nullptr }; + RegisterID* m_emptyValueRegister { nullptr }; + RegisterID* m_globalObjectRegister { nullptr }; + RegisterID* m_newTargetRegister { nullptr }; + RegisterID* m_linkTimeConstantRegisters[LinkTimeConstantCount]; + SegmentedVector<RegisterID, 32> m_constantPoolRegisters; SegmentedVector<RegisterID, 32> m_calleeRegisters; SegmentedVector<RegisterID, 32> m_parameters; SegmentedVector<Label, 32> m_labels; LabelScopeStore m_labelScopes; - RefPtr<RegisterID> m_lastVar; - int m_finallyDepth; - int m_localScopeDepth; - CodeType m_codeType; + int m_finallyDepth { 0 }; + int m_localScopeDepth { 0 }; + const CodeType m_codeType; Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack; Vector<SwitchInfo> m_switchContextStack; - Vector<ForInContext> m_forInContextStack; + Vector<std::unique_ptr<ForInContext>> m_forInContextStack; Vector<TryContext> m_tryContextStack; - Vector<std::pair<RefPtr<RegisterID>, const DeconstructionPatternNode*>> m_deconstructedParameters; + Vector<std::pair<RefPtr<RegisterID>, const DestructuringPatternNode*>> m_destructuringParameters; + enum FunctionVariableType : uint8_t { NormalFunctionVariable, GlobalFunctionVariable }; + Vector<std::pair<FunctionBodyNode*, FunctionVariableType>> m_functionsToInitialize; + bool m_needToInitializeArguments { false }; Vector<TryRange> m_tryRanges; SegmentedVector<TryData, 8> m_tryData; - int m_firstConstantIndex; - int m_nextConstantOffset; - unsigned m_globalConstantIndex; - - int m_globalVarStorageOffset; + int m_nextConstantOffset { 0 }; - int m_firstLazyFunction; - int m_lastLazyFunction; - HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int>> m_lazyFunctions; typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; FunctionOffsetMap m_functionOffsets; // Constant pool IdentifierMap m_identifierMap; + + typedef HashMap<EncodedJSValueWithRepresentation, unsigned, EncodedJSValueWithRepresentationHash, EncodedJSValueWithRepresentationHashTraits> JSValueMap; JSValueMap m_jsValueMap; - NumberMap m_numberMap; IdentifierStringMap m_stringMap; + TemplateRegistryKeyMap m_templateRegistryKeyMap; - StaticPropertyAnalyzer m_staticPropertyAnalyzer; + StaticPropertyAnalyzer m_staticPropertyAnalyzer { &m_instructions }; VM* m_vm; - OpcodeID m_lastOpcodeID; + OpcodeID m_lastOpcodeID = op_end; #ifndef NDEBUG - size_t m_lastOpcodePosition; + size_t m_lastOpcodePosition { 0 }; #endif - bool m_usesExceptions; - bool m_expressionTooDeep; - bool m_isBuiltinFunction; + bool m_usesExceptions { false }; + bool m_expressionTooDeep { false }; + bool m_isBuiltinFunction { false }; }; } diff --git a/bytecompiler/Label.h b/bytecompiler/Label.h index 81cdf3c..b76c648 100644 --- a/bytecompiler/Label.h +++ b/bytecompiler/Label.h @@ -41,7 +41,7 @@ namespace JSC { class Label { public: - explicit Label(BytecodeGenerator* generator) + explicit Label(BytecodeGenerator& generator) : m_refCount(0) , m_location(invalidLocation) , m_generator(generator) @@ -82,7 +82,7 @@ namespace JSC { int m_refCount; unsigned m_location; - BytecodeGenerator* m_generator; + BytecodeGenerator& m_generator; mutable JumpVector m_unresolvedJumps; }; diff --git a/bytecompiler/NodesCodegen.cpp b/bytecompiler/NodesCodegen.cpp index 0e81cfa..cfd3ef1 100644 --- a/bytecompiler/NodesCodegen.cpp +++ b/bytecompiler/NodesCodegen.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) -* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. +* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2015 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel <eric@webkit.org> @@ -40,12 +40,14 @@ #include "LabelScope.h" #include "Lexer.h" #include "JSCInlines.h" +#include "JSTemplateRegistryKey.h" #include "Parser.h" #include "PropertyNameArray.h" #include "RegExpCache.h" #include "RegExpObject.h" #include "SamplingTool.h" #include "StackAlignment.h" +#include "TemplateRegistryKey.h" #include <wtf/Assertions.h> #include <wtf/RefCountedLeakCounter.h> #include <wtf/Threading.h> @@ -122,6 +124,15 @@ JSValue StringNode::jsValue(BytecodeGenerator& generator) const return generator.addStringConstant(m_value); } +// ------------------------------ NumberNode ---------------------------------- + +RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return nullptr; + return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double); +} + // ------------------------------ RegExpNode ----------------------------------- RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -135,31 +146,184 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived) + generator.emitTDZCheck(generator.thisRegister()); + if (dst == generator.ignoredResult()) return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); + + RegisterID* result = generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(generator.thisRegister(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + static const unsigned thisLength = 4; + generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + thisLength, -1)); + } + return result; +} + +// ------------------------------ SuperNode ------------------------------------- + +RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + + RegisterID callee; + callee.setIndex(JSStack::Callee); + + RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); + RefPtr<RegisterID> protoParent = generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); + return generator.emitGetById(generator.finalDestination(dst), protoParent.get(), generator.propertyNames().constructor); +} + +static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator) +{ + RegisterID callee; + callee.setIndex(JSStack::Callee); + + RefPtr<RegisterID> homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); + return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); } // ------------------------------ ResolveNode ---------------------------------- bool ResolveNode::isPure(BytecodeGenerator& generator) const { - return generator.local(m_ident).get(); + return generator.variable(m_ident).offset().isStack(); } RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (dst == generator.ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, local.get()); + return nullptr; + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); + } + return generator.moveToDestinationIfNeeded(dst, local); } JSTextPosition divot = m_start + m_ident.length(); generator.emitExpressionInfo(divot, m_start, divot); - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident); - return generator.emitGetFromScope(generator.finalDestination(dst), scope.get(), m_ident, ThrowIfNotFound); + RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); + RegisterID* finalDest = generator.finalDestination(dst); + RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), var, ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident); + generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); + } + return result; +} + +#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) +// ------------------------------ TemplateStringNode ----------------------------------- + +RegisterID* TemplateStringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return nullptr; + return generator.emitLoad(dst, JSValue(generator.addStringConstant(cooked()))); +} + +// ------------------------------ TemplateLiteralNode ----------------------------------- + +RegisterID* TemplateLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (!m_templateExpressions) { + TemplateStringNode* templateString = m_templateStrings->value(); + ASSERT_WITH_MESSAGE(!m_templateStrings->next(), "Only one template element exists because there's no expression in a given template literal."); + return generator.emitNode(dst, templateString); + } + + Vector<RefPtr<RegisterID>, 16> temporaryRegisters; + + TemplateStringListNode* templateString = m_templateStrings; + TemplateExpressionListNode* templateExpression = m_templateExpressions; + for (; templateExpression; templateExpression = templateExpression->next(), templateString = templateString->next()) { + // Evaluate TemplateString. + if (!templateString->value()->cooked().isEmpty()) { + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateString->value()); + } + + // Evaluate Expression. + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateExpression->value()); + generator.emitToString(temporaryRegisters.last().get(), temporaryRegisters.last().get()); + } + + // Evaluate tail TemplateString. + if (!templateString->value()->cooked().isEmpty()) { + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateString->value()); + } + + return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); +} + +// ------------------------------ TaggedTemplateNode ----------------------------------- + +RegisterID* TaggedTemplateNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ExpectedFunction expectedFunction = NoExpectedFunction; + RefPtr<RegisterID> tag = nullptr; + RefPtr<RegisterID> base = nullptr; + if (!m_tag->isLocation()) { + tag = generator.newTemporary(); + tag = generator.emitNode(tag.get(), m_tag); + } else if (m_tag->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(m_tag); + const Identifier& identifier = resolve->identifier(); + expectedFunction = generator.expectedFunctionForIdentifier(identifier); + + Variable var = generator.variable(identifier); + if (RegisterID* local = var.local()) + tag = generator.emitMove(generator.newTemporary(), local); + else { + tag = generator.newTemporary(); + base = generator.newTemporary(); + + JSTextPosition newDivot = divotStart() + identifier.length(); + generator.emitExpressionInfo(newDivot, divotStart(), newDivot); + generator.moveToDestinationIfNeeded(base.get(), generator.emitResolveScope(base.get(), var)); + generator.emitGetFromScope(tag.get(), base.get(), var, ThrowIfNotFound); + } + } else if (m_tag->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(m_tag); + base = generator.newTemporary(); + base = generator.emitNode(base.get(), bracket->base()); + RefPtr<RegisterID> property = generator.emitNode(bracket->subscript()); + tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); + } else { + ASSERT(m_tag->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(m_tag); + base = generator.newTemporary(); + base = generator.emitNode(base.get(), dot->base()); + tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier()); + } + + RefPtr<RegisterID> templateObject = generator.emitGetTemplateObject(generator.newTemporary(), this); + + unsigned expressionsCount = 0; + for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) + ++expressionsCount; + + CallArguments callArguments(generator, nullptr, 1 + expressionsCount); + if (base) + generator.emitMove(callArguments.thisRegister(), base.get()); + else + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + + unsigned argumentIndex = 0; + generator.emitMove(callArguments.argumentRegister(argumentIndex++), templateObject.get()); + for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) + generator.emitNode(callArguments.argumentRegister(argumentIndex++), templateExpression->value()); + + return generator.emitCall(generator.finalDestination(dst, tag.get()), tag.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); } +#endif // ------------------------------ ArrayNode ------------------------------------ @@ -232,7 +396,7 @@ bool ArrayNode::isSimpleArray() const return true; } -ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPosition) const +ArgumentListNode* ArrayNode::toArgumentList(ParserArena& parserArena, int lineNumber, int startPosition) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; @@ -241,12 +405,12 @@ ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPos JSTokenLocation location; location.line = lineNumber; location.startOffset = startPosition; - ArgumentListNode* head = new (vm) ArgumentListNode(location, ptr->value()); + ArgumentListNode* head = new (parserArena) ArgumentListNode(location, ptr->value()); ArgumentListNode* tail = head; ptr = ptr->next(); for (; ptr; ptr = ptr->next()) { ASSERT(!ptr->elision()); - tail = new (vm) ArgumentListNode(location, tail, ptr->value()); + tail = new (parserArena) ArgumentListNode(location, tail, ptr->value()); } return head; } @@ -255,49 +419,59 @@ ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPos RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (!m_list) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitNewObject(generator.finalDestination(dst)); - } - return generator.emitNode(dst, m_list); + if (!m_list) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewObject(generator.finalDestination(dst)); + } + RefPtr<RegisterID> newObj = generator.emitNewObject(generator.tempDestination(dst)); + generator.emitNode(newObj.get(), m_list); + return generator.moveToDestinationIfNeeded(dst, newObj.get()); } // ------------------------------ PropertyListNode ----------------------------- +static inline void emitPutHomeObject(BytecodeGenerator& generator, RegisterID* function, RegisterID* homeObject) +{ + generator.emitPutById(function, generator.propertyNames().homeObjectPrivateName, homeObject); +} + RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<RegisterID> newObj = generator.tempDestination(dst); - - generator.emitNewObject(newObj.get()); - // Fast case: this loop just handles regular value properties. PropertyListNode* p = this; - for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next) { - if (p->m_node->m_name) { - generator.emitDirectPutById(newObj.get(), *p->m_node->name(), generator.emitNode(p->m_node->m_assign)); - continue; - } - RefPtr<RegisterID> propertyName = generator.emitNode(p->m_node->m_expression); - generator.emitDirectPutByVal(newObj.get(), propertyName.get(), generator.emitNode(p->m_node->m_assign)); - } + for (; p && (p->m_node->m_type & PropertyNode::Constant); p = p->m_next) + emitPutConstantProperty(generator, dst, *p->m_node); // Were there any get/set properties? if (p) { + // Build a list of getter/setter pairs to try to put them at the same time. If we encounter + // a computed property, just emit everything as that may override previous values. + bool hasComputedProperty = false; + typedef std::pair<PropertyNode*, PropertyNode*> GetterSetterPair; - typedef HashMap<StringImpl*, GetterSetterPair> GetterSetterMap; + typedef HashMap<UniquedStringImpl*, GetterSetterPair, IdentifierRepHash> GetterSetterMap; GetterSetterMap map; // Build a map, pairing get/set values together. for (PropertyListNode* q = p; q; q = q->m_next) { PropertyNode* node = q->m_node; - if (node->m_type == PropertyNode::Constant) + if (node->m_type & PropertyNode::Computed) { + hasComputedProperty = true; + break; + } + if (node->m_type & PropertyNode::Constant) continue; - GetterSetterPair pair(node, static_cast<PropertyNode*>(0)); + // Duplicates are possible. + GetterSetterPair pair(node, static_cast<PropertyNode*>(nullptr)); GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair); - if (!result.isNewEntry) - result.iterator->value.second = node; + if (!result.isNewEntry) { + if (result.iterator->value.first->m_type == node->m_type) + result.iterator->value.first = node; + else + result.iterator->value.second = node; + } } // Iterate over the remaining properties in the list. @@ -305,20 +479,28 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe PropertyNode* node = p->m_node; // Handle regular values. - if (node->m_type == PropertyNode::Constant) { - if (node->name()) { - generator.emitDirectPutById(newObj.get(), *node->name(), generator.emitNode(node->m_assign)); - continue; - } - RefPtr<RegisterID> propertyName = generator.emitNode(p->m_node->m_expression); - generator.emitDirectPutByVal(newObj.get(), propertyName.get(), generator.emitNode(p->m_node->m_assign)); + if (node->m_type & PropertyNode::Constant) { + emitPutConstantProperty(generator, dst, *node); continue; } - + RegisterID* value = generator.emitNode(node->m_assign); + bool isClassProperty = node->needsSuperBinding(); + if (isClassProperty) + emitPutHomeObject(generator, value, dst); + + ASSERT(node->m_type & (PropertyNode::Getter | PropertyNode::Setter)); + + // This is a get/set property which may be overridden by a computed property later. + if (hasComputedProperty) { + if (node->m_type & PropertyNode::Getter) + generator.emitPutGetterById(dst, *node->name(), value); + else + generator.emitPutSetterById(dst, *node->name(), value); + continue; + } - // This is a get/set property, find its entry in the map. - ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter); + // This is a get/set property pair. GetterSetterMap::iterator it = map.find(node->name()->impl()); ASSERT(it != map.end()); GetterSetterPair& pair = it->value; @@ -326,75 +508,129 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe // Was this already generated as a part of its partner? if (pair.second == node) continue; - + // Generate the paired node now. RefPtr<RegisterID> getterReg; RefPtr<RegisterID> setterReg; + RegisterID* secondReg = nullptr; - if (node->m_type == PropertyNode::Getter) { + if (node->m_type & PropertyNode::Getter) { getterReg = value; if (pair.second) { - ASSERT(pair.second->m_type == PropertyNode::Setter); + ASSERT(pair.second->m_type & PropertyNode::Setter); setterReg = generator.emitNode(pair.second->m_assign); + secondReg = setterReg.get(); } else { setterReg = generator.newTemporary(); generator.emitLoad(setterReg.get(), jsUndefined()); } } else { - ASSERT(node->m_type == PropertyNode::Setter); + ASSERT(node->m_type & PropertyNode::Setter); setterReg = value; if (pair.second) { - ASSERT(pair.second->m_type == PropertyNode::Getter); + ASSERT(pair.second->m_type & PropertyNode::Getter); getterReg = generator.emitNode(pair.second->m_assign); + secondReg = getterReg.get(); } else { getterReg = generator.newTemporary(); generator.emitLoad(getterReg.get(), jsUndefined()); } } - generator.emitPutGetterSetter(newObj.get(), *node->name(), getterReg.get(), setterReg.get()); + ASSERT(!pair.second || isClassProperty == pair.second->needsSuperBinding()); + if (isClassProperty && pair.second) + emitPutHomeObject(generator, secondReg, dst); + + if (isClassProperty) { + RefPtr<RegisterID> propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node->name()); + generator.emitCallDefineProperty(dst, propertyNameRegister.get(), + nullptr, getterReg.get(), setterReg.get(), BytecodeGenerator::PropertyConfigurable, m_position); + } else + generator.emitPutGetterSetter(dst, *node->name(), getterReg.get(), setterReg.get()); } } - return generator.moveToDestinationIfNeeded(dst, newObj.get()); + return dst; +} + +void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node) +{ + RefPtr<RegisterID> value = generator.emitNode(node.m_assign); + if (node.needsSuperBinding()) { + emitPutHomeObject(generator, value.get(), newObj); + + RefPtr<RegisterID> propertyNameRegister; + if (node.name()) + propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node.name()); + else + propertyNameRegister = generator.emitNode(node.m_expression); + + generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), + value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); + return; + } + if (const auto* identifier = node.name()) { + Optional<uint32_t> optionalIndex = parseIndex(*identifier); + if (!optionalIndex) { + generator.emitDirectPutById(newObj, *identifier, value.get(), node.putType()); + return; + } + + RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(optionalIndex.value())); + generator.emitDirectPutByVal(newObj, index.get(), value.get()); + return; + } + RefPtr<RegisterID> propertyName = generator.emitNode(node.m_expression); + generator.emitDirectPutByVal(newObj, propertyName.get(), value.get()); } // ------------------------------ BracketAccessorNode -------------------------------- RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_base->isResolveNode() - && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier()) - && !generator.symbolTable().slowArguments()) { - RefPtr<RegisterID> property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property.get()); + if (m_base->isSuperNode()) { + // FIXME: Should we generate the profiler info? + if (m_subscript->isString()) { + const Identifier& id = static_cast<StringNode*>(m_subscript)->value(); + return generator.emitGetById(generator.finalDestination(dst), emitSuperBaseForCallee(generator), id); + } + return generator.emitGetByVal(generator.finalDestination(dst), emitSuperBaseForCallee(generator), generator.emitNode(m_subscript)); + } + + RegisterID* ret; + RegisterID* finalDest = generator.finalDestination(dst); + + if (m_subscript->isString()) { + RefPtr<RegisterID> base = generator.emitNode(m_base); + ret = generator.emitGetById(finalDest, base.get(), static_cast<StringNode*>(m_subscript)->value()); + } else { + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); + RegisterID* property = generator.emitNode(m_subscript); + ret = generator.emitGetByVal(finalDest, base.get(), property); } - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); - RegisterID* property = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); + + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ DotAccessorNode -------------------------------- RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_ident == generator.propertyNames().length) { - if (!m_base->isResolveNode()) - goto nonArgumentsPath; - ResolveNode* resolveNode = static_cast<ResolveNode*>(m_base); - if (!generator.willResolveToArguments(resolveNode->identifier())) - goto nonArgumentsPath; - generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); - } - -nonArgumentsPath: - RefPtr<RegisterID> base = generator.emitNode(m_base); + RefPtr<RegisterID> base = m_base->isSuperNode() ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetById(generator.finalDestination(dst), base.get(), m_ident); + RegisterID* finalDest = generator.finalDestination(dst); + RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ ArgumentListNode ----------------------------- @@ -417,6 +653,7 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* RefPtr<RegisterID> func = generator.emitNode(m_expr); RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); + generator.emitMove(callArguments.thisRegister(), func.get()); return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); } @@ -449,8 +686,9 @@ CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argume RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(generator.propertyNames().eval)) { - RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local.get()); + Variable var = generator.variable(generator.propertyNames().eval); + if (RegisterID* local = var.local()) { + RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); @@ -460,8 +698,10 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg CallArguments callArguments(generator, m_args); JSTextPosition newDivot = divotStart() + 4; generator.emitExpressionInfo(newDivot, divotStart(), newDivot); - generator.emitResolveScope(callArguments.thisRegister(), generator.propertyNames().eval); - generator.emitGetFromScope(func.get(), callArguments.thisRegister(), generator.propertyNames().eval, ThrowIfNotFound); + generator.moveToDestinationIfNeeded( + callArguments.thisRegister(), + generator.emitResolveScope(callArguments.thisRegister(), var)); + generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); } @@ -472,8 +712,21 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re RefPtr<RegisterID> func = generator.emitNode(m_expr); RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); + if (m_expr->isSuperNode()) { + ASSERT(generator.isConstructor()); + ASSERT(generator.constructorKind() == ConstructorKind::Derived); + generator.emitMove(callArguments.thisRegister(), generator.newTarget()); + RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + generator.emitMove(generator.thisRegister(), ret); + return ret; + } generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ FunctionCallResolveNode ---------------------------------- @@ -482,14 +735,20 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, { ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); - if (Local local = generator.local(m_ident)) { - RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local.get()); + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { + RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local); RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); // This passes NoExpectedFunction because we expect that if the function is in a // local variable, then it's not one of our built-in constructors. - return generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } RefPtr<RegisterID> func = generator.newTemporary(); @@ -498,23 +757,87 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, JSTextPosition newDivot = divotStart() + m_ident.length(); generator.emitExpressionInfo(newDivot, divotStart(), newDivot); - generator.emitResolveScope(callArguments.thisRegister(), m_ident); - generator.emitGetFromScope(func.get(), callArguments.thisRegister(), m_ident, ThrowIfNotFound); - return generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); + generator.moveToDestinationIfNeeded( + callArguments.thisRegister(), + generator.emitResolveScope(callArguments.thisRegister(), var)); + generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); + RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; +} + +// ------------------------------ BytecodeIntrinsicNode ---------------------------------- + +RegisterID* BytecodeIntrinsicNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + return (this->*m_emitter)(generator, dst); +} + +RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putByValDirect(BytecodeGenerator& generator, RegisterID* dst) +{ + ArgumentListNode* node = m_args->m_listNode; + RefPtr<RegisterID> base = generator.emitNode(node); + node = node->m_next; + RefPtr<RegisterID> index = generator.emitNode(node); + node = node->m_next; + RefPtr<RegisterID> value = generator.emitNode(node); + + ASSERT(!node->m_next); + + return generator.moveToDestinationIfNeeded(dst, generator.emitDirectPutByVal(base.get(), index.get(), value.get())); +} + +RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toString(BytecodeGenerator& generator, RegisterID* dst) +{ + ArgumentListNode* node = m_args->m_listNode; + RefPtr<RegisterID> src = generator.emitNode(node); + ASSERT(!node->m_next); + + return generator.moveToDestinationIfNeeded(dst, generator.emitToString(generator.tempDestination(dst), src.get())); } // ------------------------------ FunctionCallBracketNode ---------------------------------- RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); - RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); + bool baseIsSuper = m_base->isSuperNode(); + bool subscriptIsString = m_subscript->isString(); + + RefPtr<RegisterID> base; + if (baseIsSuper) + base = emitSuperBaseForCallee(generator); + else { + if (subscriptIsString) + base = generator.emitNode(m_base); + else + base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); + } + + RefPtr<RegisterID> function; + if (subscriptIsString) { + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); + function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast<StringNode*>(m_subscript)->value()); + } else { + RefPtr<RegisterID> property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); + function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); + } + RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); CallArguments callArguments(generator, m_args); - generator.emitMove(callArguments.thisRegister(), base.get()); - return generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (baseIsSuper) + generator.emitMove(callArguments.thisRegister(), generator.thisRegister()); + else + generator.emitMove(callArguments.thisRegister(), base.get()); + RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ FunctionCallDotNode ---------------------------------- @@ -524,21 +847,19 @@ RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi RefPtr<RegisterID> function = generator.tempDestination(dst); RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get()); CallArguments callArguments(generator, m_args); - generator.emitNode(callArguments.thisRegister(), m_base); + bool baseIsSuper = m_base->isSuperNode(); + if (baseIsSuper) + generator.emitMove(callArguments.thisRegister(), generator.thisRegister()); + else + generator.emitNode(callArguments.thisRegister(), m_base); generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); - generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); - return generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); -} - -static RegisterID* getArgumentByVal(BytecodeGenerator& generator, ExpressionNode* base, RegisterID* property, RegisterID* dst, JSTextPosition divot, JSTextPosition divotStart, JSTextPosition divotEnd) -{ - if (base->isResolveNode() - && generator.willResolveToArguments(static_cast<ResolveNode*>(base)->identifier()) - && !generator.symbolTable().slowArguments()) { - generator.emitExpressionInfo(divot, divotStart, divotEnd); - return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); + generator.emitGetById(function.get(), baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister(), m_ident); + RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); } - return nullptr; + return ret; } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -561,15 +882,10 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, profileHookRegister = generator.newTemporary(); SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr); ExpressionNode* subject = spread->expression(); - RefPtr<RegisterID> thisRegister = getArgumentByVal(generator, subject, generator.emitLoad(0, jsNumber(0)), 0, spread->divot(), spread->divotStart(), spread->divotEnd()); RefPtr<RegisterID> argumentsRegister; - if (thisRegister) - argumentsRegister = generator.uncheckedRegisterForArguments(); - else { - argumentsRegister = generator.emitNode(subject); - generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); - thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); - } + argumentsRegister = generator.emitNode(subject); + generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); + RefPtr<RegisterID> thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); generator.emitCallVarargs(returnValue.get(), base.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 1, profileHookRegister.get(), divot(), divotStart(), divotEnd()); } else if (m_args->m_listNode && m_args->m_listNode->m_expr) { ArgumentListNode* oldList = m_args->m_listNode; @@ -597,6 +913,10 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, } generator.emitLabel(end.get()); } + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return returnValue.get(); } @@ -659,7 +979,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, } else if (m_args->m_listNode->m_next) { ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); ASSERT(!m_args->m_listNode->m_next->m_next); - m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.vm(), 0, 0); + m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.parserArena(), 0, 0); RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), oldList->m_expr); @@ -687,10 +1007,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr<RegisterID> thisRegister = generator.emitNode(m_args->m_listNode->m_expr); RefPtr<RegisterID> argsRegister; ArgumentListNode* args = m_args->m_listNode->m_next; - if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast<ResolveNode*>(args->m_expr)->identifier()) && !generator.symbolTable().slowArguments()) - argsRegister = generator.uncheckedRegisterForArguments(); - else - argsRegister = generator.emitNode(args->m_expr); + argsRegister = generator.emitNode(args->m_expr); // Function.prototype.apply ignores extra arguments, but we still // need to evaluate them for side effects. @@ -707,6 +1024,10 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); generator.emitLabel(end.get()); } + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return returnValue.get(); } @@ -735,12 +1056,13 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); const Identifier& ident = resolve->identifier(); - if (Local local = generator.local(ident)) { - RefPtr<RegisterID> localReg = local.get(); - if (local.isReadOnly()) { + Variable var = generator.variable(ident); + if (RegisterID* local = var.local()) { + RefPtr<RegisterID> localReg = local; + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); - localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); - } else if (local.isCaptured()) { + localReg = generator.emitMove(generator.tempDestination(dst), local); + } else if (generator.vm()->typeProfiler()) { RefPtr<RegisterID> tempDst = generator.finalDestination(dst); ASSERT(dst != localReg); RefPtr<RegisterID> tempDstSrc = generator.newTemporary(); @@ -748,16 +1070,23 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d generator.emitMove(tempDstSrc.get(), localReg.get()); emitIncOrDec(generator, tempDstSrc.get(), m_operator); generator.emitMove(localReg.get(), tempDstSrc.get()); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return tempDst.get(); } return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator); } generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), ident); - RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound); + RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); + RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); - generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound); + generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return oldValue.get(); } @@ -779,6 +1108,10 @@ RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* d RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutByVal(base.get(), property.get(), value.get()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, oldValue); } @@ -799,6 +1132,10 @@ RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutById(base.get(), ident, value.get()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, oldValue); } @@ -814,19 +1151,20 @@ RegisterID* PostfixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* return emitDot(generator, dst); return emitThrowReferenceError(generator, m_operator == OpPlusPlus - ? "Postfix ++ operator applied to value that is not a reference." - : "Postfix -- operator applied to value that is not a reference."); + ? ASCIILiteral("Postfix ++ operator applied to value that is not a reference.") + : ASCIILiteral("Postfix -- operator applied to value that is not a reference.")); } // ------------------------------ DeleteResolveNode ----------------------------------- RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (generator.local(m_ident).get()) + Variable var = generator.variable(m_ident); + if (var.local()) return generator.emitLoad(generator.finalDestination(dst), false); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr<RegisterID> base = generator.emitResolveScope(generator.tempDestination(dst), m_ident); + RefPtr<RegisterID> base = generator.emitResolveScope(dst, var); return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident); } @@ -838,6 +1176,8 @@ RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, Regist RefPtr<RegisterID> r1 = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + if (m_base->isSuperNode()) + return emitThrowReferenceError(generator, "Cannot delete a super property"); return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get()); } @@ -848,6 +1188,8 @@ RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RefPtr<RegisterID> r0 = generator.emitNode(m_base); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + if (m_base->isSuperNode()) + return emitThrowReferenceError(generator, "Cannot delete a super property"); return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident); } @@ -873,18 +1215,19 @@ RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst return generator.emitLoad(dst, jsUndefined()); } -// ------------------------------ TypeOfValueNode ----------------------------------- +// ------------------------------ TypeOfResolveNode ----------------------------------- RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (dst == generator.ignoredResult()) return 0; - return generator.emitTypeOf(generator.finalDestination(dst), local.get()); + return generator.emitTypeOf(generator.finalDestination(dst), local); } - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident); - RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound); + RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); + RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); if (dst == generator.ignoredResult()) return 0; return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get()); @@ -910,16 +1253,19 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds ResolveNode* resolve = static_cast<ResolveNode*>(m_expr); const Identifier& ident = resolve->identifier(); - if (Local local = generator.local(ident)) { - RefPtr<RegisterID> localReg = local.get(); - if (local.isReadOnly()) { + Variable var = generator.variable(ident); + if (RegisterID* local = var.local()) { + RefPtr<RegisterID> localReg = local; + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); - } else if (local.isCaptured()) { + } else if (generator.vm()->typeProfiler()) { RefPtr<RegisterID> tempDst = generator.tempDestination(dst); generator.emitMove(tempDst.get(), localReg.get()); emitIncOrDec(generator, tempDst.get(), m_operator); generator.emitMove(localReg.get(), tempDst.get()); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return generator.moveToDestinationIfNeeded(dst, tempDst.get()); } emitIncOrDec(generator, localReg.get(), m_operator); @@ -927,10 +1273,14 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds } generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.tempDestination(dst), ident); - RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound); + RefPtr<RegisterID> scope = generator.emitResolveScope(dst, var); + RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); emitIncOrDec(generator, value.get(), m_operator); - generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound); + generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, value.get()); } @@ -950,6 +1300,10 @@ RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* ds emitIncOrDec(generator, value, m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutByVal(base.get(), property.get(), value); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -968,6 +1322,10 @@ RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) emitIncOrDec(generator, value, m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutById(base.get(), ident, value); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -983,8 +1341,8 @@ RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d return emitDot(generator, dst); return emitThrowReferenceError(generator, m_operator == OpPlusPlus - ? "Prefix ++ operator applied to value that is not a reference." - : "Prefix -- operator applied to value that is not a reference."); + ? ASCIILiteral("Prefix ++ operator applied to value that is not a reference.") + : ASCIILiteral("Prefix -- operator applied to value that is not a reference.")); } // ------------------------------ Unary Operation Nodes ----------------------------------- @@ -1216,7 +1574,7 @@ RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* } RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); - bool wasTypeof = generator.m_lastOpcodeID == op_typeof; + bool wasTypeof = generator.lastOpcodeID() == op_typeof; RefPtr<RegisterID> src2 = generator.emitNode(right); generator.emitExpressionInfo(position(), position(), position()); if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { @@ -1335,14 +1693,18 @@ RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, Register generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue); generator.emitLabel(beforeThen.get()); + generator.emitProfileControlFlow(m_expr1->startOffset()); generator.emitNode(newDst.get(), m_expr1); generator.emitJump(afterElse.get()); generator.emitLabel(beforeElse.get()); + generator.emitProfileControlFlow(m_expr1->endOffset() + 1); generator.emitNode(newDst.get(), m_expr2); generator.emitLabel(afterElse.get()); + generator.emitProfileControlFlow(m_expr2->endOffset() + 1); + return newDst.get(); } @@ -1407,60 +1769,80 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { - if (local.isReadOnly()) { + JSTextPosition newDivot = divotStart() + m_ident.length(); + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); - return emitReadModifyAssignment(generator, generator.finalDestination(dst), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); } - if (local.isCaptured() + if (generator.vm()->typeProfiler() || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { RefPtr<RegisterID> result = generator.newTemporary(); - generator.emitMove(result.get(), local.get()); + generator.emitMove(result.get(), local); emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitMove(local.get(), result.get()); + generator.emitMove(local, result.get()); + generator.invalidateForInContextForLocal(local); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return generator.moveToDestinationIfNeeded(dst, result.get()); } - RegisterID* result = emitReadModifyAssignment(generator, local.get(), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + generator.invalidateForInContextForLocal(local); return generator.moveToDestinationIfNeeded(dst, result); } - JSTextPosition newDivot = divotStart() + m_ident.length(); generator.emitExpressionInfo(newDivot, divotStart(), newDivot); - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident); - RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound); + RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); + RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); RefPtr<RegisterID> result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); - return generator.emitPutToScope(scope.get(), m_ident, result.get(), ThrowIfNotFound); + RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return returnResult; } // ------------------------------ AssignResolveNode ----------------------------------- RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { - if (local.isReadOnly()) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); return generator.emitNode(dst, m_right); } - if (local.isCaptured()) { + if (var.isSpecial() || generator.vm()->typeProfiler()) { RefPtr<RegisterID> tempDst = generator.tempDestination(dst); generator.emitNode(tempDst.get(), m_right); - generator.emitMove(local.get(), tempDst.get()); + generator.emitMove(local, tempDst.get()); + generator.invalidateForInContextForLocal(local); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return generator.moveToDestinationIfNeeded(dst, tempDst.get()); } - RegisterID* result = generator.emitNode(local.get(), m_right); + RegisterID* result = generator.emitNode(local, m_right); + generator.invalidateForInContextForLocal(local); return generator.moveToDestinationIfNeeded(dst, result); } if (generator.isStrictMode()) generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident); + RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); if (dst == generator.ignoredResult()) dst = 0; RefPtr<RegisterID> result = generator.emitNode(dst, m_right); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitPutToScope(scope.get(), m_ident, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return returnResult; } // ------------------------------ AssignDotNode ----------------------------------- @@ -1473,6 +1855,10 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); generator.emitPutById(base.get(), m_ident, forwardResult); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, forwardResult); } @@ -1487,14 +1873,19 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast<JSC::Operator>(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitPutById(base.get(), m_ident, updatedValue); + RegisterID* ret = generator.emitPutById(base.get(), m_ident, updatedValue); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ AssignErrorNode ----------------------------------- RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); + return emitThrowReferenceError(generator, ASCIILiteral("Left side of assignment is not a reference.")); } // ------------------------------ AssignBracketNode ----------------------------------- @@ -1508,7 +1899,16 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); - generator.emitPutByVal(base.get(), property.get(), forwardResult); + + if (m_subscript->isString()) + generator.emitPutById(base.get(), static_cast<StringNode*>(m_subscript)->value(), forwardResult); + else + generator.emitPutByVal(base.get(), property.get(), forwardResult); + + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, forwardResult); } @@ -1525,6 +1925,10 @@ RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, Re generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutByVal(base.get(), property.get(), updatedValue); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return updatedValue; } @@ -1533,10 +1937,10 @@ RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, Re RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - ASSERT(m_expressions.size() > 1); - for (size_t i = 0; i < m_expressions.size() - 1; i++) - generator.emitNode(generator.ignoredResult(), m_expressions[i]); - return generator.emitNode(dst, m_expressions.last()); + CommaNode* node = this; + for (; node && node->next(); node = node->next()) + generator.emitNode(generator.ignoredResult(), node->m_expr); + return generator.emitNode(dst, node->m_expr); } // ------------------------------ ConstDeclNode ------------------------------------ @@ -1544,17 +1948,19 @@ RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) { // FIXME: This code does not match the behavior of const in Firefox. - if (Local local = generator.constLocal(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (!m_init) - return local.get(); + return local; - if (local.isCaptured()) { + // FIXME: Maybe call emitExpressionInfo here. + if (var.isSpecial() || generator.vm()->typeProfiler()) { RefPtr<RegisterID> tempDst = generator.newTemporary(); generator.emitNode(tempDst.get(), m_init); - return generator.emitMove(local.get(), tempDst.get()); + return generator.emitMove(local, tempDst.get()); } - return generator.emitNode(local.get(), m_init); + return generator.emitNode(local, m_init); } RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); @@ -1562,12 +1968,24 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) if (generator.codeType() == GlobalCode) return generator.emitInitGlobalConst(m_ident, value.get()); - if (generator.codeType() != EvalCode) - return value.get(); + if (generator.codeType() != EvalCode) { + // Do a special kind of resolution. If anything fails, then don't perform the assignment. This is + // pretty shady - particularly how negligent it is with inteleaving scopes - but it's the + // behavior that JSC has had for a long time. + + ASSERT(generator.codeType() == FunctionCode); + + var = generator.variablePerSymbolTable(m_ident); + if (!var.isResolved()) + return value.get(); + + RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), var); + return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound); + } // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope. - RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), m_ident); - return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound); + RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); + return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound); } RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) @@ -1592,15 +2010,13 @@ void ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) inline StatementNode* SourceElements::lastStatement() const { - size_t size = m_statements.size(); - return size ? m_statements[size - 1] : 0; + return m_tail; } inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - size_t size = m_statements.size(); - for (size_t i = 0; i < size; ++i) - generator.emitNode(dst, m_statements[i]); + for (StatementNode* statement = m_head; statement; statement = statement->next()) + generator.emitNode(dst, statement); } // ------------------------------ BlockNode ------------------------------------ @@ -1610,7 +2026,7 @@ inline StatementNode* BlockNode::lastStatement() const return m_statements ? m_statements->lastStatement() : 0; } -inline StatementNode* BlockNode::singleStatement() const +StatementNode* BlockNode::singleStatement() const { return m_statements ? m_statements->singleStatement() : 0; } @@ -1654,6 +2070,28 @@ void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) generator.emitNode(m_expr); } +// ------------------------------ EmptyVarExpression ---------------------------- + +RegisterID* EmptyVarExpression::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + if (!generator.vm()->typeProfiler()) + return nullptr; + + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) + generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr); + else { + RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); + RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); + generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident); + } + + generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); + + // It's safe to return null here because this node will always be a child node of VarStatementNode which ignores our return value. + return nullptr; +} + // ------------------------------ IfElseNode --------------------------------------- static inline StatementNode* singleStatement(StatementNode* statementNode) @@ -1708,6 +2146,7 @@ void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode); generator.emitLabel(beforeThen.get()); + generator.emitProfileControlFlow(m_ifBlock->startOffset()); if (!didFoldIfBlock) { generator.emitNode(dst, m_ifBlock); @@ -1717,10 +2156,14 @@ void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitLabel(beforeElse.get()); - if (m_elseBlock) + if (m_elseBlock) { + generator.emitProfileControlFlow(m_ifBlock->endOffset() + (m_ifBlock->isBlock() ? 1 : 0)); generator.emitNode(dst, m_elseBlock); + } generator.emitLabel(afterElse.get()); + StatementNode* endingBlock = m_elseBlock ? m_elseBlock : m_ifBlock; + generator.emitProfileControlFlow(endingBlock->endOffset() + (endingBlock->isBlock() ? 1 : 0)); } // ------------------------------ DoWhileNode ---------------------------------- @@ -1750,12 +2193,13 @@ void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->startOffset(), m_expr->lineStartOffset()); + generator.emitDebugHook(WillExecuteStatement, m_expr->firstLine(), m_expr->startOffset(), m_expr->lineStartOffset()); generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue); generator.emitLabel(topOfLoop.get()); generator.emitLoopHint(); + generator.emitProfileControlFlow(m_statement->startOffset()); generator.emitNode(dst, m_statement); generator.emitLabel(scope->continueTarget()); @@ -1764,6 +2208,8 @@ void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse); generator.emitLabel(scope->breakTarget()); + + generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); } // ------------------------------ ForNode -------------------------------------- @@ -1783,6 +2229,7 @@ void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitLabel(topOfLoop.get()); generator.emitLoopHint(); + generator.emitProfileControlFlow(m_statement->startOffset()); generator.emitNode(dst, m_statement); @@ -1797,131 +2244,275 @@ void ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitJump(topOfLoop.get()); generator.emitLabel(scope->breakTarget()); + generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); } // ------------------------------ ForInNode ------------------------------------ -void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* ForInNode::tryGetBoundLocal(BytecodeGenerator& generator) { - LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); - - if (!m_lexpr->isAssignmentLocation()) { - emitThrowReferenceError(generator, "Left side of for-in statement is not a reference."); - return; + if (m_lexpr->isResolveNode()) { + const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); + return generator.variable(ident).local(); } - generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); + if (m_lexpr->isDestructuringNode()) { + DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); + auto binding = assignNode->bindings(); + if (!binding->isBindingNode()) + return nullptr; - RefPtr<RegisterID> base = generator.newTemporary(); - generator.emitNode(base.get(), m_expr); - RefPtr<RegisterID> i = generator.newTemporary(); - RefPtr<RegisterID> size = generator.newTemporary(); - RefPtr<RegisterID> expectedSubscript; - RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget()); - generator.emitJump(scope->continueTarget()); + auto simpleBinding = static_cast<BindingNode*>(binding); + const Identifier& ident = simpleBinding->boundProperty(); + Variable var = generator.variable(ident); + if (var.isSpecial()) + return nullptr; + return var.local(); + } - RefPtr<Label> loopStart = generator.newLabel(); - generator.emitLabel(loopStart.get()); - generator.emitLoopHint(); + return nullptr; +} - RegisterID* propertyName; - bool optimizedForinAccess = false; +void ForInNode::emitLoopHeader(BytecodeGenerator& generator, RegisterID* propertyName) +{ if (m_lexpr->isResolveNode()) { const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); - Local local = generator.local(ident); - if (!local.get()) { - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; + Variable var = generator.variable(ident); + if (RegisterID* local = var.local()) + generator.emitMove(local, propertyName); + else { if (generator.isStrictMode()) generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident); + RegisterID* scope = generator.emitResolveScope(nullptr, var); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - generator.emitPutToScope(scope, ident, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); - } else { - expectedSubscript = generator.newTemporary(); - propertyName = expectedSubscript.get(); - generator.emitMove(local.get(), propertyName); - generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), local.get()); - optimizedForinAccess = true; + generator.emitPutToScope(scope, var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + if (generator.vm()->typeProfiler()) + generator.emitProfileType(propertyName, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); } - } else if (m_lexpr->isDotAccessorNode()) { + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1)); + return; + } + if (m_lexpr->isDotAccessorNode()) { DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); const Identifier& ident = assignNode->identifier(); - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; RegisterID* base = generator.emitNode(assignNode->base()); - generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); generator.emitPutById(base, ident, propertyName); - } else if (m_lexpr->isBracketAccessorNode()) { + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(propertyName, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); + } + return; + } + if (m_lexpr->isBracketAccessorNode()) { BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); RegisterID* subscript = generator.emitNode(assignNode->subscript()); - generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); generator.emitPutByVal(base.get(), subscript, propertyName); - } else { - ASSERT(m_lexpr->isDeconstructionNode()); - DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(propertyName, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); + } + return; + } + + if (m_lexpr->isDestructuringNode()) { + DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); auto binding = assignNode->bindings(); - if (binding->isBindingNode()) { - auto simpleBinding = static_cast<BindingNode*>(binding); - Identifier ident = simpleBinding->boundProperty(); - Local local = generator.local(ident); - propertyName = local.get(); - if (!propertyName || local.isCaptured()) - goto genericBinding; - expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName); - generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName); - optimizedForinAccess = true; - goto completedSimpleBinding; - } else { - genericBinding: - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect(propertyName); + if (!binding->isBindingNode()) { assignNode->bindings()->bindValue(generator, propertyName); + return; } - completedSimpleBinding: - ; + + auto simpleBinding = static_cast<BindingNode*>(binding); + const Identifier& ident = simpleBinding->boundProperty(); + Variable var = generator.variable(ident); + if (!var.local() || var.isSpecial()) { + assignNode->bindings()->bindValue(generator, propertyName); + return; + } + generator.emitMove(var.local(), propertyName); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(simpleBinding->divotStart(), simpleBinding->divotEnd()); + return; } - generator.emitNode(dst, m_statement); + RELEASE_ASSERT_NOT_REACHED(); +} + +void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (!m_lexpr->isAssignmentLocation()) { + emitThrowReferenceError(generator, ASCIILiteral("Left side of for-in statement is not a reference.")); + return; + } - if (optimizedForinAccess) - generator.popOptimisedForIn(); + RefPtr<Label> end = generator.newLabel(); - generator.emitLabel(scope->continueTarget()); - generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get()); generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); - generator.emitLabel(scope->breakTarget()); + + RefPtr<RegisterID> base = generator.newTemporary(); + RefPtr<RegisterID> length; + RefPtr<RegisterID> enumerator; + generator.emitNode(base.get(), m_expr); + RefPtr<RegisterID> local = this->tryGetBoundLocal(generator); + RefPtr<RegisterID> enumeratorIndex; + + int profilerStartOffset = m_statement->startOffset(); + int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0); + + enumerator = generator.emitGetPropertyEnumerator(generator.newTemporary(), base.get()); + + // Indexed property loop. + { + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); + RefPtr<Label> loopStart = generator.newLabel(); + RefPtr<Label> loopEnd = generator.newLabel(); + + length = generator.emitGetEnumerableLength(generator.newTemporary(), enumerator.get()); + RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0)); + RefPtr<RegisterID> propertyName = generator.newTemporary(); + + generator.emitLabel(loopStart.get()); + generator.emitLoopHint(); + + RefPtr<RegisterID> result = generator.emitEqualityOp(op_less, generator.newTemporary(), i.get(), length.get()); + generator.emitJumpIfFalse(result.get(), loopEnd.get()); + generator.emitHasIndexedProperty(result.get(), base.get(), i.get()); + generator.emitJumpIfFalse(result.get(), scope->continueTarget()); + + generator.emitToIndexString(propertyName.get(), i.get()); + this->emitLoopHeader(generator, propertyName.get()); + + generator.emitProfileControlFlow(profilerStartOffset); + + generator.pushIndexedForInScope(local.get(), i.get()); + generator.emitNode(dst, m_statement); + generator.popIndexedForInScope(local.get()); + + generator.emitProfileControlFlow(profilerEndOffset); + + generator.emitLabel(scope->continueTarget()); + generator.emitInc(i.get()); + generator.emitJump(loopStart.get()); + + generator.emitLabel(scope->breakTarget()); + generator.emitJump(end.get()); + generator.emitLabel(loopEnd.get()); + } + + // Structure property loop. + { + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); + RefPtr<Label> loopStart = generator.newLabel(); + RefPtr<Label> loopEnd = generator.newLabel(); + + enumeratorIndex = generator.emitLoad(generator.newTemporary(), jsNumber(0)); + RefPtr<RegisterID> propertyName = generator.newTemporary(); + generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); + + generator.emitLabel(loopStart.get()); + generator.emitLoopHint(); + + RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get()); + generator.emitJumpIfTrue(result.get(), loopEnd.get()); + generator.emitHasStructureProperty(result.get(), base.get(), propertyName.get(), enumerator.get()); + generator.emitJumpIfFalse(result.get(), scope->continueTarget()); + + this->emitLoopHeader(generator, propertyName.get()); + + generator.emitProfileControlFlow(profilerStartOffset); + + generator.pushStructureForInScope(local.get(), enumeratorIndex.get(), propertyName.get(), enumerator.get()); + generator.emitNode(dst, m_statement); + generator.popStructureForInScope(local.get()); + + generator.emitProfileControlFlow(profilerEndOffset); + + generator.emitLabel(scope->continueTarget()); + generator.emitInc(enumeratorIndex.get()); + generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); + generator.emitJump(loopStart.get()); + + generator.emitLabel(scope->breakTarget()); + generator.emitJump(end.get()); + generator.emitLabel(loopEnd.get()); + } + + // Generic property loop. + { + LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); + RefPtr<Label> loopStart = generator.newLabel(); + RefPtr<Label> loopEnd = generator.newLabel(); + + RefPtr<RegisterID> propertyName = generator.newTemporary(); + + generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); + + generator.emitLabel(loopStart.get()); + generator.emitLoopHint(); + + RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get()); + generator.emitJumpIfTrue(result.get(), loopEnd.get()); + + generator.emitHasGenericProperty(result.get(), base.get(), propertyName.get()); + generator.emitJumpIfFalse(result.get(), scope->continueTarget()); + + this->emitLoopHeader(generator, propertyName.get()); + + generator.emitProfileControlFlow(profilerStartOffset); + + generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); + generator.emitInc(enumeratorIndex.get()); + generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get()); + generator.emitJump(loopStart.get()); + + generator.emitLabel(scope->breakTarget()); + generator.emitJump(end.get()); + generator.emitLabel(loopEnd.get()); + } + + generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); + generator.emitLabel(end.get()); + generator.emitProfileControlFlow(profilerEndOffset); +} + +void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + this->emitMultiLoopBytecode(generator, dst); } // ------------------------------ ForOfNode ------------------------------------ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (!m_lexpr->isAssignmentLocation()) { - emitThrowReferenceError(generator, "Left side of for-of statement is not a reference."); + emitThrowReferenceError(generator, ASCIILiteral("Left side of for-of statement is not a reference.")); return; } - - LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); - + generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset()); auto extractor = [this, dst](BytecodeGenerator& generator, RegisterID* value) { if (m_lexpr->isResolveNode()) { const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); - if (Local local = generator.local(ident)) - generator.emitMove(local.get(), value); + Variable var = generator.variable(ident); + if (RegisterID* local = var.local()) + generator.emitMove(local, value); else { if (generator.isStrictMode()) generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident); + RegisterID* scope = generator.emitResolveScope(nullptr, var); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - generator.emitPutToScope(scope, ident, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + if (generator.vm()->typeProfiler()) + generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); } + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1)); } else if (m_lexpr->isDotAccessorNode()) { DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); const Identifier& ident = assignNode->identifier(); @@ -1929,6 +2520,10 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); generator.emitPutById(base.get(), ident, value); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); + } } else if (m_lexpr->isBracketAccessorNode()) { BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr); RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); @@ -1936,14 +2531,20 @@ void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd()); generator.emitPutByVal(base.get(), subscript, value); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(assignNode->divotStart(), assignNode->divotEnd()); + } } else { - ASSERT(m_lexpr->isDeconstructionNode()); - DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr); + ASSERT(m_lexpr->isDestructuringNode()); + DestructuringAssignmentNode* assignNode = static_cast<DestructuringAssignmentNode*>(m_lexpr); assignNode->bindings()->bindValue(generator, value); } + generator.emitProfileControlFlow(m_statement->startOffset()); generator.emitNode(dst, m_statement); }; generator.emitEnumeration(this, m_expr, extractor); + generator.emitProfileControlFlow(m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0)); } // ------------------------------ ContinueNode --------------------------------- @@ -1969,8 +2570,10 @@ void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) LabelScopePtr scope = generator.continueTarget(m_ident); ASSERT(scope); - generator.emitPopScopes(scope->scopeDepth()); + generator.emitPopScopes(generator.scopeRegister(), scope->scopeDepth()); generator.emitJump(scope->continueTarget()); + + generator.emitProfileControlFlow(endOffset()); } // ------------------------------ BreakNode ------------------------------------ @@ -1996,8 +2599,10 @@ void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) LabelScopePtr scope = generator.breakTarget(m_ident); ASSERT(scope); - generator.emitPopScopes(scope->scopeDepth()); + generator.emitPopScopes(generator.scopeRegister(), scope->scopeDepth()); generator.emitJump(scope->breakTarget()); + + generator.emitProfileControlFlow(endOffset()); } // ------------------------------ ReturnNode ----------------------------------- @@ -2011,13 +2616,22 @@ void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) dst = 0; RefPtr<RegisterID> returnRegister = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnRegister.get(), ProfileTypeBytecodeFunctionReturnStatement, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } if (generator.scopeDepth()) { returnRegister = generator.emitMove(generator.newTemporary(), returnRegister.get()); - generator.emitPopScopes(0); + generator.emitPopScopes(generator.scopeRegister(), 0); } generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); generator.emitReturn(returnRegister.get()); + generator.emitProfileControlFlow(endOffset()); + // Emitting an unreachable return here is needed in case this op_profile_control_flow is the + // last opcode in a CodeBlock because a CodeBlock's instructions must end with a terminal opcode. + if (generator.vm()->controlFlowProfiler()) + generator.emitReturn(generator.emitLoad(nullptr, jsUndefined())); } // ------------------------------ WithNode ------------------------------------- @@ -2028,15 +2642,16 @@ void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) RefPtr<RegisterID> scope = generator.emitNode(m_expr); generator.emitExpressionInfo(m_divot, m_divot - m_expressionLength, m_divot); - generator.emitPushWithScope(scope.get()); + generator.emitPushWithScope(generator.scopeRegister(), scope.get()); generator.emitNode(dst, m_statement); - generator.emitPopScope(); + generator.emitPopScope(generator.scopeRegister()); } // ------------------------------ CaseClauseNode -------------------------------- inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + generator.emitProfileControlFlow(m_startOffset); if (!m_statements) return; m_statements->emitBytecode(generator, dst); @@ -2206,6 +2821,7 @@ void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) m_block->emitBytecodeForBlock(generator, r0.get(), dst); generator.emitLabel(scope->breakTarget()); + generator.emitProfileControlFlow(endOffset()); } // ------------------------------ LabelNode ------------------------------------ @@ -2233,6 +2849,8 @@ void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) RefPtr<RegisterID> expr = generator.emitNode(m_expr); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitThrow(expr.get()); + + generator.emitProfileControlFlow(endOffset()); } // ------------------------------ TryNode -------------------------------------- @@ -2263,17 +2881,20 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) // Uncaught exception path: the catch block. RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); - RefPtr<RegisterID> exceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), here.get()); + RefPtr<RegisterID> exceptionRegister = generator.newTemporary(); + RefPtr<RegisterID> thrownValueRegister = generator.newTemporary(); + generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), here.get(), HandlerType::Catch); if (m_finallyBlock) { // If the catch block throws an exception and we have a finally block, then the finally // block should "catch" that exception. tryData = generator.pushTry(here.get()); } - - generator.emitPushCatchScope(m_exceptionIdent, exceptionRegister.get(), DontDelete); + + generator.emitPushCatchScope(generator.scopeRegister(), m_thrownValueIdent, thrownValueRegister.get(), DontDelete); + generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1); generator.emitNode(dst, m_catchBlock); - generator.emitPopScope(); + generator.emitPopScope(generator.scopeRegister()); generator.emitLabel(catchEndLabel.get()); } @@ -2284,17 +2905,27 @@ void TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) RefPtr<Label> finallyEndLabel = generator.newLabel(); + int finallyStartOffset = m_catchBlock ? m_catchBlock->endOffset() + 1 : m_tryBlock->endOffset() + 1; + // Normal path: run the finally code, and jump to the end. + generator.emitProfileControlFlow(finallyStartOffset); generator.emitNode(dst, m_finallyBlock); + generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1); generator.emitJump(finallyEndLabel.get()); // Uncaught exception path: invoke the finally block, then re-throw the exception. - RefPtr<RegisterID> tempExceptionRegister = generator.popTryAndEmitCatch(tryData, generator.newTemporary(), preFinallyLabel.get()); + RefPtr<RegisterID> exceptionRegister = generator.newTemporary(); + RefPtr<RegisterID> thrownValueRegister = generator.newTemporary(); + generator.popTryAndEmitCatch(tryData, exceptionRegister.get(), thrownValueRegister.get(), preFinallyLabel.get(), HandlerType::Finally); + generator.emitProfileControlFlow(finallyStartOffset); generator.emitNode(dst, m_finallyBlock); - generator.emitThrow(tempExceptionRegister.get()); + generator.emitThrow(exceptionRegister.get()); generator.emitLabel(finallyEndLabel.get()); - } + generator.emitProfileControlFlow(m_finallyBlock->endOffset() + 1); + } else + generator.emitProfileControlFlow(m_catchBlock->endOffset() + 1); + } // ------------------------------ ScopeNode ----------------------------- @@ -2314,6 +2945,7 @@ void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) RefPtr<RegisterID> dstRegister = generator.newTemporary(); generator.emitLoad(dstRegister.get(), jsUndefined()); + generator.emitProfileControlFlow(startStartOffset()); emitStatementsBytecode(generator, dstRegister.get()); generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset()); @@ -2336,8 +2968,25 @@ void EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) // ------------------------------ FunctionBodyNode ----------------------------- -void FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +void FunctionBodyNode::emitBytecode(BytecodeGenerator&, RegisterID*) { +} + +void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + if (generator.vm()->typeProfiler()) { + for (size_t i = 0; i < m_parameters->size(); i++) { + // FIXME: Handle Destructuring assignments into arguments. + if (!m_parameters->at(i)->isBindingNode()) + continue; + BindingNode* parameter = static_cast<BindingNode*>(m_parameters->at(i)); + RegisterID reg(CallFrame::argumentOffset(i)); + generator.emitProfileType(®, ProfileTypeBytecodeFunctionArgument, nullptr); + generator.emitTypeProfilerExpressionInfo(parameter->divotStart(), parameter->divotEnd()); + } + } + + generator.emitProfileControlFlow(startStartOffset()); generator.emitDebugHook(DidEnterCallFrame, startLine(), startStartOffset(), startLineStartOffset()); emitStatementsBytecode(generator, generator.ignoredResult()); @@ -2354,27 +3003,13 @@ void FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) // If there is no return we must automatically insert one. if (!returnNode) { RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined()); + if (generator.vm()->typeProfiler()) + generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement, nullptr); // Do not emit expression info for this profile because it's not in the user's source code. ASSERT(startOffset() >= lineStartOffset()); generator.emitDebugHook(WillLeaveCallFrame, lastLine(), startOffset(), lineStartOffset()); generator.emitReturn(r0); return; } - - // If there is a return statment, and it is the only statement in the function, check if this is a numeric compare. - if (static_cast<BlockNode*>(singleStatement)->singleStatement()) { - ExpressionNode* returnValueExpression = returnNode->value(); - if (returnValueExpression && returnValueExpression->isSubtract()) { - ExpressionNode* lhsExpression = static_cast<SubNode*>(returnValueExpression)->lhs(); - ExpressionNode* rhsExpression = static_cast<SubNode*>(returnValueExpression)->rhs(); - if (lhsExpression->isResolveNode() - && rhsExpression->isResolveNode() - && generator.isArgumentNumber(static_cast<ResolveNode*>(lhsExpression)->identifier(), 0) - && generator.isArgumentNumber(static_cast<ResolveNode*>(rhsExpression)->identifier(), 1)) { - - generator.setIsNumericCompareFunction(true); - } - } - } } // ------------------------------ FuncDeclNode --------------------------------- @@ -2389,9 +3024,89 @@ RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* { return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); } + +#if ENABLE(ES6_CLASS_SYNTAX) +// ------------------------------ ClassDeclNode --------------------------------- + +void ClassDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitNode(dst, m_classDeclaration); +} + +// ------------------------------ ClassExprNode --------------------------------- + +RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> superclass; + if (m_classHeritage) { + superclass = generator.newTemporary(); + generator.emitNode(superclass.get(), m_classHeritage); + } + + RefPtr<RegisterID> constructor; + + // FIXME: Make the prototype non-configurable & non-writable. + if (m_constructorExpression) + constructor = generator.emitNode(dst, m_constructorExpression); + else { + constructor = generator.emitNewDefaultConstructor(generator.finalDestination(dst), + m_classHeritage ? ConstructorKind::Derived : ConstructorKind::Base, m_name); + } + + const auto& propertyNames = generator.propertyNames(); + RefPtr<RegisterID> prototype = generator.emitNewObject(generator.newTemporary()); + + if (superclass) { + RefPtr<RegisterID> protoParent = generator.newTemporary(); + generator.emitLoad(protoParent.get(), jsNull()); + + RefPtr<RegisterID> tempRegister = generator.newTemporary(); + + // FIXME: Throw TypeError if it's a generator function. + RefPtr<Label> superclassIsUndefinedLabel = generator.newLabel(); + generator.emitJumpIfTrue(generator.emitIsUndefined(tempRegister.get(), superclass.get()), superclassIsUndefinedLabel.get()); + + RefPtr<Label> superclassIsNullLabel = generator.newLabel(); + generator.emitJumpIfTrue(generator.emitUnaryOp(op_eq_null, tempRegister.get(), superclass.get()), superclassIsNullLabel.get()); + + RefPtr<Label> superclassIsObjectLabel = generator.newLabel(); + generator.emitJumpIfTrue(generator.emitIsObject(tempRegister.get(), superclass.get()), superclassIsObjectLabel.get()); + generator.emitLabel(superclassIsUndefinedLabel.get()); + generator.emitThrowTypeError(ASCIILiteral("The superclass is not an object.")); + generator.emitLabel(superclassIsObjectLabel.get()); + generator.emitGetById(protoParent.get(), superclass.get(), generator.propertyNames().prototype); + + RefPtr<Label> protoParentIsObjectOrNullLabel = generator.newLabel(); + generator.emitJumpIfTrue(generator.emitUnaryOp(op_is_object_or_null, tempRegister.get(), protoParent.get()), protoParentIsObjectOrNullLabel.get()); + generator.emitThrowTypeError(ASCIILiteral("The superclass's prototype is not an object.")); + generator.emitLabel(protoParentIsObjectOrNullLabel.get()); + + generator.emitDirectPutById(constructor.get(), generator.propertyNames().underscoreProto, superclass.get(), PropertyNode::Unknown); + generator.emitLabel(superclassIsNullLabel.get()); + generator.emitDirectPutById(prototype.get(), generator.propertyNames().underscoreProto, protoParent.get(), PropertyNode::Unknown); + + emitPutHomeObject(generator, constructor.get(), prototype.get()); + } + + RefPtr<RegisterID> constructorNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.constructor); + generator.emitCallDefineProperty(prototype.get(), constructorNameRegister.get(), constructor.get(), nullptr, nullptr, + BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); + + RefPtr<RegisterID> prototypeNameRegister = generator.emitLoad(generator.newTemporary(), propertyNames.prototype); + generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position); + + if (m_staticMethods) + generator.emitNode(constructor.get(), m_staticMethods); + + if (m_instanceMethods) + generator.emitNode(prototype.get(), m_instanceMethods); + + return generator.moveToDestinationIfNeeded(dst, constructor.get()); +} +#endif -// ------------------------------ DeconstructingAssignmentNode ----------------- -RegisterID* DeconstructingAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +// ------------------------------ DestructuringAssignmentNode ----------------- +RegisterID* DestructuringAssignmentNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (RegisterID* result = m_bindings->emitDirectBinding(generator, dst, m_initializer)) return result; @@ -2401,43 +3116,106 @@ RegisterID* DeconstructingAssignmentNode::emitBytecode(BytecodeGenerator& genera return generator.moveToDestinationIfNeeded(dst, initializer.get()); } -DeconstructionPatternNode::~DeconstructionPatternNode() +DestructuringPatternNode::~DestructuringPatternNode() { } - + +static void assignDefaultValueIfUndefined(BytecodeGenerator& generator, RegisterID* maybeUndefined, ExpressionNode* defaultValue) +{ + ASSERT(defaultValue); + RefPtr<Label> isNotUndefined = generator.newLabel(); + generator.emitJumpIfFalse(generator.emitIsUndefined(generator.newTemporary(), maybeUndefined), isNotUndefined.get()); + generator.emitNode(maybeUndefined, defaultValue); + generator.emitLabel(isNotUndefined.get()); +} + void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) const { - for (size_t i = 0; i < m_targetPatterns.size(); i++) { - auto target = m_targetPatterns[i]; - if (!target) - continue; - RefPtr<RegisterID> temp = generator.newTemporary(); - generator.emitLoad(temp.get(), jsNumber(i)); - generator.emitGetByVal(temp.get(), rhs, temp.get()); - target->bindValue(generator, temp.get()); + RefPtr<RegisterID> iterator = generator.newTemporary(); + { + generator.emitGetById(iterator.get(), rhs, generator.propertyNames().iteratorSymbol); + CallArguments args(generator, nullptr); + generator.emitMove(args.thisRegister(), rhs); + generator.emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd()); + } + + if (m_targetPatterns.isEmpty()) { + generator.emitIteratorClose(iterator.get(), this); + return; + } + + RefPtr<RegisterID> done; + for (auto& target : m_targetPatterns) { + switch (target.bindingType) { + case BindingType::Elision: + case BindingType::Element: { + RefPtr<Label> iterationSkipped = generator.newLabel(); + if (!done) + done = generator.newTemporary(); + else + generator.emitJumpIfTrue(done.get(), iterationSkipped.get()); + + RefPtr<RegisterID> value = generator.newTemporary(); + generator.emitIteratorNext(value.get(), iterator.get(), this); + generator.emitGetById(done.get(), value.get(), generator.propertyNames().done); + generator.emitJumpIfTrue(done.get(), iterationSkipped.get()); + generator.emitGetById(value.get(), value.get(), generator.propertyNames().value); + + { + RefPtr<Label> valueIsSet = generator.newLabel(); + generator.emitJump(valueIsSet.get()); + generator.emitLabel(iterationSkipped.get()); + generator.emitLoad(value.get(), jsUndefined()); + generator.emitLabel(valueIsSet.get()); + } + + if (target.bindingType == BindingType::Element) { + if (target.defaultValue) + assignDefaultValueIfUndefined(generator, value.get(), target.defaultValue); + target.pattern->bindValue(generator, value.get()); + } + break; + } + + case BindingType::RestElement: { + RefPtr<RegisterID> array = generator.emitNewArray(generator.newTemporary(), 0, 0); + + RefPtr<Label> iterationDone = generator.newLabel(); + if (!done) + done = generator.newTemporary(); + else + generator.emitJumpIfTrue(done.get(), iterationDone.get()); + + RefPtr<RegisterID> index = generator.newTemporary(); + generator.emitLoad(index.get(), jsNumber(0)); + RefPtr<Label> loopStart = generator.newLabel(); + generator.emitLabel(loopStart.get()); + + RefPtr<RegisterID> value = generator.newTemporary(); + generator.emitIteratorNext(value.get(), iterator.get(), this); + generator.emitGetById(done.get(), value.get(), generator.propertyNames().done); + generator.emitJumpIfTrue(done.get(), iterationDone.get()); + generator.emitGetById(value.get(), value.get(), generator.propertyNames().value); + + generator.emitDirectPutByVal(array.get(), index.get(), value.get()); + generator.emitInc(index.get()); + generator.emitJump(loopStart.get()); + + generator.emitLabel(iterationDone.get()); + target.pattern->bindValue(generator, array.get()); + break; + } + } } + + RefPtr<Label> iteratorClosed = generator.newLabel(); + generator.emitJumpIfTrue(done.get(), iteratorClosed.get()); + generator.emitIteratorClose(iterator.get(), this); + generator.emitLabel(iteratorClosed.get()); } RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, RegisterID* dst, ExpressionNode* rhs) { - if (rhs->isResolveNode() - && generator.willResolveToArguments(static_cast<ResolveNode*>(rhs)->identifier()) - && !generator.symbolTable().slowArguments()) { - for (size_t i = 0; i < m_targetPatterns.size(); i++) { - auto target = m_targetPatterns[i]; - if (!target) - continue; - - RefPtr<RegisterID> temp = generator.newTemporary(); - generator.emitLoad(temp.get(), jsNumber(i)); - generator.emitGetArgumentByVal(temp.get(), generator.uncheckedRegisterForArguments(), temp.get()); - target->bindValue(generator, temp.get()); - } - if (dst == generator.ignoredResult() || !dst) - return generator.emitLoad(generator.finalDestination(dst), jsUndefined()); - Local local = generator.local(generator.vm()->propertyNames->arguments); - return generator.moveToDestinationIfNeeded(dst, local.get()); - } if (!rhs->isSimpleArray()) return 0; @@ -2455,13 +3233,15 @@ RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, Re for (size_t i = 0; i < m_targetPatterns.size(); i++) { registers.uncheckedAppend(generator.newTemporary()); generator.emitNode(registers.last().get(), elements[i]); + if (m_targetPatterns[i].defaultValue) + assignDefaultValueIfUndefined(generator, registers.last().get(), m_targetPatterns[i].defaultValue); if (resultRegister) generator.emitPutByIndex(resultRegister.get(), i, registers.last().get()); } for (size_t i = 0; i < m_targetPatterns.size(); i++) { - if (m_targetPatterns[i]) - m_targetPatterns[i]->bindValue(generator, registers[i].get()); + if (m_targetPatterns[i].pattern) + m_targetPatterns[i].pattern->bindValue(generator, registers[i].get()); } if (resultRegister) return generator.moveToDestinationIfNeeded(dst, resultRegister.get()); @@ -2472,13 +3252,24 @@ void ArrayPatternNode::toString(StringBuilder& builder) const { builder.append('['); for (size_t i = 0; i < m_targetPatterns.size(); i++) { - if (!m_targetPatterns[i]) { + const auto& target = m_targetPatterns[i]; + + switch (target.bindingType) { + case BindingType::Elision: builder.append(','); - continue; + break; + + case BindingType::Element: + target.pattern->toString(builder); + if (i < m_targetPatterns.size() - 1) + builder.append(','); + break; + + case BindingType::RestElement: + builder.append("..."); + target.pattern->toString(builder); + break; } - m_targetPatterns[i]->toString(builder); - if (i < m_targetPatterns.size() - 1) - builder.append(','); } builder.append(']'); } @@ -2486,7 +3277,7 @@ void ArrayPatternNode::toString(StringBuilder& builder) const void ArrayPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const { for (size_t i = 0; i < m_targetPatterns.size(); i++) { - if (DeconstructionPatternNode* node = m_targetPatterns[i].get()) + if (DestructuringPatternNode* node = m_targetPatterns[i].pattern.get()) node->collectBoundIdentifiers(identifiers); } } @@ -2495,13 +3286,11 @@ void ObjectPatternNode::toString(StringBuilder& builder) const { builder.append('{'); for (size_t i = 0; i < m_targetPatterns.size(); i++) { - if (m_targetPatterns[i].wasString) { - builder.append('"'); - escapeStringToBuilder(builder, m_targetPatterns[i].propertyName.string()); - builder.append('"'); - } else + if (m_targetPatterns[i].wasString) + builder.appendQuotedJSONString(m_targetPatterns[i].propertyName.string()); + else builder.append(m_targetPatterns[i].propertyName.string()); - builder.append(":"); + builder.append(':'); m_targetPatterns[i].pattern->toString(builder); if (i < m_targetPatterns.size() - 1) builder.append(','); @@ -2515,6 +3304,8 @@ void ObjectPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) auto& target = m_targetPatterns[i]; RefPtr<RegisterID> temp = generator.newTemporary(); generator.emitGetById(temp.get(), rhs, target.propertyName); + if (target.defaultValue) + assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue); target.pattern->bindValue(generator, temp.get()); } } @@ -2527,19 +3318,26 @@ void ObjectPatternNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const { - if (Local local = generator.local(m_boundProperty)) { - if (local.isReadOnly()) { + Variable var = generator.variable(m_boundProperty); + if (RegisterID* local = var.local()) { + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); return; } - generator.emitMove(local.get(), value); + generator.emitMove(local, value); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return; } if (generator.isStrictMode()) generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); - RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), m_boundProperty); + RegisterID* scope = generator.emitResolveScope(nullptr, var); generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); - generator.emitPutToScope(scope, m_boundProperty, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_boundProperty); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return; } diff --git a/bytecompiler/RegisterID.h b/bytecompiler/RegisterID.h index 5ec7c44..688c8b9 100644 --- a/bytecompiler/RegisterID.h +++ b/bytecompiler/RegisterID.h @@ -70,7 +70,6 @@ namespace JSC { void setIndex(int index) { - ASSERT(!m_refCount); #ifndef NDEBUG m_didSetIndex = true; #endif diff --git a/bytecompiler/StaticPropertyAnalysis.h b/bytecompiler/StaticPropertyAnalysis.h index 293c224..5a9918d 100644 --- a/bytecompiler/StaticPropertyAnalysis.h +++ b/bytecompiler/StaticPropertyAnalysis.h @@ -35,9 +35,9 @@ namespace JSC { // Reference count indicates number of live registers that alias this object. class StaticPropertyAnalysis : public RefCounted<StaticPropertyAnalysis> { public: - static PassRefPtr<StaticPropertyAnalysis> create(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* instructions, unsigned target) + static Ref<StaticPropertyAnalysis> create(Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>* instructions, unsigned target) { - return adoptRef(new StaticPropertyAnalysis(instructions, target)); + return adoptRef(*new StaticPropertyAnalysis(instructions, target)); } void addPropertyIndex(unsigned propertyIndex) { m_propertyIndexes.add(propertyIndex); } diff --git a/config.h b/config.h index 2761624..bea1bf0 100644 --- a/config.h +++ b/config.h @@ -32,24 +32,22 @@ #if OS(WINDOWS) #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0502 +#define _WIN32_WINNT 0x601 #endif #ifndef WINVER -#define WINVER 0x0502 +#define WINVER 0x0601 #endif -#if !COMPILER(MSVC7_OR_LOWER) && !OS(WINCE) +#if !COMPILER(MSVC7_OR_LOWER) // We need to define this before the first #include of stdlib.h or it won't contain rand_s. #ifndef _CRT_RAND_S #define _CRT_RAND_S #endif -#endif // !COMPILER(MSVC7_OR_LOWER) && !OS(WINCE) +#endif // !COMPILER(MSVC7_OR_LOWER #endif // OS(WINDOWS) -#define WTF_CHANGES 1 - #ifdef __cplusplus #undef new #undef delete @@ -64,7 +62,3 @@ #define SKIP_STATIC_CONSTRUCTORS_ON_GCC 1 #endif -// Enable the following if you want to use the MacroAssembler::probe() facility -// to do JIT debugging. -#define WTF_USE_MASM_PROBE 0 - diff --git a/copy-llvm-ir-to-derived-sources.sh b/copy-llvm-ir-to-derived-sources.sh index 940fbb5..70d254d 100755 --- a/copy-llvm-ir-to-derived-sources.sh +++ b/copy-llvm-ir-to-derived-sources.sh @@ -24,18 +24,20 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OBJ_DIR=${TARGET_TEMP_DIR}/Objects-${CURRENT_VARIANT} -RUNTIME_DERIVED_SOURCES_DIR=${BUILT_PRODUCTS_DIR}/DerivedSources/JavaScriptCoreRuntime +RUNTIME_INSTALL_DIR=${BUILT_PRODUCTS_DIR}/${JAVASCRIPTCORE_RESOURCES_DIR}/Runtime shopt -s nullglob for arch in $ARCHS; do if [ -d "$OBJ_DIR/$arch" ]; then - mkdir -p "$RUNTIME_DERIVED_SOURCES_DIR/$arch" + mkdir -p "$RUNTIME_INSTALL_DIR/$arch" + for file in "$OBJ_DIR/$arch"/*.o; do file_name=${file##*/} - gzip -9 -c "$file" > "$RUNTIME_DERIVED_SOURCES_DIR/$arch/${file_name%.o}.bc.gz" + cp "$file" "$RUNTIME_INSTALL_DIR/$arch/${file_name%.o}.bc" done + ${SRCROOT}/build-symbol-table-index.py $arch fi done diff --git a/create-llvm-ir-from-source-file.py b/create-llvm-ir-from-source-file.py new file mode 100644 index 0000000..f0aa4a0 --- /dev/null +++ b/create-llvm-ir-from-source-file.py @@ -0,0 +1,41 @@ +#!/usr/bin/python + +# Copyright (C) 2014 University of Szeged. All rights reserved. +# Copyright (C) 2014 Samsung Electronics. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER 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. + +import os +import subprocess +import sys + +JSC_SOURCE = sys.argv[1] +RUNTIME_INSTALL_DIR = sys.argv[2] +CLANG_EXE = sys.argv[3] +INCLUDE_DIRS = "-I%s" % sys.argv[4] + +try: + os.mkdir(os.path.join(RUNTIME_INSTALL_DIR, "runtime")) +except OSError: + pass + +subprocess.call([CLANG_EXE, "-emit-llvm", "-O3", "-std=c++11", "-fno-exceptions", "-fno-strict-aliasing", "-fno-rtti", "-ffunction-sections", "-fdata-sections", "-fno-rtti", "-fno-omit-frame-pointer", "-fPIC", "-DWTF_PLATFORM_EFL=1", "-o", os.path.join(RUNTIME_INSTALL_DIR, os.path.splitext(JSC_SOURCE)[0] + ".bc"), "-c", JSC_SOURCE] + INCLUDE_DIRS.split()) diff --git a/create-symbol-table-index.py b/create-symbol-table-index.py new file mode 100755 index 0000000..f5ba14d --- /dev/null +++ b/create-symbol-table-index.py @@ -0,0 +1,106 @@ +#!/usr/bin/python + +# Copyright (C) 2014 Apple Inc. All rights reserved. +# Copyright (C) 2014 University of Szeged. All rights reserved. +# Copyright (C) 2014 Samsung Electronics. 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. + +import glob +import os +import subprocess +import sys +import shutil +import re +from sets import Set +from operator import itemgetter + +print("Building Index Table") + +RUNTIME_INSTALL_DIR = sys.argv[1] +JSC_DIR = sys.argv[2] +DERIVED_SOURCES_DIR = sys.argv[3] +LLVM_BINS = sys.argv[4] + +try: + os.mkdir(os.path.join(RUNTIME_INSTALL_DIR, "runtime")) +except OSError: + pass + +symbol_table_location = os.path.join(RUNTIME_INSTALL_DIR, "runtime", "Runtime.symtbl") + +symbol_table = {} + +symbol_table_is_out_of_date = False + +symbol_table_modification_time = 0 + +if os.path.isfile(symbol_table_location): + symbol_table_modification_time = os.path.getmtime(symbol_table_location) + +file_suffix = "bc" +file_suffix_length = len(file_suffix) + +tested_symbols_location = os.path.join(JSC_DIR, "tested-symbols.symlst") +include_symbol_table_location = os.path.join(DERIVED_SOURCES_DIR, "InlineRuntimeSymbolTable.h") + +tested_symbols = Set([]) + +if os.path.isfile(tested_symbols_location): + with open(tested_symbols_location, 'r') as file: + print("Loading tested symbols") + for line in file: + tested_symbols.add(line[:-1]) + +for bitcode_file in glob.iglob(os.path.join(RUNTIME_INSTALL_DIR, "runtime", "*." + file_suffix)): + bitcode_basename = os.path.basename(bitcode_file) + + print("Appending symbols from " + bitcode_basename) + lines = subprocess.check_output([os.path.join(LLVM_BINS, "llvm-nm"), "--defined-only", bitcode_file]).splitlines() + + for line in lines: + symbol = line.split()[1] + if (symbol[:1] == "_" and symbol[-3:] != ".eh" and (("_" + symbol in tested_symbols) or ("_" + symbol[:7] + "L" + symbol[7:] in tested_symbols))): + symbol_table[symbol] = bitcode_basename + +if os.path.isfile(symbol_table_location): + with open(symbol_table_location, 'r') as file: + print("Loading symbol table") + for line in file: + symbol, _, location = line[:-1].partition(" ") + # don't overwrite new symbols with old locations + if not symbol in symbol_table: + symbol_table[symbol] = location + +symbol_list = symbol_table.items() + +print("Writing symbol table: " + symbol_table_location) +print("Writing inline file: " + include_symbol_table_location) + +with open(symbol_table_location, "w") as symbol_file: + with open(include_symbol_table_location, "w") as include_file: + include_file.write("#define FOR_EACH_LIBRARY_SYMBOL(macro)") + for symbol, location in symbol_list: + symbol_file.write("{} {}\n".format(symbol, location)) + include_file.write(" \\\nmacro(\"{}\", \"{}\")".format(symbol, location)) + include_file.write("\n") +print("Done") diff --git a/create_hash_table b/create_hash_table index 88e8447..b26eed0 100755 --- a/create_hash_table +++ b/create_hash_table @@ -94,6 +94,11 @@ while (<IN>) { if ($att =~ m/Function/) { push(@values, { "type" => "Function", "function" => $val, "params" => (length($param) ? $param : "") }); #printf STDERR "WARNING: Number of arguments missing for $key/$val\n" if (length($param) == 0); + } elsif ($att =~ m/Accessor/) { + my $get = $val; + my $put = "nullptr"; + $hasSetter = "true"; + push(@values, { "type" => "Accessor", "get" => $get, "put" => $put }); } elsif (length($att)) { my $get = $val; my $put = "0"; @@ -285,6 +290,11 @@ sub output() { $firstCastStr = "static_cast<NativeFunction>"; $firstValue = $values[$i]{"function"}; $secondValue = $values[$i]{"params"}; + } elsif ($values[$i]{"type"} eq "Accessor") { + $firstCastStr = "static_cast<NativeFunction>"; + $secondCastStr = "static_cast<NativeFunction>"; + $firstValue = $values[$i]{"get"}; + $secondValue = $values[$i]{"put"}; } elsif ($values[$i]{"type"} eq "Property") { $firstCastStr = "static_cast<PropertySlot::GetValueFunc>"; $secondCastStr = "static_cast<PutPropertySlot::PutValueFunc>"; @@ -320,7 +330,7 @@ sub output() { $i++; } print "};\n\n"; - print "extern const struct HashTable $name =\n"; + print "JS_EXPORT_PRIVATE extern const struct HashTable $name =\n"; print " \{ $packedSize, $compactHashSizeMask, $hasSetter, $nameEntries, 0, $nameIndex \};\n"; print "} // namespace\n"; } diff --git a/create_jit_stubs b/create_jit_stubs deleted file mode 100644 index 404fa36..0000000 --- a/create_jit_stubs +++ /dev/null @@ -1,101 +0,0 @@ -#! /usr/bin/perl -w -# -# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) -# Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public License -# along with this library; see the file COPYING.LIB. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -# Boston, MA 02110-1301, USA. - -use strict; -use File::Basename; -use Getopt::Long; - -my $usage = basename($0) . " --prefix prefix --header header file"; - -my $rtype_template = quotemeta("#rtype#"); -my $op_template = quotemeta("#op#"); - -my $prefix; -my $header; -my $enable_dfg = 0; -my $file; - -my $getOptionsResult = GetOptions( - 'prefix=s' => \$prefix, - 'header=s' => \$header, - 'dfg!' => \$enable_dfg -); - -$file = $ARGV[0]; - -die "$usage\n" unless ($header and $prefix and $file); - -my $stub_template = ""; -my $output_end = ""; -my $stub = ""; - -my $rtype = ""; -my $op = ""; -my $if_counter = 0; -my $dfg_begin = 0; - -print STDERR "Creating JIT stubs for $file \n"; -open(IN, $header) or die "No such file $header"; - -while ( $_ = <IN> ) { - if ( /^$prefix\_BEGIN\((.*)\)/ ) { - $stub = $1; - print $stub . "\n"; - } - if ( /^$prefix\((.*)\)/ ) { - $stub_template .= $1 . "\n"; - } - if ( /^$prefix\_END\((.*)\)/ ) { - $output_end .= $1 . "\n"; - } -} - -close(IN); -open(IN, $file) or die "No such file $file"; - -while ( $_ = <IN> ) { - if ( /^#if (.*)/ ) { - $if_counter++; - if ( $1 eq "ENABLE(DFG_JIT)" ) { - $dfg_begin = $if_counter; - } - } - if ( /^#endif/ ) { - if ( $if_counter == $dfg_begin ) { - $dfg_begin = 0; - } - $if_counter--; - } - if ( /^DEFINE_STUB_FUNCTION\((.*), (.*)\)/ ) { - $stub = $stub_template; - $rtype = quotemeta($1); - $op = quotemeta($2); - $stub =~ s/$rtype_template/$rtype/g; - $stub =~ s/$op_template/$op/g; - $stub =~ s/\\\*/\*/g; - if ( $enable_dfg == 1 || $dfg_begin == 0 ) { - print $stub; - } - } -} - -print $output_end; - -close(IN); diff --git a/create_regex_tables b/create_regex_tables index 7544b75..c6fd6eb 100644 --- a/create_regex_tables +++ b/create_regex_tables @@ -86,15 +86,15 @@ for name, classes in types.items(): # Generate createFunction: function = ""; - function += ("CharacterClass* %sCreate()\n" % name) + function += ("std::unique_ptr<CharacterClass> %sCreate()\n" % name) function += ("{\n") if emitTables and classes["UseTable"]: if "Inverse" in classes: - function += (" CharacterClass* characterClass = new CharacterClass(_%sData, true);\n" % (classes["Inverse"])) + function += (" auto characterClass = std::make_unique<CharacterClass>(_%sData, true);\n" % (classes["Inverse"])) else: - function += (" CharacterClass* characterClass = new CharacterClass(_%sData, false);\n" % (name)) + function += (" auto characterClass = std::make_unique<CharacterClass>(_%sData, false);\n" % (name)) else: - function += (" CharacterClass* characterClass = new CharacterClass;\n") + function += (" auto characterClass = std::make_unique<CharacterClass>();\n") for (min, max) in ranges: if (min == max): if (min > 127): @@ -106,7 +106,7 @@ for name, classes in types.items(): function += (" characterClass->m_rangesUnicode.append(CharacterRange(0x%04x, 0x%04x));\n" % (min, max)) else: function += (" characterClass->m_ranges.append(CharacterRange(0x%02x, 0x%02x));\n" % (min, max)) - function += (" return characterClass;\n") + function += (" return WTF::move(characterClass);\n") function += ("}\n\n") functions += function diff --git a/debugger/Breakpoint.h b/debugger/Breakpoint.h index 60f4fd5..8518ce4 100644 --- a/debugger/Breakpoint.h +++ b/debugger/Breakpoint.h @@ -43,7 +43,7 @@ struct Breakpoint : public DoublyLinkedListNode<Breakpoint> { { } - Breakpoint(SourceID sourceID, unsigned line, unsigned column, String condition, bool autoContinue) + Breakpoint(SourceID sourceID, unsigned line, unsigned column, const String& condition, bool autoContinue) : id(noBreakpointID) , sourceID(sourceID) , line(line) diff --git a/debugger/Debugger.cpp b/debugger/Debugger.cpp index 168d7a3..bc1b57e 100644 --- a/debugger/Debugger.cpp +++ b/debugger/Debugger.cpp @@ -25,7 +25,6 @@ #include "CodeBlock.h" #include "DebuggerCallFrame.h" #include "Error.h" - #include "HeapIterationScope.h" #include "Interpreter.h" #include "JSCJSValueInlines.h" @@ -44,12 +43,14 @@ class Recompiler : public MarkedBlock::VoidFunctor { public: Recompiler(JSC::Debugger*); ~Recompiler(); - void operator()(JSCell*); + IterationStatus operator()(JSCell*); private: typedef HashSet<FunctionExecutable*> FunctionExecutableSet; typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap; + void visit(JSCell*); + JSC::Debugger* m_debugger; FunctionExecutableSet m_functionExecutables; SourceProviderMap m_sourceProviders; @@ -69,7 +70,7 @@ inline Recompiler::~Recompiler() m_debugger->sourceParsed(iter->value, iter->key, -1, String()); } -inline void Recompiler::operator()(JSCell* cell) +inline void Recompiler::visit(JSCell* cell) { if (!cell->inherits(JSFunction::info())) return; @@ -86,19 +87,25 @@ inline void Recompiler::operator()(JSCell* cell) return; ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec(); - executable->clearCodeIfNotCompiling(); - executable->clearUnlinkedCodeForRecompilationIfNotCompiling(); + executable->clearCode(); + executable->clearUnlinkedCodeForRecompilation(); if (m_debugger == function->scope()->globalObject()->debugger()) m_sourceProviders.add(executable->source().provider(), exec); } +inline IterationStatus Recompiler::operator()(JSCell* cell) +{ + visit(cell); + return IterationStatus::Continue; +} + } // namespace namespace JSC { -class DebuggerCallFrameScope { +class DebuggerPausedScope { public: - DebuggerCallFrameScope(Debugger& debugger) + DebuggerPausedScope(Debugger& debugger) : m_debugger(debugger) { ASSERT(!m_debugger.m_currentDebuggerCallFrame); @@ -106,11 +113,11 @@ public: m_debugger.m_currentDebuggerCallFrame = DebuggerCallFrame::create(debugger.m_currentCallFrame); } - ~DebuggerCallFrameScope() + ~DebuggerPausedScope() { if (m_debugger.m_currentDebuggerCallFrame) { m_debugger.m_currentDebuggerCallFrame->invalidate(); - m_debugger.m_currentDebuggerCallFrame = 0; + m_debugger.m_currentDebuggerCallFrame = nullptr; } } @@ -141,7 +148,7 @@ private: template<typename Functor> void Debugger::forEachCodeBlock(Functor& functor) { - m_vm->waitForCompilationsToComplete(); + m_vm->prepareToDiscardCode(); m_vm->heap.forEachCodeBlock(functor); } @@ -160,6 +167,7 @@ Debugger::Debugger(bool isInWorkerThread) , m_lastExecutedLine(UINT_MAX) , m_lastExecutedSourceID(noSourceID) , m_topBreakpointID(noBreakpointID) + , m_pausingBreakpointID(noBreakpointID) { } @@ -206,6 +214,11 @@ void Debugger::detach(JSGlobalObject* globalObject, ReasonForDetach reason) m_vm = nullptr; } +bool Debugger::isAttached(JSGlobalObject* globalObject) +{ + return globalObject->debugger() == this; +} + class Debugger::SetSteppingModeFunctor { public: SetSteppingModeFunctor(Debugger* debugger, SteppingMode mode) @@ -235,7 +248,7 @@ void Debugger::setSteppingMode(SteppingMode mode) if (mode == m_steppingMode || !m_vm) return; - m_vm->waitForCompilationsToComplete(); + m_vm->prepareToDiscardCode(); m_steppingMode = mode; SetSteppingModeFunctor functor(this, mode); @@ -264,7 +277,7 @@ void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, Br unsigned line = breakpoint.line; unsigned column = breakpoint.column; - unsigned startLine = executable->lineNo(); + unsigned startLine = executable->firstLine(); unsigned startColumn = executable->startColumn(); unsigned endLine = executable->lastLine(); unsigned endColumn = executable->endColumn(); @@ -335,11 +348,17 @@ void Debugger::recompileAllJSFunctions(VM* vm) // If JavaScript is running, it's not safe to recompile, since we'll end // up throwing away code that is live on the stack. if (vm->entryScope) { - vm->entryScope->setRecompilationNeeded(true); + auto listener = [] (VM& vm, JSGlobalObject* globalObject) + { + if (Debugger* debugger = globalObject->debugger()) + debugger->recompileAllJSFunctions(&vm); + }; + + vm->entryScope->setEntryScopeDidPopListener(this, listener); return; } - vm->waitForCompilationsToComplete(); + vm->prepareToDiscardCode(); Recompiler recompiler(this); HeapIterationScope iterationScope(vm->heap); @@ -467,7 +486,7 @@ bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Br // so make it looks like the debugger is already paused. TemporaryPausedState pausedState(*this); - JSValue exception; + NakedPtr<Exception> exception; DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame(); JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception); @@ -601,7 +620,8 @@ void Debugger::stepOutOfFunction() if (!m_isPaused) return; - m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrameSkippingVMEntrySentinel() : 0; + VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame; + m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrame(topVMEntryFrame) : 0; notifyDoneProcessingDebuggerEvents(); } @@ -637,7 +657,7 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame) bool pauseNow = m_pauseOnNextStatement; pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame); - DebuggerCallFrameScope debuggerCallFrameScope(*this); + DebuggerPausedScope debuggerPausedScope(*this); intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame); TextPosition position = DebuggerCallFrame::positionForCallFrame(m_currentCallFrame); @@ -653,14 +673,20 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame) m_pauseOnNextStatement = false; if (didHitBreakpoint) { - handleBreakpointHit(breakpoint); + handleBreakpointHit(vmEntryGlobalObject, breakpoint); // Note that the actions can potentially stop the debugger, so we need to check that // we still have a current call frame when we get back. if (breakpoint.autoContinue || !m_currentCallFrame) return; + m_pausingBreakpointID = breakpoint.id; } - handlePause(m_reasonForPause, vmEntryGlobalObject); + { + PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause); + handlePause(vmEntryGlobalObject, m_reasonForPause); + } + + m_pausingBreakpointID = noBreakpointID; if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) { setSteppingMode(SteppingModeDisabled); @@ -668,13 +694,13 @@ void Debugger::pauseIfNeeded(CallFrame* callFrame) } } -void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasHandler) +void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler) { if (m_isPaused) return; PauseReasonDeclaration reason(*this, PausedForException); - if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasHandler)) { + if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) { m_pauseOnNextStatement = true; setSteppingMode(SteppingModeEnabled); } @@ -717,10 +743,13 @@ void Debugger::returnEvent(CallFrame* callFrame) return; // Treat stepping over a return statement like stepping out. - if (m_currentCallFrame == m_pauseOnCallFrame) - m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel(); + if (m_currentCallFrame == m_pauseOnCallFrame) { + VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame; + m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame); + } - m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel(); + VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame; + m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame); } void Debugger::willExecuteProgram(CallFrame* callFrame) @@ -750,11 +779,13 @@ void Debugger::didExecuteProgram(CallFrame* callFrame) if (!m_currentCallFrame) return; if (m_currentCallFrame == m_pauseOnCallFrame) { - m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel(); + VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame; + m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame); if (!m_currentCallFrame) return; } - m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel(); + VMEntryFrame* topVMEntryFrame = m_vm->topVMEntryFrame; + m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame); } void Debugger::didReachBreakpoint(CallFrame* callFrame) @@ -762,7 +793,7 @@ void Debugger::didReachBreakpoint(CallFrame* callFrame) if (m_isPaused) return; - PauseReasonDeclaration reason(*this, PausedForBreakpoint); + PauseReasonDeclaration reason(*this, PausedForDebuggerStatement); m_pauseOnNextStatement = true; setSteppingMode(SteppingModeEnabled); updateCallFrameAndPauseIfNeeded(callFrame); diff --git a/debugger/Debugger.h b/debugger/Debugger.h index 2e8524a..d70f3b7 100644 --- a/debugger/Debugger.h +++ b/debugger/Debugger.h @@ -33,6 +33,8 @@ namespace JSC { +class CodeBlock; +class Exception; class ExecState; class JSGlobalObject; class SourceProvider; @@ -59,12 +61,13 @@ public: bool needsExceptionCallbacks() const { return m_pauseOnExceptionsState != DontPauseOnExceptions; } - void attach(JSGlobalObject*); enum ReasonForDetach { TerminatingDebuggingSession, GlobalObjectIsDestructing }; - virtual void detach(JSGlobalObject*, ReasonForDetach); + void attach(JSGlobalObject*); + void detach(JSGlobalObject*, ReasonForDetach); + bool isAttached(JSGlobalObject*); BreakpointID setBreakpoint(Breakpoint, unsigned& actualLine, unsigned& actualColumn); void removeBreakpoint(BreakpointID); @@ -81,6 +84,20 @@ public: PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; } void setPauseOnExceptionsState(PauseOnExceptionsState); + enum ReasonForPause { + NotPaused, + PausedForException, + PausedAtStatement, + PausedAfterCall, + PausedBeforeReturn, + PausedAtStartOfProgram, + PausedAtEndOfProgram, + PausedForBreakpoint, + PausedForDebuggerStatement, + }; + ReasonForPause reasonForPause() const { return m_reasonForPause; } + BreakpointID pausingBreakpointID() const { return m_pausingBreakpointID; } + void setPauseOnNextStatement(bool); void breakProgram(); void continueProgram(); @@ -88,12 +105,12 @@ public: void stepOverStatement(); void stepOutOfFunction(); - bool isPaused() { return m_isPaused; } + bool isPaused() const { return m_isPaused; } bool isStepping() const { return m_steppingMode == SteppingModeEnabled; } virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0; - void exception(CallFrame*, JSValue exceptionValue, bool hasHandler); + void exception(CallFrame*, JSValue exceptionValue, bool hasCatchHandler); void atStatement(CallFrame*); void callEvent(CallFrame*); void returnEvent(CallFrame*); @@ -107,21 +124,9 @@ public: protected: virtual bool needPauseHandling(JSGlobalObject*) { return false; } - virtual void handleBreakpointHit(const Breakpoint&) { } - virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); } - - enum ReasonForPause { - NotPaused, - PausedForException, - PausedAtStatement, - PausedAfterCall, - PausedBeforeReturn, - PausedAtStartOfProgram, - PausedAtEndOfProgram, - PausedForBreakpoint - }; - - virtual void handlePause(ReasonForPause, JSGlobalObject*) { } + virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { } + virtual void handleExceptionInBreakpointCondition(ExecState*, Exception*) const { } + virtual void handlePause(JSGlobalObject*, ReasonForPause) { } virtual void notifyDoneProcessingDebuggerEvents() { } private: @@ -191,7 +196,7 @@ private: bool m_breakpointsActivated : 1; bool m_hasHandlerForExceptionCallback : 1; bool m_isInWorkerThread : 1; - SteppingMode m_steppingMode : 1; + unsigned m_steppingMode : 1; // SteppingMode ReasonForPause m_reasonForPause; JSValue m_currentException; @@ -201,12 +206,13 @@ private: SourceID m_lastExecutedSourceID; BreakpointID m_topBreakpointID; + BreakpointID m_pausingBreakpointID; BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint; SourceIDToBreakpointsMap m_sourceIDToBreakpoints; RefPtr<JSC::DebuggerCallFrame> m_currentDebuggerCallFrame; - friend class DebuggerCallFrameScope; + friend class DebuggerPausedScope; friend class TemporaryPausedState; friend class LLIntOffsetsExtractor; }; diff --git a/debugger/DebuggerActivation.cpp b/debugger/DebuggerActivation.cpp deleted file mode 100644 index 1340ff7..0000000 --- a/debugger/DebuggerActivation.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2008, 2009 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 "DebuggerActivation.h" - -#include "JSActivation.h" -#include "JSCInlines.h" - -namespace JSC { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DebuggerActivation); - -const ClassInfo DebuggerActivation::s_info = { "DebuggerActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(DebuggerActivation) }; - -DebuggerActivation::DebuggerActivation(VM& vm) - : JSNonFinalObject(vm, vm.debuggerActivationStructure.get()) -{ -} - -void DebuggerActivation::finishCreation(VM& vm, JSObject* activation) -{ - Base::finishCreation(vm); - ASSERT(activation); - ASSERT(activation->isActivationObject()); - m_activation.set(vm, this, jsCast<JSActivation*>(activation)); -} - -void DebuggerActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - - JSObject::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_activation); -} - -String DebuggerActivation::className(const JSObject* object) -{ - const DebuggerActivation* thisObject = jsCast<const DebuggerActivation*>(object); - return thisObject->m_activation->methodTable()->className(thisObject->m_activation.get()); -} - -bool DebuggerActivation::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object); - return thisObject->m_activation->methodTable()->getOwnPropertySlot(thisObject->m_activation.get(), exec, propertyName, slot); -} - -void DebuggerActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) -{ - DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(cell); - thisObject->m_activation->methodTable()->put(thisObject->m_activation.get(), exec, propertyName, value, slot); -} - -bool DebuggerActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(cell); - return thisObject->m_activation->methodTable()->deleteProperty(thisObject->m_activation.get(), exec, propertyName); -} - -void DebuggerActivation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object); - thisObject->m_activation->methodTable()->getPropertyNames(thisObject->m_activation.get(), exec, propertyNames, mode); -} - -bool DebuggerActivation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) -{ - DebuggerActivation* thisObject = jsCast<DebuggerActivation*>(object); - return thisObject->m_activation->methodTable()->defineOwnProperty(thisObject->m_activation.get(), exec, propertyName, descriptor, shouldThrow); -} - -} // namespace JSC diff --git a/debugger/DebuggerCallFrame.cpp b/debugger/DebuggerCallFrame.cpp index 83fb67f..663fc03 100644 --- a/debugger/DebuggerCallFrame.cpp +++ b/debugger/DebuggerCallFrame.cpp @@ -30,12 +30,15 @@ #include "DebuggerCallFrame.h" #include "CodeBlock.h" +#include "DebuggerEvalEnabler.h" +#include "DebuggerScope.h" #include "Interpreter.h" -#include "JSActivation.h" #include "JSFunction.h" +#include "JSLexicalEnvironment.h" #include "JSCInlines.h" #include "Parser.h" #include "StackVisitor.h" +#include "StrongInlines.h" namespace JSC { @@ -55,13 +58,36 @@ private: unsigned m_column; }; +class FindCallerMidStackFunctor { +public: + FindCallerMidStackFunctor(CallFrame* callFrame) + : m_callFrame(callFrame) + , m_callerFrame(nullptr) + { } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + if (visitor->callFrame() == m_callFrame) { + m_callerFrame = visitor->callerFrame(); + return StackVisitor::Done; + } + return StackVisitor::Continue; + } + + CallFrame* getCallerFrame() const { return m_callerFrame; } + +private: + CallFrame* m_callFrame; + CallFrame* m_callerFrame; +}; + DebuggerCallFrame::DebuggerCallFrame(CallFrame* callFrame) : m_callFrame(callFrame) { m_position = positionForCallFrame(m_callFrame); } -PassRefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame() +RefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame() { ASSERT(isValid()); if (!isValid()) @@ -70,9 +96,12 @@ PassRefPtr<DebuggerCallFrame> DebuggerCallFrame::callerFrame() if (m_caller) return m_caller; - CallFrame* callerFrame = m_callFrame->callerFrameSkippingVMEntrySentinel(); + FindCallerMidStackFunctor functor(m_callFrame); + m_callFrame->vm().topCallFrame->iterate(functor); + + CallFrame* callerFrame = functor.getCallerFrame(); if (!callerFrame) - return 0; + return nullptr; m_caller = DebuggerCallFrame::create(callerFrame); return m_caller; @@ -99,27 +128,33 @@ String DebuggerCallFrame::functionName() const ASSERT(isValid()); if (!isValid()) return String(); - JSObject* function = m_callFrame->callee(); + JSFunction* function = jsDynamicCast<JSFunction*>(m_callFrame->callee()); if (!function) return String(); return getCalculatedDisplayName(m_callFrame, function); } -JSScope* DebuggerCallFrame::scope() const +DebuggerScope* DebuggerCallFrame::scope() { ASSERT(isValid()); if (!isValid()) return 0; - CodeBlock* codeBlock = m_callFrame->codeBlock(); - if (codeBlock && codeBlock->needsActivation() && !m_callFrame->hasActivation()) { - JSActivation* activation = JSActivation::create(*codeBlock->vm(), m_callFrame, codeBlock); - m_callFrame->setActivation(activation); - m_callFrame->setScope(activation); + if (!m_scope) { + VM& vm = m_callFrame->vm(); + JSScope* scope; + CodeBlock* codeBlock = m_callFrame->codeBlock(); + if (codeBlock && codeBlock->scopeRegister().isValid()) + scope = m_callFrame->scope(codeBlock->scopeRegister().offset()); + else if (JSCallee* callee = jsDynamicCast<JSCallee*>(m_callFrame->callee())) + scope = callee->scope(); + else + scope = m_callFrame->lexicalGlobalObject(); + + m_scope.set(vm, DebuggerScope::create(vm, scope)); } - - return m_callFrame->scope(); + return m_scope.get(); } DebuggerCallFrame::Type DebuggerCallFrame::type() const @@ -128,7 +163,7 @@ DebuggerCallFrame::Type DebuggerCallFrame::type() const if (!isValid()) return ProgramType; - if (m_callFrame->callee()) + if (jsDynamicCast<JSFunction*>(m_callFrame->callee())) return FunctionType; return ProgramType; @@ -141,7 +176,7 @@ JSValue DebuggerCallFrame::thisValue() const } // Evaluate some JavaScript code in the scope of this frame. -JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception) +JSValue DebuggerCallFrame::evaluate(const String& script, NakedPtr<Exception>& exception) { ASSERT(isValid()); CallFrame* callFrame = m_callFrame; @@ -153,8 +188,11 @@ JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception) if (!callFrame->codeBlock()) return JSValue(); + DebuggerEvalEnabler evalEnabler(callFrame); VM& vm = callFrame->vm(); - EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), callFrame->codeBlock()->isStrictMode()); + auto& codeBlock = *callFrame->codeBlock(); + ThisTDZMode thisTDZMode = codeBlock.unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded; + EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode); if (vm.exception()) { exception = vm.exception(); vm.clearException(); @@ -162,7 +200,7 @@ JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception) } JSValue thisValue = thisValueForCallFrame(callFrame); - JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()); + JSValue result = vm.interpreter->execute(eval, callFrame, thisValue, scope()->jsScope()); if (vm.exception()) { exception = vm.exception(); vm.clearException(); @@ -173,10 +211,13 @@ JSValue DebuggerCallFrame::evaluate(const String& script, JSValue& exception) void DebuggerCallFrame::invalidate() { - m_callFrame = nullptr; - RefPtr<DebuggerCallFrame> frame = m_caller.release(); + RefPtr<DebuggerCallFrame> frame = this; while (frame) { frame->m_callFrame = nullptr; + if (frame->m_scope) { + frame->m_scope->invalidateChain(); + frame->m_scope.clear(); + } frame = frame->m_caller.release(); } } diff --git a/debugger/DebuggerCallFrame.h b/debugger/DebuggerCallFrame.h index ca22569..aa3cca5 100644 --- a/debugger/DebuggerCallFrame.h +++ b/debugger/DebuggerCallFrame.h @@ -29,26 +29,32 @@ #ifndef DebuggerCallFrame_h #define DebuggerCallFrame_h -#include "CallFrame.h" #include "DebuggerPrimitives.h" +#include "Strong.h" +#include <wtf/NakedPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/text/TextPosition.h> namespace JSC { +class DebuggerScope; +class Exception; +class ExecState; +typedef ExecState CallFrame; + class DebuggerCallFrame : public RefCounted<DebuggerCallFrame> { public: enum Type { ProgramType, FunctionType }; - static PassRefPtr<DebuggerCallFrame> create(CallFrame* callFrame) + static Ref<DebuggerCallFrame> create(CallFrame* callFrame) { - return adoptRef(new DebuggerCallFrame(callFrame)); + return adoptRef(*new DebuggerCallFrame(callFrame)); } JS_EXPORT_PRIVATE explicit DebuggerCallFrame(CallFrame*); - JS_EXPORT_PRIVATE PassRefPtr<DebuggerCallFrame> callerFrame(); + JS_EXPORT_PRIVATE RefPtr<DebuggerCallFrame> callerFrame(); ExecState* exec() const { return m_callFrame; } JS_EXPORT_PRIVATE SourceID sourceID() const; @@ -58,11 +64,11 @@ public: JS_EXPORT_PRIVATE const TextPosition& position() const { return m_position; } JS_EXPORT_PRIVATE JSGlobalObject* vmEntryGlobalObject() const; - JS_EXPORT_PRIVATE JSScope* scope() const; + JS_EXPORT_PRIVATE DebuggerScope* scope(); JS_EXPORT_PRIVATE String functionName() const; JS_EXPORT_PRIVATE Type type() const; JS_EXPORT_PRIVATE JSValue thisValue() const; - JSValue evaluate(const String&, JSValue& exception); + JSValue evaluate(const String&, NakedPtr<Exception>&); bool isValid() const { return !!m_callFrame; } JS_EXPORT_PRIVATE void invalidate(); @@ -78,6 +84,9 @@ private: CallFrame* m_callFrame; RefPtr<DebuggerCallFrame> m_caller; TextPosition m_position; + // The DebuggerPausedScope is responsible for calling invalidate() which, + // in turn, will clear this strong ref. + Strong<DebuggerScope> m_scope; }; } // namespace JSC diff --git a/debugger/DebuggerEvalEnabler.h b/debugger/DebuggerEvalEnabler.h new file mode 100644 index 0000000..bb75b1f --- /dev/null +++ b/debugger/DebuggerEvalEnabler.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 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 DebuggerEvalEnabler_h +#define DebuggerEvalEnabler_h + +#include "CallFrame.h" +#include "JSGlobalObject.h" + +namespace JSC { + +class DebuggerEvalEnabler { +public: + explicit DebuggerEvalEnabler(const ExecState* exec) + : m_exec(exec) + , m_evalWasDisabled(false) + { + if (exec) { + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + m_evalWasDisabled = !globalObject->evalEnabled(); + if (m_evalWasDisabled) + globalObject->setEvalEnabled(true, globalObject->evalDisabledErrorMessage()); + } + } + + ~DebuggerEvalEnabler() + { + if (m_evalWasDisabled) { + JSGlobalObject* globalObject = m_exec->lexicalGlobalObject(); + globalObject->setEvalEnabled(false, globalObject->evalDisabledErrorMessage()); + } + } + +private: + const ExecState* m_exec; + bool m_evalWasDisabled; +}; + +} // namespace JSC + +#endif // DebuggerEvalEnabler_h diff --git a/debugger/DebuggerScope.cpp b/debugger/DebuggerScope.cpp new file mode 100644 index 0000000..d53a6a0 --- /dev/null +++ b/debugger/DebuggerScope.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008-2009, 2014 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 "DebuggerScope.h" + +#include "JSLexicalEnvironment.h" +#include "JSCInlines.h" +#include "JSNameScope.h" +#include "JSWithScope.h" + +namespace JSC { + +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DebuggerScope); + +const ClassInfo DebuggerScope::s_info = { "DebuggerScope", &Base::s_info, 0, CREATE_METHOD_TABLE(DebuggerScope) }; + +DebuggerScope::DebuggerScope(VM& vm, JSScope* scope) + : JSNonFinalObject(vm, scope->globalObject()->debuggerScopeStructure()) +{ + ASSERT(scope); + m_scope.set(vm, this, scope); +} + +void DebuggerScope::finishCreation(VM& vm) +{ + Base::finishCreation(vm); +} + +void DebuggerScope::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + DebuggerScope* thisObject = jsCast<DebuggerScope*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + JSObject::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_scope); + visitor.append(&thisObject->m_next); +} + +String DebuggerScope::className(const JSObject* object) +{ + const DebuggerScope* scope = jsCast<const DebuggerScope*>(object); + ASSERT(scope->isValid()); + if (!scope->isValid()) + return String(); + JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); + return thisObject->methodTable()->className(thisObject); +} + +bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + DebuggerScope* scope = jsCast<DebuggerScope*>(object); + ASSERT(scope->isValid()); + if (!scope->isValid()) + return false; + JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); + slot.setThisValue(JSValue(thisObject)); + + // By default, JSObject::getPropertySlot() will look in the DebuggerScope's prototype + // chain and not the wrapped scope, and JSObject::getPropertySlot() cannot be overridden + // to behave differently for the DebuggerScope. + // + // Instead, we'll treat all properties in the wrapped scope and its prototype chain as + // the own properties of the DebuggerScope. This is fine because the WebInspector + // does not presently need to distinguish between what's owned at each level in the + // prototype chain. Hence, we'll invoke getPropertySlot() on the wrapped scope here + // instead of getOwnPropertySlot(). + return thisObject->getPropertySlot(exec, propertyName, slot); +} + +void DebuggerScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + DebuggerScope* scope = jsCast<DebuggerScope*>(cell); + ASSERT(scope->isValid()); + if (!scope->isValid()) + return; + JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); + slot.setThisValue(JSValue(thisObject)); + thisObject->methodTable()->put(thisObject, exec, propertyName, value, slot); +} + +bool DebuggerScope::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) +{ + DebuggerScope* scope = jsCast<DebuggerScope*>(cell); + ASSERT(scope->isValid()); + if (!scope->isValid()) + return false; + JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); + return thisObject->methodTable()->deleteProperty(thisObject, exec, propertyName); +} + +void DebuggerScope::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + DebuggerScope* scope = jsCast<DebuggerScope*>(object); + ASSERT(scope->isValid()); + if (!scope->isValid()) + return; + JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); + thisObject->methodTable()->getPropertyNames(thisObject, exec, propertyNames, mode); +} + +bool DebuggerScope::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) +{ + DebuggerScope* scope = jsCast<DebuggerScope*>(object); + ASSERT(scope->isValid()); + if (!scope->isValid()) + return false; + JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); + return thisObject->methodTable()->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); +} + +DebuggerScope* DebuggerScope::next() +{ + ASSERT(isValid()); + if (!m_next && m_scope->next()) { + VM& vm = *m_scope->vm(); + DebuggerScope* nextScope = create(vm, m_scope->next()); + m_next.set(vm, this, nextScope); + } + return m_next.get(); +} + +void DebuggerScope::invalidateChain() +{ + if (!isValid()) + return; + + DebuggerScope* scope = this; + while (scope) { + DebuggerScope* nextScope = scope->m_next.get(); + scope->m_next.clear(); + scope->m_scope.clear(); // This also marks this scope as invalid. + scope = nextScope; + } +} + +bool DebuggerScope::isCatchScope() const +{ + return m_scope->isCatchScopeObject(); +} + +bool DebuggerScope::isFunctionNameScope() const +{ + return m_scope->isFunctionNameScopeObject(); +} + +bool DebuggerScope::isWithScope() const +{ + return m_scope->isWithScope(); +} + +bool DebuggerScope::isGlobalScope() const +{ + return m_scope->isGlobalObject(); +} + +bool DebuggerScope::isFunctionOrEvalScope() const +{ + // In the current debugger implementation, every function or eval will create an + // lexical environment object. Hence, a lexical environment object implies a + // function or eval scope. + return m_scope->isActivationObject(); +} + +JSValue DebuggerScope::caughtValue() const +{ + ASSERT(isCatchScope()); + return reinterpret_cast<JSNameScope*>(m_scope.get())->value(); +} + +} // namespace JSC diff --git a/debugger/DebuggerScope.h b/debugger/DebuggerScope.h new file mode 100644 index 0000000..4416684 --- /dev/null +++ b/debugger/DebuggerScope.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008-2009, 2014 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 DebuggerScope_h +#define DebuggerScope_h + +#include "JSObject.h" + +namespace JSC { + +class DebuggerCallFrame; +class JSScope; + +class DebuggerScope : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; + + static DebuggerScope* create(VM& vm, JSScope* scope) + { + DebuggerScope* debuggerScope = new (NotNull, allocateCell<DebuggerScope>(vm.heap)) DebuggerScope(vm, scope); + debuggerScope->finishCreation(vm); + return debuggerScope; + } + + static void visitChildren(JSCell*, SlotVisitor&); + static String className(const JSObject*); + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + + DECLARE_EXPORT_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) + { + return Structure::create(vm, globalObject, jsNull(), TypeInfo(ObjectType, StructureFlags), info()); + } + + class iterator { + public: + iterator(DebuggerScope* node) + : m_node(node) + { + } + + DebuggerScope* get() { return m_node; } + iterator& operator++() { m_node = m_node->next(); return *this; } + // postfix ++ intentionally omitted + + bool operator==(const iterator& other) const { return m_node == other.m_node; } + bool operator!=(const iterator& other) const { return m_node != other.m_node; } + + private: + DebuggerScope* m_node; + }; + + iterator begin(); + iterator end(); + DebuggerScope* next(); + + void invalidateChain(); + bool isValid() const { return !!m_scope; } + + bool isCatchScope() const; + bool isFunctionNameScope() const; + bool isWithScope() const; + bool isGlobalScope() const; + bool isFunctionOrEvalScope() const; + + JSValue caughtValue() const; + +private: + JS_EXPORT_PRIVATE DebuggerScope(VM&, JSScope*); + JS_EXPORT_PRIVATE void finishCreation(VM&); + + JSScope* jsScope() const { return m_scope.get(); } + + WriteBarrier<JSScope> m_scope; + WriteBarrier<DebuggerScope> m_next; + + friend class DebuggerCallFrame; +}; + +inline DebuggerScope::iterator DebuggerScope::begin() +{ + return iterator(this); +} + +inline DebuggerScope::iterator DebuggerScope::end() +{ + return iterator(0); +} + +} // namespace JSC + +#endif // DebuggerScope_h diff --git a/dfg/DFGAbstractHeap.cpp b/dfg/DFGAbstractHeap.cpp index 05d90c4..1e11019 100644 --- a/dfg/DFGAbstractHeap.cpp +++ b/dfg/DFGAbstractHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,7 +43,7 @@ void AbstractHeap::Payload::dump(PrintStream& out) const void AbstractHeap::dump(PrintStream& out) const { out.print(kind()); - if (kind() == InvalidAbstractHeap || kind() == World || payload().isTop()) + if (kind() == InvalidAbstractHeap || kind() == World || kind() == Heap || payload().isTop()) return; out.print("(", payload(), ")"); } diff --git a/dfg/DFGAbstractHeap.h b/dfg/DFGAbstractHeap.h index 338c99e..4dafbc1 100644 --- a/dfg/DFGAbstractHeap.h +++ b/dfg/DFGAbstractHeap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,48 +34,45 @@ namespace JSC { namespace DFG { -// Implements a three-level type hierarchy: +// Implements a four-level type hierarchy: // - World is the supertype of all of the things. -// - Kind with TOP payload is the direct subtype of World. -// - Kind with non-TOP payload is the direct subtype of its corresponding TOP Kind. +// - Stack with a TOP payload is a direct subtype of World +// - Stack with a non-TOP payload is a direct subtype of Stack with a TOP payload. +// - Heap is a direct subtype of World. +// - Any other kind with TOP payload is the direct subtype of Heap. +// - Any other kind with non-TOP payload is the direct subtype of the same kind with a TOP payload. #define FOR_EACH_ABSTRACT_HEAP_KIND(macro) \ macro(InvalidAbstractHeap) \ macro(World) \ - macro(Arguments_numArguments) \ - macro(Arguments_overrideLength) \ - macro(Arguments_registers) \ - macro(Arguments_slowArguments) \ - macro(ArrayBuffer_data) \ - macro(Butterfly_arrayBuffer) \ + macro(Stack) \ + macro(Heap) \ macro(Butterfly_publicLength) \ macro(Butterfly_vectorLength) \ - macro(JSArrayBufferView_length) \ - macro(JSArrayBufferView_mode) \ - macro(JSArrayBufferView_vector) \ + macro(GetterSetter_getter) \ + macro(GetterSetter_setter) \ macro(JSCell_structureID) \ macro(JSCell_indexingType) \ macro(JSCell_typeInfoFlags) \ macro(JSCell_typeInfoType) \ - macro(JSFunction_executable) \ - macro(JSFunction_scopeChain) \ macro(JSObject_butterfly) \ - macro(JSVariableObject_registers) \ + macro(JSPropertyNameEnumerator_cachedPropertyNames) \ macro(NamedProperties) \ macro(IndexedInt32Properties) \ macro(IndexedDoubleProperties) \ macro(IndexedContiguousProperties) \ + macro(IndexedArrayStorageProperties) \ macro(ArrayStorageProperties) \ - macro(Variables) \ + macro(DirectArgumentsProperties) \ + macro(ScopeProperties) \ macro(TypedArrayProperties) \ - macro(GCState) \ - macro(BarrierState) \ + macro(HeapObjectCount) /* Used to reflect the fact that some allocations reveal object identity */\ macro(RegExpState) \ macro(InternalState) \ macro(Absolute) \ /* Use this for writes only, to indicate that this may fire watchpoints. Usually this is never directly written but instead we test to see if a node clobbers this; it just so happens that you have to write world to clobber it. */\ macro(Watchpoint_fire) \ - /* Use this for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\ + /* Use these for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\ macro(MiscFields) \ /* Use this for writes only, just to indicate that hoisting the node is invalid. This works because we don't hoist anything that has any side effects at all. */\ macro(SideState) @@ -134,6 +131,11 @@ public: return m_value; } + int32_t value32() const + { + return static_cast<int32_t>(value()); + } + bool operator==(const Payload& other) const { return m_isTop == other.m_isTop @@ -188,7 +190,7 @@ public: AbstractHeap(AbstractHeapKind kind, Payload payload) { - ASSERT(kind != InvalidAbstractHeap && kind != World); + ASSERT(kind != InvalidAbstractHeap && kind != World && kind != Heap && kind != SideState); m_value = encode(kind, payload); } @@ -206,32 +208,49 @@ public: return payloadImpl(); } - bool isDisjoint(const AbstractHeap& other) + AbstractHeap supertype() const { ASSERT(kind() != InvalidAbstractHeap); - ASSERT(other.kind() != InvalidAbstractHeap); - if (kind() == World) - return false; - if (other.kind() == World) - return false; - if (kind() != other.kind()) - return true; - return payload().isDisjoint(other.payload()); + switch (kind()) { + case World: + return AbstractHeap(); + case Heap: + case SideState: + return World; + default: + if (payload().isTop()) { + if (kind() == Stack) + return World; + return Heap; + } + return AbstractHeap(kind()); + } } - bool overlaps(const AbstractHeap& other) + bool isStrictSubtypeOf(const AbstractHeap& other) const { - return !isDisjoint(other); + AbstractHeap current = *this; + while (current.kind() != World) { + current = current.supertype(); + if (current == other) + return true; + } + return false; } - AbstractHeap supertype() const + bool isSubtypeOf(const AbstractHeap& other) const { - ASSERT(kind() != InvalidAbstractHeap); - if (kind() == World) - return AbstractHeap(); - if (payload().isTop()) - return World; - return AbstractHeap(kind()); + return *this == other || isStrictSubtypeOf(other); + } + + bool overlaps(const AbstractHeap& other) const + { + return *this == other || isStrictSubtypeOf(other) || other.isStrictSubtypeOf(*this); + } + + bool isDisjoint(const AbstractHeap& other) const + { + return !overlaps(other); } unsigned hash() const diff --git a/dfg/DFGAbstractInterpreter.h b/dfg/DFGAbstractInterpreter.h index 97582ac..b3ebd68 100644 --- a/dfg/DFGAbstractInterpreter.h +++ b/dfg/DFGAbstractInterpreter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,7 @@ #include "DFGBranchDirection.h" #include "DFGGraph.h" #include "DFGNode.h" +#include "DFGPhiChildren.h" namespace JSC { namespace DFG { @@ -80,22 +81,15 @@ public: // // This is guaranteed to be equivalent to doing: // - // if (state.startExecuting(index)) { - // state.executeEdges(index); - // result = state.executeEffects(index); - // } else - // result = true; + // state.startExecuting() + // state.executeEdges(index); + // result = state.executeEffects(index); bool execute(unsigned indexInBlock); bool execute(Node*); - // Indicate the start of execution of the node. It resets any state in the node, - // that is progressively built up by executeEdges() and executeEffects(). In - // particular, this resets canExit(), so if you want to "know" between calls of - // startExecuting() and executeEdges()/Effects() whether the last run of the - // analysis concluded that the node can exit, you should probably set that - // information aside prior to calling startExecuting(). - bool startExecuting(Node*); - bool startExecuting(unsigned indexInBlock); + // Indicate the start of execution of a node. It resets any state in the node + // that is progressively built up by executeEdges() and executeEffects(). + void startExecuting(); // Abstractly execute the edges of the given node. This runs filterEdgeByUse() // on all edges of the node. You can skip this step, if you have already used @@ -103,10 +97,14 @@ public: void executeEdges(Node*); void executeEdges(unsigned indexInBlock); - ALWAYS_INLINE void filterEdgeByUse(Node* node, Edge& edge) + ALWAYS_INLINE void filterEdgeByUse(Edge& edge) { ASSERT(mayHaveTypeCheck(edge.useKind()) || !needsTypeCheck(edge)); - filterByType(node, edge, typeFilterFor(edge.useKind())); + filterByType(edge, typeFilterFor(edge.useKind())); + } + ALWAYS_INLINE void filterEdgeByUse(Node*, Edge& edge) + { + filterEdgeByUse(edge); } // Abstractly execute the effects of the given node. This changes the abstract @@ -114,6 +112,7 @@ public: bool executeEffects(unsigned indexInBlock); bool executeEffects(unsigned clobberLimit, Node*); + void dump(PrintStream& out) const; void dump(PrintStream& out); template<typename T> @@ -135,7 +134,7 @@ public: } template<typename T> - FiltrationResult filterByValue(T node, JSValue value) + FiltrationResult filterByValue(T node, FrozenValue value) { return filterByValue(forNode(node), value); } @@ -143,12 +142,20 @@ public: FiltrationResult filter(AbstractValue&, const StructureSet&); FiltrationResult filterArrayModes(AbstractValue&, ArrayModes); FiltrationResult filter(AbstractValue&, SpeculatedType); - FiltrationResult filterByValue(AbstractValue&, JSValue); + FiltrationResult filterByValue(AbstractValue&, FrozenValue); + + PhiChildren* phiChildren() { return m_phiChildren.get(); } private: void clobberWorld(const CodeOrigin&, unsigned indexInBlock); - void clobberCapturedVars(const CodeOrigin&); + + template<typename Functor> + void forAllValues(unsigned indexInBlock, Functor&); + void clobberStructures(unsigned indexInBlock); + void observeTransition(unsigned indexInBlock, Structure* from, Structure* to); + void observeTransitions(unsigned indexInBlock, const TransitionVector&); + void setDidClobber(); enum BooleanResult { UnknownBooleanResult, @@ -157,26 +164,25 @@ private: }; BooleanResult booleanResult(Node*, AbstractValue&); - void setBuiltInConstant(Node* node, JSValue value) + void setBuiltInConstant(Node* node, FrozenValue value) { AbstractValue& abstractValue = forNode(node); - abstractValue.set(m_graph, value); - abstractValue.fixTypeForRepresentation(node); + abstractValue.set(m_graph, value, m_state.structureClobberState()); + abstractValue.fixTypeForRepresentation(m_graph, node); } - void setConstant(Node* node, JSValue value) + void setConstant(Node* node, FrozenValue value) { setBuiltInConstant(node, value); m_state.setFoundConstants(true); } - ALWAYS_INLINE void filterByType(Node* node, Edge& edge, SpeculatedType type) + ALWAYS_INLINE void filterByType(Edge& edge, SpeculatedType type) { AbstractValue& value = forNode(edge); - if (!value.isType(type)) { - node->setCanExit(true); + if (!value.isType(type)) edge.setProofStatus(NeedsCheck); - } else + else edge.setProofStatus(IsProved); filter(value, type); @@ -188,6 +194,7 @@ private: CodeBlock* m_codeBlock; Graph& m_graph; AbstractStateType& m_state; + std::unique_ptr<PhiChildren> m_phiChildren; }; } } // namespace JSC::DFG diff --git a/dfg/DFGAbstractInterpreterInlines.h b/dfg/DFGAbstractInterpreterInlines.h index 0e94194..21ee0e4 100644 --- a/dfg/DFGAbstractInterpreterInlines.h +++ b/dfg/DFGAbstractInterpreterInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,9 @@ #include "DFGAbstractInterpreter.h" #include "GetByIdStatus.h" +#include "GetterSetter.h" +#include "JITOperations.h" +#include "MathCommon.h" #include "Operations.h" #include "PutByIdStatus.h" #include "StringObject.h" @@ -42,6 +45,8 @@ AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, Abstra , m_graph(graph) , m_state(state) { + if (m_graph.m_form == SSA) + m_phiChildren = std::make_unique<PhiChildren>(m_graph); } template<typename AbstractStateType> @@ -62,11 +67,17 @@ AbstractInterpreter<AbstractStateType>::booleanResult( } // 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->origin.semantic)) - && structure->typeInfo().type() != StringType) + if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) { + bool allTrue = true; + for (unsigned i = value.m_structure.size(); i--;) { + Structure* structure = value.m_structure[i]; + if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic)) + || structure->typeInfo().type() == StringType) { + allTrue = false; + break; + } + } + if (allTrue) return DefinitelyTrue; } @@ -74,22 +85,12 @@ AbstractInterpreter<AbstractStateType>::booleanResult( } template<typename AbstractStateType> -bool AbstractInterpreter<AbstractStateType>::startExecuting(Node* node) +void AbstractInterpreter<AbstractStateType>::startExecuting() { ASSERT(m_state.block()); ASSERT(m_state.isValid()); m_state.setDidClobber(false); - - node->setCanExit(false); - - return node->shouldGenerate(); -} - -template<typename AbstractStateType> -bool AbstractInterpreter<AbstractStateType>::startExecuting(unsigned indexInBlock) -{ - return startExecuting(m_state.block()->at(indexInBlock)); } template<typename AbstractStateType> @@ -105,9 +106,12 @@ void AbstractInterpreter<AbstractStateType>::executeEdges(unsigned indexInBlock) } template<typename AbstractStateType> -void AbstractInterpreter<AbstractStateType>::verifyEdge(Node*, Edge edge) +void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge) { - RELEASE_ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind()))); + if (!(forNode(edge).m_type & ~typeFilterFor(edge.useKind()))) + return; + + DFG_CRASH(m_graph, node, toCString("Edge verification error: ", node, "->", edge, " was expected to have type ", SpeculationDump(typeFilterFor(edge.useKind())), " but has type ", SpeculationDump(forNode(edge).m_type), " (", forNode(edge).m_type, ")").data()); } template<typename AbstractStateType> @@ -127,51 +131,39 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi switch (node->op()) { case JSConstant: case DoubleConstant: - case Int52Constant: - case WeakJSConstant: - case PhantomArguments: { - setBuiltInConstant(node, m_graph.valueOfJSConstant(node)); + case Int52Constant: { + setBuiltInConstant(node, *node->constant()); break; } case Identity: { forNode(node) = forNode(node->child1()); - break; - } - - case GetArgument: { - ASSERT(m_graph.m_form == SSA); - VariableAccessData* variable = node->variableAccessData(); - AbstractValue& value = m_state.variables().operand(variable->local().offset()); - ASSERT(value.isHeapTop()); - FiltrationResult result = - value.filter(typeFilterFor(useKindFor(variable->flushFormat()))); - ASSERT_UNUSED(result, result == FiltrationOK); - forNode(node) = value; + if (forNode(node).value()) + m_state.setFoundConstants(true); break; } case ExtractOSREntryLocal: { - if (!(node->unlinkedLocal().isArgument()) - && m_graph.m_lazyVars.get(node->unlinkedLocal().toLocal())) { - // This is kind of pessimistic - we could know in some cases that the - // DFG code at the point of the OSR had already initialized the lazy - // variable. But maybe this is fine, since we're inserting OSR - // entrypoints very early in the pipeline - so any lazy initializations - // ought to be hoisted out anyway. - forNode(node).makeBytecodeTop(); - } else - forNode(node).makeHeapTop(); + forNode(node).makeBytecodeTop(); break; } case GetLocal: { VariableAccessData* variableAccessData = node->variableAccessData(); AbstractValue value = m_state.variables().operand(variableAccessData->local().offset()); - if (!variableAccessData->isCaptured()) { - if (value.isClear()) - node->setCanExit(true); - } + // The value in the local should already be checked. + DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat()))); + if (value.value()) + m_state.setFoundConstants(true); + forNode(node) = value; + break; + } + + case GetStack: { + StackAccessData* data = node->stackAccessData(); + AbstractValue value = m_state.variables().operand(data->local); + // The value in the local should already be checked. + DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format))); if (value.value()) m_state.setFoundConstants(true); forNode(node) = value; @@ -187,7 +179,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } case SetLocal: { - m_state.variables().operand(node->local().offset()) = forNode(node->child1()); + m_state.variables().operand(node->local()) = forNode(node->child1()); + break; + } + + case PutStack: { + m_state.variables().operand(node->stackAccessData()->local) = forNode(node->child1()); break; } @@ -198,10 +195,31 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } + case KillStack: { + // This is just a hint telling us that the OSR state of the local is no longer inside the + // flushed data. + break; + } + case SetArgument: - // Assert that the state of arguments has been set. - ASSERT(!m_state.block()->valuesAtHead.operand(node->local()).isClear()); + // Assert that the state of arguments has been set. SetArgument means that someone set + // the argument values out-of-band, and currently this always means setting to a + // non-clear value. + ASSERT(!m_state.variables().operand(node->local()).isClear()); break; + + case LoadVarargs: + case ForwardVarargs: { + // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn + // itself into a straight-line sequence of GetStack/PutStack. + // https://bugs.webkit.org/show_bug.cgi?id=143071 + clobberWorld(node->origin.semantic, clobberLimit); + LoadVarargsData* data = node->loadVarargsData(); + m_state.variables().operand(data->count).setType(SpecInt32); + for (unsigned i = data->limit - 1; i--;) + m_state.variables().operand(data->start.offset() + i).makeHeapTop(); + break; + } case BitAnd: case BitOr: @@ -239,6 +257,14 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } break; } + + if (node->op() == BitAnd + && (isBoolInt32Speculation(forNode(node->child1()).m_type) || + isBoolInt32Speculation(forNode(node->child2()).m_type))) { + forNode(node).setType(SpecBoolInt32); + break; + } + forNode(node).setType(SpecInt32); break; } @@ -262,7 +288,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - node->setCanExit(true); break; } @@ -272,7 +297,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi if (concreteValue.isBoolean()) setConstant(node, jsNumber(concreteValue.asBoolean())); else - setConstant(node, concreteValue); + setConstant(node, *m_graph.freeze(concreteValue)); break; } AbstractValue& value = forNode(node); @@ -280,7 +305,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean)) m_state.setFoundConstants(true); if (value.m_type & SpecBoolean) { - value.merge(SpecInt32); + value.merge(SpecBoolInt32); value.filter(~SpecBoolean); } break; @@ -296,7 +321,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } } - node->setCanExit(true); forNode(node).setType(SpecInt32); break; } @@ -321,6 +345,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } + if (isBooleanSpeculation(forNode(node->child1()).m_type)) { + forNode(node).setType(SpecBoolInt32); + break; + } + forNode(node).setType(SpecInt32); break; } @@ -331,8 +360,32 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi setConstant(node, jsDoubleNumber(child.asNumber())); break; } - forNode(node).setType(forNode(node->child1()).m_type); - forNode(node).fixTypeForRepresentation(node); + + SpeculatedType type = forNode(node->child1()).m_type; + switch (node->child1().useKind()) { + case NotCellUse: { + if (type & SpecOther) { + type &= ~SpecOther; + type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN. + } + if (type & SpecBoolean) { + type &= ~SpecBoolean; + type |= SpecBoolInt32; // True becomes 1, false becomes 0. + } + type &= SpecBytecodeNumber; + break; + } + + case Int52RepUse: + case NumberUse: + case RealNumberUse: + break; + + default: + RELEASE_ASSERT_NOT_REACHED(); + } + forNode(node).setType(type); + forNode(node).fixTypeForRepresentation(m_graph, node); break; } @@ -354,15 +407,15 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } - forNode(node).setType(forNode(node->child1()).m_type & ~SpecDoubleImpureNaN); - forNode(node).fixTypeForRepresentation(node); + forNode(node).setType(m_graph, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN); + forNode(node).fixTypeForRepresentation(m_graph, node); break; } case ValueAdd: { ASSERT(node->binaryUseKind() == UntypedUse); clobberWorld(node->origin.semantic, clobberLimit); - forNode(node).setType(SpecString | SpecBytecodeNumber); + forNode(node).setType(m_graph, SpecString | SpecBytecodeNumber); break; } @@ -383,8 +436,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - if (shouldCheckOverflow(node->arithMode())) - node->setCanExit(true); break; case Int52RepUse: if (left && right && left.isMachineInt() && right.isMachineInt()) { @@ -395,9 +446,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecMachineInt); - if (!forNode(node->child1()).isType(SpecInt32) - || !forNode(node->child2()).isType(SpecInt32)) - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -414,9 +462,19 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } break; } - + + case ArithClz32: { + JSValue operand = forNode(node->child1()).value(); + if (operand && operand.isNumber()) { + uint32_t value = toUInt32(operand.asNumber()); + setConstant(node, jsNumber(clz32(value))); + break; + } + forNode(node).setType(SpecInt32); + break; + } + case MakeRope: { - node->setCanExit(true); forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get()); break; } @@ -438,8 +496,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - if (shouldCheckOverflow(node->arithMode())) - node->setCanExit(true); break; case Int52RepUse: if (left && right && left.isMachineInt() && right.isMachineInt()) { @@ -450,9 +506,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecMachineInt); - if (!forNode(node->child1()).isType(SpecInt32) - || !forNode(node->child2()).isType(SpecInt32)) - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -491,8 +544,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - if (shouldCheckOverflow(node->arithMode())) - node->setCanExit(true); break; case Int52RepUse: if (child && child.isMachineInt()) { @@ -508,10 +559,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecMachineInt); - if (m_state.forNode(node->child1()).couldBeType(SpecInt52)) - node->setCanExit(true); - if (shouldCheckNegativeZero(node->arithMode())) - node->setCanExit(true); break; case DoubleRepUse: if (child && child.isNumber()) { @@ -549,8 +596,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - if (shouldCheckOverflow(node->arithMode())) - node->setCanExit(true); break; case Int52RepUse: if (left && right && left.isMachineInt() && right.isMachineInt()) { @@ -564,7 +609,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecMachineInt); - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -600,7 +644,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -636,7 +679,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -664,7 +706,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } forNode(node).setType(SpecInt32); - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -694,7 +735,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } forNode(node).setType(SpecInt32); - node->setCanExit(true); break; case DoubleRepUse: if (left && right && left.isNumber() && right.isNumber()) { @@ -726,11 +766,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } } forNode(node).setType(SpecInt32); - node->setCanExit(true); break; case DoubleRepUse: if (child && child.isNumber()) { - setConstant(node, jsDoubleNumber(child.asNumber())); + setConstant(node, jsDoubleNumber(fabs(child.asNumber()))); break; } forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type)); @@ -741,6 +780,54 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } break; } + + case ArithPow: { + JSValue childY = forNode(node->child2()).value(); + if (childY && childY.isNumber()) { + if (!childY.asNumber()) { + setConstant(node, jsDoubleNumber(1)); + break; + } + + JSValue childX = forNode(node->child1()).value(); + if (childX && childX.isNumber()) { + setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber()))); + break; + } + } + forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type)); + break; + } + + case ArithRound: { + JSValue operand = forNode(node->child1()).value(); + if (operand && operand.isNumber()) { + double roundedValue = jsRound(operand.asNumber()); + + if (producesInteger(node->arithRoundingMode())) { + int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue); + if (roundedValueAsInt32 == roundedValue) { + if (shouldCheckNegativeZero(node->arithRoundingMode())) { + if (roundedValueAsInt32 || !std::signbit(roundedValue)) { + setConstant(node, jsNumber(roundedValueAsInt32)); + break; + } + } else { + setConstant(node, jsNumber(roundedValueAsInt32)); + break; + } + } + } else { + setConstant(node, jsDoubleNumber(roundedValue)); + break; + } + } + if (producesInteger(node->arithRoundingMode())) + forNode(node).setType(SpecInt32); + else + forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type)); + break; + } case ArithSqrt: { JSValue child = forNode(node->child1()).value(); @@ -758,7 +845,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi setConstant(node, jsDoubleNumber(static_cast<float>(child.asNumber()))); break; } - forNode(node).setType(typeOfDoubleFRound(forNode(node->child1()).m_type)); + forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type)); break; } @@ -781,6 +868,16 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type)); break; } + + case ArithLog: { + JSValue child = forNode(node->child1()).value(); + if (child && child.isNumber()) { + setConstant(node, jsDoubleNumber(log(child.asNumber()))); + break; + } + forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type)); + break; + } case LogicalNot: { switch (booleanResult(node, forNode(node->child1()))) { @@ -791,20 +888,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi setConstant(node, jsBoolean(true)); break; default: - switch (node->child1().useKind()) { - case BooleanUse: - case Int32Use: - case DoubleRepUse: - case UntypedUse: - case StringUse: - break; - case ObjectOrOtherUse: - node->setCanExit(true); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } forNode(node).setType(SpecBoolean); break; } @@ -816,35 +899,59 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi case IsNumber: case IsString: case IsObject: + case IsObjectOrNull: case IsFunction: { - node->setCanExit( - node->op() == IsUndefined - && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)); - JSValue child = forNode(node->child1()).value(); - if (child) { + AbstractValue child = forNode(node->child1()); + if (child.value()) { bool constantWasSet = true; switch (node->op()) { case IsUndefined: setConstant(node, jsBoolean( - child.isCell() - ? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic)) - : child.isUndefined())); + child.value().isCell() + ? child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic)) + : child.value().isUndefined())); break; case IsBoolean: - setConstant(node, jsBoolean(child.isBoolean())); + setConstant(node, jsBoolean(child.value().isBoolean())); break; case IsNumber: - setConstant(node, jsBoolean(child.isNumber())); + setConstant(node, jsBoolean(child.value().isNumber())); break; case IsString: - setConstant(node, jsBoolean(isJSString(child))); + setConstant(node, jsBoolean(isJSString(child.value()))); break; case IsObject: - if (child.isNull() || !child.isObject()) { - setConstant(node, jsBoolean(child.isNull())); - break; - } - constantWasSet = false; + setConstant(node, jsBoolean(child.value().isObject())); + break; + case IsObjectOrNull: + if (child.value().isObject()) { + JSObject* object = asObject(child.value()); + if (object->type() == JSFunctionType) + setConstant(node, jsBoolean(false)); + else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData)) + setConstant(node, jsBoolean(!child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic)))); + else { + // FIXME: This could just call getCallData. + // https://bugs.webkit.org/show_bug.cgi?id=144457 + constantWasSet = false; + } + } else + setConstant(node, jsBoolean(child.value().isNull())); + break; + case IsFunction: + if (child.value().isObject()) { + JSObject* object = asObject(child.value()); + if (object->type() == JSFunctionType) + setConstant(node, jsBoolean(true)); + else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData)) + setConstant(node, jsBoolean(false)); + else { + // FIXME: This could just call getCallData. + // https://bugs.webkit.org/show_bug.cgi?id=144457 + constantWasSet = false; + } + } else + setConstant(node, jsBoolean(false)); break; default: constantWasSet = false; @@ -853,7 +960,131 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi if (constantWasSet) break; } - + + // FIXME: This code should really use AbstractValue::isType() and + // AbstractValue::couldBeType(). + // https://bugs.webkit.org/show_bug.cgi?id=146870 + + bool constantWasSet = false; + switch (node->op()) { + case IsUndefined: + // FIXME: Use the masquerades-as-undefined watchpoint thingy. + // https://bugs.webkit.org/show_bug.cgi?id=144456 + + if (!(child.m_type & (SpecOther | SpecObjectOther))) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + + break; + case IsBoolean: + if (!(child.m_type & ~SpecBoolean)) { + setConstant(node, jsBoolean(true)); + constantWasSet = true; + break; + } + + if (!(child.m_type & SpecBoolean)) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + + break; + case IsNumber: + if (!(child.m_type & ~SpecFullNumber)) { + setConstant(node, jsBoolean(true)); + constantWasSet = true; + break; + } + + if (!(child.m_type & SpecFullNumber)) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + + break; + case IsString: + if (!(child.m_type & ~SpecString)) { + setConstant(node, jsBoolean(true)); + constantWasSet = true; + break; + } + + if (!(child.m_type & SpecString)) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + + break; + case IsObject: + if (!(child.m_type & ~SpecObject)) { + setConstant(node, jsBoolean(true)); + constantWasSet = true; + break; + } + + if (!(child.m_type & SpecObject)) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + + break; + case IsObjectOrNull: + // FIXME: Use the masquerades-as-undefined watchpoint thingy. + // https://bugs.webkit.org/show_bug.cgi?id=144456 + + // These expressions are complicated to parse. A helpful way to parse this is that + // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a + // disjoint set from S". Things like "T - S" means that, provided that S is a + // subset of T, it's the "set of all things in T but not in S". Things like "T | S" + // mean the "union of T and S". + + // Is the child's type an object that isn't an other-object (i.e. object that could + // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold + // this to true. + if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) { + setConstant(node, jsBoolean(true)); + constantWasSet = true; + break; + } + + // Is the child's type definitely not either of: an object that isn't a function, + // or either undefined or null? Then: we should fold this to false. This means + // for example that if it's any non-function object, including those that have + // masquerades-as-undefined traps, then we don't fold. It also means we won't fold + // if it's undefined-or-null, since the type bits don't distinguish between + // undefined (which should fold to false) and null (which should fold to true). + if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + + break; + case IsFunction: + if (!(child.m_type & ~SpecFunction)) { + setConstant(node, jsBoolean(true)); + constantWasSet = true; + break; + } + + if (!(child.m_type & (SpecFunction | SpecObjectOther))) { + setConstant(node, jsBoolean(false)); + constantWasSet = true; + break; + } + break; + default: + break; + } + if (constantWasSet) + break; + forNode(node).setType(SpecBoolean); break; } @@ -864,47 +1095,43 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi AbstractValue& abstractChild = forNode(node->child1()); if (child) { JSValue typeString = jsTypeStringForValue(*vm, m_codeBlock->globalObjectFor(node->origin.semantic), child); - setConstant(node, typeString); + setConstant(node, *m_graph.freeze(typeString)); break; } if (isFullNumberSpeculation(abstractChild.m_type)) { - setConstant(node, vm->smallStrings.numberString()); + setConstant(node, *m_graph.freeze(vm->smallStrings.numberString())); break; } if (isStringSpeculation(abstractChild.m_type)) { - setConstant(node, vm->smallStrings.stringString()); + setConstant(node, *m_graph.freeze(vm->smallStrings.stringString())); break; } - - if (isFinalObjectSpeculation(abstractChild.m_type) || isArraySpeculation(abstractChild.m_type) || isArgumentsSpeculation(abstractChild.m_type)) { - setConstant(node, vm->smallStrings.objectString()); + + // FIXME: We could use the masquerades-as-undefined watchpoint here. + // https://bugs.webkit.org/show_bug.cgi?id=144456 + if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther))) { + setConstant(node, *m_graph.freeze(vm->smallStrings.objectString())); break; } if (isFunctionSpeculation(abstractChild.m_type)) { - setConstant(node, vm->smallStrings.functionString()); + setConstant(node, *m_graph.freeze(vm->smallStrings.functionString())); break; } if (isBooleanSpeculation(abstractChild.m_type)) { - setConstant(node, vm->smallStrings.booleanString()); + setConstant(node, *m_graph.freeze(vm->smallStrings.booleanString())); break; } - switch (node->child1().useKind()) { - case StringUse: - case CellUse: - node->setCanExit(true); - break; - case UntypedUse: - break; - default: - RELEASE_ASSERT_NOT_REACHED(); + if (isSymbolSpeculation(abstractChild.m_type)) { + setConstant(node, *m_graph.freeze(vm->smallStrings.symbolString())); break; } - forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get()); + + forNode(node).setType(m_graph, SpecStringIdent); break; } @@ -963,14 +1190,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } forNode(node).setType(SpecBoolean); - - // This is overly conservative. But the only thing this prevents is store elimination, - // and how likely is it, really, that you'll have redundant stores across a comparison - // operation? Comparison operations are typically at the end of basic blocks, so - // unless we have global store elimination (super unlikely given how unprofitable that - // optimization is to begin with), you aren't going to be wanting to store eliminate - // across an equality op. - node->setCanExit(true); break; } @@ -1003,26 +1222,22 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } forNode(node).setType(SpecBoolean); - node->setCanExit(true); // This is overly conservative. break; } case StringCharCodeAt: - node->setCanExit(true); forNode(node).setType(SpecInt32); break; case StringFromCharCode: - forNode(node).setType(SpecString); + forNode(node).setType(m_graph, SpecString); break; case StringCharAt: - node->setCanExit(true); forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get()); break; case GetByVal: { - node->setCanExit(true); switch (node->arrayMode().type()) { case Array::SelectUsingPredictions: case Array::Unprofiled: @@ -1053,7 +1268,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } else forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get()); break; - case Array::Arguments: + case Array::DirectArguments: + case Array::ScopedArguments: forNode(node).makeHeapTop(); break; case Array::Int32: @@ -1121,7 +1337,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi case PutByValDirect: case PutByVal: case PutByValAlias: { - node->setCanExit(true); switch (node->arrayMode().modeForPut().type()) { case Array::ForceExit: m_state.setIsValid(false); @@ -1153,16 +1368,59 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } case ArrayPush: - node->setCanExit(true); clobberWorld(node->origin.semantic, clobberLimit); forNode(node).setType(SpecBytecodeNumber); break; case ArrayPop: - node->setCanExit(true); clobberWorld(node->origin.semantic, clobberLimit); forNode(node).makeHeapTop(); break; + + case GetMyArgumentByVal: { + JSValue index = forNode(node->child2()).m_value; + InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame; + + if (index && index.isInt32()) { + // This pretends to return TOP for accesses that are actually proven out-of-bounds because + // that's the conservative thing to do. Otherwise we'd need to write more code to mark such + // paths as unreachable, and it's almost certainly not worth the effort. + + if (inlineCallFrame) { + if (index.asUInt32() < inlineCallFrame->arguments.size() - 1) { + forNode(node) = m_state.variables().operand( + virtualRegisterForArgument(index.asInt32() + 1) + inlineCallFrame->stackOffset); + m_state.setFoundConstants(true); + break; + } + } else { + if (index.asUInt32() < m_state.variables().numberOfArguments() - 1) { + forNode(node) = m_state.variables().argument(index.asInt32() + 1); + m_state.setFoundConstants(true); + break; + } + } + } + + if (inlineCallFrame) { + // We have a bound on the types even though it's random access. Take advantage of this. + + AbstractValue result; + for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;) { + result.merge( + m_state.variables().operand( + virtualRegisterForArgument(i) + inlineCallFrame->stackOffset)); + } + + if (result.value()) + m_state.setFoundConstants(true); + forNode(node) = result; + break; + } + + forNode(node).makeHeapTop(); + break; + } case RegExpExec: forNode(node).makeHeapTop(); @@ -1190,7 +1448,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi // constant propagation, but we can do better: // We can specialize the source variable's value on each direction of // the branch. - node->setCanExit(true); // This is overly conservative. m_state.setBranchDirection(TakeBoth); break; } @@ -1208,7 +1465,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi case Throw: case ThrowReferenceError: m_state.setIsValid(false); - node->setCanExit(true); break; case ToPrimitive: { @@ -1225,7 +1481,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } - if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString))) { + if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) { m_state.setFoundConstants(true); forNode(node) = forNode(node->child1()); break; @@ -1233,11 +1489,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi clobberWorld(node->origin.semantic, clobberLimit); - forNode(node).setType((SpecHeapTop & ~SpecCell) | SpecString); + forNode(node).setType(m_graph, (SpecHeapTop & ~SpecCell) | SpecString | SpecSymbol); break; } - case ToString: { + case ToString: + case CallStringConstructor: { switch (node->child1().useKind()) { case StringObjectUse: // This also filters that the StringObject has the primordial StringObject @@ -1245,10 +1502,8 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi filter( node->child1(), m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()); - node->setCanExit(true); // We could be more precise but it's likely not worth it. break; case StringOrStringObjectUse: - node->setCanExit(true); // We could be more precise but it's likely not worth it. break; case CellUse: case UntypedUse: @@ -1269,25 +1524,19 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } case NewArray: - node->setCanExit(true); forNode(node).set( m_graph, m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); - m_state.setHaveStructures(true); break; case NewArrayBuffer: - node->setCanExit(true); forNode(node).set( m_graph, m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); - m_state.setHaveStructures(true); break; case NewArrayWithSize: - node->setCanExit(true); - forNode(node).setType(SpecArray); - m_state.setHaveStructures(true); + forNode(node).setType(m_graph, SpecArray); break; case NewTypedArray: @@ -1305,12 +1554,10 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi m_graph, m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure( node->typedArrayType())); - m_state.setHaveStructures(true); break; case NewRegexp: forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure()); - m_state.setHaveStructures(true); break; case ToThis: { @@ -1327,214 +1574,214 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } case CreateThis: { - forNode(node).setType(SpecFinalObject); + // FIXME: We can fold this to NewObject if the incoming callee is a constant. + forNode(node).setType(m_graph, SpecFinalObject); break; } - case AllocationProfileWatchpoint: - node->setCanExit(true); - break; - case NewObject: ASSERT(node->structure()); forNode(node).set(m_graph, node->structure()); - m_state.setHaveStructures(true); break; + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case BottomValue: + m_state.setDidClobber(true); // Prevent constant folding. + // This claims to return bottom. + break; + + case PutHint: + break; + + case MaterializeNewObject: { + StructureSet set; + + m_phiChildren->forAllTransitiveIncomingValues( + m_graph.varArgChild(node, 0).node(), + [&] (Node* incoming) { + set.add(incoming->castConstant<Structure*>()); + }); + + forNode(node).set(m_graph, set); + break; + } + case CreateActivation: + case MaterializeCreateActivation: forNode(node).set( m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure()); - m_state.setHaveStructures(true); break; - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: - break; - - case CreateArguments: - forNode(node) = forNode(node->child1()); - forNode(node).filter(~SpecEmpty); - forNode(node).merge(SpecArguments); + case CreateDirectArguments: + forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure()); break; - case TearOffActivation: - case TearOffArguments: - // Does nothing that is user-visible. - break; - - case CheckArgumentsNotCreated: - if (isEmptySpeculation( - m_state.variables().operand( - m_graph.argumentsRegisterFor(node->origin.semantic).offset()).m_type)) - m_state.setFoundConstants(true); - else - node->setCanExit(true); - break; - - case GetMyArgumentsLength: - // We know that this executable does not escape its arguments, so we can optimize - // the arguments a bit. Note that this is not sufficient to force constant folding - // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation. - // We perform further optimizations on this later on. - if (node->origin.semantic.inlineCallFrame) { - forNode(node).set( - m_graph, jsNumber(node->origin.semantic.inlineCallFrame->arguments.size() - 1)); - } else - forNode(node).setType(SpecInt32); - node->setCanExit( - !isEmptySpeculation( - m_state.variables().operand( - m_graph.argumentsRegisterFor(node->origin.semantic)).m_type)); + case CreateScopedArguments: + forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()); break; - case GetMyArgumentsLengthSafe: - // This potentially clobbers all structures if the arguments object had a getter - // installed on the length property. - clobberWorld(node->origin.semantic, clobberLimit); - // We currently make no guarantee about what this returns because it does not - // speculate that the length property is actually a length. - forNode(node).makeHeapTop(); + case CreateClonedArguments: + forNode(node).setType(m_graph, SpecObjectOther); break; - case GetMyArgumentByVal: - node->setCanExit(true); - // We know that this executable does not escape its arguments, so we can optimize - // the arguments a bit. Note that this ends up being further optimized by the - // ArgumentsSimplificationPhase. - forNode(node).makeHeapTop(); + case NewFunction: + forNode(node).set( + m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure()); break; - case GetMyArgumentByValSafe: - node->setCanExit(true); - // This potentially clobbers all structures if the property we're accessing has - // a getter. We don't speculate against this. - clobberWorld(node->origin.semantic, clobberLimit); - // And the result is unknown. - forNode(node).makeHeapTop(); + case GetCallee: + if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_codeBlock->ownerExecutable())) { + InferredValue* singleton = executable->singletonFunction(); + if (JSValue value = singleton->inferredValue()) { + m_graph.watchpoints().addLazily(singleton); + JSFunction* function = jsCast<JSFunction*>(value); + setConstant(node, *m_graph.freeze(function)); + break; + } + } + forNode(node).setType(m_graph, SpecFunction); break; - case NewFunction: { - AbstractValue& value = forNode(node); - value = forNode(node->child1()); + case GetArgumentCount: + forNode(node).setType(SpecInt32); + break; - if (!(value.m_type & SpecEmpty)) { - m_state.setFoundConstants(true); - break; + case GetGetter: { + JSValue base = forNode(node->child1()).m_value; + if (base) { + GetterSetter* getterSetter = jsCast<GetterSetter*>(base); + if (!getterSetter->isGetterNull()) { + setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently())); + break; + } } - - value.setType((value.m_type & ~SpecEmpty) | SpecFunction); + + forNode(node).setType(m_graph, SpecObject); break; } - - case NewFunctionExpression: - case NewFunctionNoCheck: - forNode(node).set( - m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure()); - m_state.setHaveStructures(true); - break; - case GetCallee: - forNode(node).setType(SpecFunction); + case GetSetter: { + JSValue base = forNode(node->child1()).m_value; + if (base) { + GetterSetter* getterSetter = jsCast<GetterSetter*>(base); + if (!getterSetter->isSetterNull()) { + setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently())); + break; + } + } + + forNode(node).setType(m_graph, SpecObject); break; + } - case GetScope: // FIXME: We could get rid of these if we know that the JSFunction is a constant. https://bugs.webkit.org/show_bug.cgi?id=106202 - case GetMyScope: - case SkipTopScope: - forNode(node).setType(SpecObjectOther); + case GetScope: + if (JSValue base = forNode(node->child1()).m_value) { + if (JSFunction* function = jsDynamicCast<JSFunction*>(base)) { + setConstant(node, *m_graph.freeze(function->scope())); + break; + } + } + forNode(node).setType(m_graph, SpecObjectOther); break; case SkipScope: { JSValue child = forNode(node->child1()).value(); if (child) { - setConstant(node, JSValue(jsCast<JSScope*>(child.asCell())->next())); + setConstant(node, *m_graph.freeze(JSValue(jsCast<JSScope*>(child.asCell())->next()))); break; } - forNode(node).setType(SpecObjectOther); + forNode(node).setType(m_graph, SpecObjectOther); break; } - case GetClosureRegisters: - forNode(node).clear(); // The result is not a JS value. - break; - case GetClosureVar: + if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) { + setConstant(node, *m_graph.freeze(value)); + break; + } forNode(node).makeHeapTop(); break; case PutClosureVar: - clobberCapturedVars(node->origin.semantic); + break; + + case GetFromArguments: + forNode(node).makeHeapTop(); + break; + + case PutToArguments: break; case GetById: - case GetByIdFlush: - node->setCanExit(true); + case GetByIdFlush: { if (!node->prediction()) { m_state.setIsValid(false); break; } - if (isCellSpeculation(node->child1()->prediction())) { - if (Structure* structure = forNode(node->child1()).bestProvenStructure()) { - GetByIdStatus status = GetByIdStatus::computeFor( - m_graph.m_vm, structure, - m_graph.identifiers()[node->identifierNumber()]); - if (status.isSimple() && status.numVariants() == 1) { - // Assert things that we can't handle and that the computeFor() method - // above won't be able to return. - ASSERT(status[0].structureSet().size() == 1); - ASSERT(!status[0].chain()); - - if (status[0].specificValue()) - setConstant(node, status[0].specificValue()); - else - forNode(node).makeHeapTop(); - filter(node->child1(), status[0].structureSet()); + + AbstractValue& value = forNode(node->child1()); + if (!value.m_structure.isTop() && !value.m_structure.isClobbered() + && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) { + GetByIdStatus status = GetByIdStatus::computeFor( + value.m_structure.set(), m_graph.identifiers()[node->identifierNumber()]); + if (status.isSimple()) { + // Figure out what the result is going to be - is it TOP, a constant, or maybe + // something more subtle? + AbstractValue result; + for (unsigned i = status.numVariants(); i--;) { + DFG_ASSERT(m_graph, node, !status[i].alternateBase()); + JSValue constantResult = + m_graph.tryGetConstantProperty(value, status[i].offset()); + if (!constantResult) { + result.makeHeapTop(); + break; + } - m_state.setFoundConstants(true); - m_state.setHaveStructures(true); - break; + AbstractValue thisResult; + thisResult.set( + m_graph, *m_graph.freeze(constantResult), + m_state.structureClobberState()); + result.merge(thisResult); } + if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode)) + m_state.setFoundConstants(true); + forNode(node) = result; + break; } } + clobberWorld(node->origin.semantic, clobberLimit); forNode(node).makeHeapTop(); break; + } - case GetArrayLength: - node->setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough. + case GetArrayLength: { + JSArrayBufferView* view = m_graph.tryGetFoldableView( + forNode(node->child1()).m_value, node->arrayMode()); + if (view) { + setConstant(node, jsNumber(view->length())); + break; + } forNode(node).setType(SpecInt32); break; - - case CheckExecutable: { - // FIXME: We could track executables in AbstractValue, which would allow us to get rid of these checks - // more thoroughly. https://bugs.webkit.org/show_bug.cgi?id=106200 - // FIXME: We could eliminate these entirely if we know the exact value that flows into this. - // https://bugs.webkit.org/show_bug.cgi?id=106201 - node->setCanExit(true); - break; } - + case CheckStructure: { - // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes). AbstractValue& value = forNode(node->child1()); ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this. StructureSet& set = node->structureSet(); - - if (value.m_currentKnownStructure.isSubsetOf(set)) { - m_state.setFoundConstants(true); - break; - } - - node->setCanExit(true); - m_state.setHaveStructures(true); - - // If this structure check is attempting to prove knowledge already held in - // the futurePossibleStructure set then the constant folding phase should - // turn this into a watchpoint instead. - if (value.m_futurePossibleStructure.isSubsetOf(set) - && value.m_futurePossibleStructure.hasSingleton()) { + + // It's interesting that we could have proven that the object has a larger structure set + // that includes the set we're testing. In that case we could make the structure check + // more efficient. We currently don't. + + if (value.m_structure.isSubsetOf(set)) { m_state.setFoundConstants(true); - filter(value, value.m_futurePossibleStructure.singleton()); break; } @@ -1542,21 +1789,59 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } - case StructureTransitionWatchpoint: { + case CheckStructureImmediate: { + // FIXME: This currently can only reason about one structure at a time. + // https://bugs.webkit.org/show_bug.cgi?id=136988 + AbstractValue& value = forNode(node->child1()); - - filter(value, node->structure()); - m_state.setHaveStructures(true); - node->setCanExit(true); + StructureSet& set = node->structureSet(); + + if (value.value()) { + if (Structure* structure = jsDynamicCast<Structure*>(value.value())) { + if (set.contains(structure)) { + m_state.setFoundConstants(true); + break; + } + } + m_state.setIsValid(false); + break; + } + + if (m_phiChildren) { + bool allGood = true; + m_phiChildren->forAllTransitiveIncomingValues( + node, + [&] (Node* incoming) { + if (Structure* structure = incoming->dynamicCastConstant<Structure*>()) { + if (set.contains(structure)) + return; + } + allGood = false; + }); + if (allGood) { + m_state.setFoundConstants(true); + break; + } + } + + if (Structure* structure = set.onlyStructure()) { + filterByValue(node->child1(), *m_graph.freeze(structure)); + break; + } + + // Aw shucks, we can't do anything! break; } - + case PutStructure: - case PhantomPutStructure: - if (!forNode(node->child1()).m_currentKnownStructure.isClear()) { - clobberStructures(clobberLimit); - forNode(node->child1()).set(m_graph, node->structureTransitionData().newStructure); - m_state.setHaveStructures(true); + if (!forNode(node->child1()).m_structure.isClear()) { + if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next) + m_state.setFoundConstants(true); + else { + observeTransition( + clobberLimit, node->transition()->previous, node->transition()->next); + forNode(node->child1()).changeStructure(m_graph, node->transition()->next); + } } break; case GetButterfly: @@ -1569,7 +1854,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi m_state.setFoundConstants(true); break; } - node->setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here. switch (node->arrayMode().type()) { case Array::String: filter(node->child1(), SpecString); @@ -1580,8 +1864,11 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi case Array::ArrayStorage: case Array::SlowPutArrayStorage: break; - case Array::Arguments: - filter(node->child1(), SpecArguments); + case Array::DirectArguments: + filter(node->child1(), SpecDirectArguments); + break; + case Array::ScopedArguments: + filter(node->child1(), SpecScopedArguments); break; case Array::Int8Array: filter(node->child1(), SpecInt8Array); @@ -1615,7 +1902,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi break; } filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering()); - m_state.setHaveStructures(true); break; } case Arrayify: { @@ -1623,72 +1909,143 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi m_state.setFoundConstants(true); break; } - ASSERT(node->arrayMode().conversion() == Array::Convert - || node->arrayMode().conversion() == Array::RageConvert); - node->setCanExit(true); + ASSERT(node->arrayMode().conversion() == Array::Convert); clobberStructures(clobberLimit); filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering()); - m_state.setHaveStructures(true); break; } case ArrayifyToStructure: { AbstractValue& value = forNode(node->child1()); - StructureSet set = node->structure(); - if (value.m_futurePossibleStructure.isSubsetOf(set) - || value.m_currentKnownStructure.isSubsetOf(set)) + if (value.m_structure.isSubsetOf(StructureSet(node->structure()))) m_state.setFoundConstants(true); - node->setCanExit(true); clobberStructures(clobberLimit); - filter(value, set); - m_state.setHaveStructures(true); + + // We have a bunch of options of how to express the abstract set at this point. Let set S + // be the set of structures that the value had before clobbering and assume that all of + // them are watchable. The new value should be the least expressible upper bound of the + // intersection of "values that currently have structure = node->structure()" and "values + // that have structure in S plus any structure transition-reachable from S". Assume that + // node->structure() is not in S but it is transition-reachable from S. Then we would + // like to say that the result is "values that have structure = node->structure() until + // we invalidate", but there is no way to express this using the AbstractValue syntax. So + // we must choose between: + // + // 1) "values that currently have structure = node->structure()". This is a valid + // superset of the value that we really want, and it's specific enough to satisfy the + // preconditions of the array access that this is guarding. It's also specific enough + // to allow relevant optimizations in the case that we didn't have a contradiction + // like in this example. Notice that in the abscence of any contradiction, this result + // is precise rather than being a conservative LUB. + // + // 2) "values that currently hava structure in S plus any structure transition-reachable + // from S". This is also a valid superset of the value that we really want, but it's + // not specific enough to satisfy the preconditions of the array access that this is + // guarding - so playing such shenanigans would preclude us from having assertions on + // the typing preconditions of any array accesses. This would also not be a desirable + // answer in the absence of a contradiction. + // + // Note that it's tempting to simply say that the resulting value is BOTTOM because of + // the contradiction. That would be wrong, since we haven't hit an invalidation point, + // yet. + value.set(m_graph, node->structure()); + break; + } + case GetIndexedPropertyStorage: { + JSArrayBufferView* view = m_graph.tryGetFoldableView( + forNode(node->child1()).m_value, node->arrayMode()); + if (view) + m_state.setFoundConstants(true); + forNode(node).clear(); break; } - case GetIndexedPropertyStorage: case ConstantStoragePointer: { forNode(node).clear(); break; } case GetTypedArrayByteOffset: { + JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value); + if (view) { + setConstant(node, jsNumber(view->byteOffset())); + break; + } forNode(node).setType(SpecInt32); break; } case GetByOffset: { + StorageAccessData& data = node->storageAccessData(); + JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset); + if (result) { + setConstant(node, *m_graph.freeze(result)); + break; + } + forNode(node).makeHeapTop(); break; } + case GetGetterSetterByOffset: { + StorageAccessData& data = node->storageAccessData(); + JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset); + if (result && jsDynamicCast<GetterSetter*>(result)) { + setConstant(node, *m_graph.freeze(result)); + break; + } + + forNode(node).set(m_graph, m_graph.m_vm.getterSetterStructure.get()); + break; + } + case MultiGetByOffset: { - AbstractValue& value = forNode(node->child1()); - ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this. - - if (Structure* structure = value.bestProvenStructure()) { - bool done = false; - for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) { - const GetByIdVariant& variant = node->multiGetByOffsetData().variants[i]; - if (!variant.structureSet().contains(structure)) - continue; - - if (variant.chain()) - break; - - filter(value, structure); - forNode(node).makeHeapTop(); - m_state.setFoundConstants(true); - done = true; - break; + // This code will filter the base value in a manner that is possibly different (either more + // or less precise) than the way it would be filtered if this was strength-reduced to a + // CheckStructure. This is fine. It's legal for different passes over the code to prove + // different things about the code, so long as all of them are sound. That even includes + // one guy proving that code should never execute (due to a contradiction) and another guy + // not finding that contradiction. If someone ever proved that there would be a + // contradiction then there must always be a contradiction even if subsequent passes don't + // realize it. This is the case here. + + // Ordinarily you have to be careful with calling setFoundConstants() + // because of the effect on compile times, but this node is FTL-only. + m_state.setFoundConstants(true); + + AbstractValue base = forNode(node->child1()); + StructureSet baseSet; + AbstractValue result; + for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) { + GetByIdVariant& variant = node->multiGetByOffsetData().variants[i]; + StructureSet set = variant.structureSet(); + set.filter(base); + if (set.isEmpty()) + continue; + baseSet.merge(set); + + JSValue baseForLoad; + if (variant.alternateBase()) + baseForLoad = variant.alternateBase(); + else + baseForLoad = base.m_value; + JSValue constantResult = + m_graph.tryGetConstantProperty( + baseForLoad, variant.baseStructure(), variant.offset()); + if (!constantResult) { + result.makeHeapTop(); + continue; } - if (done) - break; + AbstractValue thisResult; + thisResult.set( + m_graph, + *m_graph.freeze(constantResult), + m_state.structureClobberState()); + result.merge(thisResult); } - StructureSet set; - for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) - set.addAll(node->multiGetByOffsetData().variants[i].structureSet()); + if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction) + m_state.setIsValid(false); - filter(node->child1(), set); - forNode(node).makeHeapTop(); + forNode(node) = result; break; } @@ -1697,71 +2054,74 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi } case MultiPutByOffset: { - AbstractValue& value = forNode(node->child1()); - ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this. - - if (Structure* structure = value.bestProvenStructure()) { - bool done = false; - for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { - const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; - if (variant.oldStructure() != structure) - continue; - - if (variant.kind() == PutByIdVariant::Replace) { - filter(node->child1(), structure); - m_state.setFoundConstants(true); - m_state.setHaveStructures(true); - done = true; - break; - } - - ASSERT(variant.kind() == PutByIdVariant::Transition); - clobberStructures(clobberLimit); - forNode(node->child1()).set(m_graph, variant.newStructure()); - m_state.setFoundConstants(true); - m_state.setHaveStructures(true); - done = true; - break; - } - if (done) - break; - } + StructureSet newSet; + TransitionVector transitions; - clobberStructures(clobberLimit); + // Ordinarily you have to be careful with calling setFoundConstants() + // because of the effect on compile times, but this node is FTL-only. + m_state.setFoundConstants(true); + + AbstractValue base = forNode(node->child1()); - StructureSet newSet; for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; - if (variant.kind() == PutByIdVariant::Replace) { - if (value.m_currentKnownStructure.contains(variant.structure())) - newSet.addAll(variant.structure()); + StructureSet thisSet = variant.oldStructure(); + thisSet.filter(base); + if (thisSet.isEmpty()) continue; + if (variant.kind() == PutByIdVariant::Transition) { + if (thisSet.onlyStructure() != variant.newStructure()) { + transitions.append( + Transition(variant.oldStructureForTransition(), variant.newStructure())); + } // else this is really a replace. + newSet.add(variant.newStructure()); + } else { + ASSERT(variant.kind() == PutByIdVariant::Replace); + newSet.merge(thisSet); } - ASSERT(variant.kind() == PutByIdVariant::Transition); - if (value.m_currentKnownStructure.contains(variant.oldStructure())) - newSet.addAll(variant.newStructure()); } - // Use filter(value, set) as a way of setting the structure set. This works because - // we would have already made the set be TOP before this. Filtering top is another - // way of setting. - filter(node->child1(), newSet); + observeTransitions(clobberLimit, transitions); + if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction) + m_state.setIsValid(false); + break; + } + + case GetExecutable: { + JSValue value = forNode(node->child1()).value(); + if (value) { + JSFunction* function = jsDynamicCast<JSFunction*>(value); + if (function) { + setConstant(node, *m_graph.freeze(function->executable())); + break; + } + } + forNode(node).setType(m_graph, SpecCellOther); break; } - case CheckFunction: { + case CheckCell: { JSValue value = forNode(node->child1()).value(); - if (value == node->function()) { + if (value == node->cellOperand()->value()) { m_state.setFoundConstants(true); ASSERT(value); break; } - - node->setCanExit(true); // Lies! We can do better. - filterByValue(node->child1(), node->function()); + filterByValue(node->child1(), *node->cellOperand()); break; } + + case CheckNotEmpty: { + AbstractValue& value = forNode(node->child1()); + if (!(value.m_type & SpecEmpty)) { + m_state.setFoundConstants(true); + break; + } + filter(value, ~SpecEmpty); + break; + } + case CheckInBounds: { JSValue left = forNode(node->child1()).value(); JSValue right = forNode(node->child2()).value(); @@ -1770,82 +2130,140 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi m_state.setFoundConstants(true); break; } - - node->setCanExit(true); break; } case PutById: case PutByIdFlush: - case PutByIdDirect: - node->setCanExit(true); - if (Structure* structure = forNode(node->child1()).bestProvenStructure()) { + case PutByIdDirect: { + AbstractValue& value = forNode(node->child1()); + if (!value.m_structure.isTop() && !value.m_structure.isClobbered()) { PutByIdStatus status = PutByIdStatus::computeFor( - m_graph.m_vm, m_graph.globalObjectFor(node->origin.semantic), - structure, + value.m_structure.set(), m_graph.identifiers()[node->identifierNumber()], node->op() == PutByIdDirect); - if (status.isSimple() && status.numVariants() == 1) { - if (status[0].kind() == PutByIdVariant::Replace) { - filter(node->child1(), structure); - m_state.setFoundConstants(true); - m_state.setHaveStructures(true); - break; + + if (status.isSimple()) { + StructureSet newSet; + TransitionVector transitions; + + for (unsigned i = status.numVariants(); i--;) { + const PutByIdVariant& variant = status[i]; + if (variant.kind() == PutByIdVariant::Transition) { + transitions.append( + Transition( + variant.oldStructureForTransition(), variant.newStructure())); + m_graph.registerStructure(variant.newStructure()); + newSet.add(variant.newStructure()); + } else { + ASSERT(variant.kind() == PutByIdVariant::Replace); + newSet.merge(variant.oldStructure()); + } } - if (status[0].kind() == PutByIdVariant::Transition) { - clobberStructures(clobberLimit); - forNode(node->child1()).set(m_graph, status[0].newStructure()); - m_state.setHaveStructures(true); + + if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode)) m_state.setFoundConstants(true); - break; - } + + observeTransitions(clobberLimit, transitions); + if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction) + m_state.setIsValid(false); + break; } } + clobberWorld(node->origin.semantic, clobberLimit); break; + } - case In: + case In: { // FIXME: We can determine when the property definitely exists based on abstract // value information. clobberWorld(node->origin.semantic, clobberLimit); forNode(node).setType(SpecBoolean); break; + } + case GetEnumerableLength: { + forNode(node).setType(SpecInt32); + break; + } + case HasGenericProperty: { + forNode(node).setType(SpecBoolean); + break; + } + case HasStructureProperty: { + forNode(node).setType(SpecBoolean); + break; + } + case HasIndexedProperty: { + ArrayMode mode = node->arrayMode(); + switch (mode.type()) { + case Array::Int32: + case Array::Double: + case Array::Contiguous: + case Array::ArrayStorage: { + break; + } + default: { + clobberWorld(node->origin.semantic, clobberLimit); + break; + } + } + forNode(node).setType(SpecBoolean); + break; + } + case GetDirectPname: { + clobberWorld(node->origin.semantic, clobberLimit); + forNode(node).makeHeapTop(); + break; + } + case GetPropertyEnumerator: { + forNode(node).setType(m_graph, SpecCell); + break; + } + case GetEnumeratorStructurePname: { + forNode(node).setType(m_graph, SpecString | SpecOther); + break; + } + case GetEnumeratorGenericPname: { + forNode(node).setType(m_graph, SpecString | SpecOther); + break; + } + case ToIndexString: { + forNode(node).setType(m_graph, SpecString); + break; + } + case GetGlobalVar: forNode(node).makeHeapTop(); break; - case VariableWatchpoint: case VarInjectionWatchpoint: - node->setCanExit(true); - break; - case PutGlobalVar: case NotifyWrite: break; case CheckHasInstance: - node->setCanExit(true); // Sadly, we don't propagate the fact that we've done CheckHasInstance break; case InstanceOf: - node->setCanExit(true); // Again, sadly, we don't propagate the fact that we've done InstanceOf forNode(node).setType(SpecBoolean); break; case Phi: RELEASE_ASSERT(m_graph.m_form == SSA); - // The state of this node would have already been decided. + // The state of this node would have already been decided, but it may have become a + // constant, in which case we'd like to know. + if (forNode(node).m_value) + m_state.setFoundConstants(true); break; case Upsilon: { m_state.createValueForNode(node->phi()); - AbstractValue& value = forNode(node->child1()); - forNode(node) = value; - forNode(node->phi()) = value; + forNode(node->phi()) = forNode(node->child1()); break; } @@ -1855,56 +2273,70 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi case Call: case Construct: - node->setCanExit(true); + case NativeCall: + case NativeConstruct: + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: clobberWorld(node->origin.semantic, clobberLimit); forNode(node).makeHeapTop(); break; case ForceOSRExit: - node->setCanExit(true); + case CheckBadCell: m_state.setIsValid(false); break; case InvalidationPoint: - node->setCanExit(true); + forAllValues(clobberLimit, AbstractValue::observeInvalidationPointFor); + m_state.setStructureClobberState(StructuresAreWatched); break; case CheckWatchdogTimer: - node->setCanExit(true); break; case Breakpoint: case ProfileWillCall: case ProfileDidCall: + case ProfileType: + case ProfileControlFlow: case Phantom: - case HardPhantom: - case Check: case CountExecution: case CheckTierUpInLoop: case CheckTierUpAtReturn: break; - case StoreBarrier: { - filter(node->child1(), SpecCell); + case Check: { + // Simplify out checks that don't actually do checking. + for (unsigned i = 0; i < AdjacencyList::Size; ++i) { + Edge edge = node->children.child(i); + if (!edge) + break; + if (edge.isProved() || edge.willNotHaveCheck()) { + m_state.setFoundConstants(true); + break; + } + } break; } - case StoreBarrierWithNullCheck: { + case StoreBarrier: { + filter(node->child1(), SpecCell); break; } case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: case LoopHint: - // We pretend that it can exit because it may want to get all state. - node->setCanExit(true); + case ZombieHint: break; - case ZombieHint: case Unreachable: case LastNodeType: case ArithIMul: case FiatInt52: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_graph, node, "Unexpected node type"); break; } @@ -1921,9 +2353,8 @@ template<typename AbstractStateType> bool AbstractInterpreter<AbstractStateType>::execute(unsigned indexInBlock) { Node* node = m_state.block()->at(indexInBlock); - if (!startExecuting(node)) - return true; + startExecuting(); executeEdges(node); return executeEffects(indexInBlock, node); } @@ -1931,79 +2362,99 @@ bool AbstractInterpreter<AbstractStateType>::execute(unsigned indexInBlock) template<typename AbstractStateType> bool AbstractInterpreter<AbstractStateType>::execute(Node* node) { - if (!startExecuting(node)) - return true; - + startExecuting(); executeEdges(node); return executeEffects(UINT_MAX, node); } template<typename AbstractStateType> void AbstractInterpreter<AbstractStateType>::clobberWorld( - const CodeOrigin& codeOrigin, unsigned clobberLimit) + const CodeOrigin&, unsigned clobberLimit) { - clobberCapturedVars(codeOrigin); clobberStructures(clobberLimit); } template<typename AbstractStateType> -void AbstractInterpreter<AbstractStateType>::clobberCapturedVars(const CodeOrigin& codeOrigin) +template<typename Functor> +void AbstractInterpreter<AbstractStateType>::forAllValues( + unsigned clobberLimit, Functor& functor) { - if (codeOrigin.inlineCallFrame) { - const BitVector& capturedVars = codeOrigin.inlineCallFrame->capturedVars; - for (size_t i = capturedVars.size(); i--;) { - if (!capturedVars.quickGet(i)) - continue; - m_state.variables().local(i).makeHeapTop(); - } - } else { - for (size_t i = m_codeBlock->m_numVars; i--;) { - if (m_codeBlock->isCaptured(virtualRegisterForLocal(i))) - m_state.variables().local(i).makeHeapTop(); - } - } - - for (size_t i = m_state.variables().numberOfArguments(); i--;) { - if (m_codeBlock->isCaptured(virtualRegisterForArgument(i))) - m_state.variables().argument(i).makeHeapTop(); - } -} - -template<typename AbstractStateType> -void AbstractInterpreter<AbstractStateType>::clobberStructures(unsigned clobberLimit) -{ - if (!m_state.haveStructures()) - return; + SamplingRegion samplingRegion("DFG AI For All Values"); if (clobberLimit >= m_state.block()->size()) clobberLimit = m_state.block()->size(); else clobberLimit++; ASSERT(clobberLimit <= m_state.block()->size()); for (size_t i = clobberLimit; i--;) - forNode(m_state.block()->at(i)).clobberStructures(); + functor(forNode(m_state.block()->at(i))); if (m_graph.m_form == SSA) { HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtHead.begin(); HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtHead.end(); for (; iter != end; ++iter) - forNode(*iter).clobberStructures(); + functor(forNode(*iter)); } for (size_t i = m_state.variables().numberOfArguments(); i--;) - m_state.variables().argument(i).clobberStructures(); + functor(m_state.variables().argument(i)); for (size_t i = m_state.variables().numberOfLocals(); i--;) - m_state.variables().local(i).clobberStructures(); - m_state.setHaveStructures(true); + functor(m_state.variables().local(i)); +} + +template<typename AbstractStateType> +void AbstractInterpreter<AbstractStateType>::clobberStructures(unsigned clobberLimit) +{ + SamplingRegion samplingRegion("DFG AI Clobber Structures"); + forAllValues(clobberLimit, AbstractValue::clobberStructuresFor); + setDidClobber(); +} + +template<typename AbstractStateType> +void AbstractInterpreter<AbstractStateType>::observeTransition( + unsigned clobberLimit, Structure* from, Structure* to) +{ + AbstractValue::TransitionObserver transitionObserver(from, to); + forAllValues(clobberLimit, transitionObserver); + + ASSERT(!from->dfgShouldWatch()); // We don't need to claim to be in a clobbered state because 'from' was never watchable (during the time we were compiling), hence no constants ever introduced into the DFG IR that ever had a watchable structure would ever have the same structure as from. +} + +template<typename AbstractStateType> +void AbstractInterpreter<AbstractStateType>::observeTransitions( + unsigned clobberLimit, const TransitionVector& vector) +{ + AbstractValue::TransitionsObserver transitionsObserver(vector); + forAllValues(clobberLimit, transitionsObserver); + + if (!ASSERT_DISABLED) { + // We don't need to claim to be in a clobbered state because none of the Transition::previous structures are watchable. + for (unsigned i = vector.size(); i--;) + ASSERT(!vector[i].previous->dfgShouldWatch()); + } +} + +template<typename AbstractStateType> +void AbstractInterpreter<AbstractStateType>::setDidClobber() +{ m_state.setDidClobber(true); + m_state.setStructureClobberState(StructuresAreClobbered); +} + +template<typename AbstractStateType> +void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) const +{ + const_cast<AbstractInterpreter<AbstractStateType>*>(this)->dump(out); } template<typename AbstractStateType> void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) { CommaPrinter comma(" "); + HashSet<Node*> seen; if (m_graph.m_form == SSA) { HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtHead.begin(); HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtHead.end(); for (; iter != end; ++iter) { Node* node = *iter; + seen.add(node); AbstractValue& value = forNode(node); if (value.isClear()) continue; @@ -2012,11 +2463,25 @@ void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) } for (size_t i = 0; i < m_state.block()->size(); ++i) { Node* node = m_state.block()->at(i); + seen.add(node); AbstractValue& value = forNode(node); if (value.isClear()) continue; out.print(comma, node, ":", value); } + if (m_graph.m_form == SSA) { + HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtTail.begin(); + HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtTail.end(); + for (; iter != end; ++iter) { + Node* node = *iter; + if (seen.contains(node)) + continue; + AbstractValue& value = forNode(node); + if (value.isClear()) + continue; + out.print(comma, node, ":", value); + } + } } template<typename AbstractStateType> @@ -2051,7 +2516,7 @@ FiltrationResult AbstractInterpreter<AbstractStateType>::filter( template<typename AbstractStateType> FiltrationResult AbstractInterpreter<AbstractStateType>::filterByValue( - AbstractValue& abstractValue, JSValue concreteValue) + AbstractValue& abstractValue, FrozenValue concreteValue) { if (abstractValue.filterByValue(concreteValue) == FiltrationOK) return FiltrationOK; diff --git a/dfg/DFGAbstractValue.cpp b/dfg/DFGAbstractValue.cpp index d39ca87..08466aa 100644 --- a/dfg/DFGAbstractValue.cpp +++ b/dfg/DFGAbstractValue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,60 +30,94 @@ #include "DFGGraph.h" #include "JSCInlines.h" +#include "TrackedReferences.h" namespace JSC { namespace DFG { -void AbstractValue::setMostSpecific(Graph& graph, JSValue value) +void AbstractValue::observeTransitions(const TransitionVector& vector) { - if (!!value && value.isCell()) { - Structure* structure = value.asCell()->structure(); - m_currentKnownStructure = structure; - setFuturePossibleStructure(graph, structure); - m_arrayModes = asArrayModes(structure->indexingType()); - } else { - m_currentKnownStructure.clear(); - m_futurePossibleStructure.clear(); - m_arrayModes = 0; + if (m_type & SpecCell) { + m_structure.observeTransitions(vector); + ArrayModes newModes = 0; + for (unsigned i = vector.size(); i--;) { + if (m_arrayModes & asArrayModes(vector[i].previous->indexingType())) + newModes |= asArrayModes(vector[i].next->indexingType()); + } + m_arrayModes |= newModes; } - - m_type = speculationFromValue(value); - m_value = value; - checkConsistency(); } -void AbstractValue::set(Graph& graph, JSValue value) +void AbstractValue::set(Graph& graph, const FrozenValue& value, StructureClobberState clobberState) { - if (!!value && value.isCell()) { - m_currentKnownStructure.makeTop(); - Structure* structure = value.asCell()->structure(); - setFuturePossibleStructure(graph, structure); - m_arrayModes = asArrayModes(structure->indexingType()); - clobberArrayModes(); + if (!!value && value.value().isCell()) { + Structure* structure = value.structure(); + if (graph.registerStructure(structure) == StructureRegisteredAndWatched) { + m_structure = structure; + if (clobberState == StructuresAreClobbered) { + m_arrayModes = ALL_ARRAY_MODES; + m_structure.clobber(); + } else + m_arrayModes = asArrayModes(structure->indexingType()); + } else { + m_structure.makeTop(); + m_arrayModes = ALL_ARRAY_MODES; + } } else { - m_currentKnownStructure.clear(); - m_futurePossibleStructure.clear(); + m_structure.clear(); m_arrayModes = 0; } - m_type = speculationFromValue(value); - m_value = value; + m_type = speculationFromValue(value.value()); + m_value = value.value(); checkConsistency(); + assertIsRegistered(graph); } void AbstractValue::set(Graph& graph, Structure* structure) { - m_currentKnownStructure = structure; - setFuturePossibleStructure(graph, structure); + m_structure = structure; m_arrayModes = asArrayModes(structure->indexingType()); m_type = speculationFromStructure(structure); m_value = JSValue(); checkConsistency(); + assertIsRegistered(graph); +} + +void AbstractValue::set(Graph& graph, const StructureSet& set) +{ + m_structure = set; + m_arrayModes = set.arrayModesFromStructures(); + m_type = set.speculationFromStructures(); + m_value = JSValue(); + + checkConsistency(); + assertIsRegistered(graph); } -void AbstractValue::fixTypeForRepresentation(NodeFlags representation) +void AbstractValue::setType(Graph& graph, SpeculatedType type) +{ + SpeculatedType cellType = type & SpecCell; + if (cellType) { + if (!(cellType & ~SpecString)) + m_structure = graph.m_vm.stringStructure.get(); + else if (isSymbolSpeculation(cellType)) + m_structure = graph.m_vm.symbolStructure.get(); + else + m_structure.makeTop(); + m_arrayModes = ALL_ARRAY_MODES; + } else { + m_structure.clear(); + m_arrayModes = 0; + } + m_type = type; + m_value = JSValue(); + checkConsistency(); +} + +void AbstractValue::fixTypeForRepresentation(Graph& graph, NodeFlags representation, Node* node) { if (representation == NodeResultDouble) { if (m_value) { @@ -95,39 +129,64 @@ void AbstractValue::fixTypeForRepresentation(NodeFlags representation) m_type &= ~SpecMachineInt; m_type |= SpecInt52AsDouble; } - if (m_type & ~SpecFullDouble) { - startCrashing(); - dataLog("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n"); - CRASH(); - } + if (m_type & ~SpecFullDouble) + DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for double node has type outside SpecFullDouble.\n").data()); } else if (representation == NodeResultInt52) { if (m_type & SpecInt52AsDouble) { m_type &= ~SpecInt52AsDouble; m_type |= SpecInt52; } - if (m_type & ~SpecMachineInt) { - startCrashing(); - dataLog("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n"); - CRASH(); - } + if (m_type & ~SpecMachineInt) + DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for int52 node has type outside SpecMachineInt.\n").data()); } else { if (m_type & SpecInt52) { m_type &= ~SpecInt52; m_type |= SpecInt52AsDouble; } - if (m_type & ~SpecBytecodeTop) { - startCrashing(); - dataLog("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n"); - CRASH(); - } + if (m_type & ~SpecBytecodeTop) + DFG_CRASH(graph, node, toCString("Abstract value ", *this, " for value node has type outside SpecBytecodeTop.\n").data()); } checkConsistency(); } -void AbstractValue::fixTypeForRepresentation(Node* node) +void AbstractValue::fixTypeForRepresentation(Graph& graph, Node* node) { - fixTypeForRepresentation(node->result()); + fixTypeForRepresentation(graph, node->result(), node); +} + +bool AbstractValue::mergeOSREntryValue(Graph& graph, JSValue value) +{ + AbstractValue oldMe = *this; + + if (isClear()) { + FrozenValue* frozenValue = graph.freeze(value); + if (frozenValue->pointsToHeap()) { + m_structure = frozenValue->structure(); + m_arrayModes = asArrayModes(frozenValue->structure()->indexingType()); + } else { + m_structure.clear(); + m_arrayModes = 0; + } + + m_type = speculationFromValue(value); + m_value = value; + } else { + mergeSpeculation(m_type, speculationFromValue(value)); + if (!!value && value.isCell()) { + Structure* structure = value.asCell()->structure(); + graph.registerStructure(structure); + mergeArrayModes(m_arrayModes, asArrayModes(structure->indexingType())); + m_structure.merge(StructureSet(structure)); + } + if (m_value != value) + m_value = JSValue(); + } + + checkConsistency(); + assertIsRegistered(graph); + + return oldMe != *this; } FiltrationResult AbstractValue::filter(Graph& graph, const StructureSet& other) @@ -141,21 +200,29 @@ FiltrationResult AbstractValue::filter(Graph& graph, const StructureSet& other) m_type &= other.speculationFromStructures(); m_arrayModes &= other.arrayModesFromStructures(); - m_currentKnownStructure.filter(other); + m_structure.filter(other); // It's possible that prior to the above two statements we had (Foo, TOP), where // Foo is a SpeculatedType that is disjoint with the passed StructureSet. In that // case, we will now have (None, [someStructure]). In general, we need to make // sure that new information gleaned from the SpeculatedType needs to be fed back // into the information gleaned from the StructureSet. - m_currentKnownStructure.filter(m_type); + m_structure.filter(m_type); - if (m_currentKnownStructure.hasSingleton()) - setFuturePossibleStructure(graph, m_currentKnownStructure.singleton()); - filterArrayModesByType(); filterValueByType(); - return normalizeClarity(); + return normalizeClarity(graph); +} + +FiltrationResult AbstractValue::changeStructure(Graph& graph, const StructureSet& other) +{ + m_type &= other.speculationFromStructures(); + m_arrayModes = other.arrayModesFromStructures(); + m_structure = other; + + filterValueByType(); + + return normalizeClarity(graph); } FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes) @@ -175,34 +242,77 @@ FiltrationResult AbstractValue::filter(SpeculatedType type) if ((m_type & type) == m_type) return FiltrationOK; + // Fast path for the case that we don't even have a cell. + if (!(m_type & SpecCell)) { + m_type &= type; + FiltrationResult result; + if (m_type == SpecNone) { + clear(); + result = Contradiction; + } else + result = FiltrationOK; + checkConsistency(); + return result; + } + m_type &= type; // It's possible that prior to this filter() call we had, say, (Final, TOP), and // the passed type is Array. At this point we'll have (None, TOP). The best way // to ensure that the structure filtering does the right thing is to filter on // the new type (None) rather than the one passed (Array). - m_currentKnownStructure.filter(m_type); - m_futurePossibleStructure.filter(m_type); + m_structure.filter(type); filterArrayModesByType(); filterValueByType(); return normalizeClarity(); } -FiltrationResult AbstractValue::filterByValue(JSValue value) +FiltrationResult AbstractValue::filterByValue(const FrozenValue& value) { - FiltrationResult result = filter(speculationFromValue(value)); + FiltrationResult result = filter(speculationFromValue(value.value())); if (m_type) - m_value = value; + m_value = value.value(); return result; } -void AbstractValue::setFuturePossibleStructure(Graph& graph, Structure* structure) +bool AbstractValue::contains(Structure* structure) const +{ + return couldBeType(speculationFromStructure(structure)) + && (m_arrayModes & arrayModeFromStructure(structure)) + && m_structure.contains(structure); +} + +FiltrationResult AbstractValue::filter(const AbstractValue& other) { - ASSERT(structure); - if (graph.watchpoints().isStillValid(structure->transitionWatchpointSet())) - m_futurePossibleStructure = structure; - else - m_futurePossibleStructure.makeTop(); + m_type &= other.m_type; + m_structure.filter(other.m_structure); + m_arrayModes &= other.m_arrayModes; + + m_structure.filter(m_type); + filterArrayModesByType(); + filterValueByType(); + + if (normalizeClarity() == Contradiction) + return Contradiction; + + if (m_value == other.m_value) + return FiltrationOK; + + // Neither of us are BOTTOM, so an empty value means TOP. + if (!m_value) { + // We previously didn't prove a value but now we have done so. + m_value = other.m_value; + return FiltrationOK; + } + + if (!other.m_value) { + // We had proved a value but the other guy hadn't, so keep our proof. + return FiltrationOK; + } + + // We both proved there to be a specific value but they are different. + clear(); + return Contradiction; } void AbstractValue::filterValueByType() @@ -250,8 +360,7 @@ bool AbstractValue::shouldBeClear() const return true; if (!(m_type & ~SpecCell) - && (!m_arrayModes - || m_currentKnownStructure.isClear())) + && (!m_arrayModes || m_structure.isClear())) return true; return false; @@ -275,12 +384,18 @@ FiltrationResult AbstractValue::normalizeClarity() return result; } +FiltrationResult AbstractValue::normalizeClarity(Graph& graph) +{ + FiltrationResult result = normalizeClarity(); + assertIsRegistered(graph); + return result; +} + #if !ASSERT_DISABLED void AbstractValue::checkConsistency() const { if (!(m_type & SpecCell)) { - ASSERT(m_currentKnownStructure.isClear()); - ASSERT(m_futurePossibleStructure.isClear()); + ASSERT(m_structure.isClear()); ASSERT(!m_arrayModes); } @@ -301,6 +416,11 @@ void AbstractValue::checkConsistency() const // we don't want to get pedantic about this as it would only increase the computational // complexity of the code. } + +void AbstractValue::assertIsRegistered(Graph& graph) const +{ + m_structure.assertIsRegistered(graph); +} #endif void AbstractValue::dump(PrintStream& out) const @@ -314,14 +434,19 @@ void AbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const if (m_type & SpecCell) { out.print( ", ", ArrayModesDump(m_arrayModes), ", ", - inContext(m_currentKnownStructure, context), ", ", - inContext(m_futurePossibleStructure, context)); + inContext(m_structure, context)); } if (!!m_value) out.print(", ", inContext(m_value, context)); out.print(")"); } +void AbstractValue::validateReferences(const TrackedReferences& trackedReferences) +{ + trackedReferences.check(m_value); + m_structure.validateReferences(trackedReferences); +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGAbstractValue.h b/dfg/DFGAbstractValue.h index 14363df..7318d0d 100644 --- a/dfg/DFGAbstractValue.h +++ b/dfg/DFGAbstractValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,14 +30,20 @@ #include "ArrayProfile.h" #include "DFGFiltrationResult.h" +#include "DFGFrozenValue.h" #include "DFGNodeFlags.h" #include "DFGStructureAbstractValue.h" +#include "DFGStructureClobberState.h" #include "JSCell.h" #include "SpeculatedType.h" #include "DumpContext.h" #include "StructureSet.h" -namespace JSC { namespace DFG { +namespace JSC { + +class TrackedReferences; + +namespace DFG { class Graph; struct Node; @@ -53,8 +59,7 @@ struct AbstractValue { { m_type = SpecNone; m_arrayModes = 0; - m_currentKnownStructure.clear(); - m_futurePossibleStructure.clear(); + m_structure.clear(); m_value = JSValue(); checkConsistency(); } @@ -72,18 +77,82 @@ struct AbstractValue { makeTop(SpecBytecodeTop); } + void makeFullTop() + { + makeTop(SpecFullTop); + } + void clobberStructures() { if (m_type & SpecCell) { - m_currentKnownStructure.makeTop(); + m_structure.clobber(); clobberArrayModes(); } else { - ASSERT(m_currentKnownStructure.isClear()); + ASSERT(m_structure.isClear()); ASSERT(!m_arrayModes); } checkConsistency(); } + + static void clobberStructuresFor(AbstractValue& value) + { + value.clobberStructures(); + } + + void observeInvalidationPoint() + { + m_structure.observeInvalidationPoint(); + checkConsistency(); + } + + static void observeInvalidationPointFor(AbstractValue& value) + { + value.observeInvalidationPoint(); + } + + void observeTransition(Structure* from, Structure* to) + { + if (m_type & SpecCell) { + m_structure.observeTransition(from, to); + observeIndexingTypeTransition(from->indexingType(), to->indexingType()); + } + checkConsistency(); + } + + void observeTransitions(const TransitionVector& vector); + + class TransitionObserver { + public: + TransitionObserver(Structure* from, Structure* to) + : m_from(from) + , m_to(to) + { + } + void operator()(AbstractValue& value) + { + value.observeTransition(m_from, m_to); + } + private: + Structure* m_from; + Structure* m_to; + }; + + class TransitionsObserver { + public: + TransitionsObserver(const TransitionVector& vector) + : m_vector(vector) + { + } + + void operator()(AbstractValue& value) + { + value.observeTransitions(m_vector); + } + private: + const TransitionVector& m_vector; + }; + void clobberValue() { m_value = JSValue(); @@ -91,7 +160,10 @@ struct AbstractValue { bool isHeapTop() const { - return (m_type | SpecHeapTop) == m_type && m_currentKnownStructure.isTop() && m_futurePossibleStructure.isTop(); + return (m_type | SpecHeapTop) == m_type + && m_structure.isTop() + && m_arrayModes == ALL_ARRAY_MODES + && !m_value; } bool valueIsTop() const @@ -111,35 +183,46 @@ struct AbstractValue { return result; } - void setMostSpecific(Graph&, JSValue); - void set(Graph&, JSValue); + static AbstractValue bytecodeTop() + { + AbstractValue result; + result.makeBytecodeTop(); + return result; + } + + static AbstractValue fullTop() + { + AbstractValue result; + result.makeFullTop(); + return result; + } + + void set(Graph&, const FrozenValue&, StructureClobberState); void set(Graph&, Structure*); + void set(Graph&, const StructureSet&); + // Set this value to represent the given set of types as precisely as possible. + void setType(Graph&, SpeculatedType); + + // As above, but only valid for non-cell types. void setType(SpeculatedType type) { - if (type & SpecCell) { - m_currentKnownStructure.makeTop(); - m_futurePossibleStructure.makeTop(); - m_arrayModes = ALL_ARRAY_MODES; - } else { - m_currentKnownStructure.clear(); - m_futurePossibleStructure.clear(); - m_arrayModes = 0; - } + RELEASE_ASSERT(!(type & SpecCell)); + m_structure.clear(); + m_arrayModes = 0; m_type = type; m_value = JSValue(); checkConsistency(); } - void fixTypeForRepresentation(NodeFlags representation); - void fixTypeForRepresentation(Node*); + void fixTypeForRepresentation(Graph&, NodeFlags representation, Node* = nullptr); + void fixTypeForRepresentation(Graph&, Node*); bool operator==(const AbstractValue& other) const { return m_type == other.m_type && m_arrayModes == other.m_arrayModes - && m_currentKnownStructure == other.m_currentKnownStructure - && m_futurePossibleStructure == other.m_futurePossibleStructure + && m_structure == other.m_structure && m_value == other.m_value; } bool operator!=(const AbstractValue& other) const @@ -162,8 +245,7 @@ struct AbstractValue { } else { result |= mergeSpeculation(m_type, other.m_type); result |= mergeArrayModes(m_arrayModes, other.m_arrayModes); - result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure); - result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure); + result |= m_structure.merge(other.m_structure); if (m_value != other.m_value) { result |= !!m_value; m_value = JSValue(); @@ -174,13 +256,14 @@ struct AbstractValue { return result; } + bool mergeOSREntryValue(Graph&, JSValue); + void merge(SpeculatedType type) { mergeSpeculation(m_type, type); if (type & SpecCell) { - m_currentKnownStructure.makeTop(); - m_futurePossibleStructure.makeTop(); + m_structure.makeTop(); m_arrayModes = ALL_ARRAY_MODES; } m_value = JSValue(); @@ -188,23 +271,25 @@ struct AbstractValue { checkConsistency(); } - bool couldBeType(SpeculatedType desiredType) + bool couldBeType(SpeculatedType desiredType) const { return !!(m_type & desiredType); } - bool isType(SpeculatedType desiredType) + bool isType(SpeculatedType desiredType) const { return !(m_type & ~desiredType); } FiltrationResult filter(Graph&, const StructureSet&); - FiltrationResult filterArrayModes(ArrayModes); - FiltrationResult filter(SpeculatedType); + FiltrationResult filterByValue(const FrozenValue& value); + FiltrationResult filter(const AbstractValue&); - FiltrationResult filterByValue(JSValue); + FiltrationResult changeStructure(Graph&, const StructureSet&); + + bool contains(Structure*) const; bool validate(JSValue value) const { @@ -225,75 +310,32 @@ struct AbstractValue { if (!!value && value.isCell()) { ASSERT(m_type & SpecCell); Structure* structure = value.asCell()->structure(); - return m_currentKnownStructure.contains(structure) - && m_futurePossibleStructure.contains(structure) + return m_structure.contains(structure) && (m_arrayModes & asArrayModes(structure->indexingType())); } return true; } - Structure* bestProvenStructure() const - { - if (m_currentKnownStructure.hasSingleton()) - return m_currentKnownStructure.singleton(); - if (m_futurePossibleStructure.hasSingleton()) - return m_futurePossibleStructure.singleton(); - return 0; - } - bool hasClobberableState() const { - return m_currentKnownStructure.isNeitherClearNorTop() + return m_structure.isNeitherClearNorTop() || !arrayModesAreClearOrTop(m_arrayModes); } #if ASSERT_DISABLED void checkConsistency() const { } + void assertIsRegistered(Graph&) const { } #else void checkConsistency() const; + void assertIsRegistered(Graph&) const; #endif void dumpInContext(PrintStream&, DumpContext*) const; void dump(PrintStream&) const; - // A great way to think about the difference between m_currentKnownStructure and - // m_futurePossibleStructure is to consider these four examples: - // - // 1) x = foo(); - // - // In this case x's m_currentKnownStructure and m_futurePossibleStructure will - // both be TOP, since we don't know anything about x for sure, yet. - // - // 2) x = foo(); - // y = x.f; - // - // Where x will later have a new property added to it, 'g'. Because of the - // known but not-yet-executed property addition, x's current structure will - // not be watchpointable; hence we have no way of statically bounding the set - // of possible structures that x may have if a clobbering event happens. So, - // x's m_currentKnownStructure will be whatever structure we check to get - // property 'f', and m_futurePossibleStructure will be TOP. - // - // 3) x = foo(); - // y = x.f; - // - // Where x has a terminal structure that is still watchpointable. In this case, - // x's m_currentKnownStructure and m_futurePossibleStructure will both be - // whatever structure we checked for when getting 'f'. - // - // 4) x = foo(); - // y = x.f; - // bar(); - // - // Where x has a terminal structure that is still watchpointable. In this - // case, m_currentKnownStructure will be TOP because bar() may potentially - // change x's structure and we have no way of proving otherwise, but - // x's m_futurePossibleStructure will be whatever structure we had checked - // when getting property 'f'. - - // NB. All fields in this struct must have trivial destructors. - + void validateReferences(const TrackedReferences&); + // This is a proven constraint on the structures that this value can have right // now. The structure of the current value must belong to this set. The set may // be TOP, indicating that it is the set of all possible structures, in which @@ -301,44 +343,25 @@ struct AbstractValue { // in which case this value cannot be a cell. This is all subject to change // anytime a new value is assigned to this one, anytime there is a control flow // merge, or most crucially, anytime a side-effect or structure check happens. - // In case of a side-effect, we typically must assume that any value may have - // had its structure changed, hence contravening our proof. We make the proof - // valid again by switching this to TOP (i.e. claiming that we have proved that - // this value may have any structure). Of note is that the proof represented by - // this field is not subject to structure transition watchpoints - even if one - // fires, we can be sure that this proof is still valid. - StructureAbstractValue m_currentKnownStructure; - - // This is a proven constraint on the structures that this value can have now - // or any time in the future subject to the structure transition watchpoints of - // all members of this set not having fired. This set is impervious to side- - // effects; even if one happens the side-effect can only cause the value to - // change to at worst another structure that is also a member of this set. But, - // the theorem being proved by this field is predicated upon there not being - // any new structure transitions introduced into any members of this set. In - // cases where there is no way for us to guard this happening, the set must be - // TOP. But in cases where we can guard new structure transitions (all members - // of the set have still-valid structure transition watchpoints) then this set - // will be finite. Anytime that we make use of the finite nature of this set, - // we must first issue a structure transition watchpoint, which will effectively - // result in m_currentKnownStructure being filtered according to - // m_futurePossibleStructure. - StructureAbstractValue m_futurePossibleStructure; + // In case of a side-effect, we must assume that any value with a structure that + // isn't being watched may have had its structure changed, hence contravening + // our proof. In such a case we make the proof valid again by switching this to + // TOP (i.e. claiming that we have proved that this value may have any + // structure). + StructureAbstractValue m_structure; // This is a proven constraint on the possible types that this value can have // now or any time in the future, unless it is reassigned. This field is - // impervious to side-effects unless the side-effect can reassign the value - // (for example if we're talking about a captured variable). The relationship - // between this field, and the structure fields above, is as follows. The - // fields above constraint the structures that a cell may have, but they say - // nothing about whether or not the value is known to be a cell. More formally, - // the m_currentKnownStructure is itself an abstract value that consists of the - // union of the set of all non-cell values and the set of cell values that have - // the given structure. This abstract value is then the intersection of the - // m_currentKnownStructure and the set of values whose type is m_type. So, for - // example if m_type is SpecFinal|SpecInt32 and m_currentKnownStructure is - // [0x12345] then this abstract value corresponds to the set of all integers - // unified with the set of all objects with structure 0x12345. + // impervious to side-effects. The relationship between this field, and the + // structure fields above, is as follows. The fields above constraint the + // structures that a cell may have, but they say nothing about whether or not + // the value is known to be a cell. More formally, the m_structure is itself an + // abstract value that consists of the union of the set of all non-cell values + // and the set of cell values that have the given structure. This abstract + // value is then the intersection of the m_structure and the set of values + // whose type is m_type. So, for example if m_type is SpecFinal|SpecInt32 and + // m_structure is [0x12345] then this abstract value corresponds to the set of + // all integers unified with the set of all objects with structure 0x12345. SpeculatedType m_type; // This is a proven constraint on the possible indexing types that this value @@ -353,7 +376,11 @@ struct AbstractValue { // implies nothing about the structure. Oddly, JSValue() (i.e. the empty value) // means either BOTTOM or TOP depending on the state of m_type: if m_type is // BOTTOM then JSValue() means BOTTOM; if m_type is not BOTTOM then JSValue() - // means TOP. + // means TOP. Also note that this value isn't necessarily known to the GC + // (strongly or even weakly - it may be an "fragile" value, see + // DFGValueStrength.h). If you perform any optimization based on a cell m_value + // that requires that the value be kept alive, you must call freeze() on that + // value, which will turn it into a weak value. JSValue m_value; private: @@ -364,6 +391,12 @@ private: m_arrayModes = ALL_ARRAY_MODES; } + void observeIndexingTypeTransition(IndexingType from, IndexingType to) + { + if (m_arrayModes & asArrayModes(from)) + m_arrayModes |= asArrayModes(to); + } + bool validateType(JSValue value) const { if (isHeapTop()) @@ -391,19 +424,17 @@ private: { m_type |= top; m_arrayModes = ALL_ARRAY_MODES; - m_currentKnownStructure.makeTop(); - m_futurePossibleStructure.makeTop(); + m_structure.makeTop(); m_value = JSValue(); checkConsistency(); } - void setFuturePossibleStructure(Graph&, Structure*); - void filterValueByType(); void filterArrayModesByType(); bool shouldBeClear() const; FiltrationResult normalizeClarity(); + FiltrationResult normalizeClarity(Graph&); }; } } // namespace JSC::DFG diff --git a/dfg/DFGAdjacencyList.h b/dfg/DFGAdjacencyList.h index 38e74da..63ebef5 100644 --- a/dfg/DFGAdjacencyList.h +++ b/dfg/DFGAdjacencyList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,7 +52,7 @@ public: } } - AdjacencyList(Kind kind, Edge child1, Edge child2, Edge child3) + AdjacencyList(Kind kind, Edge child1, Edge child2 = Edge(), Edge child3 = Edge()) { ASSERT_UNUSED(kind, kind == Fixed); initialize(child1, child2, child3); @@ -65,6 +65,8 @@ public: setNumChildren(numChildren); } + bool isEmpty() const { return !child1(); } + const Edge& child(unsigned i) const { ASSERT(i < Size); @@ -130,7 +132,7 @@ public: setChild(i, child(i + 1)); setChild(Size - 1, Edge()); } - + unsigned firstChild() const { return m_words[0].m_encodedWord; @@ -149,6 +151,56 @@ public: m_words[1].m_encodedWord = numChildren; } + AdjacencyList sanitized() const + { + return AdjacencyList(Fixed, child1().sanitized(), child2().sanitized(), child3().sanitized()); + } + + AdjacencyList justChecks() const + { + AdjacencyList result(Fixed); + unsigned sourceIndex = 0; + unsigned targetIndex = 0; + while (sourceIndex < AdjacencyList::Size) { + Edge edge = child(sourceIndex++); + if (!edge) + break; + if (edge.willHaveCheck()) + result.child(targetIndex++) = edge; + } + return result; + } + + unsigned hash() const + { + unsigned result = 0; + if (!child1()) + return result; + + result += child1().hash(); + + if (!child2()) + return result; + + result *= 3; + result += child2().hash(); + + if (!child3()) + return result; + + result *= 3; + result += child3().hash(); + + return result; + } + + bool operator==(const AdjacencyList& other) const + { + return child1() == other.child1() + && child2() == other.child2() + && child3() == other.child3(); + } + private: Edge m_words[Size]; }; diff --git a/dfg/DFGAllocator.h b/dfg/DFGAllocator.h index 6e20fb3..f380df0 100644 --- a/dfg/DFGAllocator.h +++ b/dfg/DFGAllocator.h @@ -29,7 +29,6 @@ #if ENABLE(DFG_JIT) #include "DFGCommon.h" -#include <wtf/PageAllocationAligned.h> #include <wtf/StdLibExtras.h> namespace JSC { namespace DFG { @@ -50,7 +49,7 @@ public: void* allocate(); // Use placement new to allocate, and avoid using this method. void free(T*); // Call this method to delete; never use 'delete' directly. - void freeAll(); // Only call this if T has a trivial destructor. + void freeAll(); // Only call this if you've either freed everything or if T has a trivial destructor. void reset(); // Like freeAll(), but also returns all memory to the OS. unsigned indexOf(const T*); @@ -70,7 +69,7 @@ private: bool isInThisRegion(const T* pointer) { return static_cast<unsigned>(pointer - data()) < numberOfThingsPerRegion(); } static Region* regionFor(const T* pointer) { return bitwise_cast<Region*>(bitwise_cast<uintptr_t>(pointer) & ~(size() - 1)); } - PageAllocationAligned m_allocation; + void* m_allocation; Allocator* m_allocator; Region* m_next; }; @@ -201,11 +200,9 @@ void* Allocator<T>::allocateSlow() if (logCompilationChanges()) dataLog("Allocating another allocator region.\n"); - - PageAllocationAligned allocation = PageAllocationAligned::allocate(Region::size(), Region::size(), OSAllocator::JSGCHeapPages); - if (!static_cast<bool>(allocation)) - CRASH(); - Region* region = static_cast<Region*>(allocation.base()); + + void* allocation = fastAlignedMalloc(Region::size(), Region::size()); + Region* region = static_cast<Region*>(allocation); region->m_allocation = allocation; region->m_allocator = this; startBumpingIn(region); @@ -222,7 +219,7 @@ void Allocator<T>::freeRegionsStartingAt(typename Allocator<T>::Region* region) { while (region) { Region* nextRegion = region->m_next; - region->m_allocation.deallocate(); + fastAlignedFree(region->m_allocation); region = nextRegion; } } diff --git a/dfg/DFGAnalysis.h b/dfg/DFGAnalysis.h index 2b9d149..0df93d1 100644 --- a/dfg/DFGAnalysis.h +++ b/dfg/DFGAnalysis.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,6 +53,8 @@ public: { if (m_valid) return; + // It's best to run dependent analyses from this method. + static_cast<T*>(this)->computeDependencies(graph); // Set to true early, since the analysis may choose to call its own methods in // compute() and it may want to ASSERT() validity in those methods. m_valid = true; @@ -61,6 +63,12 @@ public: bool isValid() const { return m_valid; } + // Override this to compute any dependent analyses. See + // NaturalLoops::computeDependencies(Graph&) for an example. This isn't strictly necessary but + // it makes debug dumps in cases of error work a bit better because this analysis wouldn't yet + // be pretending to be valid. + void computeDependencies(Graph&) { } + private: bool m_valid; }; diff --git a/dfg/DFGArgumentPosition.h b/dfg/DFGArgumentPosition.h index b4e4ade..a6983a7 100644 --- a/dfg/DFGArgumentPosition.h +++ b/dfg/DFGArgumentPosition.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,6 +46,9 @@ public: void addVariable(VariableAccessData* variable) { m_variables.append(variable); + + // We may set this early. Merging it here saves us time in prediction propagation. + variable->mergeShouldNeverUnbox(m_shouldNeverUnbox); } VariableAccessData* someVariable() const @@ -64,7 +67,7 @@ public: bool mergeShouldNeverUnbox(bool shouldNeverUnbox) { - return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox | shouldNeverUnbox); + return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox || shouldNeverUnbox); } bool mergeArgumentPredictionAwareness() @@ -93,7 +96,7 @@ public: bool changed = false; for (unsigned i = 0; i < m_variables.size(); ++i) { VariableAccessData* variable = m_variables[i]->find(); - changed |= checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox | variable->isProfitableToUnbox()); + changed |= checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox || variable->isProfitableToUnbox()); } if (!changed) return false; @@ -123,10 +126,7 @@ public: if (i) out.print(" "); - if (operand.isArgument()) - out.print("arg", operand.toArgument(), "(", VariableAccessDataDump(*graph, variable), ")"); - else - out.print("r", operand.toLocal(), "(", VariableAccessDataDump(*graph, variable), ")"); + out.print(operand, "(", VariableAccessDataDump(*graph, variable), ")"); } out.print("\n"); } diff --git a/dfg/DFGArgumentsEliminationPhase.cpp b/dfg/DFGArgumentsEliminationPhase.cpp new file mode 100644 index 0000000..336a70c --- /dev/null +++ b/dfg/DFGArgumentsEliminationPhase.cpp @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2015 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 "DFGArgumentsEliminationPhase.h" + +#if ENABLE(DFG_JIT) + +#include "BytecodeLivenessAnalysisInlines.h" +#include "DFGArgumentsUtilities.h" +#include "DFGBasicBlockInlines.h" +#include "DFGBlockMapInlines.h" +#include "DFGClobberize.h" +#include "DFGCombinedLiveness.h" +#include "DFGForAllKills.h" +#include "DFGGraph.h" +#include "DFGInsertionSet.h" +#include "DFGLivenessAnalysisPhase.h" +#include "DFGOSRAvailabilityAnalysisPhase.h" +#include "DFGPhase.h" +#include "JSCInlines.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/ListDump.h> + +namespace JSC { namespace DFG { + +namespace { + +bool verbose = false; + +class ArgumentsEliminationPhase : public Phase { +public: + ArgumentsEliminationPhase(Graph& graph) + : Phase(graph, "arguments elimination") + { + } + + bool run() + { + // For now this phase only works on SSA. This could be changed; we could have a block-local + // version over LoadStore. + DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA); + + if (verbose) { + dataLog("Graph before arguments elimination:\n"); + m_graph.dump(); + } + + identifyCandidates(); + if (m_candidates.isEmpty()) + return false; + + eliminateCandidatesThatEscape(); + if (m_candidates.isEmpty()) + return false; + + eliminateCandidatesThatInterfere(); + if (m_candidates.isEmpty()) + return false; + + transform(); + + return true; + } + +private: + // Just finds nodes that we know how to work with. + void identifyCandidates() + { + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + switch (node->op()) { + case CreateDirectArguments: + case CreateClonedArguments: + m_candidates.add(node); + break; + + case CreateScopedArguments: + // FIXME: We could handle this if it wasn't for the fact that scoped arguments are + // always stored into the activation. + // https://bugs.webkit.org/show_bug.cgi?id=143072 and + // https://bugs.webkit.org/show_bug.cgi?id=143073 + break; + + default: + break; + } + } + } + + if (verbose) + dataLog("Candidates: ", listDump(m_candidates), "\n"); + } + + // Look for escaping sites, and remove from the candidates set if we see an escape. + void eliminateCandidatesThatEscape() + { + auto escape = [&] (Edge edge) { + if (!edge) + return; + m_candidates.remove(edge.node()); + }; + + auto escapeBasedOnArrayMode = [&] (ArrayMode mode, Edge edge) { + switch (mode.type()) { + case Array::DirectArguments: + if (edge->op() != CreateDirectArguments) + escape(edge); + break; + + case Array::Int32: + case Array::Double: + case Array::Contiguous: + if (edge->op() != CreateClonedArguments) + escape(edge); + break; + + default: + escape(edge); + break; + } + }; + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + switch (node->op()) { + case GetFromArguments: + DFG_ASSERT(m_graph, node, node->child1()->op() == CreateDirectArguments); + break; + + case GetByVal: + escapeBasedOnArrayMode(node->arrayMode(), node->child1()); + escape(node->child2()); + escape(node->child3()); + break; + + case GetArrayLength: + escapeBasedOnArrayMode(node->arrayMode(), node->child1()); + escape(node->child2()); + break; + + case LoadVarargs: + break; + + case CallVarargs: + case ConstructVarargs: + escape(node->child1()); + escape(node->child3()); + break; + + case Check: + m_graph.doToChildren( + node, + [&] (Edge edge) { + if (edge.willNotHaveCheck()) + return; + + if (alreadyChecked(edge.useKind(), SpecObject)) + return; + + escape(edge); + }); + break; + + case MovHint: + case PutHint: + break; + + case GetButterfly: + // This barely works. The danger is that the GetButterfly is used by something that + // does something escaping to a candidate. Fortunately, the only butterfly-using ops + // that we exempt here also use the candidate directly. If there ever was a + // butterfly-using op that we wanted to exempt, then we'd have to look at the + // butterfly's child and check if it's a candidate. + break; + + case CheckArray: + escapeBasedOnArrayMode(node->arrayMode(), node->child1()); + break; + + // FIXME: For cloned arguments, we'd like to allow GetByOffset on length to not be + // an escape. + // https://bugs.webkit.org/show_bug.cgi?id=143074 + + // FIXME: We should be able to handle GetById/GetByOffset on callee. + // https://bugs.webkit.org/show_bug.cgi?id=143075 + + default: + m_graph.doToChildren(node, escape); + break; + } + } + } + + if (verbose) + dataLog("After escape analysis: ", listDump(m_candidates), "\n"); + } + + // Anywhere that a candidate is live (in bytecode or in DFG), check if there is a chance of + // interference between the stack area that the arguments object copies from and the arguments + // object's payload. Conservatively this means that the stack region doesn't get stored to. + void eliminateCandidatesThatInterfere() + { + performLivenessAnalysis(m_graph); + performOSRAvailabilityAnalysis(m_graph); + m_graph.initializeNodeOwners(); + CombinedLiveness combinedLiveness(m_graph); + + BlockMap<Operands<bool>> clobberedByBlock(m_graph); + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + Operands<bool>& clobberedByThisBlock = clobberedByBlock[block]; + clobberedByThisBlock = Operands<bool>(OperandsLike, m_graph.block(0)->variablesAtHead); + for (Node* node : *block) { + clobberize( + m_graph, node, NoOpClobberize(), + [&] (AbstractHeap heap) { + if (heap.kind() != Stack) { + ASSERT(!heap.overlaps(Stack)); + return; + } + ASSERT(!heap.payload().isTop()); + VirtualRegister reg(heap.payload().value32()); + clobberedByThisBlock.operand(reg) = true; + }, + NoOpClobberize()); + } + } + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + // Stop if we've already removed all candidates. + if (m_candidates.isEmpty()) + return; + + // Ignore blocks that don't write to the stack. + bool writesToStack = false; + for (unsigned i = clobberedByBlock[block].size(); i--;) { + if (clobberedByBlock[block][i]) { + writesToStack = true; + break; + } + } + if (!writesToStack) + continue; + + forAllKillsInBlock( + m_graph, combinedLiveness, block, + [&] (unsigned nodeIndex, Node* candidate) { + if (!m_candidates.contains(candidate)) + return; + + // Check if this block has any clobbers that affect this candidate. This is a fairly + // fast check. + bool isClobberedByBlock = false; + Operands<bool>& clobberedByThisBlock = clobberedByBlock[block]; + + if (InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame) { + if (inlineCallFrame->isVarargs()) { + isClobberedByBlock |= clobberedByThisBlock.operand( + inlineCallFrame->stackOffset + JSStack::ArgumentCount); + } + + if (!isClobberedByBlock || inlineCallFrame->isClosureCall) { + isClobberedByBlock |= clobberedByThisBlock.operand( + inlineCallFrame->stackOffset + JSStack::Callee); + } + + if (!isClobberedByBlock) { + for (unsigned i = 0; i < inlineCallFrame->arguments.size() - 1; ++i) { + VirtualRegister reg = + VirtualRegister(inlineCallFrame->stackOffset) + + CallFrame::argumentOffset(i); + if (clobberedByThisBlock.operand(reg)) { + isClobberedByBlock = true; + break; + } + } + } + } else { + // We don't include the ArgumentCount or Callee in this case because we can be + // damn sure that this won't be clobbered. + for (unsigned i = 1; i < static_cast<unsigned>(codeBlock()->numParameters()); ++i) { + if (clobberedByThisBlock.argument(i)) { + isClobberedByBlock = true; + break; + } + } + } + + if (!isClobberedByBlock) + return; + + // Check if we can immediately eliminate this candidate. If the block has a clobber + // for this arguments allocation, and we'd have to examine every node in the block, + // then we can just eliminate the candidate. + if (nodeIndex == block->size() && candidate->owner != block) { + m_candidates.remove(candidate); + return; + } + + // This loop considers all nodes up to the nodeIndex, excluding the nodeIndex. + while (nodeIndex--) { + Node* node = block->at(nodeIndex); + if (node == candidate) + break; + + bool found = false; + clobberize( + m_graph, node, NoOpClobberize(), + [&] (AbstractHeap heap) { + if (heap.kind() == Stack && !heap.payload().isTop()) { + if (argumentsInvolveStackSlot(candidate, VirtualRegister(heap.payload().value32()))) + found = true; + return; + } + if (heap.overlaps(Stack)) + found = true; + }, + NoOpClobberize()); + + if (found) { + m_candidates.remove(candidate); + return; + } + } + }); + } + + // Q: How do we handle OSR exit with a live PhantomArguments at a point where the inline call + // frame is dead? A: Naively we could say that PhantomArguments must escape the stack slots. But + // that would break PutStack sinking, which in turn would break object allocation sinking, in + // cases where we have a varargs call to an otherwise pure method. So, we need something smarter. + // For the outermost arguments, we just have a PhantomArguments that magically knows that it + // should load the arguments from the call frame. For the inline arguments, we have the heap map + // in the availabiltiy map track each possible inline argument as a promoted heap location. If the + // PutStacks for those arguments aren't sunk, those heap locations will map to very trivial + // availabilities (they will be flush availabilities). But if sinking happens then those + // availabilities may become whatever. OSR exit should be able to handle this quite naturally, + // since those availabilities speak of the stack before the optimizing compiler stack frame is + // torn down. + + if (verbose) + dataLog("After interference analysis: ", listDump(m_candidates), "\n"); + } + + void transform() + { + InsertionSet insertionSet(m_graph); + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + + auto getArrayLength = [&] (Node* candidate) -> Node* { + return emitCodeToGetArgumentsArrayLength( + insertionSet, candidate, nodeIndex, node->origin); + }; + + switch (node->op()) { + case CreateDirectArguments: + if (!m_candidates.contains(node)) + break; + + node->setOpAndDefaultFlags(PhantomDirectArguments); + break; + + case CreateClonedArguments: + if (!m_candidates.contains(node)) + break; + + node->setOpAndDefaultFlags(PhantomClonedArguments); + break; + + case GetFromArguments: { + Node* candidate = node->child1().node(); + if (!m_candidates.contains(candidate)) + break; + + DFG_ASSERT( + m_graph, node, + node->child1()->op() == CreateDirectArguments + || node->child1()->op() == PhantomDirectArguments); + VirtualRegister reg = + virtualRegisterForArgument(node->capturedArgumentsOffset().offset() + 1) + + node->origin.semantic.stackOffset(); + StackAccessData* data = m_graph.m_stackAccessData.add(reg, FlushedJSValue); + node->convertToGetStack(data); + break; + } + + case GetArrayLength: { + Node* candidate = node->child1().node(); + if (!m_candidates.contains(candidate)) + break; + + // Meh, this is kind of hackish - we use an Identity so that we can reuse the + // getArrayLength() helper. + node->convertToIdentityOn(getArrayLength(candidate)); + break; + } + + case GetByVal: { + // FIXME: For ClonedArguments, we would have already done a separate bounds check. + // This code will cause us to have two bounds checks - the original one that we + // already factored out in SSALoweringPhase, and the new one we insert here, which is + // often implicitly part of GetMyArgumentByVal. LLVM will probably eliminate the + // second bounds check, but still - that's just silly. + // https://bugs.webkit.org/show_bug.cgi?id=143076 + + Node* candidate = node->child1().node(); + if (!m_candidates.contains(candidate)) + break; + + Node* result = nullptr; + if (node->child2()->isInt32Constant()) { + unsigned index = node->child2()->asUInt32(); + InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame; + + bool safeToGetStack; + if (inlineCallFrame) + safeToGetStack = index < inlineCallFrame->arguments.size() - 1; + else { + safeToGetStack = + index < static_cast<unsigned>(codeBlock()->numParameters()) - 1; + } + if (safeToGetStack) { + StackAccessData* data; + VirtualRegister arg = virtualRegisterForArgument(index + 1); + if (inlineCallFrame) + arg += inlineCallFrame->stackOffset; + data = m_graph.m_stackAccessData.add(arg, FlushedJSValue); + + if (!inlineCallFrame || inlineCallFrame->isVarargs() + || index >= inlineCallFrame->arguments.size() - 1) { + insertionSet.insertNode( + nodeIndex, SpecNone, CheckInBounds, node->origin, + node->child2(), Edge(getArrayLength(candidate), Int32Use)); + } + + result = insertionSet.insertNode( + nodeIndex, node->prediction(), GetStack, node->origin, OpInfo(data)); + } + } + + if (!result) { + result = insertionSet.insertNode( + nodeIndex, node->prediction(), GetMyArgumentByVal, node->origin, + node->child1(), node->child2()); + } + + // Need to do this because we may have a data format conversion here. + node->convertToIdentityOn(result); + break; + } + + case LoadVarargs: { + Node* candidate = node->child1().node(); + if (!m_candidates.contains(candidate)) + break; + + LoadVarargsData* varargsData = node->loadVarargsData(); + InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame; + if (inlineCallFrame + && !inlineCallFrame->isVarargs() + && inlineCallFrame->arguments.size() - varargsData->offset <= varargsData->limit) { + Node* argumentCount = insertionSet.insertConstant( + nodeIndex, node->origin, + jsNumber(inlineCallFrame->arguments.size() - varargsData->offset)); + insertionSet.insertNode( + nodeIndex, SpecNone, MovHint, node->origin, + OpInfo(varargsData->count.offset()), Edge(argumentCount)); + insertionSet.insertNode( + nodeIndex, SpecNone, PutStack, node->origin, + OpInfo(m_graph.m_stackAccessData.add(varargsData->count, FlushedInt32)), + Edge(argumentCount, Int32Use)); + + DFG_ASSERT(m_graph, node, varargsData->limit - 1 >= varargsData->mandatoryMinimum); + // Define our limit to not include "this", since that's a bit easier to reason about. + unsigned limit = varargsData->limit - 1; + Node* undefined = nullptr; + for (unsigned storeIndex = 0; storeIndex < limit; ++storeIndex) { + // First determine if we have an element we can load, and load it if + // possible. + + unsigned loadIndex = storeIndex + varargsData->offset; + + Node* value; + if (loadIndex + 1 < inlineCallFrame->arguments.size()) { + VirtualRegister reg = + virtualRegisterForArgument(loadIndex + 1) + + inlineCallFrame->stackOffset; + StackAccessData* data = m_graph.m_stackAccessData.add( + reg, FlushedJSValue); + + value = insertionSet.insertNode( + nodeIndex, SpecNone, GetStack, node->origin, OpInfo(data)); + } else { + // FIXME: We shouldn't have to store anything if + // storeIndex >= varargsData->mandatoryMinimum, but we will still + // have GetStacks in that range. So if we don't do the stores, we'll + // have degenerate IR: we'll have GetStacks of something that didn't + // have PutStacks. + // https://bugs.webkit.org/show_bug.cgi?id=147434 + + if (!undefined) { + undefined = insertionSet.insertConstant( + nodeIndex, node->origin, jsUndefined()); + } + value = undefined; + } + + // Now that we have a value, store it. + + VirtualRegister reg = varargsData->start + storeIndex; + StackAccessData* data = + m_graph.m_stackAccessData.add(reg, FlushedJSValue); + + insertionSet.insertNode( + nodeIndex, SpecNone, MovHint, node->origin, OpInfo(reg.offset()), + Edge(value)); + insertionSet.insertNode( + nodeIndex, SpecNone, PutStack, node->origin, OpInfo(data), + Edge(value)); + } + + node->remove(); + break; + } + + node->setOpAndDefaultFlags(ForwardVarargs); + break; + } + + case CallVarargs: + case ConstructVarargs: { + Node* candidate = node->child2().node(); + if (!m_candidates.contains(candidate)) + break; + + CallVarargsData* varargsData = node->callVarargsData(); + InlineCallFrame* inlineCallFrame = candidate->origin.semantic.inlineCallFrame; + if (inlineCallFrame && !inlineCallFrame->isVarargs()) { + Vector<Node*> arguments; + for (unsigned i = 1 + varargsData->firstVarArgOffset; i < inlineCallFrame->arguments.size(); ++i) { + StackAccessData* data = m_graph.m_stackAccessData.add( + virtualRegisterForArgument(i) + inlineCallFrame->stackOffset, + FlushedJSValue); + + Node* value = insertionSet.insertNode( + nodeIndex, SpecNone, GetStack, node->origin, OpInfo(data)); + + arguments.append(value); + } + + unsigned firstChild = m_graph.m_varArgChildren.size(); + m_graph.m_varArgChildren.append(node->child1()); + m_graph.m_varArgChildren.append(node->child3()); + for (Node* argument : arguments) + m_graph.m_varArgChildren.append(Edge(argument)); + node->setOpAndDefaultFlags( + node->op() == CallVarargs ? Call : Construct); + node->children = AdjacencyList( + AdjacencyList::Variable, + firstChild, m_graph.m_varArgChildren.size() - firstChild); + break; + } + + node->setOpAndDefaultFlags( + node->op() == CallVarargs ? CallForwardVarargs : ConstructForwardVarargs); + break; + } + + case CheckArray: + case GetButterfly: { + if (!m_candidates.contains(node->child1().node())) + break; + node->remove(); + break; + } + + default: + break; + } + } + + insertionSet.execute(block); + } + } + + HashSet<Node*> m_candidates; +}; + +} // anonymous namespace + +bool performArgumentsElimination(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Arguments Elimination Phase"); + return runPhase<ArgumentsEliminationPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGArgumentsEliminationPhase.h b/dfg/DFGArgumentsEliminationPhase.h new file mode 100644 index 0000000..520b228 --- /dev/null +++ b/dfg/DFGArgumentsEliminationPhase.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 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 DFGArgumentsEliminationPhase_h +#define DFGArgumentsEliminationPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Eliminates allocations of the Arguments-class objects when it can prove that the object doesn't escape +// and none of the arguments are mutated (either via the object or via the stack). + +bool performArgumentsElimination(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGArgumentsEliminationPhase_h + diff --git a/dfg/DFGArgumentsSimplificationPhase.cpp b/dfg/DFGArgumentsSimplificationPhase.cpp deleted file mode 100644 index 29572b9..0000000 --- a/dfg/DFGArgumentsSimplificationPhase.cpp +++ /dev/null @@ -1,797 +0,0 @@ -/* - * Copyright (C) 2012, 2013 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 "DFGArgumentsSimplificationPhase.h" - -#if ENABLE(DFG_JIT) - -#include "DFGBasicBlock.h" -#include "DFGGraph.h" -#include "DFGInsertionSet.h" -#include "DFGPhase.h" -#include "DFGValidate.h" -#include "DFGVariableAccessDataDump.h" -#include "JSCInlines.h" -#include <wtf/HashSet.h> -#include <wtf/HashMap.h> - -namespace JSC { namespace DFG { - -namespace { - -struct ArgumentsAliasingData { - InlineCallFrame* callContext; - bool callContextSet; - bool multipleCallContexts; - - bool assignedFromArguments; - bool assignedFromManyThings; - - bool escapes; - - ArgumentsAliasingData() - : callContext(0) - , callContextSet(false) - , multipleCallContexts(false) - , assignedFromArguments(false) - , assignedFromManyThings(false) - , escapes(false) - { - } - - void mergeCallContext(InlineCallFrame* newCallContext) - { - if (multipleCallContexts) - return; - - if (!callContextSet) { - callContext = newCallContext; - callContextSet = true; - return; - } - - if (callContext == newCallContext) - return; - - multipleCallContexts = true; - } - - bool callContextIsValid() - { - return callContextSet && !multipleCallContexts; - } - - void mergeArgumentsAssignment() - { - assignedFromArguments = true; - } - - void mergeNonArgumentsAssignment() - { - assignedFromManyThings = true; - } - - bool argumentsAssignmentIsValid() - { - return assignedFromArguments && !assignedFromManyThings; - } - - bool isValid() - { - return callContextIsValid() && argumentsAssignmentIsValid() && !escapes; - } -}; - -} // end anonymous namespace - -class ArgumentsSimplificationPhase : public Phase { -public: - ArgumentsSimplificationPhase(Graph& graph) - : Phase(graph, "arguments simplification") - { - } - - bool run() - { - if (!m_graph.m_hasArguments) - return false; - - bool changed = false; - - // Record which arguments are known to escape no matter what. - for (InlineCallFrameSet::iterator iter = m_graph.m_plan.inlineCallFrames->begin(); !!iter; ++iter) - pruneObviousArgumentCreations(*iter); - pruneObviousArgumentCreations(0); // the machine call frame. - - // Create data for variable access datas that we will want to analyze. - for (unsigned i = m_graph.m_variableAccessData.size(); i--;) { - VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i]; - if (!variableAccessData->isRoot()) - continue; - if (variableAccessData->isCaptured()) - continue; - m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData()); - } - - // Figure out which variables are live, using a conservative approximation of - // liveness. - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - Node* node = block->at(indexInBlock); - switch (node->op()) { - case GetLocal: - case Flush: - case PhantomLocal: - m_isLive.add(node->variableAccessData()); - break; - default: - break; - } - } - } - - // Figure out which variables alias the arguments and nothing else, and are - // used only for GetByVal and GetArrayLength accesses. At the same time, - // identify uses of CreateArguments that are not consistent with the arguments - // being aliased only to variables that satisfy these constraints. - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - Node* node = block->at(indexInBlock); - switch (node->op()) { - case CreateArguments: { - // Ignore this op. If we see a lone CreateArguments then we want to - // completely ignore it because: - // 1) The default would be to see that the child is a GetLocal on the - // arguments register and conclude that we have an arguments escape. - // 2) The fact that a CreateArguments exists does not mean that it - // will continue to exist after we're done with this phase. As far - // as this phase is concerned, a CreateArguments only "exists" if it - // is used in a manner that necessitates its existance. - break; - } - - case TearOffArguments: { - // Ignore arguments tear off, because it's only relevant if we actually - // need to create the arguments. - break; - } - - case SetLocal: { - Node* source = node->child1().node(); - VariableAccessData* variableAccessData = node->variableAccessData(); - VirtualRegister argumentsRegister = - m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic); - if (source->op() != CreateArguments && source->op() != PhantomArguments) { - // Make sure that the source of the SetLocal knows that if it's - // a variable that we think is aliased to the arguments, then it - // may escape at this point. In future, we could track transitive - // aliasing. But not yet. - observeBadArgumentsUse(source); - - // If this is an assignment to the arguments register, then - // pretend as if the arguments were created. We don't want to - // optimize code that explicitly assigns to the arguments, - // because that seems too ugly. - - // But, before getting rid of CreateArguments, we will have - // an assignment to the arguments registers with JSValue(). - // That's because CSE will refuse to get rid of the - // init_lazy_reg since it treats CreateArguments as reading - // local variables. That could be fixed, but it's easier to - // work around this here. - if (source->op() == JSConstant - && !source->valueOfJSConstant(codeBlock())) - break; - - // If the variable is totally dead, then ignore it. - if (!m_isLive.contains(variableAccessData)) - break; - - if (argumentsRegister.isValid() - && (variableAccessData->local() == argumentsRegister - || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) { - m_createsArguments.add(node->origin.semantic.inlineCallFrame); - break; - } - - if (variableAccessData->isCaptured()) - break; - - // Make sure that if it's a variable that we think is aliased to - // the arguments, that we know that it might actually not be. - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - data.mergeNonArgumentsAssignment(); - data.mergeCallContext(node->origin.semantic.inlineCallFrame); - break; - } - if (argumentsRegister.isValid() - && (variableAccessData->local() == argumentsRegister - || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) { - if (node->origin.semantic.inlineCallFrame == source->origin.semantic.inlineCallFrame) - break; - m_createsArguments.add(source->origin.semantic.inlineCallFrame); - break; - } - if (variableAccessData->isCaptured()) { - m_createsArguments.add(source->origin.semantic.inlineCallFrame); - break; - } - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - data.mergeArgumentsAssignment(); - // This ensures that the variable's uses are in the same context as - // the arguments it is aliasing. - data.mergeCallContext(node->origin.semantic.inlineCallFrame); - data.mergeCallContext(source->origin.semantic.inlineCallFrame); - break; - } - - case GetLocal: - case Phi: /* FIXME: https://bugs.webkit.org/show_bug.cgi?id=108555 */ { - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured()) - break; - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - data.mergeCallContext(node->origin.semantic.inlineCallFrame); - break; - } - - case Flush: { - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured()) - break; - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - data.mergeCallContext(node->origin.semantic.inlineCallFrame); - - // If a variable is used in a flush then by definition it escapes. - data.escapes = true; - break; - } - - case SetArgument: { - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured()) - break; - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - data.mergeNonArgumentsAssignment(); - data.mergeCallContext(node->origin.semantic.inlineCallFrame); - break; - } - - case GetByVal: { - if (node->arrayMode().type() != Array::Arguments) { - observeBadArgumentsUses(node); - break; - } - - // That's so awful and pretty much impossible since it would - // imply that the arguments were predicted integer, but it's - // good to be defensive and thorough. - observeBadArgumentsUse(node->child2().node()); - observeProperArgumentsUse(node, node->child1()); - break; - } - - case GetArrayLength: { - if (node->arrayMode().type() != Array::Arguments) { - observeBadArgumentsUses(node); - break; - } - - observeProperArgumentsUse(node, node->child1()); - break; - } - - case Phantom: - case HardPhantom: - // We don't care about phantom uses, since phantom uses are all about - // just keeping things alive for OSR exit. If something - like the - // CreateArguments - is just being kept alive, then this transformation - // will not break this, since the Phantom will now just keep alive a - // PhantomArguments and OSR exit will still do the right things. - break; - - case CheckStructure: - case StructureTransitionWatchpoint: - case CheckArray: - // We don't care about these because if we get uses of the relevant - // variable then we can safely get rid of these, too. This of course - // relies on there not being any information transferred by the CFA - // from a CheckStructure on one variable to the information about the - // structures of another variable. - break; - - case MovHint: - // We don't care about MovHints at all, since they represent what happens - // in bytecode. We rematerialize arguments objects on OSR exit anyway. - break; - - default: - observeBadArgumentsUses(node); - break; - } - } - } - - // Now we know which variables are aliased to arguments. But if any of them are - // found to have escaped, or were otherwise invalidated, then we need to mark - // the arguments as requiring creation. This is a property of SetLocals to - // variables that are neither the correct arguments register nor are marked as - // being arguments-aliased. - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - Node* node = block->at(indexInBlock); - if (node->op() != SetLocal) - continue; - Node* source = node->child1().node(); - if (source->op() != CreateArguments) - continue; - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured()) { - // The captured case would have already been taken care of in the - // previous pass. - continue; - } - - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - if (data.isValid()) - continue; - - m_createsArguments.add(source->origin.semantic.inlineCallFrame); - } - } - - InsertionSet insertionSet(m_graph); - - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); indexInBlock++) { - Node* node = block->at(indexInBlock); - switch (node->op()) { - case SetLocal: { - Node* source = node->child1().node(); - if (source->op() != CreateArguments) - break; - - if (m_createsArguments.contains(source->origin.semantic.inlineCallFrame)) - break; - - VariableAccessData* variableAccessData = node->variableAccessData(); - - if (variableAccessData->mergeIsArgumentsAlias(true)) { - changed = true; - - // Make sure that the variable knows, that it may now hold non-cell values. - variableAccessData->predict(SpecEmpty); - } - - // Make sure that the SetLocal doesn't check that the input is a Cell. - if (node->child1().useKind() != UntypedUse) { - node->child1().setUseKind(UntypedUse); - changed = true; - } - break; - } - - case Flush: { - VariableAccessData* variableAccessData = node->variableAccessData(); - - if (variableAccessData->isCaptured() - || !m_argumentsAliasing.find(variableAccessData)->value.isValid() - || m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) - break; - - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - case Phantom: - case HardPhantom: { - // It's highly likely that we will have a Phantom referencing either - // CreateArguments, or a local op for the arguments register, or a - // local op for an arguments-aliased variable. In any of those cases, - // we should remove the phantom reference, since: - // 1) Phantoms only exist to aid OSR exit. But arguments simplification - // has its own OSR exit story, which is to inform OSR exit to reify - // the arguments as necessary. - // 2) The Phantom may keep the CreateArguments node alive, which is - // precisely what we don't want. - for (unsigned i = 0; i < AdjacencyList::Size; ++i) - detypeArgumentsReferencingPhantomChild(node, i); - break; - } - - case CheckStructure: - case StructureTransitionWatchpoint: - case CheckArray: { - // We can just get rid of this node, if it references a phantom argument. - if (!isOKToOptimize(node->child1().node())) - break; - node->convertToPhantom(); - break; - } - - case GetByVal: { - if (node->arrayMode().type() != Array::Arguments) - break; - - // This can be simplified to GetMyArgumentByVal if we know that - // it satisfies either condition (1) or (2): - // 1) Its first child is a valid ArgumentsAliasingData and the - // InlineCallFrame* is not marked as creating arguments. - // 2) Its first child is CreateArguments and its InlineCallFrame* - // is not marked as creating arguments. - - if (!isOKToOptimize(node->child1().node())) - break; - - insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, node->origin, node->child1()); - - node->child1() = node->child2(); - node->child2() = Edge(); - node->setOpAndDefaultFlags(GetMyArgumentByVal); - changed = true; - --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal. - break; - } - - case GetArrayLength: { - if (node->arrayMode().type() != Array::Arguments) - break; - - if (!isOKToOptimize(node->child1().node())) - break; - - insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, node->origin, node->child1()); - - node->child1() = Edge(); - node->setOpAndDefaultFlags(GetMyArgumentsLength); - changed = true; - --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength. - break; - } - - case GetMyArgumentsLength: - case GetMyArgumentsLengthSafe: { - if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) { - ASSERT(node->op() == GetMyArgumentsLengthSafe); - break; - } - if (node->op() == GetMyArgumentsLengthSafe) { - node->setOp(GetMyArgumentsLength); - changed = true; - } - - NodeOrigin origin = node->origin; - if (!origin.semantic.inlineCallFrame) - break; - - // We know exactly what this will return. But only after we have checked - // that nobody has escaped our arguments. - insertionSet.insertNode( - indexInBlock, SpecNone, CheckArgumentsNotCreated, origin); - - m_graph.convertToConstant( - node, jsNumber(origin.semantic.inlineCallFrame->arguments.size() - 1)); - changed = true; - break; - } - - case GetMyArgumentByVal: - case GetMyArgumentByValSafe: { - if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) { - ASSERT(node->op() == GetMyArgumentByValSafe); - break; - } - if (node->op() == GetMyArgumentByValSafe) { - node->setOp(GetMyArgumentByVal); - changed = true; - } - if (!node->origin.semantic.inlineCallFrame) - break; - if (!node->child1()->hasConstant()) - break; - JSValue value = node->child1()->valueOfJSConstant(codeBlock()); - if (!value.isInt32()) - break; - int32_t index = value.asInt32(); - if (index < 0 - || static_cast<size_t>(index + 1) >= - node->origin.semantic.inlineCallFrame->arguments.size()) - break; - - // We know which argument this is accessing. But only after we have checked - // that nobody has escaped our arguments. We also need to ensure that the - // index is kept alive. That's somewhat pointless since it's a constant, but - // it's important because this is one of those invariants that we like to - // have in the DFG. Note finally that we use the GetLocalUnlinked opcode - // here, since this is being done _after_ the prediction propagation phase - // has run - therefore it makes little sense to link the GetLocal operation - // into the VariableAccessData and Phi graphs. - - NodeOrigin origin = node->origin; - AdjacencyList children = node->children; - - node->convertToGetLocalUnlinked( - VirtualRegister( - origin.semantic.inlineCallFrame->stackOffset + - m_graph.baselineCodeBlockFor(origin.semantic)->argumentIndexAfterCapture(index))); - - insertionSet.insertNode( - indexInBlock, SpecNone, CheckArgumentsNotCreated, origin); - insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, origin, children); - - changed = true; - break; - } - - case TearOffArguments: { - if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) - continue; - - node->convertToPhantom(); - break; - } - - default: - break; - } - } - insertionSet.execute(block); - } - - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - Node* node = block->at(indexInBlock); - if (node->op() != CreateArguments) - continue; - // If this is a CreateArguments for an InlineCallFrame* that does - // not create arguments, then replace it with a PhantomArguments. - // PhantomArguments is a non-executing node that just indicates - // that the node should be reified as an arguments object on OSR - // exit. - if (m_createsArguments.contains(node->origin.semantic.inlineCallFrame)) - continue; - insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, node->origin, node->children); - node->setOpAndDefaultFlags(PhantomArguments); - node->children.reset(); - changed = true; - } - insertionSet.execute(block); - } - - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - Node* node = block->at(indexInBlock); - if (node->op() != Phantom) - continue; - for (unsigned i = 0; i < AdjacencyList::Size; ++i) - detypeArgumentsReferencingPhantomChild(node, i); - } - } - - if (changed) { - m_graph.dethread(); - m_graph.m_form = LoadStore; - } - - return changed; - } - -private: - HashSet<InlineCallFrame*, - DefaultHash<InlineCallFrame*>::Hash, - NullableHashTraits<InlineCallFrame*>> m_createsArguments; - HashMap<VariableAccessData*, ArgumentsAliasingData, - DefaultHash<VariableAccessData*>::Hash, - NullableHashTraits<VariableAccessData*>> m_argumentsAliasing; - HashSet<VariableAccessData*> m_isLive; - - void pruneObviousArgumentCreations(InlineCallFrame* inlineCallFrame) - { - ScriptExecutable* executable = m_graph.executableFor(inlineCallFrame); - if (m_graph.m_executablesWhoseArgumentsEscaped.contains(executable) - || executable->isStrictMode()) - m_createsArguments.add(inlineCallFrame); - } - - void observeBadArgumentsUse(Node* node) - { - if (!node) - return; - - switch (node->op()) { - case CreateArguments: { - m_createsArguments.add(node->origin.semantic.inlineCallFrame); - break; - } - - case GetLocal: { - VirtualRegister argumentsRegister = - m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic); - if (argumentsRegister.isValid() - && (node->local() == argumentsRegister - || node->local() == unmodifiedArgumentsRegister(argumentsRegister))) { - m_createsArguments.add(node->origin.semantic.inlineCallFrame); - break; - } - - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured()) - break; - - ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value; - data.escapes = true; - break; - } - - default: - break; - } - } - - void observeBadArgumentsUses(Node* node) - { - for (unsigned i = m_graph.numChildren(node); i--;) - observeBadArgumentsUse(m_graph.child(node, i).node()); - } - - void observeProperArgumentsUse(Node* node, Edge edge) - { - if (edge->op() != GetLocal) { - // When can this happen? At least two cases that I can think - // of: - // - // 1) Aliased use of arguments in the same basic block, - // like: - // - // var a = arguments; - // var x = arguments[i]; - // - // 2) If we're accessing arguments we got from the heap! - - if (edge->op() == CreateArguments - && node->origin.semantic.inlineCallFrame - != edge->origin.semantic.inlineCallFrame) - m_createsArguments.add(edge->origin.semantic.inlineCallFrame); - - return; - } - - VariableAccessData* variableAccessData = edge->variableAccessData(); - if (edge->local() == m_graph.uncheckedArgumentsRegisterFor(edge->origin.semantic) - && node->origin.semantic.inlineCallFrame != edge->origin.semantic.inlineCallFrame) { - m_createsArguments.add(edge->origin.semantic.inlineCallFrame); - return; - } - - if (variableAccessData->isCaptured()) - return; - - ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value; - data.mergeCallContext(node->origin.semantic.inlineCallFrame); - } - - bool isOKToOptimize(Node* source) - { - if (m_createsArguments.contains(source->origin.semantic.inlineCallFrame)) - return false; - - switch (source->op()) { - case GetLocal: { - VariableAccessData* variableAccessData = source->variableAccessData(); - VirtualRegister argumentsRegister = - m_graph.uncheckedArgumentsRegisterFor(source->origin.semantic); - if (!argumentsRegister.isValid()) - break; - if (argumentsRegister == variableAccessData->local()) - return true; - if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local()) - return true; - if (variableAccessData->isCaptured()) - break; - ArgumentsAliasingData& data = - m_argumentsAliasing.find(variableAccessData)->value; - if (!data.isValid()) - break; - - return true; - } - - case CreateArguments: { - return true; - } - - default: - break; - } - - return false; - } - - void detypeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex) - { - Edge edge = node->children.child(edgeIndex); - if (!edge) - return; - - switch (edge->op()) { - case GetLocal: { - VariableAccessData* variableAccessData = edge->variableAccessData(); - if (!variableAccessData->isArgumentsAlias()) - break; - node->children.child(edgeIndex).setUseKind(UntypedUse); - break; - } - - case PhantomArguments: { - node->children.child(edgeIndex).setUseKind(UntypedUse); - break; - } - - default: - break; - } - } -}; - -bool performArgumentsSimplification(Graph& graph) -{ - SamplingRegion samplingRegion("DFG Arguments Simplification Phase"); - return runPhase<ArgumentsSimplificationPhase>(graph); -} - -} } // namespace JSC::DFG - -#endif // ENABLE(DFG_JIT) - - diff --git a/dfg/DFGArgumentsUtilities.cpp b/dfg/DFGArgumentsUtilities.cpp new file mode 100644 index 0000000..5d512b1 --- /dev/null +++ b/dfg/DFGArgumentsUtilities.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 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 "DFGArgumentsUtilities.h" + +#if ENABLE(DFG_JIT) + +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +bool argumentsInvolveStackSlot(InlineCallFrame* inlineCallFrame, VirtualRegister reg) +{ + if (!inlineCallFrame) + return (reg.isArgument() && reg.toArgument()) || reg.isHeader(); + + if (inlineCallFrame->isClosureCall + && reg == VirtualRegister(inlineCallFrame->stackOffset + JSStack::Callee)) + return true; + + if (inlineCallFrame->isVarargs() + && reg == VirtualRegister(inlineCallFrame->stackOffset + JSStack::ArgumentCount)) + return true; + + unsigned numArguments = inlineCallFrame->arguments.size() - 1; + VirtualRegister argumentStart = + VirtualRegister(inlineCallFrame->stackOffset) + CallFrame::argumentOffset(0); + return reg >= argumentStart && reg < argumentStart + numArguments; +} + +bool argumentsInvolveStackSlot(Node* candidate, VirtualRegister reg) +{ + return argumentsInvolveStackSlot(candidate->origin.semantic.inlineCallFrame, reg); +} + +Node* emitCodeToGetArgumentsArrayLength( + InsertionSet& insertionSet, Node* arguments, unsigned nodeIndex, NodeOrigin origin) +{ + Graph& graph = insertionSet.graph(); + + DFG_ASSERT( + graph, arguments, + arguments->op() == CreateDirectArguments || arguments->op() == CreateScopedArguments + || arguments->op() == CreateClonedArguments || arguments->op() == PhantomDirectArguments + || arguments->op() == PhantomClonedArguments); + + InlineCallFrame* inlineCallFrame = arguments->origin.semantic.inlineCallFrame; + + if (inlineCallFrame && !inlineCallFrame->isVarargs()) { + return insertionSet.insertConstant( + nodeIndex, origin, jsNumber(inlineCallFrame->arguments.size() - 1)); + } + + Node* argumentCount; + if (!inlineCallFrame) + argumentCount = insertionSet.insertNode(nodeIndex, SpecInt32, GetArgumentCount, origin); + else { + VirtualRegister argumentCountRegister(inlineCallFrame->stackOffset + JSStack::ArgumentCount); + + argumentCount = insertionSet.insertNode( + nodeIndex, SpecInt32, GetStack, origin, + OpInfo(graph.m_stackAccessData.add(argumentCountRegister, FlushedInt32))); + } + + return insertionSet.insertNode( + nodeIndex, SpecInt32, ArithSub, origin, OpInfo(Arith::Unchecked), + Edge(argumentCount, Int32Use), + insertionSet.insertConstantForUse( + nodeIndex, origin, jsNumber(1), Int32Use)); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGDesiredStructureChains.h b/dfg/DFGArgumentsUtilities.h similarity index 70% rename from dfg/DFGDesiredStructureChains.h rename to dfg/DFGArgumentsUtilities.h index 9343710..82bfec3 100644 --- a/dfg/DFGDesiredStructureChains.h +++ b/dfg/DFGArgumentsUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,37 +23,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGDesiredStructureChains_h -#define DFGDesiredStructureChains_h +#ifndef DFGArgumentsUtilities_h +#define DFGArgumentsUtilities_h #if ENABLE(DFG_JIT) -#include "IntendedStructureChain.h" -#include <wtf/Vector.h> +#include "DFGGraph.h" +#include "DFGInsertionSet.h" namespace JSC { namespace DFG { -class DesiredStructureChains { -public: - DesiredStructureChains(); - ~DesiredStructureChains(); - - void addLazily(PassRefPtr<IntendedStructureChain> chain) - { - m_vector.append(chain); - } - - bool areStillValid() const; - - void visitChildren(SlotVisitor&); - -private: - Vector<RefPtr<IntendedStructureChain>> m_vector; -}; +bool argumentsInvolveStackSlot(InlineCallFrame*, VirtualRegister); +bool argumentsInvolveStackSlot(Node* candidate, VirtualRegister); + +Node* emitCodeToGetArgumentsArrayLength( + InsertionSet&, Node* arguments, unsigned nodeIndex, NodeOrigin); } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) -#endif // DFGDesiredStructureChains_h +#endif // DFGArgumentsUtilities_h diff --git a/dfg/DFGArithMode.h b/dfg/DFGArithMode.h index 064f064..4e09ac3 100644 --- a/dfg/DFGArithMode.h +++ b/dfg/DFGArithMode.h @@ -40,6 +40,14 @@ enum Mode { CheckOverflowAndNegativeZero, // Check for both overflow and negative zero. DoOverflow // Up-convert to the smallest type that soundly represents all possible results after input type speculation. }; + +// Define the type of operation the rounding operation will perform. +enum class RoundingMode { + Int32, // The round operation produces a integer and -0 is considered as 0. + Int32WithNegativeZeroCheck, // The round operation produces a integer and checks for -0. + Double // The round operation produce a double. The result can be -0, NaN or (+/-)Infinity. +}; + } // namespace Arith inline bool doesOverflow(Arith::Mode mode) @@ -122,6 +130,16 @@ inline bool subsumes(Arith::Mode earlier, Arith::Mode later) } } +inline bool producesInteger(Arith::RoundingMode mode) +{ + return mode == Arith::RoundingMode::Int32WithNegativeZeroCheck || mode == Arith::RoundingMode::Int32; +} + +inline bool shouldCheckNegativeZero(Arith::RoundingMode mode) +{ + return mode == Arith::RoundingMode::Int32WithNegativeZeroCheck; +} + } } // namespace JSC::DFG namespace WTF { diff --git a/dfg/DFGArrayMode.cpp b/dfg/DFGArrayMode.cpp index 0cbdc7c..b0a4b04 100644 --- a/dfg/DFGArrayMode.cpp +++ b/dfg/DFGArrayMode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -97,6 +97,24 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Int8ArrayMode: + return ArrayMode(Array::Int8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Int16ArrayMode: + return ArrayMode(Array::Int16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Int32ArrayMode: + return ArrayMode(Array::Int32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Uint8ArrayMode: + return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Uint8ClampedArrayMode: + return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Uint16ArrayMode: + return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Uint32ArrayMode: + return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Float32ArrayMode: + return ArrayMode(Array::Float32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); + case Float64ArrayMode: + return ArrayMode(Array::Float64Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); default: if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses(locker)) @@ -133,8 +151,7 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil ArrayMode ArrayMode::refine( Graph& graph, Node* node, - SpeculatedType base, SpeculatedType index, SpeculatedType value, - NodeFlags flags) const + 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 @@ -147,6 +164,10 @@ ArrayMode ArrayMode::refine( if (!isInt32Speculation(index)) return ArrayMode(Array::Generic); + // If we had exited because of an exotic object behavior, then don't try to specialize. + if (graph.hasExitSite(node->origin.semantic, ExoticObjectMode)) + return ArrayMode(Array::Generic); + // Note: our profiling currently doesn't give us good information in case we have // an unlikely control flow path that sets the base to a non-cell value. Value // profiling and prediction propagation will probably tell us that the value is @@ -158,9 +179,6 @@ ArrayMode ArrayMode::refine( // should just trust the array profile. switch (type()) { - case Array::Unprofiled: - return ArrayMode(Array::ForceExit); - case Array::Undecided: if (!value) return withType(Array::ForceExit); @@ -178,25 +196,47 @@ ArrayMode ArrayMode::refine( return withTypeAndConversion(Array::Contiguous, Array::Convert); case Array::Double: - if (flags & NodeBytecodeUsesAsInt) - return withTypeAndConversion(Array::Contiguous, Array::RageConvert); if (!value || isFullNumberSpeculation(value)) return *this; return withTypeAndConversion(Array::Contiguous, Array::Convert); case Array::Contiguous: - if (doesConversion() && (flags & NodeBytecodeUsesAsInt)) - return withConversion(Array::RageConvert); return *this; - + + case Array::Int8Array: + case Array::Int16Array: + case Array::Int32Array: + case Array::Uint8Array: + case Array::Uint8ClampedArray: + case Array::Uint16Array: + case Array::Uint32Array: + case Array::Float32Array: + case Array::Float64Array: + switch (node->op()) { + case PutByVal: + if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds()) + return withSpeculation(Array::OutOfBounds); + return withSpeculation(Array::InBounds); + default: + return withSpeculation(Array::InBounds); + } + return *this; + case Array::Unprofiled: case Array::SelectUsingPredictions: { base &= ~SpecOther; if (isStringSpeculation(base)) return withType(Array::String); - if (isArgumentsSpeculation(base)) - return withType(Array::Arguments); + if (isDirectArgumentsSpeculation(base) || isScopedArgumentsSpeculation(base)) { + // Handle out-of-bounds accesses as generic accesses. + if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds()) + return ArrayMode(Array::Generic); + + if (isDirectArgumentsSpeculation(base)) + return withType(Array::DirectArguments); + return withType(Array::ScopedArguments); + } ArrayMode result; switch (node->op()) { @@ -239,6 +279,8 @@ ArrayMode ArrayMode::refine( if (isFloat64ArraySpeculation(base)) return result.withType(Array::Float64Array); + if (type() == Array::Unprofiled) + return ArrayMode(Array::ForceExit); return ArrayMode(Array::Generic); } @@ -286,31 +328,54 @@ Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const return originalArrayStructure(graph, node->origin.semantic); } -bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value, IndexingType shape) const +bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const 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->origin.semantic)->isOriginalArrayStructure(value.m_currentKnownStructure.singleton()); + case Array::OriginalArray: { + if (value.m_structure.isTop()) + return false; + for (unsigned i = value.m_structure.size(); i--;) { + Structure* structure = value.m_structure[i]; + if ((structure->indexingType() & IndexingShapeMask) != shape) + return false; + if (!(structure->indexingType() & IsArray)) + return false; + if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure)) + return false; + } + return true; + } - case Array::Array: + 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); + if (value.m_structure.isTop()) + return false; + for (unsigned i = value.m_structure.size(); i--;) { + Structure* structure = value.m_structure[i]; + if ((structure->indexingType() & IndexingShapeMask) != shape) + return false; + if (!(structure->indexingType() & IsArray)) + return false; + } + return true; + } - default: + 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; - } + if (value.m_structure.isTop()) + return false; + for (unsigned i = value.m_structure.size(); i--;) { + Structure* structure = value.m_structure[i]; + if ((structure->indexingType() & IndexingShapeMask) != shape) + return false; + } + return true; + } } } -bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) const +bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value) const { switch (type()) { case Array::Generic: @@ -336,26 +401,44 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) c case Array::SlowPutArrayStorage: switch (arrayClass()) { - case Array::OriginalArray: + case Array::OriginalArray: { CRASH(); return false; + } - case Array::Array: + case Array::Array: { if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage))) return true; - return value.m_currentKnownStructure.hasSingleton() - && hasAnyArrayStorage(value.m_currentKnownStructure.singleton()->indexingType()) - && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); + if (value.m_structure.isTop()) + return false; + for (unsigned i = value.m_structure.size(); i--;) { + Structure* structure = value.m_structure[i]; + if (!hasAnyArrayStorage(structure->indexingType())) + return false; + if (!(structure->indexingType() & IsArray)) + return false; + } + return true; + } - default: + default: { if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage))) return true; - return value.m_currentKnownStructure.hasSingleton() - && hasAnyArrayStorage(value.m_currentKnownStructure.singleton()->indexingType()); - } + if (value.m_structure.isTop()) + return false; + for (unsigned i = value.m_structure.size(); i--;) { + Structure* structure = value.m_structure[i]; + if (!hasAnyArrayStorage(structure->indexingType())) + return false; + } + return true; + } } + + case Array::DirectArguments: + return speculationChecked(value.m_type, SpecDirectArguments); - case Array::Arguments: - return speculationChecked(value.m_type, SpecArguments); + case Array::ScopedArguments: + return speculationChecked(value.m_type, SpecScopedArguments); case Array::Int8Array: return speculationChecked(value.m_type, SpecInt8Array); @@ -419,8 +502,10 @@ const char* arrayTypeToString(Array::Type type) return "ArrayStorage"; case Array::SlowPutArrayStorage: return "SlowPutArrayStorage"; - case Array::Arguments: - return "Arguments"; + case Array::DirectArguments: + return "DirectArguments"; + case Array::ScopedArguments: + return "ScopedArguments"; case Array::Int8Array: return "Int8Array"; case Array::Int16Array: @@ -489,8 +574,6 @@ const char* arrayConversionToString(Array::Conversion conversion) return "AsIs"; case Array::Convert: return "Convert"; - case Array::RageConvert: - return "RageConvert"; default: return "Unknown!"; } diff --git a/dfg/DFGArrayMode.h b/dfg/DFGArrayMode.h index 084c985..a77c888 100644 --- a/dfg/DFGArrayMode.h +++ b/dfg/DFGArrayMode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -65,7 +65,9 @@ enum Type { ArrayStorage, SlowPutArrayStorage, - Arguments, + DirectArguments, + ScopedArguments, + Int8Array, Int16Array, Int32Array, @@ -87,14 +89,14 @@ enum Class { enum Speculation { 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, - RageConvert + Convert }; } // namespace Array @@ -220,9 +222,9 @@ public: return ArrayMode(type, arrayClass(), speculation(), conversion); } - ArrayMode refine(Graph&, Node*, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone, NodeFlags = 0) const; + ArrayMode refine(Graph&, Node*, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const; - bool alreadyChecked(Graph&, Node*, AbstractValue&) const; + bool alreadyChecked(Graph&, Node*, const AbstractValue&) const; void dump(PrintStream&) const; @@ -294,7 +296,8 @@ public: case Array::Unprofiled: case Array::ForceExit: case Array::Generic: - case Array::Arguments: + case Array::DirectArguments: + case Array::ScopedArguments: return false; default: return true; @@ -320,11 +323,9 @@ public: { switch (type()) { case Array::String: + case Array::DirectArguments: + case Array::ScopedArguments: return ArrayMode(Array::Generic); -#if USE(JSVALUE32_64) - case Array::Arguments: - return ArrayMode(Array::Generic); -#endif default: return *this; } @@ -469,7 +470,7 @@ private: return arrayMode1 | arrayMode2; } - bool alreadyChecked(Graph&, Node*, AbstractValue&, IndexingType shape) const; + bool alreadyChecked(Graph&, Node*, const AbstractValue&, IndexingType shape) const; union { struct { diff --git a/dfg/DFGArrayifySlowPathGenerator.h b/dfg/DFGArrayifySlowPathGenerator.h index 6d54b01..9019eb1 100644 --- a/dfg/DFGArrayifySlowPathGenerator.h +++ b/dfg/DFGArrayifySlowPathGenerator.h @@ -101,10 +101,7 @@ protected: jit->callOperation(operationEnsureDouble, m_tempGPR, m_baseGPR); break; case Array::Contiguous: - if (m_arrayMode.conversion() == Array::RageConvert) - jit->callOperation(operationRageEnsureContiguous, m_tempGPR, m_baseGPR); - else - jit->callOperation(operationEnsureContiguous, m_tempGPR, m_baseGPR); + jit->callOperation(operationEnsureContiguous, m_tempGPR, m_baseGPR); break; case Array::ArrayStorage: case Array::SlowPutArrayStorage: diff --git a/dfg/DFGAtTailAbstractState.cpp b/dfg/DFGAtTailAbstractState.cpp index ef6381e..9d8c710 100644 --- a/dfg/DFGAtTailAbstractState.cpp +++ b/dfg/DFGAtTailAbstractState.cpp @@ -32,8 +32,9 @@ namespace JSC { namespace DFG { -AtTailAbstractState::AtTailAbstractState() - : m_block(0) +AtTailAbstractState::AtTailAbstractState(Graph& graph) + : m_graph(graph) + , m_block(0) { } @@ -47,7 +48,7 @@ void AtTailAbstractState::createValueForNode(Node* node) AbstractValue& AtTailAbstractState::forNode(Node* node) { HashMap<Node*, AbstractValue>::iterator iter = m_block->ssa->valuesAtTail.find(node); - ASSERT(iter != m_block->ssa->valuesAtTail.end()); + DFG_ASSERT(m_graph, node, iter != m_block->ssa->valuesAtTail.end()); return iter->value; } diff --git a/dfg/DFGAtTailAbstractState.h b/dfg/DFGAtTailAbstractState.h index 7a872f9..cd6a080 100644 --- a/dfg/DFGAtTailAbstractState.h +++ b/dfg/DFGAtTailAbstractState.h @@ -36,7 +36,7 @@ namespace JSC { namespace DFG { class AtTailAbstractState { public: - AtTailAbstractState(); + AtTailAbstractState(Graph&); ~AtTailAbstractState(); @@ -54,14 +54,16 @@ public: bool isValid() { return m_block->cfaDidFinish; } + StructureClobberState structureClobberState() const { return m_block->cfaStructureClobberStateAtTail; } + void setDidClobber(bool) { } + void setStructureClobberState(StructureClobberState state) { RELEASE_ASSERT(state == m_block->cfaStructureClobberStateAtTail); } void setIsValid(bool isValid) { m_block->cfaDidFinish = isValid; } void setBranchDirection(BranchDirection) { } void setFoundConstants(bool) { } - bool haveStructures() const { return true; } // It's always safe to return true. - void setHaveStructures(bool) { } private: + Graph& m_graph; BasicBlock* m_block; }; diff --git a/dfg/DFGAvailability.h b/dfg/DFGAvailability.h index fd9bf65..507d816 100644 --- a/dfg/DFGAvailability.h +++ b/dfg/DFGAvailability.h @@ -81,10 +81,26 @@ public: return withNode(unavailableMarker()); } + void setFlush(FlushedAt flushedAt) + { + m_flushedAt = flushedAt; + } + + void setNode(Node* node) + { + m_node = node; + } + + void setNodeUnavailable() + { + m_node = unavailableMarker(); + } + bool nodeIsUndecided() const { return !m_node; } bool nodeIsUnavailable() const { return m_node == unavailableMarker(); } bool hasNode() const { return !nodeIsUndecided() && !nodeIsUnavailable(); } + bool shouldUseNode() const { return !isFlushUseful() && hasNode(); } Node* node() const { @@ -94,6 +110,12 @@ public: } FlushedAt flushedAt() const { return m_flushedAt; } + bool isFlushUseful() const + { + return flushedAt().format() != DeadFlush && flushedAt().format() != ConflictingFlush; + } + + bool isDead() const { return !isFlushUseful() && !hasNode(); } bool operator!() const { return nodeIsUnavailable() && flushedAt().format() == ConflictingFlush; } @@ -103,6 +125,11 @@ public: && m_flushedAt == other.m_flushedAt; } + bool operator!=(const Availability& other) const + { + return !(*this == other); + } + Availability merge(const Availability& other) const { return Availability( diff --git a/dfg/DFGAvailabilityMap.cpp b/dfg/DFGAvailabilityMap.cpp new file mode 100644 index 0000000..e319dc6 --- /dev/null +++ b/dfg/DFGAvailabilityMap.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGAvailabilityMap.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" +#include "JSCInlines.h" +#include "OperandsInlines.h" +#include <wtf/ListDump.h> + +namespace JSC { namespace DFG { + +void AvailabilityMap::pruneHeap() +{ + if (m_heap.isEmpty()) + return; + + HashSet<Node*> possibleNodes; + + for (unsigned i = m_locals.size(); i--;) { + if (m_locals[i].hasNode()) + possibleNodes.add(m_locals[i].node()); + } + + closeOverNodes( + [&] (Node* node) -> bool { + return possibleNodes.contains(node); + }, + [&] (Node* node) -> bool { + return possibleNodes.add(node).isNewEntry; + }); + + HashMap<PromotedHeapLocation, Availability> newHeap; + for (auto pair : m_heap) { + if (possibleNodes.contains(pair.key.base())) + newHeap.add(pair.key, pair.value); + } + m_heap = newHeap; +} + +void AvailabilityMap::pruneByLiveness(Graph& graph, CodeOrigin where) +{ + Operands<Availability> localsCopy(OperandsLike, m_locals); + graph.forAllLiveInBytecode( + where, + [&] (VirtualRegister reg) { + localsCopy.operand(reg) = m_locals.operand(reg); + }); + m_locals = localsCopy; + pruneHeap(); +} + +void AvailabilityMap::clear() +{ + m_locals.fill(Availability()); + m_heap.clear(); +} + +void AvailabilityMap::dump(PrintStream& out) const +{ + out.print("{locals = ", m_locals, "; heap = ", mapDump(m_heap), "}"); +} + +bool AvailabilityMap::operator==(const AvailabilityMap& other) const +{ + return m_locals == other.m_locals + && m_heap == other.m_heap; +} + +void AvailabilityMap::merge(const AvailabilityMap& other) +{ + for (unsigned i = other.m_locals.size(); i--;) + m_locals[i] = other.m_locals[i].merge(m_locals[i]); + + for (auto pair : other.m_heap) { + auto result = m_heap.add(pair.key, Availability()); + result.iterator->value = pair.value.merge(result.iterator->value); + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGAvailabilityMap.h b/dfg/DFGAvailabilityMap.h new file mode 100644 index 0000000..1cdd25b --- /dev/null +++ b/dfg/DFGAvailabilityMap.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014, 2015 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 DFGAvailabilityMap_h +#define DFGAvailabilityMap_h + +#if ENABLE(DFG_JIT) + +#include "DFGAvailability.h" +#include "DFGPromotedHeapLocation.h" + +namespace JSC { namespace DFG { + +struct AvailabilityMap { + void pruneHeap(); + void pruneByLiveness(Graph&, CodeOrigin); + void clear(); + + void dump(PrintStream& out) const; + + bool operator==(const AvailabilityMap& other) const; + + void merge(const AvailabilityMap& other); + + template<typename Functor> + void forEachAvailability(const Functor& functor) + { + for (unsigned i = m_locals.size(); i--;) + functor(m_locals[i]); + for (auto pair : m_heap) + functor(pair.value); + } + + template<typename HasFunctor, typename AddFunctor> + void closeOverNodes(const HasFunctor& has, const AddFunctor& add) + { + bool changed; + do { + changed = false; + for (auto pair : m_heap) { + if (pair.value.hasNode() && has(pair.key.base())) + changed |= add(pair.value.node()); + } + } while (changed); + } + + template<typename HasFunctor, typename AddFunctor> + void closeStartingWithLocal(VirtualRegister reg, const HasFunctor& has, const AddFunctor& add) + { + Availability availability = m_locals.operand(reg); + if (!availability.hasNode()) + return; + + if (!add(availability.node())) + return; + + closeOverNodes(has, add); + } + + Operands<Availability> m_locals; + HashMap<PromotedHeapLocation, Availability> m_heap; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGAvailabilityMap_h + diff --git a/dfg/DFGBackwardsPropagationPhase.cpp b/dfg/DFGBackwardsPropagationPhase.cpp index 9d063fd..2768f61 100644 --- a/dfg/DFGBackwardsPropagationPhase.cpp +++ b/dfg/DFGBackwardsPropagationPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -67,17 +67,17 @@ public: private: bool isNotNegZero(Node* node) { - if (!m_graph.isNumberConstant(node)) + if (!node->isNumberConstant()) return false; - double value = m_graph.valueOfNumberConstant(node); + double value = node->asNumber(); return (value || 1.0 / value > 0.0); } bool isNotPosZero(Node* node) { - if (!m_graph.isNumberConstant(node)) + if (!node->isNumberConstant()) return false; - double value = m_graph.valueOfNumberConstant(node); + double value = node->asNumber(); return (value || 1.0 / value < 0.0); } @@ -85,7 +85,7 @@ private: template<int power> bool isWithinPowerOfTwoForConstant(Node* node) { - JSValue immediateValue = node->valueOfJSConstant(codeBlock()); + JSValue immediateValue = node->asJSValue(); if (!immediateValue.isNumber()) return false; double immediate = immediateValue.asNumber(); @@ -95,7 +95,7 @@ private: template<int power> bool isWithinPowerOfTwoNonRecursive(Node* node) { - if (node->op() != JSConstant) + if (!node->isNumberConstant()) return false; return isWithinPowerOfTwoForConstant<power>(node); } @@ -104,7 +104,9 @@ private: bool isWithinPowerOfTwo(Node* node) { switch (node->op()) { - case JSConstant: { + case DoubleConstant: + case JSConstant: + case Int52Constant: { return isWithinPowerOfTwoForConstant<power>(node); } @@ -128,9 +130,9 @@ private: return true; Node* shiftAmount = node->child2().node(); - if (shiftAmount->op() != JSConstant) + if (!node->isNumberConstant()) return false; - JSValue immediateValue = shiftAmount->valueOfJSConstant(codeBlock()); + JSValue immediateValue = shiftAmount->asJSValue(); if (!immediateValue.isInt32()) return false; return immediateValue.asInt32() > 32 - power; @@ -257,7 +259,14 @@ private: node->child2()->mergeFlags(flags); break; } - + + case ArithClz32: { + flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex); + flags |= NodeBytecodeUsesAsInt; + node->child1()->mergeFlags(flags); + break; + } + case ArithSub: { if (isNotNegZero(node->child1().node()) || isNotPosZero(node->child2().node())) flags &= ~NodeBytecodeNeedsNegZero; @@ -310,11 +319,11 @@ private: } case ArithMod: { - flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero; + flags |= NodeBytecodeUsesAsNumber; flags &= ~NodeBytecodeUsesAsOther; node->child1()->mergeFlags(flags); - node->child2()->mergeFlags(flags); + node->child2()->mergeFlags(flags & ~NodeBytecodeNeedsNegZero); break; } @@ -324,11 +333,6 @@ private: break; } - case GetMyArgumentByValSafe: { - node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); - break; - } - case NewArrayWithSize: { node->child1()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex); break; @@ -348,7 +352,8 @@ private: break; } - case ToString: { + case ToString: + case CallStringConstructor: { node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther); break; } @@ -389,6 +394,11 @@ private: // then -0 and 0 are treated the same. node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther); break; + case SwitchCell: + // There is currently no point to being clever here since this is used for switching + // on objects. + mergeDefaultFlags(node); + break; } break; } diff --git a/dfg/DFGBasicBlock.cpp b/dfg/DFGBasicBlock.cpp index 5f3b480..f83f50c 100644 --- a/dfg/DFGBasicBlock.cpp +++ b/dfg/DFGBasicBlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,6 +41,8 @@ BasicBlock::BasicBlock( , cfaShouldRevisit(false) , cfaFoundConstants(false) , cfaDidFinish(true) + , cfaStructureClobberStateAtHead(StructuresAreWatched) + , cfaStructureClobberStateAtTail(StructuresAreWatched) , cfaBranchDirection(InvalidBranchDirection) #if !ASSERT_DISABLED , isLinked(false) @@ -50,11 +52,15 @@ BasicBlock::BasicBlock( , variablesAtTail(numArguments, numLocals) , valuesAtHead(numArguments, numLocals) , valuesAtTail(numArguments, numLocals) + , intersectionOfPastValuesAtHead(numArguments, numLocals, AbstractValue::fullTop()) + , intersectionOfCFAHasVisited(true) , executionCount(executionCount) { } -BasicBlock::~BasicBlock() { } +BasicBlock::~BasicBlock() +{ +} void BasicBlock::ensureLocals(unsigned newNumLocals) { @@ -62,6 +68,20 @@ void BasicBlock::ensureLocals(unsigned newNumLocals) variablesAtTail.ensureLocals(newNumLocals); valuesAtHead.ensureLocals(newNumLocals); valuesAtTail.ensureLocals(newNumLocals); + intersectionOfPastValuesAtHead.ensureLocals(newNumLocals, AbstractValue::fullTop()); +} + +void BasicBlock::replaceTerminal(Node* node) +{ + NodeAndIndex result = findTerminal(); + if (!result) + append(node); + else { + m_nodes.insert(result.index + 1, node); + result.node->remove(); + } + + ASSERT(terminal()); } bool BasicBlock::isInPhis(Node* node) const @@ -82,6 +102,21 @@ bool BasicBlock::isInBlock(Node* myNode) const return false; } +Node* BasicBlock::firstOriginNode() +{ + for (Node* node : *this) { + if (node->origin.isSet()) + return node; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +NodeOrigin BasicBlock::firstOrigin() +{ + return firstOriginNode()->origin; +} + void BasicBlock::removePredecessor(BasicBlock* block) { for (unsigned i = 0; i < predecessors.size(); ++i) { @@ -111,9 +146,9 @@ void BasicBlock::dump(PrintStream& out) const } BasicBlock::SSAData::SSAData(BasicBlock* block) - : availabilityAtHead(OperandsLike, block->variablesAtHead) - , availabilityAtTail(OperandsLike, block->variablesAtHead) { + availabilityAtHead.m_locals = Operands<Availability>(OperandsLike, block->variablesAtHead); + availabilityAtTail.m_locals = Operands<Availability>(OperandsLike, block->variablesAtHead); } BasicBlock::SSAData::~SSAData() { } diff --git a/dfg/DFGBasicBlock.h b/dfg/DFGBasicBlock.h index 19d5487..420ff51 100644 --- a/dfg/DFGBasicBlock.h +++ b/dfg/DFGBasicBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,13 +30,15 @@ #include "DFGAbstractValue.h" #include "DFGAvailability.h" +#include "DFGAvailabilityMap.h" #include "DFGBranchDirection.h" #include "DFGFlushedAt.h" #include "DFGNode.h" +#include "DFGNodeOrigin.h" +#include "DFGStructureClobberState.h" #include "Operands.h" #include <wtf/HashMap.h> #include <wtf/HashSet.h> -#include <wtf/OwnPtr.h> #include <wtf/Vector.h> namespace JSC { namespace DFG { @@ -45,6 +47,7 @@ class Graph; class InsertionSet; typedef Vector<BasicBlock*, 2> PredecessorList; +typedef Vector<Node*, 8> BlockNodeList; struct BasicBlock : RefCounted<BasicBlock> { BasicBlock( @@ -58,19 +61,72 @@ struct BasicBlock : RefCounted<BasicBlock> { bool isEmpty() const { return !size(); } Node*& at(size_t i) { return m_nodes[i]; } Node* at(size_t i) const { return m_nodes[i]; } + Node* tryAt(size_t i) const + { + if (i >= size()) + return nullptr; + return at(i); + } Node*& operator[](size_t i) { return at(i); } Node* operator[](size_t i) const { return at(i); } - Node* last() const { return at(size() - 1); } + + // Use this to find both the index of the terminal and the terminal itself in one go. May + // return a clear NodeAndIndex if the basic block currently lacks a terminal. That may happen + // in the middle of IR transformations within a phase but should never be the case in between + // phases. + // + // The reason why this is more than just "at(size() - 1)" is that we may place non-terminal + // liveness marking instructions after the terminal. This is supposed to happen infrequently + // but some basic blocks - most notably return blocks - will have liveness markers for all of + // the flushed variables right after the return. + // + // It turns out that doing this linear search is basically perf-neutral, so long as we force + // the method to be inlined. Hence the ALWAYS_INLINE. + ALWAYS_INLINE NodeAndIndex findTerminal() const + { + size_t i = size(); + while (i--) { + Node* node = at(i); + switch (node->op()) { + case Jump: + case Branch: + case Switch: + case Return: + case Unreachable: + return NodeAndIndex(node, i); + // The bitter end can contain Phantoms and the like. There will probably only be one or two nodes after the terminal. They are all no-ops and will not have any checked children. + case Check: // This is here because it's our universal no-op. + case Phantom: + case PhantomLocal: + case Flush: + break; + default: + return NodeAndIndex(); + } + } + return NodeAndIndex(); + } + + ALWAYS_INLINE Node* terminal() const + { + return findTerminal().node; + } + void resize(size_t size) { m_nodes.resize(size); } void grow(size_t size) { m_nodes.grow(size); } void append(Node* node) { m_nodes.append(node); } - void insertBeforeLast(Node* node) + void insertBeforeTerminal(Node* node) { - append(last()); - at(size() - 2) = node; + NodeAndIndex result = findTerminal(); + if (!result) + append(node); + else + m_nodes.insert(result.index, node); } + void replaceTerminal(Node*); + size_t numNodes() const { return phis.size() + size(); } Node* node(size_t i) const { @@ -83,15 +139,26 @@ struct BasicBlock : RefCounted<BasicBlock> { bool isInPhis(Node* node) const; bool isInBlock(Node* myNode) const; - unsigned numSuccessors() { return last()->numSuccessors(); } + BlockNodeList::iterator begin() { return m_nodes.begin(); } + BlockNodeList::iterator end() { return m_nodes.end(); } + + Node* firstOriginNode(); + NodeOrigin firstOrigin(); + + unsigned numSuccessors() { return terminal()->numSuccessors(); } BasicBlock*& successor(unsigned index) { - return last()->successor(index); + return terminal()->successor(index); } BasicBlock*& successorForCondition(bool condition) { - return last()->successorForCondition(condition); + return terminal()->successorForCondition(condition); + } + + Node::SuccessorsIterable successors() + { + return terminal()->successors(); } void removePredecessor(BasicBlock* block); @@ -103,8 +170,18 @@ struct BasicBlock : RefCounted<BasicBlock> { template<typename... Params> Node* appendNonTerminal(Graph&, SpeculatedType, Params...); + template<typename... Params> + Node* replaceTerminal(Graph&, SpeculatedType, Params...); + void dump(PrintStream& out) const; + void didLink() + { +#if !ASSERT_DISABLED + isLinked = true; +#endif + } + // This value is used internally for block linking and OSR entry. It is mostly meaningless // for other purposes due to inlining. unsigned bytecodeBegin; @@ -116,6 +193,8 @@ struct BasicBlock : RefCounted<BasicBlock> { bool cfaShouldRevisit; bool cfaFoundConstants; bool cfaDidFinish; + StructureClobberState cfaStructureClobberStateAtHead; + StructureClobberState cfaStructureClobberStateAtTail; BranchDirection cfaBranchDirection; #if !ASSERT_DISABLED bool isLinked; @@ -131,6 +210,26 @@ struct BasicBlock : RefCounted<BasicBlock> { Operands<AbstractValue> valuesAtHead; Operands<AbstractValue> valuesAtTail; + // The intersection of assumptions we have made previously at the head of this block. Note + // that under normal circumstances, each time we run the CFA, we will get strictly more precise + // results. But we don't actually require this to be the case. It's fine for the CFA to loosen + // up for any odd reason. It's fine when this happens, because anything that the CFA proves + // must be true from that point forward, except if some registered watchpoint fires, in which + // case the code won't ever run. So, the CFA proving something less precise later on is just an + // outcome of the CFA being imperfect; the more precise thing that it had proved earlier is no + // less true. + // + // But for the purpose of OSR entry, we need to make sure that we remember what assumptions we + // had used for optimizing any given basic block. That's what this is for. + // + // It's interesting that we could use this to make the CFA more precise: all future CFAs could + // filter their results with this thing to sort of maintain maximal precision. Because we + // expect CFA to usually be monotonically more precise each time we run it to fixpoint, this + // would not be a productive optimization: it would make setting up a basic block more + // expensive and would only benefit bizarre pathological cases. + Operands<AbstractValue> intersectionOfPastValuesAtHead; + bool intersectionOfCFAHasVisited; + float executionCount; // These fields are reserved for NaturalLoops. @@ -138,8 +237,9 @@ struct BasicBlock : RefCounted<BasicBlock> { unsigned innerMostLoopIndices[numberOfInnerMostLoopIndices]; struct SSAData { - Operands<Availability> availabilityAtHead; - Operands<Availability> availabilityAtTail; + AvailabilityMap availabilityAtHead; + AvailabilityMap availabilityAtTail; + HashSet<Node*> liveAtHead; HashSet<Node*> liveAtTail; HashMap<Node*, AbstractValue> valuesAtHead; @@ -148,13 +248,15 @@ struct BasicBlock : RefCounted<BasicBlock> { SSAData(BasicBlock*); ~SSAData(); }; - OwnPtr<SSAData> ssa; - + std::unique_ptr<SSAData> ssa; + private: friend class InsertionSet; - Vector<Node*, 8> m_nodes; + BlockNodeList m_nodes; }; +typedef Vector<BasicBlock*, 5> BlockList; + struct UnlinkedBlock { BasicBlock* m_block; bool m_needsNormalLinking; diff --git a/dfg/DFGBasicBlockInlines.h b/dfg/DFGBasicBlockInlines.h index 4a0fe92..3423a0d 100644 --- a/dfg/DFGBasicBlockInlines.h +++ b/dfg/DFGBasicBlockInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,7 +45,15 @@ template<typename... Params> Node* BasicBlock::appendNonTerminal(Graph& graph, SpeculatedType type, Params... params) { Node* result = graph.addNode(type, params...); - insertBeforeLast(result); + insertBeforeTerminal(result); + return result; +} + +template<typename... Params> +Node* BasicBlock::replaceTerminal(Graph& graph, SpeculatedType type, Params... params) +{ + Node* result = graph.addNode(type, params...); + replaceTerminal(result); return result; } diff --git a/dfg/DFGBinarySwitch.cpp b/dfg/DFGBinarySwitch.cpp deleted file mode 100644 index 5aa6b01..0000000 --- a/dfg/DFGBinarySwitch.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2013 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 "DFGBinarySwitch.h" - -#if ENABLE(DFG_JIT) - -#include "JSCInlines.h" - -namespace JSC { namespace DFG { - -BinarySwitch::BinarySwitch(GPRReg value, const Vector<int64_t>& cases, Type type) - : m_value(value) - , m_index(0) - , m_caseIndex(UINT_MAX) - , m_medianBias(0) - , m_type(type) -{ - if (cases.isEmpty()) - return; - - for (unsigned i = 0; i < cases.size(); ++i) - m_cases.append(Case(cases[i], i)); - std::sort(m_cases.begin(), m_cases.end()); - build(0, m_cases.size()); -} - -bool BinarySwitch::advance(MacroAssembler& jit) -{ - if (m_cases.isEmpty()) { - m_fallThrough.append(jit.jump()); - return false; - } - - if (m_index == m_branches.size()) { - RELEASE_ASSERT(m_jumpStack.isEmpty()); - return false; - } - - for (;;) { - const BranchCode& code = m_branches[m_index++]; - switch (code.kind) { - case NotEqualToFallThrough: - switch (m_type) { - case Int32: - m_fallThrough.append(jit.branch32( - MacroAssembler::NotEqual, m_value, - MacroAssembler::Imm32(static_cast<int32_t>(m_cases[code.index].value)))); - break; - case IntPtr: - m_fallThrough.append(jit.branchPtr( - MacroAssembler::NotEqual, m_value, - MacroAssembler::ImmPtr(bitwise_cast<const void*>(static_cast<intptr_t>(m_cases[code.index].value))))); - break; - } - break; - case NotEqualToPush: - switch (m_type) { - case Int32: - m_jumpStack.append(jit.branch32( - MacroAssembler::NotEqual, m_value, - MacroAssembler::Imm32(static_cast<int32_t>(m_cases[code.index].value)))); - break; - case IntPtr: - m_jumpStack.append(jit.branchPtr( - MacroAssembler::NotEqual, m_value, - MacroAssembler::ImmPtr(bitwise_cast<const void*>(static_cast<intptr_t>(m_cases[code.index].value))))); - break; - } - break; - case LessThanToPush: - switch (m_type) { - case Int32: - m_jumpStack.append(jit.branch32( - MacroAssembler::LessThan, m_value, - MacroAssembler::Imm32(static_cast<int32_t>(m_cases[code.index].value)))); - break; - case IntPtr: - m_jumpStack.append(jit.branchPtr( - MacroAssembler::LessThan, m_value, - MacroAssembler::ImmPtr(bitwise_cast<const void*>(static_cast<intptr_t>(m_cases[code.index].value))))); - break; - } - break; - case Pop: - m_jumpStack.takeLast().link(&jit); - break; - case ExecuteCase: - m_caseIndex = code.index; - return true; - } - } -} - -void BinarySwitch::build(unsigned start, unsigned end) -{ - unsigned size = end - start; - - switch (size) { - case 0: { - RELEASE_ASSERT_NOT_REACHED(); - break; - } - - case 1: { - if (start - && m_cases[start - 1].value == m_cases[start].value - 1 - && start + 1 < m_cases.size() - && m_cases[start + 1].value == m_cases[start].value + 1) { - m_branches.append(BranchCode(ExecuteCase, start)); - break; - } - - m_branches.append(BranchCode(NotEqualToFallThrough, start)); - m_branches.append(BranchCode(ExecuteCase, start)); - break; - } - - case 2: { - if (m_cases[start].value + 1 == m_cases[start + 1].value - && start - && m_cases[start - 1].value == m_cases[start].value - 1 - && start + 2 < m_cases.size() - && m_cases[start + 2].value == m_cases[start + 1].value + 1) { - m_branches.append(BranchCode(NotEqualToPush, start)); - m_branches.append(BranchCode(ExecuteCase, start)); - m_branches.append(BranchCode(Pop)); - m_branches.append(BranchCode(ExecuteCase, start + 1)); - break; - } - - unsigned firstCase = start; - unsigned secondCase = start + 1; - if (m_medianBias) - std::swap(firstCase, secondCase); - m_medianBias ^= 1; - - m_branches.append(BranchCode(NotEqualToPush, firstCase)); - m_branches.append(BranchCode(ExecuteCase, firstCase)); - m_branches.append(BranchCode(Pop)); - m_branches.append(BranchCode(NotEqualToFallThrough, secondCase)); - m_branches.append(BranchCode(ExecuteCase, secondCase)); - break; - } - - default: { - unsigned medianIndex = (start + end) / 2; - if (!(size & 1)) { - // Because end is exclusive, in the even case, this rounds up by - // default. Hence median bias sometimes flips to subtracing one - // in order to get round-down behavior. - medianIndex -= m_medianBias; - m_medianBias ^= 1; - } - - RELEASE_ASSERT(medianIndex > start); - RELEASE_ASSERT(medianIndex + 1 < end); - - m_branches.append(BranchCode(LessThanToPush, medianIndex)); - m_branches.append(BranchCode(NotEqualToPush, medianIndex)); - m_branches.append(BranchCode(ExecuteCase, medianIndex)); - - m_branches.append(BranchCode(Pop)); - build(medianIndex + 1, end); - - m_branches.append(BranchCode(Pop)); - build(start, medianIndex); - break; - } } -} - -} } // namespace JSC::DFG - -#endif // ENABLE(DFG_JIT) - diff --git a/dfg/DFGBlockMap.h b/dfg/DFGBlockMap.h new file mode 100644 index 0000000..aaf343c --- /dev/null +++ b/dfg/DFGBlockMap.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014, 2015 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 DFGBlockMap_h +#define DFGBlockMap_h + +#if ENABLE(DFG_JIT) + +#include "DFGBasicBlock.h" + +namespace JSC { namespace DFG { + +class Graph; + +template<typename T> +class BlockMap { +public: + BlockMap() + { + } + + BlockMap(Graph&); + + BlockIndex size() const + { + return m_vector.size(); + } + + T& atIndex(BlockIndex blockIndex) + { + return m_vector[blockIndex]; + } + + const T& atIndex(BlockIndex blockIndex) const + { + return m_vector[blockIndex]; + } + + T& at(BlockIndex blockIndex) + { + return m_vector[blockIndex]; + } + + const T& at(BlockIndex blockIndex) const + { + return m_vector[blockIndex]; + } + + T& at(BasicBlock* block) + { + return m_vector[block->index]; + } + + const T& at(BasicBlock* block) const + { + return m_vector[block->index]; + } + + T& operator[](BlockIndex blockIndex) + { + return m_vector[blockIndex]; + } + + const T& operator[](BlockIndex blockIndex) const + { + return m_vector[blockIndex]; + } + + T& operator[](BasicBlock* block) + { + return m_vector[block->index]; + } + + const T& operator[](BasicBlock* block) const + { + return m_vector[block->index]; + } + +private: + Vector<T> m_vector; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGBlockMap_h + diff --git a/dfg/DFGBlockMapInlines.h b/dfg/DFGBlockMapInlines.h new file mode 100644 index 0000000..e61626d --- /dev/null +++ b/dfg/DFGBlockMapInlines.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 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 DFGBlockMapInlines_h +#define DFGBlockMapInlines_h + +#if ENABLE(DFG_JIT) + +#include "DFGBlockMap.h" +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +template<typename T> +BlockMap<T>::BlockMap(Graph& graph) +{ + m_vector.resize(graph.numBlocks()); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGBlockMapInlines_h diff --git a/dfg/DFGBlockSet.cpp b/dfg/DFGBlockSet.cpp new file mode 100644 index 0000000..790e380 --- /dev/null +++ b/dfg/DFGBlockSet.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 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 "DFGBlockSet.h" + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +void BlockSet::dump(PrintStream& out) const +{ + CommaPrinter comma(" "); + for (BlockIndex blockIndex = m_set.findBit(0, true); blockIndex < m_set.size(); blockIndex = m_set.findBit(blockIndex + 1, true)) + out.print(comma, "#", blockIndex); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGBlockSet.h b/dfg/DFGBlockSet.h new file mode 100644 index 0000000..b09afec --- /dev/null +++ b/dfg/DFGBlockSet.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2014 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 DFGBlockSet_h +#define DFGBlockSet_h + +#if ENABLE(DFG_JIT) + +#include "DFGBasicBlock.h" + +namespace JSC { namespace DFG { + +class Graph; + +class BlockSet { +public: + BlockSet() { } + + // Return true if the block was added, false if it was already present. + bool add(BasicBlock* block) + { + return !m_set.set(block->index); + } + + bool contains(BasicBlock* block) const + { + if (!block) + return false; + return m_set.get(block->index); + } + + class iterator { + public: + iterator() + : m_graph(nullptr) + , m_set(nullptr) + , m_index(0) + { + } + + iterator& operator++() + { + m_index = m_set->m_set.findBit(m_index + 1, true); + return *this; + } + + BasicBlock* operator*() const; + + bool operator==(const iterator& other) const + { + return m_index == other.m_index; + } + + bool operator!=(const iterator& other) const + { + return !(*this == other); + } + + private: + friend class BlockSet; + + Graph* m_graph; + const BlockSet* m_set; + size_t m_index; + }; + + class Iterable { + public: + Iterable(Graph& graph, const BlockSet& set) + : m_graph(graph) + , m_set(set) + { + } + + iterator begin() const + { + iterator result; + result.m_graph = &m_graph; + result.m_set = &m_set; + result.m_index = m_set.m_set.findBit(0, true); + return result; + } + + iterator end() const + { + iterator result; + result.m_graph = &m_graph; + result.m_set = &m_set; + result.m_index = m_set.m_set.size(); + return result; + } + + private: + Graph& m_graph; + const BlockSet& m_set; + }; + + Iterable iterable(Graph& graph) const + { + return Iterable(graph, *this); + } + + void dump(PrintStream&) const; + +private: + BitVector m_set; +}; + +class BlockAdder { +public: + BlockAdder(BlockSet& set) + : m_set(set) + { + } + + bool operator()(BasicBlock* block) const + { + return m_set.add(block); + } +private: + BlockSet& m_set; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGBlockSet_h + diff --git a/dfg/DFGBlockSetInlines.h b/dfg/DFGBlockSetInlines.h new file mode 100644 index 0000000..df96285 --- /dev/null +++ b/dfg/DFGBlockSetInlines.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 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 DFGBlockSetInlines_h +#define DFGBlockSetInlines_h + +#if ENABLE(DFG_JIT) + +#include "DFGBlockSet.h" +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +inline BasicBlock* BlockSet::iterator::operator*() const +{ + return m_graph->block(m_index); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGBlockSetInlines_h + diff --git a/dfg/DFGBlockWorklist.cpp b/dfg/DFGBlockWorklist.cpp new file mode 100644 index 0000000..1caf9ca --- /dev/null +++ b/dfg/DFGBlockWorklist.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 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 "DFGBlockWorklist.h" + +#if ENABLE(DFG_JIT) + +#include "DFGBasicBlock.h" + +namespace JSC { namespace DFG { + +BlockWorklist::BlockWorklist() +{ +} + +BlockWorklist::~BlockWorklist() +{ +} + +bool BlockWorklist::push(BasicBlock* block) +{ + if (!m_seen.add(block)) + return false; + + m_stack.append(block); + return true; +} + +BasicBlock* BlockWorklist::pop() +{ + if (m_stack.isEmpty()) + return nullptr; + + return m_stack.takeLast(); +} + +PostOrderBlockWorklist::PostOrderBlockWorklist() +{ +} + +PostOrderBlockWorklist::~PostOrderBlockWorklist() +{ +} + +bool PostOrderBlockWorklist::pushPre(BasicBlock* block) +{ + return m_worklist.push(block, PreOrder); +} + +void PostOrderBlockWorklist::pushPost(BasicBlock* block) +{ + m_worklist.forcePush(block, PostOrder); +} + +BlockWithOrder PostOrderBlockWorklist::pop() +{ + BlockWith<VisitOrder> result = m_worklist.pop(); + return BlockWithOrder(result.block, result.data); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGBlockWorklist.h b/dfg/DFGBlockWorklist.h new file mode 100644 index 0000000..5b39e1c --- /dev/null +++ b/dfg/DFGBlockWorklist.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014 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 DFGBlockWorklist_h +#define DFGBlockWorklist_h + +#if ENABLE(DFG_JIT) + +#include "DFGBasicBlock.h" +#include "DFGBlockSet.h" +#include <wtf/Vector.h> + +namespace JSC { namespace DFG { + +struct BasicBlock; + +class BlockWorklist { +public: + BlockWorklist(); + ~BlockWorklist(); + + bool push(BasicBlock*); // Returns true if we didn't know about the block before. + + bool notEmpty() const { return !m_stack.isEmpty(); } + BasicBlock* pop(); + +private: + BlockSet m_seen; + Vector<BasicBlock*, 16> m_stack; +}; + +// When you say BlockWith<int> you should read it as "block with an int". +template<typename T> +struct BlockWith { + BlockWith() + : block(nullptr) + { + } + + BlockWith(BasicBlock* block, const T& data) + : block(block) + , data(data) + { + } + + explicit operator bool() const { return block; } + + BasicBlock* block; + T data; +}; + +// Extended block worklist is useful for enqueueing some meta-data along with the block. It also +// permits forcibly enqueueing things even if the block has already been seen. It's useful for +// things like building a spanning tree, in which case T (the auxiliary payload) would be the +// successor index. +template<typename T> +class ExtendedBlockWorklist { +public: + ExtendedBlockWorklist() { } + + void forcePush(const BlockWith<T>& entry) + { + m_stack.append(entry); + } + + void forcePush(BasicBlock* block, const T& data) + { + forcePush(BlockWith<T>(block, data)); + } + + bool push(const BlockWith<T>& entry) + { + if (!m_seen.add(entry.block)) + return false; + + forcePush(entry); + return true; + } + + bool push(BasicBlock* block, const T& data) + { + return push(BlockWith<T>(block, data)); + } + + bool notEmpty() const { return !m_stack.isEmpty(); } + + BlockWith<T> pop() + { + if (m_stack.isEmpty()) + return BlockWith<T>(); + + return m_stack.takeLast(); + } + +private: + BlockSet m_seen; + Vector<BlockWith<T>> m_stack; +}; + +enum VisitOrder { + PreOrder, + PostOrder +}; + +struct BlockWithOrder { + BlockWithOrder() + : block(nullptr) + , order(PreOrder) + { + } + + BlockWithOrder(BasicBlock* block, VisitOrder order) + : block(block) + , order(order) + { + } + + explicit operator bool() const { return block; } + + BasicBlock* block; + VisitOrder order; +}; + +// Block worklist suitable for post-order traversal. +class PostOrderBlockWorklist { +public: + PostOrderBlockWorklist(); + ~PostOrderBlockWorklist(); + + bool pushPre(BasicBlock*); + void pushPost(BasicBlock*); + + bool push(BasicBlock* block, VisitOrder order = PreOrder) + { + switch (order) { + case PreOrder: + return pushPre(block); + case PostOrder: + pushPost(block); + return true; + } + RELEASE_ASSERT_NOT_REACHED(); + return false; + } + bool push(const BlockWithOrder& data) + { + return push(data.block, data.order); + } + + bool notEmpty() const { return m_worklist.notEmpty(); } + BlockWithOrder pop(); + +private: + ExtendedBlockWorklist<VisitOrder> m_worklist; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGBlockWorklist_h + diff --git a/dfg/DFGBranchDirection.h b/dfg/DFGBranchDirection.h index 811c898..dcdde27 100644 --- a/dfg/DFGBranchDirection.h +++ b/dfg/DFGBranchDirection.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -50,7 +50,7 @@ static inline const char* branchDirectionToString(BranchDirection branchDirectio { switch (branchDirection) { case InvalidBranchDirection: - return "Invalid"; + return "InvalidBranchDirection"; case TakeTrue: return "TakeTrue"; case TakeFalse: @@ -58,6 +58,9 @@ static inline const char* branchDirectionToString(BranchDirection branchDirectio case TakeBoth: return "TakeBoth"; } + + RELEASE_ASSERT_NOT_REACHED(); + return "InvalidBranchDirection"; } static inline bool isKnownDirection(BranchDirection branchDirection) @@ -81,6 +84,15 @@ static inline bool branchCondition(BranchDirection branchDirection) } } // namespace JSC::DFG +namespace WTF { + +inline void printInternal(PrintStream& out, JSC::DFG::BranchDirection direction) +{ + out.print(JSC::DFG::branchDirectionToString(direction)); +} + +} // namespace WTF + #endif // ENABLE(DFG_JIT) #endif // DFGBranchDirection_h diff --git a/dfg/DFGByteCodeParser.cpp b/dfg/DFGByteCodeParser.cpp index 7067480..2e37e69 100644 --- a/dfg/DFGByteCodeParser.cpp +++ b/dfg/DFGByteCodeParser.cpp @@ -1,5 +1,5 @@ - /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. +/* + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,15 +29,17 @@ #if ENABLE(DFG_JIT) #include "ArrayConstructor.h" +#include "BasicBlockLocation.h" #include "CallLinkStatus.h" #include "CodeBlock.h" #include "CodeBlockWithJITType.h" #include "DFGArrayMode.h" #include "DFGCapabilities.h" +#include "DFGGraph.h" #include "DFGJITCode.h" #include "GetByIdStatus.h" #include "Heap.h" -#include "JSActivation.h" +#include "JSLexicalEnvironment.h" #include "JSCInlines.h" #include "PreciseJumpTargets.h" #include "PutByIdStatus.h" @@ -50,6 +52,8 @@ namespace JSC { namespace DFG { +static const bool verbose = false; + class ConstantBufferKey { public: ConstantBufferKey() @@ -132,19 +136,18 @@ public: , m_graph(graph) , m_currentBlock(0) , m_currentIndex(0) - , m_constantUndefined(UINT_MAX) - , m_constantNull(UINT_MAX) - , m_constantNaN(UINT_MAX) - , m_constant1(UINT_MAX) - , m_constants(m_codeBlock->numberOfConstantRegisters()) + , m_constantUndefined(graph.freeze(jsUndefined())) + , m_constantNull(graph.freeze(jsNull())) + , m_constantNaN(graph.freeze(jsNumber(PNaN))) + , m_constantOne(graph.freeze(jsNumber(1))) , m_numArguments(m_codeBlock->numParameters()) , m_numLocals(m_codeBlock->m_numCalleeRegisters) , m_parameterSlots(0) , m_numPassedVarArgs(0) , m_inlineStackTop(0) , m_haveBuiltOperandMaps(false) - , m_emptyJSValueIndex(UINT_MAX) , m_currentInstruction(0) + , m_hasDebuggerEnabled(graph.hasDebuggerEnabled()) { ASSERT(m_profiledBlock); } @@ -168,24 +171,40 @@ private: } // Helper for min and max. - bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis); + template<typename ChecksFunctor> + bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks); // Handle calls. This resolves issues surrounding inlining and intrinsics. + void handleCall( + int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize, + Node* callTarget, int argCount, int registerOffset, CallLinkStatus, + SpeculatedType prediction); + void handleCall( + int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize, + Node* callTarget, int argCount, int registerOffset, CallLinkStatus); void handleCall(int result, NodeType op, CodeSpecializationKind, unsigned instructionSize, int callee, int argCount, int registerOffset); void handleCall(Instruction* pc, NodeType op, CodeSpecializationKind); - void emitFunctionChecks(const CallLinkStatus&, Node* callTarget, int registerOffset, CodeSpecializationKind); - void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind); + void handleVarargsCall(Instruction* pc, NodeType op, CodeSpecializationKind); + void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt); + void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis); + unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CodeSpecializationKind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1. // Handle inlining. Return true if it succeeded, false if we need to plant a call. - bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind); + bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction); + enum CallerLinkability { CallerDoesNormalLinking, CallerLinksManually }; + template<typename ChecksFunctor> + bool attemptToInlineCall(Node* callTargetNode, int resultOperand, CallVariant, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind, CallerLinkability, SpeculatedType prediction, unsigned& inliningBalance, const ChecksFunctor& insertChecks); + template<typename ChecksFunctor> + void inlineCall(Node* callTargetNode, int resultOperand, CallVariant, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind, CallerLinkability, const ChecksFunctor& insertChecks); + void cancelLinkingForBlock(InlineStackEntry*, BasicBlock*); // Only works when the given block is the last one to have been added for that inline stack entry. // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. - bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); - bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType); - bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind); + template<typename ChecksFunctor> + bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks); + template<typename ChecksFunctor> + bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks); + template<typename ChecksFunctor> + bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind, const ChecksFunctor& insertChecks); Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value); - Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset); - void handleGetByOffset( - int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, - PropertyOffset); + Node* handleGetByOffset(SpeculatedType, Node* base, const StructureSet&, unsigned identifierNumber, PropertyOffset, NodeType op = GetByOffset); void handleGetById( int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, const GetByIdStatus&); @@ -194,35 +213,29 @@ private: void handlePutById( Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&, bool isDirect); - Node* emitPrototypeChecks(Structure*, IntendedStructureChain*); + void emitChecks(const ConstantStructureCheckVector&); - Node* getScope(bool skipTop, unsigned skipCount); - - // Prepare to parse a block. void prepareToParseBlock(); + void clearCaches(); + // Parse a single basic block of bytecode instructions. bool parseBlock(unsigned limit); // Link block successors. void linkBlock(BasicBlock*, Vector<BasicBlock*>& possibleTargets); void linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets); - VariableAccessData* newVariableAccessData(VirtualRegister operand, bool isCaptured) + VariableAccessData* newVariableAccessData(VirtualRegister operand) { ASSERT(!operand.isConstant()); - m_graph.m_variableAccessData.append(VariableAccessData(operand, isCaptured)); + m_graph.m_variableAccessData.append(VariableAccessData(operand)); return &m_graph.m_variableAccessData.last(); } // Get/Set the operands/result of a bytecode instruction. Node* getDirect(VirtualRegister operand) { - // Is this a constant? - if (operand.isConstant()) { - unsigned constant = operand.toConstantIndex(); - ASSERT(constant < m_constants.size()); - return getJSConstant(constant); - } + ASSERT(!operand.isConstant()); // Is this an argument? if (operand.isArgument()) @@ -234,18 +247,50 @@ private: Node* get(VirtualRegister operand) { + if (operand.isConstant()) { + unsigned constantIndex = operand.toConstantIndex(); + unsigned oldSize = m_constants.size(); + if (constantIndex >= oldSize || !m_constants[constantIndex]) { + const CodeBlock& codeBlock = *m_inlineStackTop->m_codeBlock; + JSValue value = codeBlock.getConstant(operand.offset()); + SourceCodeRepresentation sourceCodeRepresentation = codeBlock.constantSourceCodeRepresentation(operand.offset()); + if (constantIndex >= oldSize) { + m_constants.grow(constantIndex + 1); + for (unsigned i = oldSize; i < m_constants.size(); ++i) + m_constants[i] = nullptr; + } + + Node* constantNode = nullptr; + if (sourceCodeRepresentation == SourceCodeRepresentation::Double) + constantNode = addToGraph(DoubleConstant, OpInfo(m_graph.freezeStrong(jsDoubleNumber(value.asNumber())))); + else + constantNode = addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(value))); + m_constants[constantIndex] = constantNode; + } + ASSERT(m_constants[constantIndex]); + return m_constants[constantIndex]; + } + if (inlineCallFrame()) { if (!inlineCallFrame()->isClosureCall) { JSFunction* callee = inlineCallFrame()->calleeConstant(); if (operand.offset() == JSStack::Callee) - return cellConstant(callee); - if (operand.offset() == JSStack::ScopeChain) - return cellConstant(callee->scope()); + return weakJSConstant(callee); + } + } else if (operand.offset() == JSStack::Callee) { + // We have to do some constant-folding here because this enables CreateThis folding. Note + // that we don't have such watchpoint-based folding for inlined uses of Callee, since in that + // case if the function is a singleton then we already know it. + if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_codeBlock->ownerExecutable())) { + InferredValue* singleton = executable->singletonFunction(); + if (JSValue value = singleton->inferredValue()) { + m_graph.watchpoints().addLazily(singleton); + JSFunction* function = jsCast<JSFunction*>(value); + return weakJSConstant(function); + } } - } else if (operand.offset() == JSStack::Callee) return addToGraph(GetCallee); - else if (operand.offset() == JSStack::ScopeChain) - return addToGraph(GetMyScope); + } return getDirect(m_inlineStackTop->remapOperand(operand)); } @@ -272,8 +317,8 @@ private: Node* setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) { addToGraph(MovHint, OpInfo(operand.offset()), value); - - DelayedSetLocal delayed = DelayedSetLocal(operand, value); + + DelayedSetLocal delayed(currentCodeOrigin(), operand, value); if (setMode == NormalSet) { m_setLocalQueue.append(delayed); @@ -282,6 +327,13 @@ private: return delayed.execute(this, setMode); } + + void processSetLocalQueue() + { + for (unsigned i = 0; i < m_setLocalQueue.size(); ++i) + m_setLocalQueue[i].execute(this); + m_setLocalQueue.resize(0); + } Node* set(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) { @@ -304,25 +356,7 @@ private: { unsigned local = operand.toLocal(); - if (local < m_localWatchpoints.size()) { - if (VariableWatchpointSet* set = m_localWatchpoints[local]) { - if (JSValue value = set->inferredValue()) { - addToGraph(FunctionReentryWatchpoint, OpInfo(m_codeBlock->symbolTable())); - addToGraph(VariableWatchpoint, OpInfo(set)); - // Note: this is very special from an OSR exit standpoint. We wouldn't be - // able to do this for most locals, but it works here because we're dealing - // with a flushed local. For most locals we would need to issue a GetLocal - // here and ensure that we have uses in DFG IR wherever there would have - // been uses in bytecode. Clearly this optimization does not do this. But - // that's fine, because we don't need to track liveness for captured - // locals, and this optimization only kicks in for captured locals. - return inferredConstant(value); - } - } - } - Node* node = m_currentBlock->variablesAtTail.local(local); - bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame()); // This has two goals: 1) link together variable access datas, and 2) // try to avoid creating redundant GetLocals. (1) is required for @@ -334,45 +368,47 @@ private: if (node) { variable = node->variableAccessData(); - variable->mergeIsCaptured(isCaptured); - if (!isCaptured) { - switch (node->op()) { - case GetLocal: - return node; - case SetLocal: - return node->child1().node(); - default: - break; - } + switch (node->op()) { + case GetLocal: + return node; + case SetLocal: + return node->child1().node(); + default: + break; } } else - variable = newVariableAccessData(operand, isCaptured); + variable = newVariableAccessData(operand); node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable))); m_currentBlock->variablesAtTail.local(local) = node; return node; } - Node* setLocal(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) + Node* setLocal(const CodeOrigin& semanticOrigin, VirtualRegister operand, Node* value, SetMode setMode = NormalSet) { + CodeOrigin oldSemanticOrigin = m_currentSemanticOrigin; + m_currentSemanticOrigin = semanticOrigin; + unsigned local = operand.toLocal(); - bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame()); if (setMode != ImmediateNakedSet) { ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand); - if (isCaptured || argumentPosition) + if (argumentPosition) flushDirect(operand, argumentPosition); + else if (m_hasDebuggerEnabled && operand == m_codeBlock->scopeRegister()) + flush(operand); } - VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured); + VariableAccessData* variableAccessData = newVariableAccessData(operand); variableAccessData->mergeStructureCheckHoistingFailed( - m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint)); + m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex, BadCache)); variableAccessData->mergeCheckArrayHoistingFailed( - m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)); + m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex, BadIndexingType)); Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value); m_currentBlock->variablesAtTail.local(local) = node; + + m_currentSemanticOrigin = oldSemanticOrigin; return node; } @@ -383,13 +419,11 @@ private: ASSERT(argument < m_numArguments); Node* node = m_currentBlock->variablesAtTail.argument(argument); - bool isCaptured = m_codeBlock->isCaptured(operand); VariableAccessData* variable; if (node) { variable = node->variableAccessData(); - variable->mergeIsCaptured(isCaptured); switch (node->op()) { case GetLocal: @@ -400,20 +434,21 @@ private: break; } } else - variable = newVariableAccessData(operand, isCaptured); + variable = newVariableAccessData(operand); node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable))); m_currentBlock->variablesAtTail.argument(argument) = node; return node; } - Node* setArgument(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) + Node* setArgument(const CodeOrigin& semanticOrigin, VirtualRegister operand, Node* value, SetMode setMode = NormalSet) { + CodeOrigin oldSemanticOrigin = m_currentSemanticOrigin; + m_currentSemanticOrigin = semanticOrigin; + unsigned argument = operand.toArgument(); ASSERT(argument < m_numArguments); - bool isCaptured = m_codeBlock->isCaptured(operand); - - VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured); + VariableAccessData* variableAccessData = newVariableAccessData(operand); // Always flush arguments, except for 'this'. If 'this' is created by us, // then make sure that it's never unboxed. @@ -424,12 +459,13 @@ private: variableAccessData->mergeShouldNeverUnbox(true); variableAccessData->mergeStructureCheckHoistingFailed( - m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint)); + m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex, BadCache)); variableAccessData->mergeCheckArrayHoistingFailed( - m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)); + m_inlineStackTop->m_exitProfile.hasExitSite(semanticOrigin.bytecodeIndex, BadIndexingType)); Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value); m_currentBlock->variablesAtTail.argument(argument) = node; + + m_currentSemanticOrigin = oldSemanticOrigin; return node; } @@ -466,18 +502,6 @@ private: return findArgumentPositionForLocal(operand); } - void addConstant(JSValue value) - { - unsigned constantIndex = m_codeBlock->addConstantLazily(); - initializeLazyWriteBarrierForConstant( - m_graph.m_plan.writeBarriers, - m_codeBlock->constants()[constantIndex], - m_codeBlock, - constantIndex, - m_codeBlock->ownerExecutable(), - value); - } - void flush(VirtualRegister operand) { flushDirect(m_inlineStackTop->remapOperand(operand)); @@ -490,19 +514,16 @@ private: void flushDirect(VirtualRegister operand, ArgumentPosition* argumentPosition) { - bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame()); - ASSERT(!operand.isConstant()); Node* node = m_currentBlock->variablesAtTail.operand(operand); VariableAccessData* variable; - if (node) { + if (node) variable = node->variableAccessData(); - variable->mergeIsCaptured(isCaptured); - } else - variable = newVariableAccessData(operand, isCaptured); + else + variable = newVariableAccessData(operand); node = addToGraph(Flush, OpInfo(variable)); m_currentBlock->variablesAtTail.operand(operand) = node; @@ -514,20 +535,18 @@ private: { int numArguments; if (InlineCallFrame* inlineCallFrame = inlineStackEntry->m_inlineCallFrame) { + ASSERT(!m_hasDebuggerEnabled); numArguments = inlineCallFrame->arguments.size(); - if (inlineCallFrame->isClosureCall) { + if (inlineCallFrame->isClosureCall) flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::Callee))); - flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::ScopeChain))); - } + if (inlineCallFrame->isVarargs()) + flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::ArgumentCount))); } else numArguments = inlineStackEntry->m_codeBlock->numParameters(); for (unsigned argument = numArguments; argument-- > 1;) flushDirect(inlineStackEntry->remapOperand(virtualRegisterForArgument(argument))); - for (int local = 0; local < inlineStackEntry->m_codeBlock->m_numVars; ++local) { - if (!inlineStackEntry->m_codeBlock->isCaptured(virtualRegisterForLocal(local))) - continue; - flushDirect(inlineStackEntry->remapOperand(virtualRegisterForLocal(local))); - } + if (m_hasDebuggerEnabled) + flush(m_codeBlock->scopeRegister()); } void flushForTerminal() @@ -554,32 +573,15 @@ private: flushForTerminal(); } - // NOTE: Only use this to construct constants that arise from non-speculative - // constant folding. I.e. creating constants using this if we had constant - // field inference would be a bad idea, since the bytecode parser's folding - // doesn't handle liveness preservation. - Node* getJSConstantForValue(JSValue constantValue) + // Assumes that the constant should be strongly marked. + Node* jsConstant(JSValue constantValue) { - unsigned constantIndex; - if (!m_codeBlock->findConstant(constantValue, constantIndex)) { - addConstant(constantValue); - m_constants.append(ConstantRecord()); - } - - ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); - - return getJSConstant(constantIndex); + return addToGraph(JSConstant, OpInfo(m_graph.freezeStrong(constantValue))); } - Node* getJSConstant(unsigned constant) + Node* weakJSConstant(JSValue constantValue) { - Node* node = m_constants[constant].asJSValue; - if (node) - return node; - - Node* result = addToGraph(JSConstant, OpInfo(constant)); - m_constants[constant].asJSValue = result; - return result; + return addToGraph(JSConstant, OpInfo(m_graph.freeze(constantValue))); } // Helper functions to get/set the this value. @@ -593,149 +595,6 @@ private: set(m_inlineStackTop->m_codeBlock->thisRegister(), value); } - // Convenience methods for checking nodes for constants. - bool isJSConstant(Node* node) - { - return node->op() == JSConstant; - } - bool isInt32Constant(Node* node) - { - return isJSConstant(node) && valueOfJSConstant(node).isInt32(); - } - // Convenience methods for getting constant values. - JSValue valueOfJSConstant(Node* node) - { - ASSERT(isJSConstant(node)); - return m_codeBlock->getConstant(FirstConstantRegisterIndex + node->constantNumber()); - } - int32_t valueOfInt32Constant(Node* node) - { - ASSERT(isInt32Constant(node)); - return valueOfJSConstant(node).asInt32(); - } - - // This method returns a JSConstant with the value 'undefined'. - Node* constantUndefined() - { - // Has m_constantUndefined been set up yet? - if (m_constantUndefined == UINT_MAX) { - // Search the constant pool for undefined, if we find it, we can just reuse this! - unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); - for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) { - JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined); - if (testMe.isUndefined()) - return getJSConstant(m_constantUndefined); - } - - // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants. - ASSERT(m_constants.size() == numberOfConstants); - addConstant(jsUndefined()); - m_constants.append(ConstantRecord()); - ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); - } - - // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'. - ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined()); - return getJSConstant(m_constantUndefined); - } - - // This method returns a JSConstant with the value 'null'. - Node* constantNull() - { - // Has m_constantNull been set up yet? - if (m_constantNull == UINT_MAX) { - // Search the constant pool for null, if we find it, we can just reuse this! - unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); - for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) { - JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull); - if (testMe.isNull()) - return getJSConstant(m_constantNull); - } - - // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants. - ASSERT(m_constants.size() == numberOfConstants); - addConstant(jsNull()); - m_constants.append(ConstantRecord()); - ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); - } - - // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'. - ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull()); - return getJSConstant(m_constantNull); - } - - // This method returns a DoubleConstant with the value 1. - Node* one() - { - // Has m_constant1 been set up yet? - if (m_constant1 == UINT_MAX) { - // Search the constant pool for the value 1, if we find it, we can just reuse this! - unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); - for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) { - JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1); - if (testMe.isInt32() && testMe.asInt32() == 1) - return getJSConstant(m_constant1); - } - - // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants. - ASSERT(m_constants.size() == numberOfConstants); - addConstant(jsNumber(1)); - m_constants.append(ConstantRecord()); - ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); - } - - // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1. - ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32()); - ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1); - return getJSConstant(m_constant1); - } - - // This method returns a DoubleConstant with the value NaN. - Node* constantNaN() - { - JSValue nan = jsNaN(); - - // Has m_constantNaN been set up yet? - if (m_constantNaN == UINT_MAX) { - // Search the constant pool for the value NaN, if we find it, we can just reuse this! - unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); - for (m_constantNaN = 0; m_constantNaN < numberOfConstants; ++m_constantNaN) { - JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN); - if (JSValue::encode(testMe) == JSValue::encode(nan)) - return getJSConstant(m_constantNaN); - } - - // Add the value nan to the CodeBlock's constants, and add a corresponding slot in m_constants. - ASSERT(m_constants.size() == numberOfConstants); - addConstant(nan); - m_constants.append(ConstantRecord()); - ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); - } - - // m_constantNaN must refer to an entry in the CodeBlock's constant pool that has the value nan. - ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).isDouble()); - ASSERT(std::isnan(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).asDouble())); - return getJSConstant(m_constantNaN); - } - - Node* cellConstant(JSCell* cell) - { - HashMap<JSCell*, Node*>::AddResult result = m_cellConstantNodes.add(cell, nullptr); - if (result.isNewEntry) { - ASSERT(!Heap::isZombified(cell)); - result.iterator->value = addToGraph(WeakJSConstant, OpInfo(cell)); - } - - return result.iterator->value; - } - - Node* inferredConstant(JSValue value) - { - if (value.isCell()) - return cellConstant(value.asCell()); - return getJSConstantForValue(value); - } - InlineCallFrame* inlineCallFrame() { return m_inlineStackTop->m_inlineCallFrame; @@ -745,6 +604,15 @@ private: { return CodeOrigin(m_currentIndex, inlineCallFrame()); } + + NodeOrigin currentNodeOrigin() + { + // FIXME: We should set the forExit origin only on those nodes that can exit. + // https://bugs.webkit.org/show_bug.cgi?id=145204 + if (m_currentSemanticOrigin.isSet()) + return NodeOrigin(m_currentSemanticOrigin, currentCodeOrigin()); + return NodeOrigin(currentCodeOrigin()); + } BranchData* branchData(unsigned taken, unsigned notTaken) { @@ -756,91 +624,94 @@ private: return data; } + Node* addToGraph(Node* node) + { + if (Options::verboseDFGByteCodeParsing()) + dataLog(" appended ", node, " ", Graph::opName(node->op()), "\n"); + m_currentBlock->append(node); + return node; + } + Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0) { Node* result = m_graph.addNode( - SpecNone, op, NodeOrigin(currentCodeOrigin()), Edge(child1), Edge(child2), + SpecNone, op, currentNodeOrigin(), Edge(child1), Edge(child2), Edge(child3)); - ASSERT(op != Phi); - m_currentBlock->append(result); - return result; + return addToGraph(result); } Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge()) { Node* result = m_graph.addNode( - SpecNone, op, NodeOrigin(currentCodeOrigin()), child1, child2, child3); - ASSERT(op != Phi); - m_currentBlock->append(result); - return result; + SpecNone, op, currentNodeOrigin(), child1, child2, child3); + return addToGraph(result); } Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0) { Node* result = m_graph.addNode( - SpecNone, op, NodeOrigin(currentCodeOrigin()), info, Edge(child1), Edge(child2), + SpecNone, op, currentNodeOrigin(), info, Edge(child1), Edge(child2), Edge(child3)); - ASSERT(op != Phi); - m_currentBlock->append(result); - return result; + return addToGraph(result); } Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0) { Node* result = m_graph.addNode( - SpecNone, op, NodeOrigin(currentCodeOrigin()), info1, info2, + SpecNone, op, currentNodeOrigin(), info1, info2, Edge(child1), Edge(child2), Edge(child3)); - ASSERT(op != Phi); - m_currentBlock->append(result); - return result; + return addToGraph(result); } Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2) { Node* result = m_graph.addNode( - SpecNone, Node::VarArg, op, NodeOrigin(currentCodeOrigin()), info1, info2, + SpecNone, Node::VarArg, op, currentNodeOrigin(), info1, info2, m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs); - ASSERT(op != Phi); - m_currentBlock->append(result); + addToGraph(result); m_numPassedVarArgs = 0; return result; } - + void addVarArgChild(Node* child) { m_graph.m_varArgChildren.append(Edge(child)); m_numPassedVarArgs++; } - Node* addCall(int result, NodeType op, int callee, int argCount, int registerOffset) + Node* addCallWithoutSettingResult( + NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset, + SpeculatedType prediction) { - SpeculatedType prediction = getPrediction(); - - addVarArgChild(get(VirtualRegister(callee))); + addVarArgChild(callee); size_t parameterSlots = JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + argCount; if (parameterSlots > m_parameterSlots) m_parameterSlots = parameterSlots; - int dummyThisArgument = op == Call ? 0 : 1; - for (int i = 0 + dummyThisArgument; i < argCount; ++i) + for (int i = 0; i < argCount; ++i) addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); - Node* call = addToGraph(Node::VarArg, op, OpInfo(0), OpInfo(prediction)); - set(VirtualRegister(result), call); + return addToGraph(Node::VarArg, op, opInfo, OpInfo(prediction)); + } + + Node* addCall( + int result, NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset, + SpeculatedType prediction) + { + Node* call = addCallWithoutSettingResult( + op, opInfo, callee, argCount, registerOffset, prediction); + VirtualRegister resultReg(result); + if (resultReg.isValid()) + set(resultReg, call); return call; } Node* cellConstantWithStructureCheck(JSCell* object, Structure* structure) { - Node* objectNode = cellConstant(object); + Node* objectNode = weakJSConstant(object); addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectNode); return objectNode; } - Node* cellConstantWithStructureCheck(JSCell* object) - { - return cellConstantWithStructureCheck(object, object->structure()); - } - SpeculatedType getPredictionWithoutOSRExit(unsigned bytecodeIndex) { ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); @@ -874,7 +745,8 @@ private: { ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock); - return ArrayMode::fromObserved(locker, profile, action, false); + bool makeSafe = profile->outOfBounds(locker); + return ArrayMode::fromObserved(locker, profile, action, makeSafe); } ArrayMode getArrayMode(ArrayProfile* profile) @@ -882,21 +754,6 @@ private: return getArrayMode(profile, Array::Read); } - ArrayMode getArrayModeConsideringSlowPath(ArrayProfile* profile, Array::Action action) - { - ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); - - profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock); - - bool makeSafe = - m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) - || profile->outOfBounds(locker); - - ArrayMode result = ArrayMode::fromObserved(locker, profile, action, makeSafe); - - return result; - } - Node* makeSafe(Node* node) { if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) @@ -971,20 +828,14 @@ private: return node; } - bool structureChainIsStillValid(bool direct, Structure* previousStructure, StructureChain* chain) + void noticeArgumentsUse() { - if (direct) - return true; - - if (!previousStructure->storedPrototype().isNull() && previousStructure->storedPrototype().asCell()->structure() != chain->head()->get()) - return false; + // All of the arguments in this function need to be formatted as JSValues because we will + // load from them in a random-access fashion and we don't want to have to switch on + // format. - for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) { - if (!(*it)->storedPrototype().isNull() && (*it)->storedPrototype().asCell()->structure() != it[1].get()) - return false; - } - - return true; + for (ArgumentPosition* argument : m_inlineStackTop->m_argumentPositions) + argument->mergeShouldNeverUnbox(true); } void buildOperandMapsIfNecessary(); @@ -998,37 +849,14 @@ private: BasicBlock* m_currentBlock; // The bytecode index of the current instruction being generated. unsigned m_currentIndex; + // The semantic origin of the current node if different from the current Index. + CodeOrigin m_currentSemanticOrigin; - // We use these values during code generation, and to avoid the need for - // special handling we make sure they are available as constants in the - // CodeBlock's constant pool. These variables are initialized to - // UINT_MAX, and lazily updated to hold an index into the CodeBlock's - // constant pool, as necessary. - unsigned m_constantUndefined; - unsigned m_constantNull; - unsigned m_constantNaN; - unsigned m_constant1; - HashMap<JSCell*, unsigned> m_cellConstants; - HashMap<JSCell*, Node*> m_cellConstantNodes; - - // A constant in the constant pool may be represented by more than one - // node in the graph, depending on the context in which it is being used. - struct ConstantRecord { - ConstantRecord() - : asInt32(0) - , asNumeric(0) - , asJSValue(0) - { - } - - Node* asInt32; - Node* asNumeric; - Node* asJSValue; - }; - - // Track the index of the node whose result is the current value for every - // register value in the bytecode - argument, local, and temporary. - Vector<ConstantRecord, 16> m_constants; + FrozenValue* m_constantUndefined; + FrozenValue* m_constantNull; + FrozenValue* m_constantNaN; + FrozenValue* m_constantOne; + Vector<Node*, 16> m_constants; // The number of arguments passed to the function. unsigned m_numArguments; @@ -1045,8 +873,6 @@ private: HashMap<ConstantBufferKey, unsigned> m_constantBufferCache; - Vector<VariableWatchpointSet*, 16> m_localWatchpoints; - struct InlineStackEntry { ByteCodeParser* m_byteCodeParser; @@ -1063,7 +889,6 @@ private: // (the machine code block, which is the transitive, though not necessarily // direct, caller). Vector<unsigned> m_identifierRemap; - Vector<unsigned> m_constantRemap; Vector<unsigned> m_constantBufferRemap; Vector<unsigned> m_switchRemap; @@ -1075,8 +900,7 @@ private: Vector<UnlinkedBlock> m_unlinkedBlocks; // Potential block linking targets. Must be sorted by bytecodeBegin, and - // cannot have two blocks that have the same bytecodeBegin. For this very - // reason, this is not equivalent to + // cannot have two blocks that have the same bytecodeBegin. Vector<BasicBlock*> m_blockLinkingTargets; // If the callsite's basic block was split into two, then this will be @@ -1122,7 +946,7 @@ private: VirtualRegister returnValueVR, VirtualRegister inlineCallFrameStart, int argumentCountIncludingThis, - CodeSpecializationKind); + InlineCallFrame::Kind); ~InlineStackEntry() { @@ -1134,11 +958,7 @@ private: if (!m_inlineCallFrame) return operand; - if (operand.isConstant()) { - VirtualRegister result = VirtualRegister(m_constantRemap[operand.toConstantIndex()]); - ASSERT(result.isConstant()); - return result; - } + ASSERT(!operand.isConstant()); return VirtualRegister(operand.offset() + m_inlineCallFrame->stackOffset); } @@ -1147,12 +967,14 @@ private: InlineStackEntry* m_inlineStackTop; struct DelayedSetLocal { + CodeOrigin m_origin; VirtualRegister m_operand; Node* m_value; DelayedSetLocal() { } - DelayedSetLocal(VirtualRegister operand, Node* value) - : m_operand(operand) + DelayedSetLocal(const CodeOrigin& origin, VirtualRegister operand, Node* value) + : m_origin(origin) + , m_operand(operand) , m_value(value) { } @@ -1160,8 +982,8 @@ private: Node* execute(ByteCodeParser* parser, SetMode setMode = NormalSet) { if (m_operand.isArgument()) - return parser->setArgument(m_operand, m_value, setMode); - return parser->setLocal(m_operand, m_value, setMode); + return parser->setArgument(m_origin, m_operand, m_value, setMode); + return parser->setLocal(m_origin, m_operand, m_value, setMode); } }; @@ -1172,17 +994,13 @@ private: bool m_haveBuiltOperandMaps; // Mapping between identifier names and numbers. BorrowedIdentifierMap m_identifierMap; - // Mapping between values and constant numbers. - JSValueMap m_jsValueMap; - // Index of the empty value, or UINT_MAX if there is no mapping. This is a horrible - // work-around for the fact that JSValueMap can't handle "empty" values. - unsigned m_emptyJSValueIndex; CodeBlock* m_dfgCodeBlock; CallLinkStatus::ContextMap m_callContextMap; StubInfoMap m_dfgStubInfos; Instruction* m_currentInstruction; + bool m_hasDebuggerEnabled; }; #define NEXT_OPCODE(name) \ @@ -1205,148 +1023,206 @@ void ByteCodeParser::handleCall( int result, NodeType op, CodeSpecializationKind kind, unsigned instructionSize, int callee, int argumentCountIncludingThis, int registerOffset) { - ASSERT(registerOffset <= 0); - Node* callTarget = get(VirtualRegister(callee)); - CallLinkStatus callLinkStatus; + CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( + m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), + m_inlineStackTop->m_callLinkInfos, m_callContextMap); + + handleCall( + result, op, InlineCallFrame::kindFor(kind), instructionSize, callTarget, + argumentCountIncludingThis, registerOffset, callLinkStatus); +} + +void ByteCodeParser::handleCall( + int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize, + Node* callTarget, int argumentCountIncludingThis, int registerOffset, + CallLinkStatus callLinkStatus) +{ + handleCall( + result, op, kind, instructionSize, callTarget, argumentCountIncludingThis, + registerOffset, callLinkStatus, getPrediction()); +} - if (m_graph.isConstant(callTarget)) { - callLinkStatus = CallLinkStatus( - m_graph.valueOfJSConstant(callTarget)).setIsProved(true); - } else { - callLinkStatus = CallLinkStatus::computeFor( - m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), - m_inlineStackTop->m_callLinkInfos, m_callContextMap); - } +void ByteCodeParser::handleCall( + int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize, + Node* callTarget, int argumentCountIncludingThis, int registerOffset, + CallLinkStatus callLinkStatus, SpeculatedType prediction) +{ + ASSERT(registerOffset <= 0); + + if (callTarget->isCellConstant()) + callLinkStatus.setProvenConstantCallee(CallVariant(callTarget->asCell())); + + if (Options::verboseDFGByteCodeParsing()) + dataLog(" Handling call at ", currentCodeOrigin(), ": ", callLinkStatus, "\n"); if (!callLinkStatus.canOptimize()) { // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically // that we cannot optimize them. - addCall(result, op, callee, argumentCountIncludingThis, registerOffset); + addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction); return; } unsigned nextOffset = m_currentIndex + instructionSize; - SpeculatedType prediction = getPrediction(); - - if (InternalFunction* function = callLinkStatus.internalFunction()) { - if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, kind)) { - // This phantoming has to be *after* the code for the intrinsic, to signify that - // the inputs must be kept alive whatever exits the intrinsic may do. - addToGraph(Phantom, callTarget); - emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind); - return; - } - - // Can only handle this using the generic call handler. - addCall(result, op, callee, argumentCountIncludingThis, registerOffset); + + OpInfo callOpInfo; + + if (handleInlining(callTarget, result, callLinkStatus, registerOffset, virtualRegisterForArgument(0, registerOffset), VirtualRegister(), 0, argumentCountIncludingThis, nextOffset, op, kind, prediction)) { + if (m_graph.compilation()) + m_graph.compilation()->noticeInlinedCall(); return; } - - Intrinsic intrinsic = callLinkStatus.intrinsicFor(kind); - if (intrinsic != NoIntrinsic) { - emitFunctionChecks(callLinkStatus, callTarget, registerOffset, kind); - - if (handleIntrinsic(result, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) { - // This phantoming has to be *after* the code for the intrinsic, to signify that - // the inputs must be kept alive whatever exits the intrinsic may do. - addToGraph(Phantom, callTarget); - emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind); - if (m_graph.compilation()) - m_graph.compilation()->noticeInlinedCall(); - return; + +#if ENABLE(FTL_NATIVE_CALL_INLINING) + if (isFTL(m_graph.m_plan.mode) && Options::optimizeNativeCalls() && callLinkStatus.size() == 1 && !callLinkStatus.couldTakeSlowPath()) { + CallVariant callee = callLinkStatus[0]; + JSFunction* function = callee.function(); + CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); + if (function && function->isHostFunction()) { + emitFunctionChecks(callee, callTarget, virtualRegisterForArgument(0, registerOffset)); + callOpInfo = OpInfo(m_graph.freeze(function)); + + if (op == Call) + op = NativeCall; + else { + ASSERT(op == Construct); + op = NativeConstruct; + } } - } else if (handleInlining(callTarget, result, callLinkStatus, registerOffset, argumentCountIncludingThis, nextOffset, kind)) { + } +#endif + + addCall(result, op, callOpInfo, callTarget, argumentCountIncludingThis, registerOffset, prediction); +} + +void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CodeSpecializationKind kind) +{ + ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs)); + + int result = pc[1].u.operand; + int callee = pc[2].u.operand; + int thisReg = pc[3].u.operand; + int arguments = pc[4].u.operand; + int firstFreeReg = pc[5].u.operand; + int firstVarArgOffset = pc[6].u.operand; + + SpeculatedType prediction = getPrediction(); + + Node* callTarget = get(VirtualRegister(callee)); + + CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( + m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), + m_inlineStackTop->m_callLinkInfos, m_callContextMap); + if (callTarget->isCellConstant()) + callLinkStatus.setProvenConstantCallee(CallVariant(callTarget->asCell())); + + if (Options::verboseDFGByteCodeParsing()) + dataLog(" Varargs call link status at ", currentCodeOrigin(), ": ", callLinkStatus, "\n"); + + if (callLinkStatus.canOptimize() + && handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(kind), prediction)) { if (m_graph.compilation()) m_graph.compilation()->noticeInlinedCall(); return; } - addCall(result, op, callee, argumentCountIncludingThis, registerOffset); + CallVarargsData* data = m_graph.m_callVarargsData.add(); + data->firstVarArgOffset = firstVarArgOffset; + + Node* thisChild = get(VirtualRegister(thisReg)); + + Node* call = addToGraph(op, OpInfo(data), OpInfo(prediction), callTarget, get(VirtualRegister(arguments)), thisChild); + VirtualRegister resultReg(result); + if (resultReg.isValid()) + set(resultReg, call); } -void ByteCodeParser::emitFunctionChecks(const CallLinkStatus& callLinkStatus, Node* callTarget, int registerOffset, CodeSpecializationKind kind) +void ByteCodeParser::emitFunctionChecks(CallVariant callee, Node* callTarget, VirtualRegister thisArgumentReg) { Node* thisArgument; - if (kind == CodeForCall) - thisArgument = get(virtualRegisterForArgument(0, registerOffset)); + if (thisArgumentReg.isValid()) + thisArgument = get(thisArgumentReg); else thisArgument = 0; - if (callLinkStatus.isProved()) { - addToGraph(Phantom, callTarget, thisArgument); - return; + JSCell* calleeCell; + Node* callTargetForCheck; + if (callee.isClosureCall()) { + calleeCell = callee.executable(); + callTargetForCheck = addToGraph(GetExecutable, callTarget); + } else { + calleeCell = callee.nonExecutableCallee(); + callTargetForCheck = callTarget; } - ASSERT(callLinkStatus.canOptimize()); - - if (JSFunction* function = callLinkStatus.function()) - addToGraph(CheckFunction, OpInfo(function), callTarget, thisArgument); - else { - ASSERT(callLinkStatus.structure()); - ASSERT(callLinkStatus.executable()); - - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(callLinkStatus.structure())), callTarget); - addToGraph(CheckExecutable, OpInfo(callLinkStatus.executable()), callTarget, thisArgument); - } + ASSERT(calleeCell); + addToGraph(CheckCell, OpInfo(m_graph.freeze(calleeCell)), callTargetForCheck, thisArgument); } -void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind kind) +void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis) { - for (int i = kind == CodeForCall ? 0 : 1; i < argumentCountIncludingThis; ++i) + for (int i = 0; i < argumentCountIncludingThis; ++i) addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset))); } -bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind) +unsigned ByteCodeParser::inliningCost(CallVariant callee, int argumentCountIncludingThis, CodeSpecializationKind kind) { - static const bool verbose = false; - if (verbose) - dataLog("Considering inlining ", callLinkStatus, " into ", currentCodeOrigin(), "\n"); + dataLog("Considering inlining ", callee, " into ", currentCodeOrigin(), "\n"); - // First, the really simple checks: do we have an actual JS function? - if (!callLinkStatus.executable()) { + if (m_hasDebuggerEnabled) { if (verbose) - dataLog(" Failing because there is no executable.\n"); - return false; + dataLog(" Failing because the debugger is in use.\n"); + return UINT_MAX; } - if (callLinkStatus.executable()->isHostFunction()) { + + FunctionExecutable* executable = callee.functionExecutable(); + if (!executable) { if (verbose) - dataLog(" Failing because it's a host function.\n"); - return false; + dataLog(" Failing because there is no function executable.\n"); + return UINT_MAX; } - FunctionExecutable* executable = jsCast<FunctionExecutable*>(callLinkStatus.executable()); - // Does the number of arguments we're passing match the arity of the target? We currently // inline only if the number of arguments passed is greater than or equal to the number // arguments expected. if (static_cast<int>(executable->parameterCount()) + 1 > argumentCountIncludingThis) { if (verbose) dataLog(" Failing because of arity mismatch.\n"); - return false; + return UINT_MAX; } // Do we have a code block, and does the code block's size match the heuristics/requirements for - // being an inline candidate? We might not have a code block if code was thrown away or if we - // simply hadn't actually made this call yet. We could still theoretically attempt to inline it - // if we had a static proof of what was being called; this might happen for example if you call a - // global function, where watchpointing gives us static information. Overall, it's a rare case - // because we expect that any hot callees would have already been compiled. + // being an inline candidate? We might not have a code block (1) if code was thrown away, + // (2) if we simply hadn't actually made this call yet or (3) code is a builtin function and + // specialization kind is construct. In the former 2 cases, we could still theoretically attempt + // to inline it if we had a static proof of what was being called; this might happen for example + // if you call a global function, where watchpointing gives us static information. Overall, + // it's a rare case because we expect that any hot callees would have already been compiled. CodeBlock* codeBlock = executable->baselineCodeBlockFor(kind); if (!codeBlock) { if (verbose) dataLog(" Failing because no code block available.\n"); - return false; + return UINT_MAX; } CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel( - codeBlock, kind, callLinkStatus.isClosureCall()); + codeBlock, kind, callee.isClosureCall()); + if (verbose) { + dataLog(" Kind: ", kind, "\n"); + dataLog(" Is closure call: ", callee.isClosureCall(), "\n"); + dataLog(" Capability level: ", capabilityLevel, "\n"); + dataLog(" Might inline function: ", mightInlineFunctionFor(codeBlock, kind), "\n"); + dataLog(" Might compile function: ", mightCompileFunctionFor(codeBlock, kind), "\n"); + dataLog(" Is supported for inlining: ", isSupportedForInlining(codeBlock), "\n"); + dataLog(" Needs activation: ", codeBlock->ownerExecutable()->needsActivation(), "\n"); + dataLog(" Is inlining candidate: ", codeBlock->ownerExecutable()->isInliningCandidate(), "\n"); + } if (!canInline(capabilityLevel)) { if (verbose) dataLog(" Failing because the function is not inlineable.\n"); - return false; + return UINT_MAX; } // Check if the caller is already too large. We do this check here because that's just @@ -1356,13 +1232,18 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con codeBlock->m_shouldAlwaysBeInlined = false; if (verbose) dataLog(" Failing because the caller is too large.\n"); - return false; + return UINT_MAX; } // FIXME: this should be better at predicting how much bloat we will introduce by inlining // this function. // https://bugs.webkit.org/show_bug.cgi?id=127627 + // FIXME: We currently inline functions that have run in LLInt but not in Baseline. These + // functions have very low fidelity profiling, and presumably they weren't very hot if they + // haven't gotten to Baseline yet. Consider not inlining these functions. + // https://bugs.webkit.org/show_bug.cgi?id=145503 + // Have we exceeded inline stack depth, or are we trying to inline a recursive call to // too many levels? If either of these are detected, then don't inline. We adjust our // heuristics if we are dealing with a function that cannot otherwise be compiled. @@ -1375,7 +1256,7 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con if (depth >= Options::maximumInliningDepth()) { if (verbose) dataLog(" Failing because depth exceeded.\n"); - return false; + return UINT_MAX; } if (entry->executable() == executable) { @@ -1383,19 +1264,28 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con if (recursion >= Options::maximumInliningRecursion()) { if (verbose) dataLog(" Failing because recursion detected.\n"); - return false; + return UINT_MAX; } } } if (verbose) - dataLog(" Committing to inlining.\n"); + dataLog(" Inlining should be possible.\n"); - // Now we know without a doubt that we are committed to inlining. So begin the process - // by checking the callee (if necessary) and making sure that arguments and the callee - // are flushed. - emitFunctionChecks(callLinkStatus, callTargetNode, registerOffset, kind); + // It might be possible to inline. + return codeBlock->instructionCount(); +} + +template<typename ChecksFunctor> +void ByteCodeParser::inlineCall(Node* callTargetNode, int resultOperand, CallVariant callee, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind, CallerLinkability callerLinkability, const ChecksFunctor& insertChecks) +{ + CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); + + ASSERT(inliningCost(callee, argumentCountIncludingThis, specializationKind) != UINT_MAX); + CodeBlock* codeBlock = callee.functionExecutable()->baselineCodeBlockFor(specializationKind); + insertChecks(codeBlock); + // FIXME: Don't flush constants! int inlineCallFrameStart = m_inlineStackTop->remapOperand(VirtualRegister(registerOffset)).offset() + JSStack::CallFrameHeaderSize; @@ -1406,9 +1296,12 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con size_t argumentPositionStart = m_graph.m_argumentPositions.size(); + VirtualRegister resultReg(resultOperand); + if (resultReg.isValid()) + resultReg = m_inlineStackTop->remapOperand(resultReg); + InlineStackEntry inlineStackEntry( - this, codeBlock, codeBlock, m_graph.lastBlock(), callLinkStatus.function(), - m_inlineStackTop->remapOperand(VirtualRegister(resultOperand)), + this, codeBlock, codeBlock, m_graph.lastBlock(), callee.function(), resultReg, (VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind); // This is where the actual inlining really happens. @@ -1422,15 +1315,12 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con RELEASE_ASSERT( m_inlineStackTop->m_inlineCallFrame->isClosureCall - == callLinkStatus.isClosureCall()); - if (callLinkStatus.isClosureCall()) { + == callee.isClosureCall()); + if (callee.isClosureCall()) { VariableAccessData* calleeVariable = set(VirtualRegister(JSStack::Callee), callTargetNode, ImmediateNakedSet)->variableAccessData(); - VariableAccessData* scopeVariable = - set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode), ImmediateNakedSet)->variableAccessData(); calleeVariable->mergeShouldNeverUnbox(true); - scopeVariable->mergeShouldNeverUnbox(true); inlineVariableData.calleeVariable = calleeVariable; } @@ -1438,6 +1328,7 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con m_graph.m_inlineVariableData.append(inlineVariableData); parseCodeBlock(); + clearCaches(); // Reset our state now that we're back to the outer code. m_currentIndex = oldIndex; @@ -1450,20 +1341,8 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con else ASSERT(inlineStackEntry.m_callsiteBlockHead->isLinked); - // It's possible that the callsite block head is not owned by the caller. - if (!inlineStackEntry.m_caller->m_unlinkedBlocks.isEmpty()) { - // It's definitely owned by the caller, because the caller created new blocks. - // Assert that this all adds up. - ASSERT(inlineStackEntry.m_caller->m_unlinkedBlocks.last().m_block == inlineStackEntry.m_callsiteBlockHead); - ASSERT(inlineStackEntry.m_caller->m_unlinkedBlocks.last().m_needsNormalLinking); - inlineStackEntry.m_caller->m_unlinkedBlocks.last().m_needsNormalLinking = false; - } else { - // It's definitely not owned by the caller. Tell the caller that he does not - // need to link his callsite block head, because we did it for him. - ASSERT(inlineStackEntry.m_caller->m_callsiteBlockHeadNeedsLinking); - ASSERT(inlineStackEntry.m_caller->m_callsiteBlockHead == inlineStackEntry.m_callsiteBlockHead); - inlineStackEntry.m_caller->m_callsiteBlockHeadNeedsLinking = false; - } + if (callerLinkability == CallerDoesNormalLinking) + cancelLinkingForBlock(inlineStackEntry.m_caller, inlineStackEntry.m_callsiteBlockHead); linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets); } else @@ -1473,7 +1352,10 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con // If there was a return, but no early returns, then we're done. We allow parsing of // the caller to continue in whatever basic block we're in right now. if (!inlineStackEntry.m_didEarlyReturn && inlineStackEntry.m_didReturn) { - ASSERT(lastBlock->isEmpty() || !lastBlock->last()->isTerminal()); + if (Options::verboseDFGByteCodeParsing()) + dataLog(" Allowing parsing to continue in last inlined block.\n"); + + ASSERT(lastBlock->isEmpty() || !lastBlock->terminal()); // If we created new blocks then the last block needs linking, but in the // caller. It doesn't need to be linked to, but it needs outgoing links. @@ -1481,17 +1363,25 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con // 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 // in the linker's binary search. + if (Options::verboseDFGByteCodeParsing()) + dataLog(" Repurposing last block from ", lastBlock->bytecodeBegin, " to ", m_currentIndex, "\n"); lastBlock->bytecodeBegin = m_currentIndex; - m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(m_graph.lastBlock())); + if (callerLinkability == CallerDoesNormalLinking) { + if (verbose) + dataLog("Adding unlinked block ", RawPointer(m_graph.lastBlock()), " (one return)\n"); + m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(m_graph.lastBlock())); + } } m_currentBlock = m_graph.lastBlock(); - return true; + return; } + if (Options::verboseDFGByteCodeParsing()) + dataLog(" Creating new block after inlining.\n"); + // If we get to this point then all blocks must end in some sort of terminals. - ASSERT(lastBlock->last()->isTerminal()); - + ASSERT(lastBlock->terminal()); // Need to create a new basic block for the continuation at the caller. RefPtr<BasicBlock> block = adoptRef(new BasicBlock(nextOffset, m_numArguments, m_numLocals, PNaN)); @@ -1502,36 +1392,441 @@ bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, con continue; BasicBlock* blockToLink = inlineStackEntry.m_unlinkedBlocks[i].m_block; ASSERT(!blockToLink->isLinked); - Node* node = blockToLink->last(); + Node* node = blockToLink->terminal(); ASSERT(node->op() == Jump); ASSERT(!node->targetBlock()); node->targetBlock() = block.get(); inlineStackEntry.m_unlinkedBlocks[i].m_needsEarlyReturnLinking = false; -#if !ASSERT_DISABLED - blockToLink->isLinked = true; -#endif + if (verbose) + dataLog("Marking ", RawPointer(blockToLink), " as linked (jumps to return)\n"); + blockToLink->didLink(); } m_currentBlock = block.get(); ASSERT(m_inlineStackTop->m_caller->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_caller->m_blockLinkingTargets.last()->bytecodeBegin < nextOffset); - m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(block.get())); - m_inlineStackTop->m_caller->m_blockLinkingTargets.append(block.get()); + if (verbose) + dataLog("Adding unlinked block ", RawPointer(block.get()), " (many returns)\n"); + if (callerLinkability == CallerDoesNormalLinking) { + m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(block.get())); + m_inlineStackTop->m_caller->m_blockLinkingTargets.append(block.get()); + } m_graph.appendBlock(block); prepareToParseBlock(); +} + +void ByteCodeParser::cancelLinkingForBlock(InlineStackEntry* inlineStackEntry, BasicBlock* block) +{ + // It's possible that the callsite block head is not owned by the caller. + if (!inlineStackEntry->m_unlinkedBlocks.isEmpty()) { + // It's definitely owned by the caller, because the caller created new blocks. + // Assert that this all adds up. + ASSERT_UNUSED(block, inlineStackEntry->m_unlinkedBlocks.last().m_block == block); + ASSERT(inlineStackEntry->m_unlinkedBlocks.last().m_needsNormalLinking); + inlineStackEntry->m_unlinkedBlocks.last().m_needsNormalLinking = false; + } else { + // It's definitely not owned by the caller. Tell the caller that he does not + // need to link his callsite block head, because we did it for him. + ASSERT(inlineStackEntry->m_callsiteBlockHeadNeedsLinking); + ASSERT_UNUSED(block, inlineStackEntry->m_callsiteBlockHead == block); + inlineStackEntry->m_callsiteBlockHeadNeedsLinking = false; + } +} + +template<typename ChecksFunctor> +bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand, CallVariant callee, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind, CallerLinkability callerLinkability, SpeculatedType prediction, unsigned& inliningBalance, const ChecksFunctor& insertChecks) +{ + CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); + + if (!inliningBalance) + return false; + + bool didInsertChecks = false; + auto insertChecksWithAccounting = [&] () { + insertChecks(nullptr); + didInsertChecks = true; + }; + + if (verbose) + dataLog(" Considering callee ", callee, "\n"); + + // Intrinsics and internal functions can only be inlined if we're not doing varargs. This is because + // we currently don't have any way of getting profiling information for arguments to non-JS varargs + // calls. The prediction propagator won't be of any help because LoadVarargs obscures the data flow, + // and there are no callsite value profiles and native function won't have callee value profiles for + // those arguments. Even worse, if the intrinsic decides to exit, it won't really have anywhere to + // exit to: LoadVarargs is effectful and it's part of the op_call_varargs, so we can't exit without + // calling LoadVarargs twice. + if (!InlineCallFrame::isVarargs(kind)) { + if (InternalFunction* function = callee.internalFunction()) { + if (handleConstantInternalFunction(resultOperand, function, registerOffset, argumentCountIncludingThis, specializationKind, insertChecksWithAccounting)) { + RELEASE_ASSERT(didInsertChecks); + addToGraph(Phantom, callTargetNode); + emitArgumentPhantoms(registerOffset, argumentCountIncludingThis); + inliningBalance--; + return true; + } + RELEASE_ASSERT(!didInsertChecks); + return false; + } + + Intrinsic intrinsic = callee.intrinsicFor(specializationKind); + if (intrinsic != NoIntrinsic) { + if (handleIntrinsic(resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) { + RELEASE_ASSERT(didInsertChecks); + addToGraph(Phantom, callTargetNode); + emitArgumentPhantoms(registerOffset, argumentCountIncludingThis); + inliningBalance--; + return true; + } + RELEASE_ASSERT(!didInsertChecks); + return false; + } + } - // At this point we return and continue to generate code for the caller, but - // in the new basic block. + unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, specializationKind); + if (myInliningCost > inliningBalance) + return false; + + Instruction* savedCurrentInstruction = m_currentInstruction; + inlineCall(callTargetNode, resultOperand, callee, registerOffset, argumentCountIncludingThis, nextOffset, kind, callerLinkability, insertChecks); + inliningBalance -= myInliningCost; + m_currentInstruction = savedCurrentInstruction; return true; } -bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis) +bool ByteCodeParser::handleInlining( + Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, + int registerOffsetOrFirstFreeReg, VirtualRegister thisArgument, + VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, + unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind kind, SpeculatedType prediction) +{ + if (verbose) { + dataLog("Handling inlining...\n"); + dataLog("Stack: ", currentCodeOrigin(), "\n"); + } + CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); + + if (!callLinkStatus.size()) { + if (verbose) + dataLog("Bailing inlining.\n"); + return false; + } + + if (InlineCallFrame::isVarargs(kind) + && callLinkStatus.maxNumArguments() > Options::maximumVarargsForInlining()) { + if (verbose) + dataLog("Bailing inlining because of varargs.\n"); + return false; + } + + unsigned inliningBalance = Options::maximumFunctionForCallInlineCandidateInstructionCount(); + if (specializationKind == CodeForConstruct) + inliningBalance = std::min(inliningBalance, Options::maximumFunctionForConstructInlineCandidateInstructionCount()); + if (callLinkStatus.isClosureCall()) + inliningBalance = std::min(inliningBalance, Options::maximumFunctionForClosureCallInlineCandidateInstructionCount()); + + // First check if we can avoid creating control flow. Our inliner does some CFG + // simplification on the fly and this helps reduce compile times, but we can only leverage + // this in cases where we don't need control flow diamonds to check the callee. + if (!callLinkStatus.couldTakeSlowPath() && callLinkStatus.size() == 1) { + int registerOffset; + + // Only used for varargs calls. + unsigned mandatoryMinimum = 0; + unsigned maxNumArguments = 0; + + if (InlineCallFrame::isVarargs(kind)) { + if (FunctionExecutable* functionExecutable = callLinkStatus[0].functionExecutable()) + mandatoryMinimum = functionExecutable->parameterCount(); + else + mandatoryMinimum = 0; + + // includes "this" + maxNumArguments = std::max( + callLinkStatus.maxNumArguments(), + mandatoryMinimum + 1); + + // We sort of pretend that this *is* the number of arguments that were passed. + argumentCountIncludingThis = maxNumArguments; + + registerOffset = registerOffsetOrFirstFreeReg + 1; + registerOffset -= maxNumArguments; // includes "this" + registerOffset -= JSStack::CallFrameHeaderSize; + registerOffset = -WTF::roundUpToMultipleOf( + stackAlignmentRegisters(), + -registerOffset); + } else + registerOffset = registerOffsetOrFirstFreeReg; + + bool result = attemptToInlineCall( + callTargetNode, resultOperand, callLinkStatus[0], registerOffset, + argumentCountIncludingThis, nextOffset, kind, CallerDoesNormalLinking, prediction, + inliningBalance, [&] (CodeBlock* codeBlock) { + emitFunctionChecks(callLinkStatus[0], callTargetNode, thisArgument); + + // If we have a varargs call, we want to extract the arguments right now. + if (InlineCallFrame::isVarargs(kind)) { + int remappedRegisterOffset = + m_inlineStackTop->remapOperand(VirtualRegister(registerOffset)).offset(); + + ensureLocals(VirtualRegister(remappedRegisterOffset).toLocal()); + + int argumentStart = registerOffset + JSStack::CallFrameHeaderSize; + int remappedArgumentStart = + m_inlineStackTop->remapOperand(VirtualRegister(argumentStart)).offset(); + + LoadVarargsData* data = m_graph.m_loadVarargsData.add(); + data->start = VirtualRegister(remappedArgumentStart + 1); + data->count = VirtualRegister(remappedRegisterOffset + JSStack::ArgumentCount); + data->offset = argumentsOffset; + data->limit = maxNumArguments; + data->mandatoryMinimum = mandatoryMinimum; + + addToGraph(LoadVarargs, OpInfo(data), get(argumentsArgument)); + + // LoadVarargs may OSR exit. Hence, we need to keep alive callTargetNode, thisArgument + // and argumentsArgument for the baseline JIT. However, we only need a Phantom for + // callTargetNode because the other 2 are still in use and alive at this point. + addToGraph(Phantom, callTargetNode); + + // In DFG IR before SSA, we cannot insert control flow between after the + // LoadVarargs and the last SetArgument. This isn't a problem once we get to DFG + // SSA. Fortunately, we also have other reasons for not inserting control flow + // before SSA. + + VariableAccessData* countVariable = newVariableAccessData( + VirtualRegister(remappedRegisterOffset + JSStack::ArgumentCount)); + // This is pretty lame, but it will force the count to be flushed as an int. This doesn't + // matter very much, since our use of a SetArgument and Flushes for this local slot is + // mostly just a formality. + countVariable->predict(SpecInt32); + countVariable->mergeIsProfitableToUnbox(true); + Node* setArgumentCount = addToGraph(SetArgument, OpInfo(countVariable)); + m_currentBlock->variablesAtTail.setOperand(countVariable->local(), setArgumentCount); + + set(VirtualRegister(argumentStart), get(thisArgument), ImmediateNakedSet); + for (unsigned argument = 1; argument < maxNumArguments; ++argument) { + VariableAccessData* variable = newVariableAccessData( + VirtualRegister(remappedArgumentStart + argument)); + variable->mergeShouldNeverUnbox(true); // We currently have nowhere to put the type check on the LoadVarargs. LoadVarargs is effectful, so after it finishes, we cannot exit. + + // For a while it had been my intention to do things like this inside the + // prediction injection phase. But in this case it's really best to do it here, + // because it's here that we have access to the variable access datas for the + // inlining we're about to do. + // + // Something else that's interesting here is that we'd really love to get + // predictions from the arguments loaded at the callsite, rather than the + // arguments received inside the callee. But that probably won't matter for most + // calls. + if (codeBlock && argument < static_cast<unsigned>(codeBlock->numParameters())) { + ConcurrentJITLocker locker(codeBlock->m_lock); + if (ValueProfile* profile = codeBlock->valueProfileForArgument(argument)) + variable->predict(profile->computeUpdatedPrediction(locker)); + } + + Node* setArgument = addToGraph(SetArgument, OpInfo(variable)); + m_currentBlock->variablesAtTail.setOperand(variable->local(), setArgument); + } + } + }); + if (verbose) { + dataLog("Done inlining (simple).\n"); + dataLog("Stack: ", currentCodeOrigin(), "\n"); + dataLog("Result: ", result, "\n"); + } + return result; + } + + // We need to create some kind of switch over callee. For now we only do this if we believe that + // we're in the top tier. We have two reasons for this: first, it provides us an opportunity to + // do more detailed polyvariant/polymorphic profiling; and second, it reduces compile times in + // the DFG. And by polyvariant profiling we mean polyvariant profiling of *this* call. Note that + // we could improve that aspect of this by doing polymorphic inlining but having the profiling + // also. + if (!isFTL(m_graph.m_plan.mode) || !Options::enablePolymorphicCallInlining() + || InlineCallFrame::isVarargs(kind)) { + if (verbose) { + dataLog("Bailing inlining (hard).\n"); + dataLog("Stack: ", currentCodeOrigin(), "\n"); + } + return false; + } + + unsigned oldOffset = m_currentIndex; + + bool allAreClosureCalls = true; + bool allAreDirectCalls = true; + for (unsigned i = callLinkStatus.size(); i--;) { + if (callLinkStatus[i].isClosureCall()) + allAreDirectCalls = false; + else + allAreClosureCalls = false; + } + + Node* thingToSwitchOn; + if (allAreDirectCalls) + thingToSwitchOn = callTargetNode; + else if (allAreClosureCalls) + thingToSwitchOn = addToGraph(GetExecutable, callTargetNode); + else { + // FIXME: We should be able to handle this case, but it's tricky and we don't know of cases + // where it would be beneficial. It might be best to handle these cases as if all calls were + // closure calls. + // https://bugs.webkit.org/show_bug.cgi?id=136020 + if (verbose) { + dataLog("Bailing inlining (mix).\n"); + dataLog("Stack: ", currentCodeOrigin(), "\n"); + } + return false; + } + + if (verbose) { + dataLog("Doing hard inlining...\n"); + dataLog("Stack: ", currentCodeOrigin(), "\n"); + } + + int registerOffset = registerOffsetOrFirstFreeReg; + + // This makes me wish that we were in SSA all the time. We need to pick a variable into which to + // store the callee so that it will be accessible to all of the blocks we're about to create. We + // get away with doing an immediate-set here because we wouldn't have performed any side effects + // yet. + if (verbose) + dataLog("Register offset: ", registerOffset); + VirtualRegister calleeReg(registerOffset + JSStack::Callee); + calleeReg = m_inlineStackTop->remapOperand(calleeReg); + if (verbose) + dataLog("Callee is going to be ", calleeReg, "\n"); + setDirect(calleeReg, callTargetNode, ImmediateSetWithFlush); + + SwitchData& data = *m_graph.m_switchData.add(); + data.kind = SwitchCell; + addToGraph(Switch, OpInfo(&data), thingToSwitchOn); + + BasicBlock* originBlock = m_currentBlock; + if (verbose) + dataLog("Marking ", RawPointer(originBlock), " as linked (origin of poly inline)\n"); + originBlock->didLink(); + cancelLinkingForBlock(m_inlineStackTop, originBlock); + + // Each inlined callee will have a landing block that it returns at. They should all have jumps + // to the continuation block, which we create last. + Vector<BasicBlock*> landingBlocks; + + // We may force this true if we give up on inlining any of the edges. + bool couldTakeSlowPath = callLinkStatus.couldTakeSlowPath(); + + if (verbose) + dataLog("About to loop over functions at ", currentCodeOrigin(), ".\n"); + + for (unsigned i = 0; i < callLinkStatus.size(); ++i) { + m_currentIndex = oldOffset; + RefPtr<BasicBlock> block = adoptRef(new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, PNaN)); + m_currentBlock = block.get(); + m_graph.appendBlock(block); + prepareToParseBlock(); + + Node* myCallTargetNode = getDirect(calleeReg); + + bool inliningResult = attemptToInlineCall( + myCallTargetNode, resultOperand, callLinkStatus[i], registerOffset, + argumentCountIncludingThis, nextOffset, kind, CallerLinksManually, prediction, + inliningBalance, [&] (CodeBlock*) { }); + + if (!inliningResult) { + // That failed so we let the block die. Nothing interesting should have been added to + // the block. We also give up on inlining any of the (less frequent) callees. + ASSERT(m_currentBlock == block.get()); + ASSERT(m_graph.m_blocks.last() == block); + m_graph.killBlockAndItsContents(block.get()); + m_graph.m_blocks.removeLast(); + + // The fact that inlining failed means we need a slow path. + couldTakeSlowPath = true; + break; + } + + JSCell* thingToCaseOn; + if (allAreDirectCalls) + thingToCaseOn = callLinkStatus[i].nonExecutableCallee(); + else { + ASSERT(allAreClosureCalls); + thingToCaseOn = callLinkStatus[i].executable(); + } + data.cases.append(SwitchCase(m_graph.freeze(thingToCaseOn), block.get())); + m_currentIndex = nextOffset; + processSetLocalQueue(); // This only comes into play for intrinsics, since normal inlined code will leave an empty queue. + addToGraph(Jump); + if (verbose) + dataLog("Marking ", RawPointer(m_currentBlock), " as linked (tail of poly inlinee)\n"); + m_currentBlock->didLink(); + landingBlocks.append(m_currentBlock); + + if (verbose) + dataLog("Finished inlining ", callLinkStatus[i], " at ", currentCodeOrigin(), ".\n"); + } + + RefPtr<BasicBlock> slowPathBlock = adoptRef( + new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, PNaN)); + m_currentIndex = oldOffset; + data.fallThrough = BranchTarget(slowPathBlock.get()); + m_graph.appendBlock(slowPathBlock); + if (verbose) + dataLog("Marking ", RawPointer(slowPathBlock.get()), " as linked (slow path block)\n"); + slowPathBlock->didLink(); + prepareToParseBlock(); + m_currentBlock = slowPathBlock.get(); + Node* myCallTargetNode = getDirect(calleeReg); + if (couldTakeSlowPath) { + addCall( + resultOperand, callOp, OpInfo(), myCallTargetNode, argumentCountIncludingThis, + registerOffset, prediction); + } else { + addToGraph(CheckBadCell); + addToGraph(Phantom, myCallTargetNode); + emitArgumentPhantoms(registerOffset, argumentCountIncludingThis); + + set(VirtualRegister(resultOperand), addToGraph(BottomValue)); + } + + m_currentIndex = nextOffset; + processSetLocalQueue(); + addToGraph(Jump); + landingBlocks.append(m_currentBlock); + + RefPtr<BasicBlock> continuationBlock = adoptRef( + new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, PNaN)); + m_graph.appendBlock(continuationBlock); + if (verbose) + dataLog("Adding unlinked block ", RawPointer(continuationBlock.get()), " (continuation)\n"); + m_inlineStackTop->m_unlinkedBlocks.append(UnlinkedBlock(continuationBlock.get())); + prepareToParseBlock(); + m_currentBlock = continuationBlock.get(); + + for (unsigned i = landingBlocks.size(); i--;) + landingBlocks[i]->terminal()->targetBlock() = continuationBlock.get(); + + m_currentIndex = oldOffset; + + if (verbose) { + dataLog("Done inlining (hard).\n"); + dataLog("Stack: ", currentCodeOrigin(), "\n"); + } + return true; +} + +template<typename ChecksFunctor> +bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis, const ChecksFunctor& insertChecks) { if (argumentCountIncludingThis == 1) { // Math.min() - set(VirtualRegister(resultOperand), constantNaN()); + insertChecks(); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN))); return true; } if (argumentCountIncludingThis == 2) { // Math.min(x) + insertChecks(); Node* result = get(VirtualRegister(virtualRegisterForArgument(1, registerOffset))); addToGraph(Phantom, Edge(result, NumberUse)); set(VirtualRegister(resultOperand), result); @@ -1539,6 +1834,7 @@ bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOf } if (argumentCountIncludingThis == 3) { // Math.min(x, y) + insertChecks(); set(VirtualRegister(resultOperand), addToGraph(op, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); return true; } @@ -1547,18 +1843,21 @@ bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOf return false; } -bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction) +template<typename ChecksFunctor> +bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks) { switch (intrinsic) { case AbsIntrinsic: { if (argumentCountIncludingThis == 1) { // Math.abs() - set(VirtualRegister(resultOperand), constantNaN()); + insertChecks(); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN))); return true; } if (!MacroAssembler::supportsFloatingPointAbs()) return false; + insertChecks(); Node* node = addToGraph(ArithAbs, get(virtualRegisterForArgument(1, registerOffset))); if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) node->mergeFlags(NodeMayOverflowInDFG); @@ -1567,40 +1866,61 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int } case MinIntrinsic: - return handleMinMax(resultOperand, ArithMin, registerOffset, argumentCountIncludingThis); + return handleMinMax(resultOperand, ArithMin, registerOffset, argumentCountIncludingThis, insertChecks); case MaxIntrinsic: - return handleMinMax(resultOperand, ArithMax, registerOffset, argumentCountIncludingThis); - + return handleMinMax(resultOperand, ArithMax, registerOffset, argumentCountIncludingThis, insertChecks); + case SqrtIntrinsic: case CosIntrinsic: - case SinIntrinsic: { + case SinIntrinsic: + case LogIntrinsic: { if (argumentCountIncludingThis == 1) { - set(VirtualRegister(resultOperand), constantNaN()); + insertChecks(); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN))); return true; } switch (intrinsic) { case SqrtIntrinsic: - if (!MacroAssembler::supportsFloatingPointSqrt()) - return false; - + insertChecks(); set(VirtualRegister(resultOperand), addToGraph(ArithSqrt, get(virtualRegisterForArgument(1, registerOffset)))); return true; case CosIntrinsic: + insertChecks(); set(VirtualRegister(resultOperand), addToGraph(ArithCos, get(virtualRegisterForArgument(1, registerOffset)))); return true; case SinIntrinsic: + insertChecks(); set(VirtualRegister(resultOperand), addToGraph(ArithSin, get(virtualRegisterForArgument(1, registerOffset)))); return true; + + case LogIntrinsic: + insertChecks(); + set(VirtualRegister(resultOperand), addToGraph(ArithLog, get(virtualRegisterForArgument(1, registerOffset)))); + return true; default: RELEASE_ASSERT_NOT_REACHED(); return false; } } + + case PowIntrinsic: { + if (argumentCountIncludingThis < 3) { + // Math.pow() and Math.pow(x) return NaN. + insertChecks(); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN))); + return true; + } + insertChecks(); + VirtualRegister xOperand = virtualRegisterForArgument(1, registerOffset); + VirtualRegister yOperand = virtualRegisterForArgument(2, registerOffset); + set(VirtualRegister(resultOperand), addToGraph(ArithPow, get(xOperand), get(yOperand))); + return true; + } case ArrayPushIntrinsic: { if (argumentCountIncludingThis != 2) @@ -1615,6 +1935,7 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int case Array::Double: case Array::Contiguous: case Array::ArrayStorage: { + insertChecks(); Node* arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); set(VirtualRegister(resultOperand), arrayPush); @@ -1638,6 +1959,7 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int case Array::Double: case Array::Contiguous: case Array::ArrayStorage: { + insertChecks(); Node* arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset))); set(VirtualRegister(resultOperand), arrayPop); return true; @@ -1652,6 +1974,7 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int if (argumentCountIncludingThis != 2) return false; + insertChecks(); VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand)); @@ -1664,6 +1987,7 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int if (argumentCountIncludingThis != 2) return false; + insertChecks(); VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand)); @@ -1671,10 +1995,21 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int set(VirtualRegister(resultOperand), charCode); return true; } + case Clz32Intrinsic: { + insertChecks(); + if (argumentCountIncludingThis == 1) + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_graph.freeze(jsNumber(32))))); + else { + Node* operand = get(virtualRegisterForArgument(1, registerOffset)); + set(VirtualRegister(resultOperand), addToGraph(ArithClz32, operand)); + } + return true; + } case FromCharCodeIntrinsic: { if (argumentCountIncludingThis != 2) return false; + insertChecks(); VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); Node* charCode = addToGraph(StringFromCharCode, get(indexOperand)); @@ -1687,6 +2022,7 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int if (argumentCountIncludingThis != 2) return false; + insertChecks(); Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); set(VirtualRegister(resultOperand), regExpExec); @@ -1697,15 +2033,31 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int if (argumentCountIncludingThis != 2) return false; + insertChecks(); Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); set(VirtualRegister(resultOperand), regExpExec); return true; } - + case RoundIntrinsic: { + if (argumentCountIncludingThis == 1) { + insertChecks(); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN))); + return true; + } + if (argumentCountIncludingThis == 2) { + insertChecks(); + Node* operand = get(virtualRegisterForArgument(1, registerOffset)); + Node* roundNode = addToGraph(ArithRound, OpInfo(0), OpInfo(prediction), operand); + set(VirtualRegister(resultOperand), roundNode); + return true; + } + return false; + } case IMulIntrinsic: { if (argumentCountIncludingThis != 3) return false; + insertChecks(); VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset); VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset); Node* left = get(leftOperand); @@ -1717,41 +2069,57 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int case FRoundIntrinsic: { if (argumentCountIncludingThis != 2) return false; + insertChecks(); VirtualRegister operand = virtualRegisterForArgument(1, registerOffset); set(VirtualRegister(resultOperand), addToGraph(ArithFRound, get(operand))); return true; } case DFGTrueIntrinsic: { - set(VirtualRegister(resultOperand), getJSConstantForValue(jsBoolean(true))); + insertChecks(); + set(VirtualRegister(resultOperand), jsConstant(jsBoolean(true))); return true; } case OSRExitIntrinsic: { + insertChecks(); addToGraph(ForceOSRExit); - set(VirtualRegister(resultOperand), constantUndefined()); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantUndefined))); return true; } case IsFinalTierIntrinsic: { + insertChecks(); set(VirtualRegister(resultOperand), - getJSConstantForValue(jsBoolean(Options::useFTLJIT() ? isFTL(m_graph.m_plan.mode) : true))); + jsConstant(jsBoolean(Options::useFTLJIT() ? isFTL(m_graph.m_plan.mode) : true))); return true; } case SetInt32HeapPredictionIntrinsic: { + insertChecks(); for (int i = 1; i < argumentCountIncludingThis; ++i) { Node* node = get(virtualRegisterForArgument(i, registerOffset)); if (node->hasHeapPrediction()) node->setHeapPrediction(SpecInt32); } - set(VirtualRegister(resultOperand), constantUndefined()); + set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantUndefined))); + return true; + } + + case CheckInt32Intrinsic: { + insertChecks(); + for (int i = 1; i < argumentCountIncludingThis; ++i) { + Node* node = get(virtualRegisterForArgument(i, registerOffset)); + addToGraph(Phantom, Edge(node, Int32Use)); + } + set(VirtualRegister(resultOperand), jsConstant(jsBoolean(true))); return true; } case FiatInt52Intrinsic: { if (argumentCountIncludingThis != 2) return false; + insertChecks(); VirtualRegister operand = virtualRegisterForArgument(1, registerOffset); if (enableInt52()) set(VirtualRegister(resultOperand), addToGraph(FiatInt52, get(operand))); @@ -1765,9 +2133,10 @@ bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int } } +template<typename ChecksFunctor> bool ByteCodeParser::handleTypedArrayConstructor( int resultOperand, InternalFunction* function, int registerOffset, - int argumentCountIncludingThis, TypedArrayType type) + int argumentCountIncludingThis, TypedArrayType type, const ChecksFunctor& insertChecks) { if (!isTypedView(type)) return false; @@ -1811,16 +2180,21 @@ bool ByteCodeParser::handleTypedArrayConstructor( if (argumentCountIncludingThis != 2) return false; - + + insertChecks(); set(VirtualRegister(resultOperand), addToGraph(NewTypedArray, OpInfo(type), get(virtualRegisterForArgument(1, registerOffset)))); return true; } +template<typename ChecksFunctor> bool ByteCodeParser::handleConstantInternalFunction( int resultOperand, InternalFunction* function, int registerOffset, - int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind kind) + int argumentCountIncludingThis, CodeSpecializationKind kind, const ChecksFunctor& insertChecks) { + if (verbose) + dataLog(" Handling constant internal function ", JSValue(function), "\n"); + // If we ever find that we have a lot of internal functions that we specialize for, // then we should probably have some sort of hashtable dispatch, or maybe even // dispatch straight through the MethodTable of the InternalFunction. But for now, @@ -1828,18 +2202,18 @@ bool ByteCodeParser::handleConstantInternalFunction( // we know about is small enough, that having just a linear cascade of if statements // is good enough. - UNUSED_PARAM(prediction); // Remove this once we do more things. - if (function->classInfo() == ArrayConstructor::info()) { if (function->globalObject() != m_inlineStackTop->m_codeBlock->globalObject()) return false; + insertChecks(); if (argumentCountIncludingThis == 2) { set(VirtualRegister(resultOperand), addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(virtualRegisterForArgument(1, registerOffset)))); return true; } + // FIXME: Array constructor should use "this" as newTarget. for (int i = 1; i < argumentCountIncludingThis; ++i) addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); set(VirtualRegister(resultOperand), @@ -1848,12 +2222,14 @@ bool ByteCodeParser::handleConstantInternalFunction( } if (function->classInfo() == StringConstructor::info()) { + insertChecks(); + Node* result; if (argumentCountIncludingThis <= 1) - result = cellConstant(m_vm->smallStrings.emptyString()); + result = jsConstant(m_vm->smallStrings.emptyString()); else - result = addToGraph(ToString, get(virtualRegisterForArgument(1, registerOffset))); + result = addToGraph(CallStringConstructor, get(virtualRegisterForArgument(1, registerOffset))); if (kind == CodeForConstruct) result = addToGraph(NewStringObject, OpInfo(function->globalObject()->stringObjectStructure()), result); @@ -1865,7 +2241,7 @@ bool ByteCodeParser::handleConstantInternalFunction( for (unsigned typeIndex = 0; typeIndex < NUMBER_OF_TYPED_ARRAY_TYPES; ++typeIndex) { bool result = handleTypedArrayConstructor( resultOperand, function, registerOffset, argumentCountIncludingThis, - indexToTypedArrayType(typeIndex)); + indexToTypedArrayType(typeIndex), insertChecks); if (result) return true; } @@ -1873,30 +2249,30 @@ bool ByteCodeParser::handleConstantInternalFunction( return false; } -Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset) +Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, const StructureSet& structureSet, unsigned identifierNumber, PropertyOffset offset, NodeType op) { + if (base->hasConstant()) { + if (JSValue constant = m_graph.tryGetConstantProperty(base->asJSValue(), structureSet, offset)) { + addToGraph(Phantom, base); + return weakJSConstant(constant); + } + } + Node* propertyStorage; if (isInlineOffset(offset)) propertyStorage = base; else propertyStorage = addToGraph(GetButterfly, base); - Node* getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base); - - StorageAccessData storageAccessData; - storageAccessData.offset = offset; - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); + + StorageAccessData* data = m_graph.m_storageAccessData.add(); + data->offset = offset; + data->identifierNumber = identifierNumber; + + Node* getByOffset = addToGraph(op, OpInfo(data), OpInfo(prediction), propertyStorage, base); return getByOffset; } -void ByteCodeParser::handleGetByOffset( - int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber, - PropertyOffset offset) -{ - set(VirtualRegister(destinationOperand), handleGetByOffset(prediction, base, identifierNumber, offset)); -} - Node* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, PropertyOffset offset, Node* value) { Node* propertyStorage; @@ -1904,47 +2280,39 @@ Node* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, Propert propertyStorage = base; else propertyStorage = addToGraph(GetButterfly, base); - Node* result = addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, base, value); - StorageAccessData storageAccessData; - storageAccessData.offset = offset; - storageAccessData.identifierNumber = identifier; - m_graph.m_storageAccessData.append(storageAccessData); - + StorageAccessData* data = m_graph.m_storageAccessData.add(); + data->offset = offset; + data->identifierNumber = identifier; + + Node* result = addToGraph(PutByOffset, OpInfo(data), propertyStorage, base, value); + return result; } -Node* ByteCodeParser::emitPrototypeChecks( - Structure* structure, IntendedStructureChain* chain) +void ByteCodeParser::emitChecks(const ConstantStructureCheckVector& vector) { - Node* base = 0; - m_graph.chains().addLazily(chain); - Structure* currentStructure = structure; - JSObject* currentObject = 0; - for (unsigned i = 0; i < chain->size(); ++i) { - currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock)); - currentStructure = chain->at(i); - base = cellConstantWithStructureCheck(currentObject, currentStructure); - } - return base; + for (unsigned i = 0; i < vector.size(); ++i) + cellConstantWithStructureCheck(vector[i].constant(), vector[i].structure()); } void ByteCodeParser::handleGetById( int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber, const GetByIdStatus& getByIdStatus) { - if (!getByIdStatus.isSimple() || !Options::enableAccessInlining()) { + NodeType getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById; + + if (!getByIdStatus.isSimple() || !getByIdStatus.numVariants() || !Options::enableAccessInlining()) { set(VirtualRegister(destinationOperand), - addToGraph( - getByIdStatus.makesCalls() ? GetByIdFlush : GetById, - OpInfo(identifierNumber), OpInfo(prediction), base)); + addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base)); return; } if (getByIdStatus.numVariants() > 1) { - if (!isFTL(m_graph.m_plan.mode) || !Options::enablePolymorphicAccessInlining()) { + if (getByIdStatus.makesCalls() || !isFTL(m_graph.m_plan.mode) + || !Options::enablePolymorphicAccessInlining()) { set(VirtualRegister(destinationOperand), - addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); + addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base)); return; } @@ -1954,13 +2322,8 @@ void ByteCodeParser::handleGetById( // 1) Emit prototype structure checks for all chains. This could sort of maybe not be // optimal, if there is some rarely executed case in the chain that requires a lot // of checks and those checks are not watchpointable. - for (unsigned variantIndex = getByIdStatus.numVariants(); variantIndex--;) { - if (getByIdStatus[variantIndex].chain()) { - emitPrototypeChecks( - getByIdStatus[variantIndex].structureSet().singletonStructure(), - getByIdStatus[variantIndex].chain()); - } - } + for (unsigned variantIndex = getByIdStatus.numVariants(); variantIndex--;) + emitChecks(getByIdStatus[variantIndex].constantChecks()); // 2) Emit a MultiGetByOffset MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add(); @@ -1977,33 +2340,68 @@ void ByteCodeParser::handleGetById( if (m_graph.compilation()) m_graph.compilation()->noticeInlinedGetById(); - Node* originalBaseForBaselineJIT = base; + Node* originalBase = base; addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base); - if (variant.chain()) { - base = emitPrototypeChecks( - variant.structureSet().singletonStructure(), variant.chain()); - } + emitChecks(variant.constantChecks()); + + if (variant.alternateBase()) + base = weakJSConstant(variant.alternateBase()); // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to // ensure that the base of the original get_by_id is kept alive until we're done with // all of the speculations. We only insert the Phantom if there had been a CheckStructure - // on something other than the base following the CheckStructure on base, or if the - // access was compiled to a WeakJSConstant specific value, in which case we might not - // have any explicit use of the base at all. - if (variant.specificValue() || originalBaseForBaselineJIT != base) - addToGraph(Phantom, originalBaseForBaselineJIT); + // on something other than the base following the CheckStructure on base. + if (originalBase != base) + addToGraph(Phantom, originalBase); - if (variant.specificValue()) { - ASSERT(variant.specificValue().isCell()); - - set(VirtualRegister(destinationOperand), cellConstant(variant.specificValue().asCell())); + Node* loadedValue = handleGetByOffset( + variant.callLinkStatus() ? SpecCellOther : prediction, + base, variant.baseStructure(), identifierNumber, variant.offset(), + variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset); + + if (!variant.callLinkStatus()) { + set(VirtualRegister(destinationOperand), loadedValue); return; } - handleGetByOffset( - destinationOperand, prediction, base, identifierNumber, variant.offset()); + Node* getter = addToGraph(GetGetter, loadedValue); + + // Make a call. We don't try to get fancy with using the smallest operand number because + // the stack layout phase should compress the stack anyway. + + unsigned numberOfParameters = 0; + numberOfParameters++; // The 'this' argument. + numberOfParameters++; // True return PC. + + // Start with a register offset that corresponds to the last in-use register. + int registerOffset = virtualRegisterForLocal( + m_inlineStackTop->m_profiledBlock->m_numCalleeRegisters - 1).offset(); + registerOffset -= numberOfParameters; + registerOffset -= JSStack::CallFrameHeaderSize; + + // Get the alignment right. + registerOffset = -WTF::roundUpToMultipleOf( + stackAlignmentRegisters(), + -registerOffset); + + ensureLocals( + m_inlineStackTop->remapOperand( + VirtualRegister(registerOffset)).toLocal()); + + // Issue SetLocals. This has two effects: + // 1) That's how handleCall() sees the arguments. + // 2) If we inline then this ensures that the arguments are flushed so that if you use + // the dreaded arguments object on the getter, the right things happen. Well, sort of - + // since we only really care about 'this' in this case. But we're not going to take that + // shortcut. + int nextRegister = registerOffset + JSStack::CallFrameHeaderSize; + set(VirtualRegister(nextRegister++), originalBase, ImmediateNakedSet); + + handleCall( + destinationOperand, Call, InlineCallFrame::GetterCall, OPCODE_LENGTH(op_get_by_id), + getter, numberOfParameters - 1, registerOffset, *variant.callLinkStatus(), prediction); } void ByteCodeParser::emitPutById( @@ -2019,7 +2417,7 @@ void ByteCodeParser::handlePutById( Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus& putByIdStatus, bool isDirect) { - if (!putByIdStatus.isSimple() || !Options::enableAccessInlining()) { + if (!putByIdStatus.isSimple() || !putByIdStatus.numVariants() || !Options::enableAccessInlining()) { if (!putByIdStatus.isSet()) addToGraph(ForceOSRExit); emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); @@ -2040,11 +2438,7 @@ void ByteCodeParser::handlePutById( for (unsigned variantIndex = putByIdStatus.numVariants(); variantIndex--;) { if (putByIdStatus[variantIndex].kind() != PutByIdVariant::Transition) continue; - if (!putByIdStatus[variantIndex].structureChain()) - continue; - emitPrototypeChecks( - putByIdStatus[variantIndex].oldStructure(), - putByIdStatus[variantIndex].structureChain()); + emitChecks(putByIdStatus[variantIndex].constantChecks()); } } @@ -2058,7 +2452,8 @@ void ByteCodeParser::handlePutById( ASSERT(putByIdStatus.numVariants() == 1); const PutByIdVariant& variant = putByIdStatus[0]; - if (variant.kind() == PutByIdVariant::Replace) { + switch (variant.kind()) { + case PutByIdVariant::Replace: { addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structure())), base); handlePutByOffset(base, identifierNumber, variant.offset(), value); if (m_graph.compilation()) @@ -2066,85 +2461,124 @@ void ByteCodeParser::handlePutById( return; } - if (variant.kind() != PutByIdVariant::Transition) { - emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); - return; - } - - if (variant.structureChain() && !variant.structureChain()->isStillValid()) { - emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); - return; - } - - m_graph.chains().addLazily(variant.structureChain()); - - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base); - if (!isDirect) - emitPrototypeChecks(variant.oldStructure(), variant.structureChain()); + case PutByIdVariant::Transition: { + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base); + emitChecks(variant.constantChecks()); - ASSERT(variant.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); + ASSERT(variant.oldStructureForTransition()->transitionWatchpointSetHasBeenInvalidated()); - Node* propertyStorage; - StructureTransitionData* transitionData = m_graph.addStructureTransitionData( - StructureTransitionData(variant.oldStructure(), variant.newStructure())); + Node* propertyStorage; + Transition* transition = m_graph.m_transitions.add( + variant.oldStructureForTransition(), variant.newStructure()); - if (variant.oldStructure()->outOfLineCapacity() - != variant.newStructure()->outOfLineCapacity()) { + if (variant.reallocatesStorage()) { - // If we're growing the property storage then it must be because we're - // storing into the out-of-line storage. - ASSERT(!isInlineOffset(variant.offset())); + // If we're growing the property storage then it must be because we're + // storing into the out-of-line storage. + ASSERT(!isInlineOffset(variant.offset())); - if (!variant.oldStructure()->outOfLineCapacity()) { - propertyStorage = addToGraph( - AllocatePropertyStorage, OpInfo(transitionData), base); + if (!variant.oldStructureForTransition()->outOfLineCapacity()) { + propertyStorage = addToGraph( + AllocatePropertyStorage, OpInfo(transition), base); + } else { + propertyStorage = addToGraph( + ReallocatePropertyStorage, OpInfo(transition), + base, addToGraph(GetButterfly, base)); + } } else { - propertyStorage = addToGraph( - ReallocatePropertyStorage, OpInfo(transitionData), - base, addToGraph(GetButterfly, base)); + if (isInlineOffset(variant.offset())) + propertyStorage = base; + else + propertyStorage = addToGraph(GetButterfly, base); } - } else { - if (isInlineOffset(variant.offset())) - propertyStorage = base; - else - propertyStorage = addToGraph(GetButterfly, base); - } - addToGraph(PutStructure, OpInfo(transitionData), base); - - addToGraph( - PutByOffset, - OpInfo(m_graph.m_storageAccessData.size()), - propertyStorage, - base, - value); + StorageAccessData* data = m_graph.m_storageAccessData.add(); + data->offset = variant.offset(); + data->identifierNumber = identifierNumber; + + addToGraph( + PutByOffset, + OpInfo(data), + propertyStorage, + base, + value); - StorageAccessData storageAccessData; - storageAccessData.offset = variant.offset(); - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); + // FIXME: PutStructure goes last until we fix either + // https://bugs.webkit.org/show_bug.cgi?id=142921 or + // https://bugs.webkit.org/show_bug.cgi?id=142924. + addToGraph(PutStructure, OpInfo(transition), base); - if (m_graph.compilation()) - m_graph.compilation()->noticeInlinedPutById(); + if (m_graph.compilation()) + m_graph.compilation()->noticeInlinedPutById(); + return; + } + + case PutByIdVariant::Setter: { + Node* originalBase = base; + + addToGraph( + CheckStructure, OpInfo(m_graph.addStructureSet(variant.structure())), base); + + emitChecks(variant.constantChecks()); + + if (variant.alternateBase()) + base = weakJSConstant(variant.alternateBase()); + + Node* loadedValue = handleGetByOffset( + SpecCellOther, base, variant.baseStructure(), identifierNumber, variant.offset(), + GetGetterSetterByOffset); + + Node* setter = addToGraph(GetSetter, loadedValue); + + // Make a call. We don't try to get fancy with using the smallest operand number because + // the stack layout phase should compress the stack anyway. + + unsigned numberOfParameters = 0; + numberOfParameters++; // The 'this' argument. + numberOfParameters++; // The new value. + numberOfParameters++; // True return PC. + + // Start with a register offset that corresponds to the last in-use register. + int registerOffset = virtualRegisterForLocal( + m_inlineStackTop->m_profiledBlock->m_numCalleeRegisters - 1).offset(); + registerOffset -= numberOfParameters; + registerOffset -= JSStack::CallFrameHeaderSize; + + // Get the alignment right. + registerOffset = -WTF::roundUpToMultipleOf( + stackAlignmentRegisters(), + -registerOffset); + + ensureLocals( + m_inlineStackTop->remapOperand( + VirtualRegister(registerOffset)).toLocal()); + + int nextRegister = registerOffset + JSStack::CallFrameHeaderSize; + set(VirtualRegister(nextRegister++), originalBase, ImmediateNakedSet); + set(VirtualRegister(nextRegister++), value, ImmediateNakedSet); + + handleCall( + VirtualRegister().offset(), Call, InlineCallFrame::SetterCall, + OPCODE_LENGTH(op_put_by_id), setter, numberOfParameters - 1, registerOffset, + *variant.callLinkStatus(), SpecOther); + return; + } + + default: { + emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); + return; + } } } void ByteCodeParser::prepareToParseBlock() { - for (unsigned i = 0; i < m_constants.size(); ++i) - m_constants[i] = ConstantRecord(); - m_cellConstantNodes.clear(); + clearCaches(); + ASSERT(m_setLocalQueue.isEmpty()); } -Node* ByteCodeParser::getScope(bool skipTop, unsigned skipCount) +void ByteCodeParser::clearCaches() { - Node* localBase = get(VirtualRegister(JSStack::ScopeChain)); - if (skipTop) { - ASSERT(!inlineCallFrame()); - localBase = addToGraph(SkipTopScope, localBase); - } - for (unsigned n = skipCount; n--;) - localBase = addToGraph(SkipScope, localBase); - return localBase; + m_constants.resize(0); } bool ByteCodeParser::parseBlock(unsigned limit) @@ -2162,10 +2596,9 @@ bool ByteCodeParser::parseBlock(unsigned limit) m_graph.m_arguments.resize(m_numArguments); for (unsigned argument = 0; argument < m_numArguments; ++argument) { VariableAccessData* variable = newVariableAccessData( - virtualRegisterForArgument(argument), m_codeBlock->isCaptured(virtualRegisterForArgument(argument))); + virtualRegisterForArgument(argument)); variable->mergeStructureCheckHoistingFailed( - m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint)); + m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)); variable->mergeCheckArrayHoistingFailed( m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)); @@ -2176,9 +2609,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) } while (true) { - for (unsigned i = 0; i < m_setLocalQueue.size(); ++i) - m_setLocalQueue[i].execute(this); - m_setLocalQueue.resize(0); + processSetLocalQueue(); // Don't extend over jump destinations. if (m_currentIndex == limit) { @@ -2211,28 +2642,23 @@ bool ByteCodeParser::parseBlock(unsigned limit) // === Function entry opcodes === - case op_enter: + case op_enter: { + Node* undefined = addToGraph(JSConstant, OpInfo(m_constantUndefined)); // Initialize all locals to undefined. for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i) - set(virtualRegisterForLocal(i), constantUndefined(), ImmediateNakedSet); - if (m_inlineStackTop->m_codeBlock->specializationKind() == CodeForConstruct) - set(virtualRegisterForArgument(0), constantUndefined(), ImmediateNakedSet); + set(virtualRegisterForLocal(i), undefined, ImmediateNakedSet); NEXT_OPCODE(op_enter); - - case op_touch_entry: - if (m_inlineStackTop->m_codeBlock->symbolTable()->m_functionEnteredOnce.isStillValid()) - addToGraph(ForceOSRExit); - NEXT_OPCODE(op_touch_entry); + } case op_to_this: { Node* op1 = getThis(); if (op1->op() != ToThis) { Structure* cachedStructure = currentInstruction[2].u.structure.get(); - if (!cachedStructure + if (currentInstruction[2].u.toThisStatus != ToThisOK + || !cachedStructure || cachedStructure->classInfo()->methodTable.toThis != JSObject::info()->methodTable.toThis || m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint) || (op1->op() == GetLocal && op1->variableAccessData()->structureCheckHoistingFailed())) { setThis(addToGraph(ToThis, op1)); } else { @@ -2248,18 +2674,34 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_create_this: { int calleeOperand = currentInstruction[2].u.operand; Node* callee = get(VirtualRegister(calleeOperand)); + + JSFunction* function = callee->dynamicCastConstant<JSFunction*>(); + if (!function) { + JSCell* cachedFunction = currentInstruction[4].u.jsCell.unvalidatedGet(); + if (cachedFunction + && cachedFunction != JSCell::seenMultipleCalleeObjects() + && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) { + ASSERT(cachedFunction->inherits(JSFunction::info())); + + FrozenValue* frozen = m_graph.freeze(cachedFunction); + addToGraph(CheckCell, OpInfo(frozen), callee); + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(JSConstant, OpInfo(frozen))); + + function = static_cast<JSFunction*>(cachedFunction); + } + } + bool alreadyEmitted = false; - if (callee->op() == WeakJSConstant) { - JSCell* cell = callee->weakConstant(); - ASSERT(cell->inherits(JSFunction::info())); - - JSFunction* function = jsCast<JSFunction*>(cell); - if (Structure* structure = function->allocationStructure()) { - addToGraph(AllocationProfileWatchpoint, OpInfo(function)); - // The callee is still live up to this point. - addToGraph(Phantom, callee); - set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewObject, OpInfo(structure))); - alreadyEmitted = true; + if (function) { + if (FunctionRareData* rareData = function->rareData()) { + if (Structure* structure = rareData->allocationStructure()) { + m_graph.freeze(rareData); + m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet()); + // The callee is still live up to this point. + addToGraph(Phantom, callee); + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewObject, OpInfo(structure))); + alreadyEmitted = true; + } } } if (!alreadyEmitted) { @@ -2320,21 +2762,6 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_new_regexp); } - case op_get_callee: { - JSCell* cachedFunction = currentInstruction[2].u.jsCell.get(); - if (!cachedFunction - || m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadFunction)) { - set(VirtualRegister(currentInstruction[1].u.operand), get(VirtualRegister(JSStack::Callee))); - } else { - ASSERT(cachedFunction->inherits(JSFunction::info())); - Node* actualCallee = get(VirtualRegister(JSStack::Callee)); - addToGraph(CheckFunction, OpInfo(cachedFunction), actualCallee); - set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(WeakJSConstant, OpInfo(cachedFunction))); - } - NEXT_OPCODE(op_get_callee); - } - // === Bitwise operations === case op_bitand: { @@ -2394,7 +2821,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) int srcDst = currentInstruction[1].u.operand; VirtualRegister srcDstVirtualRegister = VirtualRegister(srcDst); Node* op = get(srcDstVirtualRegister); - set(srcDstVirtualRegister, makeSafe(addToGraph(ArithAdd, op, one()))); + set(srcDstVirtualRegister, makeSafe(addToGraph(ArithAdd, op, addToGraph(JSConstant, OpInfo(m_constantOne))))); NEXT_OPCODE(op_inc); } @@ -2402,7 +2829,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) int srcDst = currentInstruction[1].u.operand; VirtualRegister srcDstVirtualRegister = VirtualRegister(srcDst); Node* op = get(srcDstVirtualRegister); - set(srcDstVirtualRegister, makeSafe(addToGraph(ArithSub, op, one()))); + set(srcDstVirtualRegister, makeSafe(addToGraph(ArithSub, op, addToGraph(JSConstant, OpInfo(m_constantOne))))); NEXT_OPCODE(op_dec); } @@ -2474,15 +2901,11 @@ bool ByteCodeParser::parseBlock(unsigned limit) set(VirtualRegister(currentInstruction[1].u.operand), op); NEXT_OPCODE(op_mov); } - - case op_captured_mov: { - Node* op = get(VirtualRegister(currentInstruction[2].u.operand)); - if (VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet) { - if (set->state() != IsInvalidated) - addToGraph(NotifyWrite, OpInfo(set), op); - } - set(VirtualRegister(currentInstruction[1].u.operand), op); - NEXT_OPCODE(op_captured_mov); + + case op_check_tdz: { + Node* op = get(VirtualRegister(currentInstruction[1].u.operand)); + addToGraph(CheckNotEmpty, op); + NEXT_OPCODE(op_check_tdz); } case op_check_has_instance: @@ -2526,6 +2949,12 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_is_object); } + case op_is_object_or_null: { + Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsObjectOrNull, value)); + NEXT_OPCODE(op_is_object_or_null); + } + case op_is_function: { Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsFunction, value)); @@ -2619,7 +3048,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_eq_null: { Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); - set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareEqConstant, value, constantNull())); + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull)))); NEXT_OPCODE(op_eq_null); } @@ -2639,7 +3068,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_neq_null: { Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); - set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, addToGraph(CompareEqConstant, value, constantNull()))); + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull))))); NEXT_OPCODE(op_neq_null); } @@ -2655,10 +3084,10 @@ bool ByteCodeParser::parseBlock(unsigned limit) // === Property access operations === case op_get_by_val: { - SpeculatedType prediction = getPrediction(); + SpeculatedType prediction = getPredictionWithoutOSRExit(); Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); - ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read); + ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read); Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property); set(VirtualRegister(currentInstruction[1].u.operand), getByVal); @@ -2670,7 +3099,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_put_by_val: { Node* base = get(VirtualRegister(currentInstruction[1].u.operand)); - ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Write); + ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Write); Node* property = get(VirtualRegister(currentInstruction[2].u.operand)); Node* value = get(VirtualRegister(currentInstruction[3].u.operand)); @@ -2693,7 +3122,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; - StringImpl* uid = m_graph.identifiers()[identifierNumber]; + UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock, m_inlineStackTop->m_stubInfos, m_dfgStubInfos, @@ -2730,20 +3159,33 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_init_global_const: { Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); + JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); addToGraph( PutGlobalVar, - OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), - value); + OpInfo(globalObject->assertVariableIsInThisObject(currentInstruction[1].u.variablePointer)), + weakJSConstant(globalObject), value); NEXT_OPCODE(op_init_global_const); } + case op_profile_type: { + Node* valueToProfile = get(VirtualRegister(currentInstruction[1].u.operand)); + addToGraph(ProfileType, OpInfo(currentInstruction[2].u.location), valueToProfile); + NEXT_OPCODE(op_profile_type); + } + + case op_profile_control_flow: { + BasicBlockLocation* basicBlockLocation = currentInstruction[1].u.basicBlockLocation; + addToGraph(ProfileControlFlow, OpInfo(basicBlockLocation)); + NEXT_OPCODE(op_profile_control_flow); + } + // === Block terminators. === case op_jmp: { int relativeOffset = currentInstruction[1].u.operand; + addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); if (relativeOffset <= 0) flushForTerminal(); - addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); LAST_OPCODE(op_jmp); } @@ -2764,7 +3206,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_jeq_null: { unsigned relativeOffset = currentInstruction[2].u.operand; Node* value = get(VirtualRegister(currentInstruction[1].u.operand)); - Node* condition = addToGraph(CompareEqConstant, value, constantNull()); + Node* condition = addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull))); addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jeq_null))), condition); LAST_OPCODE(op_jeq_null); } @@ -2772,7 +3214,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_jneq_null: { unsigned relativeOffset = currentInstruction[2].u.operand; Node* value = get(VirtualRegister(currentInstruction[1].u.operand)); - Node* condition = addToGraph(CompareEqConstant, value, constantNull()); + Node* condition = addToGraph(CompareEqConstant, value, addToGraph(JSConstant, OpInfo(m_constantNull))); addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jneq_null), m_currentIndex + relativeOffset)), condition); LAST_OPCODE(op_jneq_null); } @@ -2861,10 +3303,10 @@ bool ByteCodeParser::parseBlock(unsigned limit) unsigned target = m_currentIndex + table.branchOffsets[i]; if (target == data.fallThrough.bytecodeIndex()) continue; - data.cases.append(SwitchCase::withBytecodeIndex(jsNumber(static_cast<int32_t>(table.min + i)), target)); + data.cases.append(SwitchCase::withBytecodeIndex(m_graph.freeze(jsNumber(static_cast<int32_t>(table.min + i))), target)); } - flushIfTerminal(data); addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand))); + flushIfTerminal(data); LAST_OPCODE(op_switch_imm); } @@ -2883,8 +3325,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) data.cases.append( SwitchCase::withBytecodeIndex(LazyJSValue::singleCharacterString(table.min + i), target)); } - flushIfTerminal(data); addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand))); + flushIfTerminal(data); LAST_OPCODE(op_switch_char); } @@ -2903,16 +3345,16 @@ bool ByteCodeParser::parseBlock(unsigned limit) data.cases.append( SwitchCase::withBytecodeIndex(LazyJSValue::knownStringImpl(iter->key.get()), target)); } - flushIfTerminal(data); addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand))); + flushIfTerminal(data); LAST_OPCODE(op_switch_string); } case op_ret: - flushForReturn(); if (inlineCallFrame()) { - ASSERT(m_inlineStackTop->m_returnValue.isValid()); - setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush); + flushForReturn(); + if (m_inlineStackTop->m_returnValue.isValid()) + setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush); m_inlineStackTop->m_didReturn = true; if (m_inlineStackTop->m_unlinkedBlocks.isEmpty()) { // If we're returning from the first block, then we're done parsing. @@ -2934,12 +3376,13 @@ bool ByteCodeParser::parseBlock(unsigned limit) LAST_OPCODE(op_ret); } addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand))); + flushForReturn(); LAST_OPCODE(op_ret); case op_end: - flushForReturn(); ASSERT(!inlineCallFrame()); addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand))); + flushForReturn(); LAST_OPCODE(op_end); case op_throw: @@ -2956,6 +3399,8 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_call: handleCall(currentInstruction, Call, CodeForCall); + // Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction + ASSERT(m_currentInstruction == currentInstruction); NEXT_OPCODE(op_call); case op_construct: @@ -2963,64 +3408,32 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_construct); case op_call_varargs: { - int result = currentInstruction[1].u.operand; - int callee = currentInstruction[2].u.operand; - int thisReg = currentInstruction[3].u.operand; - int arguments = currentInstruction[4].u.operand; - int firstFreeReg = currentInstruction[5].u.operand; - - ASSERT(inlineCallFrame()); - ASSERT_UNUSED(arguments, arguments == m_inlineStackTop->m_codeBlock->argumentsRegister().offset()); - ASSERT(!m_inlineStackTop->m_codeBlock->symbolTable()->slowArguments()); - - addToGraph(CheckArgumentsNotCreated); - - unsigned argCount = inlineCallFrame()->arguments.size(); - - // Let's compute the register offset. We start with the last used register, and - // then adjust for the things we want in the call frame. - int registerOffset = firstFreeReg + 1; - registerOffset -= argCount; // We will be passing some arguments. - registerOffset -= JSStack::CallFrameHeaderSize; // We will pretend to have a call frame header. - - // Get the alignment right. - registerOffset = -WTF::roundUpToMultipleOf( - stackAlignmentRegisters(), - -registerOffset); - - ensureLocals( - m_inlineStackTop->remapOperand( - VirtualRegister(registerOffset)).toLocal()); - - // The bytecode wouldn't have set up the arguments. But we'll do it and make it - // look like the bytecode had done it. - int nextRegister = registerOffset + JSStack::CallFrameHeaderSize; - set(VirtualRegister(nextRegister++), get(VirtualRegister(thisReg)), ImmediateNakedSet); - for (unsigned argument = 1; argument < argCount; ++argument) - set(VirtualRegister(nextRegister++), get(virtualRegisterForArgument(argument)), ImmediateNakedSet); - - handleCall( - result, Call, CodeForCall, OPCODE_LENGTH(op_call_varargs), - callee, argCount, registerOffset); + handleVarargsCall(currentInstruction, CallVarargs, CodeForCall); NEXT_OPCODE(op_call_varargs); } + case op_construct_varargs: { + handleVarargsCall(currentInstruction, ConstructVarargs, CodeForConstruct); + NEXT_OPCODE(op_construct_varargs); + } + case op_jneq_ptr: // Statically speculate for now. It makes sense to let speculate-only jneq_ptr // support simmer for a while before making it more general, since it's // already gnarly enough as it is. ASSERT(pointerIsFunction(currentInstruction[2].u.specialPointer)); addToGraph( - CheckFunction, - OpInfo(actualPointerFor(m_inlineStackTop->m_codeBlock, currentInstruction[2].u.specialPointer)), + CheckCell, + OpInfo(m_graph.freeze(static_cast<JSCell*>(actualPointerFor( + m_inlineStackTop->m_codeBlock, currentInstruction[2].u.specialPointer)))), get(VirtualRegister(currentInstruction[1].u.operand))); addToGraph(Jump, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr))); LAST_OPCODE(op_jneq_ptr); case op_resolve_scope: { int dst = currentInstruction[1].u.operand; - ResolveType resolveType = static_cast<ResolveType>(currentInstruction[3].u.operand); - unsigned depth = currentInstruction[4].u.operand; + ResolveType resolveType = static_cast<ResolveType>(currentInstruction[4].u.operand); + unsigned depth = currentInstruction[5].u.operand; // get_from_scope and put_to_scope depend on this watchpoint forcing OSR exit, so they don't add their own watchpoints. if (needsVarInjectionChecks(resolveType)) @@ -3031,19 +3444,35 @@ bool ByteCodeParser::parseBlock(unsigned limit) case GlobalVar: case GlobalPropertyWithVarInjectionChecks: case GlobalVarWithVarInjectionChecks: - set(VirtualRegister(dst), cellConstant(m_inlineStackTop->m_codeBlock->globalObject())); + set(VirtualRegister(dst), weakJSConstant(m_inlineStackTop->m_codeBlock->globalObject())); + if (resolveType == GlobalPropertyWithVarInjectionChecks || resolveType == GlobalVarWithVarInjectionChecks) + addToGraph(Phantom, getDirect(m_inlineStackTop->remapOperand(VirtualRegister(currentInstruction[2].u.operand)))); break; + case LocalClosureVar: case ClosureVar: case ClosureVarWithVarInjectionChecks: { - JSActivation* activation = currentInstruction[5].u.activation.get(); - if (activation - && activation->symbolTable()->m_functionEnteredOnce.isStillValid()) { - addToGraph(FunctionReentryWatchpoint, OpInfo(activation->symbolTable())); - set(VirtualRegister(dst), cellConstant(activation)); + Node* localBase = get(VirtualRegister(currentInstruction[2].u.operand)); + addToGraph(Phantom, localBase); // OSR exit cannot handle resolve_scope on a DCE'd scope. + + // We have various forms of constant folding here. This is necessary to avoid + // spurious recompiles in dead-but-foldable code. + if (SymbolTable* symbolTable = currentInstruction[6].u.symbolTable.get()) { + InferredValue* singleton = symbolTable->singletonScope(); + if (JSValue value = singleton->inferredValue()) { + m_graph.watchpoints().addLazily(singleton); + set(VirtualRegister(dst), weakJSConstant(value)); + break; + } + } + if (JSScope* scope = localBase->dynamicCastConstant<JSScope*>()) { + for (unsigned n = depth; n--;) + scope = scope->next(); + set(VirtualRegister(dst), weakJSConstant(scope)); break; } - set(VirtualRegister(dst), - getScope(m_inlineStackTop->m_codeBlock->needsActivation(), depth)); + for (unsigned n = depth; n--;) + localBase = addToGraph(SkipScope, localBase); + set(VirtualRegister(dst), localBase); break; } case Dynamic: @@ -3057,7 +3486,7 @@ bool ByteCodeParser::parseBlock(unsigned limit) int dst = currentInstruction[1].u.operand; int scope = currentInstruction[2].u.operand; unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; - StringImpl* uid = m_graph.identifiers()[identifierNumber]; + UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type(); Structure* structure = 0; @@ -3074,62 +3503,115 @@ bool ByteCodeParser::parseBlock(unsigned limit) UNUSED_PARAM(watchpoints); // We will use this in the future. For now we set it as a way of documenting the fact that that's what index 5 is in GlobalVar mode. - SpeculatedType prediction = getPrediction(); JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); switch (resolveType) { case GlobalProperty: case GlobalPropertyWithVarInjectionChecks: { - GetByIdStatus status = GetByIdStatus::computeFor(*m_vm, structure, uid); - if (status.state() != GetByIdStatus::Simple || status.numVariants() != 1) { + SpeculatedType prediction = getPrediction(); + GetByIdStatus status = GetByIdStatus::computeFor(structure, uid); + if (status.state() != GetByIdStatus::Simple + || status.numVariants() != 1 + || status[0].structureSet().size() != 1) { set(VirtualRegister(dst), addToGraph(GetByIdFlush, OpInfo(identifierNumber), OpInfo(prediction), get(VirtualRegister(scope)))); break; } - Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().singletonStructure()); + Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().onlyStructure()); addToGraph(Phantom, get(VirtualRegister(scope))); - if (JSValue specificValue = status[0].specificValue()) - set(VirtualRegister(dst), cellConstant(specificValue.asCell())); - else - set(VirtualRegister(dst), handleGetByOffset(prediction, base, identifierNumber, operand)); + set(VirtualRegister(dst), handleGetByOffset(prediction, base, status[0].structureSet(), identifierNumber, operand)); break; } case GlobalVar: case GlobalVarWithVarInjectionChecks: { addToGraph(Phantom, get(VirtualRegister(scope))); - SymbolTableEntry entry = globalObject->symbolTable()->get(uid); - VariableWatchpointSet* watchpointSet = entry.watchpointSet(); - JSValue specificValue = - watchpointSet ? watchpointSet->inferredValue() : JSValue(); - if (!specificValue) { - set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction))); - break; + WatchpointSet* watchpointSet; + ScopeOffset offset; + { + ConcurrentJITLocker locker(globalObject->symbolTable()->m_lock); + SymbolTableEntry entry = globalObject->symbolTable()->get(locker, uid); + watchpointSet = entry.watchpointSet(); + offset = entry.scopeOffset(); + } + if (watchpointSet && watchpointSet->state() == IsWatched) { + // This has a fun concurrency story. There is the possibility of a race in two + // directions: + // + // We see that the set IsWatched, but in the meantime it gets invalidated: this is + // fine because if we saw that it IsWatched then we add a watchpoint. If it gets + // invalidated, then this compilation is invalidated. Note that in the meantime we + // may load an absurd value from the global object. It's fine to load an absurd + // value if the compilation is invalidated anyway. + // + // We see that the set IsWatched, but the value isn't yet initialized: this isn't + // possible because of the ordering of operations. + // + // Here's how we order operations: + // + // Main thread stores to the global object: always store a value first, and only + // after that do we touch the watchpoint set. There is a fence in the touch, that + // ensures that the store to the global object always happens before the touch on the + // set. + // + // Compilation thread: always first load the state of the watchpoint set, and then + // load the value. The WatchpointSet::state() method does fences for us to ensure + // that the load of the state happens before our load of the value. + // + // Finalizing compilation: this happens on the main thread and synchronously checks + // validity of all watchpoint sets. + // + // We will only perform optimizations if the load of the state yields IsWatched. That + // means that at least one store would have happened to initialize the original value + // of the variable (that is, the value we'd like to constant fold to). There may be + // other stores that happen after that, but those stores will invalidate the + // watchpoint set and also the compilation. + + // Note that we need to use the operand, which is a direct pointer at the global, + // rather than looking up the global by doing variableAt(offset). That's because the + // internal data structures of JSSegmentedVariableObject are not thread-safe even + // though accessing the global itself is. The segmentation involves a vector spine + // that resizes with malloc/free, so if new globals unrelated to the one we are + // reading are added, we might access freed memory if we do variableAt(). + WriteBarrier<Unknown>* pointer = bitwise_cast<WriteBarrier<Unknown>*>(operand); + + ASSERT(globalObject->findVariableIndex(pointer) == offset); + + JSValue value = pointer->get(); + if (value) { + m_graph.watchpoints().addLazily(watchpointSet); + set(VirtualRegister(dst), weakJSConstant(value)); + break; + } } - addToGraph(VariableWatchpoint, OpInfo(watchpointSet)); - set(VirtualRegister(dst), inferredConstant(specificValue)); + SpeculatedType prediction = getPrediction(); + set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction))); break; } + case LocalClosureVar: case ClosureVar: case ClosureVarWithVarInjectionChecks: { Node* scopeNode = get(VirtualRegister(scope)); - if (JSActivation* activation = m_graph.tryGetActivation(scopeNode)) { - SymbolTable* symbolTable = activation->symbolTable(); - ConcurrentJITLocker locker(symbolTable->m_lock); - SymbolTable::Map::iterator iter = symbolTable->find(locker, uid); - ASSERT(iter != symbolTable->end(locker)); - VariableWatchpointSet* watchpointSet = iter->value.watchpointSet(); - if (watchpointSet) { - if (JSValue value = watchpointSet->inferredValue()) { - addToGraph(Phantom, scopeNode); - addToGraph(VariableWatchpoint, OpInfo(watchpointSet)); - set(VirtualRegister(dst), inferredConstant(value)); - break; - } - } + + // Ideally we wouldn't have to do this Phantom. But: + // + // For the constant case: we must do it because otherwise we would have no way of knowing + // that the scope is live at OSR here. + // + // For the non-constant case: GetClosureVar could be DCE'd, but baseline's implementation + // won't be able to handle an Undefined scope. + addToGraph(Phantom, scopeNode); + + // Constant folding in the bytecode parser is important for performance. This may not + // have executed yet. If it hasn't, then we won't have a prediction. Lacking a + // prediction, we'd otherwise think that it has to exit. Then when it did execute, we + // would recompile. But if we can fold it here, we avoid the exit. + if (JSValue value = m_graph.tryGetConstantClosureVar(scopeNode, ScopeOffset(operand))) { + set(VirtualRegister(dst), weakJSConstant(value)); + break; } + SpeculatedType prediction = getPrediction(); set(VirtualRegister(dst), - addToGraph(GetClosureVar, OpInfo(operand), OpInfo(prediction), - addToGraph(GetClosureRegisters, scopeNode))); + addToGraph(GetClosureVar, OpInfo(operand), OpInfo(prediction), scopeNode)); break; } case Dynamic: @@ -3141,17 +3623,23 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_put_to_scope: { unsigned scope = currentInstruction[1].u.operand; - unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; + unsigned identifierNumber = currentInstruction[2].u.operand; + if (identifierNumber != UINT_MAX) + identifierNumber = m_inlineStackTop->m_identifierRemap[identifierNumber]; unsigned value = currentInstruction[3].u.operand; ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type(); - StringImpl* uid = m_graph.identifiers()[identifierNumber]; - - Structure* structure = 0; - VariableWatchpointSet* watchpoints = 0; + UniquedStringImpl* uid; + if (identifierNumber != UINT_MAX) + uid = m_graph.identifiers()[identifierNumber]; + else + uid = nullptr; + + Structure* structure = nullptr; + WatchpointSet* watchpoints = nullptr; uintptr_t operand; { ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); - if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks) + if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks || resolveType == LocalClosureVar) watchpoints = currentInstruction[5].u.watchpointSet; else structure = currentInstruction[5].u.structure.get(); @@ -3163,12 +3651,19 @@ bool ByteCodeParser::parseBlock(unsigned limit) switch (resolveType) { case GlobalProperty: case GlobalPropertyWithVarInjectionChecks: { - PutByIdStatus status = PutByIdStatus::computeFor(*m_vm, globalObject, structure, uid, false); - if (status.numVariants() != 1 || status[0].kind() != PutByIdVariant::Replace) { + PutByIdStatus status; + if (uid) + status = PutByIdStatus::computeFor(globalObject, structure, uid, false); + else + status = PutByIdStatus(PutByIdStatus::TakesSlowPath); + if (status.numVariants() != 1 + || status[0].kind() != PutByIdVariant::Replace + || status[0].structure().size() != 1) { addToGraph(PutById, OpInfo(identifierNumber), get(VirtualRegister(scope)), get(VirtualRegister(value))); break; } - Node* base = cellConstantWithStructureCheck(globalObject, status[0].structure()); + ASSERT(status[0].structure().onlyStructure() == structure); + Node* base = cellConstantWithStructureCheck(globalObject, structure); addToGraph(Phantom, get(VirtualRegister(scope))); handlePutByOffset(base, identifierNumber, static_cast<PropertyOffset>(operand), get(VirtualRegister(value))); // Keep scope alive until after put. @@ -3177,21 +3672,32 @@ bool ByteCodeParser::parseBlock(unsigned limit) } case GlobalVar: case GlobalVarWithVarInjectionChecks: { - SymbolTableEntry entry = globalObject->symbolTable()->get(uid); - ASSERT(watchpoints == entry.watchpointSet()); + if (watchpoints) { + SymbolTableEntry entry = globalObject->symbolTable()->get(uid); + ASSERT_UNUSED(entry, watchpoints == entry.watchpointSet()); + } Node* valueNode = get(VirtualRegister(value)); - addToGraph(PutGlobalVar, OpInfo(operand), valueNode); - if (watchpoints->state() != IsInvalidated) - addToGraph(NotifyWrite, OpInfo(watchpoints), valueNode); + addToGraph(PutGlobalVar, OpInfo(operand), weakJSConstant(globalObject), valueNode); + if (watchpoints && watchpoints->state() != IsInvalidated) { + // Must happen after the store. See comment for GetGlobalVar. + addToGraph(NotifyWrite, OpInfo(watchpoints)); + } // Keep scope alive until after put. addToGraph(Phantom, get(VirtualRegister(scope))); break; } + case LocalClosureVar: case ClosureVar: case ClosureVarWithVarInjectionChecks: { Node* scopeNode = get(VirtualRegister(scope)); - Node* scopeRegisters = addToGraph(GetClosureRegisters, scopeNode); - addToGraph(PutClosureVar, OpInfo(operand), scopeNode, scopeRegisters, get(VirtualRegister(value))); + Node* valueNode = get(VirtualRegister(value)); + + addToGraph(PutClosureVar, OpInfo(operand), scopeNode, valueNode); + + if (watchpoints && watchpoints->state() != IsInvalidated) { + // Must happen after the store. See comment for GetGlobalVar. + addToGraph(NotifyWrite, OpInfo(watchpoints)); + } break; } case Dynamic: @@ -3221,78 +3727,82 @@ bool ByteCodeParser::parseBlock(unsigned limit) NEXT_OPCODE(op_loop_hint); } - case op_init_lazy_reg: { - set(VirtualRegister(currentInstruction[1].u.operand), getJSConstantForValue(JSValue())); - ASSERT(operandIsLocal(currentInstruction[1].u.operand)); - m_graph.m_lazyVars.set(VirtualRegister(currentInstruction[1].u.operand).toLocal()); - NEXT_OPCODE(op_init_lazy_reg); + case op_create_lexical_environment: { + FrozenValue* symbolTable = m_graph.freezeStrong(m_graph.symbolTableFor(currentNodeOrigin().semantic)); + Node* lexicalEnvironment = addToGraph(CreateActivation, OpInfo(symbolTable), get(VirtualRegister(currentInstruction[2].u.operand))); + set(VirtualRegister(currentInstruction[1].u.operand), lexicalEnvironment); + set(VirtualRegister(currentInstruction[2].u.operand), lexicalEnvironment); + NEXT_OPCODE(op_create_lexical_environment); } - case op_create_activation: { - set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CreateActivation, get(VirtualRegister(currentInstruction[1].u.operand)))); - NEXT_OPCODE(op_create_activation); + case op_get_scope: { + // Help the later stages a bit by doing some small constant folding here. Note that this + // only helps for the first basic block. It's extremely important not to constant fold + // loads from the scope register later, as that would prevent the DFG from tracking the + // bytecode-level liveness of the scope register. + Node* callee = get(VirtualRegister(JSStack::Callee)); + Node* result; + if (JSFunction* function = callee->dynamicCastConstant<JSFunction*>()) + result = weakJSConstant(function->scope()); + else + result = addToGraph(GetScope, callee); + set(VirtualRegister(currentInstruction[1].u.operand), result); + NEXT_OPCODE(op_get_scope); } - case op_create_arguments: { - m_graph.m_hasArguments = true; - Node* createArguments = addToGraph(CreateArguments, get(VirtualRegister(currentInstruction[1].u.operand))); + case op_create_direct_arguments: { + noticeArgumentsUse(); + Node* createArguments = addToGraph(CreateDirectArguments); set(VirtualRegister(currentInstruction[1].u.operand), createArguments); - set(unmodifiedArgumentsRegister(VirtualRegister(currentInstruction[1].u.operand)), createArguments); - NEXT_OPCODE(op_create_arguments); + NEXT_OPCODE(op_create_direct_arguments); } - case op_tear_off_activation: { - addToGraph(TearOffActivation, get(VirtualRegister(currentInstruction[1].u.operand))); - NEXT_OPCODE(op_tear_off_activation); + case op_create_scoped_arguments: { + noticeArgumentsUse(); + Node* createArguments = addToGraph(CreateScopedArguments, get(VirtualRegister(currentInstruction[2].u.operand))); + set(VirtualRegister(currentInstruction[1].u.operand), createArguments); + NEXT_OPCODE(op_create_scoped_arguments); } - case op_tear_off_arguments: { - m_graph.m_hasArguments = true; - addToGraph(TearOffArguments, get(unmodifiedArgumentsRegister(VirtualRegister(currentInstruction[1].u.operand))), get(VirtualRegister(currentInstruction[2].u.operand))); - NEXT_OPCODE(op_tear_off_arguments); - } - - case op_get_arguments_length: { - m_graph.m_hasArguments = true; - set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetMyArgumentsLengthSafe)); - NEXT_OPCODE(op_get_arguments_length); + case op_create_out_of_band_arguments: { + noticeArgumentsUse(); + Node* createArguments = addToGraph(CreateClonedArguments); + set(VirtualRegister(currentInstruction[1].u.operand), createArguments); + NEXT_OPCODE(op_create_out_of_band_arguments); } - case op_get_argument_by_val: { - m_graph.m_hasArguments = true; + case op_get_from_arguments: { set(VirtualRegister(currentInstruction[1].u.operand), addToGraph( - GetMyArgumentByValSafe, OpInfo(0), OpInfo(getPrediction()), - get(VirtualRegister(currentInstruction[3].u.operand)))); - NEXT_OPCODE(op_get_argument_by_val); + GetFromArguments, + OpInfo(currentInstruction[3].u.operand), + OpInfo(getPrediction()), + get(VirtualRegister(currentInstruction[2].u.operand)))); + NEXT_OPCODE(op_get_from_arguments); } - case op_new_func: { - if (!currentInstruction[3].u.operand) { - set(VirtualRegister(currentInstruction[1].u.operand), - addToGraph(NewFunctionNoCheck, OpInfo(currentInstruction[2].u.operand))); - } else { - set(VirtualRegister(currentInstruction[1].u.operand), - addToGraph( - NewFunction, - OpInfo(currentInstruction[2].u.operand), - get(VirtualRegister(currentInstruction[1].u.operand)))); - } - NEXT_OPCODE(op_new_func); + case op_put_to_arguments: { + addToGraph( + PutToArguments, + OpInfo(currentInstruction[2].u.operand), + get(VirtualRegister(currentInstruction[1].u.operand)), + get(VirtualRegister(currentInstruction[3].u.operand))); + NEXT_OPCODE(op_put_to_arguments); } - case op_new_captured_func: { - Node* function = addToGraph( - NewFunctionNoCheck, OpInfo(currentInstruction[2].u.operand)); - if (VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet) - addToGraph(NotifyWrite, OpInfo(set), function); - set(VirtualRegister(currentInstruction[1].u.operand), function); - NEXT_OPCODE(op_new_captured_func); + case op_new_func: { + FunctionExecutable* decl = m_inlineStackTop->m_profiledBlock->functionDecl(currentInstruction[3].u.operand); + FrozenValue* frozen = m_graph.freezeStrong(decl); + set(VirtualRegister(currentInstruction[1].u.operand), + addToGraph(NewFunction, OpInfo(frozen), get(VirtualRegister(currentInstruction[2].u.operand)))); + NEXT_OPCODE(op_new_func); } - + case op_new_func_exp: { + FunctionExecutable* expr = m_inlineStackTop->m_profiledBlock->functionExpr(currentInstruction[3].u.operand); + FrozenValue* frozen = m_graph.freezeStrong(expr); set(VirtualRegister(currentInstruction[1].u.operand), - addToGraph(NewFunctionExpression, OpInfo(currentInstruction[2].u.operand))); + addToGraph(NewFunction, OpInfo(frozen), get(VirtualRegister(currentInstruction[2].u.operand)))); NEXT_OPCODE(op_new_func_exp); } @@ -3308,13 +3818,93 @@ bool ByteCodeParser::parseBlock(unsigned limit) set(VirtualRegister(currentInstruction[1].u.operand), node); NEXT_OPCODE(op_to_number); } - + + case op_to_string: { + Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToString, value)); + NEXT_OPCODE(op_to_string); + } + case op_in: { set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(In, get(VirtualRegister(currentInstruction[2].u.operand)), get(VirtualRegister(currentInstruction[3].u.operand)))); NEXT_OPCODE(op_in); } + case op_get_enumerable_length: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumerableLength, + get(VirtualRegister(currentInstruction[2].u.operand)))); + NEXT_OPCODE(op_get_enumerable_length); + } + + case op_has_generic_property: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(HasGenericProperty, + get(VirtualRegister(currentInstruction[2].u.operand)), + get(VirtualRegister(currentInstruction[3].u.operand)))); + NEXT_OPCODE(op_has_generic_property); + } + + case op_has_structure_property: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(HasStructureProperty, + get(VirtualRegister(currentInstruction[2].u.operand)), + get(VirtualRegister(currentInstruction[3].u.operand)), + get(VirtualRegister(currentInstruction[4].u.operand)))); + NEXT_OPCODE(op_has_structure_property); + } + + case op_has_indexed_property: { + Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); + ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read); + Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); + Node* hasIterableProperty = addToGraph(HasIndexedProperty, OpInfo(arrayMode.asWord()), base, property); + set(VirtualRegister(currentInstruction[1].u.operand), hasIterableProperty); + NEXT_OPCODE(op_has_indexed_property); + } + + case op_get_direct_pname: { + SpeculatedType prediction = getPredictionWithoutOSRExit(); + + Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); + Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); + Node* index = get(VirtualRegister(currentInstruction[4].u.operand)); + Node* enumerator = get(VirtualRegister(currentInstruction[5].u.operand)); + + addVarArgChild(base); + addVarArgChild(property); + addVarArgChild(index); + addVarArgChild(enumerator); + set(VirtualRegister(currentInstruction[1].u.operand), + addToGraph(Node::VarArg, GetDirectPname, OpInfo(0), OpInfo(prediction))); + + NEXT_OPCODE(op_get_direct_pname); + } + + case op_get_property_enumerator: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetPropertyEnumerator, + get(VirtualRegister(currentInstruction[2].u.operand)))); + NEXT_OPCODE(op_get_property_enumerator); + } + + case op_enumerator_structure_pname: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumeratorStructurePname, + get(VirtualRegister(currentInstruction[2].u.operand)), + get(VirtualRegister(currentInstruction[3].u.operand)))); + NEXT_OPCODE(op_enumerator_structure_pname); + } + + case op_enumerator_generic_pname: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumeratorGenericPname, + get(VirtualRegister(currentInstruction[2].u.operand)), + get(VirtualRegister(currentInstruction[3].u.operand)))); + NEXT_OPCODE(op_enumerator_generic_pname); + } + + case op_to_index_string: { + set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToIndexString, + get(VirtualRegister(currentInstruction[2].u.operand)))); + NEXT_OPCODE(op_to_index_string); + } + default: // Parse failed! This should not happen because the capabilities checker // should have caught it. @@ -3328,7 +3918,7 @@ void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BasicBlock*>& possibleT { ASSERT(!block->isLinked); ASSERT(!block->isEmpty()); - Node* node = block->last(); + Node* node = block->terminal(); ASSERT(node->isTerminal()); switch (node->op()) { @@ -3355,15 +3945,19 @@ void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BasicBlock*>& possibleT break; } -#if !ASSERT_DISABLED - block->isLinked = true; -#endif + if (verbose) + dataLog("Marking ", RawPointer(block), " as linked (actually did linking)\n"); + block->didLink(); } void ByteCodeParser::linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets) { for (size_t i = 0; i < unlinkedBlocks.size(); ++i) { + if (verbose) + dataLog("Attempting to link ", RawPointer(unlinkedBlocks[i].m_block), "\n"); if (unlinkedBlocks[i].m_needsNormalLinking) { + if (verbose) + dataLog(" Does need normal linking.\n"); linkBlock(unlinkedBlocks[i].m_block, possibleTargets); unlinkedBlocks[i].m_needsNormalLinking = false; } @@ -3377,13 +3971,6 @@ void ByteCodeParser::buildOperandMapsIfNecessary() for (size_t i = 0; i < m_codeBlock->numberOfIdentifiers(); ++i) m_identifierMap.add(m_codeBlock->identifier(i).impl(), i); - for (size_t i = 0; i < m_codeBlock->numberOfConstantRegisters(); ++i) { - JSValue value = m_codeBlock->getConstant(i + FirstConstantRegisterIndex); - if (!value) - m_emptyJSValueIndex = i + FirstConstantRegisterIndex; - else - m_jsValueMap.add(JSValue::encode(value), i + FirstConstantRegisterIndex); - } m_haveBuiltOperandMaps = true; } @@ -3397,7 +3984,7 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( VirtualRegister returnValueVR, VirtualRegister inlineCallFrameStart, int argumentCountIncludingThis, - CodeSpecializationKind kind) + InlineCallFrame::Kind kind) : m_byteCodeParser(byteCodeParser) , m_codeBlock(codeBlock) , m_profiledBlock(profiledBlock) @@ -3428,12 +4015,6 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( m_argumentPositions[i] = argumentPosition; } - // Track the code-block-global exit sites. - if (m_exitProfile.hasExitSite(ArgumentsEscaped)) { - byteCodeParser->m_graph.m_executablesWhoseArgumentsEscaped.add( - codeBlock->ownerExecutable()); - } - if (m_caller) { // Inline case. ASSERT(codeBlock != byteCodeParser->m_codeBlock); @@ -3441,6 +4022,7 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( ASSERT(callsiteBlockHead); m_inlineCallFrame = byteCodeParser->m_graph.m_plan.inlineCallFrames->add(); + byteCodeParser->m_graph.freeze(codeBlock->ownerExecutable()); initializeLazyWriteBarrierForInlineCallFrameExecutable( byteCodeParser->m_graph.m_plan.writeBarriers, m_inlineCallFrame->executable, @@ -3448,68 +4030,29 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( m_inlineCallFrame, byteCodeParser->m_codeBlock->ownerExecutable(), codeBlock->ownerExecutable()); - m_inlineCallFrame->stackOffset = inlineCallFrameStart.offset() - JSStack::CallFrameHeaderSize; + m_inlineCallFrame->setStackOffset(inlineCallFrameStart.offset() - JSStack::CallFrameHeaderSize); if (callee) { m_inlineCallFrame->calleeRecovery = ValueRecovery::constant(callee); m_inlineCallFrame->isClosureCall = false; } else m_inlineCallFrame->isClosureCall = true; m_inlineCallFrame->caller = byteCodeParser->currentCodeOrigin(); - m_inlineCallFrame->arguments.resize(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet. - m_inlineCallFrame->isCall = isCall(kind); + m_inlineCallFrame->arguments.resizeToFit(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet. + m_inlineCallFrame->kind = kind; - if (m_inlineCallFrame->caller.inlineCallFrame) - m_inlineCallFrame->capturedVars = m_inlineCallFrame->caller.inlineCallFrame->capturedVars; - else { - for (int i = byteCodeParser->m_codeBlock->m_numVars; i--;) { - if (byteCodeParser->m_codeBlock->isCaptured(virtualRegisterForLocal(i))) - m_inlineCallFrame->capturedVars.set(i); - } - } - - for (int i = argumentCountIncludingThis; i--;) { - VirtualRegister argument = virtualRegisterForArgument(i); - if (codeBlock->isCaptured(argument)) - m_inlineCallFrame->capturedVars.set(VirtualRegister(argument.offset() + m_inlineCallFrame->stackOffset).toLocal()); - } - for (size_t i = codeBlock->m_numVars; i--;) { - VirtualRegister local = virtualRegisterForLocal(i); - if (codeBlock->isCaptured(local)) - m_inlineCallFrame->capturedVars.set(VirtualRegister(local.offset() + m_inlineCallFrame->stackOffset).toLocal()); - } - byteCodeParser->buildOperandMapsIfNecessary(); m_identifierRemap.resize(codeBlock->numberOfIdentifiers()); - m_constantRemap.resize(codeBlock->numberOfConstantRegisters()); m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers()); m_switchRemap.resize(codeBlock->numberOfSwitchJumpTables()); for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) { - StringImpl* rep = codeBlock->identifier(i).impl(); + UniquedStringImpl* rep = codeBlock->identifier(i).impl(); BorrowedIdentifierMap::AddResult result = byteCodeParser->m_identifierMap.add(rep, byteCodeParser->m_graph.identifiers().numberOfIdentifiers()); if (result.isNewEntry) byteCodeParser->m_graph.identifiers().addLazily(rep); m_identifierRemap[i] = result.iterator->value; } - for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i) { - JSValue value = codeBlock->getConstant(i + FirstConstantRegisterIndex); - if (!value) { - if (byteCodeParser->m_emptyJSValueIndex == UINT_MAX) { - byteCodeParser->m_emptyJSValueIndex = byteCodeParser->m_codeBlock->numberOfConstantRegisters() + FirstConstantRegisterIndex; - byteCodeParser->addConstant(JSValue()); - byteCodeParser->m_constants.append(ConstantRecord()); - } - m_constantRemap[i] = byteCodeParser->m_emptyJSValueIndex; - continue; - } - JSValueMap::AddResult result = byteCodeParser->m_jsValueMap.add(JSValue::encode(value), byteCodeParser->m_codeBlock->numberOfConstantRegisters() + FirstConstantRegisterIndex); - if (result.isNewEntry) { - byteCodeParser->addConstant(value); - byteCodeParser->m_constants.append(ConstantRecord()); - } - m_constantRemap[i] = result.iterator->value; - } for (unsigned i = 0; i < codeBlock->numberOfConstantBuffers(); ++i) { // If we inline the same code block multiple times, we don't want to needlessly // duplicate its constant buffers. @@ -3540,13 +4083,10 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( m_inlineCallFrame = 0; m_identifierRemap.resize(codeBlock->numberOfIdentifiers()); - m_constantRemap.resize(codeBlock->numberOfConstantRegisters()); m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers()); m_switchRemap.resize(codeBlock->numberOfSwitchJumpTables()); for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) m_identifierRemap[i] = i; - for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i) - m_constantRemap[i] = i + FirstConstantRegisterIndex; for (size_t i = 0; i < codeBlock->numberOfConstantBuffers(); ++i) m_constantBufferRemap[i] = i; for (size_t i = 0; i < codeBlock->numberOfSwitchJumpTables(); ++i) @@ -3554,14 +4094,13 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry( m_callsiteBlockHeadNeedsLinking = false; } - for (size_t i = 0; i < m_constantRemap.size(); ++i) - ASSERT(m_constantRemap[i] >= static_cast<unsigned>(FirstConstantRegisterIndex)); - byteCodeParser->m_inlineStackTop = this; } void ByteCodeParser::parseCodeBlock() { + clearCaches(); + CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; if (m_graph.compilation()) { @@ -3569,8 +4108,16 @@ void ByteCodeParser::parseCodeBlock() *m_vm->m_perBytecodeProfiler, m_inlineStackTop->m_profiledBlock); } - bool shouldDumpBytecode = Options::dumpBytecodeAtDFGTime(); - if (shouldDumpBytecode) { + if (UNLIKELY(Options::dumpSourceAtDFGTime())) { + Vector<DeferredSourceDump>& deferredSourceDump = m_graph.m_plan.callback->ensureDeferredSourceDump(); + if (inlineCallFrame()) { + DeferredSourceDump dump(codeBlock->baselineVersion(), m_codeBlock, JITCode::DFGJIT, inlineCallFrame()->caller); + deferredSourceDump.append(dump); + } else + deferredSourceDump.append(DeferredSourceDump(codeBlock->baselineVersion())); + } + + if (Options::dumpBytecodeAtDFGTime()) { dataLog("Parsing ", *codeBlock); if (inlineCallFrame()) { dataLog( @@ -3578,8 +4125,7 @@ void ByteCodeParser::parseCodeBlock() " ", inlineCallFrame()->caller); } dataLog( - ": captureCount = ", codeBlock->symbolTable() ? codeBlock->symbolTable()->captureCount() : 0, - ", needsActivation = ", codeBlock->needsActivation(), + ": needsActivation = ", codeBlock->needsActivation(), ", isStrictMode = ", codeBlock->ownerExecutable()->isStrictMode(), "\n"); codeBlock->baselineVersion()->dumpBytecode(); } @@ -3626,7 +4172,12 @@ void ByteCodeParser::parseCodeBlock() // 2) If the bytecodeBegin is equal to the currentIndex, then we failed to do // a peephole coalescing of this block in the if statement above. So, we're // generating suboptimal code and leaving more work for the CFG simplifier. - ASSERT(m_inlineStackTop->m_unlinkedBlocks.isEmpty() || m_inlineStackTop->m_unlinkedBlocks.last().m_block->bytecodeBegin < m_currentIndex); + if (!m_inlineStackTop->m_unlinkedBlocks.isEmpty()) { + unsigned lastBegin = + m_inlineStackTop->m_unlinkedBlocks.last().m_block->bytecodeBegin; + ASSERT_UNUSED( + lastBegin, lastBegin == UINT_MAX || lastBegin < m_currentIndex); + } m_inlineStackTop->m_unlinkedBlocks.append(UnlinkedBlock(block.get())); m_inlineStackTop->m_blockLinkingTargets.append(block.get()); // The first block is definitely an OSR target. @@ -3647,10 +4198,13 @@ void ByteCodeParser::parseCodeBlock() // are at the end of an inline function, or we realized that we // should stop parsing because there was a return in the first // basic block. - ASSERT(m_currentBlock->isEmpty() || m_currentBlock->last()->isTerminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing); + ASSERT(m_currentBlock->isEmpty() || m_currentBlock->terminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing); - if (!shouldContinueParsing) + if (!shouldContinueParsing) { + if (Options::verboseDFGByteCodeParsing()) + dataLog("Done parsing ", *codeBlock, "\n"); return; + } m_currentBlock = 0; } while (m_currentIndex < limit); @@ -3658,6 +4212,9 @@ void ByteCodeParser::parseCodeBlock() // Should have reached the end of the instructions. ASSERT(m_currentIndex == codeBlock->instructions().size()); + + if (Options::verboseDFGByteCodeParsing()) + dataLog("Done parsing ", *codeBlock, " (fell off end)\n"); } bool ByteCodeParser::parse() @@ -3677,25 +4234,9 @@ bool ByteCodeParser::parse() m_dfgCodeBlock->getStubInfoMap(m_dfgStubInfos); } - if (m_codeBlock->captureCount()) { - SymbolTable* symbolTable = m_codeBlock->symbolTable(); - ConcurrentJITLocker locker(symbolTable->m_lock); - SymbolTable::Map::iterator iter = symbolTable->begin(locker); - SymbolTable::Map::iterator end = symbolTable->end(locker); - for (; iter != end; ++iter) { - VariableWatchpointSet* set = iter->value.watchpointSet(); - if (!set) - continue; - size_t index = static_cast<size_t>(VirtualRegister(iter->value.getIndex()).toLocal()); - while (m_localWatchpoints.size() <= index) - m_localWatchpoints.append(nullptr); - m_localWatchpoints[index] = set; - } - } - InlineStackEntry inlineStackEntry( this, m_codeBlock, m_profiledBlock, 0, 0, VirtualRegister(), VirtualRegister(), - m_codeBlock->numParameters(), CodeForCall); + m_codeBlock->numParameters(), InlineCallFrame::Call); parseCodeBlock(); diff --git a/dfg/DFGByteCodeParser.h b/dfg/DFGByteCodeParser.h index cb86269..bd6888d 100644 --- a/dfg/DFGByteCodeParser.h +++ b/dfg/DFGByteCodeParser.h @@ -28,17 +28,10 @@ #if ENABLE(DFG_JIT) -#include "DFGGraph.h" +namespace JSC { namespace DFG { -namespace JSC { +class Graph; -class CodeBlock; -class VM; - -namespace DFG { - -// Populate the Graph with a basic block of code from the CodeBlock, -// starting at the provided bytecode index. bool parse(Graph&); } } // namespace JSC::DFG diff --git a/dfg/DFGCFAPhase.cpp b/dfg/DFGCFAPhase.cpp index 5f69de1..6bf4759 100644 --- a/dfg/DFGCFAPhase.cpp +++ b/dfg/DFGCFAPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -79,6 +79,59 @@ public: performForwardCFA(); } while (m_changed); + if (m_graph.m_form != SSA) { + ASSERT(!m_changed); + + // Widen the abstract values at the block that serves as the must-handle OSR entry. + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + if (!block->isOSRTarget) + continue; + if (block->bytecodeBegin != m_graph.m_plan.osrEntryBytecodeIndex) + continue; + + bool changed = false; + for (size_t i = m_graph.m_plan.mustHandleValues.size(); i--;) { + int operand = m_graph.m_plan.mustHandleValues.operandForIndex(i); + JSValue value = m_graph.m_plan.mustHandleValues[i]; + Node* node = block->variablesAtHead.operand(operand); + if (!node) + continue; + + AbstractValue& target = block->valuesAtHead.operand(operand); + changed |= target.mergeOSREntryValue(m_graph, value); + target.fixTypeForRepresentation( + m_graph, resultFor(node->variableAccessData()->flushFormat())); + } + + if (changed || !block->cfaHasVisited) { + m_changed = true; + block->cfaShouldRevisit = true; + } + } + + // Propagate any of the changes we just introduced. + while (m_changed) { + m_changed = false; + performForwardCFA(); + } + + // Make sure we record the intersection of all proofs that we ever allowed the + // compiler to rely upon. + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + block->intersectionOfCFAHasVisited &= block->cfaHasVisited; + for (unsigned i = block->intersectionOfPastValuesAtHead.size(); i--;) + block->intersectionOfPastValuesAtHead[i].filter(block->valuesAtHead[i]); + } + } + return true; } @@ -92,8 +145,11 @@ private: if (m_verbose) dataLog(" Block ", *block, ":\n"); m_state.beginBasicBlock(block); - if (m_verbose) + if (m_verbose) { dataLog(" head vars: ", block->valuesAtHead, "\n"); + if (m_graph.m_form == SSA) + dataLog(" head regs: ", mapDump(block->ssa->valuesAtHead), "\n"); + } for (unsigned i = 0; i < block->size(); ++i) { if (m_verbose) { Node* node = block->at(i); @@ -102,10 +158,8 @@ private: if (!safeToExecute(m_state, m_graph, node)) dataLog("(UNSAFE) "); - m_interpreter.dump(WTF::dataFile()); + dataLog(m_state.variables(), " ", m_interpreter); - if (m_state.haveStructures()) - dataLog(" (Have Structures)"); dataLogF("\n"); } if (!m_interpreter.execute(i)) { @@ -121,8 +175,11 @@ private: } m_changed |= m_state.endBasicBlock(MergeToSuccessors); - if (m_verbose) + if (m_verbose) { dataLog(" tail vars: ", block->valuesAtTail, "\n"); + if (m_graph.m_form == SSA) + dataLog(" head regs: ", mapDump(block->ssa->valuesAtTail), "\n"); + } } void performForwardCFA() diff --git a/dfg/DFGCFGSimplificationPhase.cpp b/dfg/DFGCFGSimplificationPhase.cpp index 8d29fbc..34a1336 100644 --- a/dfg/DFGCFGSimplificationPhase.cpp +++ b/dfg/DFGCFGSimplificationPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -59,7 +59,7 @@ public: continue; ASSERT(block->isReachable); - switch (block->last()->op()) { + switch (block->terminal()->op()) { case Jump: { // Successor with one predecessor -> merge. if (block->successor(0)->predecessors.size() == 1) { @@ -99,17 +99,19 @@ public: if (extremeLogging) m_graph.dump(); m_graph.dethread(); - - ASSERT(block->last()->isTerminal()); - NodeOrigin boundaryNodeOrigin = block->last()->origin; - block->last()->convertToPhantom(); - ASSERT(block->last()->refCount() == 1); - + + Node* terminal = block->terminal(); + ASSERT(terminal->isTerminal()); + NodeOrigin boundaryNodeOrigin = terminal->origin; + jettisonBlock(block, jettisonedBlock, boundaryNodeOrigin); - - block->appendNode( + + block->replaceTerminal( m_graph, SpecNone, Jump, boundaryNodeOrigin, OpInfo(targetBlock)); + + ASSERT(block->terminal()); + } innerChanged = outerChanged = true; break; @@ -129,7 +131,7 @@ public: } case Switch: { - SwitchData* data = block->last()->switchData(); + SwitchData* data = block->terminal()->switchData(); // Prune out cases that end up jumping to default. for (unsigned i = 0; i < data->cases.size(); ++i) { @@ -149,8 +151,9 @@ public: } // Switch on constant -> jettison all other targets and merge. - if (block->last()->child1()->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(block->last()->child1().node()); + Node* terminal = block->terminal(); + if (terminal->child1()->hasConstant()) { + FrozenValue* value = terminal->child1()->constant(); TriState found = FalseTriState; BasicBlock* targetBlock = 0; for (unsigned i = data->cases.size(); found == FalseTriState && i--;) { @@ -166,10 +169,9 @@ public: ASSERT(targetBlock); Vector<BasicBlock*, 1> jettisonedBlocks; - for (unsigned i = block->numSuccessors(); i--;) { - BasicBlock* jettisonedBlock = block->successor(i); - if (jettisonedBlock != targetBlock) - jettisonedBlocks.append(jettisonedBlock); + for (BasicBlock* successor : terminal->successors()) { + if (successor != targetBlock) + jettisonedBlocks.append(successor); } if (targetBlock->predecessors.size() == 1) { @@ -183,11 +185,12 @@ public: m_graph.dump(); m_graph.dethread(); - NodeOrigin boundaryNodeOrigin = block->last()->origin; - block->last()->convertToPhantom(); + NodeOrigin boundaryNodeOrigin = terminal->origin; + for (unsigned i = jettisonedBlocks.size(); i--;) jettisonBlock(block, jettisonedBlocks[i], boundaryNodeOrigin); - block->appendNode( + + block->replaceTerminal( m_graph, SpecNone, Jump, boundaryNodeOrigin, OpInfo(targetBlock)); } innerChanged = outerChanged = true; @@ -253,13 +256,10 @@ private: m_graph.dethread(); mergeBlocks(block, targetBlock, noBlocks()); } else { - Node* branch = block->last(); - ASSERT(branch->isTerminal()); + Node* branch = block->terminal(); ASSERT(branch->op() == Branch || branch->op() == Switch); - branch->convertToPhantom(); - ASSERT(branch->refCount() == 1); - - block->appendNode( + + block->replaceTerminal( m_graph, SpecNone, Jump, branch->origin, OpInfo(targetBlock)); } } @@ -272,8 +272,13 @@ private: NodeType nodeType; if (livenessNode->flags() & NodeIsFlushed) nodeType = Flush; - else + else { + // This seems like it shouldn't be necessary because we could just rematerialize + // PhantomLocals or something similar using bytecode liveness. However, in ThreadedCPS, it's + // worth the sanity to maintain this eagerly. See + // https://bugs.webkit.org/show_bug.cgi?id=144086 nodeType = PhantomLocal; + } block->appendNode( m_graph, SpecNone, nodeType, nodeOrigin, OpInfo(livenessNode->variableAccessData())); @@ -317,11 +322,12 @@ private: // kept alive. // Remove the terminal of firstBlock since we don't need it anymore. Well, we don't - // really remove it; we actually turn it into a Phantom. - ASSERT(firstBlock->last()->isTerminal()); - NodeOrigin boundaryNodeOrigin = firstBlock->last()->origin; - firstBlock->last()->convertToPhantom(); - ASSERT(firstBlock->last()->refCount() == 1); + // really remove it; we actually turn it into a check. + Node* terminal = firstBlock->terminal(); + ASSERT(terminal->isTerminal()); + NodeOrigin boundaryNodeOrigin = terminal->origin; + terminal->remove(); + ASSERT(terminal->refCount() == 1); for (unsigned i = jettisonedBlocks.size(); i--;) { BasicBlock* jettisonedBlock = jettisonedBlocks[i]; @@ -342,7 +348,7 @@ private: for (size_t i = 0; i < secondBlock->size(); ++i) firstBlock->append(secondBlock->at(i)); - ASSERT(firstBlock->last()->isTerminal()); + ASSERT(firstBlock->terminal()->isTerminal()); // Fix the predecessors of my new successors. This is tricky, since we are going to reset // all predecessors anyway due to reachability analysis. But we need to fix the diff --git a/dfg/DFGCPSRethreadingPhase.cpp b/dfg/DFGCPSRethreadingPhase.cpp index 076ba25..09dbf32 100644 --- a/dfg/DFGCPSRethreadingPhase.cpp +++ b/dfg/DFGCPSRethreadingPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,6 +53,7 @@ public: freeUnnecessaryNodes(); m_graph.clearReplacements(); canonicalizeLocalsInBlocks(); + specialCaseArguments(); propagatePhis<LocalOperand>(); propagatePhis<ArgumentOperand>(); computeIsFlushed(); @@ -90,13 +91,15 @@ private: node->children.setChild1(Edge()); break; case Phantom: - if (!node->child1()) + if (!node->child1()) { + m_graph.m_allocator.free(node); continue; + } switch (node->child1()->op()) { case Phi: case SetArgument: case SetLocal: - node->convertToPhantomLocal(); + node->convertPhantomToPhantomLocal(); break; default: ASSERT(node->child1()->hasResult()); @@ -117,15 +120,15 @@ private: } template<OperandKind operandKind> - void clearVariablesAtHeadAndTail() + void clearVariables() { ASSERT( m_block->variablesAtHead.sizeFor<operandKind>() == m_block->variablesAtTail.sizeFor<operandKind>()); for (unsigned i = m_block->variablesAtHead.sizeFor<operandKind>(); i--;) { - m_block->variablesAtHead.atFor<operandKind>(i) = 0; - m_block->variablesAtTail.atFor<operandKind>(i) = 0; + m_block->variablesAtHead.atFor<operandKind>(i) = nullptr; + m_block->variablesAtTail.atFor<operandKind>(i) = nullptr; } } @@ -184,29 +187,14 @@ private: return; } - if (variable->isCaptured()) { - variable->setIsLoadedFrom(true); - if (otherNode->op() == GetLocal) - otherNode = otherNode->child1().node(); - else - ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument); - - ASSERT(otherNode->op() == Phi || otherNode->op() == SetLocal || otherNode->op() == SetArgument); - - // Keep this GetLocal but link it to the prior ones. - node->children.setChild1(Edge(otherNode)); - m_block->variablesAtTail.atFor<operandKind>(idx) = node; - return; - } - if (otherNode->op() == GetLocal) { // Replace all references to this GetLocal with otherNode. - node->misc.replacement = otherNode; + node->replaceWith(otherNode); return; } ASSERT(otherNode->op() == SetLocal); - node->misc.replacement = otherNode->child1().node(); + node->replaceWith(otherNode->child1().node()); return; } @@ -226,11 +214,6 @@ private: canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local().toLocal()); } - void canonicalizeSetLocal(Node* node) - { - m_block->variablesAtTail.setOperand(node->local(), node); - } - template<NodeType nodeType, OperandKind operandKind> void canonicalizeFlushOrPhantomLocalFor(Node* node, VariableAccessData* variable, size_t idx) { @@ -257,13 +240,9 @@ private: // for the purpose of OSR. PhantomLocal(SetLocal) means: at this point I // know that I would have read the value written by that SetLocal. This is // redundant and inefficient, since really it just means that we want to - // be keeping the operand to the SetLocal alive. The SetLocal may die, and - // we'll be fine because OSR tracks dead SetLocals. - - // So we turn this into a Phantom on the child of the SetLocal. + // keep the last MovHinted value of that local alive. - node->convertToPhantom(); - node->children.setChild1(otherNode->child1()); + node->remove(); return; } @@ -294,13 +273,9 @@ private: canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local().toLocal()); } - void canonicalizeSetArgument(Node* node) + void canonicalizeSet(Node* node) { - VirtualRegister local = node->local(); - ASSERT(local.isArgument()); - int argument = local.toArgument(); - m_block->variablesAtHead.setArgumentFirstTime(argument, node); - m_block->variablesAtTail.setArgumentFirstTime(argument, node); + m_block->variablesAtTail.setOperand(node->local(), node); } void canonicalizeLocalsInBlock() @@ -309,8 +284,8 @@ private: return; ASSERT(m_block->isReachable); - clearVariablesAtHeadAndTail<ArgumentOperand>(); - clearVariablesAtHeadAndTail<LocalOperand>(); + clearVariables<ArgumentOperand>(); + clearVariables<LocalOperand>(); // Assumes that all phi references have been removed. Assumes that things that // should be live have a non-zero ref count, but doesn't assume that the ref @@ -339,10 +314,8 @@ private: // there ever was a SetLocal and it was followed by Flushes, then the tail // variable will be a SetLocal and not those subsequent Flushes. // - // Child of GetLocal: the operation that the GetLocal keeps alive. For - // uncaptured locals, it may be a Phi from the current block. For arguments, - // it may be a SetArgument. For captured locals and arguments it may also be - // a SetLocal. + // Child of GetLocal: the operation that the GetLocal keeps alive. It may be + // a Phi from the current block. For arguments, it may be a SetArgument. // // Child of SetLocal: must be a value producing node. // @@ -365,7 +338,7 @@ private: break; case SetLocal: - canonicalizeSetLocal(node); + canonicalizeSet(node); break; case Flush: @@ -377,7 +350,7 @@ private: break; case SetArgument: - canonicalizeSetArgument(node); + canonicalizeSet(node); break; default: @@ -396,6 +369,16 @@ private: } } + void specialCaseArguments() + { + // Normally, a SetArgument denotes the start of a live range for a local's value on the stack. + // But those SetArguments used for the actual arguments to the machine CodeBlock get + // special-cased. We could have instead used two different node types - one for the arguments + // at the prologue case, and another for the other uses. But this seemed like IR overkill. + for (unsigned i = m_graph.m_arguments.size(); i--;) + m_graph.block(0)->variablesAtHead.setArgumentFirstTime(i, m_graph.m_arguments[i]); + } + template<OperandKind operandKind> void propagatePhis() { @@ -500,8 +483,21 @@ private: } while (!m_flushedLocalOpWorklist.isEmpty()) { Node* node = m_flushedLocalOpWorklist.takeLast(); - ASSERT(node->flags() & NodeIsFlushed); - DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge); + switch (node->op()) { + case SetLocal: + case SetArgument: + break; + + case Flush: + case Phi: + ASSERT(node->flags() & NodeIsFlushed); + DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge); + break; + + default: + DFG_CRASH(m_graph, node, "Invalid node in flush graph"); + break; + } } } diff --git a/dfg/DFGCSEPhase.cpp b/dfg/DFGCSEPhase.cpp index d4e1023..a3b8676 100644 --- a/dfg/DFGCSEPhase.cpp +++ b/dfg/DFGCSEPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,8 @@ #if ENABLE(DFG_JIT) #include "DFGAbstractHeap.h" +#include "DFGBlockMapInlines.h" +#include "DFGClobberSet.h" #include "DFGClobberize.h" #include "DFGEdgeUsesStructure.h" #include "DFGGraph.h" @@ -39,21 +41,52 @@ namespace JSC { namespace DFG { -enum CSEMode { NormalCSE, StoreElimination }; +// This file contains two CSE implementations: local and global. LocalCSE typically runs when we're +// in DFG mode, i.e. we want to compile quickly. LocalCSE contains a lot of optimizations for +// compile time. GlobalCSE, on the other hand, is fairly straight-forward. It will find more +// optimization opportunities by virtue of being global. -template<CSEMode cseMode> -class CSEPhase : public Phase { +namespace { + +const bool verbose = false; + +class ClobberFilter { public: - CSEPhase(Graph& graph) - : Phase(graph, cseMode == NormalCSE ? "common subexpression elimination" : "store elimination") + ClobberFilter(AbstractHeap heap) + : m_heap(heap) + { + } + + bool operator()(const ImpureMap::KeyValuePairType& pair) const + { + return m_heap.overlaps(pair.key.heap()); + } + +private: + AbstractHeap m_heap; +}; + +inline void clobber(ImpureMap& map, AbstractHeap heap) +{ + ClobberFilter filter(heap); + map.removeIf(filter); +} + +class LocalCSEPhase : public Phase { +public: + LocalCSEPhase(Graph& graph) + : Phase(graph, "local common subexpression elimination") + , m_smallBlock(graph) + , m_largeBlock(graph) { } bool run() { - ASSERT(m_graph.m_fixpointState != BeforeFixpoint); + ASSERT(m_graph.m_fixpointState == FixpointNotConverged); + ASSERT(m_graph.m_form == ThreadedCPS || m_graph.m_form == LoadStore); - m_changed = false; + bool changed = false; m_graph.clearReplacements(); @@ -62,1477 +95,621 @@ public: if (!block) continue; - // All Phis need to already be marked as relevant to OSR. - if (!ASSERT_DISABLED) { - for (unsigned i = 0; i < block->phis.size(); ++i) - ASSERT(block->phis[i]->flags() & NodeRelevantToOSR); - } - - for (unsigned i = block->size(); i--;) { - Node* node = block->at(i); - - switch (node->op()) { - case SetLocal: - case GetLocal: // FIXME: The GetLocal case is only necessary until we do https://bugs.webkit.org/show_bug.cgi?id=106707. - node->mergeFlags(NodeRelevantToOSR); - break; - default: - node->clearFlags(NodeRelevantToOSR); - break; - } - } + if (block->size() <= SmallMaps::capacity) + changed |= m_smallBlock.run(block); + else + changed |= m_largeBlock.run(block); } - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - - for (unsigned i = block->size(); i--;) { - Node* node = block->at(i); - if (!node->containsMovHint()) - continue; - - ASSERT(node->op() != ZombieHint); - node->child1()->mergeFlags(NodeRelevantToOSR); - } - } - - if (m_graph.m_form == SSA) { - Vector<BasicBlock*> depthFirst; - m_graph.getBlocksInDepthFirstOrder(depthFirst); - for (unsigned i = 0; i < depthFirst.size(); ++i) - performBlockCSE(depthFirst[i]); - } else { - for (unsigned blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) - performBlockCSE(m_graph.block(blockIndex)); - } - - return m_changed; + return changed; } private: + class SmallMaps { + public: + // This permits SmallMaps to be used for blocks that have up to 100 nodes. In practice, + // fewer than half of the nodes in a block have pure defs, and even fewer have impure defs. + // Thus, a capacity limit of 100 probably means that somewhere around ~40 things may end up + // in one of these "small" list-based maps. That number still seems largeish, except that + // the overhead of HashMaps can be quite high currently: clearing them, or even removing + // enough things from them, deletes (or resizes) their backing store eagerly. Hence + // HashMaps induce a lot of malloc traffic. + static const unsigned capacity = 100; - unsigned endIndexForPureCSE() - { - unsigned result = m_lastSeen[m_currentNode->op()]; - if (result == UINT_MAX) - result = 0; - else - result++; - ASSERT(result <= m_indexInBlock); - return result; - } - - Node* pureCSE(Node* node) - { - Edge child1 = node->child1().sanitized(); - Edge child2 = node->child2().sanitized(); - Edge child3 = node->child3().sanitized(); - - for (unsigned i = endIndexForPureCSE(); i--;) { - Node* otherNode = m_currentBlock->at(i); - if (otherNode == child1 || otherNode == child2 || otherNode == child3) - break; - - if (node->op() != otherNode->op()) - continue; - - Edge otherChild = otherNode->child1().sanitized(); - if (!otherChild) - return otherNode; - if (otherChild != child1) - continue; - - otherChild = otherNode->child2().sanitized(); - if (!otherChild) - return otherNode; - if (otherChild != child2) - continue; - - otherChild = otherNode->child3().sanitized(); - if (!otherChild) - return otherNode; - if (otherChild != child3) - continue; - - return otherNode; - } - return 0; - } - - Node* constantCSE(Node* node) - { - for (unsigned i = endIndexForPureCSE(); i--;) { - Node* otherNode = m_currentBlock->at(i); - if (otherNode->op() != node->op()) - continue; - - if (otherNode->constantNumber() != node->constantNumber()) - continue; - - return otherNode; - } - return 0; - } - - Node* weakConstantCSE(Node* node) - { - for (unsigned i = endIndexForPureCSE(); i--;) { - Node* otherNode = m_currentBlock->at(i); - if (otherNode->op() != WeakJSConstant) - continue; - - if (otherNode->weakConstant() != node->weakConstant()) - continue; - - return otherNode; - } - return 0; - } - - Node* constantStoragePointerCSE(Node* node) - { - for (unsigned i = endIndexForPureCSE(); i--;) { - Node* otherNode = m_currentBlock->at(i); - if (otherNode->op() != ConstantStoragePointer) - continue; - - if (otherNode->storagePointer() != node->storagePointer()) - continue; - - return otherNode; + SmallMaps() + : m_pureLength(0) + , m_impureLength(0) + { } - return 0; - } - Node* getCalleeLoadElimination() - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetCallee: - return node; - default: - break; - } + void clear() + { + m_pureLength = 0; + m_impureLength = 0; } - return 0; - } - Node* getArrayLengthElimination(Node* array) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetArrayLength: - if (node->child1() == array) - return node; - break; - - case PutByValDirect: - case PutByVal: - if (!m_graph.byValIsPure(node)) - return 0; - if (node->arrayMode().mayStoreToHole()) - return 0; - break; - - default: - if (m_graph.clobbersWorld(node)) - return 0; + void write(AbstractHeap heap) + { + for (unsigned i = 0; i < m_impureLength; ++i) { + if (heap.overlaps(m_impureMap[i].key.heap())) + m_impureMap[i--] = m_impureMap[--m_impureLength]; } } - return 0; - } - Node* globalVarLoadElimination(WriteBarrier<Unknown>* registerPointer) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetGlobalVar: - if (node->registerPointer() == registerPointer) - return node; - break; - case PutGlobalVar: - if (node->registerPointer() == registerPointer) - return node->child1().node(); - break; - default: - break; + Node* addPure(PureValue value, Node* node) + { + for (unsigned i = m_pureLength; i--;) { + if (m_pureMap[i].key == value) + return m_pureMap[i].value; } - if (m_graph.clobbersWorld(node)) - break; + + ASSERT(m_pureLength < capacity); + m_pureMap[m_pureLength++] = WTF::KeyValuePair<PureValue, Node*>(value, node); + return nullptr; } - return 0; - } - - Node* scopedVarLoadElimination(Node* registers, int varNumber) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetClosureVar: { - if (node->child1() == registers && node->varNumber() == varNumber) - return node; - break; - } - case PutClosureVar: { - if (node->varNumber() != varNumber) - break; - if (node->child2() == registers) - return node->child3().node(); - return 0; - } - case SetLocal: { - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured() - && variableAccessData->local() == static_cast<VirtualRegister>(varNumber)) - return 0; - break; - } - default: - break; + + LazyNode findReplacement(HeapLocation location) + { + for (unsigned i = m_impureLength; i--;) { + if (m_impureMap[i].key == location) + return m_impureMap[i].value; } - if (m_graph.clobbersWorld(node)) - break; - } - return 0; - } - - bool varInjectionWatchpointElimination() - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node->op() == VarInjectionWatchpoint) - return true; - if (m_graph.clobbersWorld(node)) - break; + return nullptr; } - return false; - } - Node* globalVarStoreElimination(WriteBarrier<Unknown>* registerPointer) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case PutGlobalVar: - if (node->registerPointer() == registerPointer) - return node; - break; - - case GetGlobalVar: - if (node->registerPointer() == registerPointer) - return 0; - break; - - default: - break; - } - if (m_graph.clobbersWorld(node) || node->canExit()) - return 0; + LazyNode addImpure(HeapLocation location, LazyNode node) + { + // FIXME: If we are using small maps, we must not def() derived values. + // For now the only derived values we def() are constant-based. + if (location.index() && !location.index().isNode()) + return nullptr; + if (LazyNode result = findReplacement(location)) + return result; + ASSERT(m_impureLength < capacity); + m_impureMap[m_impureLength++] = WTF::KeyValuePair<HeapLocation, LazyNode>(location, node); + return nullptr; } - return 0; - } - Node* scopedVarStoreElimination(Node* scope, Node* registers, int varNumber) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case PutClosureVar: { - if (node->varNumber() != varNumber) - break; - if (node->child1() == scope && node->child2() == registers) - return node; - return 0; - } - - case GetClosureVar: { - // Let's be conservative. - if (node->varNumber() == varNumber) - return 0; - break; - } - - case GetLocal: - case SetLocal: { - VariableAccessData* variableAccessData = node->variableAccessData(); - if (variableAccessData->isCaptured() - && variableAccessData->local() == static_cast<VirtualRegister>(varNumber)) - return 0; - break; - } + private: + WTF::KeyValuePair<PureValue, Node*> m_pureMap[capacity]; + WTF::KeyValuePair<HeapLocation, LazyNode> m_impureMap[capacity]; + unsigned m_pureLength; + unsigned m_impureLength; + }; - default: - break; - } - if (m_graph.clobbersWorld(node) || node->canExit()) - return 0; + class LargeMaps { + public: + LargeMaps() + { } - return 0; - } - Node* getByValLoadElimination(Node* child1, Node* child2, ArrayMode arrayMode) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1 || node == child2) - break; - - switch (node->op()) { - case GetByVal: - if (!m_graph.byValIsPure(node)) - return 0; - if (node->child1() == child1 - && node->child2() == child2 - && node->arrayMode().type() == arrayMode.type()) - return node; - break; - - case PutByValDirect: - case PutByVal: - case PutByValAlias: { - if (!m_graph.byValIsPure(node)) - return 0; - // Typed arrays - if (arrayMode.typedArrayType() != NotTypedArray) - return 0; - if (m_graph.varArgChild(node, 0) == child1 - && m_graph.varArgChild(node, 1) == child2 - && node->arrayMode().type() == arrayMode.type()) - return m_graph.varArgChild(node, 2).node(); - // We must assume that the PutByVal will clobber the location we're getting from. - // FIXME: We can do better; if we know that the PutByVal is accessing an array of a - // different type than the GetByVal, then we know that they won't clobber each other. - // ... except of course for typed arrays, where all typed arrays clobber all other - // typed arrays! An Int32Array can alias a Float64Array for example, and so on. - return 0; - } - default: - if (m_graph.clobbersWorld(node)) - return 0; - break; - } + void clear() + { + m_pureMap.clear(); + m_impureMap.clear(); } - return 0; - } - - bool checkFunctionElimination(JSCell* function, Node* child1) - { - for (unsigned i = endIndexForPureCSE(); i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - if (node->op() == CheckFunction && node->child1() == child1 && node->function() == function) - return true; + + void write(AbstractHeap heap) + { + clobber(m_impureMap, heap); } - return false; - } - bool checkExecutableElimination(ExecutableBase* executable, Node* child1) - { - for (unsigned i = endIndexForPureCSE(); i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - if (node->op() == CheckExecutable && node->child1() == child1 && node->executable() == executable) - return true; + Node* addPure(PureValue value, Node* node) + { + auto result = m_pureMap.add(value, node); + if (result.isNewEntry) + return nullptr; + return result.iterator->value; } - return false; - } - - bool checkStructureElimination(const StructureSet& structureSet, Node* child1) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - switch (node->op()) { - case CheckStructure: - if (node->child1() == child1 - && structureSet.isSupersetOf(node->structureSet())) - return true; - break; - - case StructureTransitionWatchpoint: - if (node->child1() == child1 - && structureSet.contains(node->structure())) - return true; - break; - - case PutStructure: - if (node->child1() == child1 - && structureSet.contains(node->structureTransitionData().newStructure)) - return true; - if (structureSet.contains(node->structureTransitionData().previousStructure)) - return false; - break; - - case PutByOffset: - // Setting a property cannot change the structure. - break; - - case MultiPutByOffset: - if (node->multiPutByOffsetData().writesStructures()) - return false; - break; - - case PutByValDirect: - case PutByVal: - case PutByValAlias: - if (m_graph.byValIsPure(node)) { - // If PutByVal speculates that it's accessing an array with an - // integer index, then it's impossible for it to cause a structure - // change. - break; + + LazyNode findReplacement(HeapLocation location) + { + return m_impureMap.get(location); + } + + LazyNode addImpure(HeapLocation location, LazyNode node) + { + auto result = m_impureMap.add(location, node); + if (result.isNewEntry) + return nullptr; + return result.iterator->value; + } + + private: + HashMap<PureValue, Node*> m_pureMap; + HashMap<HeapLocation, LazyNode> m_impureMap; + }; + + template<typename Maps> + class BlockCSE { + public: + BlockCSE(Graph& graph) + : m_graph(graph) + , m_insertionSet(graph) + { + } + + bool run(BasicBlock* block) + { + m_maps.clear(); + m_changed = false; + m_block = block; + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + m_node = block->at(nodeIndex); + m_graph.performSubstitution(m_node); + + if (m_node->op() == Identity) { + m_node->replaceWith(m_node->child1().node()); + m_changed = true; + } else { + // This rule only makes sense for local CSE, since in SSA form we have already + // factored the bounds check out of the PutByVal. It's kind of gross, but we + // still have reason to believe that PutByValAlias is a good optimization and + // that it's better to do it with a single node rather than separating out the + // CheckInBounds. + if (m_node->op() == PutByVal || m_node->op() == PutByValDirect) { + HeapLocation heap; + + Node* base = m_graph.varArgChild(m_node, 0).node(); + Node* index = m_graph.varArgChild(m_node, 1).node(); + + ArrayMode mode = m_node->arrayMode(); + switch (mode.type()) { + case Array::Int32: + if (!mode.isInBounds()) + break; + heap = HeapLocation( + IndexedPropertyLoc, IndexedInt32Properties, base, index); + break; + + case Array::Double: + if (!mode.isInBounds()) + break; + heap = HeapLocation( + IndexedPropertyLoc, IndexedDoubleProperties, base, index); + break; + + case Array::Contiguous: + if (!mode.isInBounds()) + break; + heap = HeapLocation( + IndexedPropertyLoc, IndexedContiguousProperties, base, index); + break; + + case Array::Int8Array: + case Array::Int16Array: + case Array::Int32Array: + case Array::Uint8Array: + case Array::Uint8ClampedArray: + case Array::Uint16Array: + case Array::Uint32Array: + case Array::Float32Array: + case Array::Float64Array: + if (!mode.isInBounds()) + break; + heap = HeapLocation( + IndexedPropertyLoc, TypedArrayProperties, base, index); + break; + + default: + break; + } + + if (!!heap && m_maps.findReplacement(heap)) + m_node->setOp(PutByValAlias); + } + + clobberize(m_graph, m_node, *this); } - return false; - - case Arrayify: - case ArrayifyToStructure: - // We could check if the arrayification could affect our structures. - // But that seems like it would take Effort. - return false; - - default: - if (m_graph.clobbersWorld(node)) - return false; - break; } - } - return false; - } - - bool structureTransitionWatchpointElimination(Structure* structure, Node* child1) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - switch (node->op()) { - case CheckStructure: - if (node->child1() == child1 - && node->structureSet().containsOnly(structure)) - return true; - break; - - case PutStructure: - ASSERT(node->structureTransitionData().previousStructure != structure); - break; - - case PutByOffset: - // Setting a property cannot change the structure. - break; - - case MultiPutByOffset: - if (node->multiPutByOffsetData().writesStructures()) - return false; - break; - - case PutByValDirect: - case PutByVal: - case PutByValAlias: - if (m_graph.byValIsPure(node)) { - // If PutByVal speculates that it's accessing an array with an - // integer index, then it's impossible for it to cause a structure - // change. - break; - } - return false; - - case StructureTransitionWatchpoint: - if (node->structure() == structure && node->child1() == child1) - return true; - break; - - case Arrayify: - case ArrayifyToStructure: - // We could check if the arrayification could affect our structures. - // But that seems like it would take Effort. - return false; - - default: - if (m_graph.clobbersWorld(node)) - return false; - break; - } - } - return false; - } - - Node* putStructureStoreElimination(Node* child1) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - switch (node->op()) { - case CheckStructure: - return 0; - - case PhantomPutStructure: - if (node->child1() == child1) // No need to retrace our steps. - return 0; - break; - - case PutStructure: - if (node->child1() == child1) - return node; - break; - - // PutStructure needs to execute if we GC. Hence this needs to - // be careful with respect to nodes that GC. - case CreateArguments: - case TearOffArguments: - case NewFunctionNoCheck: - case NewFunction: - case NewFunctionExpression: - case CreateActivation: - case TearOffActivation: - case ToPrimitive: - case NewRegexp: - case NewArrayBuffer: - case NewArray: - case NewObject: - case CreateThis: - case AllocatePropertyStorage: - case ReallocatePropertyStorage: - case TypeOf: - case ToString: - case NewStringObject: - case MakeRope: - case NewTypedArray: - case MultiPutByOffset: - return 0; - - // This either exits, causes a GC (lazy string allocation), or clobbers - // the world. The chances of it not doing any of those things are so - // slim that we might as well not even try to reason about it. - case GetByVal: - return 0; - - case GetIndexedPropertyStorage: - if (node->arrayMode().getIndexedPropertyStorageMayTriggerGC()) - return 0; - break; - - default: - break; - } - if (m_graph.clobbersWorld(node) || node->canExit()) - return 0; - if (edgesUseStructure(m_graph, node)) - return 0; + m_insertionSet.execute(block); + + return m_changed; } - return 0; - } - Node* getByOffsetLoadElimination(unsigned identifierNumber, Node* base) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == base) - break; - - switch (node->op()) { - case GetByOffset: - if (node->child2() == base - && m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) - return node; - break; - - case MultiGetByOffset: - if (node->child1() == base - && node->multiGetByOffsetData().identifierNumber == identifierNumber) - return node; - break; - - case PutByOffset: - if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) { - if (node->child2() == base) // Must be same property storage. - return node->child3().node(); - return 0; - } - break; - - case MultiPutByOffset: - if (node->multiPutByOffsetData().identifierNumber == identifierNumber) { - if (node->child1() == base) - return node->child2().node(); - return 0; - } - break; - - case PutByValDirect: - case PutByVal: - case PutByValAlias: - if (m_graph.byValIsPure(node)) { - // If PutByVal speculates that it's accessing an array with an - // integer index, then it's impossible for it to cause a structure - // change. - break; - } - return 0; - - default: - if (m_graph.clobbersWorld(node)) - return 0; - break; - } - } - return 0; - } + void read(AbstractHeap) { } - Node* putByOffsetStoreElimination(unsigned identifierNumber, Node* child1) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - switch (node->op()) { - case GetByOffset: - if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) - return 0; - break; - - case PutByOffset: - if (m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) { - if (node->child1() == child1) // Must be same property storage. - return node; - return 0; - } - break; - - case MultiPutByOffset: - if (node->multiPutByOffsetData().identifierNumber == identifierNumber) - return 0; - break; - - case PutByValDirect: - case PutByVal: - case PutByValAlias: - case GetByVal: - if (m_graph.byValIsPure(node)) { - // If PutByVal speculates that it's accessing an array with an - // integer index, then it's impossible for it to cause a structure - // change. - break; - } - return 0; - - default: - if (m_graph.clobbersWorld(node)) - return 0; - break; - } - if (node->canExit()) - return 0; + void write(AbstractHeap heap) + { + m_maps.write(heap); } - return 0; - } - - Node* getPropertyStorageLoadElimination(Node* child1) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - switch (node->op()) { - case GetButterfly: - if (node->child1() == child1) - return node; - break; + + void def(PureValue value) + { + Node* match = m_maps.addPure(value, m_node); + if (!match) + return; - case AllocatePropertyStorage: - case ReallocatePropertyStorage: - // If we can cheaply prove this is a change to our object's storage, we - // can optimize and use its result. - if (node->child1() == child1) - return node; - // Otherwise, we currently can't prove that this doesn't change our object's - // storage, so we conservatively assume that it may change the storage - // pointer of any object, including ours. - return 0; - - case PutByValDirect: - case PutByVal: - case PutByValAlias: - if (m_graph.byValIsPure(node)) { - // If PutByVal speculates that it's accessing an array with an - // integer index, then it's impossible for it to cause a structure - // change. - break; - } - return 0; - - case Arrayify: - case ArrayifyToStructure: - // We could check if the arrayification could affect our butterfly. - // But that seems like it would take Effort. - return 0; - - case MultiPutByOffset: - if (node->multiPutByOffsetData().reallocatesStorage()) - return 0; - break; - - default: - if (m_graph.clobbersWorld(node)) - return 0; - break; - } + m_node->replaceWith(match); + m_changed = true; } - return 0; - } - bool checkArrayElimination(Node* child1, ArrayMode arrayMode) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - switch (node->op()) { - case CheckArray: - if (node->child1() == child1 && node->arrayMode() == arrayMode) - return true; - break; - - case Arrayify: - case ArrayifyToStructure: - // We could check if the arrayification could affect our array. - // But that seems like it would take Effort. - return false; - - default: - if (m_graph.clobbersWorld(node)) - return false; - break; - } - } - return false; - } - - Node* getIndexedPropertyStorageLoadElimination(Node* child1, ArrayMode arrayMode) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; - - switch (node->op()) { - case GetIndexedPropertyStorage: { - if (node->child1() == child1 && node->arrayMode() == arrayMode) - return node; - break; + void def(HeapLocation location, LazyNode value) + { + LazyNode match = m_maps.addImpure(location, value); + if (!match) + return; + + if (m_node->op() == GetLocal) { + // Usually the CPS rethreading phase does this. But it's OK for us to mess with + // locals so long as: + // + // - We dethread the graph. Any changes we make may invalidate the assumptions of + // our CPS form, particularly if this GetLocal is linked to the variablesAtTail. + // + // - We don't introduce a Phantom for the child of the GetLocal. This wouldn't be + // totally wrong but it would pessimize the code. Just because there is a + // GetLocal doesn't mean that the child was live. Simply rerouting the all uses + // of this GetLocal will preserve the live-at-exit information just fine. + // + // We accomplish the latter by just clearing the child; then the Phantom that we + // introduce won't have children and so it will eventually just be deleted. + + m_node->child1() = Edge(); + m_graph.dethread(); } - - default: - if (m_graph.clobbersWorld(node)) - return 0; - break; + + if (value.isNode() && value.asNode() == m_node) { + match.ensureIsNode(m_insertionSet, m_block, 0)->owner = m_block; + ASSERT(match.isNode()); + m_node->replaceWith(match.asNode()); + m_changed = true; } } - return 0; - } - Node* getTypedArrayByteOffsetLoadElimination(Node* child1) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node == child1) - break; + private: + Graph& m_graph; + + bool m_changed; + Node* m_node; + BasicBlock* m_block; + + Maps m_maps; - switch (node->op()) { - case GetTypedArrayByteOffset: { - if (node->child1() == child1) - return node; - break; - } + InsertionSet m_insertionSet; + }; - default: - if (m_graph.clobbersWorld(node)) - return 0; - break; - } - } - return 0; - } - - Node* getMyScopeLoadElimination() + BlockCSE<SmallMaps> m_smallBlock; + BlockCSE<LargeMaps> m_largeBlock; +}; + +class GlobalCSEPhase : public Phase { +public: + GlobalCSEPhase(Graph& graph) + : Phase(graph, "global common subexpression elimination") + , m_impureDataMap(graph) + , m_insertionSet(graph) { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case CreateActivation: - // This may cause us to return a different scope. - return 0; - case GetMyScope: - return node; - default: - break; - } - } - return 0; } - Node* getLocalLoadElimination(VirtualRegister local, Node*& relevantLocalOp, bool careAboutClobbering) + bool run() { - relevantLocalOp = 0; + ASSERT(m_graph.m_fixpointState == FixpointNotConverged); + ASSERT(m_graph.m_form == SSA); - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetLocal: - if (node->local() == local) { - relevantLocalOp = node; - return node; - } - break; - - case GetLocalUnlinked: - if (node->unlinkedLocal() == local) { - relevantLocalOp = node; - return node; - } - break; - - case SetLocal: - if (node->local() == local) { - relevantLocalOp = node; - return node->child1().node(); - } - break; - - case GetClosureVar: - case PutClosureVar: - if (static_cast<VirtualRegister>(node->varNumber()) == local) - return 0; - break; - - default: - if (careAboutClobbering && m_graph.clobbersWorld(node)) - return 0; - break; - } + m_graph.initializeNodeOwners(); + m_graph.m_dominators.computeIfNecessary(m_graph); + + m_preOrder = m_graph.blocksInPreOrder(); + + // First figure out what gets clobbered by blocks. Node that this uses the preOrder list + // for convenience only. + for (unsigned i = m_preOrder.size(); i--;) { + m_block = m_preOrder[i]; + m_impureData = &m_impureDataMap[m_block]; + for (unsigned nodeIndex = m_block->size(); nodeIndex--;) + addWrites(m_graph, m_block->at(nodeIndex), m_impureData->writes); } - return 0; + + // Based on my experience doing this before, what follows might have to be made iterative. + // Right now it doesn't have to be iterative because everything is dominator-bsed. But when + // validation is enabled, we check if iterating would find new CSE opportunities. + + bool changed = iterate(); + + // FIXME: It should be possible to assert that CSE will not find any new opportunities if you + // run it a second time. Unfortunately, we cannot assert this right now. Note that if we did + // this, we'd have to first reset all of our state. + // https://bugs.webkit.org/show_bug.cgi?id=145853 + + return changed; } - bool uncapturedSetLocalStoreElimination(VirtualRegister local, Node* expectedNode) + bool iterate() { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetLocal: - case Flush: - if (node->local() == local) - return false; - break; - - case GetLocalUnlinked: - if (node->unlinkedLocal() == local) - return false; - break; - - case SetLocal: { - if (node->local() != local) - break; - if (node != expectedNode) - return false; - return true; - } - - case GetClosureVar: - case PutClosureVar: - if (static_cast<VirtualRegister>(node->varNumber()) == local) - return false; - break; - - case GetMyScope: - case SkipTopScope: - if (node->origin.semantic.inlineCallFrame) - break; - if (m_graph.uncheckedActivationRegister() == local) - return false; - break; - - case CheckArgumentsNotCreated: - case GetMyArgumentsLength: - case GetMyArgumentsLengthSafe: - if (m_graph.uncheckedArgumentsRegisterFor(node->origin.semantic) == local) - return false; - break; - - case GetMyArgumentByVal: - case GetMyArgumentByValSafe: - return false; - - case GetByVal: - // If this is accessing arguments then it's potentially accessing locals. - if (node->arrayMode().type() == Array::Arguments) - return false; - break; - - case CreateArguments: - case TearOffActivation: - case TearOffArguments: - // If an activation is being torn off then it means that captured variables - // are live. We could be clever here and check if the local qualifies as an - // argument register. But that seems like it would buy us very little since - // any kind of tear offs are rare to begin with. - return false; - - default: - break; - } - if (m_graph.clobbersWorld(node)) - return false; - } - RELEASE_ASSERT_NOT_REACHED(); - return false; - } + if (verbose) + dataLog("Performing iteration.\n"); + + m_changed = false; + m_graph.clearReplacements(); + + for (unsigned i = 0; i < m_preOrder.size(); ++i) { + m_block = m_preOrder[i]; + m_impureData = &m_impureDataMap[m_block]; + m_writesSoFar.clear(); + + if (verbose) + dataLog("Processing block ", *m_block, ":\n"); - bool capturedSetLocalStoreElimination(VirtualRegister local, Node* expectedNode) - { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - switch (node->op()) { - case GetLocal: - case Flush: - if (node->local() == local) - return false; - break; + for (unsigned nodeIndex = 0; nodeIndex < m_block->size(); ++nodeIndex) { + m_nodeIndex = nodeIndex; + m_node = m_block->at(nodeIndex); + if (verbose) + dataLog(" Looking at node ", m_node, ":\n"); - case GetLocalUnlinked: - if (node->unlinkedLocal() == local) - return false; - break; + m_graph.performSubstitution(m_node); - case SetLocal: { - if (node->local() != local) - break; - if (node != expectedNode) - return false; - return true; - } - - case Phantom: - case Check: - case HardPhantom: - case MovHint: - case JSConstant: - case DoubleConstant: - case Int52Constant: - break; - - default: - return false; + if (m_node->op() == Identity) { + m_node->replaceWith(m_node->child1().node()); + m_changed = true; + } else + clobberize(m_graph, m_node, *this); } + + m_insertionSet.execute(m_block); + + m_impureData->didVisit = true; } - RELEASE_ASSERT_NOT_REACHED(); - return false; - } - - bool setLocalStoreElimination(VariableAccessData* variableAccessData, Node* expectedNode) - { - if (variableAccessData->isCaptured()) - return capturedSetLocalStoreElimination(variableAccessData->local(), expectedNode); - return uncapturedSetLocalStoreElimination(variableAccessData->local(), expectedNode); + + return m_changed; } + + void read(AbstractHeap) { } - bool invalidationPointElimination() + void write(AbstractHeap heap) { - for (unsigned i = m_indexInBlock; i--;) { - Node* node = m_currentBlock->at(i); - if (node->op() == InvalidationPoint) - return true; - if (writesOverlap(m_graph, node, Watchpoint_fire)) - break; - } - return false; + clobber(m_impureData->availableAtTail, heap); + m_writesSoFar.add(heap); + if (verbose) + dataLog(" Clobbered, new tail map: ", mapDump(m_impureData->availableAtTail), "\n"); } - void eliminateIrrelevantPhantomChildren(Node* node) + void def(PureValue value) { - ASSERT(node->op() == Phantom); - for (unsigned i = 0; i < AdjacencyList::Size; ++i) { - Edge edge = node->children.child(i); - if (!edge) - continue; - if (edge.useKind() != UntypedUse) - continue; // Keep the type check. - if (edge->flags() & NodeRelevantToOSR) - continue; - - node->children.removeEdge(i--); - m_changed = true; - } - } - - bool setReplacement(Node* replacement) - { - if (!replacement) - return false; + // With pure values we do not have to worry about the possibility of some control flow path + // clobbering the value. So, we just search for all of the like values that have been + // computed. We pick one that is in a block that dominates ours. Note that this means that + // a PureValue will map to a list of nodes, since there may be many places in the control + // flow graph that compute a value but only one of them that dominates us. We may build up + // a large list of nodes that compute some value in the case of gnarly control flow. This + // is probably OK. - if (!ASSERT_DISABLED - && canonicalResultRepresentation(m_currentNode->result()) != canonicalResultRepresentation(replacement->result())) { - startCrashing(); - dataLog("CSE attempting to replace a node with a mismatched result: ", m_currentNode, " with ", replacement, "\n"); - dataLog("\n"); - m_graph.dump(); - RELEASE_ASSERT_NOT_REACHED(); + auto result = m_pureValues.add(value, Vector<Node*>()); + if (result.isNewEntry) { + result.iterator->value.append(m_node); + return; } - m_currentNode->convertToPhantom(); - eliminateIrrelevantPhantomChildren(m_currentNode); - - // At this point we will eliminate all references to this node. - m_currentNode->misc.replacement = replacement; - - m_changed = true; + for (unsigned i = result.iterator->value.size(); i--;) { + Node* candidate = result.iterator->value[i]; + if (m_graph.m_dominators.dominates(candidate->owner, m_block)) { + m_node->replaceWith(candidate); + m_changed = true; + return; + } + } - return true; + result.iterator->value.append(m_node); } - void eliminate() + LazyNode findReplacement(HeapLocation location) { - ASSERT(m_currentNode->mustGenerate()); - m_currentNode->convertToPhantom(); - eliminateIrrelevantPhantomChildren(m_currentNode); + // At this instant, our "availableAtTail" reflects the set of things that are available in + // this block so far. We check this map to find block-local CSE opportunities before doing + // a global search. + LazyNode match = m_impureData->availableAtTail.get(location); + if (!!match) { + if (verbose) + dataLog(" Found local match: ", match, "\n"); + return match; + } - m_changed = true; - } - - void eliminate(Node* node, NodeType phantomType = Phantom) - { - if (!node) - return; - ASSERT(node->mustGenerate()); - node->setOpAndDefaultFlags(phantomType); - if (phantomType == Phantom) - eliminateIrrelevantPhantomChildren(node); + // If it's not available at this point in the block, and at some prior point in the block + // we have clobbered this heap location, then there is no point in doing a global search. + if (m_writesSoFar.overlaps(location.heap())) { + if (verbose) + dataLog(" Not looking globally because of local clobber: ", m_writesSoFar, "\n"); + return nullptr; + } - m_changed = true; - } - - void performNodeCSE(Node* node) - { - if (cseMode == NormalCSE) - m_graph.performSubstitution(node); + // This perfoms a backward search over the control flow graph to find some possible + // non-local def() that matches our heap location. Such a match is only valid if there does + // not exist any path from that def() to our block that contains a write() that overlaps + // our heap. This algorithm looks for both of these things (the matching def and the + // overlapping writes) in one backwards DFS pass. + // + // This starts by looking at the starting block's predecessors, and then it continues along + // their predecessors. As soon as this finds a possible def() - one that defines the heap + // location we want while dominating our starting block - it assumes that this one must be + // the match. It then lets the DFS over predecessors complete, but it doesn't add the + // def()'s predecessors; this ensures that any blocks we visit thereafter are on some path + // from the def() to us. As soon as the DFG finds a write() that overlaps the location's + // heap, it stops, assuming that there is no possible match. Note that the write() case may + // trigger before we find a def(), or after. Either way, the write() case causes this + // function to immediately return nullptr. + // + // If the write() is found before we find the def(), then we know that any def() we would + // find would have a path to us that trips over the write() and hence becomes invalid. This + // is just a direct outcome of us looking for a def() that dominates us. Given a block A + // that dominates block B - so that A is the one that would have the def() and B is our + // starting block - we know that any other block must either be on the path from A to B, or + // it must be on a path from the root to A, but not both. So, if we haven't found A yet but + // we already have found a block C that has a write(), then C must be on some path from A + // to B, which means that A's def() is invalid for our purposes. Hence, before we find the + // def(), stopping on write() is the right thing to do. + // + // Stopping on write() is also the right thing to do after we find the def(). After we find + // the def(), we don't add that block's predecessors to the search worklist. That means + // that henceforth the only blocks we will see in the search are blocks on the path from + // the def() to us. If any such block has a write() that clobbers our heap then we should + // give up. + // + // Hence this graph search algorithm ends up being deceptively simple: any overlapping + // write() causes us to immediately return nullptr, and a matching def() means that we just + // record it and neglect to visit its precessors. - switch (node->op()) { + Vector<BasicBlock*, 8> worklist; + Vector<BasicBlock*, 8> seenList; + BitVector seen; - case Identity: - if (cseMode == StoreElimination) - break; - setReplacement(node->child1().node()); - break; - - // Handle the pure nodes. These nodes never have any side-effects. - case BitAnd: - case BitOr: - case BitXor: - case BitRShift: - case BitLShift: - case BitURShift: - case ArithAbs: - case ArithMin: - case ArithMax: - case ArithSqrt: - case ArithFRound: - case ArithSin: - case ArithCos: - case StringCharAt: - case StringCharCodeAt: - case IsUndefined: - case IsBoolean: - case IsNumber: - case IsString: - case IsObject: - case IsFunction: - case LogicalNot: - case SkipTopScope: - case SkipScope: - case GetClosureRegisters: - case GetScope: - case TypeOf: - case CompareEqConstant: - case ValueToInt32: - case MakeRope: - case DoubleRep: - case ValueRep: - case Int52Rep: - case BooleanToNumber: - if (cseMode == StoreElimination) - break; - setReplacement(pureCSE(node)); - break; - - case ArithAdd: - case ArithSub: - case ArithNegate: - case ArithMul: - case ArithDiv: - case ArithMod: - case UInt32ToNumber: - case DoubleAsInt32: { - if (cseMode == StoreElimination) - break; - Node* candidate = pureCSE(node); - if (!candidate) - break; - if (!subsumes(candidate->arithMode(), node->arithMode())) { - if (!subsumes(node->arithMode(), candidate->arithMode())) - break; - candidate->setArithMode(node->arithMode()); + for (unsigned i = m_block->predecessors.size(); i--;) { + BasicBlock* predecessor = m_block->predecessors[i]; + if (!seen.get(predecessor->index)) { + worklist.append(predecessor); + seen.set(predecessor->index); } - setReplacement(candidate); - break; - } - - case GetCallee: - if (cseMode == StoreElimination) - break; - setReplacement(getCalleeLoadElimination()); - break; - - case GetLocal: { - if (cseMode == StoreElimination) - break; - VariableAccessData* variableAccessData = node->variableAccessData(); - if (!variableAccessData->isCaptured()) - break; - Node* relevantLocalOp; - Node* possibleReplacement = getLocalLoadElimination(variableAccessData->local(), relevantLocalOp, variableAccessData->isCaptured()); - if (!relevantLocalOp) - break; - if (relevantLocalOp->op() != GetLocalUnlinked - && relevantLocalOp->variableAccessData() != variableAccessData) - break; - Node* phi = node->child1().node(); - if (!setReplacement(possibleReplacement)) - break; - - m_graph.dethread(); - - // If we replace a GetLocal with a GetLocalUnlinked, then turn the GetLocalUnlinked - // into a GetLocal. - if (relevantLocalOp->op() == GetLocalUnlinked) - relevantLocalOp->convertToGetLocal(variableAccessData, phi); - - m_changed = true; - break; - } - - case GetLocalUnlinked: { - if (cseMode == StoreElimination) - break; - Node* relevantLocalOpIgnored; - setReplacement(getLocalLoadElimination(node->unlinkedLocal(), relevantLocalOpIgnored, true)); - break; } - - case Flush: { - ASSERT(m_graph.m_form != SSA); - VariableAccessData* variableAccessData = node->variableAccessData(); - if (!node->child1()) { - // FIXME: It's silly that we punt on flush-eliminating here. We don't really - // need child1 to figure out what's going on. - // https://bugs.webkit.org/show_bug.cgi?id=130521 - break; - } - Node* replacement = node->child1().node(); - if (replacement->op() != SetLocal) - break; - ASSERT(replacement->variableAccessData() == variableAccessData); - // FIXME: We should be able to remove SetLocals that can exit; we just need - // to replace them with appropriate type checks. - if (cseMode == NormalCSE) { - // Need to be conservative at this time; if the SetLocal has any chance of performing - // any speculations then we cannot do anything. - FlushFormat format = variableAccessData->flushFormat(); - ASSERT(format != DeadFlush); - if (format != FlushedJSValue) - break; - } else { - if (replacement->canExit()) - break; + + while (!worklist.isEmpty()) { + BasicBlock* block = worklist.takeLast(); + seenList.append(block); + + if (verbose) + dataLog(" Searching in block ", *block, "\n"); + ImpureBlockData& data = m_impureDataMap[block]; + + // We require strict domination because this would only see things in our own block if + // they came *after* our position in the block. Clearly, while our block dominates + // itself, the things in the block after us don't dominate us. + if (m_graph.m_dominators.strictlyDominates(block, m_block)) { + if (verbose) + dataLog(" It strictly dominates.\n"); + DFG_ASSERT(m_graph, m_node, data.didVisit); + DFG_ASSERT(m_graph, m_node, !match); + if (verbose) + dataLog(" Availability map: ", mapDump(data.availableAtTail), "\n"); + match = data.availableAtTail.get(location); + if (verbose) + dataLog(" Availability: ", match, "\n"); + if (!!match) { + // Don't examine the predecessors of a match. At this point we just want to + // establish that other blocks on the path from here to there don't clobber + // the location we're interested in. + continue; + } } - if (!setLocalStoreElimination(variableAccessData, replacement)) - break; - ASSERT(replacement->op() == SetLocal); - node->convertToPhantom(); - Node* dataNode = replacement->child1().node(); - ASSERT(dataNode->hasResult()); - node->child1() = dataNode->defaultEdge(); - m_graph.dethread(); - m_changed = true; - break; - } - - case JSConstant: - case DoubleConstant: - case Int52Constant: - if (cseMode == StoreElimination) - break; - // This is strange, but necessary. Some phases will convert nodes to constants, - // which may result in duplicated constants. We use CSE to clean this up. - setReplacement(constantCSE(node)); - break; - case WeakJSConstant: - if (cseMode == StoreElimination) - break; - // FIXME: have CSE for weak constants against strong constants and vice-versa. - setReplacement(weakConstantCSE(node)); - break; - - case ConstantStoragePointer: - if (cseMode == StoreElimination) - break; - setReplacement(constantStoragePointerCSE(node)); - break; - - case GetArrayLength: - if (cseMode == StoreElimination) - break; - setReplacement(getArrayLengthElimination(node->child1().node())); - break; - - case GetMyScope: - if (cseMode == StoreElimination) - break; - setReplacement(getMyScopeLoadElimination()); - break; - - // Handle nodes that are conditionally pure: these are pure, and can - // be CSE'd, so long as the prediction is the one we want. - case CompareLess: - case CompareLessEq: - case CompareGreater: - case CompareGreaterEq: - case CompareEq: { - if (cseMode == StoreElimination) - break; - if (m_graph.isPredictedNumerical(node)) { - Node* replacement = pureCSE(node); - if (replacement && m_graph.isPredictedNumerical(replacement)) - setReplacement(replacement); + if (verbose) + dataLog(" Dealing with write set ", data.writes, "\n"); + if (data.writes.overlaps(location.heap())) { + if (verbose) + dataLog(" Clobbered.\n"); + return nullptr; } - break; - } - - // Finally handle heap accesses. These are not quite pure, but we can still - // optimize them provided that some subtle conditions are met. - case GetGlobalVar: - if (cseMode == StoreElimination) - break; - setReplacement(globalVarLoadElimination(node->registerPointer())); - break; - - case GetClosureVar: { - if (cseMode == StoreElimination) - break; - setReplacement(scopedVarLoadElimination(node->child1().node(), node->varNumber())); - break; - } - - case VarInjectionWatchpoint: - if (cseMode == StoreElimination) - break; - if (varInjectionWatchpointElimination()) - eliminate(); - break; - - case PutGlobalVar: - if (cseMode == NormalCSE) - break; - eliminate(globalVarStoreElimination(node->registerPointer())); - break; - case PutClosureVar: { - if (cseMode == NormalCSE) - break; - eliminate(scopedVarStoreElimination(node->child1().node(), node->child2().node(), node->varNumber())); - break; - } - - case GetByVal: - if (cseMode == StoreElimination) - break; - if (m_graph.byValIsPure(node)) - setReplacement(getByValLoadElimination(node->child1().node(), node->child2().node(), node->arrayMode())); - break; - - case PutByValDirect: - case PutByVal: { - if (cseMode == StoreElimination) - break; - Edge child1 = m_graph.varArgChild(node, 0); - Edge child2 = m_graph.varArgChild(node, 1); - if (node->arrayMode().canCSEStorage()) { - Node* replacement = getByValLoadElimination(child1.node(), child2.node(), node->arrayMode()); - if (!replacement) - break; - node->setOp(PutByValAlias); + for (unsigned i = block->predecessors.size(); i--;) { + BasicBlock* predecessor = block->predecessors[i]; + if (!seen.get(predecessor->index)) { + worklist.append(predecessor); + seen.set(predecessor->index); + } } - break; - } - - case CheckStructure: - if (cseMode == StoreElimination) - break; - if (checkStructureElimination(node->structureSet(), node->child1().node())) - eliminate(); - break; - - case StructureTransitionWatchpoint: - if (cseMode == StoreElimination) - break; - if (structureTransitionWatchpointElimination(node->structure(), node->child1().node())) - eliminate(); - break; - - case PutStructure: - if (cseMode == NormalCSE) - break; - eliminate(putStructureStoreElimination(node->child1().node()), PhantomPutStructure); - break; - - case CheckFunction: - if (cseMode == StoreElimination) - break; - if (checkFunctionElimination(node->function(), node->child1().node())) - eliminate(); - break; - - case CheckExecutable: - if (cseMode == StoreElimination) - break; - if (checkExecutableElimination(node->executable(), node->child1().node())) - eliminate(); - break; - - case CheckArray: - if (cseMode == StoreElimination) - break; - if (checkArrayElimination(node->child1().node(), node->arrayMode())) - eliminate(); - break; - - case GetIndexedPropertyStorage: { - if (cseMode == StoreElimination) - break; - setReplacement(getIndexedPropertyStorageLoadElimination(node->child1().node(), node->arrayMode())); - break; - } - - case GetTypedArrayByteOffset: { - if (cseMode == StoreElimination) - break; - setReplacement(getTypedArrayByteOffsetLoadElimination(node->child1().node())); - break; - } - - case GetButterfly: - if (cseMode == StoreElimination) - break; - setReplacement(getPropertyStorageLoadElimination(node->child1().node())); - break; - - case GetByOffset: - if (cseMode == StoreElimination) - break; - setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber, node->child2().node())); - break; - - case MultiGetByOffset: - if (cseMode == StoreElimination) - break; - setReplacement(getByOffsetLoadElimination(node->multiGetByOffsetData().identifierNumber, node->child1().node())); - break; - - case PutByOffset: - if (cseMode == NormalCSE) - break; - eliminate(putByOffsetStoreElimination(m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber, node->child1().node())); - break; - - case InvalidationPoint: - if (invalidationPointElimination()) - eliminate(); - break; - - case Phantom: - // FIXME: we ought to remove Phantom's that have no children. - // NB. It would be incorrect to do this for HardPhantom. In fact, the whole point - // of HardPhantom is that we *don't* do this for HardPhantoms, since they signify - // a more strict kind of liveness than the Phantom bytecode liveness. - eliminateIrrelevantPhantomChildren(node); - break; - - default: - // do nothing. - break; } - m_lastSeen[node->op()] = m_indexInBlock; + if (!match) + return nullptr; + + // Cache the results for next time. We cache them both for this block and for all of our + // predecessors, since even though we've already visited our predecessors, our predecessors + // probably have successors other than us. + // FIXME: Consider caching failed searches as well, when match is null. It's not clear that + // the reduction in compile time would warrant the increase in complexity, though. + // https://bugs.webkit.org/show_bug.cgi?id=134876 + for (BasicBlock* block : seenList) + m_impureDataMap[block].availableAtTail.add(location, match); + m_impureData->availableAtTail.add(location, match); + + return match; } - void performBlockCSE(BasicBlock* block) + void def(HeapLocation location, LazyNode value) { - if (!block) - return; - if (!block->isReachable) - return; + if (verbose) + dataLog(" Got heap location def: ", location, " -> ", value, "\n"); - m_currentBlock = block; - for (unsigned i = 0; i < LastNodeType; ++i) - m_lastSeen[i] = UINT_MAX; + LazyNode match = findReplacement(location); - for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) { - m_currentNode = block->at(m_indexInBlock); - performNodeCSE(m_currentNode); - } + if (verbose) + dataLog(" Got match: ", match, "\n"); - if (!ASSERT_DISABLED && cseMode == StoreElimination) { - // Nobody should have replacements set. - for (unsigned i = 0; i < block->size(); ++i) - ASSERT(!block->at(i)->misc.replacement); + if (!match) { + if (verbose) + dataLog(" Adding at-tail mapping: ", location, " -> ", value, "\n"); + auto result = m_impureData->availableAtTail.add(location, value); + ASSERT_UNUSED(result, result.isNewEntry); + return; + } + + if (value.isNode() && value.asNode() == m_node) { + if (!match.isNode()) { + // We need to properly record the constant in order to use an existing one if applicable. + // This ensures that re-running GCSE will not find new optimizations. + match.ensureIsNode(m_insertionSet, m_block, m_nodeIndex)->owner = m_block; + auto result = m_pureValues.add(PureValue(match.asNode(), match->constant()), Vector<Node*>()); + bool replaced = false; + if (!result.isNewEntry) { + for (unsigned i = result.iterator->value.size(); i--;) { + Node* candidate = result.iterator->value[i]; + if (m_graph.m_dominators.dominates(candidate->owner, m_block)) { + ASSERT(candidate); + match->replaceWith(candidate); + match.setNode(candidate); + replaced = true; + break; + } + } + } + if (!replaced) + result.iterator->value.append(match.asNode()); + } + ASSERT(match.asNode()); + m_node->replaceWith(match.asNode()); + m_changed = true; } } - BasicBlock* m_currentBlock; - Node* m_currentNode; - unsigned m_indexInBlock; - std::array<unsigned, LastNodeType> m_lastSeen; - bool m_changed; // Only tracks changes that have a substantive effect on other optimizations. + struct ImpureBlockData { + ImpureBlockData() + : didVisit(false) + { + } + + ClobberSet writes; + ImpureMap availableAtTail; + bool didVisit; + }; + + Vector<BasicBlock*> m_preOrder; + + PureMultiMap m_pureValues; + BlockMap<ImpureBlockData> m_impureDataMap; + + BasicBlock* m_block; + Node* m_node; + unsigned m_nodeIndex; + ImpureBlockData* m_impureData; + ClobberSet m_writesSoFar; + InsertionSet m_insertionSet; + + bool m_changed; }; -bool performCSE(Graph& graph) +} // anonymous namespace + +bool performLocalCSE(Graph& graph) { - SamplingRegion samplingRegion("DFG CSE Phase"); - return runPhase<CSEPhase<NormalCSE>>(graph); + SamplingRegion samplingRegion("DFG LocalCSE Phase"); + return runPhase<LocalCSEPhase>(graph); } -bool performStoreElimination(Graph& graph) +bool performGlobalCSE(Graph& graph) { - SamplingRegion samplingRegion("DFG Store Elimination Phase"); - return runPhase<CSEPhase<StoreElimination>>(graph); + SamplingRegion samplingRegion("DFG GlobalCSE Phase"); + return runPhase<GlobalCSEPhase>(graph); } } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) - - diff --git a/dfg/DFGCSEPhase.h b/dfg/DFGCSEPhase.h index 8f857ad..562fd9b 100644 --- a/dfg/DFGCSEPhase.h +++ b/dfg/DFGCSEPhase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,14 +34,20 @@ namespace JSC { namespace DFG { class Graph; -// Block-local common subexpression elimination. This is an optional phase, but -// it is rather profitable. It has fairly accurate heap modeling and will match -// a wide range of subexpression similarities. It's known to produce big wins -// on a few benchmarks, and is relatively cheap to run. -bool performCSE(Graph&); - -// Perform just block-local store elimination. -bool performStoreElimination(Graph&); +// Block-local common subexpression elimination. It uses clobberize() for heap +// modeling, which is quite precise. This phase is known to produce big wins on +// a few benchmarks, and is relatively cheap to run. +// +// Note that this phase also gets rid of Identity nodes, which means that it's +// currently not an optional phase. Basically, DFG IR doesn't have use-lists, +// so there is no instantaneous replaceAllUsesWith operation. Instead, you turn +// a node into an Identity and wait for CSE to clean it up. +bool performLocalCSE(Graph&); + +// Same, but global. Only works for SSA. This will find common subexpressions +// both in the same block and in any block that dominates the current block. It +// has no limits on how far it will look for load-elimination opportunities. +bool performGlobalCSE(Graph&); } } // namespace JSC::DFG diff --git a/dfg/DFGCallArrayAllocatorSlowPathGenerator.h b/dfg/DFGCallArrayAllocatorSlowPathGenerator.h index 02abdfd..9780e50 100644 --- a/dfg/DFGCallArrayAllocatorSlowPathGenerator.h +++ b/dfg/DFGCallArrayAllocatorSlowPathGenerator.h @@ -96,7 +96,7 @@ protected: for (unsigned i = 0; i < m_plans.size(); ++i) jit->silentSpill(m_plans[i]); GPRReg scratchGPR = AssemblyHelpers::selectScratchGPR(m_sizeGPR); - MacroAssembler::Jump bigLength = jit->m_jit.branch32(MacroAssembler::AboveOrEqual, m_sizeGPR, MacroAssembler::TrustedImm32(MIN_SPARSE_ARRAY_INDEX)); + MacroAssembler::Jump bigLength = jit->m_jit.branch32(MacroAssembler::AboveOrEqual, m_sizeGPR, MacroAssembler::TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)); jit->m_jit.move(MacroAssembler::TrustedImmPtr(m_contiguousStructure), scratchGPR); MacroAssembler::Jump done = jit->m_jit.jump(); bigLength.link(&jit->m_jit); diff --git a/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h b/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h new file mode 100644 index 0000000..871854c --- /dev/null +++ b/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 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 DFGCallCreateDirectArgumentsSlowPathGenerator_h +#define DFGCallCreateDirectArgumentsSlowPathGenerator_h + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "DFGOperations.h" +#include "DFGSlowPathGenerator.h" +#include "DFGSpeculativeJIT.h" +#include "DirectArguments.h" + +namespace JSC { namespace DFG { + +// This calls operationCreateDirectArguments but then restores the value of lengthGPR. +class CallCreateDirectArgumentsSlowPathGenerator : public JumpingSlowPathGenerator<MacroAssembler::JumpList> { +public: + CallCreateDirectArgumentsSlowPathGenerator( + MacroAssembler::JumpList from, SpeculativeJIT* jit, GPRReg resultGPR, Structure* structure, + GPRReg lengthGPR, unsigned minCapacity) + : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit) + , m_resultGPR(resultGPR) + , m_structure(structure) + , m_lengthGPR(lengthGPR) + , m_minCapacity(minCapacity) + { + jit->silentSpillAllRegistersImpl(false, m_plans, resultGPR); + } + +protected: + void generateInternal(SpeculativeJIT* jit) override + { + linkFrom(jit); + for (unsigned i = 0; i < m_plans.size(); ++i) + jit->silentSpill(m_plans[i]); + jit->callOperation( + operationCreateDirectArguments, m_resultGPR, m_structure, m_lengthGPR, m_minCapacity); + GPRReg canTrample = SpeculativeJIT::pickCanTrample(m_resultGPR); + for (unsigned i = m_plans.size(); i--;) + jit->silentFill(m_plans[i], canTrample); + jit->m_jit.loadPtr( + MacroAssembler::Address(m_resultGPR, DirectArguments::offsetOfLength()), m_lengthGPR); + jumpTo(jit); + } + +private: + GPRReg m_resultGPR; + Structure* m_structure; + GPRReg m_lengthGPR; + unsigned m_minCapacity; + Vector<SilentRegisterSavePlan, 2> m_plans; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGCallCreateDirectArgumentsSlowPathGenerator_h + diff --git a/dfg/DFGCapabilities.cpp b/dfg/DFGCapabilities.cpp index ab0fd25..ef4c247 100644 --- a/dfg/DFGCapabilities.cpp +++ b/dfg/DFGCapabilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,59 +30,58 @@ #include "CodeBlock.h" #include "DFGCommon.h" -#include "DFGFunctionWhitelist.h" #include "Interpreter.h" #include "JSCInlines.h" #include "Options.h" namespace JSC { namespace DFG { -bool isSupported(CodeBlock* codeBlock) +bool isSupported() { return Options::useDFGJIT() - && MacroAssembler::supportsFloatingPoint() - && Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount()) - && FunctionWhitelist::ensureGlobalWhitelist().contains(codeBlock); + && MacroAssembler::supportsFloatingPoint(); +} + +bool isSupportedForInlining(CodeBlock* codeBlock) +{ + return codeBlock->ownerExecutable()->isInliningCandidate(); } bool mightCompileEval(CodeBlock* codeBlock) { - return isSupported(codeBlock) + return isSupported() && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount(); } bool mightCompileProgram(CodeBlock* codeBlock) { - return isSupported(codeBlock) + return isSupported() && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount(); } bool mightCompileFunctionForCall(CodeBlock* codeBlock) { - return isSupported(codeBlock) + return isSupported() && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount(); } bool mightCompileFunctionForConstruct(CodeBlock* codeBlock) { - return isSupported(codeBlock) + return isSupported() && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount(); } bool mightInlineFunctionForCall(CodeBlock* codeBlock) { return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount() - && !codeBlock->ownerExecutable()->needsActivation() - && codeBlock->ownerExecutable()->isInliningCandidate(); + && isSupportedForInlining(codeBlock); } bool mightInlineFunctionForClosureCall(CodeBlock* codeBlock) { return codeBlock->instructionCount() <= Options::maximumFunctionForClosureCallInlineCandidateInstructionCount() - && !codeBlock->ownerExecutable()->needsActivation() - && codeBlock->ownerExecutable()->isInliningCandidate(); + && isSupportedForInlining(codeBlock); } bool mightInlineFunctionForConstruct(CodeBlock* codeBlock) { return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount() - && !codeBlock->ownerExecutable()->needsActivation() - && codeBlock->ownerExecutable()->isInliningCandidate(); + && isSupportedForInlining(codeBlock); } inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, CapabilityLevel result) @@ -93,12 +92,13 @@ inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, CapabilityLevel r CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction* pc) { + UNUSED_PARAM(codeBlock); // This function does some bytecode parsing. Ordinarily bytecode parsing requires the owning CodeBlock. It's sort of strange that we don't use it here right now. + switch (opcodeID) { case op_enter: - case op_touch_entry: case op_to_this: + case op_check_tdz: case op_create_this: - case op_get_callee: case op_bitand: case op_bitor: case op_bitxor: @@ -117,8 +117,9 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc case op_debug: case op_profile_will_call: case op_profile_did_call: + case op_profile_type: + case op_profile_control_flow: case op_mov: - case op_captured_mov: case op_check_has_instance: case op_instanceof: case op_is_undefined: @@ -126,6 +127,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc case op_is_number: case op_is_string: case op_is_object: + case op_is_object_or_null: case op_is_function: case op_not: case op_less: @@ -178,18 +180,34 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc case op_throw_static_error: case op_call: case op_construct: - case op_init_lazy_reg: - case op_create_arguments: - case op_tear_off_arguments: - case op_get_argument_by_val: - case op_get_arguments_length: + case op_call_varargs: + case op_construct_varargs: + case op_create_direct_arguments: + case op_create_scoped_arguments: + case op_create_out_of_band_arguments: + case op_get_from_arguments: + case op_put_to_arguments: case op_jneq_ptr: case op_typeof: case op_to_number: + case op_to_string: case op_switch_imm: case op_switch_char: case op_in: + case op_get_scope: case op_get_from_scope: + case op_get_enumerable_length: + case op_has_generic_property: + case op_has_structure_property: + case op_has_indexed_property: + case op_get_direct_pname: + case op_get_property_enumerator: + case op_enumerator_structure_pname: + case op_enumerator_generic_pname: + case op_to_index_string: + case op_new_func: + case op_new_func_exp: + case op_create_lexical_environment: return CanCompileAndInline; case op_put_to_scope: { @@ -203,26 +221,13 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc case op_resolve_scope: { // We don't compile 'catch' or 'with', so there's no point in compiling variable resolution within them. - ResolveType resolveType = ResolveModeAndType(pc[3].u.operand).type(); + ResolveType resolveType = ResolveModeAndType(pc[4].u.operand).type(); if (resolveType == Dynamic) return CannotCompile; return CanCompileAndInline; } - case op_call_varargs: - if (codeBlock->usesArguments() && pc[4].u.operand == codeBlock->argumentsRegister().offset() - && !pc[6].u.operand) - return CanInline; - // FIXME: We should handle this. - // https://bugs.webkit.org/show_bug.cgi?id=127626 - return CannotCompile; - - case op_new_regexp: - case op_create_activation: - case op_tear_off_activation: - case op_new_func: - case op_new_captured_func: - case op_new_func_exp: + case op_new_regexp: case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT. return CanCompile; diff --git a/dfg/DFGCapabilities.h b/dfg/DFGCapabilities.h index b01f044..4010bb2 100644 --- a/dfg/DFGCapabilities.h +++ b/dfg/DFGCapabilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,7 +38,8 @@ namespace JSC { namespace DFG { #if ENABLE(DFG_JIT) // Fast check functions; if they return true it is still necessary to // check opcodes. -bool isSupported(CodeBlock*); +bool isSupported(); +bool isSupportedForInlining(CodeBlock*); bool mightCompileEval(CodeBlock*); bool mightCompileProgram(CodeBlock*); bool mightCompileFunctionForCall(CodeBlock*); @@ -85,9 +86,7 @@ inline CapabilityLevel functionCapabilityLevel(bool mightCompile, bool mightInli return leastUpperBound(CanCompileAndInline, computedCapabilityLevel); if (mightCompile && !mightInline) return leastUpperBound(CanCompile, computedCapabilityLevel); - if (!mightCompile && mightInline) - return leastUpperBound(CanInline, computedCapabilityLevel); - if (!mightCompile && !mightInline) + if (!mightCompile) return CannotCompile; RELEASE_ASSERT_NOT_REACHED(); return CannotCompile; @@ -141,6 +140,14 @@ inline bool mightInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind return mightInlineFunctionForConstruct(codeBlock); } +inline bool mightCompileFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind) +{ + if (kind == CodeForCall) + return mightCompileFunctionForCall(codeBlock); + ASSERT(kind == CodeForConstruct); + return mightCompileFunctionForConstruct(codeBlock); +} + inline bool mightInlineFunction(CodeBlock* codeBlock) { return mightInlineFunctionFor(codeBlock, codeBlock->specializationKind()); diff --git a/dfg/DFGResurrectionForValidationPhase.cpp b/dfg/DFGCleanUpPhase.cpp similarity index 53% rename from dfg/DFGResurrectionForValidationPhase.cpp rename to dfg/DFGCleanUpPhase.cpp index 710ad0f..313094c 100644 --- a/dfg/DFGResurrectionForValidationPhase.cpp +++ b/dfg/DFGCleanUpPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,53 +24,66 @@ */ #include "config.h" -#include "DFGResurrectionForValidationPhase.h" +#include "DFGCleanUpPhase.h" #if ENABLE(DFG_JIT) -#include "DFGBasicBlockInlines.h" #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" +#include "DFGPredictionPropagationPhase.h" +#include "DFGVariableAccessDataDump.h" #include "JSCInlines.h" namespace JSC { namespace DFG { -class ResurrectionForValidationPhase : public Phase { +class CleanUpPhase : public Phase { public: - ResurrectionForValidationPhase(Graph& graph) - : Phase(graph, "resurrection for validation") + CleanUpPhase(Graph& graph) + : Phase(graph, "clean up") { } bool run() { - InsertionSet insertionSet(m_graph); + bool changed = false; - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - - for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { - Node* node = block->at(nodeIndex); - if (!node->hasResult()) - continue; - insertionSet.insertNode( - nodeIndex + 1, SpecNone, Phantom, node->origin, node->defaultEdge()); + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + unsigned sourceIndex = 0; + unsigned targetIndex = 0; + while (sourceIndex < block->size()) { + Node* node = block->at(sourceIndex++); + bool kill = false; + + if (node->op() == Check) + node->children = node->children.justChecks(); + + switch (node->op()) { + case Phantom: + case Check: + if (node->children.isEmpty()) + kill = true; + break; + default: + break; + } + + if (kill) + m_graph.m_allocator.free(node); + else + block->at(targetIndex++) = node; } - - insertionSet.execute(block); + block->resize(targetIndex); } - return true; + return changed; } }; - -bool performResurrectionForValidation(Graph& graph) + +bool performCleanUp(Graph& graph) { - SamplingRegion samplingRegion("DFG Resurrection For Validation Phase"); - return runPhase<ResurrectionForValidationPhase>(graph); + SamplingRegion samplingRegion("DFG Clean Up Phase"); + return runPhase<CleanUpPhase>(graph); } } } // namespace JSC::DFG diff --git a/dfg/DFGCleanUpPhase.h b/dfg/DFGCleanUpPhase.h new file mode 100644 index 0000000..3a1bc69 --- /dev/null +++ b/dfg/DFGCleanUpPhase.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014, 2015 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 DFGCleanUpPhase_h +#define DFGCleanUpPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Cleans up unneeded nodes, like empty Checks and Phantoms. + +bool performCleanUp(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGCleanUpPhase_h diff --git a/dfg/DFGClobberSet.cpp b/dfg/DFGClobberSet.cpp index 997c4d2..d4630e3 100644 --- a/dfg/DFGClobberSet.cpp +++ b/dfg/DFGClobberSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -122,37 +122,38 @@ HashSet<AbstractHeap> ClobberSet::setOf(bool direct) const void addReads(Graph& graph, Node* node, ClobberSet& readSet) { ClobberSetAdd addRead(readSet); - NoOpClobberize addWrite; - clobberize(graph, node, addRead, addWrite); + NoOpClobberize noOp; + clobberize(graph, node, addRead, noOp, noOp); } void addWrites(Graph& graph, Node* node, ClobberSet& writeSet) { - NoOpClobberize addRead; + NoOpClobberize noOp; ClobberSetAdd addWrite(writeSet); - clobberize(graph, node, addRead, addWrite); + clobberize(graph, node, noOp, addWrite, noOp); } void addReadsAndWrites(Graph& graph, Node* node, ClobberSet& readSet, ClobberSet& writeSet) { ClobberSetAdd addRead(readSet); ClobberSetAdd addWrite(writeSet); - clobberize(graph, node, addRead, addWrite); + NoOpClobberize noOp; + clobberize(graph, node, addRead, addWrite, noOp); } bool readsOverlap(Graph& graph, Node* node, ClobberSet& readSet) { ClobberSetOverlaps addRead(readSet); - NoOpClobberize addWrite; - clobberize(graph, node, addRead, addWrite); + NoOpClobberize noOp; + clobberize(graph, node, addRead, noOp, noOp); return addRead.result(); } bool writesOverlap(Graph& graph, Node* node, ClobberSet& writeSet) { - NoOpClobberize addRead; + NoOpClobberize noOp; ClobberSetOverlaps addWrite(writeSet); - clobberize(graph, node, addRead, addWrite); + clobberize(graph, node, noOp, addWrite, noOp); return addWrite.result(); } diff --git a/dfg/DFGClobberSet.h b/dfg/DFGClobberSet.h index 5dfe495..d76d355 100644 --- a/dfg/DFGClobberSet.h +++ b/dfg/DFGClobberSet.h @@ -80,7 +80,7 @@ public: { } - void operator()(AbstractHeap heap) + void operator()(AbstractHeap heap) const { m_set.add(heap); } @@ -96,7 +96,7 @@ public: { } - void operator()(AbstractHeap heap) + void operator()(AbstractHeap heap) const { m_result |= m_set.overlaps(heap); } @@ -105,7 +105,7 @@ public: private: const ClobberSet& m_set; - bool m_result; + mutable bool m_result; }; void addReads(Graph&, Node*, ClobberSet&); diff --git a/dfg/DFGClobberize.cpp b/dfg/DFGClobberize.cpp index 18ca74e..a693ba4 100644 --- a/dfg/DFGClobberize.cpp +++ b/dfg/DFGClobberize.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,20 +34,47 @@ namespace JSC { namespace DFG { bool doesWrites(Graph& graph, Node* node) { - NoOpClobberize addRead; + NoOpClobberize noOp; CheckClobberize addWrite; - clobberize(graph, node, addRead, addWrite); + clobberize(graph, node, noOp, addWrite, noOp); return addWrite.result(); } +bool accessesOverlap(Graph& graph, Node* node, AbstractHeap heap) +{ + NoOpClobberize noOp; + AbstractHeapOverlaps addAccess(heap); + clobberize(graph, node, addAccess, addAccess, noOp); + return addAccess.result(); +} + bool writesOverlap(Graph& graph, Node* node, AbstractHeap heap) { - NoOpClobberize addRead; + NoOpClobberize noOp; AbstractHeapOverlaps addWrite(heap); - clobberize(graph, node, addRead, addWrite); + clobberize(graph, node, noOp, addWrite, noOp); return addWrite.result(); } +bool clobbersHeap(Graph& graph, Node* node) +{ + bool result = false; + clobberize( + graph, node, NoOpClobberize(), + [&] (AbstractHeap heap) { + switch (heap.kind()) { + case World: + case Heap: + result = true; + break; + default: + break; + } + }, + NoOpClobberize()); + return result; +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGClobberize.h b/dfg/DFGClobberize.h index 9e464cf..5c6d17d 100644 --- a/dfg/DFGClobberize.h +++ b/dfg/DFGClobberize.h @@ -1,5 +1,5 @@ - /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. +/* + * Copyright (C) 2013-2015 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,23 +31,23 @@ #include "DFGAbstractHeap.h" #include "DFGEdgeUsesStructure.h" #include "DFGGraph.h" +#include "DFGHeapLocation.h" +#include "DFGLazyNode.h" +#include "DFGPureValue.h" namespace JSC { namespace DFG { -template<typename ReadFunctor, typename WriteFunctor> -void clobberizeForAllocation(ReadFunctor& read, WriteFunctor& write) -{ - read(GCState); - read(BarrierState); - write(GCState); - write(BarrierState); -} - -template<typename ReadFunctor, typename WriteFunctor> -void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write) +template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor> +void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def) { // Some notes: // + // - The canonical way of clobbering the world is to read world and write + // heap. This is because World subsumes Heap and Stack, and Stack can be + // read by anyone but only written to by explicit stack writing operations. + // Of course, claiming to also write World is not wrong; it'll just + // pessimise some important optimizations. + // // - We cannot hoist, or sink, anything that has effects. This means that the // easiest way of indicating that something cannot be hoisted is to claim // that it side-effects some miscellaneous thing. @@ -60,9 +60,9 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write // versions of those nodes that backward-exit instead, but I'm not convinced // of the soundness. // - // - Some nodes lie, and claim that they do not read the JSCell_structureID, JSCell_typeInfoFlags, etc. - // These are nodes that use the structure in a way that does not depend on - // things that change under structure transitions. + // - Some nodes lie, and claim that they do not read the JSCell_structureID, + // JSCell_typeInfoFlags, etc. These are nodes that use the structure in a way + // that does not depend on things that change under structure transitions. // // - It's implicitly understood that OSR exits read the world. This is why we // generally don't move or eliminate stores. Every node can exit, so the @@ -77,7 +77,33 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write // can use it for IR dumps. No promises on whether the answers are sound // prior to type inference - though they probably could be if we did some // small hacking. + // + // - If you do read(Stack) or read(World), then make sure that readTop() in + // PreciseLocalClobberize is correct. + // While read() and write() are fairly self-explanatory - they track what sorts of things the + // node may read or write - the def() functor is more tricky. It tells you the heap locations + // (not just abstract heaps) that are defined by a node. A heap location comprises an abstract + // heap, some nodes, and a LocationKind. Briefly, a location defined by a node is a location + // whose value can be deduced from looking at the node itself. The locations returned must obey + // the following properties: + // + // - If someone wants to CSE a load from the heap, then a HeapLocation object should be + // sufficient to find a single matching node. + // + // - The abstract heap is the only abstract heap that could be clobbered to invalidate any such + // CSE attempt. I.e. if clobberize() reports that on every path between some node and a node + // that defines a HeapLocation that it wanted, there were no writes to any abstract heap that + // overlap the location's heap, then we have a sound match. Effectively, the semantics of + // write() and def() are intertwined such that for them to be sound they must agree on what + // is CSEable. + // + // read(), write(), and def() for heap locations is enough to do GCSE on effectful things. To + // keep things simple, this code will also def() pure things. def() must be overloaded to also + // accept PureValue. This way, a client of clobberize() can implement GCSE entirely using the + // information that clobberize() passes to write() and def(). Other clients of clobberize() can + // just ignore def() by using a NoOpClobberize functor. + if (edgesUseStructure(graph, node)) read(JSCell_structureID); @@ -85,34 +111,35 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case JSConstant: case DoubleConstant: case Int52Constant: - case WeakJSConstant: + def(PureValue(node, node->constant())); + return; + case Identity: case Phantom: - case HardPhantom: + case Check: + case ExtractOSREntryLocal: + case CheckStructureImmediate: + return; + case BitAnd: case BitOr: case BitXor: case BitLShift: case BitRShift: case BitURShift: - case ValueToInt32: - case ArithAdd: - case ArithSub: - case ArithNegate: - case ArithMul: case ArithIMul: - case ArithDiv: - case ArithMod: case ArithAbs: + case ArithClz32: case ArithMin: case ArithMax: + case ArithPow: case ArithSqrt: case ArithFRound: case ArithSin: case ArithCos: + case ArithLog: case GetScope: case SkipScope: - case CheckFunction: case StringCharCodeAt: case StringFromCharCode: case CompareEqConstant: @@ -121,80 +148,224 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case IsBoolean: case IsNumber: case IsString: + case IsObject: case LogicalNot: - case ExtractOSREntryLocal: case CheckInBounds: - case ConstantStoragePointer: - case UInt32ToNumber: - case DoubleAsInt32: - case Check: case DoubleRep: case ValueRep: case Int52Rep: case BooleanToNumber: case FiatInt52: + case MakeRope: + case ValueToInt32: + case GetExecutable: + case BottomValue: + case TypeOf: + def(PureValue(node)); return; + case HasGenericProperty: + case HasStructureProperty: + case GetEnumerableLength: + case GetPropertyEnumerator: { + read(Heap); + write(SideState); + return; + } + + case GetDirectPname: { + // This reads and writes heap because it can end up calling a generic getByVal + // if the Structure changed, which could in turn end up calling a getter. + read(World); + write(Heap); + return; + } + + case ToIndexString: + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: { + def(PureValue(node)); + return; + } + + case HasIndexedProperty: { + read(JSObject_butterfly); + ArrayMode mode = node->arrayMode(); + switch (mode.type()) { + case Array::Int32: { + if (mode.isInBounds()) { + read(Butterfly_publicLength); + read(IndexedInt32Properties); + def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node)); + return; + } + read(Heap); + return; + } + + case Array::Double: { + if (mode.isInBounds()) { + read(Butterfly_publicLength); + read(IndexedDoubleProperties); + def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node)); + return; + } + read(Heap); + return; + } + + case Array::Contiguous: { + if (mode.isInBounds()) { + read(Butterfly_publicLength); + read(IndexedContiguousProperties); + def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node)); + return; + } + read(Heap); + return; + } + + case Array::ArrayStorage: { + if (mode.isInBounds()) { + read(Butterfly_vectorLength); + read(IndexedArrayStorageProperties); + return; + } + read(Heap); + return; + } + + default: { + read(World); + write(Heap); + return; + } + } + RELEASE_ASSERT_NOT_REACHED(); + return; + } + + case ArithAdd: + case ArithSub: + case ArithNegate: + case ArithMul: + case ArithDiv: + case ArithMod: + case DoubleAsInt32: + case UInt32ToNumber: + def(PureValue(node, node->arithMode())); + return; + + case ArithRound: + def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode()))); + return; + + case CheckCell: + def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand())); + return; + + case CheckNotEmpty: + def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1()))); + return; + + case ConstantStoragePointer: + def(PureValue(node, node->storagePointer())); + return; + case MovHint: case ZombieHint: + case KillStack: case Upsilon: case Phi: - case Flush: case PhantomLocal: case SetArgument: - case PhantomArguments: case Jump: case Branch: case Switch: case Throw: case ForceOSRExit: + case CheckBadCell: case Return: case Unreachable: case CheckTierUpInLoop: case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: case LoopHint: - case InvalidationPoint: case Breakpoint: case ProfileWillCall: case ProfileDidCall: + case ProfileType: + case ProfileControlFlow: + case StoreBarrier: + case PutHint: write(SideState); return; - case VariableWatchpoint: - case TypedArrayWatchpoint: - read(Watchpoint_fire); + case InvalidationPoint: write(SideState); + def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node)); return; - + + case Flush: + read(AbstractHeap(Stack, node->local())); + write(SideState); + return; + case NotifyWrite: write(Watchpoint_fire); write(SideState); return; - case CreateActivation: - case CreateArguments: - clobberizeForAllocation(read, write); - write(SideState); - write(Watchpoint_fire); + case CreateActivation: { + SymbolTable* table = node->castOperand<SymbolTable*>(); + if (table->singletonScope()->isStillValid()) + write(Watchpoint_fire); + read(HeapObjectCount); + write(HeapObjectCount); + return; + } + + case CreateDirectArguments: + case CreateScopedArguments: + case CreateClonedArguments: + read(Stack); + read(HeapObjectCount); + write(HeapObjectCount); return; + + case PhantomDirectArguments: + case PhantomClonedArguments: + // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those + // locals being promoted. + if (!isFTL(graph.m_plan.mode)) + read(Stack); - case FunctionReentryWatchpoint: - read(Watchpoint_fire); + // Even though it's phantom, it still has the property that one can't be replaced with another. + read(HeapObjectCount); + write(HeapObjectCount); return; case ToThis: case CreateThis: read(MiscFields); - clobberizeForAllocation(read, write); + read(HeapObjectCount); + write(HeapObjectCount); return; case VarInjectionWatchpoint: - case AllocationProfileWatchpoint: - case IsObject: + read(MiscFields); + def(HeapLocation(VarInjectionWatchpointLoc, MiscFields), LazyNode(node)); + return; + + case IsObjectOrNull: + read(MiscFields); + def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node)); + return; + case IsFunction: - case TypeOf: read(MiscFields); + def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node)); return; case GetById: @@ -206,30 +377,87 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case ArrayPop: case Call: case Construct: + case NativeCall: + case NativeConstruct: + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: case ToPrimitive: case In: - case GetMyArgumentsLengthSafe: - case GetMyArgumentByValSafe: case ValueAdd: read(World); - write(World); + write(Heap); + return; + + case GetGetter: + read(GetterSetter_getter); + def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node)); + return; + + case GetSetter: + read(GetterSetter_setter); + def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node)); return; case GetCallee: - read(AbstractHeap(Variables, JSStack::Callee)); + read(AbstractHeap(Stack, JSStack::Callee)); + def(HeapLocation(StackLoc, AbstractHeap(Stack, JSStack::Callee)), LazyNode(node)); + return; + + case GetArgumentCount: + read(AbstractHeap(Stack, JSStack::ArgumentCount)); + def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, JSStack::ArgumentCount)), LazyNode(node)); return; case GetLocal: - case GetArgument: - read(AbstractHeap(Variables, node->local())); + read(AbstractHeap(Stack, node->local())); + def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node)); return; case SetLocal: - write(AbstractHeap(Variables, node->local())); + write(AbstractHeap(Stack, node->local())); + def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node())); + return; + + case GetStack: { + AbstractHeap heap(Stack, node->stackAccessData()->local); + read(heap); + def(HeapLocation(StackLoc, heap), LazyNode(node)); return; + } + + case PutStack: { + AbstractHeap heap(Stack, node->stackAccessData()->local); + write(heap); + def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node())); + return; + } + + case LoadVarargs: { + read(World); + write(Heap); + LoadVarargsData* data = node->loadVarargsData(); + write(AbstractHeap(Stack, data->count.offset())); + for (unsigned i = data->limit; i--;) + write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i))); + return; + } + + case ForwardVarargs: { + // We could be way more precise here. + read(Stack); + + LoadVarargsData* data = node->loadVarargsData(); + write(AbstractHeap(Stack, data->count.offset())); + for (unsigned i = data->limit; i--;) + write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i))); + return; + } case GetLocalUnlinked: - read(AbstractHeap(Variables, node->unlinkedLocal())); + read(AbstractHeap(Stack, node->unlinkedLocal())); + def(HeapLocation(StackLoc, AbstractHeap(Stack, node->unlinkedLocal())), LazyNode(node)); return; case GetByVal: { @@ -240,7 +468,7 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case Array::Undecided: // Assume the worst since we don't have profiling yet. read(World); - write(World); + write(Heap); return; case Array::ForceExit: @@ -249,61 +477,71 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case Array::Generic: read(World); - write(World); + write(Heap); return; case Array::String: if (mode.isOutOfBounds()) { read(World); - write(World); + write(Heap); return; } // This appears to read nothing because it's only reading immutable data. + def(PureValue(node, mode.asWord())); return; - case Array::Arguments: - read(Arguments_registers); - read(Variables); + case Array::DirectArguments: + read(DirectArgumentsProperties); + def(HeapLocation(IndexedPropertyLoc, DirectArgumentsProperties, node->child1(), node->child2()), LazyNode(node)); + return; + + case Array::ScopedArguments: + read(ScopeProperties); + def(HeapLocation(IndexedPropertyLoc, ScopeProperties, node->child1(), node->child2()), LazyNode(node)); return; case Array::Int32: if (mode.isInBounds()) { read(Butterfly_publicLength); - read(Butterfly_vectorLength); read(IndexedInt32Properties); + def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node)); return; } read(World); - write(World); + write(Heap); return; case Array::Double: if (mode.isInBounds()) { read(Butterfly_publicLength); - read(Butterfly_vectorLength); read(IndexedDoubleProperties); + def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node)); return; } read(World); - write(World); + write(Heap); return; case Array::Contiguous: if (mode.isInBounds()) { read(Butterfly_publicLength); - read(Butterfly_vectorLength); read(IndexedContiguousProperties); + def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node)); return; } read(World); - write(World); + write(Heap); return; case Array::ArrayStorage: case Array::SlowPutArrayStorage: - // Give up on life for now. + if (mode.isInBounds()) { + read(Butterfly_vectorLength); + read(IndexedArrayStorageProperties); + return; + } read(World); - write(World); + write(Heap); return; case Array::Int8Array: @@ -316,26 +554,35 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case Array::Float32Array: case Array::Float64Array: read(TypedArrayProperties); - read(JSArrayBufferView_vector); - read(JSArrayBufferView_length); + read(MiscFields); + def(HeapLocation(IndexedPropertyLoc, TypedArrayProperties, node->child1(), node->child2()), LazyNode(node)); return; } RELEASE_ASSERT_NOT_REACHED(); return; } + + case GetMyArgumentByVal: { + read(Stack); + // FIXME: It would be trivial to have a def here. + // https://bugs.webkit.org/show_bug.cgi?id=143077 + return; + } case PutByValDirect: case PutByVal: case PutByValAlias: { ArrayMode mode = node->arrayMode(); + Node* base = graph.varArgChild(node, 0).node(); + Node* index = graph.varArgChild(node, 1).node(); + Node* value = graph.varArgChild(node, 2).node(); switch (mode.modeForPut().type()) { case Array::SelectUsingPredictions: case Array::Unprofiled: case Array::Undecided: - case Array::String: // Assume the worst since we don't have profiling yet. read(World); - write(World); + write(Heap); return; case Array::ForceExit: @@ -344,57 +591,59 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case Array::Generic: read(World); - write(World); - return; - - case Array::Arguments: - read(Arguments_registers); - read(Arguments_numArguments); - read(Arguments_slowArguments); - write(Variables); + write(Heap); return; case Array::Int32: if (node->arrayMode().isOutOfBounds()) { read(World); - write(World); + write(Heap); return; } read(Butterfly_publicLength); read(Butterfly_vectorLength); read(IndexedInt32Properties); write(IndexedInt32Properties); + if (node->arrayMode().mayStoreToHole()) + write(Butterfly_publicLength); + def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value)); return; case Array::Double: if (node->arrayMode().isOutOfBounds()) { read(World); - write(World); + write(Heap); return; } read(Butterfly_publicLength); read(Butterfly_vectorLength); read(IndexedDoubleProperties); write(IndexedDoubleProperties); + if (node->arrayMode().mayStoreToHole()) + write(Butterfly_publicLength); + def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, base, index), LazyNode(value)); return; case Array::Contiguous: if (node->arrayMode().isOutOfBounds()) { read(World); - write(World); + write(Heap); return; } read(Butterfly_publicLength); read(Butterfly_vectorLength); read(IndexedContiguousProperties); write(IndexedContiguousProperties); + if (node->arrayMode().mayStoreToHole()) + write(Butterfly_publicLength); + def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value)); return; case Array::ArrayStorage: case Array::SlowPutArrayStorage: // Give up on life for now. read(World); - write(World); + write(Heap); return; case Array::Int8Array: @@ -406,9 +655,15 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case Array::Uint32Array: case Array::Float32Array: case Array::Float64Array: - read(JSArrayBufferView_vector); - read(JSArrayBufferView_length); + read(MiscFields); write(TypedArrayProperties); + // FIXME: We can't def() anything here because these operations truncate their inputs. + // https://bugs.webkit.org/show_bug.cgi?id=134737 + return; + case Array::String: + case Array::DirectArguments: + case Array::ScopedArguments: + DFG_CRASH(graph, node, "impossible array mode for put"); return; } RELEASE_ASSERT_NOT_REACHED(); @@ -416,8 +671,6 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write } case CheckStructure: - case StructureTransitionWatchpoint: - case InstanceOf: read(JSCell_structureID); return; @@ -429,14 +682,15 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case CheckHasInstance: read(JSCell_typeInfoFlags); + def(HeapLocation(CheckHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node)); return; - case CheckExecutable: - read(JSFunction_executable); + case InstanceOf: + read(JSCell_structureID); + def(HeapLocation(InstanceOfLoc, JSCell_structureID, node->child1(), node->child2()), LazyNode(node)); return; - + case PutStructure: - case PhantomPutStructure: write(JSCell_structureID); write(JSCell_typeInfoType); write(JSCell_typeInfoFlags); @@ -445,17 +699,18 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case AllocatePropertyStorage: write(JSObject_butterfly); - clobberizeForAllocation(read, write); + def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node)); return; case ReallocatePropertyStorage: read(JSObject_butterfly); write(JSObject_butterfly); - clobberizeForAllocation(read, write); + def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node)); return; case GetButterfly: read(JSObject_butterfly); + def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node)); return; case Arrayify: @@ -467,47 +722,60 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write write(JSCell_indexingType); write(JSObject_butterfly); write(Watchpoint_fire); - clobberizeForAllocation(read, write); return; case GetIndexedPropertyStorage: - if (node->arrayMode().type() == Array::String) + if (node->arrayMode().type() == Array::String) { + def(PureValue(node, node->arrayMode().asWord())); return; - read(JSArrayBufferView_vector); + } + read(MiscFields); + def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node)); return; case GetTypedArrayByteOffset: - read(JSArrayBufferView_vector); - read(JSArrayBufferView_mode); - read(Butterfly_arrayBuffer); - read(ArrayBuffer_data); + read(MiscFields); + def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node)); return; case GetByOffset: - read(AbstractHeap(NamedProperties, graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber)); + case GetGetterSetterByOffset: { + unsigned identifierNumber = node->storageAccessData().identifierNumber; + AbstractHeap heap(NamedProperties, identifierNumber); + read(heap); + def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node)); return; + } - case MultiGetByOffset: + case MultiGetByOffset: { read(JSCell_structureID); read(JSObject_butterfly); - read(AbstractHeap(NamedProperties, node->multiGetByOffsetData().identifierNumber)); + AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber); + read(heap); + def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node)); return; + } - case MultiPutByOffset: + case MultiPutByOffset: { read(JSCell_structureID); read(JSObject_butterfly); - write(AbstractHeap(NamedProperties, node->multiPutByOffsetData().identifierNumber)); + AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber); + write(heap); if (node->multiPutByOffsetData().writesStructures()) write(JSCell_structureID); - if (node->multiPutByOffsetData().reallocatesStorage()) { + if (node->multiPutByOffsetData().reallocatesStorage()) write(JSObject_butterfly); - clobberizeForAllocation(read, write); - } + def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node())); return; + } - case PutByOffset: - write(AbstractHeap(NamedProperties, graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber)); + case PutByOffset: { + unsigned identifierNumber = node->storageAccessData().identifierNumber; + AbstractHeap heap(NamedProperties, identifierNumber); + write(heap); + def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node())); return; + } case GetArrayLength: { ArrayMode mode = node->arrayMode(); @@ -518,77 +786,179 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case Array::ArrayStorage: case Array::SlowPutArrayStorage: read(Butterfly_publicLength); + def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node)); return; case Array::String: + def(PureValue(node, mode.asWord())); return; - case Array::Arguments: - read(Arguments_overrideLength); - read(Arguments_numArguments); + case Array::DirectArguments: + case Array::ScopedArguments: + read(MiscFields); + def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node)); return; default: - read(JSArrayBufferView_length); + ASSERT(mode.typedArrayType() != NotTypedArray); + read(MiscFields); + def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node)); return; } } - case GetMyScope: - read(AbstractHeap(Variables, JSStack::ScopeChain)); - return; - - case SkipTopScope: - read(AbstractHeap(Variables, graph.activationRegister())); + case GetClosureVar: + read(AbstractHeap(ScopeProperties, node->scopeOffset().offset())); + def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node)); return; - case GetClosureRegisters: - read(JSVariableObject_registers); + case PutClosureVar: + write(AbstractHeap(ScopeProperties, node->scopeOffset().offset())); + def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node())); return; - case GetClosureVar: - read(AbstractHeap(Variables, node->varNumber())); + case GetFromArguments: { + AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset()); + read(heap); + def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node)); return; + } - case PutClosureVar: - write(AbstractHeap(Variables, node->varNumber())); + case PutToArguments: { + AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset()); + write(heap); + def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node())); return; + } case GetGlobalVar: - read(AbstractHeap(Absolute, node->registerPointer())); + read(AbstractHeap(Absolute, node->variablePointer())); + def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node)); return; case PutGlobalVar: - write(AbstractHeap(Absolute, node->registerPointer())); + write(AbstractHeap(Absolute, node->variablePointer())); + def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node())); return; - case NewObject: - case NewArray: case NewArrayWithSize: - case NewArrayBuffer: - case NewRegexp: - case NewStringObject: - case MakeRope: - case NewFunctionNoCheck: - case NewFunction: - case NewFunctionExpression: - clobberizeForAllocation(read, write); - return; - case NewTypedArray: - clobberizeForAllocation(read, write); - switch (node->child1().useKind()) { - case Int32Use: + read(HeapObjectCount); + write(HeapObjectCount); + return; + + case NewArray: { + read(HeapObjectCount); + write(HeapObjectCount); + + unsigned numElements = node->numChildren(); + + def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node), + LazyNode(graph.freeze(jsNumber(numElements)))); + + if (!numElements) return; - case UntypedUse: - read(World); - write(World); + + AbstractHeap heap; + switch (node->indexingType()) { + case ALL_DOUBLE_INDEXING_TYPES: + heap = IndexedDoubleProperties; + break; + + case ALL_INT32_INDEXING_TYPES: + heap = IndexedInt32Properties; + break; + + case ALL_CONTIGUOUS_INDEXING_TYPES: + heap = IndexedContiguousProperties; + break; + + default: return; + } + + if (numElements < graph.m_uint32ValuesInUse.size()) { + for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) { + Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx]; + def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))), + LazyNode(use.node())); + } + } else { + for (uint32_t operandIdx : graph.m_uint32ValuesInUse) { + if (operandIdx >= numElements) + continue; + Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx]; + def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))), + LazyNode(use.node())); + } + } + return; + } + + case NewArrayBuffer: { + read(HeapObjectCount); + write(HeapObjectCount); + + unsigned numElements = node->numConstants(); + def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node), + LazyNode(graph.freeze(jsNumber(numElements)))); + + AbstractHeap heap; + NodeType op = JSConstant; + switch (node->indexingType()) { + case ALL_DOUBLE_INDEXING_TYPES: + heap = IndexedDoubleProperties; + op = DoubleConstant; + break; + + case ALL_INT32_INDEXING_TYPES: + heap = IndexedInt32Properties; + break; + + case ALL_CONTIGUOUS_INDEXING_TYPES: + heap = IndexedContiguousProperties; + break; + default: - RELEASE_ASSERT_NOT_REACHED(); return; } + + JSValue* data = graph.m_codeBlock->constantBuffer(node->startConstant()); + if (numElements < graph.m_uint32ValuesInUse.size()) { + for (unsigned index = 0; index < numElements; ++index) { + def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))), + LazyNode(graph.freeze(data[index]), op)); + } + } else { + for (uint32_t index : graph.m_uint32ValuesInUse) { + if (index >= numElements) + continue; + def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))), + LazyNode(graph.freeze(data[index]), op)); + } + } + return; + } + + case NewObject: + case NewRegexp: + case NewStringObject: + case PhantomNewObject: + case MaterializeNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case MaterializeCreateActivation: + read(HeapObjectCount); + write(HeapObjectCount); + return; + case NewFunction: + if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid()) + write(Watchpoint_fire); + read(HeapObjectCount); + write(HeapObjectCount); + return; + case RegExpExec: case RegExpTest: read(RegExpState); @@ -598,9 +968,10 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case StringCharAt: if (node->arrayMode().isOutOfBounds()) { read(World); - write(World); + write(Heap); return; } + def(PureValue(node)); return; case CompareEq: @@ -608,53 +979,38 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write case CompareLessEq: case CompareGreater: case CompareGreaterEq: - if (!node->isBinaryUseKind(UntypedUse)) + if (!node->isBinaryUseKind(UntypedUse)) { + def(PureValue(node)); return; + } read(World); - write(World); + write(Heap); return; case ToString: + case CallStringConstructor: switch (node->child1().useKind()) { case StringObjectUse: case StringOrStringObjectUse: + // These don't def a pure value, unfortunately. I'll avoid load-eliminating these for + // now. return; case CellUse: case UntypedUse: read(World); - write(World); + write(Heap); return; default: RELEASE_ASSERT_NOT_REACHED(); return; } - - case TearOffActivation: - write(JSVariableObject_registers); - return; - - case TearOffArguments: - write(Arguments_registers); - return; - - case GetMyArgumentsLength: - read(AbstractHeap(Variables, graph.argumentsRegisterFor(node->origin.semantic))); - read(AbstractHeap(Variables, JSStack::ArgumentCount)); - return; - case GetMyArgumentByVal: - read(Variables); - return; - - case CheckArgumentsNotCreated: - read(AbstractHeap(Variables, graph.argumentsRegisterFor(node->origin.semantic))); - return; - case ThrowReferenceError: write(SideState); - clobberizeForAllocation(read, write); + read(HeapObjectCount); + write(HeapObjectCount); return; case CountExecution: @@ -662,25 +1018,20 @@ void clobberize(Graph& graph, Node* node, ReadFunctor& read, WriteFunctor& write read(InternalState); write(InternalState); return; - - case StoreBarrier: - case StoreBarrierWithNullCheck: - read(BarrierState); - write(BarrierState); - return; case LastNodeType: RELEASE_ASSERT_NOT_REACHED(); return; } - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data()); } class NoOpClobberize { public: NoOpClobberize() { } - void operator()(AbstractHeap) { } + template<typename... T> + void operator()(T...) const { } }; class CheckClobberize { @@ -690,12 +1041,13 @@ public: { } - void operator()(AbstractHeap) { m_result = true; } + template<typename... T> + void operator()(T...) const { m_result = true; } bool result() const { return m_result; } private: - bool m_result; + mutable bool m_result; }; bool doesWrites(Graph&, Node*); @@ -708,7 +1060,7 @@ public: { } - void operator()(AbstractHeap otherHeap) + void operator()(AbstractHeap otherHeap) const { if (m_result) return; @@ -719,11 +1071,80 @@ public: private: AbstractHeap m_heap; - bool m_result; + mutable bool m_result; }; +bool accessesOverlap(Graph&, Node*, AbstractHeap); bool writesOverlap(Graph&, Node*, AbstractHeap); +bool clobbersHeap(Graph&, Node*); + +// We would have used bind() for these, but because of the overlaoding that we are doing, +// it's quite a bit of clearer to just write this out the traditional way. + +template<typename T> +class ReadMethodClobberize { +public: + ReadMethodClobberize(T& value) + : m_value(value) + { + } + + void operator()(AbstractHeap heap) const + { + m_value.read(heap); + } +private: + T& m_value; +}; + +template<typename T> +class WriteMethodClobberize { +public: + WriteMethodClobberize(T& value) + : m_value(value) + { + } + + void operator()(AbstractHeap heap) const + { + m_value.write(heap); + } +private: + T& m_value; +}; + +template<typename T> +class DefMethodClobberize { +public: + DefMethodClobberize(T& value) + : m_value(value) + { + } + + void operator()(PureValue value) const + { + m_value.def(value); + } + + void operator()(HeapLocation location, LazyNode node) const + { + m_value.def(location, node); + } + +private: + T& m_value; +}; + +template<typename Adaptor> +void clobberize(Graph& graph, Node* node, Adaptor& adaptor) +{ + ReadMethodClobberize<Adaptor> read(adaptor); + WriteMethodClobberize<Adaptor> write(adaptor); + DefMethodClobberize<Adaptor> def(adaptor); + clobberize(graph, node, read, write, def); +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGCombinedLiveness.cpp b/dfg/DFGCombinedLiveness.cpp new file mode 100644 index 0000000..ccf9433 --- /dev/null +++ b/dfg/DFGCombinedLiveness.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 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 "DFGCombinedLiveness.h" + +#if ENABLE(DFG_JIT) + +#include "DFGAvailabilityMap.h" +#include "DFGBlockMapInlines.h" +#include "FullBytecodeLiveness.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +HashSet<Node*> liveNodesAtHead(Graph& graph, BasicBlock* block) +{ + HashSet<Node*> seen; + for (Node* node : block->ssa->liveAtHead) + seen.add(node); + + AvailabilityMap& availabilityMap = block->ssa->availabilityAtHead; + graph.forAllLocalsLiveInBytecode( + block->firstOrigin().forExit, + [&] (VirtualRegister reg) { + availabilityMap.closeStartingWithLocal( + reg, + [&] (Node* node) -> bool { + return seen.contains(node); + }, + [&] (Node* node) -> bool { + return seen.add(node).isNewEntry; + }); + }); + + return seen; +} + +CombinedLiveness::CombinedLiveness(Graph& graph) + : liveAtHead(graph) + , liveAtTail(graph) +{ + // First compute the liveAtHead for each block. + for (BasicBlock* block : graph.blocksInNaturalOrder()) + liveAtHead[block] = liveNodesAtHead(graph, block); + + // Now compute the liveAtTail by unifying the liveAtHead of the successors. + for (BasicBlock* block : graph.blocksInNaturalOrder()) { + for (BasicBlock* successor : block->successors()) { + for (Node* node : liveAtHead[successor]) + liveAtTail[block].add(node); + } + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGValueRecoveryOverride.h b/dfg/DFGCombinedLiveness.h similarity index 72% rename from dfg/DFGValueRecoveryOverride.h rename to dfg/DFGCombinedLiveness.h index 009f98a..ff761cf 100644 --- a/dfg/DFGValueRecoveryOverride.h +++ b/dfg/DFGCombinedLiveness.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,33 +23,31 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGValueRecoveryOverride_h -#define DFGValueRecoveryOverride_h +#ifndef DFGCombinedLiveness_h +#define DFGCombinedLiveness_h #if ENABLE(DFG_JIT) -#include "ValueRecovery.h" -#include <wtf/RefCounted.h> +#include "DFGBlockMap.h" +#include "DFGGraph.h" namespace JSC { namespace DFG { -class ValueRecoveryOverride : public RefCounted<ValueRecoveryOverride> { -public: - ValueRecoveryOverride() { } +// Returns the set of nodes live at tail, both due to due DFG and due to bytecode (i.e. OSR exit). +HashSet<Node*> liveNodesAtHead(Graph&, BasicBlock*); + +struct CombinedLiveness { + CombinedLiveness() { } - ValueRecoveryOverride(VirtualRegister operand, const ValueRecovery& recovery) - : operand(operand) - , recovery(recovery) - { - } + CombinedLiveness(Graph&); - VirtualRegister operand; - ValueRecovery recovery; + BlockMap<HashSet<Node*>> liveAtHead; + BlockMap<HashSet<Node*>> liveAtTail; }; } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) -#endif // DFGValueRecoveryOverride_h +#endif // DFGCombinedLiveness_h diff --git a/dfg/DFGCommon.cpp b/dfg/DFGCommon.cpp index 09ac340..96ac252 100644 --- a/dfg/DFGCommon.cpp +++ b/dfg/DFGCommon.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,20 +26,35 @@ #include "config.h" #include "DFGCommon.h" -#if ENABLE(DFG_JIT) - #include "DFGNode.h" #include "JSCInlines.h" +#include <wtf/PrintStream.h> + +#if ENABLE(DFG_JIT) namespace JSC { namespace DFG { +static StaticSpinLock crashLock; + void startCrashing() { -#if ENABLE(COMPARE_AND_SWAP) - static unsigned lock; - while (!WTF::weakCompareAndSwap(&lock, 0, 1)) - std::this_thread::yield(); -#endif + crashLock.lock(); +} + +bool isCrashing() +{ + return crashLock.isLocked(); +} + +bool stringLessThan(StringImpl& a, StringImpl& b) +{ + unsigned minLength = std::min(a.length(), b.length()); + for (unsigned i = 0; i < minLength; ++i) { + if (a[i] == b[i]) + continue; + return a[i] < b[i]; + } + return a.length() < b.length(); } } } // namespace JSC::DFG @@ -123,3 +138,28 @@ void printInternal(PrintStream& out, ProofStatus status) #endif // ENABLE(DFG_JIT) +namespace WTF { + +using namespace JSC::DFG; + +void printInternal(PrintStream& out, CapabilityLevel capabilityLevel) +{ + switch (capabilityLevel) { + case CannotCompile: + out.print("CannotCompile"); + return; + case CanCompile: + out.print("CanCompile"); + return; + case CanCompileAndInline: + out.print("CanCompileAndInline"); + return; + case CapabilityLevelNotSet: + out.print("CapabilityLevelNotSet"); + return; + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + diff --git a/dfg/DFGCommon.h b/dfg/DFGCommon.h index dbe7ca2..df8c8ef 100644 --- a/dfg/DFGCommon.h +++ b/dfg/DFGCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,6 @@ #if ENABLE(DFG_JIT) -#include "CodeOrigin.h" #include "Options.h" #include "VirtualRegister.h" @@ -63,6 +62,13 @@ enum RefNodeMode { DontRefNode }; +enum SwitchKind { + SwitchImm, + SwitchChar, + SwitchString, + SwitchCell +}; + inline bool verboseCompilationEnabled(CompilationMode mode = DFGMode) { return Options::verboseCompilation() || Options::dumpGraphAtEachPhase() || (isFTL(mode) && Options::verboseFTLCompilation()); @@ -146,6 +152,10 @@ enum PredictionPass { FixupPass }; +enum StructureRegistrationState { HaveNotStartedRegistering, AllStructuresAreRegistered }; + +enum StructureRegistrationResult { StructureRegisteredNormally, StructureRegisteredAndWatched }; + enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged }; // Describes the form you can expect the entire graph to be in. @@ -182,12 +192,10 @@ enum GraphForm { // expect to be live at the head, and which locals they make available at the // tail. ThreadedCPS form also implies that: // - // - GetLocals and SetLocals to uncaptured variables are not redundant within - // a basic block. + // - GetLocals and SetLocals are not redundant within a basic block. // // - All GetLocals and Flushes are linked directly to the last access point - // of the variable, which must not be another GetLocal if the variable is - // uncaptured. + // of the variable, which must not be another GetLocal. // // - Phantom(Phi) is not legal, but PhantomLocal is. // @@ -245,6 +253,11 @@ inline KillStatus killStatusForDoesKill(bool doesKill) return doesKill ? DoesKill : DoesNotKill; } +enum class PlanStage { + Initial, + AfterFixup +}; + template<typename T, typename U> bool checkAndSet(T& left, U right) { @@ -259,6 +272,35 @@ bool checkAndSet(T& left, U right) // when you're forcing a crash with diagnostics. void startCrashing(); +JS_EXPORT_PRIVATE bool isCrashing(); + +struct NodeAndIndex { + NodeAndIndex() + : node(nullptr) + , index(UINT_MAX) + { + } + + NodeAndIndex(Node* node, unsigned index) + : node(node) + , index(index) + { + ASSERT(!node == (index == UINT_MAX)); + } + + bool operator!() const + { + return !node; + } + + Node* node; + unsigned index; +}; + +// A less-than operator for strings that is useful for generating string switches. Sorts by < +// relation on characters. Ensures that if a is a prefix of b, then a < b. +bool stringLessThan(StringImpl& a, StringImpl& b); + } } // namespace JSC::DFG namespace WTF { @@ -279,7 +321,6 @@ namespace JSC { namespace DFG { enum CapabilityLevel { CannotCompile, - CanInline, CanCompile, CanCompileAndInline, CapabilityLevelNotSet @@ -299,7 +340,6 @@ inline bool canCompile(CapabilityLevel level) inline bool canInline(CapabilityLevel level) { switch (level) { - case CanInline: case CanCompileAndInline: return true; default: @@ -312,14 +352,6 @@ inline CapabilityLevel leastUpperBound(CapabilityLevel a, CapabilityLevel b) switch (a) { case CannotCompile: return CannotCompile; - case CanInline: - switch (b) { - case CanInline: - case CanCompileAndInline: - return CanInline; - default: - return CannotCompile; - } case CanCompile: switch (b) { case CanCompile: @@ -351,5 +383,11 @@ inline bool shouldShowDisassembly(CompilationMode mode = DFGMode) } } // namespace JSC::DFG +namespace WTF { + +void printInternal(PrintStream&, JSC::DFG::CapabilityLevel); + +} // namespace WTF + #endif // DFGCommon_h diff --git a/dfg/DFGCommonData.cpp b/dfg/DFGCommonData.cpp index ad4d09d..73860a1 100644 --- a/dfg/DFGCommonData.cpp +++ b/dfg/DFGCommonData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,7 @@ #include "DFGNode.h" #include "DFGPlan.h" #include "JSCInlines.h" +#include "TrackedReferences.h" #include "VM.h" namespace JSC { namespace DFG { @@ -41,8 +42,8 @@ void CommonData::notifyCompilingStructureTransition(Plan& plan, CodeBlock* codeB plan.transitions.addLazily( codeBlock, node->origin.semantic.codeOriginOwner(), - node->structureTransitionData().previousStructure, - node->structureTransitionData().newStructure); + node->transition()->previous, + node->transition()->next); } unsigned CommonData::addCodeOrigin(CodeOrigin codeOrigin) @@ -72,6 +73,24 @@ bool CommonData::invalidate() return true; } +void CommonData::validateReferences(const TrackedReferences& trackedReferences) +{ + if (InlineCallFrameSet* set = inlineCallFrames.get()) { + for (InlineCallFrame* inlineCallFrame : *set) { + for (ValueRecovery& recovery : inlineCallFrame->arguments) { + if (recovery.isConstant()) + trackedReferences.check(recovery.constant()); + } + + if (ScriptExecutable* executable = inlineCallFrame->executable.get()) + trackedReferences.check(executable); + + if (inlineCallFrame->calleeRecovery.isConstant()) + trackedReferences.check(inlineCallFrame->calleeRecovery.constant()); + } + } +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGCommonData.h b/dfg/DFGCommonData.h index af5c38d..af4812d 100644 --- a/dfg/DFGCommonData.h +++ b/dfg/DFGCommonData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,6 @@ #include "DFGJumpReplacement.h" #include "InlineCallFrameSet.h" #include "JSCell.h" -#include "ProfiledCodeBlockJettisoningWatchpoint.h" #include "ProfilerCompilation.h" #include "SymbolTable.h" #include <wtf/Bag.h> @@ -42,6 +41,7 @@ namespace JSC { class CodeBlock; class Identifier; +class TrackedReferences; namespace DFG { @@ -72,7 +72,6 @@ class CommonData { public: CommonData() : isStillValid(true) - , machineCaptureStart(std::numeric_limits<int>::max()) , frameRegisterCount(std::numeric_limits<unsigned>::max()) , requiredRegisterCountForExit(std::numeric_limits<unsigned>::max()) { } @@ -88,6 +87,8 @@ public: { return std::max(frameRegisterCount, requiredRegisterCountForExit); } + + void validateReferences(const TrackedReferences&); RefPtr<InlineCallFrameSet> inlineCallFrames; Vector<CodeOrigin, 0, UnsafeVectorOverflow> codeOrigins; @@ -95,8 +96,8 @@ public: Vector<Identifier> dfgIdentifiers; Vector<WeakReferenceTransition> transitions; Vector<WriteBarrier<JSCell>> weakReferences; - SegmentedVector<CodeBlockJettisoningWatchpoint, 1, 0> watchpoints; - SegmentedVector<ProfiledCodeBlockJettisoningWatchpoint, 1, 0> profiledWatchpoints; + Vector<WriteBarrier<Structure>> weakStructureReferences; + SegmentedVector<CodeBlockJettisoningWatchpoint, 1> watchpoints; Vector<JumpReplacement> jumpReplacements; RefPtr<Profiler::Compilation> compilation; @@ -104,9 +105,6 @@ public: bool allTransitionsHaveBeenMarked; // Initialized and used on every GC. bool isStillValid; - int machineCaptureStart; - std::unique_ptr<SlowArgument[]> slowArguments; - #if USE(JSVALUE32_64) std::unique_ptr<Bag<double>> doubleConstants; #endif diff --git a/dfg/DFGConstantFoldingPhase.cpp b/dfg/DFGConstantFoldingPhase.cpp index d0059a8..fd8df4d 100644 --- a/dfg/DFGConstantFoldingPhase.cpp +++ b/dfg/DFGConstantFoldingPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,7 @@ #if ENABLE(DFG_JIT) #include "DFGAbstractInterpreterInlines.h" +#include "DFGArgumentsUtilities.h" #include "DFGBasicBlock.h" #include "DFGGraph.h" #include "DFGInPlaceAbstractState.h" @@ -62,6 +63,16 @@ public: changed |= foldConstants(block); } + if (changed && m_graph.m_form == SSA) { + // It's now possible that we have Upsilons pointed at JSConstants. Fix that. + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + fixUpsilons(block); + } + } + return changed; } @@ -76,6 +87,7 @@ private: Node* node = block->at(indexInBlock); + bool alreadyHandled = false; bool eliminated = false; switch (node->op()) { @@ -86,16 +98,6 @@ private: break; } - case CheckArgumentsNotCreated: { - if (!isEmptySpeculation( - m_state.variables().operand( - m_graph.argumentsRegisterFor(node->origin.semantic)).m_type)) - break; - node->convertToPhantom(); - eliminated = true; - break; - } - case CheckStructure: case ArrayifyToStructure: { AbstractValue& value = m_state.forNode(node->child1()); @@ -104,27 +106,71 @@ private: set = node->structure(); else set = node->structureSet(); - if (value.m_currentKnownStructure.isSubsetOf(set)) { + if (value.m_structure.isSubsetOf(set)) { m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell. - node->convertToPhantom(); + node->remove(); eliminated = true; break; } - StructureAbstractValue& structureValue = value.m_futurePossibleStructure; - if (structureValue.isSubsetOf(set) - && structureValue.hasSingleton()) { - Structure* structure = structureValue.singleton(); - m_interpreter.execute(indexInBlock); // Catch the fact that we may filter on cell. - AdjacencyList children = node->children; - children.removeEdge(0); - if (!!children.child1()) - m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->origin, children); - node->children.setChild2(Edge()); - node->children.setChild3(Edge()); - node->convertToStructureTransitionWatchpoint(structure); - eliminated = true; + break; + } + + case GetIndexedPropertyStorage: { + JSArrayBufferView* view = m_graph.tryGetFoldableView( + m_state.forNode(node->child1()).m_value, node->arrayMode()); + if (!view) + break; + + if (view->mode() == FastTypedArray) { + // FIXME: It would be awesome to be able to fold the property storage for + // these GC-allocated typed arrays. For now it doesn't matter because the + // most common use-cases for constant typed arrays involve large arrays with + // aliased buffer views. + // https://bugs.webkit.org/show_bug.cgi?id=125425 break; } + + m_interpreter.execute(indexInBlock); + eliminated = true; + + m_insertionSet.insertCheck(indexInBlock, node->origin, node->children); + node->convertToConstantStoragePointer(view->vector()); + break; + } + + case CheckStructureImmediate: { + AbstractValue& value = m_state.forNode(node->child1()); + StructureSet& set = node->structureSet(); + + if (value.value()) { + if (Structure* structure = jsDynamicCast<Structure*>(value.value())) { + if (set.contains(structure)) { + m_interpreter.execute(indexInBlock); + node->remove(); + eliminated = true; + break; + } + } + } + + if (PhiChildren* phiChildren = m_interpreter.phiChildren()) { + bool allGood = true; + phiChildren->forAllTransitiveIncomingValues( + node, + [&] (Node* incoming) { + if (Structure* structure = incoming->dynamicCastConstant<Structure*>()) { + if (set.contains(structure)) + return; + } + allGood = false; + }); + if (allGood) { + m_interpreter.execute(indexInBlock); + node->remove(); + eliminated = true; + break; + } + } break; } @@ -132,25 +178,42 @@ private: case Arrayify: { if (!node->arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node->child1()))) break; - node->convertToPhantom(); + node->remove(); eliminated = true; break; } - case CheckFunction: { - if (m_state.forNode(node->child1()).value() != node->function()) + case PutStructure: { + if (m_state.forNode(node->child1()).m_structure.onlyStructure() != node->transition()->next) break; - node->convertToPhantom(); + + node->remove(); eliminated = true; break; } + case CheckCell: { + if (m_state.forNode(node->child1()).value() != node->cellOperand()->value()) + break; + node->remove(); + eliminated = true; + break; + } + + case CheckNotEmpty: { + if (m_state.forNode(node->child1()).m_type & SpecEmpty) + break; + node->remove(); + eliminated = true; + break; + } + case CheckInBounds: { JSValue left = m_state.forNode(node->child1()).value(); JSValue right = m_state.forNode(node->child2()).value(); if (left && right && left.isInt32() && right.isInt32() && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) { - node->convertToPhantom(); + node->remove(); eliminated = true; break; } @@ -158,48 +221,135 @@ private: break; } - case MultiGetByOffset: { - Edge childEdge = node->child1(); - Node* child = childEdge.node(); - MultiGetByOffsetData& data = node->multiGetByOffsetData(); - - Structure* structure = m_state.forNode(child).bestProvenStructure(); - if (!structure) + case GetMyArgumentByVal: { + JSValue index = m_state.forNode(node->child2()).value(); + if (!index || !index.isInt32()) break; - for (unsigned i = data.variants.size(); i--;) { - const GetByIdVariant& variant = data.variants[i]; - if (!variant.structureSet().contains(structure)) - continue; - - if (variant.chain()) + Node* arguments = node->child1().node(); + InlineCallFrame* inlineCallFrame = arguments->origin.semantic.inlineCallFrame; + + // Don't try to do anything if the index is known to be outside our static bounds. Note + // that our static bounds are usually strictly larger than the dynamic bounds. The + // exception is something like this, assuming foo() is not inlined: + // + // function foo() { return arguments[5]; } + // + // Here the static bound on number of arguments is 0, and we're accessing index 5. We + // will not strength-reduce this to GetStack because GetStack is otherwise assumed by the + // compiler to access those variables that are statically accounted for; for example if + // we emitted a GetStack on arg6 we would have out-of-bounds access crashes anywhere that + // uses an Operands<> map. There is not much cost to continuing to use a + // GetMyArgumentByVal in such statically-out-of-bounds accesses; we just lose CFA unless + // GCSE removes the access entirely. + if (inlineCallFrame) { + if (index.asUInt32() >= inlineCallFrame->arguments.size() - 1) break; - - emitGetByOffset(indexInBlock, node, structure, variant, data.identifierNumber); + } else { + if (index.asUInt32() >= m_state.variables().numberOfArguments() - 1) + break; + } + + m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. + + StackAccessData* data; + if (inlineCallFrame) { + data = m_graph.m_stackAccessData.add( + VirtualRegister( + inlineCallFrame->stackOffset + + CallFrame::argumentOffset(index.asInt32())), + FlushedJSValue); + } else { + data = m_graph.m_stackAccessData.add( + virtualRegisterForArgument(index.asInt32() + 1), FlushedJSValue); + } + + if (inlineCallFrame && !inlineCallFrame->isVarargs() + && index.asUInt32() < inlineCallFrame->arguments.size() - 1) { + node->convertToGetStack(data); eliminated = true; break; } + + Node* length = emitCodeToGetArgumentsArrayLength( + m_insertionSet, arguments, indexInBlock, node->origin); + m_insertionSet.insertNode( + indexInBlock, SpecNone, CheckInBounds, node->origin, + node->child2(), Edge(length, Int32Use)); + node->convertToGetStack(data); + eliminated = true; + break; + } + + case MultiGetByOffset: { + Edge baseEdge = node->child1(); + Node* base = baseEdge.node(); + MultiGetByOffsetData& data = node->multiGetByOffsetData(); + + // First prune the variants, then check if the MultiGetByOffset can be + // strength-reduced to a GetByOffset. + + AbstractValue baseValue = m_state.forNode(base); + + m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. + alreadyHandled = true; // Don't allow the default constant folder to do things to this. + + for (unsigned i = 0; i < data.variants.size(); ++i) { + GetByIdVariant& variant = data.variants[i]; + variant.structureSet().filter(baseValue); + if (variant.structureSet().isEmpty()) { + data.variants[i--] = data.variants.last(); + data.variants.removeLast(); + changed = true; + } + } + + if (data.variants.size() != 1) + break; + + emitGetByOffset( + indexInBlock, node, baseValue, data.variants[0], data.identifierNumber); + changed = true; break; } case MultiPutByOffset: { - Edge childEdge = node->child1(); - Node* child = childEdge.node(); + Edge baseEdge = node->child1(); + Node* base = baseEdge.node(); MultiPutByOffsetData& data = node->multiPutByOffsetData(); + + AbstractValue baseValue = m_state.forNode(base); - Structure* structure = m_state.forNode(child).bestProvenStructure(); - if (!structure) - break; + m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. + alreadyHandled = true; // Don't allow the default constant folder to do things to this. - for (unsigned i = data.variants.size(); i--;) { - const PutByIdVariant& variant = data.variants[i]; - if (variant.oldStructure() != structure) + + for (unsigned i = 0; i < data.variants.size(); ++i) { + PutByIdVariant& variant = data.variants[i]; + variant.oldStructure().filter(baseValue); + + if (variant.oldStructure().isEmpty()) { + data.variants[i--] = data.variants.last(); + data.variants.removeLast(); + changed = true; continue; + } - emitPutByOffset(indexInBlock, node, structure, variant, data.identifierNumber); - eliminated = true; - break; + if (variant.kind() == PutByIdVariant::Transition + && variant.oldStructure().onlyStructure() == variant.newStructure()) { + variant = PutByIdVariant::replace( + variant.oldStructure(), + variant.offset()); + changed = true; + } } + + if (data.variants.size() != 1) + break; + + emitPutByOffset( + indexInBlock, node, baseValue, data.variants[0], data.identifierNumber); + changed = true; break; } @@ -209,29 +359,49 @@ private: Node* child = childEdge.node(); unsigned identifierNumber = node->identifierNumber(); - if (childEdge.useKind() != CellUse) + AbstractValue baseValue = m_state.forNode(child); + + m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. + alreadyHandled = true; // Don't allow the default constant folder to do things to this. + + if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered() + || (node->child1().useKind() == UntypedUse || (baseValue.m_type & ~SpecCell))) break; - Structure* structure = m_state.forNode(child).bestProvenStructure(); - if (!structure) - break; - GetByIdStatus status = GetByIdStatus::computeFor( - vm(), structure, m_graph.identifiers()[identifierNumber]); + baseValue.m_structure.set(), m_graph.identifiers()[identifierNumber]); + if (!status.isSimple()) + break; + + for (unsigned i = status.numVariants(); i--;) { + if (!status[i].constantChecks().isEmpty() + || status[i].alternateBase()) { + // FIXME: We could handle prototype cases. + // https://bugs.webkit.org/show_bug.cgi?id=110386 + break; + } + } - if (!status.isSimple() || status.numVariants() != 1) { - // FIXME: We could handle prototype cases. - // https://bugs.webkit.org/show_bug.cgi?id=110386 + if (status.numVariants() == 1) { + emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber); + changed = true; break; } - emitGetByOffset(indexInBlock, node, structure, status[0], identifierNumber); - eliminated = true; + if (!isFTL(m_graph.m_plan.mode)) + break; + + MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add(); + data->variants = status.variants(); + data->identifierNumber = identifierNumber; + node->convertToMultiGetByOffset(data); + changed = true; break; } case PutById: - case PutByIdDirect: { + case PutByIdDirect: + case PutByIdFlush: { NodeOrigin origin = node->origin; Edge childEdge = node->child1(); Node* child = childEdge.node(); @@ -239,44 +409,83 @@ private: ASSERT(childEdge.useKind() == CellUse); - Structure* structure = m_state.forNode(child).bestProvenStructure(); - if (!structure) + AbstractValue baseValue = m_state.forNode(child); + + m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. + alreadyHandled = true; // Don't allow the default constant folder to do things to this. + + if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()) break; PutByIdStatus status = PutByIdStatus::computeFor( - vm(), m_graph.globalObjectFor(origin.semantic), - structure, + baseValue.m_structure.set(), m_graph.identifiers()[identifierNumber], node->op() == PutByIdDirect); if (!status.isSimple()) break; - if (status.numVariants() != 1) + + ASSERT(status.numVariants()); + + if (status.numVariants() > 1 && !isFTL(m_graph.m_plan.mode)) + break; + + changed = true; + + for (unsigned i = status.numVariants(); i--;) + addChecks(origin, indexInBlock, status[i].constantChecks()); + + if (status.numVariants() == 1) { + emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber); break; + } - emitPutByOffset(indexInBlock, node, structure, status[0], identifierNumber); - eliminated = true; + ASSERT(isFTL(m_graph.m_plan.mode)); + + MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add(); + data->variants = status.variants(); + data->identifierNumber = identifierNumber; + node->convertToMultiPutByOffset(data); break; } case ToPrimitive: { - if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString)) + if (m_state.forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol)) break; node->convertToIdentity(); + changed = true; break; } - - default: + + case Check: { + alreadyHandled = true; + m_interpreter.execute(indexInBlock); + for (unsigned i = 0; i < AdjacencyList::Size; ++i) { + Edge edge = node->children.child(i); + if (!edge) + break; + if (edge.isProved() || edge.willNotHaveCheck()) { + node->children.removeEdge(i--); + changed = true; + } + } break; } + default: + break; + } + if (eliminated) { changed = true; continue; } + if (alreadyHandled) + continue; + m_interpreter.execute(indexInBlock); if (!m_state.isValid()) { // If we invalidated then we shouldn't attempt to constant-fold. Here's an @@ -295,32 +504,23 @@ private: } if (!node->shouldGenerate() || m_state.didClobber() || node->hasConstant()) continue; - JSValue value = m_state.forNode(node).value(); - if (!value) - continue; - // Check if merging the abstract value of the constant into the abstract value - // we've proven for this node wouldn't widen the proof. If it widens the proof - // (i.e. says that the set contains more things in it than it previously did) - // then we refuse to fold. - AbstractValue oldValue = m_state.forNode(node); - AbstractValue constantValue; - constantValue.set(m_graph, value); - constantValue.fixTypeForRepresentation(node); - if (oldValue.merge(constantValue)) + // Interesting fact: this freezing that we do right here may turn an fragile value into + // a weak value. See DFGValueStrength.h. + FrozenValue* value = m_graph.freeze(m_state.forNode(node).value()); + if (!*value) continue; - - NodeOrigin origin = node->origin; - AdjacencyList children = node->children; - if (node->op() == GetLocal) + if (node->op() == GetLocal) { + // Need to preserve bytecode liveness in ThreadedCPS form. This wouldn't be necessary + // if it wasn't for https://bugs.webkit.org/show_bug.cgi?id=144086. + m_insertionSet.insertNode( + indexInBlock, SpecNone, PhantomLocal, node->origin, + OpInfo(node->variableAccessData())); m_graph.dethread(); - else - ASSERT(!node->hasVariableAccessData(m_graph)); - + } else + m_insertionSet.insertCheck(indexInBlock, node->origin, node->children); m_graph.convertToConstant(node, value); - m_insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, origin, children); changed = true; } @@ -330,38 +530,28 @@ private: return changed; } - void emitGetByOffset(unsigned indexInBlock, Node* node, Structure* structure, const GetByIdVariant& variant, unsigned identifierNumber) + void emitGetByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const GetByIdVariant& variant, unsigned identifierNumber) { NodeOrigin origin = node->origin; Edge childEdge = node->child1(); - Node* child = childEdge.node(); - bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton(); - bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell; + addBaseCheck(indexInBlock, node, baseValue, variant.structureSet()); - ASSERT(!variant.chain()); - ASSERT(variant.structureSet().contains(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_interpreter.execute(indexInBlock); - - if (needsWatchpoint) { - m_insertionSet.insertNode( - indexInBlock, SpecNone, StructureTransitionWatchpoint, origin, - OpInfo(structure), childEdge); - } else if (needsCellCheck) { - m_insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, origin, childEdge); - } - - if (variant.specificValue()) { - m_graph.convertToConstant(node, variant.specificValue()); + JSValue baseForLoad; + if (variant.alternateBase()) + baseForLoad = variant.alternateBase(); + else + baseForLoad = baseValue.m_value; + if (JSValue value = m_graph.tryGetConstantProperty(baseForLoad, variant.baseStructure(), variant.offset())) { + m_graph.convertToConstant(node, m_graph.freeze(value)); return; } - childEdge.setUseKind(KnownCellUse); + if (variant.alternateBase()) { + Node* child = m_insertionSet.insertConstant(indexInBlock, origin, variant.alternateBase()); + childEdge = Edge(child, KnownCellUse); + } else + childEdge.setUseKind(KnownCellUse); Edge propertyStorage; @@ -372,129 +562,131 @@ private: indexInBlock, SpecNone, GetButterfly, origin, childEdge)); } - node->convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorage); + StorageAccessData& data = *m_graph.m_storageAccessData.add(); + data.offset = variant.offset(); + data.identifierNumber = identifierNumber; - StorageAccessData storageAccessData; - storageAccessData.offset = variant.offset(); - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); + node->convertToGetByOffset(data, propertyStorage); } - void emitPutByOffset(unsigned indexInBlock, Node* node, Structure* structure, const PutByIdVariant& variant, unsigned identifierNumber) + void emitPutByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const PutByIdVariant& variant, unsigned identifierNumber) { NodeOrigin origin = node->origin; Edge childEdge = node->child1(); - Node* child = childEdge.node(); - - ASSERT(variant.oldStructure() == structure); - bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton(); - bool needsCellCheck = m_state.forNode(child).m_type & ~SpecCell; - - // 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_interpreter.execute(indexInBlock); - - if (needsWatchpoint) { - m_insertionSet.insertNode( - indexInBlock, SpecNone, StructureTransitionWatchpoint, origin, - OpInfo(structure), childEdge); - } else if (needsCellCheck) { - m_insertionSet.insertNode( - indexInBlock, SpecNone, Phantom, origin, childEdge); - } + addBaseCheck(indexInBlock, node, baseValue, variant.oldStructure()); childEdge.setUseKind(KnownCellUse); - StructureTransitionData* transitionData = 0; + Transition* transition = 0; if (variant.kind() == PutByIdVariant::Transition) { - transitionData = m_graph.addStructureTransitionData( - StructureTransitionData(structure, variant.newStructure())); - - if (node->op() == PutById) { - if (!structure->storedPrototype().isNull()) { - addStructureTransitionCheck( - origin, indexInBlock, - structure->storedPrototype().asCell()); - } - - m_graph.chains().addLazily(variant.structureChain()); - - for (unsigned i = 0; i < variant.structureChain()->size(); ++i) { - JSValue prototype = variant.structureChain()->at(i)->storedPrototype(); - if (prototype.isNull()) - continue; - ASSERT(prototype.isCell()); - addStructureTransitionCheck( - origin, indexInBlock, prototype.asCell()); - } - } + transition = m_graph.m_transitions.add( + variant.oldStructureForTransition(), variant.newStructure()); } Edge propertyStorage; if (isInlineOffset(variant.offset())) propertyStorage = childEdge; - else if ( - variant.kind() == PutByIdVariant::Replace - || structure->outOfLineCapacity() == variant.newStructure()->outOfLineCapacity()) { + else if (!variant.reallocatesStorage()) { propertyStorage = Edge(m_insertionSet.insertNode( indexInBlock, SpecNone, GetButterfly, origin, childEdge)); - } else if (!structure->outOfLineCapacity()) { + } else if (!variant.oldStructureForTransition()->outOfLineCapacity()) { ASSERT(variant.newStructure()->outOfLineCapacity()); ASSERT(!isInlineOffset(variant.offset())); Node* allocatePropertyStorage = m_insertionSet.insertNode( indexInBlock, SpecNone, AllocatePropertyStorage, - origin, OpInfo(transitionData), childEdge); - m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse)); + origin, OpInfo(transition), childEdge); propertyStorage = Edge(allocatePropertyStorage); } else { - ASSERT(structure->outOfLineCapacity()); - ASSERT(variant.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity()); + ASSERT(variant.oldStructureForTransition()->outOfLineCapacity()); + ASSERT(variant.newStructure()->outOfLineCapacity() > variant.oldStructureForTransition()->outOfLineCapacity()); ASSERT(!isInlineOffset(variant.offset())); Node* reallocatePropertyStorage = m_insertionSet.insertNode( indexInBlock, SpecNone, ReallocatePropertyStorage, origin, - OpInfo(transitionData), childEdge, + OpInfo(transition), childEdge, Edge(m_insertionSet.insertNode( indexInBlock, SpecNone, GetButterfly, origin, childEdge))); - m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse)); propertyStorage = Edge(reallocatePropertyStorage); } + StorageAccessData& data = *m_graph.m_storageAccessData.add(); + data.offset = variant.offset(); + data.identifierNumber = identifierNumber; + + node->convertToPutByOffset(data, propertyStorage); + if (variant.kind() == PutByIdVariant::Transition) { - Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transitionData), childEdge); - m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node->child1().node(), KnownCellUse)); - m_insertionSet.insert(indexInBlock, putStructure); + // FIXME: PutStructure goes last until we fix either + // https://bugs.webkit.org/show_bug.cgi?id=142921 or + // https://bugs.webkit.org/show_bug.cgi?id=142924. + m_insertionSet.insertNode( + indexInBlock + 1, SpecNone, PutStructure, origin, OpInfo(transition), childEdge); } - - node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage); - m_insertionSet.insertNode( - indexInBlock, SpecNone, StoreBarrier, origin, - Edge(node->child2().node(), KnownCellUse)); - - StorageAccessData storageAccessData; - storageAccessData.offset = variant.offset(); - storageAccessData.identifierNumber = identifierNumber; - m_graph.m_storageAccessData.append(storageAccessData); } - - void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell) + + void addBaseCheck( + unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const StructureSet& set) { - Node* weakConstant = m_insertionSet.insertNode( - indexInBlock, speculationFromValue(cell), WeakJSConstant, origin, OpInfo(cell)); - - if (m_graph.watchpoints().isStillValid(cell->structure()->transitionWatchpointSet())) { + if (!baseValue.m_structure.isSubsetOf(set)) { + // Arises when we prune MultiGetByOffset. We could have a + // MultiGetByOffset with a single variant that checks for structure S, + // and the input has structures S and T, for example. m_insertionSet.insertNode( - indexInBlock, SpecNone, StructureTransitionWatchpoint, origin, - OpInfo(cell->structure()), Edge(weakConstant, CellUse)); + indexInBlock, SpecNone, CheckStructure, node->origin, + OpInfo(m_graph.addStructureSet(set)), node->child1()); return; } + + if (baseValue.m_type & ~SpecCell) + m_insertionSet.insertCheck(indexInBlock, node->origin, node->child1()); + } + + void addChecks( + NodeOrigin origin, unsigned indexInBlock, const ConstantStructureCheckVector& checks) + { + for (unsigned i = 0; i < checks.size(); ++i) { + addStructureTransitionCheck( + origin, indexInBlock, checks[i].constant(), checks[i].structure()); + } + } + void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell, Structure* structure) + { + if (m_graph.registerStructure(cell->structure()) == StructureRegisteredAndWatched) + return; + + m_graph.registerStructure(structure); + + Node* weakConstant = m_insertionSet.insertNode( + indexInBlock, speculationFromValue(cell), JSConstant, origin, + OpInfo(m_graph.freeze(cell))); + m_insertionSet.insertNode( indexInBlock, SpecNone, CheckStructure, origin, - OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse)); + OpInfo(m_graph.addStructureSet(structure)), Edge(weakConstant, CellUse)); + } + + void fixUpsilons(BasicBlock* block) + { + for (unsigned nodeIndex = block->size(); nodeIndex--;) { + Node* node = block->at(nodeIndex); + if (node->op() != Upsilon) + continue; + switch (node->phi()->op()) { + case Phi: + break; + case JSConstant: + case DoubleConstant: + case Int52Constant: + node->remove(); + break; + default: + DFG_CRASH(m_graph, node, "Bad Upsilon phi() pointer"); + break; + } + } } InPlaceAbstractState m_state; diff --git a/dfg/DFGConstantHoistingPhase.cpp b/dfg/DFGConstantHoistingPhase.cpp new file mode 100644 index 0000000..68f3651 --- /dev/null +++ b/dfg/DFGConstantHoistingPhase.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2015 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 "DFGConstantHoistingPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" +#include "DFGInsertionSet.h" +#include "DFGPhase.h" +#include "DFGPredictionPropagationPhase.h" +#include "DFGVariableAccessDataDump.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +namespace { + +class ConstantHoistingPhase : public Phase { +public: + ConstantHoistingPhase(Graph& graph) + : Phase(graph, "constant hoisting") + { + } + + bool run() + { + DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA); + + m_graph.clearReplacements(); + + HashMap<FrozenValue*, Node*> jsValues; + HashMap<FrozenValue*, Node*> doubleValues; + HashMap<FrozenValue*, Node*> int52Values; + + auto valuesFor = [&] (NodeType op) -> HashMap<FrozenValue*, Node*>& { + // Use a roundabout approach because clang thinks that this closure returning a + // reference to a stack-allocated value in outer scope is a bug. It's not. + HashMap<FrozenValue*, Node*>* result; + + switch (op) { + case JSConstant: + result = &jsValues; + break; + case DoubleConstant: + result = &doubleValues; + break; + case Int52Constant: + result = &int52Values; + break; + default: + DFG_CRASH(m_graph, nullptr, "Invalid node type in valuesFor()"); + result = nullptr; + break; + } + + return *result; + }; + + Vector<Node*> toFree; + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + unsigned sourceIndex = 0; + unsigned targetIndex = 0; + while (sourceIndex < block->size()) { + Node* node = block->at(sourceIndex++); + switch (node->op()) { + case JSConstant: + case DoubleConstant: + case Int52Constant: { + HashMap<FrozenValue*, Node*>& values = valuesFor(node->op()); + auto result = values.add(node->constant(), node); + if (result.isNewEntry) + node->origin = NodeOrigin(); + else { + node->setReplacement(result.iterator->value); + toFree.append(node); + } + break; + } + default: + block->at(targetIndex++) = node; + break; + } + } + block->resize(targetIndex); + } + + // Insert the constants into the root block. + InsertionSet insertionSet(m_graph); + auto insertConstants = [&] (const HashMap<FrozenValue*, Node*>& values) { + for (auto& entry : values) + insertionSet.insert(0, entry.value); + }; + insertConstants(jsValues); + insertConstants(doubleValues); + insertConstants(int52Values); + insertionSet.execute(m_graph.block(0)); + + // Perform all of the substitutions. We want all instances of the removed constants to + // point at their replacements. + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) + m_graph.performSubstitution(node); + } + + // And finally free the constants that we removed. + for (Node* node : toFree) + m_graph.m_allocator.free(node); + + return true; + } +}; + +} // anonymous namespace + +bool performConstantHoisting(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Constant Hoisting Phase"); + return runPhase<ConstantHoistingPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGConstantHoistingPhase.h b/dfg/DFGConstantHoistingPhase.h new file mode 100644 index 0000000..5124f16 --- /dev/null +++ b/dfg/DFGConstantHoistingPhase.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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 DFGConstantHoistingPhase_h +#define DFGConstantHoistingPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Hoists all constants to the top of the root block. + +bool performConstantHoisting(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGConstantHoistingPhase_h diff --git a/dfg/DFGCriticalEdgeBreakingPhase.cpp b/dfg/DFGCriticalEdgeBreakingPhase.cpp index 1656774..18f6f5e 100644 --- a/dfg/DFGCriticalEdgeBreakingPhase.cpp +++ b/dfg/DFGCriticalEdgeBreakingPhase.cpp @@ -77,7 +77,7 @@ private: // don't know its execution frequency. BasicBlock* pad = m_insertionSet.insertBefore(*successor, PNaN); pad->appendNode( - m_graph, SpecNone, Jump, (*successor)->at(0)->origin, OpInfo(*successor)); + m_graph, SpecNone, Jump, (*successor)->firstOrigin(), OpInfo(*successor)); pad->predecessors.append(predecessor); (*successor)->replacePredecessor(predecessor, pad); diff --git a/dfg/DFGDCEPhase.cpp b/dfg/DFGDCEPhase.cpp index e8cf933..5290f24 100644 --- a/dfg/DFGDCEPhase.cpp +++ b/dfg/DFGDCEPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,75 +48,34 @@ public: { ASSERT(m_graph.m_form == ThreadedCPS || m_graph.m_form == SSA); - // First reset the counts to 0 for all nodes. - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned indexInBlock = block->size(); indexInBlock--;) - block->at(indexInBlock)->setRefCount(0); - for (unsigned phiIndex = block->phis.size(); phiIndex--;) - block->phis[phiIndex]->setRefCount(0); - } - - // Now find the roots: - // - Nodes that are must-generate. - // - Nodes that are reachable from type checks. - // Set their ref counts to 1 and put them on the worklist. - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { + m_graph.computeRefCounts(); + + for (BasicBlock* block : m_graph.blocksInPreOrder()) + fixupBlock(block); + + cleanVariables(m_graph.m_arguments); + + // Just do a basic Phantom/Check clean-up. + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; - for (unsigned indexInBlock = block->size(); indexInBlock--;) { - Node* node = block->at(indexInBlock); - DFG_NODE_DO_TO_CHILDREN(m_graph, node, findTypeCheckRoot); - if (!(node->flags() & NodeMustGenerate)) - continue; - if (!node->postfixRef()) - m_worklist.append(node); - } - } - - while (!m_worklist.isEmpty()) { - while (!m_worklist.isEmpty()) { - Node* node = m_worklist.last(); - m_worklist.removeLast(); - ASSERT(node->shouldGenerate()); // It should not be on the worklist unless it's ref'ed. - DFG_NODE_DO_TO_CHILDREN(m_graph, node, countEdge); - } - - if (m_graph.m_form == SSA) { - // Find Phi->Upsilon edges, which are represented as meta-data in the - // Upsilon. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) + unsigned sourceIndex = 0; + unsigned targetIndex = 0; + while (sourceIndex < block->size()) { + Node* node = block->at(sourceIndex++); + switch (node->op()) { + case Check: + case Phantom: + if (node->children.isEmpty()) continue; - for (unsigned nodeIndex = block->size(); nodeIndex--;) { - Node* node = block->at(nodeIndex); - if (node->op() != Upsilon) - continue; - if (node->shouldGenerate()) - continue; - if (node->phi()->shouldGenerate()) - countNode(node); - } + break; + default: + break; } + block->at(targetIndex++) = node; } - } - - if (m_graph.m_form == SSA) { - Vector<BasicBlock*> depthFirst; - m_graph.getBlocksInDepthFirstOrder(depthFirst); - for (unsigned i = 0; i < depthFirst.size(); ++i) - fixupBlock(depthFirst[i]); - } else { - RELEASE_ASSERT(m_graph.m_form == ThreadedCPS); - - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) - fixupBlock(m_graph.block(blockIndex)); - - cleanVariables(m_graph.m_arguments); + block->resize(targetIndex); } m_graph.m_refCountState = ExactRefCount; @@ -125,51 +84,16 @@ public: } private: - void findTypeCheckRoot(Node*, Edge edge) - { - // We may have an "unproved" untyped use for code that is unreachable. The CFA - // will just not have gotten around to it. - if (edge.willNotHaveCheck()) - return; - if (!edge->postfixRef()) - m_worklist.append(edge.node()); - } - - void countNode(Node* node) - { - if (node->postfixRef()) - return; - m_worklist.append(node); - } - - void countEdge(Node*, Edge edge) - { - // Don't count edges that are already counted for their type checks. - if (edge.willHaveCheck()) - return; - countNode(edge.node()); - } - void fixupBlock(BasicBlock* block) { if (!block) return; - - switch (m_graph.m_form) { - case SSA: - break; - - case ThreadedCPS: { - // Clean up variable links for the block. We need to do this before the actual DCE - // because we need to see GetLocals, so we can bypass them in situations where the - // vars-at-tail point to a GetLocal, the GetLocal is dead, but the Phi it points - // to is alive. - + + if (m_graph.m_form == ThreadedCPS) { for (unsigned phiIndex = 0; phiIndex < block->phis.size(); ++phiIndex) { - if (!block->phis[phiIndex]->shouldGenerate()) { - // FIXME: We could actually free nodes here. Except that it probably - // doesn't matter, since we don't add any nodes after this phase. - // https://bugs.webkit.org/show_bug.cgi?id=126239 + Node* phi = block->phis[phiIndex]; + if (!phi->shouldGenerate()) { + m_graph.m_allocator.free(phi); block->phis[phiIndex--] = block->phis.last(); block->phis.removeLast(); } @@ -177,12 +101,6 @@ private: cleanVariables(block->variablesAtHead); cleanVariables(block->variablesAtTail); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - return; } // This has to be a forward loop because we are using the insertion set. @@ -191,62 +109,29 @@ private: if (node->shouldGenerate()) continue; - switch (node->op()) { - case MovHint: { - // Check if the child is dead. MovHint's child would only be a Phantom - // if we had just killed it. - if (node->child1()->op() == Phantom) { - node->setOpAndDefaultFlags(ZombieHint); - node->child1() = Edge(); - break; + if (node->flags() & NodeHasVarArgs) { + for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) { + Edge edge = m_graph.m_varArgChildren[childIdx]; + + if (!edge || edge.willNotHaveCheck()) + continue; + + m_insertionSet.insertNode(indexInBlock, SpecNone, Check, node->origin, edge); } - break; - } - case ZombieHint: { - // Currently we assume that DCE runs only once. - RELEASE_ASSERT_NOT_REACHED(); - break; + node->setOpAndDefaultFlags(Check); + node->children.reset(); + node->setRefCount(1); + continue; } - default: { - if (node->flags() & NodeHasVarArgs) { - for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) { - Edge edge = m_graph.m_varArgChildren[childIdx]; - - if (!edge || edge.willNotHaveCheck()) - continue; - - m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node->origin, edge); - } - - node->convertToPhantomUnchecked(); - node->children.reset(); - node->setRefCount(1); - break; - } - - node->convertToPhantom(); - eliminateIrrelevantPhantomChildren(node); - node->setRefCount(1); - break; - } } + node->remove(); + node->setRefCount(1); } m_insertionSet.execute(block); } - void eliminateIrrelevantPhantomChildren(Node* node) - { - for (unsigned i = 0; i < AdjacencyList::Size; ++i) { - Edge edge = node->children.child(i); - if (!edge) - continue; - if (edge.willNotHaveCheck()) - node->children.removeEdge(i--); - } - } - template<typename VariablesVectorType> void cleanVariables(VariablesVectorType& variables) { @@ -254,53 +139,12 @@ private: Node* node = variables[i]; if (!node) continue; - if (node->op() != Phantom && node->shouldGenerate()) + if (node->op() != Check && node->shouldGenerate()) continue; - if (node->op() == GetLocal) { - node = node->child1().node(); - - // FIXME: In the case that the variable is captured, we really want to be able - // to replace the variable-at-tail with the last use of the variable in the same - // way that CPS rethreading would do. The child of the GetLocal isn't necessarily - // the same as what CPS rethreading would do. For example, we may have: - // - // a: SetLocal(...) // live - // b: GetLocal(@a) // live - // c: GetLocal(@a) // dead - // - // When killing @c, the code below will set the variable-at-tail to @a, while CPS - // rethreading would have set @b. This is a benign bug, since all clients of CPS - // only use the variable-at-tail of captured variables to get the - // VariableAccessData and observe that it is in fact captured. But, this feels - // like it could cause bugs in the future. - // - // It's tempting to just dethread and then invoke CPS rethreading, but CPS - // rethreading fails to preserve exact ref-counts. So we would need a fixpoint. - // It's probably the case that this fixpoint will be guaranteed to converge after - // the second iteration (i.e. the second run of DCE will not kill anything and so - // will not need to dethread), but for now the safest approach is probably just to - // allow for this tiny bit of sloppiness. - // - // Another possible solution would be to simply say that DCE dethreads but then - // we never rethread before going to the backend. That feels intuitively right - // because it's unlikely that any of the phases after DCE in the backend rely on - // ThreadedCPS. - // - // https://bugs.webkit.org/show_bug.cgi?id=130115 - ASSERT( - node->op() == Phi || node->op() == SetArgument - || node->variableAccessData()->isCaptured()); - - if (node->shouldGenerate()) { - variables[i] = node; - continue; - } - } - variables[i] = 0; + variables[i] = nullptr; } } - Vector<Node*, 128> m_worklist; InsertionSet m_insertionSet; }; diff --git a/dfg/DFGDesiredIdentifiers.cpp b/dfg/DFGDesiredIdentifiers.cpp index dfa8faa..74e2468 100644 --- a/dfg/DFGDesiredIdentifiers.cpp +++ b/dfg/DFGDesiredIdentifiers.cpp @@ -52,14 +52,14 @@ unsigned DesiredIdentifiers::numberOfIdentifiers() return m_codeBlock->numberOfIdentifiers() + m_addedIdentifiers.size(); } -void DesiredIdentifiers::addLazily(StringImpl* rep) +void DesiredIdentifiers::addLazily(UniquedStringImpl* rep) { m_addedIdentifiers.append(rep); } -StringImpl* DesiredIdentifiers::at(unsigned index) const +UniquedStringImpl* DesiredIdentifiers::at(unsigned index) const { - StringImpl* result; + UniquedStringImpl* result; if (index < m_codeBlock->numberOfIdentifiers()) result = m_codeBlock->identifier(index).impl(); else @@ -71,9 +71,9 @@ StringImpl* DesiredIdentifiers::at(unsigned index) const void DesiredIdentifiers::reallyAdd(VM& vm, CommonData* commonData) { for (unsigned i = 0; i < m_addedIdentifiers.size(); ++i) { - StringImpl* rep = m_addedIdentifiers[i]; + auto rep = m_addedIdentifiers[i]; ASSERT(rep->hasAtLeastOneRef()); - commonData->dfgIdentifiers.append(Identifier(&vm, rep)); + commonData->dfgIdentifiers.append(Identifier::fromUid(&vm, rep)); } } diff --git a/dfg/DFGDesiredIdentifiers.h b/dfg/DFGDesiredIdentifiers.h index 10c2159..3a2a348 100644 --- a/dfg/DFGDesiredIdentifiers.h +++ b/dfg/DFGDesiredIdentifiers.h @@ -45,17 +45,17 @@ public: ~DesiredIdentifiers(); unsigned numberOfIdentifiers(); - void addLazily(StringImpl*); + void addLazily(UniquedStringImpl*); - StringImpl* at(unsigned index) const; + UniquedStringImpl* at(unsigned index) const; - StringImpl* operator[](unsigned index) const { return at(index); } + UniquedStringImpl* operator[](unsigned index) const { return at(index); } void reallyAdd(VM&, CommonData*); private: CodeBlock* m_codeBlock; - Vector<StringImpl*> m_addedIdentifiers; + Vector<UniquedStringImpl*> m_addedIdentifiers; }; } } // namespace JSC::DFG diff --git a/dfg/DFGDesiredWatchpoints.cpp b/dfg/DFGDesiredWatchpoints.cpp index a7704f4..7f5b01c 100644 --- a/dfg/DFGDesiredWatchpoints.cpp +++ b/dfg/DFGDesiredWatchpoints.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,6 +44,13 @@ void ArrayBufferViewWatchpointAdaptor::add( codeBlock->vm()->heap.addReference(neuteringWatchpoint, view->buffer()); } +void InferredValueAdaptor::add( + CodeBlock* codeBlock, InferredValue* inferredValue, Watchpoint* watchpoint) +{ + codeBlock->addConstant(inferredValue); // For common users, it doesn't really matter if it's weak or not. If references to it go away, we go away, too. + inferredValue->add(watchpoint); +} + DesiredWatchpoints::DesiredWatchpoints() { } DesiredWatchpoints::~DesiredWatchpoints() { } @@ -57,25 +64,29 @@ void DesiredWatchpoints::addLazily(InlineWatchpointSet& set) m_inlineSets.addLazily(&set); } -void DesiredWatchpoints::addLazily(JSArrayBufferView* view) +void DesiredWatchpoints::addLazily(InferredValue* inferredValue) { - m_bufferViews.addLazily(view); + m_inferredValues.addLazily(inferredValue); } -void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSet* set) +void DesiredWatchpoints::addLazily(JSArrayBufferView* view) { - m_sets.addLazily(codeOrigin, exitKind, set); + m_bufferViews.addLazily(view); } -void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, InlineWatchpointSet& set) +bool DesiredWatchpoints::consider(Structure* structure) { - m_inlineSets.addLazily(codeOrigin, exitKind, &set); + if (!structure->dfgShouldWatch()) + return false; + addLazily(structure->transitionWatchpointSet()); + return true; } void DesiredWatchpoints::reallyAdd(CodeBlock* codeBlock, CommonData& commonData) { m_sets.reallyAdd(codeBlock, commonData); m_inlineSets.reallyAdd(codeBlock, commonData); + m_inferredValues.reallyAdd(codeBlock, commonData); m_bufferViews.reallyAdd(codeBlock, commonData); } @@ -83,6 +94,7 @@ bool DesiredWatchpoints::areStillValid() const { return m_sets.areStillValid() && m_inlineSets.areStillValid() + && m_inferredValues.areStillValid() && m_bufferViews.areStillValid(); } diff --git a/dfg/DFGDesiredWatchpoints.h b/dfg/DFGDesiredWatchpoints.h index 3e07f9b..ce89a04 100644 --- a/dfg/DFGDesiredWatchpoints.h +++ b/dfg/DFGDesiredWatchpoints.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,7 @@ #include "CodeOrigin.h" #include "DFGCommonData.h" +#include "InferredValue.h" #include "JSArrayBufferView.h" #include "Watchpoint.h" #include <wtf/HashMap.h> @@ -39,26 +40,7 @@ namespace JSC { namespace DFG { -template<typename WatchpointSetType> -struct WatchpointForGenericWatchpointSet { - WatchpointForGenericWatchpointSet() - : m_exitKind(ExitKindUnset) - , m_set(0) - { - } - - WatchpointForGenericWatchpointSet( - CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set) - : m_codeOrigin(codeOrigin) - , m_exitKind(exitKind) - , m_set(set) - { - } - - CodeOrigin m_codeOrigin; - ExitKind m_exitKind; - WatchpointSetType* m_set; -}; +class Graph; template<typename T> struct GenericSetAdaptor { @@ -69,6 +51,14 @@ struct GenericSetAdaptor { static bool hasBeenInvalidated(T* set) { return set->hasBeenInvalidated(); } }; +struct InferredValueAdaptor { + static void add(CodeBlock*, InferredValue*, Watchpoint*); + static bool hasBeenInvalidated(InferredValue* inferredValue) + { + return inferredValue->hasBeenInvalidated(); + } +}; + struct ArrayBufferViewWatchpointAdaptor { static void add(CodeBlock*, JSArrayBufferView*, Watchpoint*); static bool hasBeenInvalidated(JSArrayBufferView* view) @@ -95,12 +85,6 @@ public: m_sets.add(set); } - void addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSetType* set) - { - m_profiledWatchpoints.append( - WatchpointForGenericWatchpointSet<WatchpointSetType>(codeOrigin, exitKind, set)); - } - void reallyAdd(CodeBlock* codeBlock, CommonData& common) { RELEASE_ASSERT(!m_reallyAdded); @@ -112,14 +96,6 @@ public: Adaptor::add(codeBlock, *iter, &common.watchpoints.last()); } - for (unsigned i = m_profiledWatchpoints.size(); i--;) { - WatchpointForGenericWatchpointSet<WatchpointSetType> watchpoint = - m_profiledWatchpoints[i]; - common.profiledWatchpoints.append( - ProfiledCodeBlockJettisoningWatchpoint(watchpoint.m_codeOrigin, watchpoint.m_exitKind, codeBlock)); - Adaptor::add(codeBlock, watchpoint.m_set, &common.profiledWatchpoints.last()); - } - m_reallyAdded = true; } @@ -132,53 +108,16 @@ public: return false; } - for (unsigned i = m_profiledWatchpoints.size(); i--;) { - if (Adaptor::hasBeenInvalidated(m_profiledWatchpoints[i].m_set)) - return false; - } - return true; } -#if ASSERT_DISABLED - bool isStillValid(WatchpointSetType* set) - { - return !Adaptor::hasBeenInvalidated(set); - } - - bool shouldAssumeMixedState(WatchpointSetType*) + bool isWatched(WatchpointSetType* set) const { - return true; - } -#else - bool isStillValid(WatchpointSetType* set) - { - bool result = !Adaptor::hasBeenInvalidated(set); - m_firstKnownState.add(set, result); - return result; - } - - bool shouldAssumeMixedState(WatchpointSetType* set) - { - typename StateMap::iterator iter = m_firstKnownState.find(set); - if (iter == m_firstKnownState.end()) - return false; - - return iter->value != !Adaptor::hasBeenInvalidated(set); - } -#endif - - bool isValidOrMixed(WatchpointSetType* set) - { - return isStillValid(set) || shouldAssumeMixedState(set); + return m_sets.contains(set); } private: - Vector<WatchpointForGenericWatchpointSet<WatchpointSetType>> m_profiledWatchpoints; HashSet<WatchpointSetType*> m_sets; -#if !ASSERT_DISABLED - StateMap m_firstKnownState; -#endif bool m_reallyAdded; }; @@ -189,54 +128,36 @@ public: void addLazily(WatchpointSet*); void addLazily(InlineWatchpointSet&); + void addLazily(InferredValue*); void addLazily(JSArrayBufferView*); - void addLazily(CodeOrigin, ExitKind, WatchpointSet*); - void addLazily(CodeOrigin, ExitKind, InlineWatchpointSet&); + + bool consider(Structure*); void reallyAdd(CodeBlock*, CommonData&); bool areStillValid() const; - bool isStillValid(WatchpointSet* set) - { - return m_sets.isStillValid(set); - } - bool isStillValid(InlineWatchpointSet& set) - { - return m_inlineSets.isStillValid(&set); - } - bool isStillValid(JSArrayBufferView* view) - { - return m_bufferViews.isStillValid(view); - } - bool shouldAssumeMixedState(WatchpointSet* set) - { - return m_sets.shouldAssumeMixedState(set); - } - bool shouldAssumeMixedState(InlineWatchpointSet& set) - { - return m_inlineSets.shouldAssumeMixedState(&set); - } - bool shouldAssumeMixedState(JSArrayBufferView* view) + bool isWatched(WatchpointSet* set) { - return m_bufferViews.shouldAssumeMixedState(view); + return m_sets.isWatched(set); } - bool isValidOrMixed(WatchpointSet* set) + bool isWatched(InlineWatchpointSet& set) { - return m_sets.isValidOrMixed(set); + return m_inlineSets.isWatched(&set); } - bool isValidOrMixed(InlineWatchpointSet& set) + bool isWatched(InferredValue* inferredValue) { - return m_inlineSets.isValidOrMixed(&set); + return m_inferredValues.isWatched(inferredValue); } - bool isValidOrMixed(JSArrayBufferView* view) + bool isWatched(JSArrayBufferView* view) { - return m_bufferViews.isValidOrMixed(view); + return m_bufferViews.isWatched(view); } private: GenericDesiredWatchpoints<WatchpointSet> m_sets; GenericDesiredWatchpoints<InlineWatchpointSet> m_inlineSets; + GenericDesiredWatchpoints<InferredValue, InferredValueAdaptor> m_inferredValues; GenericDesiredWatchpoints<JSArrayBufferView, ArrayBufferViewWatchpointAdaptor> m_bufferViews; }; diff --git a/dfg/DFGDesiredWeakReferences.cpp b/dfg/DFGDesiredWeakReferences.cpp index 1ee02ba..f14968c 100644 --- a/dfg/DFGDesiredWeakReferences.cpp +++ b/dfg/DFGDesiredWeakReferences.cpp @@ -50,21 +50,31 @@ DesiredWeakReferences::~DesiredWeakReferences() void DesiredWeakReferences::addLazily(JSCell* cell) { - m_references.append(cell); + m_references.add(cell); +} + +bool DesiredWeakReferences::contains(JSCell* cell) +{ + return m_references.contains(cell); } void DesiredWeakReferences::reallyAdd(VM& vm, CommonData* common) { - for (unsigned i = 0; i < m_references.size(); i++) { - JSCell* target = m_references[i]; - common->weakReferences.append(WriteBarrier<JSCell>(vm, m_codeBlock->ownerExecutable(), target)); + for (JSCell* target : m_references) { + if (Structure* structure = jsDynamicCast<Structure*>(target)) { + common->weakStructureReferences.append( + WriteBarrier<Structure>(vm, m_codeBlock->ownerExecutable(), structure)); + } else { + common->weakReferences.append( + WriteBarrier<JSCell>(vm, m_codeBlock->ownerExecutable(), target)); + } } } void DesiredWeakReferences::visitChildren(SlotVisitor& visitor) { - for (unsigned i = m_references.size(); i--;) - visitor.appendUnbarrieredPointer(&m_references[i]); + for (JSCell* target : m_references) + visitor.appendUnbarrieredPointer(&target); } } } // namespace JSC::DFG diff --git a/dfg/DFGDesiredWeakReferences.h b/dfg/DFGDesiredWeakReferences.h index 48ad44c..e312255 100644 --- a/dfg/DFGDesiredWeakReferences.h +++ b/dfg/DFGDesiredWeakReferences.h @@ -26,7 +26,7 @@ #ifndef DFGDesiredWeakReferences_h #define DFGDesiredWeakReferences_h -#include <wtf/Vector.h> +#include <wtf/HashSet.h> #if ENABLE(DFG_JIT) @@ -48,13 +48,15 @@ public: ~DesiredWeakReferences(); void addLazily(JSCell*); + bool contains(JSCell*); + void reallyAdd(VM&, CommonData*); void visitChildren(SlotVisitor&); private: CodeBlock* m_codeBlock; - Vector<JSCell*> m_references; + HashSet<JSCell*> m_references; }; } } // namespace JSC::DFG diff --git a/dfg/DFGDisassembler.cpp b/dfg/DFGDisassembler.cpp index 3176100..e221c4c 100644 --- a/dfg/DFGDisassembler.cpp +++ b/dfg/DFGDisassembler.cpp @@ -112,8 +112,6 @@ Vector<Disassembler::DumpedOp> Disassembler::createDumpList(LinkBuffer& linkBuff append(result, out, previousOrigin); Node* lastNodeForDisassembly = block->at(0); for (size_t i = 0; i < block->size(); ++i) { - if (!block->at(i)->willHaveCodeGenOrOSR() && !Options::showAllDFGNodes()) - continue; MacroAssembler::Label currentLabel; HashMap<Node*, MacroAssembler::Label>::iterator iter = m_labelForNode.find(block->at(i)); if (iter != m_labelForNode.end()) diff --git a/dfg/DFGDisassembler.h b/dfg/DFGDisassembler.h index 7844fc2..7b31946 100644 --- a/dfg/DFGDisassembler.h +++ b/dfg/DFGDisassembler.h @@ -28,6 +28,7 @@ #if ENABLE(DFG_JIT) +#include "CodeOrigin.h" #include "DFGCommon.h" #include "DumpContext.h" #include "MacroAssembler.h" diff --git a/dfg/DFGDoesGC.cpp b/dfg/DFGDoesGC.cpp new file mode 100644 index 0000000..5946840 --- /dev/null +++ b/dfg/DFGDoesGC.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGDoesGC.h" + +#if ENABLE(DFG_JIT) + +#include "DFGClobberize.h" +#include "DFGGraph.h" +#include "DFGNode.h" +#include "Operations.h" + +namespace JSC { namespace DFG { + +bool doesGC(Graph& graph, Node* node) +{ + if (clobbersHeap(graph, node)) + return true; + + // Now consider nodes that don't clobber the world but that still may GC. This includes all + // nodes. By convention we put world-clobbering nodes in the block of "false" cases but we can + // put them anywhere. + switch (node->op()) { + case JSConstant: + case DoubleConstant: + case Int52Constant: + case Identity: + case GetCallee: + case GetArgumentCount: + case GetLocal: + case SetLocal: + case MovHint: + case ZombieHint: + case Phantom: + case Upsilon: + case Phi: + case Flush: + case PhantomLocal: + case GetLocalUnlinked: + case SetArgument: + case BitAnd: + case BitOr: + case BitXor: + case BitLShift: + case BitRShift: + case BitURShift: + case ValueToInt32: + case UInt32ToNumber: + case DoubleAsInt32: + case ArithAdd: + case ArithClz32: + case ArithSub: + case ArithNegate: + case ArithMul: + case ArithIMul: + case ArithDiv: + case ArithMod: + case ArithAbs: + case ArithMin: + case ArithMax: + case ArithPow: + case ArithSqrt: + case ArithRound: + case ArithFRound: + case ArithSin: + case ArithCos: + case ArithLog: + case ValueAdd: + case GetById: + case GetByIdFlush: + case PutById: + case PutByIdFlush: + case PutByIdDirect: + case CheckStructure: + case GetExecutable: + case GetButterfly: + case CheckArray: + case GetScope: + case SkipScope: + case GetClosureVar: + case PutClosureVar: + case GetGlobalVar: + case PutGlobalVar: + case VarInjectionWatchpoint: + case CheckCell: + case CheckNotEmpty: + case RegExpExec: + case RegExpTest: + case CompareLess: + case CompareLessEq: + case CompareGreater: + case CompareGreaterEq: + case CompareEq: + case CompareEqConstant: + case CompareStrictEq: + case Call: + case Construct: + case CallVarargs: + case ConstructVarargs: + case LoadVarargs: + case CallForwardVarargs: + case ConstructForwardVarargs: + case NativeCall: + case NativeConstruct: + case Breakpoint: + case ProfileWillCall: + case ProfileDidCall: + case ProfileType: + case ProfileControlFlow: + case CheckHasInstance: + case InstanceOf: + case IsUndefined: + case IsBoolean: + case IsNumber: + case IsString: + case IsObject: + case IsObjectOrNull: + case IsFunction: + case TypeOf: + case LogicalNot: + case ToPrimitive: + case ToString: + case CallStringConstructor: + case In: + case Jump: + case Branch: + case Switch: + case Return: + case Throw: + case CountExecution: + case ForceOSRExit: + case CheckWatchdogTimer: + case StringFromCharCode: + case Unreachable: + case ExtractOSREntryLocal: + case CheckTierUpInLoop: + case CheckTierUpAtReturn: + case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: + case LoopHint: + case StoreBarrier: + case InvalidationPoint: + case NotifyWrite: + case CheckInBounds: + case ConstantStoragePointer: + case Check: + case MultiGetByOffset: + case ValueRep: + case DoubleRep: + case Int52Rep: + case GetGetter: + case GetSetter: + case GetByVal: + case GetIndexedPropertyStorage: + case GetArrayLength: + case ArrayPush: + case ArrayPop: + case StringCharAt: + case StringCharCodeAt: + case GetTypedArrayByteOffset: + case PutByValDirect: + case PutByVal: + case PutByValAlias: + case PutStructure: + case GetByOffset: + case GetGetterSetterByOffset: + case PutByOffset: + case GetEnumerableLength: + case HasGenericProperty: + case HasStructureProperty: + case HasIndexedProperty: + case GetDirectPname: + case FiatInt52: + case BooleanToNumber: + case CheckBadCell: + case BottomValue: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case GetMyArgumentByVal: + case ForwardVarargs: + case PutHint: + case CheckStructureImmediate: + case PutStack: + case KillStack: + case GetStack: + case GetFromArguments: + case PutToArguments: + return false; + + case CreateActivation: + case CreateDirectArguments: + case CreateScopedArguments: + case CreateClonedArguments: + case ToThis: + case CreateThis: + case AllocatePropertyStorage: + case ReallocatePropertyStorage: + case Arrayify: + case ArrayifyToStructure: + case NewObject: + case NewArray: + case NewArrayWithSize: + case NewArrayBuffer: + case NewRegexp: + case NewStringObject: + case MakeRope: + case NewFunction: + case NewTypedArray: + case ThrowReferenceError: + case GetPropertyEnumerator: + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: + case ToIndexString: + case MaterializeNewObject: + case MaterializeCreateActivation: + return true; + + case MultiPutByOffset: + return node->multiPutByOffsetData().reallocatesStorage(); + + case LastNodeType: + RELEASE_ASSERT_NOT_REACHED(); + return true; + } + + RELEASE_ASSERT_NOT_REACHED(); + return true; +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGDoesGC.h b/dfg/DFGDoesGC.h new file mode 100644 index 0000000..4503d21 --- /dev/null +++ b/dfg/DFGDoesGC.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 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 DFGDoesGC_h +#define DFGDoesGC_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; +struct Node; + +bool doesGC(Graph&, Node*); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGDoesGC_h + diff --git a/dfg/DFGDominators.cpp b/dfg/DFGDominators.cpp index bdd6a6a..4c67e8b 100644 --- a/dfg/DFGDominators.cpp +++ b/dfg/DFGDominators.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,10 @@ #if ENABLE(DFG_JIT) +#include "DFGBlockMapInlines.h" +#include "DFGBlockWorklist.h" #include "DFGGraph.h" +#include "DFGNaiveDominators.h" #include "JSCInlines.h" namespace JSC { namespace DFG { @@ -41,91 +44,429 @@ Dominators::~Dominators() { } -void Dominators::compute(Graph& graph) -{ - // This implements a naive dominator solver. +namespace { + +// This implements Lengauer and Tarjan's "A Fast Algorithm for Finding Dominators in a Flowgraph" +// (TOPLAS 1979). It uses the "simple" implementation of LINK and EVAL, which yields an O(n log n) +// solution. The full paper is linked below; this code attempts to closely follow the algorithm as +// it is presented in the paper; in particular sections 3 and 4 as well as appendix B. +// https://www.cs.princeton.edu/courses/archive/fall03/cs528/handouts/a%20fast%20algorithm%20for%20finding.pdf +// +// This code is very subtle. The Lengauer-Tarjan algorithm is incredibly deep to begin with. The +// goal of this code is to follow the code in the paper, however our implementation must deviate +// from the paper when it comes to recursion. The authors had used recursion to implement DFS, and +// also to implement the "simple" EVAL. We convert both of those into worklist-based solutions. +// Finally, once the algorithm gives us immediate dominators, we implement dominance tests by +// walking the dominator tree and computing pre and post numbers. We then use the range inclusion +// check trick that was first discovered by Paul F. Dietz in 1982 in "Maintaining order in a linked +// list" (see http://dl.acm.org/citation.cfm?id=802184). + +class LengauerTarjan { +public: + LengauerTarjan(Graph& graph) + : m_graph(graph) + , m_data(graph) + { + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + m_data[block].label = block; + } + } - ASSERT(graph.block(0)->predecessors.isEmpty()); + void compute() + { + computeDepthFirstPreNumbering(); // Step 1. + computeSemiDominatorsAndImplicitImmediateDominators(); // Steps 2 and 3. + computeExplicitImmediateDominators(); // Step 4. + } - unsigned numBlocks = graph.numBlocks(); + BasicBlock* immediateDominator(BasicBlock* block) + { + return m_data[block].dom; + } + +private: + void computeDepthFirstPreNumbering() + { + // Use a block worklist that also tracks the index inside the successor list. This is + // necessary for ensuring that we don't attempt to visit a successor until the previous + // successors that we had visited are fully processed. This ends up being revealed in the + // output of this method because the first time we see an edge to a block, we set the + // block's parent. So, if we have: + // + // A -> B + // A -> C + // B -> C + // + // And we're processing A, then we want to ensure that if we see A->B first (and hence set + // B's prenumber before we set C's) then we also end up setting C's parent to B by virtue + // of not noticing A->C until we're done processing B. + + ExtendedBlockWorklist<unsigned> worklist; + worklist.push(m_graph.block(0), 0); + + while (BlockWith<unsigned> item = worklist.pop()) { + BasicBlock* block = item.block; + unsigned successorIndex = item.data; + + // We initially push with successorIndex = 0 regardless of whether or not we have any + // successors. This is so that we can assign our prenumber. Subsequently we get pushed + // with higher successorIndex values, but only if they are in range. + ASSERT(!successorIndex || successorIndex < block->numSuccessors()); + + if (!successorIndex) { + m_data[block].semiNumber = m_blockByPreNumber.size(); + m_blockByPreNumber.append(block); + } + + if (successorIndex < block->numSuccessors()) { + unsigned nextSuccessorIndex = successorIndex + 1; + if (nextSuccessorIndex < block->numSuccessors()) + worklist.forcePush(block, nextSuccessorIndex); + + BasicBlock* successorBlock = block->successor(successorIndex); + if (worklist.push(successorBlock, 0)) + m_data[successorBlock].parent = block; + } + } + } - // Allocate storage for the dense dominance matrix. - if (numBlocks > m_results.size()) { - m_results.grow(numBlocks); - for (unsigned i = numBlocks; i--;) - m_results[i].resize(numBlocks); - m_scratch.resize(numBlocks); + void computeSemiDominatorsAndImplicitImmediateDominators() + { + for (unsigned currentPreNumber = m_blockByPreNumber.size(); currentPreNumber-- > 1;) { + BasicBlock* block = m_blockByPreNumber[currentPreNumber]; + BlockData& blockData = m_data[block]; + + // Step 2: + for (BasicBlock* predecessorBlock : block->predecessors) { + BasicBlock* intermediateBlock = eval(predecessorBlock); + blockData.semiNumber = std::min( + m_data[intermediateBlock].semiNumber, blockData.semiNumber); + } + unsigned bucketPreNumber = blockData.semiNumber; + ASSERT(bucketPreNumber <= currentPreNumber); + m_data[m_blockByPreNumber[bucketPreNumber]].bucket.append(block); + link(blockData.parent, block); + + // Step 3: + for (BasicBlock* semiDominee : m_data[blockData.parent].bucket) { + BasicBlock* possibleDominator = eval(semiDominee); + BlockData& semiDomineeData = m_data[semiDominee]; + ASSERT(m_blockByPreNumber[semiDomineeData.semiNumber] == blockData.parent); + BlockData& possibleDominatorData = m_data[possibleDominator]; + if (possibleDominatorData.semiNumber < semiDomineeData.semiNumber) + semiDomineeData.dom = possibleDominator; + else + semiDomineeData.dom = blockData.parent; + } + m_data[blockData.parent].bucket.clear(); + } + } + + void computeExplicitImmediateDominators() + { + for (unsigned currentPreNumber = 1; currentPreNumber < m_blockByPreNumber.size(); ++currentPreNumber) { + BasicBlock* block = m_blockByPreNumber[currentPreNumber]; + BlockData& blockData = m_data[block]; + + if (blockData.dom != m_blockByPreNumber[blockData.semiNumber]) + blockData.dom = m_data[blockData.dom].dom; + } + } + + void link(BasicBlock* from, BasicBlock* to) + { + m_data[to].ancestor = from; + } + + BasicBlock* eval(BasicBlock* block) + { + if (!m_data[block].ancestor) + return block; + + compress(block); + return m_data[block].label; + } + + void compress(BasicBlock* initialBlock) + { + // This was meant to be a recursive function, but we don't like recursion because we don't + // want to blow the stack. The original function will call compress() recursively on the + // ancestor of anything that has an ancestor. So, we populate our worklist with the + // recursive ancestors of initialBlock. Then we process the list starting from the block + // that is furthest up the ancestor chain. + + BasicBlock* ancestor = m_data[initialBlock].ancestor; + ASSERT(ancestor); + if (!m_data[ancestor].ancestor) + return; + + Vector<BasicBlock*, 16> stack; + for (BasicBlock* block = initialBlock; block; block = m_data[block].ancestor) + stack.append(block); + + // We only care about blocks that have an ancestor that has an ancestor. The last two + // elements in the stack won't satisfy this property. + ASSERT(stack.size() >= 2); + ASSERT(!m_data[stack[stack.size() - 1]].ancestor); + ASSERT(!m_data[m_data[stack[stack.size() - 2]].ancestor].ancestor); + + for (unsigned i = stack.size() - 2; i--;) { + BasicBlock* block = stack[i]; + BasicBlock*& labelOfBlock = m_data[block].label; + BasicBlock*& ancestorOfBlock = m_data[block].ancestor; + ASSERT(ancestorOfBlock); + ASSERT(m_data[ancestorOfBlock].ancestor); + + BasicBlock* labelOfAncestorOfBlock = m_data[ancestorOfBlock].label; + + if (m_data[labelOfAncestorOfBlock].semiNumber < m_data[labelOfBlock].semiNumber) + labelOfBlock = labelOfAncestorOfBlock; + ancestorOfBlock = m_data[ancestorOfBlock].ancestor; + } } - // We know that the entry block is only dominated by itself. - m_results[0].clearAll(); - m_results[0].set(0); + struct BlockData { + BlockData() + : parent(nullptr) + , preNumber(UINT_MAX) + , semiNumber(UINT_MAX) + , ancestor(nullptr) + , label(nullptr) + , dom(nullptr) + { + } + + BasicBlock* parent; + unsigned preNumber; + unsigned semiNumber; + BasicBlock* ancestor; + BasicBlock* label; + Vector<BasicBlock*> bucket; + BasicBlock* dom; + }; + + Graph& m_graph; + BlockMap<BlockData> m_data; + Vector<BasicBlock*> m_blockByPreNumber; +}; - // Find all of the valid blocks. - m_scratch.clearAll(); - for (unsigned i = numBlocks; i--;) { - if (!graph.block(i)) - continue; - m_scratch.set(i); +struct ValidationContext { + ValidationContext(Graph& graph, Dominators& dominators) + : graph(graph) + , dominators(dominators) + { } - // Mark all nodes as dominated by everything. - for (unsigned i = numBlocks; i-- > 1;) { - if (!graph.block(i) || graph.block(i)->predecessors.isEmpty()) - m_results[i].clearAll(); - else - m_results[i].set(m_scratch); + void reportError(BasicBlock* from, BasicBlock* to, const char* message) + { + Error error; + error.from = from; + error.to = to; + error.message = message; + errors.append(error); } + + void handleErrors() + { + if (errors.isEmpty()) + return; + + startCrashing(); + dataLog("DFG DOMINATOR VALIDATION FAILED:\n"); + dataLog("\n"); + dataLog("For block domination relationships:\n"); + for (unsigned i = 0; i < errors.size(); ++i) { + dataLog( + " ", pointerDump(errors[i].from), " -> ", pointerDump(errors[i].to), + " (", errors[i].message, ")\n"); + } + dataLog("\n"); + dataLog("Control flow graph:\n"); + for (BlockIndex blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) { + BasicBlock* block = graph.block(blockIndex); + if (!block) + continue; + dataLog(" Block #", blockIndex, ": successors = ["); + CommaPrinter comma; + for (unsigned i = 0; i < block->numSuccessors(); ++i) + dataLog(comma, *block->successor(i)); + dataLog("], predecessors = ["); + comma = CommaPrinter(); + for (unsigned i = 0; i < block->predecessors.size(); ++i) + dataLog(comma, *block->predecessors[i]); + dataLog("]\n"); + } + dataLog("\n"); + dataLog("Lengauer-Tarjan Dominators:\n"); + dataLog(dominators); + dataLog("\n"); + dataLog("Naive Dominators:\n"); + naiveDominators.dump(graph, WTF::dataFile()); + dataLog("\n"); + dataLog("Graph at time of failure:\n"); + graph.dump(); + dataLog("\n"); + dataLog("DFG DOMINATOR VALIDATION FAILIED!\n"); + CRASH(); + } + + Graph& graph; + Dominators& dominators; + NaiveDominators naiveDominators; + + struct Error { + BasicBlock* from; + BasicBlock* to; + const char* message; + }; + + Vector<Error> errors; +}; + +} // anonymous namespace - // Iteratively eliminate nodes that are not dominator. - bool changed; - do { - changed = false; - // Prune dominators in all non entry blocks: forward scan. - for (unsigned i = 1; i < numBlocks; ++i) - changed |= pruneDominators(graph, i); +void Dominators::compute(Graph& graph) +{ + LengauerTarjan lengauerTarjan(graph); + lengauerTarjan.compute(); - if (!changed) + m_data = BlockMap<BlockData>(graph); + + // From here we want to build a spanning tree with both upward and downward links and we want + // to do a search over this tree to compute pre and post numbers that can be used for dominance + // tests. + + for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) { + BasicBlock* block = graph.block(blockIndex); + if (!block) + continue; + + BasicBlock* idomBlock = lengauerTarjan.immediateDominator(block); + m_data[block].idomParent = idomBlock; + if (idomBlock) + m_data[idomBlock].idomKids.append(block); + } + + unsigned nextPreNumber = 0; + unsigned nextPostNumber = 0; + + // Plain stack-based worklist because we are guaranteed to see each block exactly once anyway. + Vector<BlockWithOrder> worklist; + worklist.append(BlockWithOrder(graph.block(0), PreOrder)); + while (!worklist.isEmpty()) { + BlockWithOrder item = worklist.takeLast(); + switch (item.order) { + case PreOrder: + m_data[item.block].preNumber = nextPreNumber++; + worklist.append(BlockWithOrder(item.block, PostOrder)); + for (BasicBlock* kid : m_data[item.block].idomKids) + worklist.append(BlockWithOrder(kid, PreOrder)); break; + case PostOrder: + m_data[item.block].postNumber = nextPostNumber++; + break; + } + } + + if (validationEnabled()) { + // Check our dominator calculation: + // 1) Check that our range-based ancestry test is the same as a naive ancestry test. + // 2) Check that our notion of who dominates whom is identical to a naive (not + // Lengauer-Tarjan) dominator calculation. + + ValidationContext context(graph, *this); + context.naiveDominators.compute(graph); + + for (BlockIndex fromBlockIndex = graph.numBlocks(); fromBlockIndex--;) { + BasicBlock* fromBlock = graph.block(fromBlockIndex); + if (!fromBlock || m_data[fromBlock].preNumber == UINT_MAX) + continue; + for (BlockIndex toBlockIndex = graph.numBlocks(); toBlockIndex--;) { + BasicBlock* toBlock = graph.block(toBlockIndex); + if (!toBlock || m_data[toBlock].preNumber == UINT_MAX) + continue; + + if (dominates(fromBlock, toBlock) != naiveDominates(fromBlock, toBlock)) + context.reportError(fromBlock, toBlock, "Range-based domination check is broken"); + if (dominates(fromBlock, toBlock) != context.naiveDominators.dominates(fromBlock, toBlock)) + context.reportError(fromBlock, toBlock, "Lengauer-Tarjan domination is broken"); + } + } + + context.handleErrors(); + } +} - // Prune dominators in all non entry blocks: backward scan. - changed = false; - for (unsigned i = numBlocks; i-- > 1;) - changed |= pruneDominators(graph, i); - } while (changed); +BlockSet Dominators::strictDominatorsOf(BasicBlock* to) const +{ + BlockSet result; + forAllStrictDominatorsOf(to, BlockAdder(result)); + return result; } -bool Dominators::pruneDominators(Graph& graph, BlockIndex idx) +BlockSet Dominators::dominatorsOf(BasicBlock* to) const { - BasicBlock* block = graph.block(idx); + BlockSet result; + forAllDominatorsOf(to, BlockAdder(result)); + return result; +} - if (!block || block->predecessors.isEmpty()) - return false; +BlockSet Dominators::blocksStrictlyDominatedBy(BasicBlock* from) const +{ + BlockSet result; + forAllBlocksStrictlyDominatedBy(from, BlockAdder(result)); + return result; +} - // Find the intersection of dom(preds). - m_scratch.set(m_results[block->predecessors[0]->index]); - for (unsigned j = block->predecessors.size(); j-- > 1;) - m_scratch.filter(m_results[block->predecessors[j]->index]); +BlockSet Dominators::blocksDominatedBy(BasicBlock* from) const +{ + BlockSet result; + forAllBlocksDominatedBy(from, BlockAdder(result)); + return result; +} - // The block is also dominated by itself. - m_scratch.set(idx); +BlockSet Dominators::dominanceFrontierOf(BasicBlock* from) const +{ + BlockSet result; + forAllBlocksInDominanceFrontierOfImpl(from, BlockAdder(result)); + return result; +} - return m_results[idx].setAndCheck(m_scratch); +BlockSet Dominators::iteratedDominanceFrontierOf(const BlockList& from) const +{ + BlockSet result; + forAllBlocksInIteratedDominanceFrontierOfImpl(from, BlockAdder(result)); + return result; } -void Dominators::dump(Graph& graph, PrintStream& out) const +bool Dominators::naiveDominates(BasicBlock* from, BasicBlock* to) const { - for (BlockIndex blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) { - BasicBlock* block = graph.block(blockIndex); - if (!block) + for (BasicBlock* block = to; block; block = m_data[block].idomParent) { + if (block == from) + return true; + } + return false; +} + +void Dominators::dump(PrintStream& out) const +{ + if (!isValid()) { + out.print(" Not Valid.\n"); + return; + } + + for (BlockIndex blockIndex = 0; blockIndex < m_data.size(); ++blockIndex) { + if (m_data[blockIndex].preNumber == UINT_MAX) continue; - out.print(" Block ", *block, ":"); - for (BlockIndex otherIndex = 0; otherIndex < graph.numBlocks(); ++otherIndex) { - if (!dominates(block->index, otherIndex)) - continue; - out.print(" #", otherIndex); - } - out.print("\n"); + + out.print(" Block #", blockIndex, ": idom = ", pointerDump(m_data[blockIndex].idomParent), ", idomKids = ["); + CommaPrinter comma; + for (unsigned i = 0; i < m_data[blockIndex].idomKids.size(); ++i) + out.print(comma, *m_data[blockIndex].idomKids[i]); + out.print("], pre/post = ", m_data[blockIndex].preNumber, "/", m_data[blockIndex].postNumber, "\n"); } } diff --git a/dfg/DFGDominators.h b/dfg/DFGDominators.h index e9dc5c7..e218ba7 100644 --- a/dfg/DFGDominators.h +++ b/dfg/DFGDominators.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,8 +30,9 @@ #include "DFGAnalysis.h" #include "DFGBasicBlock.h" +#include "DFGBlockMap.h" +#include "DFGBlockSet.h" #include "DFGCommon.h" -#include <wtf/FastBitVector.h> namespace JSC { namespace DFG { @@ -44,24 +45,173 @@ public: void compute(Graph&); - bool dominates(BlockIndex from, BlockIndex to) const + bool strictlyDominates(BasicBlock* from, BasicBlock* to) const { ASSERT(isValid()); - return m_results[to].get(from); + return m_data[to].preNumber > m_data[from].preNumber + && m_data[to].postNumber < m_data[from].postNumber; } bool dominates(BasicBlock* from, BasicBlock* to) const { - return dominates(from->index, to->index); + return from == to || strictlyDominates(from, to); } - void dump(Graph&, PrintStream&) const; + BasicBlock* immediateDominatorOf(BasicBlock* block) const + { + return m_data[block].idomParent; + } + + template<typename Functor> + void forAllStrictDominatorsOf(BasicBlock* to, const Functor& functor) const + { + for (BasicBlock* block = m_data[to].idomParent; block; block = m_data[block].idomParent) + functor(block); + } + + template<typename Functor> + void forAllDominatorsOf(BasicBlock* to, const Functor& functor) const + { + for (BasicBlock* block = to; block; block = m_data[block].idomParent) + functor(block); + } + + template<typename Functor> + void forAllBlocksStrictlyDominatedBy(BasicBlock* from, const Functor& functor) const + { + Vector<BasicBlock*, 16> worklist; + worklist.appendVector(m_data[from].idomKids); + while (!worklist.isEmpty()) { + BasicBlock* block = worklist.takeLast(); + functor(block); + worklist.appendVector(m_data[block].idomKids); + } + } + + template<typename Functor> + void forAllBlocksDominatedBy(BasicBlock* from, const Functor& functor) const + { + Vector<BasicBlock*, 16> worklist; + worklist.append(from); + while (!worklist.isEmpty()) { + BasicBlock* block = worklist.takeLast(); + functor(block); + worklist.appendVector(m_data[block].idomKids); + } + } + + BlockSet strictDominatorsOf(BasicBlock* to) const; + BlockSet dominatorsOf(BasicBlock* to) const; + BlockSet blocksStrictlyDominatedBy(BasicBlock* from) const; + BlockSet blocksDominatedBy(BasicBlock* from) const; + + template<typename Functor> + void forAllBlocksInDominanceFrontierOf( + BasicBlock* from, const Functor& functor) const + { + BlockSet set; + forAllBlocksInDominanceFrontierOfImpl( + from, + [&] (BasicBlock* block) { + if (set.add(block)) + functor(block); + }); + } + + BlockSet dominanceFrontierOf(BasicBlock* from) const; + + template<typename Functor> + void forAllBlocksInIteratedDominanceFrontierOf( + const BlockList& from, const Functor& functor) + { + forAllBlocksInPrunedIteratedDominanceFrontierOf( + from, + [&] (BasicBlock* block) -> bool { + functor(block); + return true; + }); + } + + // This is a close relative of forAllBlocksInIteratedDominanceFrontierOf(), which allows the + // given functor to return false to indicate that we don't wish to consider the given block. + // Useful for computing pruned SSA form. + template<typename Functor> + void forAllBlocksInPrunedIteratedDominanceFrontierOf( + const BlockList& from, const Functor& functor) + { + BlockSet set; + forAllBlocksInIteratedDominanceFrontierOfImpl( + from, + [&] (BasicBlock* block) -> bool { + if (!set.add(block)) + return false; + return functor(block); + }); + } + + BlockSet iteratedDominanceFrontierOf(const BlockList& from) const; + + void dump(PrintStream&) const; private: - bool pruneDominators(Graph&, BlockIndex); + bool naiveDominates(BasicBlock* from, BasicBlock* to) const; + + template<typename Functor> + void forAllBlocksInDominanceFrontierOfImpl( + BasicBlock* from, const Functor& functor) const + { + // Paraphrasing from http://en.wikipedia.org/wiki/Dominator_(graph_theory): + // "The dominance frontier of a block 'from' is the set of all blocks 'to' such that + // 'from' dominates an immediate predecessor of 'to', but 'from' does not strictly + // dominate 'to'." + // + // A useful corner case to remember: a block may be in its own dominance frontier if it has + // a loop edge to itself, since it dominates itself and so it dominates its own immediate + // predecessor, and a block never strictly dominates itself. + + forAllBlocksDominatedBy( + from, + [&] (BasicBlock* block) { + for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { + BasicBlock* to = block->successor(successorIndex); + if (!strictlyDominates(from, to)) + functor(to); + } + }); + } + + template<typename Functor> + void forAllBlocksInIteratedDominanceFrontierOfImpl( + const BlockList& from, const Functor& functor) const + { + BlockList worklist = from; + while (!worklist.isEmpty()) { + BasicBlock* block = worklist.takeLast(); + forAllBlocksInDominanceFrontierOfImpl( + block, + [&] (BasicBlock* otherBlock) { + if (functor(otherBlock)) + worklist.append(otherBlock); + }); + } + } + + struct BlockData { + BlockData() + : idomParent(nullptr) + , preNumber(UINT_MAX) + , postNumber(UINT_MAX) + { + } + + Vector<BasicBlock*> idomKids; + BasicBlock* idomParent; + + unsigned preNumber; + unsigned postNumber; + }; - Vector<FastBitVector> m_results; // For each block, the bitvector of blocks that dominate it. - FastBitVector m_scratch; // A temporary bitvector with bit for each block. We recycle this to save new/deletes. + BlockMap<BlockData> m_data; }; } } // namespace JSC::DFG diff --git a/dfg/DFGDriver.cpp b/dfg/DFGDriver.cpp index 30b4f38..5b83f69 100644 --- a/dfg/DFGDriver.cpp +++ b/dfg/DFGDriver.cpp @@ -30,6 +30,7 @@ #include "JSString.h" #include "CodeBlock.h" +#include "DFGFunctionWhitelist.h" #include "DFGJITCode.h" #include "DFGPlan.h" #include "DFGThunks.h" @@ -38,6 +39,7 @@ #include "JSCInlines.h" #include "Options.h" #include "SamplingTool.h" +#include "TypeProfilerLog.h" #include <wtf/Atomics.h> #if ENABLE(FTL_JIT) @@ -61,6 +63,10 @@ static CompilationResult compileImpl( { SamplingRegion samplingRegion("DFG Compilation (Driver)"); + if (!Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount()) + || !FunctionWhitelist::ensureGlobalWhitelist().contains(codeBlock)) + return CompilationFailed; + numCompilations++; ASSERT(codeBlock); @@ -78,23 +84,26 @@ static CompilationResult compileImpl( if (mode == DFGMode) { vm.getCTIStub(linkCallThunkGenerator); vm.getCTIStub(linkConstructThunkGenerator); - vm.getCTIStub(linkClosureCallThunkGenerator); + vm.getCTIStub(linkPolymorphicCallThunkGenerator); vm.getCTIStub(virtualCallThunkGenerator); vm.getCTIStub(virtualConstructThunkGenerator); } else { vm.getCTIStub(linkCallThatPreservesRegsThunkGenerator); vm.getCTIStub(linkConstructThatPreservesRegsThunkGenerator); - vm.getCTIStub(linkClosureCallThatPreservesRegsThunkGenerator); + vm.getCTIStub(linkPolymorphicCallThatPreservesRegsThunkGenerator); vm.getCTIStub(virtualCallThatPreservesRegsThunkGenerator); vm.getCTIStub(virtualConstructThatPreservesRegsThunkGenerator); } + if (vm.typeProfiler()) + vm.typeProfilerLog()->processLogEntries(ASCIILiteral("Preparing for DFG compilation.")); + RefPtr<Plan> plan = adoptRef( new Plan(codeBlock, profiledDFGCodeBlock, mode, osrEntryBytecodeIndex, mustHandleValues)); + plan->callback = callback; if (Options::enableConcurrentJIT()) { Worklist* worklist = ensureGlobalWorklistFor(mode); - plan->callback = callback; if (logCompilationChanges(mode)) dataLog("Deferring DFG compilation of ", *codeBlock, " with queue length ", worklist->queueLength(), ".\n"); worklist->enqueue(plan); diff --git a/dfg/DFGEdge.cpp b/dfg/DFGEdge.cpp index bf05f35..154401e 100644 --- a/dfg/DFGEdge.cpp +++ b/dfg/DFGEdge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,7 +36,7 @@ namespace JSC { namespace DFG { void Edge::dump(PrintStream& out) const { if (useKindUnchecked() != UntypedUse) { - if (needsCheck()) + if (!isProved()) out.print("Check:"); out.print(useKind(), ":"); } diff --git a/dfg/DFGEdge.h b/dfg/DFGEdge.h index 4ceda0c..7a05fab 100644 --- a/dfg/DFGEdge.h +++ b/dfg/DFGEdge.h @@ -115,10 +115,6 @@ public: { return proofStatus() == IsProved; } - bool needsCheck() const - { - return proofStatus() == NeedsCheck; - } bool willNotHaveCheck() const { @@ -205,13 +201,13 @@ private: ASSERT((shiftedValue >> shift()) == bitwise_cast<uintptr_t>(node)); ASSERT(useKind >= 0 && useKind < LastUseKind); ASSERT((static_cast<uintptr_t>(LastUseKind) << 2) <= (static_cast<uintptr_t>(2) << shift())); - return shiftedValue | (static_cast<uintptr_t>(useKind) << 2) | (DFG::doesKill(killStatus) << 1) | DFG::isProved(proofStatus); + return shiftedValue | (static_cast<uintptr_t>(useKind) << 2) | (DFG::doesKill(killStatus) << 1) | static_cast<uintptr_t>(DFG::isProved(proofStatus)); } #else static uintptr_t makeWord(UseKind useKind, ProofStatus proofStatus, KillStatus killStatus) { - return (static_cast<uintptr_t>(useKind) << 2) | (DFG::doesKill(killStatus) << 1) | DFG::isProved(proofStatus); + return (static_cast<uintptr_t>(useKind) << 2) | (DFG::doesKill(killStatus) << 1) | static_cast<uintptr_t>(DFG::isProved(proofStatus)); } Node* m_node; diff --git a/dfg/DFGEdgeDominates.h b/dfg/DFGEdgeDominates.h index 0af2e98..d95c79d 100644 --- a/dfg/DFGEdgeDominates.h +++ b/dfg/DFGEdgeDominates.h @@ -45,10 +45,10 @@ public: void operator()(Node*, Edge edge) { - bool result = m_graph.m_dominators.dominates(edge.node()->misc.owner, m_block); + bool result = m_graph.m_dominators.dominates(edge.node()->owner, m_block); if (verbose) { dataLog( - "Checking if ", edge, " in ", *edge.node()->misc.owner, + "Checking if ", edge, " in ", *edge.node()->owner, " dominates ", *m_block, ": ", result, "\n"); } m_result &= result; diff --git a/dfg/DFGEpoch.cpp b/dfg/DFGEpoch.cpp new file mode 100644 index 0000000..7da1deb --- /dev/null +++ b/dfg/DFGEpoch.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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 "DFGEpoch.h" + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +void Epoch::dump(PrintStream& out) const +{ + if (!*this) + out.print("none"); + else + out.print(m_epoch); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGEpoch.h b/dfg/DFGEpoch.h new file mode 100644 index 0000000..9865dd7 --- /dev/null +++ b/dfg/DFGEpoch.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2015 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 DFGEpoch_h +#define DFGEpoch_h + +#if ENABLE(DFG_JIT) + +#include <wtf/PrintStream.h> + +namespace JSC { namespace DFG { + +// Utility class for epoch-based analyses. + +class Epoch { +public: + Epoch() + : m_epoch(s_none) + { + } + + static Epoch fromUnsigned(unsigned value) + { + Epoch result; + result.m_epoch = value; + return result; + } + + unsigned toUnsigned() const + { + return m_epoch; + } + + static Epoch first() + { + Epoch result; + result.m_epoch = s_first; + return result; + } + + bool operator!() const + { + return m_epoch == s_none; + } + + Epoch next() const + { + Epoch result; + result.m_epoch = m_epoch + 1; + return result; + } + + void bump() + { + *this = next(); + } + + bool operator==(const Epoch& other) const + { + return m_epoch == other.m_epoch; + } + + bool operator!=(const Epoch& other) const + { + return !(*this == other); + } + + bool operator<(const Epoch& other) const + { + return m_epoch < other.m_epoch; + } + + bool operator>(const Epoch& other) const + { + return other < *this; + } + + bool operator<=(const Epoch& other) const + { + return !(*this > other); + } + + bool operator>=(const Epoch& other) const + { + return !(*this < other); + } + + void dump(PrintStream&) const; + +private: + static const unsigned s_none = 0; + static const unsigned s_first = 1; + + unsigned m_epoch; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGEpoch_h + diff --git a/dfg/DFGFiltrationResult.h b/dfg/DFGFiltrationResult.h index f51aecd..ad0bf4d 100644 --- a/dfg/DFGFiltrationResult.h +++ b/dfg/DFGFiltrationResult.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,8 +30,20 @@ namespace JSC { namespace DFG { +// Tells you if an operation that filters type (i.e. does a type check/speculation) will always +// exit. Formally, this means that the proven type of a value prior to the filter was not +// bottom (i.e. not "clear" or "SpecEmpty") but becomes bottom as a result of executing the +// filter. +// +// Note that per this definition, a filter will not return Contradiction if the node's proven +// type was already bottom. This is necessary because we have this yucky convention of using +// a proven type of bottom for nodes that don't hold JS values, like Phi nodes in ThreadedCPS +// and storage nodes. enum FiltrationResult { + // Means that this operation may not always exit. FiltrationOK, + + // Means taht this operation will always exit. Contradiction }; diff --git a/dfg/DFGFixupPhase.cpp b/dfg/DFGFixupPhase.cpp index 5223b59..1affa1a 100644 --- a/dfg/DFGFixupPhase.cpp +++ b/dfg/DFGFixupPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,12 +28,14 @@ #if ENABLE(DFG_JIT) +#include "ArrayPrototype.h" #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" #include "DFGPredictionPropagationPhase.h" #include "DFGVariableAccessDataDump.h" #include "JSCInlines.h" +#include "TypeLocation.h" namespace JSC { namespace DFG { @@ -66,7 +68,9 @@ public: for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) injectTypeConversionsInBlock(m_graph.block(blockIndex)); - + + m_graph.m_planStage = PlanStage::AfterFixup; + return true; } @@ -79,10 +83,8 @@ private: m_block = block; for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) { m_currentNode = block->at(m_indexInBlock); - addPhantomsIfNecessary(); fixupNode(m_currentNode); } - clearPhantomsAtEnd(); m_insertionSet.execute(block); } @@ -92,7 +94,7 @@ private: switch (op) { case SetLocal: { - // This gets handled by fixupSetLocalsInBlock(). + // This gets handled by fixupGetAndSetLocalsInBlock(). return; } @@ -116,6 +118,12 @@ private: node->child2().setUseKind(Int32Use); break; } + + case ArithClz32: { + fixIntConvertingEdge(node->child1()); + node->setArithMode(Arith::Unchecked); + break; + } case UInt32ToNumber: { fixIntConvertingEdge(node->child1()); @@ -133,14 +141,12 @@ private: case ValueAdd: { if (attemptToMakeIntegerAdd(node)) { node->setOp(ArithAdd); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); break; } if (Node::shouldSpeculateNumberOrBooleanExpectingDefined(node->child1().node(), node->child2().node())) { fixDoubleOrBooleanEdge(node->child1()); fixDoubleOrBooleanEdge(node->child2()); node->setOp(ArithAdd); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); node->setResult(NodeResultDouble); break; } @@ -243,7 +249,7 @@ private: case ArithMod: { if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInt32(FixupPass)) { - if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7s()) { + if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) { fixIntOrBooleanEdge(node->child1()); fixIntOrBooleanEdge(node->child2()); if (bytecodeCanTruncateInteger(node->arithNodeFlags())) @@ -259,12 +265,6 @@ private: fixDoubleOrBooleanEdge(node->child1()); fixDoubleOrBooleanEdge(node->child2()); - // But we have to make sure that everything is phantom'd until after the - // DoubleAsInt32 node, which occurs after the Div/Mod node that the conversions - // will be insered on. - addRequiredPhantom(node->child1().node()); - addRequiredPhantom(node->child2().node()); - // We don't need to do ref'ing on the children because we're stealing them from // the original division. Node* newDivision = m_insertionSet.insertNode( @@ -309,11 +309,47 @@ private: node->setResult(NodeResultDouble); break; } + + case ArithPow: { + node->setResult(NodeResultDouble); + if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) { + fixDoubleOrBooleanEdge(node->child1()); + fixIntOrBooleanEdge(node->child2()); + break; + } + + fixDoubleOrBooleanEdge(node->child1()); + fixDoubleOrBooleanEdge(node->child2()); + break; + } + + case ArithRound: { + if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(FixupPass)) { + fixIntOrBooleanEdge(node->child1()); + insertCheck<Int32Use>(m_indexInBlock, node->child1().node()); + node->convertToIdentity(); + break; + } + fixDoubleOrBooleanEdge(node->child1()); + + if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, FixupPass)) { + node->setResult(NodeResultInt32); + if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) + node->setArithRoundingMode(Arith::RoundingMode::Int32); + else + node->setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck); + } else { + node->setResult(NodeResultDouble); + node->setArithRoundingMode(Arith::RoundingMode::Double); + } + break; + } case ArithSqrt: case ArithFRound: case ArithSin: - case ArithCos: { + case ArithCos: + case ArithLog: { fixDoubleOrBooleanEdge(node->child1()); node->setResult(NodeResultDouble); break; @@ -333,14 +369,6 @@ private: break; } - case TypeOf: { - if (node->child1()->shouldSpeculateString()) - fixEdge<StringUse>(node->child1()); - else if (node->child1()->shouldSpeculateCell()) - fixEdge<CellUse>(node->child1()); - break; - } - case CompareEqConstant: { break; } @@ -354,26 +382,26 @@ private: && Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) { fixEdge<BooleanUse>(node->child1()); fixEdge<BooleanUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (Node::shouldSpeculateInt32OrBoolean(node->child1().node(), node->child2().node())) { fixIntOrBooleanEdge(node->child1()); fixIntOrBooleanEdge(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (enableInt52() && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) { fixEdge<Int52RepUse>(node->child1()); fixEdge<Int52RepUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (Node::shouldSpeculateNumberOrBoolean(node->child1().node(), node->child2().node())) { fixDoubleOrBooleanEdge(node->child1()); fixDoubleOrBooleanEdge(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (node->op() != CompareEq) @@ -381,31 +409,31 @@ private: if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) { fixEdge<StringIdentUse>(node->child1()); fixEdge<StringIdentUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) { fixEdge<StringUse>(node->child1()); fixEdge<StringUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) { fixEdge<ObjectUse>(node->child1()); fixEdge<ObjectUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) { fixEdge<ObjectUse>(node->child1()); fixEdge<ObjectOrOtherUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) { fixEdge<ObjectOrOtherUse>(node->child1()); fixEdge<ObjectUse>(node->child2()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } break; @@ -438,12 +466,26 @@ private: fixEdge<StringIdentUse>(node->child2()); break; } - if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && (GPRInfo::numberOfRegisters >= 7 || isFTL(m_graph.m_plan.mode))) { + if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) { fixEdge<StringUse>(node->child1()); fixEdge<StringUse>(node->child2()); break; } - if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) { + WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint(); + if (masqueradesAsUndefinedWatchpoint->isStillValid()) { + + if (node->child1()->shouldSpeculateObject()) { + m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint); + fixEdge<ObjectUse>(node->child1()); + break; + } + if (node->child2()->shouldSpeculateObject()) { + m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint); + fixEdge<ObjectUse>(node->child2()); + break; + } + + } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) { fixEdge<ObjectUse>(node->child1()); fixEdge<ObjectUse>(node->child2()); break; @@ -468,11 +510,11 @@ private: fixEdge<NotStringVarUse>(node->child1()); break; } - if (node->child1()->shouldSpeculateString() && (GPRInfo::numberOfRegisters >= 8 || isFTL(m_graph.m_plan.mode))) { + if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) { fixEdge<StringUse>(node->child1()); break; } - if (node->child2()->shouldSpeculateString() && (GPRInfo::numberOfRegisters >= 8 || isFTL(m_graph.m_plan.mode))) { + if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) { fixEdge<StringUse>(node->child2()); break; } @@ -494,23 +536,79 @@ private: } case GetByVal: { + if (!node->prediction()) { + m_insertionSet.insertNode( + m_indexInBlock, SpecNone, ForceOSRExit, node->origin); + } + node->setArrayMode( node->arrayMode().refine( m_graph, node, node->child1()->prediction(), node->child2()->prediction(), - SpecNone, node->flags())); + SpecNone)); blessArrayOperation(node->child1(), node->child2(), node->child3()); ArrayMode arrayMode = node->arrayMode(); switch (arrayMode.type()) { + case Array::Contiguous: case Array::Double: if (arrayMode.arrayClass() == Array::OriginalArray - && arrayMode.speculation() == Array::InBounds - && m_graph.globalObjectFor(node->origin.semantic)->arrayPrototypeChainIsSane() - && !(node->flags() & NodeBytecodeUsesAsOther)) - node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain)); + && arrayMode.speculation() == Array::InBounds) { + JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); + if (globalObject->arrayPrototypeChainIsSane()) { + // Check if SaneChain will work on a per-type basis. Note that: + // + // 1) We don't want double arrays to sometimes return undefined, since + // that would require a change to the return type and it would pessimise + // things a lot. So, we'd only want to do that if we actually had + // evidence that we could read from a hole. That's pretty annoying. + // Likely the best way to handle that case is with an equivalent of + // SaneChain for OutOfBounds. For now we just detect when Undefined and + // NaN are indistinguishable according to backwards propagation, and just + // use SaneChain in that case. This happens to catch a lot of cases. + // + // 2) We don't want int32 array loads to have to do a hole check just to + // coerce to Undefined, since that would mean twice the checks. + // + // This has two implications. First, we have to do more checks than we'd + // like. It's unfortunate that we have to do the hole check. Second, + // some accesses that hit a hole will now need to take the full-blown + // out-of-bounds slow path. We can fix that with: + // https://bugs.webkit.org/show_bug.cgi?id=144668 + + bool canDoSaneChain = false; + switch (arrayMode.type()) { + case Array::Contiguous: + // This is happens to be entirely natural. We already would have + // returned any JSValue, and now we'll return Undefined. We still do + // the check but it doesn't require taking any kind of slow path. + canDoSaneChain = true; + break; + + case Array::Double: + if (!(node->flags() & NodeBytecodeUsesAsOther)) { + // Holes look like NaN already, so if the user doesn't care + // about the difference between Undefined and NaN then we can + // do this. + canDoSaneChain = true; + } + break; + + default: + break; + } + + if (canDoSaneChain) { + m_graph.watchpoints().addLazily( + globalObject->arrayPrototype()->structure()->transitionWatchpointSet()); + m_graph.watchpoints().addLazily( + globalObject->objectPrototype()->structure()->transitionWatchpointSet()); + node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain)); + } + } + } break; case Array::String: @@ -636,10 +734,9 @@ private: case Array::Contiguous: case Array::ArrayStorage: case Array::SlowPutArrayStorage: - case Array::Arguments: fixEdge<KnownCellUse>(child1); fixEdge<Int32Use>(child2); - insertStoreBarrier(m_indexInBlock, child1); + speculateForBarrier(child3); break; default: fixEdge<KnownCellUse>(child1); @@ -677,7 +774,7 @@ private: break; case Array::Contiguous: case Array::ArrayStorage: - insertStoreBarrier(m_indexInBlock, node->child1()); + speculateForBarrier(node->child2()); break; default: break; @@ -703,46 +800,12 @@ private: fixEdge<BooleanUse>(node->child1()); else if (node->child1()->shouldSpeculateObjectOrOther()) fixEdge<ObjectOrOtherUse>(node->child1()); - // FIXME: We should just be able to do shouldSpeculateInt32OrBoolean() and - // shouldSpeculateNumberOrBoolean() here, but we can't because then the Branch - // could speculate on the result of a non-speculative conversion node. - // https://bugs.webkit.org/show_bug.cgi?id=126778 - else if (node->child1()->shouldSpeculateInt32()) - fixEdge<Int32Use>(node->child1()); + else if (node->child1()->shouldSpeculateInt32OrBoolean()) + fixIntOrBooleanEdge(node->child1()); else if (node->child1()->shouldSpeculateNumber()) fixEdge<DoubleRepUse>(node->child1()); - - Node* logicalNot = node->child1().node(); - if (logicalNot->op() == LogicalNot) { - - // Make sure that OSR exit can't observe the LogicalNot. If it can, - // then we must compute it and cannot peephole around it. - bool found = false; - bool ok = true; - for (unsigned i = m_indexInBlock; i--;) { - Node* candidate = m_block->at(i); - if (candidate == logicalNot) { - found = true; - break; - } - if (candidate->canExit()) { - ok = false; - found = true; - break; - } - } - ASSERT_UNUSED(found, found); - - if (ok) { - Edge newChildEdge = logicalNot->child1(); - if (newChildEdge->hasBooleanResult()) { - node->children.setChild1(newChildEdge); - - BranchData* data = node->branchData(); - std::swap(data->taken, data->notTaken); - } - } - } + else if (node->child1()->shouldSpeculateString()) + fixEdge<StringUse>(node->child1()); break; } @@ -763,6 +826,12 @@ private: else if (node->child1()->shouldSpeculateString()) fixEdge<StringUse>(node->child1()); break; + case SwitchCell: + if (node->child1()->shouldSpeculateCell()) + fixEdge<CellUse>(node->child1()); + // else it's fine for this to have UntypedUse; we will handle this by just making + // non-cells take the default case. + break; } break; } @@ -772,8 +841,9 @@ private: break; } - case ToString: { - fixupToString(node); + case ToString: + case CallStringConstructor: { + fixupToStringOrCallStringConstructor(node); break; } @@ -822,7 +892,7 @@ private: case NewTypedArray: { if (node->child1()->shouldSpeculateInt32()) { fixEdge<Int32Use>(node->child1()); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); break; } break; @@ -844,10 +914,11 @@ private: } m_insertionSet.insertNode( - m_indexInBlock, SpecNone, Phantom, node->origin, + m_indexInBlock, SpecNone, Check, node->origin, Edge(node->child1().node(), OtherUse)); observeUseKindOnNode<OtherUse>(node->child1().node()); - node->convertToWeakConstant(m_graph.globalThisObjectFor(node->origin.semantic)); + m_graph.convertToConstant( + node, m_graph.globalThisObjectFor(node->origin.semantic)); break; } @@ -860,28 +931,28 @@ private: break; } - case GetMyArgumentByVal: - case GetMyArgumentByValSafe: { - fixEdge<Int32Use>(node->child1()); + case PutStructure: { + fixEdge<KnownCellUse>(node->child1()); break; } - case PutStructure: { + case GetClosureVar: + case GetFromArguments: { fixEdge<KnownCellUse>(node->child1()); - insertStoreBarrier(m_indexInBlock, node->child1()); break; } - case PutClosureVar: { + case PutClosureVar: + case PutToArguments: { fixEdge<KnownCellUse>(node->child1()); - insertStoreBarrier(m_indexInBlock, node->child1()); + speculateForBarrier(node->child2()); break; } - - case GetClosureRegisters: - case SkipTopScope: + case SkipScope: - case GetScope: { + case GetScope: + case GetGetter: + case GetSetter: { fixEdge<KnownCellUse>(node->child1()); break; } @@ -889,7 +960,6 @@ private: case AllocatePropertyStorage: case ReallocatePropertyStorage: { fixEdge<KnownCellUse>(node->child1()); - insertStoreBarrier(m_indexInBlock + 1, node->child1()); break; } @@ -897,18 +967,25 @@ private: case GetByIdFlush: { if (!node->child1()->shouldSpeculateCell()) break; - StringImpl* impl = m_graph.identifiers()[node->identifierNumber()]; - if (impl == vm().propertyNames->length.impl()) { - attemptToMakeGetArrayLength(node); - break; - } - if (impl == vm().propertyNames->byteLength.impl()) { - attemptToMakeGetTypedArrayByteLength(node); - break; - } - if (impl == vm().propertyNames->byteOffset.impl()) { - attemptToMakeGetTypedArrayByteOffset(node); - break; + + // If we hadn't exited because of BadCache, BadIndexingType, or ExoticObjectMode, then + // leave this as a GetById. + if (!m_graph.hasExitSite(node->origin.semantic, BadCache) + && !m_graph.hasExitSite(node->origin.semantic, BadIndexingType) + && !m_graph.hasExitSite(node->origin.semantic, ExoticObjectMode)) { + auto uid = m_graph.identifiers()[node->identifierNumber()]; + if (uid == vm().propertyNames->length.impl()) { + attemptToMakeGetArrayLength(node); + break; + } + if (uid == vm().propertyNames->byteLength.impl()) { + attemptToMakeGetTypedArrayByteLength(node); + break; + } + if (uid == vm().propertyNames->byteOffset.impl()) { + attemptToMakeGetTypedArrayByteOffset(node); + break; + } } fixEdge<CellUse>(node->child1()); break; @@ -918,14 +995,17 @@ private: case PutByIdFlush: case PutByIdDirect: { fixEdge<CellUse>(node->child1()); - insertStoreBarrier(m_indexInBlock, node->child1()); + speculateForBarrier(node->child2()); break; } - case CheckExecutable: + case GetExecutable: { + fixEdge<FunctionUse>(node->child1()); + break; + } + case CheckStructure: - case StructureTransitionWatchpoint: - case CheckFunction: + case CheckCell: case CheckHasInstance: case CreateThis: case GetButterfly: { @@ -941,7 +1021,8 @@ private: break; } - case GetByOffset: { + case GetByOffset: + case GetGetterSetterByOffset: { if (!node->child1()->hasStorageResult()) fixEdge<KnownCellUse>(node->child1()); fixEdge<KnownCellUse>(node->child2()); @@ -957,13 +1038,13 @@ private: if (!node->child1()->hasStorageResult()) fixEdge<KnownCellUse>(node->child1()); fixEdge<KnownCellUse>(node->child2()); - insertStoreBarrier(m_indexInBlock, node->child2()); + speculateForBarrier(node->child3()); break; } case MultiPutByOffset: { fixEdge<CellUse>(node->child1()); - insertStoreBarrier(m_indexInBlock, node->child1()); + speculateForBarrier(node->child2()); break; } @@ -982,20 +1063,28 @@ private: break; } - case Phantom: case Check: { - switch (node->child1().useKind()) { - case NumberUse: - if (node->child1()->shouldSpeculateInt32ForArithmetic()) - node->child1().setUseKind(Int32Use); - break; - default: - break; - } - observeUseKindOnEdge(node->child1()); + m_graph.doToChildren( + node, + [&] (Edge& edge) { + switch (edge.useKind()) { + case NumberUse: + if (edge->shouldSpeculateInt32ForArithmetic()) + edge.setUseKind(Int32Use); + break; + default: + break; + } + observeUseKindOnEdge(edge); + }); break; } + case Phantom: + // Phantoms are meaningless past Fixup. We recreate them on-demand in the backend. + node->remove(); + break; + case FiatInt52: { RELEASE_ASSERT(enableInt52()); node->convertToIdentity(); @@ -1007,82 +1096,197 @@ private: case GetArrayLength: case Phi: case Upsilon: - case GetArgument: - case PhantomPutStructure: case GetIndexedPropertyStorage: case GetTypedArrayByteOffset: case LastNodeType: case CheckTierUpInLoop: case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: case InvalidationPoint: case CheckArray: case CheckInBounds: case ConstantStoragePointer: case DoubleAsInt32: case ValueToInt32: - case HardPhantom: // HardPhantom would be trivial to handle but anyway we assert that we won't see it here yet. case DoubleRep: case ValueRep: case Int52Rep: - case DoubleConstant: case Int52Constant: case Identity: // This should have been cleaned up. case BooleanToNumber: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case ForwardVarargs: + case GetMyArgumentByVal: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PutStack: + case KillStack: + case GetStack: + case StoreBarrier: // These are just nodes that we don't currently expect to see during fixup. // If we ever wanted to insert them prior to fixup, then we just have to create // fixup rules for them. - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_graph, node, "Unexpected node during fixup"); break; case PutGlobalVar: { - Node* globalObjectNode = m_insertionSet.insertNode( - m_indexInBlock, SpecNone, WeakJSConstant, node->origin, - OpInfo(m_graph.globalObjectFor(node->origin.semantic))); - Node* barrierNode = m_graph.addNode( - SpecNone, StoreBarrier, m_currentNode->origin, - Edge(globalObjectNode, KnownCellUse)); - m_insertionSet.insert(m_indexInBlock, barrierNode); - break; - } - - case TearOffActivation: { - Node* barrierNode = m_graph.addNode( - SpecNone, StoreBarrierWithNullCheck, m_currentNode->origin, - Edge(node->child1().node(), UntypedUse)); - m_insertionSet.insert(m_indexInBlock, barrierNode); + fixEdge<CellUse>(node->child1()); + speculateForBarrier(node->child2()); break; } case IsString: if (node->child1()->shouldSpeculateString()) { m_insertionSet.insertNode( - m_indexInBlock, SpecNone, Phantom, node->origin, + m_indexInBlock, SpecNone, Check, node->origin, Edge(node->child1().node(), StringUse)); m_graph.convertToConstant(node, jsBoolean(true)); observeUseKindOnNode<StringUse>(node); } break; + + case IsObject: + if (node->child1()->shouldSpeculateObject()) { + m_insertionSet.insertNode( + m_indexInBlock, SpecNone, Check, node->origin, + Edge(node->child1().node(), ObjectUse)); + m_graph.convertToConstant(node, jsBoolean(true)); + observeUseKindOnNode<ObjectUse>(node); + } + break; + + case GetEnumerableLength: { + fixEdge<CellUse>(node->child1()); + break; + } + case HasGenericProperty: { + fixEdge<CellUse>(node->child2()); + break; + } + case HasStructureProperty: { + fixEdge<StringUse>(node->child2()); + fixEdge<KnownCellUse>(node->child3()); + break; + } + case HasIndexedProperty: { + node->setArrayMode( + node->arrayMode().refine( + m_graph, node, + node->child1()->prediction(), + node->child2()->prediction(), + SpecNone)); + + blessArrayOperation(node->child1(), node->child2(), node->child3()); + fixEdge<CellUse>(node->child1()); + fixEdge<KnownInt32Use>(node->child2()); + break; + } + case GetDirectPname: { + Edge& base = m_graph.varArgChild(node, 0); + Edge& property = m_graph.varArgChild(node, 1); + Edge& index = m_graph.varArgChild(node, 2); + Edge& enumerator = m_graph.varArgChild(node, 3); + fixEdge<CellUse>(base); + fixEdge<KnownCellUse>(property); + fixEdge<KnownInt32Use>(index); + fixEdge<KnownCellUse>(enumerator); + break; + } + case GetPropertyEnumerator: { + fixEdge<CellUse>(node->child1()); + break; + } + case GetEnumeratorStructurePname: { + fixEdge<KnownCellUse>(node->child1()); + fixEdge<KnownInt32Use>(node->child2()); + break; + } + case GetEnumeratorGenericPname: { + fixEdge<KnownCellUse>(node->child1()); + fixEdge<KnownInt32Use>(node->child2()); + break; + } + case ToIndexString: { + fixEdge<KnownInt32Use>(node->child1()); + break; + } + case ProfileType: { + // We want to insert type checks based on the instructionTypeSet of the TypeLocation, not the globalTypeSet. + // Because the instructionTypeSet is contained in globalTypeSet, if we produce a type check for + // type T for the instructionTypeSet, the global type set must also have information for type T. + // So if it the type check succeeds for type T in the instructionTypeSet, a type check for type T + // in the globalTypeSet would've also succeeded. + // (The other direction does not hold in general). + + RefPtr<TypeSet> typeSet = node->typeLocation()->m_instructionTypeSet; + RuntimeTypeMask seenTypes = typeSet->seenTypes(); + if (typeSet->doesTypeConformTo(TypeMachineInt)) { + if (node->child1()->shouldSpeculateInt32()) + fixEdge<Int32Use>(node->child1()); + else + fixEdge<MachineIntUse>(node->child1()); + node->remove(); + } else if (typeSet->doesTypeConformTo(TypeNumber | TypeMachineInt)) { + fixEdge<NumberUse>(node->child1()); + node->remove(); + } else if (typeSet->doesTypeConformTo(TypeString)) { + fixEdge<StringUse>(node->child1()); + node->remove(); + } else if (typeSet->doesTypeConformTo(TypeBoolean)) { + fixEdge<BooleanUse>(node->child1()); + node->remove(); + } else if (typeSet->doesTypeConformTo(TypeUndefined | TypeNull) && (seenTypes & TypeUndefined) && (seenTypes & TypeNull)) { + fixEdge<OtherUse>(node->child1()); + node->remove(); + } else if (typeSet->doesTypeConformTo(TypeObject)) { + StructureSet set = typeSet->structureSet(); + if (!set.isEmpty()) { + fixEdge<CellUse>(node->child1()); + node->convertToCheckStructure(m_graph.addStructureSet(set)); + } + } + + break; + } + + case CreateScopedArguments: + case CreateActivation: + case NewFunction: { + fixEdge<CellUse>(node->child1()); + break; + } #if !ASSERT_DISABLED // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes. case SetArgument: case JSConstant: - case WeakJSConstant: + case DoubleConstant: case GetLocal: case GetCallee: + case GetArgumentCount: case Flush: case PhantomLocal: case GetLocalUnlinked: - case GetMyScope: - case GetClosureVar: case GetGlobalVar: case NotifyWrite: - case VariableWatchpoint: case VarInjectionWatchpoint: - case AllocationProfileWatchpoint: case Call: case Construct: + case CallVarargs: + case ConstructVarargs: + case CallForwardVarargs: + case ConstructForwardVarargs: + case LoadVarargs: + case ProfileControlFlow: + case NativeCall: + case NativeConstruct: case NewObject: case NewArrayBuffer: case NewRegexp: @@ -1092,34 +1296,26 @@ private: case IsUndefined: case IsBoolean: case IsNumber: - case IsObject: + case IsObjectOrNull: case IsFunction: - case CreateActivation: - case CreateArguments: - case PhantomArguments: - case TearOffArguments: - case GetMyArgumentsLength: - case GetMyArgumentsLengthSafe: - case CheckArgumentsNotCreated: - case NewFunction: - case NewFunctionNoCheck: - case NewFunctionExpression: + case CreateDirectArguments: + case CreateClonedArguments: case Jump: case Return: case Throw: case ThrowReferenceError: case CountExecution: case ForceOSRExit: + case CheckBadCell: + case CheckNotEmpty: case CheckWatchdogTimer: case Unreachable: case ExtractOSREntryLocal: case LoopHint: - case StoreBarrier: - case StoreBarrierWithNullCheck: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: case MovHint: case ZombieHint: + case BottomValue: + case TypeOf: break; #else default: @@ -1169,7 +1365,7 @@ private: // decision process much easier. observeUseKindOnNode<StringUse>(edge.node()); m_insertionSet.insertNode( - m_indexInBlock, SpecNone, Phantom, node->origin, + m_indexInBlock, SpecNone, Check, node->origin, Edge(edge.node(), StringUse)); edge.setUseKind(KnownStringUse); return; @@ -1194,9 +1390,9 @@ private: if (!edge) break; edge.setUseKind(KnownStringUse); - if (!m_graph.isConstant(edge.node())) + JSString* string = edge->dynamicCastConstant<JSString*>(); + if (!string) continue; - JSString* string = jsCast<JSString*>(m_graph.valueOfJSConstant(edge.node()).asCell()); if (string->length()) continue; @@ -1242,7 +1438,7 @@ private: } } - void fixupToString(Node* node) + void fixupToStringOrCallStringConstructor(Node* node) { if (node->child1()->shouldSpeculateString()) { fixEdge<StringUse>(node->child1()); @@ -1271,9 +1467,6 @@ private: template<UseKind leftUseKind> bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right) { - Node* originalLeft = left.node(); - Node* originalRight = right.node(); - ASSERT(leftUseKind == StringUse || leftUseKind == StringObjectUse || leftUseKind == StringOrStringObjectUse); if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->origin.semantic)) @@ -1303,37 +1496,37 @@ private: m_indexInBlock, SpecString, ToString, node->origin, Edge(toPrimitive)); fixupToPrimitive(toPrimitive); - fixupToString(toString); - + + // Don't fix up ToString. ToString and ToPrimitive are originated from the same bytecode and + // ToPrimitive may have an observable side effect. ToString should not be converted into Check + // with speculative type check because OSR exit reproduce an observable side effect done in + // ToPrimitive. + right.setNode(toString); } - // We're doing checks up there, so we need to make sure that the - // *original* inputs to the addition are live up to here. - m_insertionSet.insertNode( - m_indexInBlock, SpecNone, Phantom, node->origin, - Edge(originalLeft), Edge(originalRight)); - convertToMakeRope(node); return true; } - bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, StringImpl* uid) + bool isStringPrototypeMethodSane( + JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl* uid) { unsigned attributesUnused; - JSCell* specificValue; - PropertyOffset offset = stringPrototypeStructure->getConcurrently( - vm(), uid, attributesUnused, specificValue); + PropertyOffset offset = + stringPrototypeStructure->getConcurrently(uid, attributesUnused); if (!isValidOffset(offset)) return false; - if (!specificValue) + JSValue value = m_graph.tryGetConstantProperty( + stringPrototype, stringPrototypeStructure, offset); + if (!value) return false; - if (!specificValue->inherits(JSFunction::info())) + JSFunction* function = jsDynamicCast<JSFunction*>(value); + if (!function) return false; - JSFunction* function = jsCast<JSFunction*>(specificValue); if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic) return false; @@ -1351,7 +1544,7 @@ private: JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype()); Structure* stringPrototypeStructure = stringPrototypeObject->structure(); - if (!m_graph.watchpoints().isStillValid(stringPrototypeStructure->transitionWatchpointSet())) + if (m_graph.registerStructure(stringPrototypeStructure) != StructureRegisteredAndWatched) return false; if (stringPrototypeStructure->isDictionary()) @@ -1362,9 +1555,9 @@ private: // (that would call toString()). We don't want the DFG to have to distinguish // between the two, just because that seems like it would get confusing. So we // just require both methods to be sane. - if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->valueOf.impl())) + if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->valueOf.impl())) return false; - if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->toString.impl())) + if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->toString.impl())) return false; return true; @@ -1435,12 +1628,14 @@ private: if (arrayMode.type() == Array::String) { m_insertionSet.insertNode( - m_indexInBlock, SpecNone, Phantom, origin, Edge(array, StringUse)); + m_indexInBlock, SpecNone, Check, origin, Edge(array, StringUse)); } else { + // Note that we only need to be using a structure check if we opt for SaneChain, since + // that needs to protect against JSArray's __proto__ being changed. Structure* structure = arrayMode.originalArrayStructure(m_graph, origin.semantic); Edge indexEdge = index ? Edge(index, Int32Use) : Edge(); - + if (arrayMode.doesConversion()) { if (structure) { m_insertionSet.insertNode( @@ -1546,6 +1741,7 @@ private: m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true); break; case NumberUse: + case RealNumberUse: case DoubleRepUse: case DoubleRepRealUse: if (variable->doubleFormatState() == UsingDoubleFormat) @@ -1563,6 +1759,7 @@ private: case CellUse: case KnownCellUse: case ObjectUse: + case FunctionUse: case StringUse: case KnownStringUse: case StringObjectUse: @@ -1583,10 +1780,44 @@ private: edge.setUseKind(useKind); } - void insertStoreBarrier(unsigned indexInBlock, Edge child1) + void speculateForBarrier(Edge value) { - Node* barrierNode = m_graph.addNode(SpecNone, StoreBarrier, m_currentNode->origin, child1); - m_insertionSet.insert(indexInBlock, barrierNode); + // Currently, the DFG won't take advantage of this speculation. But, we want to do it in + // the DFG anyway because if such a speculation would be wrong, we want to know before + // we do an expensive compile. + + if (value->shouldSpeculateInt32()) { + insertCheck<Int32Use>(m_indexInBlock, value.node()); + return; + } + + if (value->shouldSpeculateBoolean()) { + insertCheck<BooleanUse>(m_indexInBlock, value.node()); + return; + } + + if (value->shouldSpeculateOther()) { + insertCheck<OtherUse>(m_indexInBlock, value.node()); + return; + } + + if (value->shouldSpeculateNumber()) { + insertCheck<NumberUse>(m_indexInBlock, value.node()); + return; + } + + if (value->shouldSpeculateNotCell()) { + insertCheck<NotCellUse>(m_indexInBlock, value.node()); + return; + } + } + + template<UseKind useKind> + void insertCheck(unsigned indexInBlock, Node* node) + { + observeUseKindOnNode<useKind>(node); + m_insertionSet.insertNode( + indexInBlock, SpecNone, Check, m_currentNode->origin, Edge(node, useKind)); } void fixIntConvertingEdge(Edge& edge) @@ -1610,7 +1841,6 @@ private: observeUseKindOnNode(node, useKind); edge = Edge(newNode, KnownInt32Use); - addRequiredPhantom(node); } void fixIntOrBooleanEdge(Edge& edge) @@ -1632,7 +1862,6 @@ private: observeUseKindOnNode(node, useKind); edge = Edge(newNode, Int32Use); - addRequiredPhantom(node); } void fixDoubleOrBooleanEdge(Edge& edge) @@ -1654,34 +1883,21 @@ private: observeUseKindOnNode(node, useKind); edge = Edge(newNode, DoubleRepUse); - addRequiredPhantom(node); } void truncateConstantToInt32(Edge& edge) { Node* oldNode = edge.node(); - ASSERT(oldNode->hasConstant()); - JSValue value = m_graph.valueOfJSConstant(oldNode); + JSValue value = oldNode->asJSValue(); if (value.isInt32()) return; value = jsNumber(JSC::toInt32(value.asNumber())); ASSERT(value.isInt32()); - unsigned constantRegister; - if (!codeBlock()->findConstant(value, constantRegister)) { - constantRegister = codeBlock()->addConstantLazily(); - initializeLazyWriteBarrierForConstant( - m_graph.m_plan.writeBarriers, - codeBlock()->constants()[constantRegister], - codeBlock(), - constantRegister, - codeBlock()->ownerExecutable(), - value); - } edge.setNode(m_insertionSet.insertNode( m_indexInBlock, SpecInt32, JSConstant, m_currentNode->origin, - OpInfo(constantRegister))); + OpInfo(m_graph.freeze(value)))); } void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode) @@ -1784,12 +2000,12 @@ private: Node* shiftAmount = m_insertionSet.insertNode( m_indexInBlock, SpecInt32, JSConstant, node->origin, - OpInfo(m_graph.constantRegisterForConstant(jsNumber(logElementSize(type))))); + OpInfo(m_graph.freeze(jsNumber(logElementSize(type))))); // We can use a BitLShift here because typed arrays will never have a byteLength // that overflows int32. node->setOp(BitLShift); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); observeUseKindOnNode(length, Int32Use); observeUseKindOnNode(shiftAmount, Int32Use); node->child1() = Edge(length, Int32Use); @@ -1800,7 +2016,7 @@ private: void convertToGetArrayLength(Node* node, ArrayMode arrayMode) { node->setOp(GetArrayLength); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); fixEdge<KnownCellUse>(node->child1()); node->setArrayMode(arrayMode); @@ -1833,7 +2049,7 @@ private: 0, neverNeedsStorage); node->setOp(GetTypedArrayByteOffset); - node->clearFlags(NodeMustGenerate | NodeClobbersWorld); + node->clearFlags(NodeMustGenerate); fixEdge<KnownCellUse>(node->child1()); return true; } @@ -1846,11 +2062,9 @@ private: m_block = block; for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) { m_currentNode = block->at(m_indexInBlock); - addPhantomsIfNecessary(); tryToRelaxRepresentation(m_currentNode); DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge); } - clearPhantomsAtEnd(); m_insertionSet.execute(block); } @@ -1864,9 +2078,7 @@ private: switch (node->op()) { case MovHint: - case Phantom: case Check: - case HardPhantom: DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, fixEdgeRepresentation); break; @@ -1909,6 +2121,13 @@ private: edge.setUseKind(Int52RepUse); break; + case RealNumberUse: + if (edge->hasDoubleResult()) + edge.setUseKind(DoubleRepRealUse); + else if (edge->hasInt52Result()) + edge.setUseKind(Int52RepUse); + break; + default: break; } @@ -1926,21 +2145,26 @@ private: if (edge->hasDoubleResult()) break; - addRequiredPhantom(edge.node()); - - if (edge->op() == JSConstant && m_graph.isNumberConstant(edge.node())) { + if (edge->isNumberConstant()) { result = m_insertionSet.insertNode( m_indexInBlock, SpecBytecodeDouble, DoubleConstant, node->origin, - OpInfo(m_graph.constantRegisterForConstant( - jsDoubleNumber(m_graph.valueOfNumberConstant(edge.node()))))); + OpInfo(m_graph.freeze(jsDoubleNumber(edge->asNumber())))); } else if (edge->hasInt52Result()) { result = m_insertionSet.insertNode( m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin, Edge(edge.node(), Int52RepUse)); } else { + UseKind useKind; + if (edge->shouldSpeculateDoubleReal()) + useKind = RealNumberUse; + else if (edge->shouldSpeculateNumber()) + useKind = NumberUse; + else + useKind = NotCellUse; + result = m_insertionSet.insertNode( m_indexInBlock, SpecBytecodeDouble, DoubleRep, node->origin, - Edge(edge.node(), NumberUse)); + Edge(edge.node(), useKind)); } edge.setNode(result); @@ -1951,12 +2175,10 @@ private: if (edge->hasInt52Result()) break; - addRequiredPhantom(edge.node()); - - if (edge->op() == JSConstant && m_graph.isMachineIntConstant(edge.node())) { + if (edge->isMachineIntConstant()) { result = m_insertionSet.insertNode( m_indexInBlock, SpecMachineInt, Int52Constant, node->origin, - OpInfo(edge->constantNumber())); + OpInfo(edge->constant())); } else if (edge->hasDoubleResult()) { result = m_insertionSet.insertNode( m_indexInBlock, SpecMachineInt, Int52Rep, node->origin, @@ -1979,8 +2201,6 @@ private: if (!edge->hasDoubleResult() && !edge->hasInt52Result()) break; - addRequiredPhantom(edge.node()); - if (edge->hasDoubleResult()) { result = m_insertionSet.insertNode( m_indexInBlock, SpecBytecodeDouble, ValueRep, node->origin, @@ -1996,47 +2216,11 @@ private: } } } - void addRequiredPhantom(Node* node) - { - m_requiredPhantoms.append(node); - } - - void addPhantomsIfNecessary() - { - if (m_requiredPhantoms.isEmpty()) - return; - - for (unsigned i = m_requiredPhantoms.size(); i--;) { - Node* node = m_requiredPhantoms[i]; - m_insertionSet.insertNode( - m_indexInBlock, SpecNone, Phantom, m_currentNode->origin, - node->defaultEdge()); - } - - m_requiredPhantoms.resize(0); - } - - void clearPhantomsAtEnd() - { - // Terminal nodes don't need post-phantoms, and inserting them would violate - // the current requirement that a terminal is the last thing in a block. We - // should eventually change that requirement. Currently we get around this by - // ensuring that all terminals accept just one input, and if that input is a - // conversion node then no further speculations will be performed. See - // references to the bug, below, for places where we have to have hacks to - // work around this. - // FIXME: Get rid of this by allowing Phantoms after terminals. - // https://bugs.webkit.org/show_bug.cgi?id=126778 - - m_requiredPhantoms.resize(0); - } - BasicBlock* m_block; unsigned m_indexInBlock; Node* m_currentNode; InsertionSet m_insertionSet; bool m_profitabilityChanged; - Vector<Node*, 3> m_requiredPhantoms; }; bool performFixup(Graph& graph) diff --git a/dfg/DFGFlushFormat.cpp b/dfg/DFGFlushFormat.cpp index 0bf55ba..fa483ac 100644 --- a/dfg/DFGFlushFormat.cpp +++ b/dfg/DFGFlushFormat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,9 +58,6 @@ void printInternal(PrintStream& out, FlushFormat format) case FlushedJSValue: out.print("FlushedJSValue"); return; - case FlushedArguments: - out.print("FlushedArguments"); - return; case ConflictingFlush: out.print("ConflictingFlush"); return; diff --git a/dfg/DFGFlushFormat.h b/dfg/DFGFlushFormat.h index 10e3c00..480944b 100644 --- a/dfg/DFGFlushFormat.h +++ b/dfg/DFGFlushFormat.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,7 +44,6 @@ enum FlushFormat { FlushedCell, FlushedBoolean, FlushedJSValue, - FlushedArguments, ConflictingFlush }; @@ -55,7 +54,6 @@ inline NodeFlags resultFor(FlushFormat format) case FlushedJSValue: case FlushedCell: case ConflictingFlush: - case FlushedArguments: return NodeResultJS; case FlushedInt32: return NodeResultInt32; @@ -76,7 +74,6 @@ inline UseKind useKindFor(FlushFormat format) case DeadFlush: case FlushedJSValue: case ConflictingFlush: - case FlushedArguments: return UntypedUse; case FlushedCell: return CellUse; @@ -93,6 +90,11 @@ inline UseKind useKindFor(FlushFormat format) return UntypedUse; } +inline SpeculatedType typeFilterFor(FlushFormat format) +{ + return typeFilterFor(useKindFor(format)); +} + inline DataFormat dataFormatFor(FlushFormat format) { switch (format) { @@ -111,13 +113,27 @@ inline DataFormat dataFormatFor(FlushFormat format) return DataFormatCell; case FlushedBoolean: return DataFormatBoolean; - case FlushedArguments: - return DataFormatArguments; } RELEASE_ASSERT_NOT_REACHED(); return DataFormatDead; } +inline FlushFormat merge(FlushFormat a, FlushFormat b) +{ + if (a == DeadFlush) + return b; + if (b == DeadFlush) + return a; + if (a == b) + return a; + return ConflictingFlush; +} + +inline bool isConcrete(FlushFormat format) +{ + return format != DeadFlush && format != ConflictingFlush; +} + } } // namespace JSC::DFG namespace WTF { diff --git a/dfg/DFGFlushedAt.cpp b/dfg/DFGFlushedAt.cpp index 984a38d..c15a2e6 100644 --- a/dfg/DFGFlushedAt.cpp +++ b/dfg/DFGFlushedAt.cpp @@ -36,8 +36,10 @@ void FlushedAt::dump(PrintStream& out) const { if (m_format == DeadFlush || m_format == ConflictingFlush) out.print(m_format); + else if (m_virtualRegister.isValid()) + out.print(m_virtualRegister, ":", m_format); else - out.print("r", m_virtualRegister, ":", m_format); + out.print(m_format); } void FlushedAt::dumpInContext(PrintStream& out, DumpContext*) const diff --git a/dfg/DFGFlushedAt.h b/dfg/DFGFlushedAt.h index 3bc1cee..ea913dd 100644 --- a/dfg/DFGFlushedAt.h +++ b/dfg/DFGFlushedAt.h @@ -52,8 +52,6 @@ public: { if (format == DeadFlush) ASSERT(!virtualRegister.isValid()); - else - ASSERT(virtualRegister.isValid()); } bool operator!() const { return m_format == DeadFlush; } diff --git a/dfg/DFGForAllKills.h b/dfg/DFGForAllKills.h new file mode 100644 index 0000000..bb630cd --- /dev/null +++ b/dfg/DFGForAllKills.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2015 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 DFGForAllKills_h +#define DFGForAllKills_h + +#include "DFGCombinedLiveness.h" +#include "DFGGraph.h" +#include "DFGOSRAvailabilityAnalysisPhase.h" +#include "FullBytecodeLiveness.h" + +namespace JSC { namespace DFG { + +// Utilities for finding the last points where a node is live in DFG SSA. This accounts for liveness due +// to OSR exit. This is usually used for enumerating over all of the program points where a node is live, +// by exploring all blocks where the node is live at tail and then exploring all program points where the +// node is killed. A prerequisite to using these utilities is having liveness and OSR availability +// computed. + +// This tells you those things that die on the boundary between nodeBefore and nodeAfter. It is +// conservative in the sense that it might resort to telling you some things that are still live at +// nodeAfter. +template<typename Functor> +void forAllKilledOperands(Graph& graph, Node* nodeBefore, Node* nodeAfter, const Functor& functor) +{ + CodeOrigin before = nodeBefore->origin.forExit; + + if (!nodeAfter) { + graph.forAllLiveInBytecode(before, functor); + return; + } + + CodeOrigin after = nodeAfter->origin.forExit; + + VirtualRegister alreadyNoted; + if (!!after) { + // If we MovHint something that is live at the time, then we kill the old value. + if (nodeAfter->containsMovHint()) { + VirtualRegister reg = nodeAfter->unlinkedLocal(); + if (graph.isLiveInBytecode(reg, after)) { + functor(reg); + alreadyNoted = reg; + } + } + } + + if (!before) { + if (!after) + return; + // The true before-origin is the origin at predecessors that jump to us. But there can be + // many such predecessors and they will likely all have a different origin. So, it's better + // to do the conservative thing. + graph.forAllLocalsLiveInBytecode(after, functor); + return; + } + + if (before == after) + return; + + // before could be unset even if after is, but the opposite cannot happen. + ASSERT(!!after); + + // It's easier to do this if the inline call frames are the same. This is way faster than the + // other loop, below. + if (before.inlineCallFrame == after.inlineCallFrame) { + int stackOffset = before.inlineCallFrame ? before.inlineCallFrame->stackOffset : 0; + CodeBlock* codeBlock = graph.baselineCodeBlockFor(before.inlineCallFrame); + FullBytecodeLiveness& fullLiveness = graph.livenessFor(codeBlock); + const FastBitVector& liveBefore = fullLiveness.getLiveness(before.bytecodeIndex); + const FastBitVector& liveAfter = fullLiveness.getLiveness(after.bytecodeIndex); + + for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) { + if (liveBefore.get(relativeLocal) && !liveAfter.get(relativeLocal)) + functor(virtualRegisterForLocal(relativeLocal) + stackOffset); + } + + return; + } + + // Detect kills the super conservative way: it is killed if it was live before and dead after. + BitVector liveAfter = graph.localsLiveInBytecode(after); + graph.forAllLocalsLiveInBytecode( + before, + [&] (VirtualRegister reg) { + if (reg == alreadyNoted) + return; + if (liveAfter.get(reg.toLocal())) + return; + functor(reg); + }); +} + +// Tells you all of the nodes that would no longer be live across the node at this nodeIndex. +template<typename Functor> +void forAllKilledNodesAtNodeIndex( + Graph& graph, AvailabilityMap& availabilityMap, BasicBlock* block, unsigned nodeIndex, + const Functor& functor) +{ + static const unsigned seenInClosureFlag = 1; + static const unsigned calledFunctorFlag = 2; + HashMap<Node*, unsigned> flags; + + Node* node = block->at(nodeIndex); + + graph.doToChildren( + node, + [&] (Edge edge) { + if (edge.doesKill()) { + auto& result = flags.add(edge.node(), 0).iterator->value; + if (!(result & calledFunctorFlag)) { + functor(edge.node()); + result |= calledFunctorFlag; + } + } + }); + + Node* before = nullptr; + if (nodeIndex) + before = block->at(nodeIndex - 1); + + forAllKilledOperands( + graph, before, node, + [&] (VirtualRegister reg) { + availabilityMap.closeStartingWithLocal( + reg, + [&] (Node* node) -> bool { + return flags.get(node) & seenInClosureFlag; + }, + [&] (Node* node) -> bool { + auto& resultFlags = flags.add(node, 0).iterator->value; + bool result = resultFlags & seenInClosureFlag; + if (!(resultFlags & calledFunctorFlag)) + functor(node); + resultFlags |= seenInClosureFlag | calledFunctorFlag; + return result; + }); + }); +} + +// Tells you all of the places to start searching from in a basic block. Gives you the node index at which +// the value is either no longer live. This pretends that nodes are dead at the end of the block, so that +// you can use this to do per-basic-block analyses. +template<typename Functor> +void forAllKillsInBlock( + Graph& graph, const CombinedLiveness& combinedLiveness, BasicBlock* block, + const Functor& functor) +{ + for (Node* node : combinedLiveness.liveAtTail[block]) + functor(block->size(), node); + + LocalOSRAvailabilityCalculator localAvailability; + localAvailability.beginBlock(block); + // Start at the second node, because the functor is expected to only inspect nodes from the start of + // the block up to nodeIndex (exclusive), so if nodeIndex is zero then the functor has nothing to do. + for (unsigned nodeIndex = 1; nodeIndex < block->size(); ++nodeIndex) { + forAllKilledNodesAtNodeIndex( + graph, localAvailability.m_availability, block, nodeIndex, + [&] (Node* node) { + functor(nodeIndex, node); + }); + localAvailability.executeNode(block->at(nodeIndex)); + } +} + +} } // namespace JSC::DFG + +#endif // DFGForAllKills_h + diff --git a/dfg/DFGFrozenValue.cpp b/dfg/DFGFrozenValue.cpp new file mode 100644 index 0000000..a62c38d --- /dev/null +++ b/dfg/DFGFrozenValue.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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 "DFGFrozenValue.h" + +#if ENABLE(DFG_JIT) + +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +FrozenValue* FrozenValue::emptySingleton() +{ + static FrozenValue empty; + return ∅ +} + +void FrozenValue::dumpInContext(PrintStream& out, DumpContext* context) const +{ + if (!!m_value && m_value.isCell()) + out.print(m_strength, ":"); + m_value.dumpInContextAssumingStructure(out, context, m_structure); +} + +void FrozenValue::dump(PrintStream& out) const +{ + dumpInContext(out, 0); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGFrozenValue.h b/dfg/DFGFrozenValue.h new file mode 100644 index 0000000..094356f --- /dev/null +++ b/dfg/DFGFrozenValue.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014, 2015 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 DFGFrozenValue_h +#define DFGFrozenValue_h + +#if ENABLE(DFG_JIT) + +#include "DFGValueStrength.h" +#include "JSCell.h" +#include "JSCJSValue.h" +#include "Structure.h" + +namespace JSC { namespace DFG { + +class Graph; + +class FrozenValue { +public: + FrozenValue() + : m_structure(nullptr) + , m_strength(WeakValue) + { + } + + FrozenValue(JSValue value) + : m_value(value) + , m_structure(nullptr) + , m_strength(WeakValue) + { + RELEASE_ASSERT(!value || !value.isCell()); + } + + FrozenValue(JSValue value, Structure* structure, ValueStrength strength) + : m_value(value) + , m_structure(structure) + , m_strength(strength) + { + ASSERT((!!value && value.isCell()) == !!structure); + ASSERT(!value || !value.isCell() || value.asCell()->classInfo() == structure->classInfo()); + ASSERT(!!structure || (strength == WeakValue)); + } + + static FrozenValue* emptySingleton(); + + bool operator!() const { return !m_value; } + + JSValue value() const { return m_value; } + JSCell* cell() const { return m_value.asCell(); } + + template<typename T> + T dynamicCast() + { + return jsDynamicCast<T>(value()); + } + template<typename T> + T cast() + { + return jsCast<T>(value()); + } + + Structure* structure() const { return m_structure; } + + void strengthenTo(ValueStrength strength) + { + if (!!m_value && m_value.isCell()) + m_strength = merge(m_strength, strength); + } + + bool pointsToHeap() const { return !!value() && value().isCell(); } + + // The strength of the value itself. The structure is almost always weak. + ValueStrength strength() const { return m_strength; } + + void dumpInContext(PrintStream& out, DumpContext* context) const; + void dump(PrintStream& out) const; + +private: + friend class Graph; + + // This is a utility method for DFG::Graph::freeze(). You should almost always call + // Graph::freeze() directly. Calling this instead of Graph::freeze() can result in + // the same constant being viewed as having different structures during the course + // of compilation, which can sometimes cause bad things to happen. For example, we + // may observe that one version of the constant has an unwatchable structure but + // then a later version may start to have a watchable structure due to a transition. + // The point of freezing is to ensure that we generally only see one version of + // constants, but that requires freezing through the Graph. + static FrozenValue freeze(JSValue value) + { + return FrozenValue( + value, + (!!value && value.isCell()) ? value.asCell()->structure() : nullptr, + WeakValue); + } + + JSValue m_value; + Structure* m_structure; + ValueStrength m_strength; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGFrozenValue_h + diff --git a/dfg/DFGFunctionWhitelist.cpp b/dfg/DFGFunctionWhitelist.cpp index f618499..57dc109 100644 --- a/dfg/DFGFunctionWhitelist.cpp +++ b/dfg/DFGFunctionWhitelist.cpp @@ -42,7 +42,7 @@ FunctionWhitelist& FunctionWhitelist::ensureGlobalWhitelist() static LazyNeverDestroyed<FunctionWhitelist> functionWhitelist; static std::once_flag initializeWhitelistFlag; std::call_once(initializeWhitelistFlag, [] { - const char* functionWhitelistFile = Options::dfgFunctionWhitelistFile(); + const char* functionWhitelistFile = Options::dfgWhitelist(); functionWhitelist.construct(functionWhitelistFile); }); return functionWhitelist; @@ -92,7 +92,7 @@ void FunctionWhitelist::parseFunctionNamesInFile(const char* filename) bool FunctionWhitelist::contains(CodeBlock* codeBlock) const { ASSERT(!isCompilationThread()); - if (!Options::dfgFunctionWhitelistFile()) + if (!Options::dfgWhitelist()) return true; if (m_entries.isEmpty()) @@ -106,10 +106,7 @@ bool FunctionWhitelist::contains(CodeBlock* codeBlock) const if (m_entries.contains(hash)) return true; - String nameAndHash = name; - nameAndHash.append('#'); - nameAndHash.append(hash); - return m_entries.contains(nameAndHash); + return m_entries.contains(name + '#' + hash); } } } // namespace JSC::DFG diff --git a/dfg/DFGGenerationInfo.h b/dfg/DFGGenerationInfo.h index e3330fa..b30f350 100644 --- a/dfg/DFGGenerationInfo.h +++ b/dfg/DFGGenerationInfo.h @@ -38,9 +38,9 @@ namespace JSC { namespace DFG { // === GenerationInfo === // -// This class is used to track the current status of a live values during code generation. +// This class is used to track the current status of live values during code generation. // Can provide information as to whether a value is in machine registers, and if so which, -// whether a value has been spilled to the RegsiterFile, and if so may be able to provide +// whether a value has been spilled to the RegisterFile, and if so may be able to provide // details of the format in memory (all values are spilled in a boxed form, but we may be // able to track the type of box), and tracks how many outstanding uses of a value remain, // so that we know when the value is dead and the machine registers associated with it @@ -153,8 +153,6 @@ public: void noticeOSRBirth(VariableEventStream& stream, Node* node, VirtualRegister virtualRegister) { - if (m_isConstant) - return; if (m_node != node) return; if (!alive()) @@ -164,7 +162,9 @@ public: m_bornForOSR = true; - if (m_registerFormat != DataFormatNone) + if (m_isConstant) + appendBirth(stream); + else if (m_registerFormat != DataFormatNone) appendFill(BirthToFill, stream); else if (m_spillFormat != DataFormatNone) appendSpill(BirthToSpill, stream, virtualRegister); @@ -379,6 +379,11 @@ public: } private: + void appendBirth(VariableEventStream& stream) + { + stream.appendAndLog(VariableEvent::birth(MinifiedID(m_node))); + } + void appendFill(VariableEventKind kind, VariableEventStream& stream) { ASSERT(m_bornForOSR); diff --git a/dfg/DFGGraph.cpp b/dfg/DFGGraph.cpp index 0156c8b..74aca3b 100644 --- a/dfg/DFGGraph.cpp +++ b/dfg/DFGGraph.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,16 +28,18 @@ #if ENABLE(DFG_JIT) +#include "BytecodeKills.h" #include "BytecodeLivenessAnalysisInlines.h" #include "CodeBlock.h" #include "CodeBlockWithJITType.h" +#include "DFGBlockWorklist.h" #include "DFGClobberSet.h" #include "DFGJITCode.h" #include "DFGVariableAccessDataDump.h" #include "FullBytecodeLiveness.h" #include "FunctionExecutableDump.h" #include "JIT.h" -#include "JSActivation.h" +#include "JSLexicalEnvironment.h" #include "MaxFrameExtentForSlowPathCall.h" #include "OperandsInlines.h" #include "JSCInlines.h" @@ -60,23 +62,31 @@ Graph::Graph(VM& vm, Plan& plan, LongLivedState& longLivedState) , m_codeBlock(m_plan.codeBlock.get()) , m_profiledBlock(m_codeBlock->alternative()) , m_allocator(longLivedState.m_allocator) - , m_mustHandleAbstractValues(OperandsLike, plan.mustHandleValues) - , m_hasArguments(false) , m_nextMachineLocal(0) - , m_machineCaptureStart(std::numeric_limits<int>::max()) , m_fixpointState(BeforeFixpoint) + , m_structureRegistrationState(HaveNotStartedRegistering) , m_form(LoadStore) , m_unificationState(LocallyUnified) , m_refCountState(EverythingIsLive) { ASSERT(m_profiledBlock); - for (unsigned i = m_mustHandleAbstractValues.size(); i--;) - m_mustHandleAbstractValues[i].setMostSpecific(*this, plan.mustHandleValues[i]); + m_hasDebuggerEnabled = m_profiledBlock->globalObject()->hasDebugger() + || Options::forceDebuggerBytecodeGeneration(); } Graph::~Graph() { + for (BlockIndex blockIndex = numBlocks(); blockIndex--;) { + BasicBlock* block = this->block(blockIndex); + if (!block) + continue; + + for (unsigned phiIndex = block->phis.size(); phiIndex--;) + m_allocator.free(block->phis[phiIndex]); + for (unsigned nodeIndex = block->size(); nodeIndex--;) + m_allocator.free(block->at(nodeIndex)); + } m_allocator.freeAll(); } @@ -146,7 +156,6 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* NodeType op = node->op(); unsigned refCount = node->refCount(); - bool skipped = !refCount; bool mustGenerate = node->mustGenerate(); if (mustGenerate) --refCount; @@ -168,11 +177,10 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* // (5) The arguments to the operation. The may be of the form: // @# - a NodeIndex referencing a prior node in the graph. // arg# - an argument number. - // $# - 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. - out.printf("% 4d:%s<%c%u:", (int)node->index(), skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount); - if (node->hasResult() && !skipped && node->hasVirtualRegister()) + out.printf("% 4d:<%c%u:", (int)node->index(), mustGenerate ? '!' : ' ', refCount); + if (node->hasResult() && node->hasVirtualRegister() && node->virtualRegister().isValid()) out.print(node->virtualRegister()); else out.print("-"); @@ -201,46 +209,48 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* out.print(comma, node->arrayMode()); if (node->hasArithMode()) out.print(comma, node->arithMode()); - if (node->hasVarNumber()) - out.print(comma, node->varNumber()); + if (node->hasScopeOffset()) + out.print(comma, node->scopeOffset()); + if (node->hasDirectArgumentsOffset()) + out.print(comma, node->capturedArgumentsOffset()); if (node->hasRegisterPointer()) - out.print(comma, "global", globalObjectFor(node->origin.semantic)->findRegisterIndex(node->registerPointer()), "(", RawPointer(node->registerPointer()), ")"); + out.print(comma, "global", globalObjectFor(node->origin.semantic)->findVariableIndex(node->variablePointer()), "(", RawPointer(node->variablePointer()), ")"); if (node->hasIdentifier()) out.print(comma, "id", node->identifierNumber(), "{", identifiers()[node->identifierNumber()], "}"); + if (node->hasPromotedLocationDescriptor()) + out.print(comma, node->promotedLocationDescriptor()); if (node->hasStructureSet()) out.print(comma, inContext(node->structureSet(), context)); if (node->hasStructure()) out.print(comma, inContext(*node->structure(), context)); - if (node->hasStructureTransitionData()) - out.print(comma, inContext(*node->structureTransitionData().previousStructure, context), " -> ", inContext(*node->structureTransitionData().newStructure, context)); - if (node->hasFunction()) { - out.print(comma, "function(", RawPointer(node->function()), ", "); - if (node->function()->inherits(JSFunction::info())) { - JSFunction* function = jsCast<JSFunction*>(node->function()); - if (function->isHostFunction()) - out.print("<host function>"); - else - out.print(FunctionExecutableDump(function->jsExecutable())); - } else - out.print("<not JSFunction>"); - out.print(")"); - } - if (node->hasExecutable()) { - if (node->executable()->inherits(FunctionExecutable::info())) - out.print(comma, "executable(", FunctionExecutableDump(jsCast<FunctionExecutable*>(node->executable())), ")"); - else - out.print(comma, "executable(not function: ", RawPointer(node->executable()), ")"); + if (node->hasTransition()) { + out.print(comma, pointerDumpInContext(node->transition(), context)); +#if USE(JSVALUE64) + out.print(", ID:", node->transition()->next->id()); +#else + out.print(", ID:", RawPointer(node->transition()->next)); +#endif } - if (node->hasFunctionDeclIndex()) { - FunctionExecutable* executable = m_codeBlock->functionDecl(node->functionDeclIndex()); - out.print(comma, FunctionExecutableDump(executable)); - } - if (node->hasFunctionExprIndex()) { - FunctionExecutable* executable = m_codeBlock->functionExpr(node->functionExprIndex()); - out.print(comma, FunctionExecutableDump(executable)); + if (node->hasCellOperand()) { + if (!node->cellOperand()->value() || !node->cellOperand()->value().isCell()) + out.print(comma, "invalid cell operand: ", node->cellOperand()->value()); + else { + out.print(comma, pointerDump(node->cellOperand()->value().asCell())); + if (node->cellOperand()->value().isCell()) { + CallVariant variant(node->cellOperand()->value().asCell()); + if (ExecutableBase* executable = variant.executable()) { + if (executable->isHostFunction()) + out.print(comma, "<host function>"); + else if (FunctionExecutable* functionExecutable = jsDynamicCast<FunctionExecutable*>(executable)) + out.print(comma, FunctionExecutableDump(functionExecutable)); + else + out.print(comma, "<non-function executable>"); + } + } + } } if (node->hasStorageAccessData()) { - StorageAccessData& storageAccessData = m_storageAccessData[node->storageAccessDataIndex()]; + StorageAccessData& storageAccessData = node->storageAccessData(); out.print(comma, "id", storageAccessData.identifierNumber, "{", identifiers()[storageAccessData.identifierNumber], "}"); out.print(", ", static_cast<ptrdiff_t>(storageAccessData.offset)); } @@ -261,42 +271,32 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* VariableAccessData* variableAccessData = node->tryGetVariableAccessData(); if (variableAccessData) { VirtualRegister operand = variableAccessData->local(); - if (operand.isArgument()) - out.print(comma, "arg", operand.toArgument(), "(", VariableAccessDataDump(*this, variableAccessData), ")"); - else - out.print(comma, "loc", operand.toLocal(), "(", VariableAccessDataDump(*this, variableAccessData), ")"); - + out.print(comma, variableAccessData->local(), "(", VariableAccessDataDump(*this, variableAccessData), ")"); operand = variableAccessData->machineLocal(); - if (operand.isValid()) { - if (operand.isArgument()) - out.print(comma, "machine:arg", operand.toArgument()); - else - out.print(comma, "machine:loc", operand.toLocal()); - } + if (operand.isValid()) + out.print(comma, "machine:", operand); } } - if (node->hasUnlinkedLocal()) { - VirtualRegister operand = node->unlinkedLocal(); - if (operand.isArgument()) - out.print(comma, "arg", operand.toArgument()); - else - out.print(comma, "loc", operand.toLocal()); + if (node->hasStackAccessData()) { + StackAccessData* data = node->stackAccessData(); + out.print(comma, data->local); + if (data->machineLocal.isValid()) + out.print(comma, "machine:", data->machineLocal); + out.print(comma, data->format); } + if (node->hasUnlinkedLocal()) + out.print(comma, node->unlinkedLocal()); if (node->hasUnlinkedMachineLocal()) { VirtualRegister operand = node->unlinkedMachineLocal(); - if (operand.isValid()) { - if (operand.isArgument()) - out.print(comma, "machine:arg", operand.toArgument()); - else - out.print(comma, "machine:loc", operand.toLocal()); - } + if (operand.isValid()) + out.print(comma, "machine:", operand); } if (node->hasConstantBuffer()) { out.print(comma); out.print(node->startConstant(), ":["); CommaPrinter anotherComma; for (unsigned i = 0; i < node->numConstants(); ++i) - out.print(anotherComma, inContext(m_codeBlock->constantBuffer(node->startConstant())[i], context)); + out.print(anotherComma, pointerDumpInContext(freeze(m_codeBlock->constantBuffer(node->startConstant())[i]), context)); out.print("]"); } if (node->hasIndexingType()) @@ -307,19 +307,26 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* out.print(comma, "^", node->phi()->index()); if (node->hasExecutionCounter()) out.print(comma, RawPointer(node->executionCounter())); - if (node->hasVariableWatchpointSet()) - out.print(comma, RawPointer(node->variableWatchpointSet())); - if (node->hasTypedArray()) - out.print(comma, inContext(JSValue(node->typedArray()), context)); + if (node->hasWatchpointSet()) + out.print(comma, RawPointer(node->watchpointSet())); if (node->hasStoragePointer()) out.print(comma, RawPointer(node->storagePointer())); - if (node->isConstant()) { - out.print(comma, "$", node->constantNumber()); - JSValue value = valueOfJSConstant(node); - out.print(" = ", inContext(value, context)); + if (node->hasObjectMaterializationData()) + out.print(comma, node->objectMaterializationData()); + if (node->hasCallVarargsData()) + out.print(comma, "firstVarArgOffset = ", node->callVarargsData()->firstVarArgOffset); + if (node->hasLoadVarargsData()) { + LoadVarargsData* data = node->loadVarargsData(); + out.print(comma, "start = ", data->start, ", count = ", data->count); + if (data->machineStart.isValid()) + out.print(", machineStart = ", data->machineStart); + if (data->machineCount.isValid()) + out.print(", machineCount = ", data->machineCount); + out.print(", offset = ", data->offset, ", mandatoryMinimum = ", data->mandatoryMinimum); + out.print(", limit = ", data->limit); } - if (op == WeakJSConstant) - out.print(comma, RawPointer(node->weakConstant()), " (", inContext(*node->weakConstant()->structure(), context), ")"); + if (node->isConstant()) + out.print(comma, pointerDumpInContext(node->constant(), context)); if (node->isJump()) out.print(comma, "T:", *node->targetBlock()); if (node->isBranch()) @@ -338,47 +345,58 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* out.print(comma, "R:", sortedListDump(reads.direct(), ",")); if (!writes.isEmpty()) out.print(comma, "W:", sortedListDump(writes.direct(), ",")); - out.print(comma, "bc#", node->origin.semantic.bytecodeIndex); - if (node->origin.semantic != node->origin.forExit) - out.print(comma, "exit: ", node->origin.forExit); + if (node->origin.isSet()) { + out.print(comma, "bc#", node->origin.semantic.bytecodeIndex); + if (node->origin.semantic != node->origin.forExit) + out.print(comma, "exit: ", node->origin.forExit); + } out.print(")"); - if (!skipped) { - if (node->hasVariableAccessData(*this) && node->tryGetVariableAccessData()) - out.print(" predicting ", SpeculationDump(node->tryGetVariableAccessData()->prediction())); - else if (node->hasHeapPrediction()) - out.print(" predicting ", SpeculationDump(node->getHeapPrediction())); - } + if (node->hasVariableAccessData(*this) && node->tryGetVariableAccessData()) + out.print(" predicting ", SpeculationDump(node->tryGetVariableAccessData()->prediction())); + else if (node->hasHeapPrediction()) + out.print(" predicting ", SpeculationDump(node->getHeapPrediction())); out.print("\n"); } +bool Graph::terminalsAreValid() +{ + for (BasicBlock* block : blocksInNaturalOrder()) { + if (!block->terminal()) + return false; + } + return true; +} + void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context) { - out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n"); + out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "):", block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n"); if (block->executionCount == block->executionCount) out.print(prefix, " Execution count: ", block->executionCount, "\n"); out.print(prefix, " Predecessors:"); for (size_t i = 0; i < block->predecessors.size(); ++i) out.print(" ", *block->predecessors[i]); out.print("\n"); - if (m_dominators.isValid()) { - out.print(prefix, " Dominated by:"); - for (size_t i = 0; i < m_blocks.size(); ++i) { - if (!m_dominators.dominates(i, block->index)) - continue; - out.print(" #", i); + out.print(prefix, " Successors:"); + if (block->terminal()) { + for (BasicBlock* successor : block->successors()) { + out.print(" ", *successor); + if (m_prePostNumbering.isValid()) + out.print(" (", m_prePostNumbering.edgeKind(block, successor), ")"); } - out.print("\n"); - out.print(prefix, " Dominates:"); - for (size_t i = 0; i < m_blocks.size(); ++i) { - if (!m_dominators.dominates(block->index, i)) - continue; - out.print(" #", i); - } - out.print("\n"); + } else + out.print(" <invalid>"); + out.print("\n"); + if (m_dominators.isValid() && terminalsAreValid()) { + out.print(prefix, " Dominated by: ", m_dominators.dominatorsOf(block), "\n"); + out.print(prefix, " Dominates: ", m_dominators.blocksDominatedBy(block), "\n"); + out.print(prefix, " Dominance Frontier: ", m_dominators.dominanceFrontierOf(block), "\n"); + out.print(prefix, " Iterated Dominance Frontier: ", m_dominators.iteratedDominanceFrontierOf(BlockList(1, block)), "\n"); } + if (m_prePostNumbering.isValid()) + out.print(prefix, " Pre/Post Numbering: ", m_prePostNumbering.preNumber(block), "/", m_prePostNumbering.postNumber(block), "\n"); if (m_naturalLoops.isValid()) { if (const NaturalLoop* loop = m_naturalLoops.headerOf(block)) { out.print(prefix, " Loop header, contains:"); @@ -406,7 +424,7 @@ void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* bl Node* phiNode = block->phis[i]; if (!phiNode->shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly) continue; - out.print(" @", phiNode->index(), "<", phiNode->refCount(), ">->("); + out.print(" @", phiNode->index(), "<", phiNode->local(), ",", phiNode->refCount(), ">->("); if (phiNode->child1()) { out.print("@", phiNode->child1()->index()); if (phiNode->child2()) { @@ -428,10 +446,14 @@ void Graph::dump(PrintStream& out, DumpContext* context) if (!context) context = &myContext; - dataLog("\n"); - dataLog("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n"); - dataLog(" Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n"); - dataLog("\n"); + out.print("\n"); + out.print("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n"); + out.print(" Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n"); + if (m_form == SSA) + out.print(" Argument formats: ", listDump(m_argumentFormats), "\n"); + else + out.print(" Arguments: ", listDump(m_arguments), "\n"); + out.print("\n"); Node* lastNode = 0; for (size_t b = 0; b < m_blocks.size(); ++b) { @@ -439,16 +461,28 @@ void Graph::dump(PrintStream& out, DumpContext* context) if (!block) continue; dumpBlockHeader(out, "", block, DumpAllPhis, context); + out.print(" States: ", block->cfaStructureClobberStateAtHead); + if (!block->cfaHasVisited) + out.print(", CurrentlyCFAUnreachable"); + if (!block->intersectionOfCFAHasVisited) + out.print(", CFAUnreachable"); + out.print("\n"); switch (m_form) { case LoadStore: case ThreadedCPS: { - out.print(" vars before: "); + out.print(" Vars Before: "); if (block->cfaHasVisited) out.print(inContext(block->valuesAtHead, context)); else out.print("<empty>"); out.print("\n"); - out.print(" var links: ", block->variablesAtHead, "\n"); + out.print(" Intersected Vars Before: "); + if (block->intersectionOfCFAHasVisited) + out.print(inContext(block->intersectionOfPastValuesAtHead, context)); + else + out.print("<empty>"); + out.print("\n"); + out.print(" Var Links: ", block->variablesAtHead, "\n"); break; } @@ -464,16 +498,20 @@ void Graph::dump(PrintStream& out, DumpContext* context) dump(out, "", block->at(i), context); lastNode = block->at(i); } + out.print(" States: ", block->cfaBranchDirection, ", ", block->cfaStructureClobberStateAtTail); + if (!block->cfaDidFinish) + out.print(", CFAInvalidated"); + out.print("\n"); switch (m_form) { case LoadStore: case ThreadedCPS: { - out.print(" vars after: "); + out.print(" Vars After: "); if (block->cfaHasVisited) out.print(inContext(block->valuesAtTail, context)); else out.print("<empty>"); out.print("\n"); - out.print(" var links: ", block->variablesAtTail, "\n"); + out.print(" Var Links: ", block->variablesAtTail, "\n"); break; } @@ -484,12 +522,18 @@ void Graph::dump(PrintStream& out, DumpContext* context) out.print(" Values: ", nodeMapDump(block->ssa->valuesAtTail, context), "\n"); break; } } - dataLog("\n"); + out.print("\n"); + } + + out.print("GC Values:\n"); + for (FrozenValue* value : m_frozenValues) { + if (value->pointsToHeap()) + out.print(" ", inContext(*value, &myContext), "\n"); } if (!myContext.isEmpty()) { - myContext.dump(WTF::dataFile()); - dataLog("\n"); + myContext.dump(out); + out.print("\n"); } } @@ -551,6 +595,113 @@ void Graph::resetReachability() determineReachability(); } +namespace { + +class RefCountCalculator { +public: + RefCountCalculator(Graph& graph) + : m_graph(graph) + { + } + + void calculate() + { + // First reset the counts to 0 for all nodes. + for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + for (unsigned indexInBlock = block->size(); indexInBlock--;) + block->at(indexInBlock)->setRefCount(0); + for (unsigned phiIndex = block->phis.size(); phiIndex--;) + block->phis[phiIndex]->setRefCount(0); + } + + // Now find the roots: + // - Nodes that are must-generate. + // - Nodes that are reachable from type checks. + // Set their ref counts to 1 and put them on the worklist. + for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + for (unsigned indexInBlock = block->size(); indexInBlock--;) { + Node* node = block->at(indexInBlock); + DFG_NODE_DO_TO_CHILDREN(m_graph, node, findTypeCheckRoot); + if (!(node->flags() & NodeMustGenerate)) + continue; + if (!node->postfixRef()) + m_worklist.append(node); + } + } + + while (!m_worklist.isEmpty()) { + while (!m_worklist.isEmpty()) { + Node* node = m_worklist.last(); + m_worklist.removeLast(); + ASSERT(node->shouldGenerate()); // It should not be on the worklist unless it's ref'ed. + DFG_NODE_DO_TO_CHILDREN(m_graph, node, countEdge); + } + + if (m_graph.m_form == SSA) { + // Find Phi->Upsilon edges, which are represented as meta-data in the + // Upsilon. + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + for (unsigned nodeIndex = block->size(); nodeIndex--;) { + Node* node = block->at(nodeIndex); + if (node->op() != Upsilon) + continue; + if (node->shouldGenerate()) + continue; + if (node->phi()->shouldGenerate()) + countNode(node); + } + } + } + } + } + +private: + void findTypeCheckRoot(Node*, Edge edge) + { + // We may have an "unproved" untyped use for code that is unreachable. The CFA + // will just not have gotten around to it. + if (edge.isProved() || edge.willNotHaveCheck()) + return; + if (!edge->postfixRef()) + m_worklist.append(edge.node()); + } + + void countNode(Node* node) + { + if (node->postfixRef()) + return; + m_worklist.append(node); + } + + void countEdge(Node*, Edge edge) + { + // Don't count edges that are already counted for their type checks. + if (!(edge.isProved() || edge.willNotHaveCheck())) + return; + countNode(edge.node()); + } + + Graph& m_graph; + Vector<Node*, 128> m_worklist; +}; + +} // anonymous namespace + +void Graph::computeRefCounts() +{ + RefCountCalculator calculator(*this); + calculator.calculate(); +} + void Graph::killBlockAndItsContents(BasicBlock* block) { for (unsigned phiIndex = block->phis.size(); phiIndex--;) @@ -574,29 +725,15 @@ void Graph::killUnreachableBlocks() } } -void Graph::resetExitStates() -{ - for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) { - BasicBlock* block = m_blocks[blockIndex].get(); - if (!block) - continue; - for (unsigned indexInBlock = block->size(); indexInBlock--;) - block->at(indexInBlock)->setCanExit(true); - } -} - void Graph::invalidateCFG() { m_dominators.invalidate(); m_naturalLoops.invalidate(); + m_prePostNumbering.invalidate(); } void Graph::substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal) { - if (variableAccessData->isCaptured()) { - // Let CSE worry about this one. - return; - } for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) { Node* node = block[indexInBlock]; bool shouldContinue = true; @@ -626,26 +763,37 @@ void Graph::substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, Va } } -void Graph::addForDepthFirstSort(Vector<BasicBlock*>& result, Vector<BasicBlock*, 16>& worklist, HashSet<BasicBlock*>& seen, BasicBlock* block) +BlockList Graph::blocksInPreOrder() { - if (seen.contains(block)) - return; - - result.append(block); - worklist.append(block); - seen.add(block); + BlockList result; + BlockWorklist worklist; + worklist.push(block(0)); + while (BasicBlock* block = worklist.pop()) { + result.append(block); + for (unsigned i = block->numSuccessors(); i--;) + worklist.push(block->successor(i)); + } + return result; } -void Graph::getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result) +BlockList Graph::blocksInPostOrder() { - Vector<BasicBlock*, 16> worklist; - HashSet<BasicBlock*> seen; - addForDepthFirstSort(result, worklist, seen, block(0)); - while (!worklist.isEmpty()) { - BasicBlock* block = worklist.takeLast(); - for (unsigned i = block->numSuccessors(); i--;) - addForDepthFirstSort(result, worklist, seen, block->successor(i)); + BlockList result; + PostOrderBlockWorklist worklist; + worklist.push(block(0)); + while (BlockWithOrder item = worklist.pop()) { + switch (item.order) { + case PreOrder: + worklist.pushPost(item.block); + for (unsigned i = item.block->numSuccessors(); i--;) + worklist.push(item.block->successor(i)); + break; + case PostOrder: + result.append(item.block); + break; + } } + return result; } void Graph::clearReplacements() @@ -655,9 +803,22 @@ void Graph::clearReplacements() if (!block) continue; for (unsigned phiIndex = block->phis.size(); phiIndex--;) - block->phis[phiIndex]->misc.replacement = 0; + block->phis[phiIndex]->setReplacement(nullptr); for (unsigned nodeIndex = block->size(); nodeIndex--;) - block->at(nodeIndex)->misc.replacement = 0; + block->at(nodeIndex)->setReplacement(nullptr); + } +} + +void Graph::clearEpochs() +{ + for (BlockIndex blockIndex = numBlocks(); blockIndex--;) { + BasicBlock* block = m_blocks[blockIndex].get(); + if (!block) + continue; + for (unsigned phiIndex = block->phis.size(); phiIndex--;) + block->phis[phiIndex]->setEpoch(Epoch()); + for (unsigned nodeIndex = block->size(); nodeIndex--;) + block->at(nodeIndex)->setEpoch(Epoch()); } } @@ -668,9 +829,9 @@ void Graph::initializeNodeOwners() if (!block) continue; for (unsigned phiIndex = block->phis.size(); phiIndex--;) - block->phis[phiIndex]->misc.owner = block; + block->phis[phiIndex]->owner = block; for (unsigned nodeIndex = block->size(); nodeIndex--;) - block->at(nodeIndex)->misc.owner = block; + block->at(nodeIndex)->owner = block; } } @@ -705,6 +866,24 @@ FullBytecodeLiveness& Graph::livenessFor(InlineCallFrame* inlineCallFrame) return livenessFor(baselineCodeBlockFor(inlineCallFrame)); } +BytecodeKills& Graph::killsFor(CodeBlock* codeBlock) +{ + HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>>::iterator iter = m_bytecodeKills.find(codeBlock); + if (iter != m_bytecodeKills.end()) + return *iter->value; + + std::unique_ptr<BytecodeKills> kills = std::make_unique<BytecodeKills>(); + codeBlock->livenessAnalysis().computeKills(*kills); + BytecodeKills& result = *kills; + m_bytecodeKills.add(codeBlock, WTF::move(kills)); + return result; +} + +BytecodeKills& Graph::killsFor(InlineCallFrame* inlineCallFrame) +{ + return killsFor(baselineCodeBlockFor(inlineCallFrame)); +} + bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin) { for (;;) { @@ -715,12 +894,12 @@ bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin) if (reg.isArgument()) { RELEASE_ASSERT(reg.offset() < JSStack::CallFrameHeaderSize); - if (!codeOrigin.inlineCallFrame->isClosureCall) - return false; - - if (reg.offset() == JSStack::Callee) + if (codeOrigin.inlineCallFrame->isClosureCall + && reg.offset() == JSStack::Callee) return true; - if (reg.offset() == JSStack::ScopeChain) + + if (codeOrigin.inlineCallFrame->isVarargs() + && reg.offset() == JSStack::ArgumentCount) return true; return false; @@ -736,8 +915,6 @@ bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin) // Arguments are always live. This would be redundant if it wasn't for our // op_call_varargs inlining. - // FIXME: 'this' might not be live, but we don't have a way of knowing. - // https://bugs.webkit.org/show_bug.cgi?id=128519 if (reg.isArgument() && static_cast<size_t>(reg.toArgument()) < inlineCallFrame->arguments.size()) return true; @@ -748,6 +925,19 @@ bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin) return true; } +BitVector Graph::localsLiveInBytecode(CodeOrigin codeOrigin) +{ + BitVector result; + result.ensureSize(block(0)->variablesAtHead.numberOfLocals()); + forAllLocalsLiveInBytecode( + codeOrigin, + [&] (VirtualRegister reg) { + ASSERT(reg.isLocal()); + result.quickSet(reg.toLocal()); + }); + return result; +} + unsigned Graph::frameRegisterCount() { unsigned result = m_nextMachineLocal + std::max(m_parameterSlots, static_cast<unsigned>(maxFrameExtentForSlowPathCallInRegisters)); @@ -776,49 +966,182 @@ unsigned Graph::requiredRegisterCountForExecutionAndExit() return std::max(frameRegisterCount(), requiredRegisterCountForExit()); } -JSActivation* Graph::tryGetActivation(Node* node) +JSValue Graph::tryGetConstantProperty( + JSValue base, const StructureSet& structureSet, PropertyOffset offset) { - if (!node->hasConstant()) - return 0; - return jsDynamicCast<JSActivation*>(valueOfJSConstant(node)); + if (!base || !base.isObject()) + return JSValue(); + + JSObject* object = asObject(base); + + for (unsigned i = structureSet.size(); i--;) { + Structure* structure = structureSet[i]; + WatchpointSet* set = structure->propertyReplacementWatchpointSet(offset); + if (!set || !set->isStillValid()) + return JSValue(); + + ASSERT(structure->isValidOffset(offset)); + ASSERT(!structure->isUncacheableDictionary()); + + watchpoints().addLazily(set); + } + + // What follows may require some extra thought. We need this load to load a valid JSValue. If + // our profiling makes sense and we're still on track to generate code that won't be + // invalidated, then we have nothing to worry about. We do, however, have to worry about + // loading - and then using - an invalid JSValue in the case that unbeknownst to us our code + // is doomed. + // + // One argument in favor of this code is that it should definitely work because the butterfly + // is always set before the structure. However, we don't currently have a fence between those + // stores. It's not clear if this matters, however. We don't ever shrink the property storage. + // So, for this to fail, you'd need an access on a constant object pointer such that the inline + // caches told us that the object had a structure that it did not *yet* have, and then later, + // the object transitioned to that structure that the inline caches had alraedy seen. And then + // the processor reordered the stores. Seems unlikely and difficult to test. I believe that + // this is worth revisiting but it isn't worth losing sleep over. Filed: + // https://bugs.webkit.org/show_bug.cgi?id=134641 + // + // For now, we just do the minimal thing: defend against the structure right now being + // incompatible with the getDirect we're trying to do. The easiest way to do that is to + // determine if the structure belongs to the proven set. + + if (!structureSet.contains(object->structure())) + return JSValue(); + + return object->getDirect(offset); +} + +JSValue Graph::tryGetConstantProperty(JSValue base, Structure* structure, PropertyOffset offset) +{ + return tryGetConstantProperty(base, StructureSet(structure), offset); } -WriteBarrierBase<Unknown>* Graph::tryGetRegisters(Node* node) +JSValue Graph::tryGetConstantProperty( + JSValue base, const StructureAbstractValue& structure, PropertyOffset offset) { - JSActivation* activation = tryGetActivation(node); + if (structure.isTop() || structure.isClobbered()) + return JSValue(); + + return tryGetConstantProperty(base, structure.set(), offset); +} + +JSValue Graph::tryGetConstantProperty(const AbstractValue& base, PropertyOffset offset) +{ + return tryGetConstantProperty(base.m_value, base.m_structure, offset); +} + +JSValue Graph::tryGetConstantClosureVar(JSValue base, ScopeOffset offset) +{ + // This has an awesome concurrency story. See comment for GetGlobalVar in ByteCodeParser. + + if (!base) + return JSValue(); + + JSLexicalEnvironment* activation = jsDynamicCast<JSLexicalEnvironment*>(base); if (!activation) - return 0; - if (!activation->isTornOff()) - return 0; - return activation->registers(); + return JSValue(); + + SymbolTable* symbolTable = activation->symbolTable(); + JSValue value; + WatchpointSet* set; + { + ConcurrentJITLocker locker(symbolTable->m_lock); + + SymbolTableEntry* entry = symbolTable->entryFor(locker, offset); + if (!entry) + return JSValue(); + + set = entry->watchpointSet(); + if (!set) + return JSValue(); + + if (set->state() != IsWatched) + return JSValue(); + + ASSERT(entry->scopeOffset() == offset); + value = activation->variableAt(offset).get(); + if (!value) + return JSValue(); + } + + watchpoints().addLazily(set); + + return value; } -JSArrayBufferView* Graph::tryGetFoldableView(Node* node) +JSValue Graph::tryGetConstantClosureVar(const AbstractValue& value, ScopeOffset offset) +{ + return tryGetConstantClosureVar(value.m_value, offset); +} + +JSValue Graph::tryGetConstantClosureVar(Node* node, ScopeOffset offset) { if (!node->hasConstant()) - return 0; - JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(valueOfJSConstant(node)); - if (!view) - return 0; - if (!watchpoints().isStillValid(view)) - return 0; + return JSValue(); + return tryGetConstantClosureVar(node->asJSValue(), offset); +} + +JSArrayBufferView* Graph::tryGetFoldableView(JSValue value) +{ + if (!value) + return nullptr; + JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(value); + if (!value) + return nullptr; + if (!view->length()) + return nullptr; + WTF::loadLoadFence(); + watchpoints().addLazily(view); return view; } -JSArrayBufferView* Graph::tryGetFoldableView(Node* node, ArrayMode arrayMode) +JSArrayBufferView* Graph::tryGetFoldableView(JSValue value, ArrayMode arrayMode) { if (arrayMode.typedArrayType() == NotTypedArray) - return 0; - return tryGetFoldableView(node); + return nullptr; + return tryGetFoldableView(value); } -JSArrayBufferView* Graph::tryGetFoldableViewForChild1(Node* node) +void Graph::registerFrozenValues() { - return tryGetFoldableView(child(node, 0).node(), node->arrayMode()); + m_codeBlock->constants().resize(0); + m_codeBlock->constantsSourceCodeRepresentation().resize(0); + for (FrozenValue* value : m_frozenValues) { + if (!value->pointsToHeap()) + continue; + + ASSERT(value->structure()); + ASSERT(m_plan.weakReferences.contains(value->structure())); + + switch (value->strength()) { + case WeakValue: { + m_plan.weakReferences.addLazily(value->value().asCell()); + break; + } + case StrongValue: { + unsigned constantIndex = m_codeBlock->addConstantLazily(); + initializeLazyWriteBarrierForConstant( + m_plan.writeBarriers, + m_codeBlock->constants()[constantIndex], + m_codeBlock, + constantIndex, + m_codeBlock->ownerExecutable(), + value->value()); + break; + } } + } + m_codeBlock->constants().shrinkToFit(); + m_codeBlock->constantsSourceCodeRepresentation().shrinkToFit(); } void Graph::visitChildren(SlotVisitor& visitor) { + for (FrozenValue* value : m_frozenValues) { + visitor.appendUnbarrieredReadOnlyValue(value->value()); + visitor.appendUnbarrieredReadOnlyPointer(value->structure()); + } + for (BlockIndex blockIndex = numBlocks(); blockIndex--;) { BasicBlock* block = this->block(blockIndex); if (!block) @@ -828,25 +1151,11 @@ void Graph::visitChildren(SlotVisitor& visitor) Node* node = block->at(nodeIndex); switch (node->op()) { - case JSConstant: - case WeakJSConstant: - visitor.appendUnbarrieredReadOnlyValue(valueOfJSConstant(node)); - break; - - case CheckFunction: - visitor.appendUnbarrieredReadOnlyPointer(node->function()); - break; - - case CheckExecutable: - visitor.appendUnbarrieredReadOnlyPointer(node->executable()); - break; - case CheckStructure: for (unsigned i = node->structureSet().size(); i--;) visitor.appendUnbarrieredReadOnlyPointer(node->structureSet()[i]); break; - case StructureTransitionWatchpoint: case NewObject: case ArrayifyToStructure: case NewStringObject: @@ -854,13 +1163,38 @@ void Graph::visitChildren(SlotVisitor& visitor) break; case PutStructure: - case PhantomPutStructure: case AllocatePropertyStorage: case ReallocatePropertyStorage: visitor.appendUnbarrieredReadOnlyPointer( - node->structureTransitionData().previousStructure); + node->transition()->previous); visitor.appendUnbarrieredReadOnlyPointer( - node->structureTransitionData().newStructure); + node->transition()->next); + break; + + case MultiGetByOffset: + for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) { + GetByIdVariant& variant = node->multiGetByOffsetData().variants[i]; + const StructureSet& set = variant.structureSet(); + for (unsigned j = set.size(); j--;) + visitor.appendUnbarrieredReadOnlyPointer(set[j]); + + // Don't need to mark anything in the structure chain because that would + // have been decomposed into CheckStructure's. Don't need to mark the + // callLinkStatus because we wouldn't use MultiGetByOffset if any of the + // variants did that. + ASSERT(!variant.callLinkStatus()); + } + break; + + case MultiPutByOffset: + for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { + PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; + const StructureSet& set = variant.oldStructure(); + for (unsigned j = set.size(); j--;) + visitor.appendUnbarrieredReadOnlyPointer(set[j]); + if (variant.kind() == PutByIdVariant::Transition) + visitor.appendUnbarrieredReadOnlyPointer(variant.newStructure()); + } break; default: @@ -870,6 +1204,156 @@ void Graph::visitChildren(SlotVisitor& visitor) } } +FrozenValue* Graph::freeze(JSValue value) +{ + if (UNLIKELY(!value)) + return FrozenValue::emptySingleton(); + + auto result = m_frozenValueMap.add(JSValue::encode(value), nullptr); + if (LIKELY(!result.isNewEntry)) + return result.iterator->value; + + if (value.isUInt32()) + m_uint32ValuesInUse.append(value.asUInt32()); + + FrozenValue frozenValue = FrozenValue::freeze(value); + if (Structure* structure = frozenValue.structure()) + registerStructure(structure); + + return result.iterator->value = m_frozenValues.add(frozenValue); +} + +FrozenValue* Graph::freezeStrong(JSValue value) +{ + FrozenValue* result = freeze(value); + result->strengthenTo(StrongValue); + return result; +} + +void Graph::convertToConstant(Node* node, FrozenValue* value) +{ + if (value->structure()) + assertIsRegistered(value->structure()); + node->convertToConstant(value); +} + +void Graph::convertToConstant(Node* node, JSValue value) +{ + convertToConstant(node, freeze(value)); +} + +void Graph::convertToStrongConstant(Node* node, JSValue value) +{ + convertToConstant(node, freezeStrong(value)); +} + +StructureRegistrationResult Graph::registerStructure(Structure* structure) +{ + m_plan.weakReferences.addLazily(structure); + if (m_plan.watchpoints.consider(structure)) + return StructureRegisteredAndWatched; + return StructureRegisteredNormally; +} + +void Graph::assertIsRegistered(Structure* structure) +{ + // It's convenient to be able to call this with a maybe-null structure. + if (!structure) + return; + + if (m_structureRegistrationState == HaveNotStartedRegistering) + return; + + DFG_ASSERT(*this, nullptr, m_plan.weakReferences.contains(structure)); + + if (!structure->dfgShouldWatch()) + return; + if (watchpoints().isWatched(structure->transitionWatchpointSet())) + return; + + DFG_CRASH(*this, nullptr, toCString("Structure ", pointerDump(structure), " is watchable but isn't being watched.").data()); +} + +NO_RETURN_DUE_TO_CRASH static void crash( + Graph& graph, const CString& whileText, const char* file, int line, const char* function, + const char* assertion) +{ + startCrashing(); + dataLog("DFG ASSERTION FAILED: ", assertion, "\n"); + dataLog(file, "(", line, ") : ", function, "\n"); + dataLog("\n"); + dataLog(whileText); + dataLog("Graph at time of failure:\n"); + graph.dump(); + dataLog("\n"); + dataLog("DFG ASSERTION FAILED: ", assertion, "\n"); + dataLog(file, "(", line, ") : ", function, "\n"); + CRASH_WITH_SECURITY_IMPLICATION(); +} + +void Graph::handleAssertionFailure( + std::nullptr_t, const char* file, int line, const char* function, const char* assertion) +{ + crash(*this, "", file, line, function, assertion); +} + +void Graph::handleAssertionFailure( + Node* node, const char* file, int line, const char* function, const char* assertion) +{ + crash(*this, toCString("While handling node ", node, "\n\n"), file, line, function, assertion); +} + +void Graph::handleAssertionFailure( + BasicBlock* block, const char* file, int line, const char* function, const char* assertion) +{ + crash(*this, toCString("While handling block ", pointerDump(block), "\n\n"), file, line, function, assertion); +} + +ValueProfile* Graph::valueProfileFor(Node* node) +{ + if (!node) + return nullptr; + + CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); + + if (node->hasLocal(*this)) { + if (!node->local().isArgument()) + return nullptr; + int argument = node->local().toArgument(); + Node* argumentNode = m_arguments[argument]; + if (!argumentNode) + return nullptr; + if (node->variableAccessData() != argumentNode->variableAccessData()) + return nullptr; + return profiledBlock->valueProfileForArgument(argument); + } + + if (node->hasHeapPrediction()) + return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); + + return nullptr; +} + +MethodOfGettingAValueProfile Graph::methodOfGettingAValueProfileFor(Node* node) +{ + if (!node) + return MethodOfGettingAValueProfile(); + + if (ValueProfile* valueProfile = valueProfileFor(node)) + return MethodOfGettingAValueProfile(valueProfile); + + if (node->op() == GetLocal) { + CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); + + return MethodOfGettingAValueProfile::fromLazyOperand( + profiledBlock, + LazyOperandValueProfileKey( + node->origin.semantic.bytecodeIndex, node->local())); + } + + return MethodOfGettingAValueProfile(); +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGGraph.h b/dfg/DFGGraph.h index aa1a854..e19ad1f 100644 --- a/dfg/DFGGraph.h +++ b/dfg/DFGGraph.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,16 +29,20 @@ #if ENABLE(DFG_JIT) #include "AssemblyHelpers.h" +#include "BytecodeLivenessAnalysisInlines.h" #include "CodeBlock.h" #include "DFGArgumentPosition.h" #include "DFGBasicBlock.h" #include "DFGDominators.h" +#include "DFGFrozenValue.h" #include "DFGLongLivedState.h" #include "DFGNaturalLoops.h" #include "DFGNode.h" #include "DFGNodeAllocator.h" #include "DFGPlan.h" +#include "DFGPrePostNumbering.h" #include "DFGScannable.h" +#include "FullBytecodeLiveness.h" #include "JSStack.h" #include "MethodOfGettingAValueProfile.h" #include <unordered_map> @@ -54,10 +58,47 @@ class ExecState; namespace DFG { -struct StorageAccessData { - PropertyOffset offset; - unsigned identifierNumber; -}; +#define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \ + Node* _node = (node); \ + if (_node->flags() & NodeHasVarArgs) { \ + for (unsigned _childIdx = _node->firstChild(); \ + _childIdx < _node->firstChild() + _node->numChildren(); \ + _childIdx++) { \ + if (!!(graph).m_varArgChildren[_childIdx]) \ + thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \ + } \ + } else { \ + if (!_node->child1()) { \ + ASSERT( \ + !_node->child2() \ + && !_node->child3()); \ + break; \ + } \ + thingToDo(_node, _node->child1()); \ + \ + if (!_node->child2()) { \ + ASSERT(!_node->child3()); \ + break; \ + } \ + thingToDo(_node, _node->child2()); \ + \ + if (!_node->child3()) \ + break; \ + thingToDo(_node, _node->child3()); \ + } \ + } while (false) + +#define DFG_ASSERT(graph, node, assertion) do { \ + if (!!(assertion)) \ + break; \ + (graph).handleAssertionFailure( \ + (node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \ + } while (false) + +#define DFG_CRASH(graph, node, reason) do { \ + (graph).handleAssertionFailure( \ + (node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, (reason)); \ + } while (false) struct InlineVariableData { InlineCallFrame* inlineCallFrame; @@ -124,7 +165,7 @@ public: return; // Check if there is any replacement. - Node* replacement = child->misc.replacement; + Node* replacement = child->replacement(); if (!replacement) return; @@ -132,7 +173,7 @@ public: // There is definitely a replacement. Assert that the replacement does not // have a replacement. - ASSERT(!child->misc.replacement); + ASSERT(!child->replacement()); } template<typename... Params> @@ -145,41 +186,21 @@ public: void dethread(); - void convertToConstant(Node* node, unsigned constantNumber) - { - if (node->op() == GetLocal) - dethread(); - else - ASSERT(!node->hasVariableAccessData(*this)); - node->convertToConstant(constantNumber); - } - - unsigned constantRegisterForConstant(JSValue value) - { - unsigned constantRegister; - if (!m_codeBlock->findConstant(value, constantRegister)) { - constantRegister = m_codeBlock->addConstantLazily(); - initializeLazyWriteBarrierForConstant( - m_plan.writeBarriers, - m_codeBlock->constants()[constantRegister], - m_codeBlock, - constantRegister, - m_codeBlock->ownerExecutable(), - value); - } - return constantRegister; - } + FrozenValue* freeze(JSValue); // We use weak freezing by default. + FrozenValue* freezeStrong(JSValue); // Shorthand for freeze(value)->strengthenTo(StrongValue). + + void convertToConstant(Node* node, FrozenValue* value); + void convertToConstant(Node* node, JSValue value); + void convertToStrongConstant(Node* node, JSValue value); + + StructureRegistrationResult registerStructure(Structure* structure); + void assertIsRegistered(Structure* structure); - void convertToConstant(Node* node, JSValue value) - { - if (value.isObject()) - node->convertToWeakConstant(value.asCell()); - else - convertToConstant(node, constantRegisterForConstant(value)); - } - // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names). void dump(PrintStream& = WTF::dataFile(), DumpContext* = 0); + + bool terminalsAreValid(); + enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis }; void dumpBlockHeader(PrintStream&, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*); void dump(PrintStream&, Edge); @@ -191,11 +212,6 @@ public: // preceding node. Returns true if anything was printed. bool dumpCodeOrigin(PrintStream&, const char* prefix, Node* previousNode, Node* currentNode, DumpContext*); - SpeculatedType getJSConstantSpeculation(Node* node) - { - return speculationFromValue(node->valueOfJSConstant(m_codeBlock)); - } - AddSpeculationMode addSpeculationMode(Node* add, bool leftShouldSpeculateInt32, bool rightShouldSpeculateInt32, PredictionPass pass) { ASSERT(add->op() == ValueAdd || add->op() == ArithAdd || add->op() == ArithSub); @@ -206,9 +222,9 @@ public: Node* right = add->child2().node(); if (left->hasConstant()) - return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, left, source); + return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, right, left, source); if (right->hasConstant()) - return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, right, source); + return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, left, right, source); return (leftShouldSpeculateInt32 && rightShouldSpeculateInt32 && add->canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32; } @@ -252,12 +268,7 @@ public: Node* left = add->child1().node(); Node* right = add->child2().node(); - bool speculation; - if (add->op() == ValueAdd) - speculation = Node::shouldSpeculateMachineInt(left, right); - else - speculation = Node::shouldSpeculateMachineInt(left, right); - + bool speculation = Node::shouldSpeculateMachineInt(left, right); return speculation && !hasExitSite(add, Int52Overflow); } @@ -303,100 +314,13 @@ public: && !hasExitSite(negate, Int52Overflow) && negate->canSpeculateInt52(pass); } - - VirtualRegister bytecodeRegisterForArgument(CodeOrigin codeOrigin, int argument) + + bool roundShouldSpeculateInt32(Node* arithRound, PredictionPass pass) { - return VirtualRegister( - codeOrigin.inlineCallFrame->stackOffset + - baselineCodeBlockFor(codeOrigin)->argumentIndexAfterCapture(argument)); + ASSERT(arithRound->op() == ArithRound); + return arithRound->canSpeculateInt32(pass) && !hasExitSite(arithRound->origin.semantic, Overflow) && !hasExitSite(arithRound->origin.semantic, NegativeZero); } - // Helper methods to check nodes for constants. - bool isConstant(Node* node) - { - return node->hasConstant(); - } - bool isJSConstant(Node* node) - { - return node->hasConstant(); - } - bool isInt32Constant(Node* node) - { - return node->isInt32Constant(m_codeBlock); - } - bool isDoubleConstant(Node* node) - { - return node->isDoubleConstant(m_codeBlock); - } - bool isNumberConstant(Node* node) - { - return node->isNumberConstant(m_codeBlock); - } - bool isMachineIntConstant(Node* node) - { - return node->isMachineIntConstant(m_codeBlock); - } - bool isBooleanConstant(Node* node) - { - return node->isBooleanConstant(m_codeBlock); - } - bool isCellConstant(Node* node) - { - if (!isJSConstant(node)) - return false; - JSValue value = valueOfJSConstant(node); - return value.isCell() && !!value; - } - bool isFunctionConstant(Node* node) - { - if (!isJSConstant(node)) - return false; - if (!getJSFunction(valueOfJSConstant(node))) - return false; - return true; - } - bool isInternalFunctionConstant(Node* node) - { - if (!isJSConstant(node)) - return false; - JSValue value = valueOfJSConstant(node); - if (!value.isCell() || !value) - return false; - JSCell* cell = value.asCell(); - if (!cell->inherits(InternalFunction::info())) - return false; - return true; - } - // Helper methods get constant values from nodes. - JSValue valueOfJSConstant(Node* node) - { - return node->valueOfJSConstant(m_codeBlock); - } - int32_t valueOfInt32Constant(Node* node) - { - JSValue value = valueOfJSConstant(node); - if (!value.isInt32()) { - dataLog("Value isn't int32: ", value, "\n"); - dump(); - RELEASE_ASSERT_NOT_REACHED(); - } - return value.asInt32(); - } - double valueOfNumberConstant(Node* node) - { - return valueOfJSConstant(node).asNumber(); - } - bool valueOfBooleanConstant(Node* node) - { - return valueOfJSConstant(node).asBoolean(); - } - JSFunction* valueOfFunctionConstant(Node* node) - { - JSCell* function = getJSFunction(valueOfJSConstant(node)); - ASSERT(function); - return jsCast<JSFunction*>(function); - } - static const char *opName(NodeType); StructureSet* addStructureSet(const StructureSet& structureSet) @@ -406,12 +330,6 @@ public: return &m_structureSet.last(); } - StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData) - { - m_structureTransitionData.append(structureTransitionData); - return &m_structureTransitionData.last(); - } - JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin) { return m_codeBlock->globalObjectFor(codeOrigin); @@ -448,6 +366,16 @@ public: return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock); } + SymbolTable* symbolTableFor(InlineCallFrame* inlineCallFrame) + { + return baselineCodeBlockFor(inlineCallFrame)->symbolTable(); + } + + SymbolTable* symbolTableFor(const CodeOrigin& codeOrigin) + { + return symbolTableFor(codeOrigin.inlineCallFrame); + } + bool isStrictModeFor(CodeOrigin codeOrigin) { if (!codeOrigin.inlineCallFrame) @@ -462,8 +390,7 @@ public: bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin) { - return m_plan.watchpoints.isStillValid( - globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()); + return globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid(); } bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind) @@ -481,60 +408,6 @@ public: return hasExitSite(node->origin.semantic, exitKind); } - bool usesArguments(InlineCallFrame* inlineCallFrame) - { - if (!inlineCallFrame) - return m_profiledBlock->usesArguments(); - - return baselineCodeBlockForInlineCallFrame(inlineCallFrame)->usesArguments(); - } - - VirtualRegister argumentsRegisterFor(InlineCallFrame* inlineCallFrame) - { - if (!inlineCallFrame) - return m_profiledBlock->argumentsRegister(); - - return VirtualRegister(baselineCodeBlockForInlineCallFrame( - inlineCallFrame)->argumentsRegister().offset() + - inlineCallFrame->stackOffset); - } - - VirtualRegister argumentsRegisterFor(const CodeOrigin& codeOrigin) - { - return argumentsRegisterFor(codeOrigin.inlineCallFrame); - } - - VirtualRegister machineArgumentsRegisterFor(InlineCallFrame* inlineCallFrame) - { - if (!inlineCallFrame) - return m_codeBlock->argumentsRegister(); - - return inlineCallFrame->argumentsRegister; - } - - VirtualRegister machineArgumentsRegisterFor(const CodeOrigin& codeOrigin) - { - return machineArgumentsRegisterFor(codeOrigin.inlineCallFrame); - } - - VirtualRegister uncheckedArgumentsRegisterFor(InlineCallFrame* inlineCallFrame) - { - if (!inlineCallFrame) - return m_profiledBlock->uncheckedArgumentsRegister(); - - CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); - if (!codeBlock->usesArguments()) - return VirtualRegister(); - - return VirtualRegister(codeBlock->argumentsRegister().offset() + - inlineCallFrame->stackOffset); - } - - VirtualRegister uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin) - { - return uncheckedArgumentsRegisterFor(codeOrigin.inlineCallFrame); - } - VirtualRegister activationRegister() { return m_profiledBlock->activationRegister(); @@ -555,54 +428,8 @@ public: return m_profiledBlock->uncheckedActivationRegister(); } - ValueProfile* valueProfileFor(Node* node) - { - if (!node) - return 0; - - CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); - - if (node->op() == GetArgument) - return profiledBlock->valueProfileForArgument(node->local().toArgument()); - - if (node->hasLocal(*this)) { - if (m_form == SSA) - return 0; - if (!node->local().isArgument()) - return 0; - int argument = node->local().toArgument(); - if (node->variableAccessData() != m_arguments[argument]->variableAccessData()) - return 0; - return profiledBlock->valueProfileForArgument(argument); - } - - if (node->hasHeapPrediction()) - return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); - - return 0; - } - - MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* node) - { - if (!node) - return MethodOfGettingAValueProfile(); - - CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); - - if (node->op() == GetLocal) { - return MethodOfGettingAValueProfile::fromLazyOperand( - profiledBlock, - LazyOperandValueProfileKey( - node->origin.semantic.bytecodeIndex, node->local())); - } - - return MethodOfGettingAValueProfile(valueProfileFor(node)); - } - - bool usesArguments() const - { - return m_codeBlock->usesArguments(); - } + ValueProfile* valueProfileFor(Node*); + MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node*); BlockIndex numBlocks() const { return m_blocks.size(); } BasicBlock* block(BlockIndex blockIndex) const { return m_blocks[blockIndex].get(); } @@ -616,7 +443,7 @@ public: void killBlock(BlockIndex blockIndex) { - m_blocks[blockIndex].clear(); + m_blocks[blockIndex] = nullptr; } void killBlock(BasicBlock* basicBlock) @@ -628,76 +455,10 @@ public: void killUnreachableBlocks(); - bool isPredictedNumerical(Node* node) - { - return isNumerical(node->child1().useKind()) && isNumerical(node->child2().useKind()); - } - - // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing. - // It really means that it will not clobber the entire world. It's still up to you to - // carefully consider things like: - // - PutByVal definitely changes the array it stores to, and may even change its length. - // - PutByOffset definitely changes the object it stores to. - // - and so on. - bool byValIsPure(Node* node) - { - 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(); - case Array::SlowPutArrayStorage: - return !node->arrayMode().mayStoreToHole(); - case Array::String: - return node->op() == GetByVal && node->arrayMode().isInBounds(); -#if USE(JSVALUE32_64) - case Array::Arguments: - if (node->op() == GetByVal) - return true; - return false; -#endif // USE(JSVALUE32_64) - default: - return true; - } - } - - bool clobbersWorld(Node* node) - { - if (node->flags() & NodeClobbersWorld) - return true; - if (!(node->flags() & NodeMightClobber)) - return false; - switch (node->op()) { - case GetByVal: - case PutByValDirect: - case PutByVal: - case PutByValAlias: - return !byValIsPure(node); - case ToString: - switch (node->child1().useKind()) { - case StringObjectUse: - case StringOrStringObjectUse: - return false; - case CellUse: - case UntypedUse: - return true; - default: - RELEASE_ASSERT_NOT_REACHED(); - return true; - } - default: - RELEASE_ASSERT_NOT_REACHED(); - return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst. - } - } - void determineReachability(); void resetReachability(); - void resetExitStates(); + void computeRefCounts(); unsigned varArgNumChildren(Node* node) { @@ -803,34 +564,234 @@ public: void clearFlagsOnAllNodes(NodeFlags); void clearReplacements(); + void clearEpochs(); void initializeNodeOwners(); - void getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result); + BlockList blocksInPreOrder(); + BlockList blocksInPostOrder(); + + class NaturalBlockIterable { + public: + NaturalBlockIterable() + : m_graph(nullptr) + { + } + + NaturalBlockIterable(Graph& graph) + : m_graph(&graph) + { + } + + class iterator { + public: + iterator() + : m_graph(nullptr) + , m_index(0) + { + } + + iterator(Graph& graph, BlockIndex index) + : m_graph(&graph) + , m_index(findNext(index)) + { + } + + BasicBlock *operator*() + { + return m_graph->block(m_index); + } + + iterator& operator++() + { + m_index = findNext(m_index + 1); + return *this; + } + + bool operator==(const iterator& other) const + { + return m_index == other.m_index; + } + + bool operator!=(const iterator& other) const + { + return !(*this == other); + } + + private: + BlockIndex findNext(BlockIndex index) + { + while (index < m_graph->numBlocks() && !m_graph->block(index)) + index++; + return index; + } + + Graph* m_graph; + BlockIndex m_index; + }; + + iterator begin() + { + return iterator(*m_graph, 0); + } + + iterator end() + { + return iterator(*m_graph, m_graph->numBlocks()); + } + + private: + Graph* m_graph; + }; + + NaturalBlockIterable blocksInNaturalOrder() + { + return NaturalBlockIterable(*this); + } + + template<typename ChildFunctor> + void doToChildrenWithNode(Node* node, const ChildFunctor& functor) + { + DFG_NODE_DO_TO_CHILDREN(*this, node, functor); + } + + template<typename ChildFunctor> + void doToChildren(Node* node, const ChildFunctor& functor) + { + doToChildrenWithNode( + node, + [&functor] (Node*, Edge& edge) { + functor(edge); + }); + } + + bool uses(Node* node, Node* child) + { + bool result = false; + doToChildren(node, [&] (Edge edge) { result |= edge == child; }); + return result; + } Profiler::Compilation* compilation() { return m_plan.compilation.get(); } DesiredIdentifiers& identifiers() { return m_plan.identifiers; } DesiredWatchpoints& watchpoints() { return m_plan.watchpoints; } - DesiredStructureChains& chains() { return m_plan.chains; } FullBytecodeLiveness& livenessFor(CodeBlock*); FullBytecodeLiveness& livenessFor(InlineCallFrame*); + + // Quickly query if a single local is live at the given point. This is faster than calling + // forAllLiveInBytecode() if you will only query one local. But, if you want to know all of the + // locals live, then calling this for each local is much slower than forAllLiveInBytecode(). bool isLiveInBytecode(VirtualRegister, CodeOrigin); + // Quickly get all of the non-argument locals live at the given point. This doesn't give you + // any arguments because those are all presumed live. You can call forAllLiveInBytecode() to + // also get the arguments. This is much faster than calling isLiveInBytecode() for each local. + template<typename Functor> + void forAllLocalsLiveInBytecode(CodeOrigin codeOrigin, const Functor& functor) + { + // Support for not redundantly reporting arguments. Necessary because in case of a varargs + // call, only the callee knows that arguments are live while in the case of a non-varargs + // call, both callee and caller will see the variables live. + VirtualRegister exclusionStart; + VirtualRegister exclusionEnd; + + for (;;) { + InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; + VirtualRegister stackOffset(inlineCallFrame ? inlineCallFrame->stackOffset : 0); + + if (inlineCallFrame) { + if (inlineCallFrame->isClosureCall) + functor(stackOffset + JSStack::Callee); + if (inlineCallFrame->isVarargs()) + functor(stackOffset + JSStack::ArgumentCount); + } + + CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame); + FullBytecodeLiveness& fullLiveness = livenessFor(codeBlock); + const FastBitVector& liveness = fullLiveness.getLiveness(codeOrigin.bytecodeIndex); + for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) { + VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal); + + // Don't report if our callee already reported. + if (reg >= exclusionStart && reg < exclusionEnd) + continue; + + if (liveness.get(relativeLocal)) + functor(reg); + } + + if (!inlineCallFrame) + break; + + // Arguments are always live. This would be redundant if it wasn't for our + // op_call_varargs inlining. See the comment above. + exclusionStart = stackOffset + CallFrame::argumentOffsetIncludingThis(0); + exclusionEnd = stackOffset + CallFrame::argumentOffsetIncludingThis(inlineCallFrame->arguments.size()); + + // We will always have a "this" argument and exclusionStart should be a smaller stack + // offset than exclusionEnd. + ASSERT(exclusionStart < exclusionEnd); + + for (VirtualRegister reg = exclusionStart; reg < exclusionEnd; reg += 1) + functor(reg); + + codeOrigin = inlineCallFrame->caller; + } + } + + // Get a BitVector of all of the non-argument locals live right now. This is mostly useful if + // you want to compare two sets of live locals from two different CodeOrigins. + BitVector localsLiveInBytecode(CodeOrigin); + + // Tells you all of the arguments and locals live at the given CodeOrigin. This is a small + // extension to forAllLocalsLiveInBytecode(), since all arguments are always presumed live. + template<typename Functor> + void forAllLiveInBytecode(CodeOrigin codeOrigin, const Functor& functor) + { + forAllLocalsLiveInBytecode(codeOrigin, functor); + + // Report all arguments as being live. + for (unsigned argument = block(0)->variablesAtHead.numberOfArguments(); argument--;) + functor(virtualRegisterForArgument(argument)); + } + + BytecodeKills& killsFor(CodeBlock*); + BytecodeKills& killsFor(InlineCallFrame*); + unsigned frameRegisterCount(); unsigned stackPointerOffset(); unsigned requiredRegisterCountForExit(); unsigned requiredRegisterCountForExecutionAndExit(); - JSActivation* tryGetActivation(Node*); - WriteBarrierBase<Unknown>* tryGetRegisters(Node*); + JSValue tryGetConstantProperty(JSValue base, const StructureSet&, PropertyOffset); + JSValue tryGetConstantProperty(JSValue base, Structure*, PropertyOffset); + JSValue tryGetConstantProperty(JSValue base, const StructureAbstractValue&, PropertyOffset); + JSValue tryGetConstantProperty(const AbstractValue&, PropertyOffset); + + JSValue tryGetConstantClosureVar(JSValue base, ScopeOffset); + JSValue tryGetConstantClosureVar(const AbstractValue&, ScopeOffset); + JSValue tryGetConstantClosureVar(Node*, ScopeOffset); - JSArrayBufferView* tryGetFoldableView(Node*); - JSArrayBufferView* tryGetFoldableView(Node*, ArrayMode); - JSArrayBufferView* tryGetFoldableViewForChild1(Node*); + JSArrayBufferView* tryGetFoldableView(JSValue); + JSArrayBufferView* tryGetFoldableView(JSValue, ArrayMode arrayMode); + + void registerFrozenValues(); virtual void visitChildren(SlotVisitor&) override; + NO_RETURN_DUE_TO_CRASH void handleAssertionFailure( + std::nullptr_t, const char* file, int line, const char* function, + const char* assertion); + NO_RETURN_DUE_TO_CRASH void handleAssertionFailure( + Node*, const char* file, int line, const char* function, + const char* assertion); + NO_RETURN_DUE_TO_CRASH void handleAssertionFailure( + BasicBlock*, const char* file, int line, const char* function, + const char* assertion); + + bool hasDebuggerEnabled() const { return m_hasDebuggerEnabled; } + VM& m_vm; Plan& m_plan; CodeBlock* m_codeBlock; @@ -838,33 +799,68 @@ public: NodeAllocator& m_allocator; - Operands<AbstractValue> m_mustHandleAbstractValues; - Vector< RefPtr<BasicBlock> , 8> m_blocks; Vector<Edge, 16> m_varArgChildren; - Vector<StorageAccessData> m_storageAccessData; + + HashMap<EncodedJSValue, FrozenValue*, EncodedJSValueHash, EncodedJSValueHashTraits> m_frozenValueMap; + Bag<FrozenValue> m_frozenValues; + + Vector<uint32_t> m_uint32ValuesInUse; + + Bag<StorageAccessData> m_storageAccessData; + + // In CPS, this is all of the SetArgument nodes for the arguments in the machine code block + // that survived DCE. All of them except maybe "this" will survive DCE, because of the Flush + // nodes. + // + // In SSA, this is all of the GetStack nodes for the arguments in the machine code block that + // may have some speculation in the prologue and survived DCE. Note that to get the speculation + // for an argument in SSA, you must use m_argumentFormats, since we still have to speculate + // even if the argument got killed. For example: + // + // function foo(x) { + // var tmp = x + 1; + // } + // + // Assume that x is always int during profiling. The ArithAdd for "x + 1" will be dead and will + // have a proven check for the edge to "x". So, we will not insert a Check node and we will + // kill the GetStack for "x". But, we must do the int check in the progolue, because that's the + // thing we used to allow DCE of ArithAdd. Otherwise the add could be impure: + // + // var o = { + // valueOf: function() { do side effects; } + // }; + // foo(o); + // + // If we DCE the ArithAdd and we remove the int check on x, then this won't do the side + // effects. Vector<Node*, 8> m_arguments; + + // In CPS, this is meaningless. In SSA, this is the argument speculation that we've locked in. + Vector<FlushFormat> m_argumentFormats; + SegmentedVector<VariableAccessData, 16> m_variableAccessData; SegmentedVector<ArgumentPosition, 8> m_argumentPositions; SegmentedVector<StructureSet, 16> m_structureSet; - SegmentedVector<StructureTransitionData, 8> m_structureTransitionData; + Bag<Transition> m_transitions; SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData; Bag<BranchData> m_branchData; Bag<SwitchData> m_switchData; Bag<MultiGetByOffsetData> m_multiGetByOffsetData; Bag<MultiPutByOffsetData> m_multiPutByOffsetData; + Bag<ObjectMaterializationData> m_objectMaterializationData; + Bag<CallVarargsData> m_callVarargsData; + Bag<LoadVarargsData> m_loadVarargsData; + Bag<StackAccessData> m_stackAccessData; Vector<InlineVariableData, 4> m_inlineVariableData; HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness; - bool m_hasArguments; - HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped; - BitVector m_lazyVars; + HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>> m_bytecodeKills; Dominators m_dominators; + PrePostNumbering m_prePostNumbering; NaturalLoops m_naturalLoops; unsigned m_localVars; unsigned m_nextMachineLocal; unsigned m_parameterSlots; - int m_machineCaptureStart; - std::unique_ptr<SlowArgument[]> m_slowArguments; #if USE(JSVALUE32_64) std::unordered_map<int64_t, double*> m_doubleConstantsMap; @@ -872,26 +868,34 @@ public: #endif OptimizationFixpointState m_fixpointState; + StructureRegistrationState m_structureRegistrationState; GraphForm m_form; UnificationState m_unificationState; + PlanStage m_planStage { PlanStage::Initial }; RefCountState m_refCountState; + bool m_hasDebuggerEnabled; private: void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor); - void addForDepthFirstSort(Vector<BasicBlock*>& result, Vector<BasicBlock*, 16>& worklist, HashSet<BasicBlock*>& seen, BasicBlock*); - AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate, RareCaseProfilingSource source) + AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* operand, Node*immediate, RareCaseProfilingSource source) { ASSERT(immediate->hasConstant()); - JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock); + JSValue immediateValue = immediate->asJSValue(); if (!immediateValue.isNumber() && !immediateValue.isBoolean()) return DontSpeculateInt32; if (!variableShouldSpeculateInt32) return DontSpeculateInt32; + + // Integer constants can be typed Double if they are written like a double in the source code (e.g. 42.0). + // In that case, we stay conservative unless the other operand was explicitly typed as integer. + NodeFlags operandResultType = operand->result(); + if (operandResultType != NodeResultInt32 && immediateValue.isDouble()) + return DontSpeculateInt32; - if (immediateValue.isInt32() || immediateValue.isBoolean()) + if (immediateValue.isBoolean() || jsNumber(immediateValue.asNumber()).isInt32()) return add->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32; double doubleImmediate = immediateValue.asDouble(); @@ -903,36 +907,6 @@ private: } }; -#define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \ - Node* _node = (node); \ - if (_node->flags() & NodeHasVarArgs) { \ - for (unsigned _childIdx = _node->firstChild(); \ - _childIdx < _node->firstChild() + _node->numChildren(); \ - _childIdx++) { \ - if (!!(graph).m_varArgChildren[_childIdx]) \ - thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \ - } \ - } else { \ - if (!_node->child1()) { \ - ASSERT( \ - !_node->child2() \ - && !_node->child3()); \ - break; \ - } \ - thingToDo(_node, _node->child1()); \ - \ - if (!_node->child2()) { \ - ASSERT(!_node->child3()); \ - break; \ - } \ - thingToDo(_node, _node->child2()); \ - \ - if (!_node->child3()) \ - break; \ - thingToDo(_node, _node->child3()); \ - } \ - } while (false) - } } // namespace JSC::DFG #endif diff --git a/dfg/DFGHeapLocation.cpp b/dfg/DFGHeapLocation.cpp new file mode 100644 index 0000000..2ca344a --- /dev/null +++ b/dfg/DFGHeapLocation.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGHeapLocation.h" + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +void HeapLocation::dump(PrintStream& out) const +{ + out.print(m_kind, ":", m_heap); + + if (!m_base) + return; + + out.print("[", m_base); + if (m_index) + out.print(", ", m_index); + out.print("]"); +} + +} } // namespace JSC::DFG + +namespace WTF { + +using namespace JSC::DFG; + +void printInternal(PrintStream& out, LocationKind kind) +{ + switch (kind) { + case InvalidLocationKind: + out.print("InvalidLocationKind"); + return; + + case InvalidationPointLoc: + out.print("InvalidationPointLoc"); + return; + + case IsObjectOrNullLoc: + out.print("IsObjectOrNullLoc"); + return; + + case IsFunctionLoc: + out.print("IsFunctionLoc"); + return; + + case GetterLoc: + out.print("GetterLoc"); + return; + + case SetterLoc: + out.print("SetterLoc"); + return; + + case StackLoc: + out.print("StackLoc"); + return; + + case StackPayloadLoc: + out.print("StackPayloadLoc"); + return; + + case ArrayLengthLoc: + out.print("ArrayLengthLoc"); + return; + + case ButterflyLoc: + out.print("ButterflyLoc"); + return; + + case CheckHasInstanceLoc: + out.print("CheckHasInstanceLoc"); + return; + + case ClosureVariableLoc: + out.print("ClosureVariableLoc"); + return; + + case DirectArgumentsLoc: + out.print("DirectArgumentsLoc"); + return; + + case GlobalVariableLoc: + out.print("GlobalVariableLoc"); + return; + + case HasIndexedPropertyLoc: + out.print("HasIndexedPorpertyLoc"); + return; + + case IndexedPropertyLoc: + out.print("IndexedPorpertyLoc"); + return; + + case IndexedPropertyStorageLoc: + out.print("IndexedPropertyStorageLoc"); + return; + + case InstanceOfLoc: + out.print("InstanceOfLoc"); + return; + + case NamedPropertyLoc: + out.print("NamedPropertyLoc"); + return; + + case TypedArrayByteOffsetLoc: + out.print("TypedArrayByteOffsetLoc"); + return; + + case VarInjectionWatchpointLoc: + out.print("VarInjectionWatchpointLoc"); + return; + + case StructureLoc: + out.print("StructureLoc"); + return; + } + + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGHeapLocation.h b/dfg/DFGHeapLocation.h new file mode 100644 index 0000000..3d3a94c --- /dev/null +++ b/dfg/DFGHeapLocation.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2014, 2015 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 DFGHeapLocation_h +#define DFGHeapLocation_h + +#if ENABLE(DFG_JIT) + +#include "DFGAbstractHeap.h" +#include "DFGLazyNode.h" +#include "DFGNode.h" + +namespace JSC { namespace DFG { + +enum LocationKind { + InvalidLocationKind, + + ArrayLengthLoc, + ButterflyLoc, + CheckHasInstanceLoc, + ClosureVariableLoc, + DirectArgumentsLoc, + GetterLoc, + GlobalVariableLoc, + HasIndexedPropertyLoc, + IndexedPropertyLoc, + IndexedPropertyStorageLoc, + InstanceOfLoc, + InvalidationPointLoc, + IsFunctionLoc, + IsObjectOrNullLoc, + NamedPropertyLoc, + SetterLoc, + StructureLoc, + TypedArrayByteOffsetLoc, + VarInjectionWatchpointLoc, + StackLoc, + StackPayloadLoc +}; + +class HeapLocation { +public: + HeapLocation( + LocationKind kind = InvalidLocationKind, + AbstractHeap heap = AbstractHeap(), + Node* base = nullptr, LazyNode index = LazyNode()) + : m_kind(kind) + , m_heap(heap) + , m_base(base) + , m_index(index) + { + ASSERT((kind == InvalidLocationKind) == !heap); + ASSERT(!!m_heap || !m_base); + ASSERT(m_base || !m_index); + } + + HeapLocation(LocationKind kind, AbstractHeap heap, Node* base, Node* index) + : HeapLocation(kind, heap, base, LazyNode(index)) + { + } + + HeapLocation(LocationKind kind, AbstractHeap heap, Edge base, Edge index = Edge()) + : HeapLocation(kind, heap, base.node(), index.node()) + { + } + + HeapLocation(WTF::HashTableDeletedValueType) + : m_kind(InvalidLocationKind) + , m_heap(WTF::HashTableDeletedValue) + , m_base(nullptr) + , m_index(nullptr) + { + } + + bool operator!() const { return !m_heap; } + + LocationKind kind() const { return m_kind; } + AbstractHeap heap() const { return m_heap; } + Node* base() const { return m_base; } + LazyNode index() const { return m_index; } + + unsigned hash() const + { + return m_kind + m_heap.hash() + m_index.hash() + m_kind; + } + + bool operator==(const HeapLocation& other) const + { + return m_kind == other.m_kind + && m_heap == other.m_heap + && m_base == other.m_base + && m_index == other.m_index; + } + + bool isHashTableDeletedValue() const + { + return m_heap.isHashTableDeletedValue(); + } + + void dump(PrintStream& out) const; + +private: + LocationKind m_kind; + AbstractHeap m_heap; + Node* m_base; + LazyNode m_index; +}; + +struct HeapLocationHash { + static unsigned hash(const HeapLocation& key) { return key.hash(); } + static bool equal(const HeapLocation& a, const HeapLocation& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} } // namespace JSC::DFG + +namespace WTF { + +void printInternal(PrintStream&, JSC::DFG::LocationKind); + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::DFG::HeapLocation> { + typedef JSC::DFG::HeapLocationHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::DFG::HeapLocation> : SimpleClassHashTraits<JSC::DFG::HeapLocation> { + static const bool emptyValueIsZero = false; +}; + +} // namespace WTF + +namespace JSC { namespace DFG { + +typedef HashMap<HeapLocation, LazyNode> ImpureMap; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGHeapLocation_h + diff --git a/dfg/DFGInPlaceAbstractState.cpp b/dfg/DFGInPlaceAbstractState.cpp index 1121305..b1269c1 100644 --- a/dfg/DFGInPlaceAbstractState.cpp +++ b/dfg/DFGInPlaceAbstractState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,6 +37,8 @@ namespace JSC { namespace DFG { +static const bool verbose = false; + InPlaceAbstractState::InPlaceAbstractState(Graph& graph) : m_graph(graph) , m_variables(m_graph.m_codeBlock->numParameters(), graph.m_localVars) @@ -58,36 +60,20 @@ void InPlaceAbstractState::beginBasicBlock(BasicBlock* basicBlock) forNode(basicBlock->at(i)).clear(); m_variables = basicBlock->valuesAtHead; - m_haveStructures = false; - for (size_t i = 0; i < m_variables.numberOfArguments(); ++i) { - if (m_variables.argument(i).hasClobberableState()) { - m_haveStructures = true; - break; - } - } - for (size_t i = 0; i < m_variables.numberOfLocals(); ++i) { - if (m_variables.local(i).hasClobberableState()) { - m_haveStructures = true; - break; - } - } if (m_graph.m_form == SSA) { HashMap<Node*, AbstractValue>::iterator iter = basicBlock->ssa->valuesAtHead.begin(); HashMap<Node*, AbstractValue>::iterator end = basicBlock->ssa->valuesAtHead.end(); - for (; iter != end; ++iter) { + for (; iter != end; ++iter) forNode(iter->key) = iter->value; - if (iter->value.hasClobberableState()) - m_haveStructures = true; - } } - basicBlock->cfaShouldRevisit = false; basicBlock->cfaHasVisited = true; m_block = basicBlock; m_isValid = true; m_foundConstants = false; m_branchDirection = InvalidBranchDirection; + m_structureClobberState = basicBlock->cfaStructureClobberStateAtHead; } static void setLiveValues(HashMap<Node*, AbstractValue>& values, HashSet<Node*>& live) @@ -106,37 +92,44 @@ void InPlaceAbstractState::initialize() root->cfaShouldRevisit = true; root->cfaHasVisited = false; root->cfaFoundConstants = false; + root->cfaStructureClobberStateAtHead = StructuresAreWatched; + root->cfaStructureClobberStateAtTail = StructuresAreWatched; for (size_t i = 0; i < root->valuesAtHead.numberOfArguments(); ++i) { root->valuesAtTail.argument(i).clear(); - if (m_graph.m_form == SSA) { - root->valuesAtHead.argument(i).makeHeapTop(); - continue; - } - - Node* node = root->variablesAtHead.argument(i); - ASSERT(node->op() == SetArgument); - if (!node->variableAccessData()->shouldUnboxIfPossible()) { - root->valuesAtHead.argument(i).makeHeapTop(); - continue; + + FlushFormat format; + if (m_graph.m_form == SSA) + format = m_graph.m_argumentFormats[i]; + else { + Node* node = m_graph.m_arguments[i]; + if (!node) + format = FlushedJSValue; + else { + ASSERT(node->op() == SetArgument); + format = node->variableAccessData()->flushFormat(); + } } - SpeculatedType prediction = - node->variableAccessData()->argumentAwarePrediction(); - if (isInt32Speculation(prediction)) + switch (format) { + case FlushedInt32: root->valuesAtHead.argument(i).setType(SpecInt32); - else if (isBooleanSpeculation(prediction)) + break; + case FlushedBoolean: root->valuesAtHead.argument(i).setType(SpecBoolean); - else if (isCellSpeculation(prediction)) - root->valuesAtHead.argument(i).setType(SpecCell); - else + break; + case FlushedCell: + root->valuesAtHead.argument(i).setType(m_graph, SpecCell); + break; + case FlushedJSValue: root->valuesAtHead.argument(i).makeHeapTop(); + break; + default: + DFG_CRASH(m_graph, nullptr, "Bad flush format for argument"); + break; + } } for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) { - Node* node = root->variablesAtHead.local(i); - if (node && node->variableAccessData()->isCaptured()) - root->valuesAtHead.local(i).makeHeapTop(); - else - root->valuesAtHead.local(i).clear(); + root->valuesAtHead.local(i).clear(); root->valuesAtTail.local(i).clear(); } for (BlockIndex blockIndex = 1 ; blockIndex < m_graph.numBlocks(); ++blockIndex) { @@ -147,6 +140,8 @@ void InPlaceAbstractState::initialize() block->cfaShouldRevisit = false; block->cfaHasVisited = false; block->cfaFoundConstants = false; + block->cfaStructureClobberStateAtHead = StructuresAreWatched; + block->cfaStructureClobberStateAtTail = StructuresAreWatched; for (size_t i = 0; i < block->valuesAtHead.numberOfArguments(); ++i) { block->valuesAtHead.argument(i).clear(); block->valuesAtTail.argument(i).clear(); @@ -155,25 +150,6 @@ void InPlaceAbstractState::initialize() block->valuesAtHead.local(i).clear(); block->valuesAtTail.local(i).clear(); } - if (m_graph.m_form == SSA) - continue; - if (!block->isOSRTarget) - continue; - if (block->bytecodeBegin != m_graph.m_plan.osrEntryBytecodeIndex) - continue; - for (size_t i = 0; i < m_graph.m_mustHandleAbstractValues.size(); ++i) { - int operand = m_graph.m_mustHandleAbstractValues.operandForIndex(i); - Node* node = block->variablesAtHead.operand(operand); - if (!node) - continue; - AbstractValue value = m_graph.m_mustHandleAbstractValues[i]; - AbstractValue& abstractValue = block->valuesAtHead.operand(operand); - VariableAccessData* variable = node->variableAccessData(); - FlushFormat format = variable->flushFormat(); - abstractValue.merge(value); - abstractValue.fixTypeForRepresentation(resultFor(format)); - } - block->cfaShouldRevisit = true; } if (m_graph.m_form == SSA) { for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { @@ -203,7 +179,9 @@ bool InPlaceAbstractState::endBasicBlock(MergeMode mergeMode) bool changed = false; - if (mergeMode != DontMerge || !ASSERT_DISABLED) { + if ((mergeMode != DontMerge) || !ASSERT_DISABLED) { + changed |= checkAndSet(block->cfaStructureClobberStateAtTail, m_structureClobberState); + switch (m_graph.m_form) { case ThreadedCPS: { for (size_t argument = 0; argument < block->variablesAtTail.numberOfArguments(); ++argument) { @@ -251,6 +229,7 @@ void InPlaceAbstractState::reset() m_block = 0; m_isValid = false; m_branchDirection = InvalidBranchDirection; + m_structureClobberState = StructuresAreWatched; } bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node* node) @@ -260,40 +239,31 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract AbstractValue source; - if (node->variableAccessData()->isCaptured()) { - // If it's captured then we know that whatever value was stored into the variable last is the - // one we care about. This is true even if the variable at tail is dead, which might happen if - // the last thing we did to the variable was a GetLocal and then ended up not using the - // GetLocal's result. - + switch (node->op()) { + case Phi: + case SetArgument: + case PhantomLocal: + case Flush: + // The block transfers the value from head to tail. source = inVariable; - } else { - switch (node->op()) { - case Phi: - case SetArgument: - case PhantomLocal: - case Flush: - // The block transfers the value from head to tail. - source = inVariable; - break; + break; - case GetLocal: - // The block refines the value with additional speculations. - source = forNode(node); - break; + case GetLocal: + // The block refines the value with additional speculations. + source = forNode(node); + break; - case SetLocal: - // The block sets the variable, and potentially refines it, both - // before and after setting it. - source = forNode(node->child1()); - if (node->variableAccessData()->flushFormat() == FlushedDouble) - RELEASE_ASSERT(!(source.m_type & ~SpecFullDouble)); - break; + case SetLocal: + // The block sets the variable, and potentially refines it, both + // before and after setting it. + source = forNode(node->child1()); + if (node->variableAccessData()->flushFormat() == FlushedDouble) + RELEASE_ASSERT(!(source.m_type & ~SpecFullDouble)); + break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } + default: + RELEASE_ASSERT_NOT_REACHED(); + break; } if (destination == source) { @@ -311,11 +281,17 @@ bool InPlaceAbstractState::mergeStateAtTail(AbstractValue& destination, Abstract bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to) { + if (verbose) + dataLog(" Merging from ", pointerDump(from), " to ", pointerDump(to), "\n"); ASSERT(from->variablesAtTail.numberOfArguments() == to->variablesAtHead.numberOfArguments()); ASSERT(from->variablesAtTail.numberOfLocals() == to->variablesAtHead.numberOfLocals()); bool changed = false; + changed |= checkAndSet( + to->cfaStructureClobberStateAtHead, + DFG::merge(from->cfaStructureClobberStateAtTail, to->cfaStructureClobberStateAtHead)); + switch (m_graph.m_form) { case ThreadedCPS: { for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) { @@ -338,8 +314,12 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to) HashSet<Node*>::iterator end = to->ssa->liveAtHead.end(); for (; iter != end; ++iter) { Node* node = *iter; + if (verbose) + dataLog(" Merging for ", node, ": from ", from->ssa->valuesAtTail.find(node)->value, " to ", to->ssa->valuesAtHead.find(node)->value, "\n"); changed |= to->ssa->valuesAtHead.find(node)->value.merge( from->ssa->valuesAtTail.find(node)->value); + if (verbose) + dataLog(" Result: ", to->ssa->valuesAtHead.find(node)->value, "\n"); } break; } @@ -352,6 +332,8 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to) if (!to->cfaHasVisited) changed = true; + if (verbose) + dataLog(" Will revisit: ", changed, "\n"); to->cfaShouldRevisit |= changed; return changed; @@ -359,7 +341,7 @@ bool InPlaceAbstractState::merge(BasicBlock* from, BasicBlock* to) inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock) { - Node* terminal = basicBlock->last(); + Node* terminal = basicBlock->terminal(); ASSERT(terminal->isTerminal()); diff --git a/dfg/DFGInPlaceAbstractState.h b/dfg/DFGInPlaceAbstractState.h index 48da3aa..297418f 100644 --- a/dfg/DFGInPlaceAbstractState.h +++ b/dfg/DFGInPlaceAbstractState.h @@ -103,6 +103,9 @@ public: // Did the last executed node clobber the world? bool didClobber() const { return m_didClobber; } + // Are structures currently clobbered? + StructureClobberState structureClobberState() const { return m_structureClobberState; } + // Is the execution state still valid? This will be false if execute() has // returned false previously. bool isValid() const { return m_isValid; } @@ -122,11 +125,16 @@ public: // Methods intended to be called from AbstractInterpreter. void setDidClobber(bool didClobber) { m_didClobber = didClobber; } + void setStructureClobberState(StructureClobberState value) { m_structureClobberState = value; } void setIsValid(bool isValid) { m_isValid = isValid; } void setBranchDirection(BranchDirection branchDirection) { m_branchDirection = branchDirection; } + + // This method is evil - it causes a huge maintenance headache and there is a gross amount of + // code devoted to it. It would be much nicer to just always run the constant folder on each + // block. But, the last time we did it, it was a 1% SunSpider regression: + // https://bugs.webkit.org/show_bug.cgi?id=133947 + // So, we should probably keep this method. void setFoundConstants(bool foundConstants) { m_foundConstants = foundConstants; } - bool haveStructures() const { return m_haveStructures; } // It's always safe to return true. - void setHaveStructures(bool haveStructures) { m_haveStructures = haveStructures; } private: bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, Node*); @@ -138,11 +146,11 @@ private: Operands<AbstractValue> m_variables; BasicBlock* m_block; - bool m_haveStructures; bool m_foundConstants; bool m_isValid; bool m_didClobber; + StructureClobberState m_structureClobberState; BranchDirection m_branchDirection; // This is only set for blocks that end in Branch and that execute to completion (i.e. m_isValid == true). }; diff --git a/dfg/DFGInsertOSRHintsForUpdate.cpp b/dfg/DFGInsertOSRHintsForUpdate.cpp new file mode 100644 index 0000000..a187678 --- /dev/null +++ b/dfg/DFGInsertOSRHintsForUpdate.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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 "DFGInsertOSRHintsForUpdate.h" + +#if ENABLE(DFG_JIT) + +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +void insertOSRHintsForUpdate( + InsertionSet& insertionSet, unsigned nodeIndex, NodeOrigin origin, + AvailabilityMap& availability, Node* originalNode, Node* newNode) +{ + for (unsigned i = availability.m_locals.size(); i--;) { + int operand = availability.m_locals.operandForIndex(i); + + if (availability.m_locals[i].hasNode() && availability.m_locals[i].node() == originalNode) { + insertionSet.insertNode( + nodeIndex, SpecNone, MovHint, origin, OpInfo(operand), + newNode->defaultEdge()); + } + } + + for (auto pair : availability.m_heap) { + if (pair.value.hasNode() && pair.value.node() == originalNode) { + insertionSet.insert( + nodeIndex, pair.key.createHint(insertionSet.graph(), origin, newNode)); + } + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGInsertOSRHintsForUpdate.h b/dfg/DFGInsertOSRHintsForUpdate.h new file mode 100644 index 0000000..4e42b49 --- /dev/null +++ b/dfg/DFGInsertOSRHintsForUpdate.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 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 DFGInsertOSRHintsForUpdate_h +#define DFGInsertOSRHintsForUpdate_h + +#if ENABLE(DFG_JIT) + +#include "DFGAvailabilityMap.h" +#include "DFGInsertionSet.h" + +namespace JSC { namespace DFG { + +void insertOSRHintsForUpdate( + InsertionSet&, unsigned nodeIndex, NodeOrigin, AvailabilityMap&, + Node* originalNode, Node* newNode); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGInsertOSRHintsForUpdate_h + diff --git a/dfg/DFGInsertionSet.h b/dfg/DFGInsertionSet.h index a44616b..c5ed4c2 100644 --- a/dfg/DFGInsertionSet.h +++ b/dfg/DFGInsertionSet.h @@ -43,6 +43,8 @@ public: { } + Graph& graph() { return m_graph; } + Node* insert(const Insertion& insertion) { ASSERT(!m_insertions.size() || m_insertions.last().index() <= insertion.index()); @@ -62,23 +64,21 @@ public: } Node* insertConstant( - size_t index, NodeOrigin origin, JSValue value, + size_t index, NodeOrigin origin, FrozenValue* value, NodeType op = JSConstant) { - unsigned constantReg = - m_graph.constantRegisterForConstant(value); return insertNode( - index, speculationFromValue(value), op, origin, OpInfo(constantReg)); + index, speculationFromValue(value->value()), op, origin, OpInfo(value)); } Node* insertConstant( - size_t index, CodeOrigin origin, JSValue value, NodeType op = JSConstant) + size_t index, CodeOrigin origin, FrozenValue* value, NodeType op = JSConstant) { return insertConstant(index, NodeOrigin(origin), value, op); } Edge insertConstantForUse( - size_t index, NodeOrigin origin, JSValue value, UseKind useKind) + size_t index, NodeOrigin origin, FrozenValue* value, UseKind useKind) { NodeType op; if (isDouble(useKind)) @@ -91,11 +91,60 @@ public: } Edge insertConstantForUse( - size_t index, CodeOrigin origin, JSValue value, UseKind useKind) + size_t index, CodeOrigin origin, FrozenValue* value, UseKind useKind) { return insertConstantForUse(index, NodeOrigin(origin), value, useKind); } + Node* insertConstant(size_t index, NodeOrigin origin, JSValue value, NodeType op = JSConstant) + { + return insertConstant(index, origin, m_graph.freeze(value), op); + } + + Node* insertConstant(size_t index, CodeOrigin origin, JSValue value, NodeType op = JSConstant) + { + return insertConstant(index, origin, m_graph.freeze(value), op); + } + + Edge insertConstantForUse(size_t index, NodeOrigin origin, JSValue value, UseKind useKind) + { + return insertConstantForUse(index, origin, m_graph.freeze(value), useKind); + } + + Edge insertConstantForUse(size_t index, CodeOrigin origin, JSValue value, UseKind useKind) + { + return insertConstantForUse(index, NodeOrigin(origin), value, useKind); + } + + Edge insertBottomConstantForUse(size_t index, NodeOrigin origin, UseKind useKind) + { + if (isDouble(useKind)) + return insertConstantForUse(index, origin, jsNumber(PNaN), useKind); + if (useKind == Int52RepUse) + return insertConstantForUse(index, origin, jsNumber(0), useKind); + return insertConstantForUse(index, origin, jsUndefined(), useKind); + } + + Node* insertCheck(size_t index, NodeOrigin origin, AdjacencyList children) + { + children = children.justChecks(); + if (children.isEmpty()) + return nullptr; + return insertNode(index, SpecNone, Check, origin, children); + } + + Node* insertCheck(size_t index, Node* node) + { + return insertCheck(index, node->origin, node->children); + } + + Node* insertCheck(size_t index, NodeOrigin origin, Edge edge) + { + if (edge.willHaveCheck()) + return insertNode(index, SpecNone, Check, origin, edge); + return nullptr; + } + void execute(BasicBlock* block) { executeInsertions(*block, m_insertions); diff --git a/dfg/DFGIntegerCheckCombiningPhase.cpp b/dfg/DFGIntegerCheckCombiningPhase.cpp index 96fdc68..5ddda08 100644 --- a/dfg/DFGIntegerCheckCombiningPhase.cpp +++ b/dfg/DFGIntegerCheckCombiningPhase.cpp @@ -236,12 +236,12 @@ private: switch (data.m_key.m_kind) { case Addition: { if (range.m_minBound < 0) { - insertMustAdd( + insertAdd( nodeIndex, NodeOrigin(range.m_minOrigin, node->origin.forExit), data.m_key.m_source, range.m_minBound); } if (range.m_maxBound > 0) { - insertMustAdd( + insertAdd( nodeIndex, NodeOrigin(range.m_maxOrigin, node->origin.forExit), data.m_key.m_source, range.m_maxBound); } @@ -292,7 +292,7 @@ private: break; case ArrayBounds: - node->convertToPhantom(); + node->remove(); m_changed = true; break; @@ -311,11 +311,11 @@ private: if (node->arithMode() != Arith::CheckOverflow && node->arithMode() != Arith::CheckOverflowAndNegativeZero) break; - if (!m_graph.isInt32Constant(node->child2().node())) + if (!node->child2()->isInt32Constant()) break; return RangeKeyAndAddend( RangeKey::addition(node->child1()), - m_graph.valueOfInt32Constant(node->child2().node())); + node->child2()->asInt32()); } case CheckInBounds: { @@ -325,15 +325,15 @@ private: Edge index = node->child1(); - if (m_graph.isInt32Constant(index.node())) { + if (index->isInt32Constant()) { source = Edge(); - addend = m_graph.valueOfInt32Constant(index.node()); + addend = index->asInt32(); } else if ( index->op() == ArithAdd && index->isBinaryUseKind(Int32Use) - && m_graph.isInt32Constant(index->child2().node())) { + && index->child2()->isInt32Constant()) { source = index->child1(); - addend = m_graph.valueOfInt32Constant(index->child2().node()); + addend = index->child2()->asInt32(); } else { source = index; addend = 0; @@ -341,7 +341,7 @@ private: return RangeKeyAndAddend(RangeKey::arrayBounds(source, key), addend); } - + default: break; } @@ -355,8 +355,17 @@ private: return false; switch (key.m_kind) { - case ArrayBounds: - return (range.m_maxBound - range.m_minBound) >= 0; + case ArrayBounds: { + // Have to do this carefully because C++ compilers are too smart. But all we're really doing is detecting if + // the difference between the bounds is 2^31 or more. If it was, then we'd have to worry about wrap-around. + // The way we'd like to write this expression is (range.m_maxBound - range.m_minBound) >= 0, but that is a + // signed subtraction and compare, which allows the C++ compiler to do anything it wants in case of + // wrap-around. + uint32_t maxBound = range.m_maxBound; + uint32_t minBound = range.m_minBound; + uint32_t unsignedDifference = maxBound - minBound; + return !(unsignedDifference >> 31); + } default: return true; @@ -376,15 +385,6 @@ private: nodeIndex, origin, jsNumber(addend), source.useKind())); } - Node* insertMustAdd( - unsigned nodeIndex, NodeOrigin origin, Edge source, int32_t addend) - { - Node* result = insertAdd(nodeIndex, origin, source, addend); - m_insertionSet.insertNode( - nodeIndex, SpecNone, HardPhantom, origin, result->defaultEdge()); - return result; - } - typedef std::unordered_map<RangeKey, Range, HashMethod<RangeKey>> RangeMap; RangeMap m_map; diff --git a/dfg/DFGIntegerRangeOptimizationPhase.cpp b/dfg/DFGIntegerRangeOptimizationPhase.cpp new file mode 100644 index 0000000..c47dbc3 --- /dev/null +++ b/dfg/DFGIntegerRangeOptimizationPhase.cpp @@ -0,0 +1,1337 @@ +/* + * Copyright (C) 2015 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 "DFGIntegerRangeOptimizationPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGBlockMapInlines.h" +#include "DFGGraph.h" +#include "DFGInsertionSet.h" +#include "DFGPhase.h" +#include "DFGPredictionPropagationPhase.h" +#include "DFGVariableAccessDataDump.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +namespace { + +const bool verbose = false; + +int64_t clampedSumImpl() { return 0; } + +template<typename... Args> +int64_t clampedSumImpl(int left, Args... args) +{ + return static_cast<int64_t>(left) + clampedSumImpl(args...); +} + +template<typename... Args> +int clampedSum(Args... args) +{ + int64_t result = clampedSumImpl(args...); + return static_cast<int>(std::min( + static_cast<int64_t>(std::numeric_limits<int>::max()), + std::max( + static_cast<int64_t>(std::numeric_limits<int>::min()), + result))); +} + +class Relationship { +public: + enum Kind { + LessThan, + Equal, + NotEqual, + GreaterThan + }; + + static Kind flipped(Kind kind) + { + switch (kind) { + case LessThan: + return GreaterThan; + case Equal: + return Equal; + case NotEqual: + return NotEqual; + case GreaterThan: + return LessThan; + } + RELEASE_ASSERT_NOT_REACHED(); + return kind; + } + + Relationship() + : m_left(nullptr) + , m_right(nullptr) + , m_kind(Equal) + , m_offset(0) + { + } + + Relationship(Node* left, Node* right, Kind kind, int offset = 0) + : m_left(left) + , m_right(right) + , m_kind(kind) + , m_offset(offset) + { + RELEASE_ASSERT(m_left); + RELEASE_ASSERT(m_right); + RELEASE_ASSERT(m_left != m_right); + } + + static Relationship safeCreate(Node* left, Node* right, Kind kind, int offset = 0) + { + if (!left || !right || left == right) + return Relationship(); + return Relationship(left, right, kind, offset); + } + + typedef void* (Relationship::*UnspecifiedBoolType); + + explicit operator bool() const { return m_left; } + + Node* left() const { return m_left; } + Node* right() const { return m_right; } + Kind kind() const { return m_kind; } + int offset() const { return m_offset; } + + Relationship flipped() const + { + if (!*this) + return Relationship(); + + // This should return Relationship() if -m_offset overflows. For example: + // + // @a > @b - 2**31 + // + // If we flip it we get: + // + // @b < @a + 2**31 + // + // Except that the sign gets flipped since it's INT_MIN: + // + // @b < @a - 2**31 + // + // And that makes no sense. To see how little sense it makes, consider: + // + // @a > @zero - 2**31 + // + // We would flip it to mean: + // + // @zero < @a - 2**31 + // + // Which is absurd. + + if (m_offset == std::numeric_limits<int>::min()) + return Relationship(); + + return Relationship(m_right, m_left, flipped(m_kind), -m_offset); + } + + Relationship inverse() const + { + if (!*this) + return *this; + + switch (m_kind) { + case Equal: + return Relationship(m_left, m_right, NotEqual, m_offset); + case NotEqual: + return Relationship(m_left, m_right, Equal, m_offset); + case LessThan: + if (sumOverflows<int>(m_offset, -1)) + return Relationship(); + return Relationship(m_left, m_right, GreaterThan, m_offset - 1); + case GreaterThan: + if (sumOverflows<int>(m_offset, 1)) + return Relationship(); + return Relationship(m_left, m_right, LessThan, m_offset + 1); + } + + RELEASE_ASSERT_NOT_REACHED(); + } + + bool isCanonical() const { return m_left < m_right; } + + Relationship canonical() const + { + if (isCanonical()) + return *this; + return flipped(); + } + + bool sameNodesAs(const Relationship& other) const + { + return m_left == other.m_left + && m_right == other.m_right; + } + + bool operator==(const Relationship& other) const + { + return sameNodesAs(other) + && m_kind == other.m_kind + && m_offset == other.m_offset; + } + + bool operator!=(const Relationship& other) const + { + return !(*this == other); + } + + bool operator<(const Relationship& other) const + { + if (m_left != other.m_left) + return m_left < other.m_left; + if (m_right != other.m_right) + return m_right < other.m_right; + if (m_kind != other.m_kind) + return m_kind < other.m_kind; + return m_offset < other.m_offset; + } + + // If possible, returns a form of this relationship where the given node is the left + // side. Returns a null relationship if this relationship cannot say anything about this + // node. + Relationship forNode(Node* node) const + { + if (m_left == node) + return *this; + if (m_right == node) + return flipped(); + return Relationship(); + } + + void setLeft(Node* left) + { + RELEASE_ASSERT(left != m_right); + m_left = left; + } + bool addToOffset(int offset) + { + if (sumOverflows<int>(m_offset, offset)) + return false; + m_offset += offset; + return true; + } + + // Attempts to create a relationship that summarizes the union of this relationship and + // the other relationship. The null relationship is returned to indicate TOP. This is used + // for merging the current relationship-at-head for some pair of nodes and a new + // relationship-at-head being proposed by a predecessor. We wish to create a new + // relationship that is true whenever either of them are true, which ensuring that we don't + // do this forever. Anytime we create a relationship that is not equal to either of the + // previous ones, we will cause the analysis fixpoint to reexecute. + // + // If *this and other are identical, we just return it. + // + // If they are different, we pick from a finite set of "general" relationships: + // + // Eq: this == other + C, where C is -1, 0, or 1. + // Lt: this < other + C, where C is -1, 0, or 1. + // Gt: this > other + C, where C is -1, 0, or 1. + // Ne: this != other + C, where C is -1, 0, or 1. + // TOP: the null relationship. + // + // Constraining C to -1,0,1 is necessary to ensure that the set of general relationships is + // finite. This finite set of relationships forms a pretty simple lattice where a + // relA->relB means "relB is more general than relA". For example, this<other+1 is more + // general than this==other. I'll leave it as an exercise for the reader to see that a + // graph between the 13 general relationships is indeed a lattice. The fact that the set of + // general relationships is a finite lattice ensures monotonicity of the fixpoint, since + // any merge over not-identical relationships returns a relationship that is closer to the + // TOP relationship than either of the original relationships. Here's how convergence is + // achieved for any pair of relationships over the same nodes: + // + // - If they are identical, then returning *this means that we won't be responsible for + // causing another fixpoint iteration. Once all merges reach this point, we're done. + // + // - If they are different, then we pick the most constraining of the 13 general + // relationships that is true if either *this or other are true. This means that if the + // relationships are not identical, the merged relationship will be closer to TOP than + // either of the originals. Returning a different relationship means that we will be + // responsible for the fixpoint to reloop, but we can only do this at most 13 times since + // that's how "deep" the general relationship lattice is. + // + // Note that C being constrained to -1,0,1 also ensures that we never have to return a + // combination of Lt and Gt, as in for example this<other+C && this>other-D. That's why + // this function can return zero or one relationships rather than a list of relationships. + // The only possible values of C and D where this would work are -1 and 1, but in that case + // we just say this==other. That said, the logic for merging two == relationships, like + // this==other+C || this==other+D is to attempt to create these two relationships: + // this>other+min(C,D)-1 && this<other+max(C,D)+1. But only one of these relationships will + // belong to the set of general relationships. + // + // Here's an example of this in action: + // + // for (var i = a; ; ++i) { } + // + // Without C being constrained to -1,0,1, we could end up looping forever: first we'd say + // that i==a, then we might say that i<a+2, then i<a+3, then i<a+4, etc. We won't do this + // because i<a+2 is not a valid general relationship: so when we merge i==a from the first + // iteration and i==a+1 from the second iteration, we create i>a-1 and i<a+2 but then + // realize that only i>a-1 is a valid general relationship. This gives us exactly what we + // want: a statement that i>=a. + Relationship merge(const Relationship& other) const + { + if (!sameNodesAs(other)) + return Relationship(); + + // Handle the super obvious case first. + if (*this == other) + return *this; + + // This does some interesting permutations to reduce the amount of duplicate code. For + // example: + // + // initially: @a != @b, @a > @b + // @b != @a, @b < @a + // @b < @a, @b != @a + // finally: @b != a, @b < @a + // + // Another example: + // + // initially: @a < @b, @a != @b + // finally: @a != @b, @a < @b + + Relationship a = *this; + Relationship b = other; + bool needFlip = false; + + // Get rid of GreaterThan. + if (a.m_kind == GreaterThan || b.m_kind == GreaterThan) { + a = a.flipped(); + b = b.flipped(); + + // In rare cases, we might not be able to flip. Just give up on life in those + // cases. + if (!a || !b) + return Relationship(); + + needFlip = true; + + // If we still have GreaterThan, then it means that we started with @a < @b and + // @a > @b. That's pretty much always a tautology; we don't attempt to do smart + // things for that case for now. + if (a.m_kind == GreaterThan || b.m_kind == GreaterThan) + return Relationship(); + } + + // Make sure that if we have a LessThan, then it's first. + if (b.m_kind == LessThan) + std::swap(a, b); + + // Make sure that if we have a NotEqual, then it's first. + if (b.m_kind == NotEqual) + std::swap(a, b); + + Relationship result = a.mergeImpl(b); + + if (needFlip) + return result.flipped(); + + return result; + } + + // Attempts to construct one Relationship that adequately summarizes the intersection of + // this and other. Returns a null relationship if the filtration should be expressed as two + // different relationships. Returning null is always safe because relationship lists in + // this phase always imply intersection. So, you could soundly skip calling this method and + // just put both relationships into the list. But, that could lead the fixpoint to diverge. + // Hence this will attempt to combine the two relationships into one as a convergence hack. + // In some cases, it will do something conservative. It's always safe for this to return + // *this, or to return other. It'll do that sometimes, mainly to accelerate convergence for + // things that we don't think are important enough to slow down the analysis. + Relationship filter(const Relationship& other) const + { + // We are only interested in merging relationships over the same nodes. + ASSERT(sameNodesAs(other)); + + if (*this == other) + return *this; + + // From here we can assume that the two relationships are not identical. Usually we use + // this to assume that we have different offsets anytime that everything but the offset + // is identical. + + // We want equality to take precedent over everything else, and we don't want multiple + // independent claims of equality. That would just be a contradiction. When it does + // happen, we will be conservative in the sense that we will pick one. + if (m_kind == Equal) + return *this; + if (other.m_kind == Equal) + return other; + + // Useful helper for flipping. + auto filterFlipped = [&] () -> Relationship { + // If we cannot flip, then just conservatively return *this. + Relationship a = flipped(); + Relationship b = other.flipped(); + if (!a || !b) + return *this; + Relationship result = a.filter(b); + if (!result) + return Relationship(); + result = result.flipped(); + if (!result) + return *this; + return result; + }; + + if (m_kind == NotEqual) { + if (other.m_kind == NotEqual) { + // We could do something smarter here. We could even keep both NotEqual's. We + // would need to make sure that we correctly collapsed them when merging. But + // for now, we just pick one of them and hope for the best. + return *this; + } + + if (other.m_kind == GreaterThan) { + // Implement this in terms of NotEqual.filter(LessThan). + return filterFlipped(); + } + + ASSERT(other.m_kind == LessThan); + // We have two claims: + // @a != @b + C + // @a < @b + D + // + // If C >= D, then the NotEqual is redundant. + // If C < D - 1, then we could keep both, but for now we just keep the LessThan. + // If C == D - 1, then the LessThan can be turned into: + // + // @a < @b + C + // + // Note that C == this.m_offset, D == other.m_offset. + + if (m_offset == other.m_offset - 1) + return Relationship(m_left, m_right, LessThan, m_offset); + + return other; + } + + if (other.m_kind == NotEqual) + return other.filter(*this); + + if (m_kind == LessThan) { + if (other.m_kind == LessThan) { + return Relationship( + m_left, m_right, LessThan, std::min(m_offset, other.m_offset)); + } + + ASSERT(other.m_kind == GreaterThan); + if (sumOverflows<int>(m_offset, -1)) + return Relationship(); + if (sumOverflows<int>(other.m_offset, 1)) + return Relationship(); + if (m_offset - 1 == other.m_offset + 1) + return Relationship(m_left, m_right, Equal, m_offset - 1); + + return Relationship(); + } + + ASSERT(m_kind == GreaterThan); + return filterFlipped(); + } + + int minValueOfLeft() const + { + if (m_left->isInt32Constant()) + return m_left->asInt32(); + + if (m_kind == LessThan || m_kind == NotEqual) + return std::numeric_limits<int>::min(); + + int minRightValue = std::numeric_limits<int>::min(); + if (m_right->isInt32Constant()) + minRightValue = m_right->asInt32(); + + if (m_kind == GreaterThan) + return clampedSum(minRightValue, m_offset, 1); + ASSERT(m_kind == Equal); + return clampedSum(minRightValue, m_offset); + } + + int maxValueOfLeft() const + { + if (m_left->isInt32Constant()) + return m_left->asInt32(); + + if (m_kind == GreaterThan || m_kind == NotEqual) + return std::numeric_limits<int>::max(); + + int maxRightValue = std::numeric_limits<int>::max(); + if (m_right->isInt32Constant()) + maxRightValue = m_right->asInt32(); + + if (m_kind == LessThan) + return clampedSum(maxRightValue, m_offset, -1); + ASSERT(m_kind == Equal); + return clampedSum(maxRightValue, m_offset); + } + + void dump(PrintStream& out) const + { + // This prints out the relationship without any whitespace, like @x<@y+42. This + // optimizes for the clarity of a list of relationships. It's easier to read something + // like [@1<@2+3, @4==@5-6] than it would be if there was whitespace inside the + // relationships. + + if (!*this) { + out.print("null"); + return; + } + + out.print(m_left); + switch (m_kind) { + case LessThan: + out.print("<"); + break; + case Equal: + out.print("=="); + break; + case NotEqual: + out.print("!="); + break; + case GreaterThan: + out.print(">"); + break; + } + out.print(m_right); + if (m_offset > 0) + out.print("+", m_offset); + else if (m_offset < 0) + out.print("-", -static_cast<int64_t>(m_offset)); + } + +private: + Relationship mergeImpl(const Relationship& other) const + { + ASSERT(sameNodesAs(other)); + ASSERT(m_kind != GreaterThan); + ASSERT(other.m_kind != GreaterThan); + ASSERT(*this != other); + + // The purpose of this method is to guarantee that: + // + // - We avoid having more than one Relationship over the same two nodes. Therefore, if + // the merge could be expressed as two Relationships, we prefer to instead pick the + // less precise single Relationship form even if that means TOP. + // + // - If the difference between two Relationships is just the m_offset, then we create a + // Relationship that has an offset of -1, 0, or 1. This is an essential convergence + // hack. We need -1 and 1 to support <= and >=. + + // From here we can assume that the two relationships are not identical. Usually we use + // this to assume that we have different offsets anytime that everything but the offset + // is identical. + + if (m_kind == NotEqual) { + if (other.m_kind == NotEqual) + return Relationship(); // Different offsets, so tautology. + + if (other.m_kind == Equal) { + if (m_offset != other.m_offset) { + // Saying that you might be B when you've already said that you're anything + // but A, where A and B are different, is a tautology. You could just say + // that you're anything but A. Adding "(a == b + 1)" to "(a != b + 5)" has + // no value. + return *this; + } + // Otherwise, same offsets: we're saying that you're either A or you're not + // equal to A. + + return Relationship(); + } + + RELEASE_ASSERT(other.m_kind == LessThan); + // We have these claims, and we're merging them: + // @a != @b + C + // @a < @b + D + // + // If we have C == D, then the merge is clearly just the NotEqual. + // If we have C < D, then the merge is a tautology. + // If we have C > D, then we could keep both claims, but we are cheap, so we + // don't. We just use the NotEqual. + + if (m_offset < other.m_offset) + return Relationship(); + + return *this; + } + + if (m_kind == LessThan) { + if (other.m_kind == LessThan) { + // Figure out what offset to select to merge them. The appropriate offsets are + // -1, 0, or 1. + + // First figure out what offset we'd like to use. + int bestOffset = std::max(m_offset, other.m_offset); + + // We have something like @a < @b + 2. We can't represent this under the + // -1,0,1 rule. + if (bestOffset <= 1) + return Relationship(m_left, m_right, LessThan, std::max(bestOffset, -1)); + + return Relationship(); + } + + // The only thing left is Equal. We would have eliminated the GreaterThan's, and + // if we merge LessThan and NotEqual, the NotEqual always comes first. + RELEASE_ASSERT(other.m_kind == Equal); + + // This is the really interesting case. We have: + // + // @a < @b + C + // + // and: + // + // @a == @b + D + // + // Therefore we'd like to return: + // + // @a < @b + max(C, D + 1) + + int bestOffset = std::max(m_offset, other.m_offset + 1); + + // We have something like @a < @b + 2. We can't do it. + if (bestOffset <= 1) + return Relationship(m_left, m_right, LessThan, std::max(bestOffset, -1)); + + return Relationship(); + } + + // The only thing left is Equal, since we would have gotten rid of the GreaterThan's. + RELEASE_ASSERT(m_kind == Equal); + + // We would never see NotEqual, because those always come first. We would never + // see GreaterThan, because we would have eliminated those. We would never see + // LessThan, because those always come first. + + RELEASE_ASSERT(other.m_kind == Equal); + // We have @a == @b + C and @a == @b + D, where C != D. Turn this into some + // inequality that involves a constant that is -1,0,1. Note that we will never have + // lessThan and greaterThan because the constants are constrained to -1,0,1. The only + // way for both of them to be valid is a<b+1 and a>b-1, but then we would have said + // a==b. + + Relationship lessThan; + Relationship greaterThan; + + int lessThanEqOffset = std::max(m_offset, other.m_offset); + if (lessThanEqOffset >= -2 && lessThanEqOffset <= 0) { + lessThan = Relationship( + m_left, other.m_right, LessThan, lessThanEqOffset + 1); + + ASSERT(lessThan.offset() >= -1 && lessThan.offset() <= 1); + } + + int greaterThanEqOffset = std::min(m_offset, other.m_offset); + if (greaterThanEqOffset >= 0 && greaterThanEqOffset <= 2) { + greaterThan = Relationship( + m_left, other.m_right, GreaterThan, greaterThanEqOffset - 1); + + ASSERT(greaterThan.offset() >= -1 && greaterThan.offset() <= 1); + } + + if (lessThan) { + // Both relationships cannot be valid; see above. + RELEASE_ASSERT(!greaterThan); + + return lessThan; + } + + return greaterThan; + } + + Node* m_left; + Node* m_right; + Kind m_kind; + int m_offset; // This offset can be arbitrarily large. +}; + +typedef HashMap<Node*, Vector<Relationship>> RelationshipMap; + +class IntegerRangeOptimizationPhase : public Phase { +public: + IntegerRangeOptimizationPhase(Graph& graph) + : Phase(graph, "integer range optimization") + , m_zero(nullptr) + , m_relationshipsAtHead(graph) + , m_insertionSet(graph) + { + } + + bool run() + { + ASSERT(m_graph.m_form == SSA); + + // Before we do anything, make sure that we have a zero constant at the top. + for (Node* node : *m_graph.block(0)) { + if (node->isInt32Constant() && !node->asInt32()) { + m_zero = node; + break; + } + } + if (!m_zero) { + m_zero = m_insertionSet.insertConstant(0, NodeOrigin(), jsNumber(0)); + m_insertionSet.execute(m_graph.block(0)); + } + + if (verbose) { + dataLog("Graph before integer range optimization:\n"); + m_graph.dump(); + } + + // This performs a fixpoint over the blocks in reverse post-order. Logically, we + // maintain a list of relationships at each point in the program. The list should be + // read as an intersection. For example if we have {rel1, rel2, ..., relN}, you should + // read this as: + // + // TOP && rel1 && rel2 && ... && relN + // + // This allows us to express things like: + // + // @a > @b - 42 && @a < @b + 25 + // + // But not things like: + // + // @a < @b - 42 || @a > @b + 25 + // + // We merge two lists by merging each relationship in one list with each relationship + // in the other list. Merging two relationships will yield a relationship list; as with + // all such lists it is an intersction. Merging relationships over different variables + // always yields the empty list (i.e. TOP). This merge style is sound because if we + // have: + // + // (A && B && C) || (D && E && F) + // + // Then a valid merge is just one that will return true if A, B, C are all true, or + // that will return true if D, E, F are all true. Our merge style essentially does: + // + // (A || D) && (A || E) && (A || F) && (B || D) && (B || E) && (B || F) && + // (C || D) && (C || E) && (C || F) + // + // If A && B && C is true, then this returns true. If D && E && F is true, this also + // returns true. + // + // While this appears at first like a kind of expression explosion, in practice it + // isn't. The code that handles this knows that the merge of two relationships over + // different variables is TOP (i.e. the empty list). For example if A above is @a < @b + // and B above is @c > @d, where @a, @b, @c, and @d are different nodes, the merge will + // yield nothing. In fact, the merge algorithm will skip such merges entirely because + // the relationship lists are actually keyed by node. + // + // Note that it's always safe to drop any of relationship from the relationship list. + // This merely increases the likelihood of the "expression" yielding true, i.e. being + // closer to TOP. Optimizations are only performed if we can establish that the + // expression implied by the relationship list is false for all of those cases where + // some check would have failed. + // + // There is no notion of BOTTOM because we treat blocks that haven't had their + // state-at-head set as a special case: we just transfer all live relationships to such + // a block. After the head of a block is set, we perform the merging as above. In all + // other places where we would ordinarily need BOTTOM, we approximate it by having some + // non-BOTTOM relationship. + + BlockList postOrder = m_graph.blocksInPostOrder(); + + // This loop analyzes the IR to give us m_relationshipsAtHead for each block. This + // may reexecute blocks many times, but it is guaranteed to converge. The state of + // the relationshipsAtHead over any pair of nodes converge monotonically towards the + // TOP relationship (i.e. no relationships in the relationship list). The merge rule + // when between the current relationshipsAtHead and the relationships being propagated + // from a predecessor ensures monotonicity by converting disagreements into one of a + // small set of "general" relationships. There are 12 such relationshis, plus TOP. See + // the comment above Relationship::merge() for details. + bool changed = true; + while (changed) { + changed = false; + for (unsigned postOrderIndex = postOrder.size(); postOrderIndex--;) { + BasicBlock* block = postOrder[postOrderIndex]; + DFG_ASSERT( + m_graph, nullptr, + block == m_graph.block(0) || m_seenBlocks.contains(block)); + + m_relationships = m_relationshipsAtHead[block]; + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (verbose) + dataLog("Analysis: at ", node, ": ", listDump(sortedRelationships()), "\n"); + executeNode(node); + } + + // Now comes perhaps the most important piece of cleverness: if we Branch, and + // the predicate involves some relation over integers, we propagate different + // information to the taken and notTaken paths. This handles: + // - Branch on int32. + // - Branch on LogicalNot on int32. + // - Branch on compare on int32's. + // - Branch on LogicalNot of compare on int32's. + Node* terminal = block->terminal(); + bool alreadyMerged = false; + if (terminal->op() == Branch) { + Relationship relationshipForTrue; + BranchData* branchData = terminal->branchData(); + + bool invert = false; + if (terminal->child1()->op() == LogicalNot) { + terminal = terminal->child1().node(); + invert = true; + } + + if (terminal->child1().useKind() == Int32Use) { + relationshipForTrue = Relationship::safeCreate( + terminal->child1().node(), m_zero, Relationship::NotEqual, 0); + } else { + Node* compare = terminal->child1().node(); + switch (compare->op()) { + case CompareEq: + case CompareStrictEq: + case CompareLess: + case CompareLessEq: + case CompareGreater: + case CompareGreaterEq: { + if (!compare->isBinaryUseKind(Int32Use)) + break; + + switch (compare->op()) { + case CompareEq: + case CompareStrictEq: + relationshipForTrue = Relationship::safeCreate( + compare->child1().node(), compare->child2().node(), + Relationship::Equal, 0); + break; + case CompareLess: + relationshipForTrue = Relationship::safeCreate( + compare->child1().node(), compare->child2().node(), + Relationship::LessThan, 0); + break; + case CompareLessEq: + relationshipForTrue = Relationship::safeCreate( + compare->child1().node(), compare->child2().node(), + Relationship::LessThan, 1); + break; + case CompareGreater: + relationshipForTrue = Relationship::safeCreate( + compare->child1().node(), compare->child2().node(), + Relationship::GreaterThan, 0); + break; + case CompareGreaterEq: + relationshipForTrue = Relationship::safeCreate( + compare->child1().node(), compare->child2().node(), + Relationship::GreaterThan, -1); + break; + default: + DFG_CRASH(m_graph, compare, "Invalid comparison node type"); + break; + } + break; + } + + default: + break; + } + } + + if (invert) + relationshipForTrue = relationshipForTrue.inverse(); + + if (relationshipForTrue) { + RelationshipMap forTrue = m_relationships; + RelationshipMap forFalse = m_relationships; + + if (verbose) + dataLog("Dealing with true:\n"); + setRelationship(forTrue, relationshipForTrue); + if (Relationship relationshipForFalse = relationshipForTrue.inverse()) { + if (verbose) + dataLog("Dealing with false:\n"); + setRelationship(forFalse, relationshipForFalse); + } + + changed |= mergeTo(forTrue, branchData->taken.block); + changed |= mergeTo(forFalse, branchData->notTaken.block); + alreadyMerged = true; + } + } + + if (!alreadyMerged) { + for (BasicBlock* successor : block->successors()) + changed |= mergeTo(m_relationships, successor); + } + } + } + + // Now we transform the code based on the results computed in the previous loop. + changed = false; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + m_relationships = m_relationshipsAtHead[block]; + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (verbose) + dataLog("Transformation: at ", node, ": ", listDump(sortedRelationships()), "\n"); + + // This ends up being pretty awkward to write because we need to decide if we + // optimize by using the relationships before the operation, but we need to + // call executeNode() before we optimize. + switch (node->op()) { + case ArithAdd: { + if (!node->isBinaryUseKind(Int32Use)) + break; + if (node->arithMode() != Arith::CheckOverflow) + break; + if (!node->child2()->isInt32Constant()) + break; + + auto iter = m_relationships.find(node->child1().node()); + if (iter == m_relationships.end()) + break; + + int minValue = std::numeric_limits<int>::min(); + int maxValue = std::numeric_limits<int>::max(); + for (Relationship relationship : iter->value) { + minValue = std::max(minValue, relationship.minValueOfLeft()); + maxValue = std::min(maxValue, relationship.maxValueOfLeft()); + } + + if (sumOverflows<int>(minValue, node->child2()->asInt32()) || + sumOverflows<int>(maxValue, node->child2()->asInt32())) + break; + + executeNode(block->at(nodeIndex)); + node->setArithMode(Arith::Unchecked); + changed = true; + break; + } + + case CheckInBounds: { + auto iter = m_relationships.find(node->child1().node()); + if (iter == m_relationships.end()) + break; + + bool nonNegative = false; + bool lessThanLength = false; + for (Relationship relationship : iter->value) { + if (relationship.minValueOfLeft() >= 0) + nonNegative = true; + + if (relationship.right() == node->child2()) { + if (relationship.kind() == Relationship::Equal + && relationship.offset() < 0) + lessThanLength = true; + + if (relationship.kind() == Relationship::LessThan + && relationship.offset() <= 0) + lessThanLength = true; + } + } + + if (nonNegative && lessThanLength) { + executeNode(block->at(nodeIndex)); + node->remove(); + changed = true; + } + break; + } + + default: + break; + } + + executeNode(block->at(nodeIndex)); + } + } + + return changed; + } + +private: + void executeNode(Node* node) + { + switch (node->op()) { + case CheckInBounds: { + setRelationship(Relationship::safeCreate(node->child1().node(), node->child2().node(), Relationship::LessThan)); + setRelationship(Relationship::safeCreate(node->child1().node(), m_zero, Relationship::GreaterThan, -1)); + break; + } + + case ArithAdd: { + // We're only interested in int32 additions and we currently only know how to + // handle the non-wrapping ones. + if (!node->isBinaryUseKind(Int32Use)) + break; + + // FIXME: We could handle the unchecked arithmetic case. We just do it don't right + // now. + if (node->arithMode() != Arith::CheckOverflow) + break; + + // Handle add: @value + constant. + if (!node->child2()->isInt32Constant()) + break; + + int offset = node->child2()->asInt32(); + + // We add a relationship for @add == @value + constant, and then we copy the + // relationships for @value. This gives us a one-deep view of @value's existing + // relationships, which matches the one-deep search in setRelationship(). + + setRelationship( + Relationship(node, node->child1().node(), Relationship::Equal, offset)); + + auto iter = m_relationships.find(node->child1().node()); + if (iter != m_relationships.end()) { + Vector<Relationship> toAdd; + for (Relationship relationship : iter->value) { + // We have: + // add: ArithAdd(@x, C) + // @x op @y + D + // + // The following certainly holds: + // @x == @add - C + // + // Which allows us to substitute: + // @add - C op @y + D + // + // And then carry the C over: + // @add op @y + D + C + + Relationship newRelationship = relationship; + ASSERT(newRelationship.left() == node->child1().node()); + + if (newRelationship.right() == node) + continue; + newRelationship.setLeft(node); + if (newRelationship.addToOffset(offset)) + toAdd.append(newRelationship); + } + for (Relationship relationship : toAdd) + setRelationship(relationship, 0); + } + + // Now we want to establish that both the input and the output of the addition are + // within a particular range of integers. + + if (offset > 0) { + // If we have "add: @value + 1" then we know that @value <= max - 1, i.e. that + // @value < max. + if (!sumOverflows<int>(std::numeric_limits<int>::max(), -offset, 1)) { + setRelationship( + Relationship::safeCreate( + node->child1().node(), m_zero, Relationship::LessThan, + std::numeric_limits<int>::max() - offset + 1), + 0); + } + + // If we have "add: @value + 1" then we know that @add >= min + 1, i.e. that + // @add > min. + if (!sumOverflows<int>(std::numeric_limits<int>::min(), offset, -1)) { + setRelationship( + Relationship( + node, m_zero, Relationship::GreaterThan, + std::numeric_limits<int>::min() + offset - 1), + 0); + } + } + + if (offset < 0 && offset != std::numeric_limits<int>::min()) { + // If we have "add: @value - 1" then we know that @value >= min + 1, i.e. that + // @value > min. + if (!sumOverflows<int>(std::numeric_limits<int>::min(), offset, -1)) { + setRelationship( + Relationship::safeCreate( + node->child1().node(), m_zero, Relationship::GreaterThan, + std::numeric_limits<int>::min() + offset - 1), + 0); + } + + // If we have "add: @value + 1" then we know that @add <= max - 1, i.e. that + // @add < max. + if (!sumOverflows<int>(std::numeric_limits<int>::max(), -offset, 1)) { + setRelationship( + Relationship( + node, m_zero, Relationship::LessThan, + std::numeric_limits<int>::max() - offset + 1), + 0); + } + } + break; + } + + case GetArrayLength: { + setRelationship(Relationship(node, m_zero, Relationship::GreaterThan, -1)); + break; + } + + case Upsilon: { + setRelationship( + Relationship::safeCreate( + node->child1().node(), node->phi(), Relationship::Equal, 0)); + + auto iter = m_relationships.find(node->child1().node()); + if (iter != m_relationships.end()) { + Vector<Relationship> toAdd; + for (Relationship relationship : iter->value) { + Relationship newRelationship = relationship; + if (node->phi() == newRelationship.right()) + continue; + newRelationship.setLeft(node->phi()); + toAdd.append(newRelationship); + } + for (Relationship relationship : toAdd) + setRelationship(relationship); + } + break; + } + + default: + break; + } + } + + void setRelationship(Relationship relationship, unsigned timeToLive = 1) + { + setRelationship(m_relationships, relationship, timeToLive); + } + + void setRelationship( + RelationshipMap& relationshipMap, Relationship relationship, unsigned timeToLive = 1) + { + setOneSide(relationshipMap, relationship, timeToLive); + setOneSide(relationshipMap, relationship.flipped(), timeToLive); + } + + void setOneSide( + RelationshipMap& relationshipMap, Relationship relationship, unsigned timeToLive = 1) + { + if (!relationship) + return; + + if (verbose) + dataLog(" Setting: ", relationship, " (ttl = ", timeToLive, ")\n"); + + auto result = relationshipMap.add( + relationship.left(), Vector<Relationship>()); + Vector<Relationship>& relationships = result.iterator->value; + Vector<Relationship> toAdd; + bool found = false; + for (Relationship& otherRelationship : relationships) { + if (otherRelationship.sameNodesAs(relationship)) { + if (Relationship filtered = otherRelationship.filter(relationship)) { + ASSERT(filtered.left() == relationship.left()); + otherRelationship = filtered; + found = true; + } + } + + if (timeToLive && otherRelationship.kind() == Relationship::Equal) { + if (verbose) + dataLog(" Considering: ", otherRelationship, "\n"); + + // We have: + // @a op @b + C + // @a == @c + D + // + // This implies: + // @c + D op @b + C + // @c op @b + C - D + // + // Where: @a == relationship.left(), @b == relationship.right(), + // @a == otherRelationship.left(), @c == otherRelationship.right(). + + if (otherRelationship.offset() != std::numeric_limits<int>::min()) { + Relationship newRelationship = relationship; + if (newRelationship.right() != otherRelationship.right()) { + newRelationship.setLeft(otherRelationship.right()); + if (newRelationship.addToOffset(-otherRelationship.offset())) + toAdd.append(newRelationship); + } + } + } + } + + if (!found) + relationships.append(relationship); + + for (Relationship anotherRelationship : toAdd) { + ASSERT(timeToLive); + setOneSide(relationshipMap, anotherRelationship, timeToLive - 1); + } + } + + bool mergeTo(RelationshipMap& relationshipMap, BasicBlock* target) + { + if (verbose) { + dataLog("Merging to ", pointerDump(target), ":\n"); + dataLog(" Incoming: ", listDump(sortedRelationships(relationshipMap)), "\n"); + dataLog(" At head: ", listDump(sortedRelationships(m_relationshipsAtHead[target])), "\n"); + } + + if (m_seenBlocks.add(target)) { + // This is a new block. We copy subject to liveness pruning. + auto isLive = [&] (Node* node) { + if (node == m_zero) + return true; + return target->ssa->liveAtHead.contains(node); + }; + + for (auto& entry : relationshipMap) { + if (!isLive(entry.key)) + continue; + + Vector<Relationship> values; + for (Relationship relationship : entry.value) { + ASSERT(relationship.left() == entry.key); + if (isLive(relationship.right())) { + if (verbose) + dataLog(" Propagating ", relationship, "\n"); + values.append(relationship); + } + } + + std::sort(values.begin(), values.end()); + m_relationshipsAtHead[target].add(entry.key, values); + } + return true; + } + + // Merge by intersecting. We have no notion of BOTTOM, so we use the omission of + // relationships for a pair of nodes to mean TOP. The reason why we don't need BOTTOM + // is (1) we just overapproximate contradictions and (2) a value never having been + // assigned would only happen if we have not processed the node's predecessor. We + // shouldn't process blocks until we have processed the block's predecessor because we + // are using reverse postorder. + Vector<Node*> toRemove; + bool changed = false; + for (auto& entry : m_relationshipsAtHead[target]) { + auto iter = relationshipMap.find(entry.key); + if (iter == relationshipMap.end()) { + toRemove.append(entry.key); + changed = true; + continue; + } + + Vector<Relationship> mergedRelationships; + for (Relationship targetRelationship : entry.value) { + for (Relationship sourceRelationship : iter->value) { + if (verbose) + dataLog(" Merging ", targetRelationship, " and ", sourceRelationship, ":\n"); + Relationship newRelationship = + targetRelationship.merge(sourceRelationship); + + if (verbose) + dataLog(" Got ", newRelationship, "\n"); + + if (!newRelationship) + continue; + + // We need to filter() to avoid exponential explosion of identical + // relationships. We do this here to avoid making setOneSide() do + // more work, since we expect setOneSide() will be called more + // frequently. Here's an example. At some point someone might start + // with two relationships like @a > @b - C and @a < @b + D. Then + // someone does a setRelationship() passing something that turns + // both of these into @a == @b. Now we have @a == @b duplicated. + // Let's say that this duplicate @a == @b ends up at the head of a + // loop. If we didn't have this rule, then the loop would propagate + // duplicate @a == @b's onto the existing duplicate @a == @b's. + // There would be four pairs of @a == @b, each of which would + // create a new @a == @b. Now we'd have four of these duplicates + // and the next time around we'd have 8, then 16, etc. We avoid + // this here by doing this filtration. That might be a bit of + // overkill, since it's probably just the identical duplicate + // relationship case we want' to avoid. But, I'll keep this until + // we have evidence that this is a performance problem. Remember - + // we are already dealing with a list that is pruned down to + // relationships with identical left operand. It shouldn't be a + // large list. + bool found = false; + for (Relationship& existingRelationship : mergedRelationships) { + if (existingRelationship.sameNodesAs(newRelationship)) { + Relationship filtered = + existingRelationship.filter(newRelationship); + if (filtered) { + existingRelationship = filtered; + found = true; + break; + } + } + } + + if (!found) + mergedRelationships.append(newRelationship); + } + } + std::sort(mergedRelationships.begin(), mergedRelationships.end()); + if (entry.value == mergedRelationships) + continue; + + entry.value = mergedRelationships; + changed = true; + } + for (Node* node : toRemove) + m_relationshipsAtHead[target].remove(node); + + return changed; + } + + Vector<Relationship> sortedRelationships(const RelationshipMap& relationships) + { + Vector<Relationship> result; + for (auto& entry : relationships) + result.appendVector(entry.value); + std::sort(result.begin(), result.end()); + return result; + } + + Vector<Relationship> sortedRelationships() + { + return sortedRelationships(m_relationships); + } + + Node* m_zero; + RelationshipMap m_relationships; + BlockSet m_seenBlocks; + BlockMap<RelationshipMap> m_relationshipsAtHead; + InsertionSet m_insertionSet; +}; + +} // anonymous namespace + +bool performIntegerRangeOptimization(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Integer Range Optimization Phase"); + return runPhase<IntegerRangeOptimizationPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGIntegerRangeOptimizationPhase.h b/dfg/DFGIntegerRangeOptimizationPhase.h new file mode 100644 index 0000000..fe0615e --- /dev/null +++ b/dfg/DFGIntegerRangeOptimizationPhase.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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 DFGIntegerRangeOptimizationPhase_h +#define DFGIntegerRangeOptimizationPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Removes overflow checks and out-of-bounds checks by doing a forward flow analysis to prove +// inequalities. It will remove the overflow and bounds checks in loops like: +// +// for (var i = 0; i < array.length; ++i) array[i]; + +bool performIntegerRangeOptimization(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGIntegerRangeOptimizationPhase_h + diff --git a/dfg/DFGInvalidationPointInjectionPhase.cpp b/dfg/DFGInvalidationPointInjectionPhase.cpp index 510ed5c..9228001 100644 --- a/dfg/DFGInvalidationPointInjectionPhase.cpp +++ b/dfg/DFGInvalidationPointInjectionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,7 @@ #if ENABLE(DFG_JIT) +#include "DFGBlockSetInlines.h" #include "DFGClobberize.h" #include "DFGGraph.h" #include "DFGInsertionSet.h" @@ -50,7 +51,7 @@ public: { ASSERT(m_graph.m_form != SSA); - BitVector blocksThatNeedInvalidationPoints; + BlockSet blocksThatNeedInvalidationPoints; for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); @@ -63,17 +64,13 @@ public: // Note: this assumes that control flow occurs at bytecode instruction boundaries. if (m_originThatHadFire.isSet()) { for (unsigned i = block->numSuccessors(); i--;) - blocksThatNeedInvalidationPoints.set(block->successor(i)->index); + blocksThatNeedInvalidationPoints.add(block->successor(i)); } m_insertionSet.execute(block); } - - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - if (!blocksThatNeedInvalidationPoints.get(blockIndex)) - continue; - - BasicBlock* block = m_graph.block(blockIndex); + + for (BasicBlock* block : blocksThatNeedInvalidationPoints.iterable(m_graph)) { insertInvalidationCheck(0, block->at(0)); m_insertionSet.execute(block); } diff --git a/dfg/DFGJITCode.cpp b/dfg/DFGJITCode.cpp index 0d69079..db044e5 100644 --- a/dfg/DFGJITCode.cpp +++ b/dfg/DFGJITCode.cpp @@ -30,6 +30,7 @@ #include "CodeBlock.h" #include "JSCInlines.h" +#include "TrackedReferences.h" namespace JSC { namespace DFG { @@ -82,24 +83,8 @@ void JITCode::reconstruct( reconstruct(codeBlock, codeOrigin, streamIndex, recoveries); result = Operands<JSValue>(OperandsLike, recoveries); - for (size_t i = result.size(); i--;) { - int operand = result.operandForIndex(i); - - if (codeOrigin == CodeOrigin(0) - && operandIsArgument(operand) - && !VirtualRegister(operand).toArgument() - && codeBlock->codeType() == FunctionCode - && codeBlock->specializationKind() == CodeForConstruct) { - // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will - // also never be used. It doesn't matter what we put into the value for this, - // but it has to be an actual value that can be grokked by subsequent DFG passes, - // so we sanitize it here by turning it into Undefined. - result[i] = jsUndefined(); - continue; - } - + for (size_t i = result.size(); i--;) result[i] = recoveries[i].recover(exec); - } } #if ENABLE(FTL_JIT) @@ -186,6 +171,18 @@ void JITCode::setOptimizationThresholdBasedOnCompilationResult( } #endif // ENABLE(FTL_JIT) +void JITCode::validateReferences(const TrackedReferences& trackedReferences) +{ + common.validateReferences(trackedReferences); + + for (OSREntryData& entry : osrEntry) { + for (unsigned i = entry.m_expectedValues.size(); i--;) + entry.m_expectedValues[i].validateReferences(trackedReferences); + } + + minifiedDFG.validateReferences(trackedReferences); +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGJITCode.h b/dfg/DFGJITCode.h index 4d3136f..266a7ce 100644 --- a/dfg/DFGJITCode.h +++ b/dfg/DFGJITCode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,7 +38,11 @@ #include "JITCode.h" #include <wtf/SegmentedVector.h> -namespace JSC { namespace DFG { +namespace JSC { + +class TrackedReferences; + +namespace DFG { class JITCompiler; @@ -107,6 +111,8 @@ public: void setOptimizationThresholdBasedOnCompilationResult(CodeBlock*, CompilationResult); #endif // ENABLE(FTL_JIT) + void validateReferences(const TrackedReferences&) override; + void shrinkToFit(); private: @@ -120,6 +126,7 @@ public: DFG::VariableEventStream variableEventStream; DFG::MinifiedGraph minifiedDFG; #if ENABLE(FTL_JIT) + uint8_t nestedTriggerIsSet { 0 }; UpperTierExecutionCounter tierUpCounter; RefPtr<CodeBlock> osrEntryBlock; unsigned osrEntryRetry; diff --git a/dfg/DFGJITCompiler.cpp b/dfg/DFGJITCompiler.cpp index c54746e..cf35be6 100644 --- a/dfg/DFGJITCompiler.cpp +++ b/dfg/DFGJITCompiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,7 +55,7 @@ JITCompiler::JITCompiler(Graph& dfg) , m_blockHeads(dfg.numBlocks()) { if (shouldShowDisassembly() || m_graph.m_vm.m_perBytecodeProfiler) - m_disassembler = adoptPtr(new Disassembler(dfg)); + m_disassembler = std::make_unique<Disassembler>(dfg); } JITCompiler::~JITCompiler() @@ -116,35 +116,40 @@ void JITCompiler::compileBody() void JITCompiler::compileExceptionHandlers() { - if (m_exceptionChecks.empty() && m_exceptionChecksWithCallFrameRollback.empty()) - return; - - Jump doLookup; - if (!m_exceptionChecksWithCallFrameRollback.empty()) { m_exceptionChecksWithCallFrameRollback.link(this); - emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::argumentGPR1); - doLookup = jump(); - } - if (!m_exceptionChecks.empty()) - m_exceptionChecks.link(this); + // lookupExceptionHandlerFromCallerFrame is passed two arguments, the VM and the exec (the CallFrame*). + move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); + addPtr(TrustedImm32(m_graph.stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, stackPointerRegister); + +#if CPU(X86) + // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! + poke(GPRInfo::argumentGPR0); + poke(GPRInfo::argumentGPR1, 1); +#endif + m_calls.append(CallLinkRecord(call(), lookupExceptionHandlerFromCallerFrame)); - // lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*). - move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); + jumpToExceptionHandler(); + } - if (doLookup.isSet()) - doLookup.link(this); + if (!m_exceptionChecks.empty()) { + m_exceptionChecks.link(this); - move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0); + // lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*). + move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0); + move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); #if CPU(X86) - // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! - poke(GPRInfo::argumentGPR0); - poke(GPRInfo::argumentGPR1, 1); + // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! + poke(GPRInfo::argumentGPR0); + poke(GPRInfo::argumentGPR1, 1); #endif - m_calls.append(CallLinkRecord(call(), lookupExceptionHandler)); - jumpToExceptionHandler(); + m_calls.append(CallLinkRecord(call(), lookupExceptionHandler)); + + jumpToExceptionHandler(); + } } void JITCompiler::link(LinkBuffer& linkBuffer) @@ -156,12 +161,11 @@ void JITCompiler::link(LinkBuffer& linkBuffer) if (!m_graph.m_plan.inlineCallFrames->isEmpty()) m_jitCode->common.inlineCallFrames = m_graph.m_plan.inlineCallFrames; - m_jitCode->common.machineCaptureStart = m_graph.m_machineCaptureStart; - m_jitCode->common.slowArguments = WTF::move(m_graph.m_slowArguments); - #if USE(JSVALUE32_64) m_jitCode->common.doubleConstants = WTF::move(m_graph.m_doubleConstants); #endif + + m_graph.registerFrozenValues(); BitVector usedJumpTables; for (Bag<SwitchData>::iterator iter = m_graph.m_switchData.begin(); !!iter; ++iter) { @@ -182,7 +186,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer) table.ctiOffsets[j] = table.ctiDefault; for (unsigned j = data.cases.size(); j--;) { SwitchCase& myCase = data.cases[j]; - table.ctiOffsets[myCase.value.switchLookupValue() - table.min] = + table.ctiOffsets[myCase.value.switchLookupValue(data.kind) - table.min] = linkBuffer.locationOf(m_blockHeads[myCase.target.block->index]); } } @@ -241,12 +245,12 @@ void JITCompiler::link(LinkBuffer& linkBuffer) JSCallRecord& record = m_jsCalls[i]; CallLinkInfo& info = *record.m_info; ThunkGenerator generator = linkThunkGeneratorFor( - info.callType == CallLinkInfo::Construct ? CodeForConstruct : CodeForCall, + info.specializationKind(), RegisterPreservationNotRequired); linkBuffer.link(record.m_slowCall, FunctionPtr(m_vm->getCTIStub(generator).code().executableAddress())); - info.callReturnLocation = linkBuffer.locationOfNearCall(record.m_slowCall); - info.hotPathBegin = linkBuffer.locationOf(record.m_targetToCheck); - info.hotPathOther = linkBuffer.locationOfNearCall(record.m_fastCall); + info.setCallLocations(linkBuffer.locationOfNearCall(record.m_slowCall), + linkBuffer.locationOf(record.m_targetToCheck), + linkBuffer.locationOfNearCall(record.m_fastCall)); } MacroAssemblerCodeRef osrExitThunk = vm()->getCTIStub(osrExitGenerationThunkGenerator); @@ -285,12 +289,30 @@ void JITCompiler::compile() setStartOfCode(); compileEntry(); - m_speculative = adoptPtr(new SpeculativeJIT(*this)); + m_speculative = std::make_unique<SpeculativeJIT>(*this); + + // Plant a check that sufficient space is available in the JSStack. + addPtr(TrustedImm32(virtualRegisterForLocal(m_graph.requiredRegisterCountForExecutionAndExit() - 1).offset() * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1); + Jump stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1); + addPtr(TrustedImm32(m_graph.stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, stackPointerRegister); checkStackPointerAlignment(); compileBody(); setEndOfMainPath(); + // === Footer code generation === + // + // Generate the stack overflow handling; if the stack check in the entry head fails, + // we need to call out to a helper function to throw the StackOverflowError. + stackOverflow.link(this); + + emitStoreCodeOrigin(CodeOrigin(0)); + + if (maxFrameExtentForSlowPathCall) + addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister); + + m_speculative->callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock); + // Generate slow path code. m_speculative->runSlowPathGenerators(); @@ -300,13 +322,10 @@ void JITCompiler::compile() // Create OSR entry trampolines if necessary. m_speculative->createOSREntries(); setEndOfCode(); -} -void JITCompiler::link() -{ - OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(*m_vm, *this, m_codeBlock, JITCompilationCanFail)); + auto linkBuffer = std::make_unique<LinkBuffer>(*m_vm, *this, m_codeBlock, JITCompilationCanFail); if (linkBuffer->didFailToAllocate()) { - m_graph.m_plan.finalizer = adoptPtr(new FailedFinalizer(m_graph.m_plan)); + m_graph.m_plan.finalizer = std::make_unique<FailedFinalizer>(m_graph.m_plan); return; } @@ -318,8 +337,8 @@ void JITCompiler::link() disassemble(*linkBuffer); - m_graph.m_plan.finalizer = adoptPtr(new JITFinalizer( - m_graph.m_plan, m_jitCode.release(), linkBuffer.release())); + m_graph.m_plan.finalizer = std::make_unique<JITFinalizer>( + m_graph.m_plan, m_jitCode.release(), WTF::move(linkBuffer)); } void JITCompiler::compileFunction() @@ -343,7 +362,7 @@ void JITCompiler::compileFunction() checkStackPointerAlignment(); // === Function body code generation === - m_speculative = adoptPtr(new SpeculativeJIT(*this)); + m_speculative = std::make_unique<SpeculativeJIT>(*this); compileBody(); setEndOfMainPath(); @@ -387,7 +406,9 @@ void JITCompiler::compileFunction() #else thunkReg = GPRInfo::regT5; #endif - move(TrustedImmPtr(m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters())), thunkReg); + CodeLocationLabel* arityThunkLabels = + m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters()); + move(TrustedImmPtr(arityThunkLabels), thunkReg); loadPtr(BaseIndex(thunkReg, GPRInfo::regT0, timesPtr()), thunkReg); m_callArityFixup = call(); jump(fromArityCheck); @@ -401,14 +422,11 @@ void JITCompiler::compileFunction() // Create OSR entry trampolines if necessary. m_speculative->createOSREntries(); setEndOfCode(); -} -void JITCompiler::linkFunction() -{ // === Link === - OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(*m_vm, *this, m_codeBlock, JITCompilationCanFail)); + auto linkBuffer = std::make_unique<LinkBuffer>(*m_vm, *this, m_codeBlock, JITCompilationCanFail); if (linkBuffer->didFailToAllocate()) { - m_graph.m_plan.finalizer = adoptPtr(new FailedFinalizer(m_graph.m_plan)); + m_graph.m_plan.finalizer = std::make_unique<FailedFinalizer>(m_graph.m_plan); return; } link(*linkBuffer); @@ -417,20 +435,22 @@ void JITCompiler::linkFunction() m_jitCode->shrinkToFit(); codeBlock()->shrinkToFit(CodeBlock::LateShrink); - linkBuffer->link(m_callArityFixup, FunctionPtr((m_vm->getCTIStub(arityFixup)).code().executableAddress())); + linkBuffer->link(m_callArityFixup, FunctionPtr((m_vm->getCTIStub(arityFixupGenerator)).code().executableAddress())); disassemble(*linkBuffer); MacroAssemblerCodePtr withArityCheck = linkBuffer->locationOf(m_arityCheck); - m_graph.m_plan.finalizer = adoptPtr(new JITFinalizer( - m_graph.m_plan, m_jitCode.release(), linkBuffer.release(), withArityCheck)); + m_graph.m_plan.finalizer = std::make_unique<JITFinalizer>( + m_graph.m_plan, m_jitCode.release(), WTF::move(linkBuffer), withArityCheck); } void JITCompiler::disassemble(LinkBuffer& linkBuffer) { - if (shouldShowDisassembly()) + if (shouldShowDisassembly()) { m_disassembler->dump(linkBuffer); + linkBuffer.didAlreadyDisassemble(); + } if (m_graph.m_plan.compilation) m_disassembler->reportToProfiler(m_graph.m_plan.compilation.get(), linkBuffer); @@ -439,11 +459,7 @@ void JITCompiler::disassemble(LinkBuffer& linkBuffer) #if USE(JSVALUE32_64) void* JITCompiler::addressOfDoubleConstant(Node* node) { - ASSERT(m_graph.isNumberConstant(node)); - JSValue jsvalue = node->valueOfJSConstant(codeBlock()); - ASSERT(jsvalue.isDouble()); - - double value = jsvalue.asDouble(); + double value = node->asNumber(); int64_t valueBits = bitwise_cast<int64_t>(value); auto it = m_graph.m_doubleConstantsMap.find(valueBits); if (it != m_graph.m_doubleConstantsMap.end()) @@ -459,6 +475,54 @@ void* JITCompiler::addressOfDoubleConstant(Node* node) } #endif +void JITCompiler::noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer) +{ + // OSR entry is not allowed into blocks deemed unreachable by control flow analysis. + if (!basicBlock.intersectionOfCFAHasVisited) + return; + + OSREntryData* entry = m_jitCode->appendOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead)); + + entry->m_expectedValues = basicBlock.intersectionOfPastValuesAtHead; + + // Fix the expected values: in our protocol, a dead variable will have an expected + // value of (None, []). But the old JIT may stash some values there. So we really + // need (Top, TOP). + for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) { + Node* node = basicBlock.variablesAtHead.argument(argument); + if (!node || !node->shouldGenerate()) + entry->m_expectedValues.argument(argument).makeHeapTop(); + } + for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) { + Node* node = basicBlock.variablesAtHead.local(local); + if (!node || !node->shouldGenerate()) + entry->m_expectedValues.local(local).makeHeapTop(); + else { + VariableAccessData* variable = node->variableAccessData(); + entry->m_machineStackUsed.set(variable->machineLocal().toLocal()); + + switch (variable->flushFormat()) { + case FlushedDouble: + entry->m_localsForcedDouble.set(local); + break; + case FlushedInt52: + entry->m_localsForcedMachineInt.set(local); + break; + default: + break; + } + + if (variable->local() != variable->machineLocal()) { + entry->m_reshufflings.append( + OSREntryReshuffling( + variable->local().offset(), variable->machineLocal().offset())); + } + } + } + + entry->m_reshufflings.shrinkToFit(); +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGJITCompiler.h b/dfg/DFGJITCompiler.h index 24c27de..9710eba 100644 --- a/dfg/DFGJITCompiler.h +++ b/dfg/DFGJITCompiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -111,9 +111,6 @@ public: void compile(); void compileFunction(); - void link(); - void linkFunction(); - // Accessors for properties. Graph& graph() { return m_graph; } @@ -268,55 +265,9 @@ public: #endif } - void noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer) - { - // OSR entry is not allowed into blocks deemed unreachable by control flow analysis. - if (!basicBlock.cfaHasVisited) - return; - - OSREntryData* entry = m_jitCode->appendOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead)); - - entry->m_expectedValues = basicBlock.valuesAtHead; - - // Fix the expected values: in our protocol, a dead variable will have an expected - // value of (None, []). But the old JIT may stash some values there. So we really - // need (Top, TOP). - for (size_t argument = 0; argument < basicBlock.variablesAtHead.numberOfArguments(); ++argument) { - Node* node = basicBlock.variablesAtHead.argument(argument); - if (!node || !node->shouldGenerate()) - entry->m_expectedValues.argument(argument).makeHeapTop(); - } - for (size_t local = 0; local < basicBlock.variablesAtHead.numberOfLocals(); ++local) { - Node* node = basicBlock.variablesAtHead.local(local); - if (!node || !node->shouldGenerate()) - entry->m_expectedValues.local(local).makeHeapTop(); - else { - VariableAccessData* variable = node->variableAccessData(); - entry->m_machineStackUsed.set(variable->machineLocal().toLocal()); - - switch (variable->flushFormat()) { - case FlushedDouble: - entry->m_localsForcedDouble.set(local); - break; - case FlushedInt52: - entry->m_localsForcedMachineInt.set(local); - break; - default: - break; - } - - if (variable->local() != variable->machineLocal()) { - entry->m_reshufflings.append( - OSREntryReshuffling( - variable->local().offset(), variable->machineLocal().offset())); - } - } - } - - entry->m_reshufflings.shrinkToFit(); - } + void noticeOSREntry(BasicBlock&, JITCompiler::Label blockHead, LinkBuffer&); - PassRefPtr<JITCode> jitCode() { return m_jitCode; } + RefPtr<JITCode> jitCode() { return m_jitCode; } Vector<Label>& blockHeads() { return m_blockHeads; } @@ -336,7 +287,7 @@ private: // The dataflow graph currently being generated. Graph& m_graph; - OwnPtr<Disassembler> m_disassembler; + std::unique_ptr<Disassembler> m_disassembler; RefPtr<JITCode> m_jitCode; @@ -372,7 +323,7 @@ private: Call m_callArityFixup; Label m_arityCheck; - OwnPtr<SpeculativeJIT> m_speculative; + std::unique_ptr<SpeculativeJIT> m_speculative; }; } } // namespace JSC::DFG diff --git a/dfg/DFGJITFinalizer.cpp b/dfg/DFGJITFinalizer.cpp index 8be38e4..836c0e0 100644 --- a/dfg/DFGJITFinalizer.cpp +++ b/dfg/DFGJITFinalizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,7 @@ #if ENABLE(DFG_JIT) #include "CodeBlock.h" +#include "CodeBlockWithJITType.h" #include "DFGCommon.h" #include "DFGPlan.h" #include "JSCInlines.h" @@ -36,10 +37,10 @@ namespace JSC { namespace DFG { -JITFinalizer::JITFinalizer(Plan& plan, PassRefPtr<JITCode> jitCode, PassOwnPtr<LinkBuffer> linkBuffer, MacroAssemblerCodePtr withArityCheck) +JITFinalizer::JITFinalizer(Plan& plan, PassRefPtr<JITCode> jitCode, std::unique_ptr<LinkBuffer> linkBuffer, MacroAssemblerCodePtr withArityCheck) : Finalizer(plan) , m_jitCode(jitCode) - , m_linkBuffer(linkBuffer) + , m_linkBuffer(WTF::move(linkBuffer)) , m_withArityCheck(withArityCheck) { } @@ -56,7 +57,9 @@ size_t JITFinalizer::codeSize() bool JITFinalizer::finalize() { m_jitCode->initializeCodeRef( - m_linkBuffer->finalizeCodeWithoutDisassembly(), MacroAssemblerCodePtr()); + FINALIZE_DFG_CODE(*m_linkBuffer, ("DFG JIT code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock.get(), JITCode::DFGJIT)).data())), + MacroAssemblerCodePtr()); + m_plan.codeBlock->setJITCode(m_jitCode); finalizeCommon(); @@ -68,7 +71,8 @@ bool JITFinalizer::finalizeFunction() { RELEASE_ASSERT(!m_withArityCheck.isEmptyValue()); m_jitCode->initializeCodeRef( - m_linkBuffer->finalizeCodeWithoutDisassembly(), m_withArityCheck); + FINALIZE_DFG_CODE(*m_linkBuffer, ("DFG JIT code for %s", toCString(CodeBlockWithJITType(m_plan.codeBlock.get(), JITCode::DFGJIT)).data())), + m_withArityCheck); m_plan.codeBlock->setJITCode(m_jitCode); finalizeCommon(); diff --git a/dfg/DFGJITFinalizer.h b/dfg/DFGJITFinalizer.h index 76bb6d5..110442f 100644 --- a/dfg/DFGJITFinalizer.h +++ b/dfg/DFGJITFinalizer.h @@ -37,7 +37,7 @@ namespace JSC { namespace DFG { class JITFinalizer : public Finalizer { public: - JITFinalizer(Plan&, PassRefPtr<JITCode>, PassOwnPtr<LinkBuffer>, MacroAssemblerCodePtr withArityCheck = MacroAssemblerCodePtr(MacroAssemblerCodePtr::EmptyValue)); + JITFinalizer(Plan&, PassRefPtr<JITCode>, std::unique_ptr<LinkBuffer>, MacroAssemblerCodePtr withArityCheck = MacroAssemblerCodePtr(MacroAssemblerCodePtr::EmptyValue)); virtual ~JITFinalizer(); virtual size_t codeSize() override; @@ -48,7 +48,7 @@ private: void finalizeCommon(); RefPtr<JITCode> m_jitCode; - OwnPtr<LinkBuffer> m_linkBuffer; + std::unique_ptr<LinkBuffer> m_linkBuffer; MacroAssemblerCodePtr m_withArityCheck; }; diff --git a/dfg/DFGLICMPhase.cpp b/dfg/DFGLICMPhase.cpp index 334e6ba..62cde8a 100644 --- a/dfg/DFGLICMPhase.cpp +++ b/dfg/DFGLICMPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,13 +62,14 @@ class LICMPhase : public Phase { public: LICMPhase(Graph& graph) : Phase(graph, "LICM") + , m_state(graph) , m_interpreter(graph, m_state) { } bool run() { - ASSERT(m_graph.m_form == SSA); + DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA); m_graph.m_dominators.computeIfNecessary(m_graph); m_graph.m_naturalLoops.computeIfNecessary(m_graph); @@ -123,11 +124,17 @@ public: BasicBlock* predecessor = header->predecessors[i]; if (m_graph.m_dominators.dominates(header, predecessor)) continue; - RELEASE_ASSERT(!preHeader || preHeader == predecessor); + DFG_ASSERT(m_graph, nullptr, !preHeader || preHeader == predecessor); preHeader = predecessor; } - RELEASE_ASSERT(preHeader->last()->op() == Jump); + DFG_ASSERT(m_graph, preHeader->terminal(), preHeader->terminal()->op() == Jump); + + // We should validate the pre-header. If we placed forExit origins on nodes only if + // at the top of that node it is legal to exit, then we would simply check if Jump + // had a forExit. We should disable hoisting to pre-headers that don't validate. + // Or, we could only allow hoisting of things that definitely don't exit. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=145204 data.preHeader = preHeader; } @@ -149,16 +156,9 @@ public: // // For maximum profit, we walk blocks in DFS order to ensure that we generally // tend to hoist dominators before dominatees. - Vector<BasicBlock*> depthFirst; - m_graph.getBlocksInDepthFirstOrder(depthFirst); Vector<const NaturalLoop*> loopStack; bool changed = false; - for ( - unsigned depthFirstIndex = 0; - depthFirstIndex < depthFirst.size(); - ++depthFirstIndex) { - - BasicBlock* block = depthFirst[depthFirstIndex]; + for (BasicBlock* block : m_graph.blocksInPreOrder()) { const NaturalLoop* loop = m_graph.m_naturalLoops.innerMostLoopOf(block); if (!loop) continue; @@ -219,6 +219,47 @@ private: return false; } + // FIXME: At this point if the hoisting of the full node fails but the node has type checks, + // we could still hoist just the checks. + // https://bugs.webkit.org/show_bug.cgi?id=144525 + + // FIXME: If a node has a type check - even something like a CheckStructure - then we should + // only hoist the node if we know that it will execute on every loop iteration or if we know + // that the type check will always succeed at the loop pre-header through some other means + // (like looking at prediction propagation results). Otherwise, we might make a mistake like + // this: + // + // var o = ...; // sometimes null and sometimes an object with structure S1. + // for (...) { + // if (o) + // ... = o.f; // CheckStructure and GetByOffset, which we will currently hoist. + // } + // + // When we encounter such code, we'll hoist the CheckStructure and GetByOffset and then we + // will have a recompile. We'll then end up thinking that the get_by_id needs to be + // polymorphic, which is false. + // + // We can counter this by either having a control flow equivalence check, or by consulting + // prediction propagation to see if the check would always succeed. Prediction propagation + // would not be enough for things like: + // + // var p = ...; // some boolean predicate + // var o = {}; + // if (p) + // o.f = 42; + // for (...) { + // if (p) + // ... = o.f; + // } + // + // Prediction propagation can't tell us anything about the structure, and the CheckStructure + // will appear to be hoistable because the loop doesn't clobber structures. The cell check + // in the CheckStructure will be hoistable though, since prediction propagation can tell us + // that o is always SpecFinalObject. In cases like this, control flow equivalence is the + // only effective guard. + // + // https://bugs.webkit.org/show_bug.cgi?id=144527 + if (readsOverlap(m_graph, node, data.writes)) { if (verbose) { dataLog( @@ -243,10 +284,12 @@ private: "\n"); } - data.preHeader->insertBeforeLast(node); - node->misc.owner = data.preHeader; + data.preHeader->insertBeforeTerminal(node); + node->owner = data.preHeader; NodeOrigin originalOrigin = node->origin; - node->origin.forExit = data.preHeader->last()->origin.forExit; + node->origin.forExit = data.preHeader->terminal()->origin.forExit; + if (!node->origin.semantic.isSet()) + node->origin.semantic = node->origin.forExit; // Modify the states at the end of the preHeader of the loop we hoisted to, // and all pre-headers inside the loop. @@ -267,9 +310,9 @@ private: // It just so happens that all of the nodes we currently know how to hoist // don't have var-arg children. That may change and then we can fix this // code. But for now we just assert that's the case. - RELEASE_ASSERT(!(node->flags() & NodeHasVarArgs)); + DFG_ASSERT(m_graph, node, !(node->flags() & NodeHasVarArgs)); - nodeRef = m_graph.addNode(SpecNone, Phantom, originalOrigin, node->children); + nodeRef = m_graph.addNode(SpecNone, Check, originalOrigin, node->children); return true; } diff --git a/dfg/DFGLazyJSValue.cpp b/dfg/DFGLazyJSValue.cpp index 76d2c51..6011490 100644 --- a/dfg/DFGLazyJSValue.cpp +++ b/dfg/DFGLazyJSValue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,14 +36,14 @@ JSValue LazyJSValue::getValue(VM& vm) const { switch (m_kind) { case KnownValue: - return value(); + return value()->value(); case SingleCharacterString: return jsSingleCharacterString(&vm, u.character); case KnownStringImpl: return jsString(&vm, u.stringImpl); } RELEASE_ASSERT_NOT_REACHED(); - return value(); + return JSValue(); } static TriState equalToSingleCharacter(JSValue value, UChar character) @@ -81,11 +81,11 @@ TriState LazyJSValue::strictEqual(const LazyJSValue& other) const case KnownValue: switch (other.m_kind) { case KnownValue: - return JSValue::pureStrictEqual(value(), other.value()); + return JSValue::pureStrictEqual(value()->value(), other.value()->value()); case SingleCharacterString: - return equalToSingleCharacter(value(), other.character()); + return equalToSingleCharacter(value()->value(), other.character()); case KnownStringImpl: - return equalToStringImpl(value(), other.stringImpl()); + return equalToStringImpl(value()->value(), other.stringImpl()); } break; case SingleCharacterString: @@ -113,11 +113,41 @@ TriState LazyJSValue::strictEqual(const LazyJSValue& other) const return FalseTriState; } +uintptr_t LazyJSValue::switchLookupValue(SwitchKind kind) const +{ + // NB. Not every kind of JSValue will be able to give you a switch lookup + // value, and this method will assert, or do bad things, if you use it + // for a kind of value that can't. + switch (m_kind) { + case KnownValue: + switch (kind) { + case SwitchImm: + return value()->value().asInt32(); + case SwitchCell: + return bitwise_cast<uintptr_t>(value()->value().asCell()); + default: + RELEASE_ASSERT_NOT_REACHED(); + return 0; + } + case SingleCharacterString: + switch (kind) { + case SwitchChar: + return character(); + default: + RELEASE_ASSERT_NOT_REACHED(); + return 0; + } + default: + RELEASE_ASSERT_NOT_REACHED(); + return 0; + } +} + void LazyJSValue::dumpInContext(PrintStream& out, DumpContext* context) const { switch (m_kind) { case KnownValue: - value().dumpInContext(out, context); + value()->dumpInContext(out, context); return; case SingleCharacterString: out.print("Lazy:SingleCharacterString("); diff --git a/dfg/DFGLazyJSValue.h b/dfg/DFGLazyJSValue.h index a391855..a1231db 100644 --- a/dfg/DFGLazyJSValue.h +++ b/dfg/DFGLazyJSValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,8 @@ #if ENABLE(DFG_JIT) -#include "JSCJSValue.h" +#include "DFGCommon.h" +#include "DFGFrozenValue.h" #include <wtf/text/StringImpl.h> namespace JSC { namespace DFG { @@ -44,10 +45,10 @@ enum LazinessKind { class LazyJSValue { public: - LazyJSValue(JSValue value = JSValue()) + LazyJSValue(FrozenValue* value = FrozenValue::emptySingleton()) : m_kind(KnownValue) { - u.value = JSValue::encode(value); + u.value = value; } static LazyJSValue singleCharacterString(UChar character) @@ -66,19 +67,19 @@ public: return result; } - JSValue tryGetValue() const + FrozenValue* tryGetValue(Graph&) const { if (m_kind == KnownValue) return value(); - return JSValue(); + return nullptr; } JSValue getValue(VM&) const; - JSValue value() const + FrozenValue* value() const { ASSERT(m_kind == KnownValue); - return JSValue::decode(u.value); + return u.value; } UChar character() const @@ -95,28 +96,14 @@ public: TriState strictEqual(const LazyJSValue& other) const; - unsigned switchLookupValue() const - { - // NB. Not every kind of JSValue will be able to give you a switch lookup - // value, and this method will assert, or do bad things, if you use it - // for a kind of value that can't. - switch (m_kind) { - case KnownValue: - return value().asInt32(); - case SingleCharacterString: - return character(); - default: - RELEASE_ASSERT_NOT_REACHED(); - return 0; - } - } + uintptr_t switchLookupValue(SwitchKind) const; void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; private: union { - EncodedJSValue value; + FrozenValue* value; UChar character; StringImpl* stringImpl; } u; diff --git a/dfg/DFGLazyNode.cpp b/dfg/DFGLazyNode.cpp new file mode 100644 index 0000000..954ed98 --- /dev/null +++ b/dfg/DFGLazyNode.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 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 "DFGLazyNode.h" + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +void LazyNode::dump(PrintStream& out) const +{ + if (!*this) + out.print("LazyNode:0"); + else { + if (isNode()) + out.print("LazyNode:@", asNode()->index()); + else + out.print("LazyNode:FrozenValue:", Graph::opName(op()), ", ", pointerDump(asValue())); + out.print(")"); + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGLazyNode.h b/dfg/DFGLazyNode.h new file mode 100644 index 0000000..ffd572f --- /dev/null +++ b/dfg/DFGLazyNode.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 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 DFGLazyNode_h +#define DFGLazyNode_h + +#if ENABLE(DFG_JIT) + +#include "DFGCommon.h" +#include "DFGInsertionSet.h" +#include <wtf/PrintStream.h> + +namespace JSC { namespace DFG { + +class LazyNode { +public: + static const size_t jsConstantTag = 0; + static const size_t doubleConstantTag = 1; + static const size_t int52ConstantTag = 2; + + static const uintptr_t tagMask = 0x3; + static const uintptr_t pointerMask = ~tagMask; + + explicit LazyNode(Node* node = nullptr) + : m_node(node) + , m_value(reinterpret_cast<uintptr_t>(nullptr)) + { + if (node && node->isConstant()) + setFrozenValue(node->constant(), node->op()); + } + + explicit LazyNode(FrozenValue* value, NodeType op = JSConstant) + : m_node(nullptr) + , m_value(reinterpret_cast<uintptr_t>(nullptr)) + { + setFrozenValue(value, op); + } + + LazyNode(std::nullptr_t) + : m_node(nullptr) + , m_value(reinterpret_cast<uintptr_t>(nullptr)) + { + } + + LazyNode(WTF::HashTableDeletedValueType) + : m_node(reinterpret_cast<Node*>(-1)) + { + } + + void setNode(Node* node) + { + m_node = node; + if (node && node->isConstant()) + setFrozenValue(node->constant(), node->op()); + } + + bool isHashTableDeletedValue() const { return m_node == reinterpret_cast<Node*>(-1); } + + bool isNode() const { return m_node; } + + NodeType op() const + { + if (m_node) + return m_node->op(); + + switch (m_value & tagMask) { + case jsConstantTag: + return JSConstant; + case doubleConstantTag: + return DoubleConstant; + case int52ConstantTag: + return Int52Constant; + default: + RELEASE_ASSERT_NOT_REACHED(); + } + } + + Node* asNode() const + { + ASSERT(m_node || !asValue()); + return m_node; + } + + FrozenValue* asValue() const + { + return reinterpret_cast<FrozenValue*>(m_value & pointerMask); + } + + unsigned hash() const + { + if (asValue()) + return WTF::PtrHash<FrozenValue*>::hash(asValue()); + return WTF::PtrHash<Node*>::hash(m_node); + } + + bool operator==(const LazyNode& other) const + { + if (asValue() || other.asValue()) + return m_value == other.m_value; + return m_node == other.m_node; + } + + bool operator!=(const LazyNode& other) const + { + return !(*this == other); + } + + Node* ensureIsNode(InsertionSet& insertionSet, BasicBlock* block, unsigned nodeIndex) + { + if (!m_node) + m_node = insertionSet.insertConstant(nodeIndex, block->at(nodeIndex)->origin, asValue(), op()); + + return asNode(); + } + + Node* operator->() const { return asNode(); } + + Node& operator*() const { return *asNode(); } + + bool operator!() const { return !asValue() && !asNode(); } + + explicit operator bool() const { return !!*this; } + + void dump(PrintStream& out) const; + +private: + void setFrozenValue(FrozenValue* value, NodeType op) + { + ASSERT(value); + m_value = reinterpret_cast<uintptr_t>(value); + ASSERT(m_value == (m_value & pointerMask)); + switch (op) { + case JSConstant: + m_value |= jsConstantTag; + break; + case DoubleConstant: + m_value |= doubleConstantTag; + break; + case Int52Constant: + m_value |= int52ConstantTag; + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + } + + Node* m_node; + uintptr_t m_value; +}; + +} } // namespace JSC::DFG + +namespace WTF { + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::DFG::LazyNode> : SimpleClassHashTraits<JSC::DFG::LazyNode> { + static const bool emptyValueIsZero = true; +}; + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + +#endif // DFGLazyNode_h diff --git a/dfg/DFGLivenessAnalysisPhase.cpp b/dfg/DFGLivenessAnalysisPhase.cpp index b3131a4..b2dc4d2 100644 --- a/dfg/DFGLivenessAnalysisPhase.cpp +++ b/dfg/DFGLivenessAnalysisPhase.cpp @@ -68,13 +68,11 @@ public: } while (m_changed); if (!m_graph.block(0)->ssa->liveAtHead.isEmpty()) { - startCrashing(); - dataLog( - "Bad liveness analysis result: live at root is not empty: ", - nodeListDump(m_graph.block(0)->ssa->liveAtHead), "\n"); - dataLog("IR at time of error:\n"); - m_graph.dump(); - CRASH(); + DFG_CRASH( + m_graph, nullptr, + toCString( + "Bad liveness analysis result: live at root is not empty: ", + nodeListDump(m_graph.block(0)->ssa->liveAtHead)).data()); } return true; diff --git a/dfg/DFGLoopPreHeaderCreationPhase.cpp b/dfg/DFGLoopPreHeaderCreationPhase.cpp index b11b2db..340ef2d 100644 --- a/dfg/DFGLoopPreHeaderCreationPhase.cpp +++ b/dfg/DFGLoopPreHeaderCreationPhase.cpp @@ -42,7 +42,7 @@ BasicBlock* createPreHeader(Graph& graph, BlockInsertionSet& insertionSet, Basic // Don't bother to preserve execution frequencies for now. BasicBlock* preHeader = insertionSet.insertBefore(block, PNaN); preHeader->appendNode( - graph, SpecNone, Jump, block->at(0)->origin, OpInfo(block)); + graph, SpecNone, Jump, block->firstOrigin(), OpInfo(block)); for (unsigned predecessorIndex = 0; predecessorIndex < block->predecessors.size(); predecessorIndex++) { BasicBlock* predecessor = block->predecessors[predecessorIndex]; @@ -88,11 +88,23 @@ public: existingPreHeader = predecessor; continue; } - if (existingPreHeader == predecessor) - continue; + // We won't have duplicate entries in the predecessors list. + DFG_ASSERT(m_graph, nullptr, existingPreHeader != predecessor); needsNewPreHeader = true; break; } + + // This phase should only be run on a DFG where unreachable blocks have been pruned. + // We also don't allow loops back to root. This means that every loop header has got + // to have a pre-header. + DFG_ASSERT(m_graph, nullptr, existingPreHeader); + + // We are looking at the predecessors of a loop header. A loop header has to have + // some predecessor other than the pre-header. We must have broken critical edges + // because that is the DFG SSA convention. Therefore, each predecessor of the loop + // header must have only one successor. + DFG_ASSERT(m_graph, nullptr, existingPreHeader->terminal()->op() == Jump); + if (!needsNewPreHeader) continue; diff --git a/dfg/DFGMayExit.cpp b/dfg/DFGMayExit.cpp new file mode 100644 index 0000000..4631ecd --- /dev/null +++ b/dfg/DFGMayExit.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGMayExit.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" +#include "DFGNode.h" +#include "Operations.h" + +namespace JSC { namespace DFG { + +namespace { + +class EdgeMayExit { +public: + EdgeMayExit() + : m_result(false) + { + } + + void operator()(Node*, Edge edge) + { + if (edge.willHaveCheck()) { + m_result = true; + return; + } + + switch (edge.useKind()) { + // These are shady because nodes that have these use kinds will typically exit for + // unrelated reasons. For example CompareEq doesn't usually exit, but if it uses ObjectUse + // then it will. + case ObjectUse: + case ObjectOrOtherUse: + m_result = true; + break; + + // These are shady because they check the structure even if the type of the child node + // passes the StringObject type filter. + case StringObjectUse: + case StringOrStringObjectUse: + m_result = true; + break; + + default: + break; + } + } + + bool result() const { return m_result; } + +private: + bool m_result; +}; + +} // anonymous namespace + +bool mayExit(Graph& graph, Node* node) +{ + switch (node->op()) { + // This is a carefully curated list of nodes that definitely do not exit. We try to be very + // conservative when maintaining this list, because adding new node types to it doesn't + // generally make things a lot better but it might introduce insanely subtle bugs. + case SetArgument: + case JSConstant: + case DoubleConstant: + case Int52Constant: + case MovHint: + case SetLocal: + case Flush: + case Phantom: + case Check: + case GetLocal: + case LoopHint: + case Phi: + case Upsilon: + case ZombieHint: + case BottomValue: + case PutHint: + case PhantomNewObject: + case PutStack: + case KillStack: + case GetStack: + case GetCallee: + case GetArgumentCount: + case GetScope: + case PhantomLocal: + case CountExecution: + case Jump: + case Branch: + case Unreachable: + case DoubleRep: + case Int52Rep: + case ValueRep: + break; + + default: + // If in doubt, return true. + return true; + } + + EdgeMayExit functor; + DFG_NODE_DO_TO_CHILDREN(graph, node, functor); + return functor.result(); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGArgumentsSimplificationPhase.h b/dfg/DFGMayExit.h similarity index 78% rename from dfg/DFGArgumentsSimplificationPhase.h rename to dfg/DFGMayExit.h index 25098ca..e5ae040 100644 --- a/dfg/DFGArgumentsSimplificationPhase.h +++ b/dfg/DFGMayExit.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,25 +23,24 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGArgumentsSimplificationPhase_h -#define DFGArgumentsSimplificationPhase_h +#ifndef DFGMayExit_h +#define DFGMayExit_h #if ENABLE(DFG_JIT) namespace JSC { namespace DFG { class Graph; +struct Node; -// Simplifies reflective uses of the Arguments object: -// -// Inlined arguments.length -> constant -// Inlined arguments[constant] -> GetLocalUnlinked +// A *very* conservative approximation of whether or not a node could possibly exit. Usually +// returns true except in cases where we obviously don't expect an exit. -bool performArgumentsSimplification(Graph&); +bool mayExit(Graph&, Node*); } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) -#endif // DFGArgumentsSimplificationPhase_h +#endif // DFGMayExit_h diff --git a/dfg/DFGDesiredStructureChains.cpp b/dfg/DFGMinifiedGraph.cpp similarity index 72% rename from dfg/DFGDesiredStructureChains.cpp rename to dfg/DFGMinifiedGraph.cpp index 259a5db..61f331f 100644 --- a/dfg/DFGDesiredStructureChains.cpp +++ b/dfg/DFGMinifiedGraph.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,30 +24,27 @@ */ #include "config.h" -#include "DFGDesiredStructureChains.h" +#include "DFGMinifiedGraph.h" #if ENABLE(DFG_JIT) #include "JSCInlines.h" +#include "TrackedReferences.h" namespace JSC { namespace DFG { -DesiredStructureChains::DesiredStructureChains() { } -DesiredStructureChains::~DesiredStructureChains() { } - -bool DesiredStructureChains::areStillValid() const +void MinifiedGraph::prepareAndShrink() { - for (unsigned i = 0; i < m_vector.size(); ++i) { - if (!m_vector[i]->isStillValid()) - return false; - } - return true; + std::sort(m_list.begin(), m_list.end(), MinifiedNode::compareByNodeIndex); + m_list.shrinkToFit(); } -void DesiredStructureChains::visitChildren(SlotVisitor& visitor) +void MinifiedGraph::validateReferences(const TrackedReferences& trackedReferences) { - for (unsigned i = m_vector.size(); i--;) - m_vector[i]->visitChildren(visitor); + for (MinifiedNode& node : m_list) { + if (node.hasConstant()) + trackedReferences.check(node.constant()); + } } } } // namespace JSC::DFG diff --git a/dfg/DFGMinifiedGraph.h b/dfg/DFGMinifiedGraph.h index bc14970..4fc44f8 100644 --- a/dfg/DFGMinifiedGraph.h +++ b/dfg/DFGMinifiedGraph.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,11 @@ #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> -namespace JSC { namespace DFG { +namespace JSC { + +class TrackedReferences; + +namespace DFG { class MinifiedGraph { public: @@ -50,11 +54,9 @@ public: m_list.append(node); } - void prepareAndShrink() - { - std::sort(m_list.begin(), m_list.end(), MinifiedNode::compareByNodeIndex); - m_list.shrinkToFit(); - } + void prepareAndShrink(); + + void validateReferences(const TrackedReferences&); private: Vector<MinifiedNode> m_list; diff --git a/dfg/DFGMinifiedID.h b/dfg/DFGMinifiedID.h index 5f947d1..bdb312d 100644 --- a/dfg/DFGMinifiedID.h +++ b/dfg/DFGMinifiedID.h @@ -26,8 +26,6 @@ #ifndef DFGMinifiedID_h #define DFGMinifiedID_h -#if ENABLE(DFG_JIT) - #include "DFGCommon.h" #include <wtf/HashMap.h> #include <wtf/PrintStream.h> @@ -37,6 +35,7 @@ namespace JSC { namespace DFG { class Graph; class MinifiedNode; class ValueSource; +struct Node; class MinifiedID { public: @@ -98,11 +97,11 @@ template<> struct DefaultHash<JSC::DFG::MinifiedID> { }; template<typename T> struct HashTraits; -template<> struct HashTraits<JSC::DFG::MinifiedID> : SimpleClassHashTraits<JSC::DFG::MinifiedID> { }; +template<> struct HashTraits<JSC::DFG::MinifiedID> : SimpleClassHashTraits<JSC::DFG::MinifiedID> { + static const bool emptyValueIsZero = false; +}; } // namespace WTF -#endif // ENABLE(DFG_JIT) - #endif // DFGMinifiedID_h diff --git a/dfg/DFGMinifiedNode.cpp b/dfg/DFGMinifiedNode.cpp index 4d433aa..80795c2 100644 --- a/dfg/DFGMinifiedNode.cpp +++ b/dfg/DFGMinifiedNode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,13 +39,11 @@ MinifiedNode MinifiedNode::fromNode(Node* node) MinifiedNode result; result.m_id = MinifiedID(node); result.m_op = node->op(); - if (hasConstantNumber(node->op())) - result.m_info = node->constantNumber(); - else if (hasWeakConstant(node->op())) - result.m_info = bitwise_cast<uintptr_t>(node->weakConstant()); + if (hasConstant(node->op())) + result.m_info = JSValue::encode(node->asJSValue()); else { - ASSERT(node->op() == PhantomArguments); - result.m_info = 0; + ASSERT(node->op() == PhantomDirectArguments || node->op() == PhantomClonedArguments); + result.m_info = bitwise_cast<uintptr_t>(node->origin.semantic.inlineCallFrame); } return result; } diff --git a/dfg/DFGMinifiedNode.h b/dfg/DFGMinifiedNode.h index 0cc35ef..29798bc 100644 --- a/dfg/DFGMinifiedNode.h +++ b/dfg/DFGMinifiedNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,8 +42,8 @@ inline bool belongsInMinifiedGraph(NodeType type) case JSConstant: case Int52Constant: case DoubleConstant: - case WeakJSConstant: - case PhantomArguments: + case PhantomDirectArguments: + case PhantomClonedArguments: return true; default: return false; @@ -59,22 +59,18 @@ public: MinifiedID id() const { return m_id; } NodeType op() const { return m_op; } - bool hasConstant() const { return hasConstantNumber() || hasWeakConstant(); } + bool hasConstant() const { return hasConstant(m_op); } - bool hasConstantNumber() const { return hasConstantNumber(m_op); } - - unsigned constantNumber() const + JSValue constant() const { - ASSERT(hasConstantNumber(m_op)); - return m_info; + return JSValue::decode(bitwise_cast<EncodedJSValue>(m_info)); } - bool hasWeakConstant() const { return hasWeakConstant(m_op); } + bool hasInlineCallFrame() const { return hasInlineCallFrame(m_op); } - JSCell* weakConstant() const + InlineCallFrame* inlineCallFrame() const { - ASSERT(hasWeakConstant(m_op)); - return bitwise_cast<JSCell*>(m_info); + return bitwise_cast<InlineCallFrame*>(static_cast<uintptr_t>(m_info)); } static MinifiedID getID(MinifiedNode* node) { return node->id(); } @@ -84,17 +80,18 @@ public: } private: - static bool hasConstantNumber(NodeType type) + static bool hasConstant(NodeType type) { return type == JSConstant || type == Int52Constant || type == DoubleConstant; } - static bool hasWeakConstant(NodeType type) + + static bool hasInlineCallFrame(NodeType type) { - return type == WeakJSConstant; + return type == PhantomDirectArguments || type == PhantomClonedArguments; } MinifiedID m_id; - uintptr_t m_info; + uint64_t m_info; NodeType m_op; }; diff --git a/dfg/DFGMovHintRemovalPhase.cpp b/dfg/DFGMovHintRemovalPhase.cpp new file mode 100644 index 0000000..e2cf37e --- /dev/null +++ b/dfg/DFGMovHintRemovalPhase.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 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 "DFGMovHintRemovalPhase.h" + +#if ENABLE(DFG_JIT) + +#include "BytecodeLivenessAnalysisInlines.h" +#include "DFGEpoch.h" +#include "DFGForAllKills.h" +#include "DFGGraph.h" +#include "DFGInsertionSet.h" +#include "DFGMayExit.h" +#include "DFGPhase.h" +#include "JSCInlines.h" +#include "OperandsInlines.h" + +namespace JSC { namespace DFG { + +namespace { + +bool verbose = false; + +class MovHintRemovalPhase : public Phase { +public: + MovHintRemovalPhase(Graph& graph) + : Phase(graph, "MovHint removal") + , m_state(OperandsLike, graph.block(0)->variablesAtHead) + , m_changed(false) + { + } + + bool run() + { + if (verbose) { + dataLog("Graph before MovHint removal:\n"); + m_graph.dump(); + } + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) + handleBlock(block); + + return m_changed; + } + +private: + void handleBlock(BasicBlock* block) + { + if (verbose) + dataLog("Handing block ", pointerDump(block), "\n"); + + // A MovHint is unnecessary if the local dies before it is used. We answer this question by + // maintaining the current exit epoch, and associating an epoch with each local. When a + // local dies, it gets the current exit epoch. If a MovHint occurs in the same epoch as its + // local, then it means there was no exit between the local's death and the MovHint - i.e. + // the MovHint is unnecessary. + + Epoch currentEpoch = Epoch::first(); + + m_state.fill(Epoch()); + m_graph.forAllLiveInBytecode( + block->terminal()->origin.forExit, + [&] (VirtualRegister reg) { + m_state.operand(reg) = currentEpoch; + }); + + if (verbose) + dataLog(" Locals: ", m_state, "\n"); + + // Assume that blocks after us exit. + currentEpoch.bump(); + + for (unsigned nodeIndex = block->size(); nodeIndex--;) { + Node* node = block->at(nodeIndex); + + if (node->op() == MovHint) { + Epoch localEpoch = m_state.operand(node->unlinkedLocal()); + if (verbose) + dataLog(" At ", node, ": current = ", currentEpoch, ", local = ", localEpoch, "\n"); + if (!localEpoch || localEpoch == currentEpoch) { + node->setOpAndDefaultFlags(ZombieHint); + node->child1() = Edge(); + m_changed = true; + } + m_state.operand(node->unlinkedLocal()) = Epoch(); + } + + if (mayExit(m_graph, node)) + currentEpoch.bump(); + + if (nodeIndex) { + forAllKilledOperands( + m_graph, block->at(nodeIndex - 1), node, + [&] (VirtualRegister reg) { + // This function is a bit sloppy - it might claim to kill a local even if + // it's still live after. We need to protect against that. + if (!!m_state.operand(reg)) + return; + + if (verbose) + dataLog(" Killed operand at ", node, ": ", reg, "\n"); + m_state.operand(reg) = currentEpoch; + }); + } + } + } + + Operands<Epoch> m_state; + bool m_changed; +}; + +} // anonymous namespace + +bool performMovHintRemoval(Graph& graph) +{ + SamplingRegion samplingRegion("DFG MovHint Removal Phase"); + return runPhase<MovHintRemovalPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGMovHintRemovalPhase.h b/dfg/DFGMovHintRemovalPhase.h new file mode 100644 index 0000000..dd4c206 --- /dev/null +++ b/dfg/DFGMovHintRemovalPhase.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 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 DFGMovHintRemovalPhase_h +#define DFGMovHintRemovalPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Cleans up unnecessary MovHints. A MovHint is necessary if the variable dies before there is an +// exit. + +bool performMovHintRemoval(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGMovHintRemovalPhase_h diff --git a/dfg/DFGNaiveDominators.cpp b/dfg/DFGNaiveDominators.cpp new file mode 100644 index 0000000..eb8c63a --- /dev/null +++ b/dfg/DFGNaiveDominators.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2011, 2014 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 "DFGNaiveDominators.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +NaiveDominators::NaiveDominators() +{ +} + +NaiveDominators::~NaiveDominators() +{ +} + +void NaiveDominators::compute(Graph& graph) +{ + // This implements a naive dominator solver. + + ASSERT(graph.block(0)->predecessors.isEmpty()); + + unsigned numBlocks = graph.numBlocks(); + + // Allocate storage for the dense dominance matrix. + if (numBlocks > m_results.size()) { + m_results.grow(numBlocks); + for (unsigned i = numBlocks; i--;) + m_results[i].resize(numBlocks); + m_scratch.resize(numBlocks); + } + + // We know that the entry block is only dominated by itself. + m_results[0].clearAll(); + m_results[0].set(0); + + // Find all of the valid blocks. + m_scratch.clearAll(); + for (unsigned i = numBlocks; i--;) { + if (!graph.block(i)) + continue; + m_scratch.set(i); + } + + // Mark all nodes as dominated by everything. + for (unsigned i = numBlocks; i-- > 1;) { + if (!graph.block(i) || graph.block(i)->predecessors.isEmpty()) + m_results[i].clearAll(); + else + m_results[i].set(m_scratch); + } + + // Iteratively eliminate nodes that are not dominator. + bool changed; + do { + changed = false; + // Prune dominators in all non entry blocks: forward scan. + for (unsigned i = 1; i < numBlocks; ++i) + changed |= pruneDominators(graph, i); + + if (!changed) + break; + + // Prune dominators in all non entry blocks: backward scan. + changed = false; + for (unsigned i = numBlocks; i-- > 1;) + changed |= pruneDominators(graph, i); + } while (changed); +} + +bool NaiveDominators::pruneDominators(Graph& graph, BlockIndex idx) +{ + BasicBlock* block = graph.block(idx); + + if (!block || block->predecessors.isEmpty()) + return false; + + // Find the intersection of dom(preds). + m_scratch.set(m_results[block->predecessors[0]->index]); + for (unsigned j = block->predecessors.size(); j-- > 1;) + m_scratch.filter(m_results[block->predecessors[j]->index]); + + // The block is also dominated by itself. + m_scratch.set(idx); + + return m_results[idx].setAndCheck(m_scratch); +} + +void NaiveDominators::dump(Graph& graph, PrintStream& out) const +{ + for (BlockIndex blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) { + BasicBlock* block = graph.block(blockIndex); + if (!block) + continue; + out.print(" Block ", *block, ":"); + for (BlockIndex otherIndex = 0; otherIndex < graph.numBlocks(); ++otherIndex) { + if (!dominates(block->index, otherIndex)) + continue; + out.print(" #", otherIndex); + } + out.print("\n"); + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGNaiveDominators.h b/dfg/DFGNaiveDominators.h new file mode 100644 index 0000000..d88dd3a --- /dev/null +++ b/dfg/DFGNaiveDominators.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011, 2014 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 DFGNaiveDominators_h +#define DFGNaiveDominators_h + +#if ENABLE(DFG_JIT) + +#include "DFGBasicBlock.h" +#include "DFGCommon.h" +#include <wtf/FastBitVector.h> + +namespace JSC { namespace DFG { + +class Graph; + +// This class is only used for validating the real dominators implementation. + +class NaiveDominators { +public: + NaiveDominators(); + ~NaiveDominators(); + + void compute(Graph&); + + bool dominates(BlockIndex from, BlockIndex to) const + { + return m_results[to].get(from); + } + + bool dominates(BasicBlock* from, BasicBlock* to) const + { + return dominates(from->index, to->index); + } + + void dump(Graph&, PrintStream&) const; + +private: + bool pruneDominators(Graph&, BlockIndex); + + Vector<FastBitVector> m_results; // For each block, the bitvector of blocks that dominate it. + FastBitVector m_scratch; // A temporary bitvector with bit for each block. We recycle this to save new/deletes. +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGNaiveDominators_h diff --git a/dfg/DFGNaturalLoops.cpp b/dfg/DFGNaturalLoops.cpp index b43ba95..edb78cf 100644 --- a/dfg/DFGNaturalLoops.cpp +++ b/dfg/DFGNaturalLoops.cpp @@ -45,6 +45,11 @@ void NaturalLoop::dump(PrintStream& out) const NaturalLoops::NaturalLoops() { } NaturalLoops::~NaturalLoops() { } +void NaturalLoops::computeDependencies(Graph& graph) +{ + graph.m_dominators.computeIfNecessary(graph); +} + void NaturalLoops::compute(Graph& graph) { // Implement the classic dominator-based natural loop finder. The first @@ -57,11 +62,9 @@ void NaturalLoops::compute(Graph& graph) static const bool verbose = false; - graph.m_dominators.computeIfNecessary(graph); - if (verbose) { dataLog("Dominators:\n"); - graph.m_dominators.dump(graph, WTF::dataFile()); + graph.m_dominators.dump(WTF::dataFile()); } m_loops.resize(0); diff --git a/dfg/DFGNaturalLoops.h b/dfg/DFGNaturalLoops.h index 1ac67ac..57225e3 100644 --- a/dfg/DFGNaturalLoops.h +++ b/dfg/DFGNaturalLoops.h @@ -93,6 +93,7 @@ public: NaturalLoops(); ~NaturalLoops(); + void computeDependencies(Graph&); void compute(Graph&); unsigned numLoops() const diff --git a/dfg/DFGNode.cpp b/dfg/DFGNode.cpp index 933664a..6a98534 100644 --- a/dfg/DFGNode.cpp +++ b/dfg/DFGNode.cpp @@ -30,6 +30,7 @@ #include "DFGGraph.h" #include "DFGNodeAllocator.h" +#include "DFGPromotedHeapLocation.h" #include "JSCInlines.h" namespace JSC { namespace DFG { @@ -37,7 +38,7 @@ namespace JSC { namespace DFG { bool MultiPutByOffsetData::writesStructures() const { for (unsigned i = variants.size(); i--;) { - if (variants[i].kind() == PutByIdVariant::Transition) + if (variants[i].writesStructures()) return true; } return false; @@ -46,14 +47,8 @@ bool MultiPutByOffsetData::writesStructures() const bool MultiPutByOffsetData::reallocatesStorage() const { for (unsigned i = variants.size(); i--;) { - if (variants[i].kind() != PutByIdVariant::Transition) - continue; - - if (variants[i].oldStructure()->outOfLineCapacity() == - variants[i].newStructure()->outOfLineCapacity()) - continue; - - return true; + if (variants[i].reallocatesStorage()) + return true; } return false; } @@ -80,7 +75,6 @@ bool Node::hasVariableAccessData(Graph& graph) case Phi: return graph.m_form != SSA; case GetLocal: - case GetArgument: case SetLocal: case SetArgument: case Flush: @@ -91,6 +85,15 @@ bool Node::hasVariableAccessData(Graph& graph) } } +void Node::remove() +{ + ASSERT(!(flags() & NodeHasVarArgs)); + + children = children.justChecks(); + + setOpAndDefaultFlags(Check); +} + void Node::convertToIdentity() { RELEASE_ASSERT(child1()); @@ -100,6 +103,101 @@ void Node::convertToIdentity() setResult(result); } +void Node::convertToIdentityOn(Node* child) +{ + children.reset(); + child1() = child->defaultEdge(); + NodeFlags output = canonicalResultRepresentation(this->result()); + NodeFlags input = canonicalResultRepresentation(child->result()); + if (output == input) { + setOpAndDefaultFlags(Identity); + setResult(output); + return; + } + switch (output) { + case NodeResultDouble: + setOpAndDefaultFlags(DoubleRep); + switch (input) { + case NodeResultInt52: + child1().setUseKind(Int52RepUse); + return; + case NodeResultJS: + child1().setUseKind(NumberUse); + return; + default: + RELEASE_ASSERT_NOT_REACHED(); + return; + } + case NodeResultInt52: + setOpAndDefaultFlags(Int52Rep); + switch (input) { + case NodeResultDouble: + child1().setUseKind(DoubleRepMachineIntUse); + return; + case NodeResultJS: + child1().setUseKind(MachineIntUse); + return; + default: + RELEASE_ASSERT_NOT_REACHED(); + return; + } + case NodeResultJS: + setOpAndDefaultFlags(ValueRep); + switch (input) { + case NodeResultDouble: + child1().setUseKind(DoubleRepUse); + return; + case NodeResultInt52: + child1().setUseKind(Int52RepUse); + return; + default: + RELEASE_ASSERT_NOT_REACHED(); + return; + } + default: + RELEASE_ASSERT_NOT_REACHED(); + return; + } +} + +void Node::convertToPutHint(const PromotedLocationDescriptor& descriptor, Node* base, Node* value) +{ + m_op = PutHint; + m_opInfo = descriptor.imm1().m_value; + m_opInfo2 = descriptor.imm2().m_value; + child1() = base->defaultEdge(); + child2() = value->defaultEdge(); + child3() = Edge(); +} + +void Node::convertToPutStructureHint(Node* structure) +{ + ASSERT(m_op == PutStructure); + ASSERT(structure->castConstant<Structure*>() == transition()->next); + convertToPutHint(StructurePLoc, child1().node(), structure); +} + +void Node::convertToPutByOffsetHint() +{ + ASSERT(m_op == PutByOffset); + convertToPutHint( + PromotedLocationDescriptor(NamedPropertyPLoc, storageAccessData().identifierNumber), + child2().node(), child3().node()); +} + +void Node::convertToPutClosureVarHint() +{ + ASSERT(m_op == PutClosureVar); + convertToPutHint( + PromotedLocationDescriptor(ClosureVarPLoc, scopeOffset().offset()), + child1().node(), child2().node()); +} + +PromotedLocationDescriptor Node::promotedLocationDescriptor() +{ + return PromotedLocationDescriptor(static_cast<PromotedLocationKind>(m_opInfo), m_opInfo2); +} + } } // namespace JSC::DFG namespace WTF { @@ -119,6 +217,9 @@ void printInternal(PrintStream& out, SwitchKind kind) case SwitchString: out.print("SwitchString"); return; + case SwitchCell: + out.print("SwitchCell"); + return; } RELEASE_ASSERT_NOT_REACHED(); } diff --git a/dfg/DFGNode.h b/dfg/DFGNode.h index 3688142..9ca2cdc 100644 --- a/dfg/DFGNode.h +++ b/dfg/DFGNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,16 +28,20 @@ #if ENABLE(DFG_JIT) +#include "BasicBlockLocation.h" #include "CodeBlock.h" #include "DFGAbstractValue.h" #include "DFGAdjacencyList.h" #include "DFGArithMode.h" #include "DFGArrayMode.h" #include "DFGCommon.h" +#include "DFGEpoch.h" #include "DFGLazyJSValue.h" #include "DFGNodeFlags.h" #include "DFGNodeOrigin.h" #include "DFGNodeType.h" +#include "DFGObjectMaterializationData.h" +#include "DFGTransition.h" #include "DFGUseKind.h" #include "DFGVariableAccessData.h" #include "GetByIdVariant.h" @@ -46,14 +50,21 @@ #include "PutByIdVariant.h" #include "SpeculatedType.h" #include "StructureSet.h" +#include "TypeLocation.h" #include "ValueProfile.h" #include <wtf/ListDump.h> namespace JSC { namespace DFG { class Graph; +class PromotedLocationDescriptor; struct BasicBlock; +struct StorageAccessData { + PropertyOffset offset; + unsigned identifierNumber; +}; + struct MultiGetByOffsetData { unsigned identifierNumber; Vector<GetByIdVariant, 2> variants; @@ -67,19 +78,6 @@ struct MultiPutByOffsetData { bool reallocatesStorage() const; }; -struct StructureTransitionData { - Structure* previousStructure; - Structure* newStructure; - - StructureTransitionData() { } - - StructureTransitionData(Structure* previousStructure, Structure* newStructure) - : previousStructure(previousStructure) - , newStructure(newStructure) - { - } -}; - struct NewArrayBufferData { unsigned startConstant; unsigned numConstants; @@ -169,12 +167,6 @@ struct SwitchCase { BranchTarget target; }; -enum SwitchKind { - SwitchImm, - SwitchChar, - SwitchString -}; - struct SwitchData { // Initializes most fields to obviously invalid values. Anyone // constructing this should make sure to initialize everything they @@ -193,10 +185,44 @@ struct SwitchData { bool didUseJumpTable; }; +struct CallVarargsData { + int firstVarArgOffset; +}; + +struct LoadVarargsData { + VirtualRegister start; // Local for the first element. This is the first actual argument, not this. + VirtualRegister count; // Local for the count. + VirtualRegister machineStart; + VirtualRegister machineCount; + unsigned offset; // Which array element to start with. Usually this is 0. + unsigned mandatoryMinimum; // The number of elements on the stack that must be initialized; if the array is too short then the missing elements must get undefined. Does not include "this". + unsigned limit; // Maximum number of elements to load. Includes "this". +}; + +struct StackAccessData { + StackAccessData() + : format(DeadFlush) + { + } + + StackAccessData(VirtualRegister local, FlushFormat format) + : local(local) + , format(format) + { + } + + VirtualRegister local; + VirtualRegister machineLocal; + FlushFormat format; + + FlushedAt flushedAt() { return FlushedAt(format, machineLocal); } +}; + // This type used in passing an immediate argument to Node constructor; // distinguishes an immediate value (typically an index into a CodeBlock data structure - // a constant index, argument, or identifier) from a Node*. struct OpInfo { + OpInfo() : m_value(0) { } explicit OpInfo(int32_t value) : m_value(static_cast<uintptr_t>(value)) { } explicit OpInfo(uint32_t value) : m_value(static_cast<uintptr_t>(value)) { } #if OS(DARWIN) || USE(JSVALUE64) @@ -220,8 +246,9 @@ struct Node { , m_virtualRegister(VirtualRegister()) , m_refCount(1) , m_prediction(SpecNone) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); } @@ -234,8 +261,9 @@ struct Node { , m_prediction(SpecNone) , m_opInfo(0) , m_opInfo2(0) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); } @@ -249,8 +277,9 @@ struct Node { , m_prediction(SpecNone) , m_opInfo(0) , m_opInfo2(0) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); setResult(result); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -265,8 +294,9 @@ struct Node { , m_prediction(SpecNone) , m_opInfo(imm.m_value) , m_opInfo2(0) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); } @@ -280,8 +310,9 @@ struct Node { , m_prediction(SpecNone) , m_opInfo(imm.m_value) , m_opInfo2(0) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); setResult(result); ASSERT(!(m_flags & NodeHasVarArgs)); @@ -296,8 +327,9 @@ struct Node { , m_prediction(SpecNone) , m_opInfo(imm1.m_value) , m_opInfo2(imm2.m_value) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); ASSERT(!(m_flags & NodeHasVarArgs)); } @@ -311,8 +343,9 @@ struct Node { , m_prediction(SpecNone) , m_opInfo(imm1.m_value) , m_opInfo2(imm2.m_value) + , owner(nullptr) { - misc.replacement = 0; + m_misc.replacement = nullptr; setOpAndDefaultFlags(op); ASSERT(m_flags & NodeHasVarArgs); } @@ -335,7 +368,6 @@ struct Node { bool mergeFlags(NodeFlags flags) { - ASSERT(!(flags & NodeDoesNotExit)); NodeFlags newFlags = m_flags | flags; if (newFlags == m_flags) return false; @@ -345,7 +377,6 @@ struct Node { bool filterFlags(NodeFlags flags) { - ASSERT(flags & NodeDoesNotExit); NodeFlags newFlags = m_flags & flags; if (newFlags == m_flags) return false; @@ -376,36 +407,35 @@ struct Node { m_flags = defaultFlags(op); } - void convertToPhantom() + void remove(); + + void convertToCheckStructure(StructureSet* set) { - setOpAndDefaultFlags(Phantom); + setOpAndDefaultFlags(CheckStructure); + m_opInfo = bitwise_cast<uintptr_t>(set); } - void convertToPhantomUnchecked() + void convertToCheckStructureImmediate(Node* structure) { - setOpAndDefaultFlags(Phantom); + ASSERT(op() == CheckStructure); + m_op = CheckStructureImmediate; + children.setChild1(Edge(structure, CellUse)); + } + + void replaceWith(Node* other) + { + remove(); + setReplacement(other); } void convertToIdentity(); + void convertToIdentityOn(Node*); bool mustGenerate() { return m_flags & NodeMustGenerate; } - void setCanExit(bool exits) - { - if (exits) - m_flags &= ~NodeDoesNotExit; - else - m_flags |= NodeDoesNotExit; - } - - bool canExit() - { - return !(m_flags & NodeDoesNotExit); - } - bool isConstant() { switch (op()) { @@ -418,37 +448,40 @@ struct Node { } } - bool isWeakConstant() - { - return op() == WeakJSConstant; - } - - bool isPhantomArguments() - { - return op() == PhantomArguments; - } - bool hasConstant() { switch (op()) { case JSConstant: case DoubleConstant: case Int52Constant: - case WeakJSConstant: - case PhantomArguments: return true; + + case PhantomDirectArguments: + case PhantomClonedArguments: + // These pretend to be the empty value constant for the benefit of the DFG backend, which + // otherwise wouldn't take kindly to a node that doesn't compute a value. + return true; + default: return false; } } - unsigned constantNumber() + FrozenValue* constant() { - ASSERT(isConstant()); - return m_opInfo; + ASSERT(hasConstant()); + + if (op() == PhantomDirectArguments || op() == PhantomClonedArguments) { + // These pretend to be the empty value constant for the benefit of the DFG backend, which + // otherwise wouldn't take kindly to a node that doesn't compute a value. + return FrozenValue::emptySingleton(); + } + + return bitwise_cast<FrozenValue*>(m_opInfo); } - void convertToConstant(unsigned constantNumber) + // Don't call this directly - use Graph::convertToConstant() instead! + void convertToConstant(FrozenValue* value) { if (hasDoubleResult()) m_op = DoubleConstant; @@ -456,16 +489,8 @@ struct Node { m_op = Int52Constant; else m_op = JSConstant; - m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld); - m_opInfo = constantNumber; - children.reset(); - } - - void convertToWeakConstant(JSCell* cell) - { - m_op = WeakJSConstant; - m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld); - m_opInfo = bitwise_cast<uintptr_t>(cell); + m_flags &= ~NodeMustGenerate; + m_opInfo = bitwise_cast<uintptr_t>(value); children.reset(); } @@ -474,54 +499,111 @@ struct Node { ASSERT(op() == GetIndexedPropertyStorage); m_op = ConstantStoragePointer; m_opInfo = bitwise_cast<uintptr_t>(pointer); + children.reset(); } void convertToGetLocalUnlinked(VirtualRegister local) { m_op = GetLocalUnlinked; - m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld); + m_flags &= ~NodeMustGenerate; m_opInfo = local.offset(); m_opInfo2 = VirtualRegister().offset(); children.reset(); } - void convertToStructureTransitionWatchpoint(Structure* structure) + void convertToPutStack(StackAccessData* data) { - ASSERT(m_op == CheckStructure || m_op == ArrayifyToStructure); - ASSERT(!child2()); - ASSERT(!child3()); - m_opInfo = bitwise_cast<uintptr_t>(structure); - m_op = StructureTransitionWatchpoint; + m_op = PutStack; + m_flags |= NodeMustGenerate; + m_opInfo = bitwise_cast<uintptr_t>(data); + m_opInfo2 = 0; } - void convertToStructureTransitionWatchpoint() + void convertToGetStack(StackAccessData* data) { - convertToStructureTransitionWatchpoint(structureSet().singletonStructure()); + m_op = GetStack; + m_flags &= ~NodeMustGenerate; + m_opInfo = bitwise_cast<uintptr_t>(data); + m_opInfo2 = 0; + children.reset(); } - void convertToGetByOffset(unsigned storageAccessDataIndex, Edge storage) + void convertToGetByOffset(StorageAccessData& data, Edge storage) { ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset); - m_opInfo = storageAccessDataIndex; + m_opInfo = bitwise_cast<uintptr_t>(&data); children.setChild2(children.child1()); children.child2().setUseKind(KnownCellUse); children.setChild1(storage); m_op = GetByOffset; - m_flags &= ~NodeClobbersWorld; + m_flags &= ~NodeMustGenerate; } - void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage) + void convertToMultiGetByOffset(MultiGetByOffsetData* data) { - ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == MultiPutByOffset); - m_opInfo = storageAccessDataIndex; + ASSERT(m_op == GetById || m_op == GetByIdFlush); + m_opInfo = bitwise_cast<intptr_t>(data); + child1().setUseKind(CellUse); + m_op = MultiGetByOffset; + ASSERT(m_flags & NodeMustGenerate); + } + + void convertToPutByOffset(StorageAccessData& data, Edge storage) + { + ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush || m_op == MultiPutByOffset); + m_opInfo = bitwise_cast<uintptr_t>(&data); children.setChild3(children.child2()); children.setChild2(children.child1()); children.setChild1(storage); m_op = PutByOffset; - m_flags &= ~NodeClobbersWorld; } - void convertToPhantomLocal() + void convertToMultiPutByOffset(MultiPutByOffsetData* data) + { + ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush); + m_opInfo = bitwise_cast<intptr_t>(data); + m_op = MultiPutByOffset; + } + + void convertToPutHint(const PromotedLocationDescriptor&, Node* base, Node* value); + + void convertToPutByOffsetHint(); + void convertToPutStructureHint(Node* structure); + void convertToPutClosureVarHint(); + + void convertToPhantomNewObject() + { + ASSERT(m_op == NewObject || m_op == MaterializeNewObject); + m_op = PhantomNewObject; + m_flags &= ~NodeHasVarArgs; + m_flags |= NodeMustGenerate; + m_opInfo = 0; + m_opInfo2 = 0; + children = AdjacencyList(); + } + + void convertToPhantomNewFunction() + { + ASSERT(m_op == NewFunction); + m_op = PhantomNewFunction; + m_flags |= NodeMustGenerate; + m_opInfo = 0; + m_opInfo2 = 0; + children = AdjacencyList(); + } + + void convertToPhantomCreateActivation() + { + ASSERT(m_op == CreateActivation || m_op == MaterializeCreateActivation); + m_op = PhantomCreateActivation; + m_flags &= ~NodeHasVarArgs; + m_flags |= NodeMustGenerate; + m_opInfo = 0; + m_opInfo2 = 0; + children = AdjacencyList(); + } + + void convertPhantomToPhantomLocal() { ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgument)); m_op = PhantomLocal; @@ -529,6 +611,13 @@ struct Node { children.setChild1(Edge()); } + void convertFlushToPhantomLocal() + { + ASSERT(m_op == Flush); + m_op = PhantomLocal; + children = AdjacencyList(); + } + void convertToGetLocal(VariableAccessData* variable, Node* phi) { ASSERT(m_op == GetLocalUnlinked); @@ -543,60 +632,95 @@ struct Node { ASSERT(m_op == ToPrimitive); m_op = ToString; } - - JSCell* weakConstant() + + void convertToArithSqrt() { - ASSERT(op() == WeakJSConstant); - return bitwise_cast<JSCell*>(m_opInfo); + ASSERT(m_op == ArithPow); + child2() = Edge(); + m_op = ArithSqrt; } - JSValue valueOfJSConstant(CodeBlock* codeBlock) + JSValue asJSValue() { - switch (op()) { - case WeakJSConstant: - return JSValue(weakConstant()); - case JSConstant: - case DoubleConstant: - case Int52Constant: - return codeBlock->constantRegister(FirstConstantRegisterIndex + constantNumber()).get(); - case PhantomArguments: - return JSValue(); - default: - RELEASE_ASSERT_NOT_REACHED(); - return JSValue(); // Have to return something in release mode. - } + return constant()->value(); } - - bool isInt32Constant(CodeBlock* codeBlock) + + bool isInt32Constant() { - return isConstant() && valueOfJSConstant(codeBlock).isInt32(); + return isConstant() && constant()->value().isInt32(); } - - bool isDoubleConstant(CodeBlock* codeBlock) + + int32_t asInt32() { - bool result = isConstant() && valueOfJSConstant(codeBlock).isDouble(); - if (result) - ASSERT(!isInt32Constant(codeBlock)); - return result; + return asJSValue().asInt32(); } - - bool isNumberConstant(CodeBlock* codeBlock) + + uint32_t asUInt32() { - bool result = isConstant() && valueOfJSConstant(codeBlock).isNumber(); - ASSERT(result == (isInt32Constant(codeBlock) || isDoubleConstant(codeBlock))); - return result; + return asInt32(); } - - bool isMachineIntConstant(CodeBlock* codeBlock) + + bool isDoubleConstant() { - return isConstant() && valueOfJSConstant(codeBlock).isMachineInt(); + return isConstant() && constant()->value().isDouble(); + } + + bool isNumberConstant() + { + return isConstant() && constant()->value().isNumber(); } - bool isBooleanConstant(CodeBlock* codeBlock) + double asNumber() { - return isConstant() && valueOfJSConstant(codeBlock).isBoolean(); + return asJSValue().asNumber(); + } + + bool isMachineIntConstant() + { + return isConstant() && constant()->value().isMachineInt(); + } + + int64_t asMachineInt() + { + return asJSValue().asMachineInt(); + } + + bool isBooleanConstant() + { + return isConstant() && constant()->value().isBoolean(); + } + + bool asBoolean() + { + return constant()->value().asBoolean(); + } + + bool isCellConstant() + { + return isConstant() && constant()->value() && constant()->value().isCell(); + } + + JSCell* asCell() + { + return constant()->value().asCell(); + } + + template<typename T> + T dynamicCastConstant() + { + if (!isCellConstant()) + return nullptr; + return jsDynamicCast<T>(asCell()); } + template<typename T> + T castConstant() + { + T result = dynamicCastConstant<T>(); + RELEASE_ASSERT(result); + return result; + } + bool containsMovHint() { switch (op()) { @@ -646,6 +770,7 @@ struct Node { case ExtractOSREntryLocal: case MovHint: case ZombieHint: + case KillStack: return true; default: return false; @@ -675,6 +800,23 @@ struct Node { return VirtualRegister(m_opInfo2); } + bool hasStackAccessData() + { + switch (op()) { + case PutStack: + case GetStack: + return true; + default: + return false; + } + } + + StackAccessData* stackAccessData() + { + ASSERT(hasStackAccessData()); + return bitwise_cast<StackAccessData*>(m_opInfo); + } + bool hasPhi() { return op() == Upsilon; @@ -688,13 +830,7 @@ struct Node { bool isStoreBarrier() { - switch (op()) { - case StoreBarrier: - case StoreBarrierWithNullCheck: - return true; - default: - return false; - } + return op() == StoreBarrier; } bool hasIdentifier() @@ -717,33 +853,20 @@ struct Node { return m_opInfo; } - bool hasArithNodeFlags() + bool hasPromotedLocationDescriptor() { - switch (op()) { - case UInt32ToNumber: - case ArithAdd: - case ArithSub: - case ArithNegate: - case ArithMul: - case ArithAbs: - case ArithMin: - case ArithMax: - case ArithMod: - case ArithDiv: - case ValueAdd: - return true; - default: - return false; - } + return op() == PutHint; } + PromotedLocationDescriptor promotedLocationDescriptor(); + // This corrects the arithmetic node flags, so that irrelevant bits are // ignored. In particular, anything other than ArithMul does not need // to know if it can speculate on negative zero. NodeFlags arithNodeFlags() { NodeFlags result = m_flags & NodeArithFlagsMask; - if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == DoubleAsInt32) + if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == DoubleAsInt32) return result; return result & ~NodeBytecodeNeedsNegZero; } @@ -835,15 +958,26 @@ struct Node { return m_opInfo; } - bool hasVarNumber() + bool hasScopeOffset() { return op() == GetClosureVar || op() == PutClosureVar; } - int varNumber() + ScopeOffset scopeOffset() { - ASSERT(hasVarNumber()); - return m_opInfo; + ASSERT(hasScopeOffset()); + return ScopeOffset(m_opInfo); + } + + bool hasDirectArgumentsOffset() + { + return op() == GetFromArguments || op() == PutToArguments; + } + + DirectArgumentsOffset capturedArgumentsOffset() + { + ASSERT(hasDirectArgumentsOffset()); + return DirectArgumentsOffset(m_opInfo); } bool hasRegisterPointer() @@ -851,11 +985,41 @@ struct Node { return op() == GetGlobalVar || op() == PutGlobalVar; } - WriteBarrier<Unknown>* registerPointer() + WriteBarrier<Unknown>* variablePointer() { return bitwise_cast<WriteBarrier<Unknown>*>(m_opInfo); } + bool hasCallVarargsData() + { + switch (op()) { + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: + return true; + default: + return false; + } + } + + CallVarargsData* callVarargsData() + { + ASSERT(hasCallVarargsData()); + return bitwise_cast<CallVarargsData*>(m_opInfo); + } + + bool hasLoadVarargsData() + { + return op() == LoadVarargs || op() == ForwardVarargs; + } + + LoadVarargsData* loadVarargsData() + { + ASSERT(hasLoadVarargsData()); + return bitwise_cast<LoadVarargsData*>(m_opInfo); + } + bool hasResult() { return !!result(); @@ -994,6 +1158,76 @@ struct Node { } } + class SuccessorsIterable { + public: + SuccessorsIterable() + : m_terminal(nullptr) + { + } + + SuccessorsIterable(Node* terminal) + : m_terminal(terminal) + { + } + + class iterator { + public: + iterator() + : m_terminal(nullptr) + , m_index(UINT_MAX) + { + } + + iterator(Node* terminal, unsigned index) + : m_terminal(terminal) + , m_index(index) + { + } + + BasicBlock* operator*() + { + return m_terminal->successor(m_index); + } + + iterator& operator++() + { + m_index++; + return *this; + } + + bool operator==(const iterator& other) const + { + return m_index == other.m_index; + } + + bool operator!=(const iterator& other) const + { + return !(*this == other); + } + private: + Node* m_terminal; + unsigned m_index; + }; + + iterator begin() + { + return iterator(m_terminal, 0); + } + + iterator end() + { + return iterator(m_terminal, m_terminal->numSuccessors()); + } + + private: + Node* m_terminal; + }; + + SuccessorsIterable successors() + { + return SuccessorsIterable(this); + } + BasicBlock*& successorForCondition(bool condition) { return branchData()->forCondition(condition); @@ -1002,16 +1236,22 @@ struct Node { bool hasHeapPrediction() { switch (op()) { + case ArithRound: + case GetDirectPname: case GetById: case GetByIdFlush: case GetByVal: - case GetMyArgumentByVal: - case GetMyArgumentByValSafe: case Call: case Construct: + case CallVarargs: + case ConstructVarargs: + case CallForwardVarargs: + case NativeCall: + case NativeConstruct: case GetByOffset: case MultiGetByOffset: case GetClosureVar: + case GetFromArguments: case ArrayPop: case ArrayPush: case RegExpExec: @@ -1028,67 +1268,61 @@ struct Node { ASSERT(hasHeapPrediction()); return static_cast<SpeculatedType>(m_opInfo2); } - - bool predictHeap(SpeculatedType prediction) - { - ASSERT(hasHeapPrediction()); - - return mergeSpeculation(m_opInfo2, prediction); - } - + void setHeapPrediction(SpeculatedType prediction) { ASSERT(hasHeapPrediction()); m_opInfo2 = prediction; } - bool hasFunction() + bool hasCellOperand() { switch (op()) { - case CheckFunction: - case AllocationProfileWatchpoint: + case CheckCell: + case NativeConstruct: + case NativeCall: + case NewFunction: + case CreateActivation: + case MaterializeCreateActivation: return true; default: return false; } } - JSCell* function() + FrozenValue* cellOperand() { - ASSERT(hasFunction()); - JSCell* result = reinterpret_cast<JSFunction*>(m_opInfo); - ASSERT(JSValue(result).isFunction()); - return result; - } - - bool hasExecutable() - { - return op() == CheckExecutable; - } - - ExecutableBase* executable() - { - return jsCast<ExecutableBase*>(reinterpret_cast<JSCell*>(m_opInfo)); + ASSERT(hasCellOperand()); + switch (op()) { + case MaterializeCreateActivation: + return reinterpret_cast<FrozenValue*>(m_opInfo2); + default: + return reinterpret_cast<FrozenValue*>(m_opInfo); + } + RELEASE_ASSERT_NOT_REACHED(); } - bool hasVariableWatchpointSet() + template<typename T> + T castOperand() { - return op() == NotifyWrite || op() == VariableWatchpoint; + return cellOperand()->cast<T>(); } - VariableWatchpointSet* variableWatchpointSet() + void setCellOperand(FrozenValue* value) { - return reinterpret_cast<VariableWatchpointSet*>(m_opInfo); + ASSERT(hasCellOperand()); + m_opInfo = bitwise_cast<uintptr_t>(value); } - bool hasTypedArray() + bool hasWatchpointSet() { - return op() == TypedArrayWatchpoint; + return op() == NotifyWrite; } - JSArrayBufferView* typedArray() + WatchpointSet* watchpointSet() { - return reinterpret_cast<JSArrayBufferView*>(m_opInfo); + ASSERT(hasWatchpointSet()); + return reinterpret_cast<WatchpointSet*>(m_opInfo); } bool hasStoragePointer() @@ -1098,14 +1332,14 @@ struct Node { void* storagePointer() { + ASSERT(hasStoragePointer()); return reinterpret_cast<void*>(m_opInfo); } - bool hasStructureTransitionData() + bool hasTransition() { switch (op()) { case PutStructure: - case PhantomPutStructure: case AllocatePropertyStorage: case ReallocatePropertyStorage: return true; @@ -1114,16 +1348,17 @@ struct Node { } } - StructureTransitionData& structureTransitionData() + Transition* transition() { - ASSERT(hasStructureTransitionData()); - return *reinterpret_cast<StructureTransitionData*>(m_opInfo); + ASSERT(hasTransition()); + return reinterpret_cast<Transition*>(m_opInfo); } bool hasStructureSet() { switch (op()) { case CheckStructure: + case CheckStructureImmediate: return true; default: return false; @@ -1139,7 +1374,6 @@ struct Node { bool hasStructure() { switch (op()) { - case StructureTransitionWatchpoint: case ArrayifyToStructure: case NewObject: case NewStringObject: @@ -1157,13 +1391,20 @@ struct Node { bool hasStorageAccessData() { - return op() == GetByOffset || op() == PutByOffset; + switch (op()) { + case GetByOffset: + case PutByOffset: + case GetGetterSetterByOffset: + return true; + default: + return false; + } } - unsigned storageAccessDataIndex() + StorageAccessData& storageAccessData() { ASSERT(hasStorageAccessData()); - return m_opInfo; + return *bitwise_cast<StorageAccessData*>(m_opInfo); } bool hasMultiGetByOffsetData() @@ -1173,6 +1414,7 @@ struct Node { MultiGetByOffsetData& multiGetByOffsetData() { + ASSERT(hasMultiGetByOffsetData()); return *reinterpret_cast<MultiGetByOffsetData*>(m_opInfo); } @@ -1183,41 +1425,102 @@ struct Node { MultiPutByOffsetData& multiPutByOffsetData() { + ASSERT(hasMultiPutByOffsetData()); return *reinterpret_cast<MultiPutByOffsetData*>(m_opInfo); } - bool hasFunctionDeclIndex() + bool hasObjectMaterializationData() { - return op() == NewFunction - || op() == NewFunctionNoCheck; + switch (op()) { + case MaterializeNewObject: + case MaterializeCreateActivation: + return true; + + default: + return false; + } } - unsigned functionDeclIndex() + ObjectMaterializationData& objectMaterializationData() { - ASSERT(hasFunctionDeclIndex()); - return m_opInfo; + ASSERT(hasObjectMaterializationData()); + return *reinterpret_cast<ObjectMaterializationData*>(m_opInfo); } - - bool hasFunctionExprIndex() + + bool isObjectAllocation() { - return op() == NewFunctionExpression; + switch (op()) { + case NewObject: + case MaterializeNewObject: + return true; + default: + return false; + } } - unsigned functionExprIndex() + bool isPhantomObjectAllocation() { - ASSERT(hasFunctionExprIndex()); - return m_opInfo; + switch (op()) { + case PhantomNewObject: + return true; + default: + return false; + } } - bool hasSymbolTable() + bool isActivationAllocation() { - return op() == FunctionReentryWatchpoint; + switch (op()) { + case CreateActivation: + case MaterializeCreateActivation: + return true; + default: + return false; + } } - - SymbolTable* symbolTable() + + bool isPhantomActivationAllocation() + { + switch (op()) { + case PhantomCreateActivation: + return true; + default: + return false; + } + } + + bool isFunctionAllocation() + { + switch (op()) { + case NewFunction: + return true; + default: + return false; + } + } + + bool isPhantomFunctionAllocation() { - ASSERT(hasSymbolTable()); - return reinterpret_cast<SymbolTable*>(m_opInfo); + switch (op()) { + case PhantomNewFunction: + return true; + default: + return false; + } + } + + bool isPhantomAllocation() + { + switch (op()) { + case PhantomNewObject: + case PhantomDirectArguments: + case PhantomClonedArguments: + case PhantomNewFunction: + case PhantomCreateActivation: + return true; + default: + return false; + } } bool hasArrayMode() @@ -1236,6 +1539,7 @@ struct Node { case ArrayifyToStructure: case ArrayPush: case ArrayPop: + case HasIndexedProperty: return true; default: return false; @@ -1286,6 +1590,23 @@ struct Node { { m_opInfo = mode; } + + bool hasArithRoundingMode() + { + return op() == ArithRound; + } + + Arith::RoundingMode arithRoundingMode() + { + ASSERT(hasArithRoundingMode()); + return static_cast<Arith::RoundingMode>(m_opInfo); + } + + void setArithRoundingMode(Arith::RoundingMode mode) + { + ASSERT(hasArithRoundingMode()); + m_opInfo = static_cast<uintptr_t>(mode); + } bool hasVirtualRegister() { @@ -1321,22 +1642,6 @@ struct Node { return m_refCount; } - bool willHaveCodeGenOrOSR() - { - switch (op()) { - case SetLocal: - case MovHint: - case ZombieHint: - case PhantomArguments: - return true; - case Phantom: - case HardPhantom: - return child1().useKindUnchecked() != UntypedUse || child2().useKindUnchecked() != UntypedUse || child3().useKindUnchecked() != UntypedUse; - default: - return shouldGenerate(); - } - } - bool isSemanticallySkippable() { return op() == CountExecution; @@ -1477,6 +1782,11 @@ struct Node { return isDoubleSpeculation(prediction()); } + bool shouldSpeculateDoubleReal() + { + return isDoubleRealSpeculation(prediction()); + } + bool shouldSpeculateNumber() { return isFullNumberSpeculation(prediction()); @@ -1547,9 +1857,14 @@ struct Node { return isArraySpeculation(prediction()); } - bool shouldSpeculateArguments() + bool shouldSpeculateDirectArguments() + { + return isDirectArgumentsSpeculation(prediction()); + } + + bool shouldSpeculateScopedArguments() { - return isArgumentsSpeculation(prediction()); + return isScopedArgumentsSpeculation(prediction()); } bool shouldSpeculateInt8Array() @@ -1617,6 +1932,11 @@ struct Node { return isCellSpeculation(prediction()); } + bool shouldSpeculateNotCell() + { + return isNotCellSpeculation(prediction()); + } + static bool shouldSpeculateBoolean(Node* op1, Node* op2) { return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean(); @@ -1703,6 +2023,48 @@ struct Node { { return canSpeculateInt52(sourceFor(pass)); } + + bool hasTypeLocation() + { + return op() == ProfileType; + } + + TypeLocation* typeLocation() + { + ASSERT(hasTypeLocation()); + return reinterpret_cast<TypeLocation*>(m_opInfo); + } + + bool hasBasicBlockLocation() + { + return op() == ProfileControlFlow; + } + + BasicBlockLocation* basicBlockLocation() + { + ASSERT(hasBasicBlockLocation()); + return reinterpret_cast<BasicBlockLocation*>(m_opInfo); + } + + Node* replacement() const + { + return m_misc.replacement; + } + + void setReplacement(Node* replacement) + { + m_misc.replacement = replacement; + } + + Epoch epoch() const + { + return Epoch::fromUnsigned(m_misc.epoch); + } + + void setEpoch(Epoch epoch) + { + m_misc.epoch = epoch.toUnsigned(); + } void dumpChildren(PrintStream& out) { @@ -1743,19 +2105,22 @@ public: AbstractValue value; // Miscellaneous data that is usually meaningless, but can hold some analysis results - // if you ask right. For example, if you do Graph::initializeNodeOwners(), misc.owner + // if you ask right. For example, if you do Graph::initializeNodeOwners(), Node::owner // will tell you which basic block a node belongs to. You cannot rely on this persisting // across transformations unless you do the maintenance work yourself. Other phases use - // misc.replacement, but they do so manually: first you do Graph::clearReplacements() - // and then you set, and use, replacement's yourself. + // Node::replacement, but they do so manually: first you do Graph::clearReplacements() + // and then you set, and use, replacement's yourself. Same thing for epoch. // // Bottom line: don't use these fields unless you initialize them yourself, or by // calling some appropriate methods that initialize them the way you want. Otherwise, // these fields are meaningless. +private: union { Node* replacement; - BasicBlock* owner; - } misc; + unsigned epoch; + } m_misc; +public: + BasicBlock* owner; }; inline bool nodeComparator(Node* a, Node* b) diff --git a/dfg/DFGNodeFlags.cpp b/dfg/DFGNodeFlags.cpp index e3181ca..366fbec 100644 --- a/dfg/DFGNodeFlags.cpp +++ b/dfg/DFGNodeFlags.cpp @@ -74,12 +74,6 @@ void dumpNodeFlags(PrintStream& actualOut, NodeFlags flags) if (flags & NodeHasVarArgs) out.print(comma, "VarArgs"); - if (flags & NodeClobbersWorld) - out.print(comma, "Clobbers"); - - if (flags & NodeMightClobber) - out.print(comma, "MightClobber"); - if (flags & NodeResultMask) { if (!(flags & NodeBytecodeUsesAsNumber) && !(flags & NodeBytecodeNeedsNegZero)) out.print(comma, "PureInt"); @@ -109,9 +103,6 @@ void dumpNodeFlags(PrintStream& actualOut, NodeFlags flags) if (flags & NodeBytecodeUsesAsArrayIndex) out.print(comma, "ReallyWantsInt"); - if (!(flags & NodeDoesNotExit)) - out.print(comma, "CanExit"); - if (flags & NodeIsFlushed) out.print(comma, "IsFlushed"); diff --git a/dfg/DFGNodeFlags.h b/dfg/DFGNodeFlags.h index 8243b75..4db2a43 100644 --- a/dfg/DFGNodeFlags.h +++ b/dfg/DFGNodeFlags.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,8 +46,7 @@ namespace JSC { namespace DFG { #define NodeMustGenerate 0x0008 // set on nodes that have side effects, and may not trivially be removed by DCE. #define NodeHasVarArgs 0x0010 -#define NodeClobbersWorld 0x0020 -#define NodeMightClobber 0x0040 +// 0x0020 and 0x0040 are free. #define NodeBehaviorMask 0x0780 #define NodeMayOverflowInBaseline 0x0080 @@ -66,11 +65,11 @@ namespace JSC { namespace DFG { #define NodeArithFlagsMask (NodeBehaviorMask | NodeBytecodeBackPropMask) -#define NodeDoesNotExit 0x10000 // This flag is negated to make it natural for the default to be that a node does exit. +#define NodeIsFlushed 0x10000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush. -#define NodeRelevantToOSR 0x20000 - -#define NodeIsFlushed 0x40000 // Used by Graph::computeIsFlushed(), will tell you which local nodes are backwards-reachable from a Flush. +#define NodeMiscFlag1 0x20000 +#define NodeMiscFlag2 0x40000 +#define NodeMiscFlag3 0x80000 typedef uint32_t NodeFlags; @@ -97,7 +96,7 @@ enum RareCaseProfilingSource { static inline bool nodeMayOverflow(NodeFlags flags, RareCaseProfilingSource source) { - NodeFlags mask; + NodeFlags mask = 0; switch (source) { case BaselineRareCase: mask = NodeMayOverflowInBaseline; @@ -114,7 +113,7 @@ static inline bool nodeMayOverflow(NodeFlags flags, RareCaseProfilingSource sour static inline bool nodeMayNegZero(NodeFlags flags, RareCaseProfilingSource source) { - NodeFlags mask; + NodeFlags mask = 0; switch (source) { case BaselineRareCase: mask = NodeMayNegZeroInBaseline; diff --git a/dfg/DFGNodeOrigin.h b/dfg/DFGNodeOrigin.h index 472f134..12cc064 100644 --- a/dfg/DFGNodeOrigin.h +++ b/dfg/DFGNodeOrigin.h @@ -49,6 +49,7 @@ struct NodeOrigin { bool isSet() const { + ASSERT(semantic.isSet() == forExit.isSet()); return semantic.isSet(); } diff --git a/dfg/DFGNodeType.h b/dfg/DFGNodeType.h index 37433e3..69f6ae5 100644 --- a/dfg/DFGNodeType.h +++ b/dfg/DFGNodeType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,15 +35,11 @@ namespace JSC { namespace DFG { // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below. #define FOR_EACH_DFG_OP(macro) \ /* A constant in the CodeBlock's constant pool. */\ - macro(JSConstant, NodeResultJS | NodeDoesNotExit) \ + macro(JSConstant, NodeResultJS) \ \ /* Constants with specific representations. */\ - macro(DoubleConstant, NodeResultDouble | NodeDoesNotExit) \ - macro(Int52Constant, NodeResultInt52 | NodeDoesNotExit) \ - \ - /* A constant not in the CodeBlock's constant pool. Uses get patched to jumps that exit the */\ - /* code block. */\ - macro(WeakJSConstant, NodeResultJS | NodeDoesNotExit) \ + macro(DoubleConstant, NodeResultDouble) \ + macro(Int52Constant, NodeResultInt52) \ \ /* 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, */\ @@ -54,22 +50,33 @@ namespace JSC { namespace DFG { macro(ToThis, NodeResultJS) \ macro(CreateThis, NodeResultJS) /* Note this is not MustGenerate since we're returning it anyway. */ \ macro(GetCallee, NodeResultJS) \ + macro(GetArgumentCount, NodeResultInt32) \ \ /* Nodes for local variable access. These nodes are linked together using Phi nodes. */\ /* Any two nodes that are part of the same Phi graph will share the same */\ - /* VariableAccessData, and thus will share predictions. */\ - macro(GetLocal, NodeResultJS) \ + /* VariableAccessData, and thus will share predictions. FIXME: We should come up with */\ + /* better names for a lot of these. https://bugs.webkit.org/show_bug.cgi?id=137307. */\ + /* Note that GetLocal is MustGenerate because it's our only way of knowing that some other */\ + /* basic block might have read a local variable in bytecode. We only remove GetLocals if it */\ + /* is redundant because of an earlier GetLocal or SetLocal in the same block. We could make */\ + /* these not MustGenerate and use a more sophisticated analysis to insert PhantomLocals in */\ + /* the same way that we insert Phantoms. That's hard and probably not profitable. See */\ + /* https://bugs.webkit.org/show_bug.cgi?id=144086 */\ + macro(GetLocal, NodeResultJS | NodeMustGenerate) \ macro(SetLocal, 0) \ - macro(MovHint, NodeDoesNotExit) \ - macro(ZombieHint, NodeDoesNotExit) \ - macro(GetArgument, NodeResultJS | NodeMustGenerate) \ + \ + macro(PutStack, NodeMustGenerate) \ + macro(KillStack, NodeMustGenerate) \ + macro(GetStack, NodeResultJS) \ + \ + macro(MovHint, NodeMustGenerate) \ + macro(ZombieHint, NodeMustGenerate) \ macro(Phantom, NodeMustGenerate) \ - macro(HardPhantom, NodeMustGenerate) /* Like Phantom, but we never remove any of its children. */ \ - macro(Check, 0) /* Used if we want just a type check but not liveness. DCE eithers kills this or converts it to Phantom. */\ - macro(Upsilon, NodeDoesNotExit | NodeRelevantToOSR) \ - macro(Phi, NodeDoesNotExit | NodeRelevantToOSR) \ - macro(Flush, NodeMustGenerate | NodeDoesNotExit) \ - macro(PhantomLocal, NodeMustGenerate | NodeDoesNotExit) \ + macro(Check, NodeMustGenerate) /* Used if we want just a type check but not liveness. Non-checking uses will be removed. */\ + macro(Upsilon, 0) \ + macro(Phi, 0) \ + macro(Flush, NodeMustGenerate) \ + macro(PhantomLocal, NodeMustGenerate) \ \ /* Hint that this is where bytecode thinks is a good place to OSR. Note that this */\ /* will exist even in inlined loops. This has no execution semantics but it must */\ @@ -84,6 +91,7 @@ namespace JSC { namespace DFG { /* Tier-up checks from the DFG to the FTL. */\ macro(CheckTierUpInLoop, NodeMustGenerate) \ macro(CheckTierUpAndOSREnter, NodeMustGenerate) \ + macro(CheckTierUpWithNestedTriggerAndOSREnter, NodeMustGenerate) \ macro(CheckTierUpAtReturn, NodeMustGenerate) \ \ /* Get the value of a local variable, without linking into the VariableAccessData */\ @@ -92,7 +100,7 @@ namespace JSC { namespace DFG { macro(GetLocalUnlinked, NodeResultJS) \ \ /* Marker for an argument being set at the prologue of a function. */\ - macro(SetArgument, NodeDoesNotExit) \ + macro(SetArgument, 0) \ \ /* Marker of location in the IR where we may possibly perform jump replacement to */\ /* invalidate this code block. */\ @@ -123,90 +131,88 @@ namespace JSC { namespace DFG { /* Bogus type asserting node. Useful for testing, disappears during Fixup. */\ macro(FiatInt52, NodeResultJS) \ \ - /* Nodes for arithmetic operations. */\ - macro(ArithAdd, NodeResultNumber) \ - macro(ArithSub, NodeResultNumber) \ - macro(ArithNegate, NodeResultNumber) \ - macro(ArithMul, NodeResultNumber) \ + /* Nodes for arithmetic operations. Note that if they do checks other than just type checks, */\ + /* then they are MustGenerate. This is probably stricter than it needs to be - for example */\ + /* they won't do checks if they are speculated double. Also, we could kill these if we do it */\ + /* before AI starts eliminating downstream operations based on proofs, for example in the */\ + /* case of "var tmp = a + b; return (tmp | 0) == tmp;". If a, b are speculated integer then */\ + /* this is only true if we do the overflow check - hence the need to keep it alive. More */\ + /* generally, we need to keep alive any operation whose checks cause filtration in AI. */\ + macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \ + macro(ArithClz32, NodeResultInt32) \ + macro(ArithSub, NodeResultNumber | NodeMustGenerate) \ + macro(ArithNegate, NodeResultNumber | NodeMustGenerate) \ + macro(ArithMul, NodeResultNumber | NodeMustGenerate) \ macro(ArithIMul, NodeResultInt32) \ - macro(ArithDiv, NodeResultNumber) \ - macro(ArithMod, NodeResultNumber) \ - macro(ArithAbs, NodeResultNumber) \ + macro(ArithDiv, NodeResultNumber | NodeMustGenerate) \ + macro(ArithMod, NodeResultNumber | NodeMustGenerate) \ + macro(ArithAbs, NodeResultNumber | NodeMustGenerate) \ macro(ArithMin, NodeResultNumber) \ macro(ArithMax, NodeResultNumber) \ macro(ArithFRound, NodeResultNumber) \ + macro(ArithPow, NodeResultNumber) \ + macro(ArithRound, NodeResultNumber) \ macro(ArithSqrt, NodeResultNumber) \ macro(ArithSin, NodeResultNumber) \ macro(ArithCos, NodeResultNumber) \ + macro(ArithLog, NodeResultNumber) \ \ /* Add of values may either be arithmetic, or result in string concatenation. */\ - macro(ValueAdd, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ + macro(ValueAdd, NodeResultJS | NodeMustGenerate) \ \ /* Property access. */\ /* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\ /* Since a put to 'length' may invalidate optimizations here, */\ /* this must be the directly subsequent property put. Note that PutByVal */\ /* opcodes use VarArgs beause they may have up to 4 children. */\ - macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \ - macro(PutByValDirect, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ - macro(PutByVal, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ - macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ - macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ - macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ - macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ - macro(PutByIdFlush, NodeMustGenerate | NodeMustGenerate | NodeClobbersWorld) \ - macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ + macro(GetByVal, NodeResultJS | NodeMustGenerate) \ + macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \ + macro(LoadVarargs, NodeMustGenerate) \ + macro(ForwardVarargs, NodeMustGenerate) \ + macro(PutByValDirect, NodeMustGenerate | NodeHasVarArgs) \ + macro(PutByVal, NodeMustGenerate | NodeHasVarArgs) \ + macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs) \ + macro(GetById, NodeResultJS | NodeMustGenerate) \ + macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \ + macro(PutById, NodeMustGenerate) \ + macro(PutByIdFlush, NodeMustGenerate | NodeMustGenerate) \ + macro(PutByIdDirect, NodeMustGenerate) \ macro(CheckStructure, NodeMustGenerate) \ - macro(CheckExecutable, NodeMustGenerate) \ - /* Transition watchpoints are a contract between the party setting the watchpoint */\ - /* and the runtime system, where the party promises that the child object once had */\ - /* the structure being watched, and the runtime system in turn promises that the */\ - /* watchpoint will be turned into an OSR exit if any object with that structure */\ - /* ever transitions to a different structure. Hence, the child object must have */\ - /* previously had a CheckStructure executed on it or we're dealing with an object */\ - /* constant (WeakJSConstant) and the object was known to have that structure at */\ - /* compile-time. In the latter case this means that no structure checks have to be */\ - /* performed for this object by JITted code. In the former case this means that*/\ - /* the object's structure does not need to be rechecked due to side-effecting */\ - /* (clobbering) operations. */\ - macro(StructureTransitionWatchpoint, NodeMustGenerate) \ + macro(GetExecutable, NodeResultJS) \ macro(PutStructure, NodeMustGenerate) \ - macro(PhantomPutStructure, NodeMustGenerate | NodeDoesNotExit) \ - macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \ - macro(ReallocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \ + macro(AllocatePropertyStorage, NodeMustGenerate | NodeResultStorage) \ + macro(ReallocatePropertyStorage, NodeMustGenerate | NodeResultStorage) \ macro(GetButterfly, NodeResultStorage) \ macro(CheckArray, NodeMustGenerate) \ macro(Arrayify, NodeMustGenerate) \ macro(ArrayifyToStructure, NodeMustGenerate) \ macro(GetIndexedPropertyStorage, NodeResultStorage) \ macro(ConstantStoragePointer, NodeResultStorage) \ - macro(TypedArrayWatchpoint, NodeMustGenerate) \ + macro(GetGetter, NodeResultJS) \ + macro(GetSetter, NodeResultJS) \ macro(GetByOffset, NodeResultJS) \ - macro(MultiGetByOffset, NodeResultJS) \ + macro(GetGetterSetterByOffset, NodeResultJS) \ + macro(MultiGetByOffset, NodeResultJS | NodeMustGenerate) \ macro(PutByOffset, NodeMustGenerate) \ macro(MultiPutByOffset, NodeMustGenerate) \ macro(GetArrayLength, NodeResultInt32) \ macro(GetTypedArrayByteOffset, NodeResultInt32) \ macro(GetScope, NodeResultJS) \ - macro(GetMyScope, NodeResultJS) \ - macro(SkipTopScope, NodeResultJS) \ macro(SkipScope, NodeResultJS) \ - macro(GetClosureRegisters, NodeResultStorage) \ macro(GetClosureVar, NodeResultJS) \ macro(PutClosureVar, NodeMustGenerate) \ macro(GetGlobalVar, NodeResultJS) \ macro(PutGlobalVar, NodeMustGenerate) \ macro(NotifyWrite, NodeMustGenerate) \ - macro(VariableWatchpoint, NodeMustGenerate) \ macro(VarInjectionWatchpoint, NodeMustGenerate) \ - macro(FunctionReentryWatchpoint, NodeMustGenerate) \ - macro(CheckFunction, NodeMustGenerate) \ - macro(AllocationProfileWatchpoint, NodeMustGenerate) \ + macro(CheckCell, NodeMustGenerate) \ + macro(CheckNotEmpty, NodeMustGenerate) \ + macro(CheckBadCell, NodeMustGenerate) \ macro(CheckInBounds, NodeMustGenerate) \ \ /* Optimizations for array mutation. */\ - macro(ArrayPush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ - macro(ArrayPop, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ + macro(ArrayPush, NodeResultJS | NodeMustGenerate) \ + macro(ArrayPop, NodeResultJS | NodeMustGenerate) \ \ /* Optimizations for regular expression matching. */\ macro(RegExpExec, NodeResultJS | NodeMustGenerate) \ @@ -218,26 +224,41 @@ namespace JSC { namespace DFG { macro(StringFromCharCode, NodeResultJS) \ \ /* Nodes for comparison operations. */\ - macro(CompareLess, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \ - macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \ - macro(CompareGreater, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \ - macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \ - macro(CompareEq, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \ + macro(CompareLess, NodeResultBoolean | NodeMustGenerate) \ + macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate) \ + macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \ + macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \ + macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \ macro(CompareEqConstant, NodeResultBoolean) \ macro(CompareStrictEq, NodeResultBoolean) \ \ /* Calls. */\ - macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \ - macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \ + macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ + macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ + macro(CallVarargs, NodeResultJS | NodeMustGenerate) \ + macro(CallForwardVarargs, NodeResultJS | NodeMustGenerate) \ + macro(ConstructVarargs, NodeResultJS | NodeMustGenerate) \ + macro(ConstructForwardVarargs, NodeResultJS | NodeMustGenerate) \ + macro(NativeCall, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ + macro(NativeConstruct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ \ /* Allocations. */\ macro(NewObject, NodeResultJS) \ macro(NewArray, NodeResultJS | NodeHasVarArgs) \ macro(NewArrayWithSize, NodeResultJS | NodeMustGenerate) \ macro(NewArrayBuffer, NodeResultJS) \ - macro(NewTypedArray, NodeResultJS | NodeClobbersWorld | NodeMustGenerate) \ + macro(NewTypedArray, NodeResultJS | NodeMustGenerate) \ macro(NewRegexp, NodeResultJS) \ \ + /* Support for allocation sinking. */\ + macro(PhantomNewObject, NodeResultJS | NodeMustGenerate) \ + macro(PutHint, NodeMustGenerate) \ + macro(CheckStructureImmediate, NodeMustGenerate) \ + macro(MaterializeNewObject, NodeResultJS | NodeHasVarArgs) \ + macro(PhantomNewFunction, NodeResultJS | NodeMustGenerate) \ + macro(PhantomCreateActivation, NodeResultJS | NodeMustGenerate) \ + macro(MaterializeCreateActivation, NodeResultJS | NodeHasVarArgs) \ + \ /* Nodes for misc operations. */\ macro(Breakpoint, NodeMustGenerate) \ macro(ProfileWillCall, NodeMustGenerate) \ @@ -249,36 +270,30 @@ namespace JSC { namespace DFG { macro(IsNumber, NodeResultBoolean) \ macro(IsString, NodeResultBoolean) \ macro(IsObject, NodeResultBoolean) \ + macro(IsObjectOrNull, NodeResultBoolean) \ macro(IsFunction, NodeResultBoolean) \ macro(TypeOf, NodeResultJS) \ macro(LogicalNot, NodeResultBoolean) \ - macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ - macro(ToString, NodeResultJS | NodeMustGenerate | NodeMightClobber) \ + macro(ToPrimitive, NodeResultJS | NodeMustGenerate) \ + macro(ToString, NodeResultJS | NodeMustGenerate) \ + macro(CallStringConstructor, NodeResultJS | NodeMustGenerate) \ macro(NewStringObject, NodeResultJS) \ macro(MakeRope, NodeResultJS) \ - macro(In, NodeResultBoolean | NodeMustGenerate | NodeClobbersWorld) \ + macro(In, NodeResultBoolean | NodeMustGenerate) \ + macro(ProfileType, NodeMustGenerate) \ + macro(ProfileControlFlow, NodeMustGenerate) \ \ - /* Nodes used for activations. Activation support works by having it anchored at */\ - /* epilgoues via TearOffActivation, and all CreateActivation nodes kept alive by */\ - /* being threaded with each other. */\ macro(CreateActivation, NodeResultJS) \ - macro(TearOffActivation, NodeMustGenerate) \ - \ - /* Nodes used for arguments. Similar to activation support, only it makes even less */\ - /* sense. */\ - macro(CreateArguments, NodeResultJS) \ - macro(PhantomArguments, NodeResultJS | NodeDoesNotExit) \ - macro(TearOffArguments, NodeMustGenerate) \ - macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate) \ - macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate) \ - macro(GetMyArgumentsLengthSafe, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ - macro(GetMyArgumentByValSafe, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ - macro(CheckArgumentsNotCreated, NodeMustGenerate) \ \ - /* Nodes for creating functions. */\ - macro(NewFunctionNoCheck, NodeResultJS) \ + macro(CreateDirectArguments, NodeResultJS) \ + macro(PhantomDirectArguments, NodeResultJS | NodeMustGenerate) \ + macro(CreateScopedArguments, NodeResultJS) \ + macro(CreateClonedArguments, NodeResultJS) \ + macro(PhantomClonedArguments, NodeResultJS | NodeMustGenerate) \ + macro(GetFromArguments, NodeResultJS) \ + macro(PutToArguments, NodeMustGenerate) \ + \ macro(NewFunction, NodeResultJS) \ - macro(NewFunctionExpression, NodeResultJS) \ \ /* These aren't terminals but always exit */ \ macro(Throw, NodeMustGenerate) \ @@ -299,12 +314,27 @@ namespace JSC { namespace DFG { /* different compiler. */\ macro(ForceOSRExit, NodeMustGenerate) \ \ + /* Vends a bottom JS value. It is invalid to ever execute this. Useful for cases */\ + /* where we know that we would have exited but we'd like to still track the control */\ + /* flow. */\ + macro(BottomValue, NodeResultJS) \ + \ /* Checks the watchdog timer. If the timer has fired, we OSR exit to the */ \ /* baseline JIT to redo the watchdog timer check, and service the timer. */ \ macro(CheckWatchdogTimer, NodeMustGenerate) \ /* Write barriers ! */\ macro(StoreBarrier, NodeMustGenerate) \ - macro(StoreBarrierWithNullCheck, NodeMustGenerate) \ + \ + /* For-in enumeration opcodes */\ + macro(GetEnumerableLength, NodeMustGenerate | NodeResultJS) \ + macro(HasIndexedProperty, NodeResultBoolean) \ + macro(HasStructureProperty, NodeResultBoolean) \ + macro(HasGenericProperty, NodeResultBoolean) \ + macro(GetDirectPname, NodeMustGenerate | NodeHasVarArgs | NodeResultJS) \ + macro(GetPropertyEnumerator, NodeMustGenerate | NodeResultJS) \ + macro(GetEnumeratorStructurePname, NodeMustGenerate | NodeResultJS) \ + macro(GetEnumeratorGenericPname, NodeMustGenerate | NodeResultJS) \ + macro(ToIndexString, NodeResultJS) // This enum generates a monotonically increasing id for all Node types, // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask). diff --git a/dfg/DFGOSRAvailabilityAnalysisPhase.cpp b/dfg/DFGOSRAvailabilityAnalysisPhase.cpp index fbb2e1f..ff5fd95 100644 --- a/dfg/DFGOSRAvailabilityAnalysisPhase.cpp +++ b/dfg/DFGOSRAvailabilityAnalysisPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,7 @@ #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" +#include "DFGPromoteHeapAccess.h" #include "JSCInlines.h" namespace JSC { namespace DFG { @@ -51,27 +52,22 @@ public: BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; - block->ssa->availabilityAtHead.fill(Availability()); - block->ssa->availabilityAtTail.fill(Availability()); + block->ssa->availabilityAtHead.clear(); + block->ssa->availabilityAtTail.clear(); } BasicBlock* root = m_graph.block(0); - for (unsigned argument = root->ssa->availabilityAtHead.numberOfArguments(); argument--;) { - root->ssa->availabilityAtHead.argument(argument) = - Availability::unavailable().withFlush( - FlushedAt(FlushedJSValue, virtualRegisterForArgument(argument))); + root->ssa->availabilityAtHead.m_locals.fill(Availability::unavailable()); + for (unsigned argument = m_graph.m_argumentFormats.size(); argument--;) { + FlushedAt flushedAt = FlushedAt( + m_graph.m_argumentFormats[argument], + virtualRegisterForArgument(argument)); + root->ssa->availabilityAtHead.m_locals.argument(argument) = Availability(flushedAt); } - if (m_graph.m_plan.mode == FTLForOSREntryMode) { - for (unsigned local = m_graph.m_profiledBlock->m_numCalleeRegisters; local--;) - root->ssa->availabilityAtHead.local(local) = Availability::unavailable(); - } else { - for (unsigned local = root->ssa->availabilityAtHead.numberOfLocals(); local--;) - root->ssa->availabilityAtHead.local(local) = Availability::unavailable(); - } - // This could be made more efficient by processing blocks in reverse postorder. - Operands<Availability> availability; + + LocalOSRAvailabilityCalculator calculator; bool changed; do { changed = false; @@ -81,55 +77,22 @@ public: if (!block) continue; - availability = block->ssa->availabilityAtHead; + calculator.beginBlock(block); - for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { - Node* node = block->at(nodeIndex); - - switch (node->op()) { - case SetLocal: { - VariableAccessData* variable = node->variableAccessData(); - availability.operand(variable->local()) = - Availability(node->child1().node(), variable->flushedAt()); - break; - } - - case GetArgument: { - VariableAccessData* variable = node->variableAccessData(); - availability.operand(variable->local()) = - Availability(node, variable->flushedAt()); - break; - } - - case MovHint: { - availability.operand(node->unlinkedLocal()) = - Availability(node->child1().node()); - break; - } - - case ZombieHint: { - availability.operand(node->unlinkedLocal()) = - Availability::unavailable(); - break; - } - - default: - break; - } - } + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) + calculator.executeNode(block->at(nodeIndex)); - if (availability == block->ssa->availabilityAtTail) + if (calculator.m_availability == block->ssa->availabilityAtTail) continue; - block->ssa->availabilityAtTail = availability; + block->ssa->availabilityAtTail = calculator.m_availability; changed = true; for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { BasicBlock* successor = block->successor(successorIndex); - for (unsigned i = availability.size(); i--;) { - successor->ssa->availabilityAtHead[i] = availability[i].merge( - successor->ssa->availabilityAtHead[i]); - } + successor->ssa->availabilityAtHead.merge(calculator.m_availability); + successor->ssa->availabilityAtHead.pruneByLiveness( + m_graph, successor->firstOrigin().forExit); } } } while (changed); @@ -144,6 +107,110 @@ bool performOSRAvailabilityAnalysis(Graph& graph) return runPhase<OSRAvailabilityAnalysisPhase>(graph); } +LocalOSRAvailabilityCalculator::LocalOSRAvailabilityCalculator() +{ +} + +LocalOSRAvailabilityCalculator::~LocalOSRAvailabilityCalculator() +{ +} + +void LocalOSRAvailabilityCalculator::beginBlock(BasicBlock* block) +{ + m_availability = block->ssa->availabilityAtHead; +} + +void LocalOSRAvailabilityCalculator::endBlock(BasicBlock* block) +{ + m_availability = block->ssa->availabilityAtTail; +} + +void LocalOSRAvailabilityCalculator::executeNode(Node* node) +{ + switch (node->op()) { + case PutStack: { + StackAccessData* data = node->stackAccessData(); + m_availability.m_locals.operand(data->local).setFlush(data->flushedAt()); + break; + } + + case KillStack: { + m_availability.m_locals.operand(node->unlinkedLocal()).setFlush(FlushedAt(ConflictingFlush)); + break; + } + + case GetStack: { + StackAccessData* data = node->stackAccessData(); + m_availability.m_locals.operand(data->local) = Availability(node, data->flushedAt()); + break; + } + + case MovHint: { + m_availability.m_locals.operand(node->unlinkedLocal()).setNode(node->child1().node()); + break; + } + + case ZombieHint: { + m_availability.m_locals.operand(node->unlinkedLocal()).setNodeUnavailable(); + break; + } + + case LoadVarargs: + case ForwardVarargs: { + LoadVarargsData* data = node->loadVarargsData(); + m_availability.m_locals.operand(data->count) = + Availability(FlushedAt(FlushedInt32, data->machineCount)); + for (unsigned i = data->limit; i--;) { + m_availability.m_locals.operand(VirtualRegister(data->start.offset() + i)) = + Availability(FlushedAt(FlushedJSValue, VirtualRegister(data->machineStart.offset() + i))); + } + break; + } + + case PhantomDirectArguments: + case PhantomClonedArguments: { + InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; + if (!inlineCallFrame) { + // We don't need to record anything about how the arguments are to be recovered. It's just a + // given that we can read them from the stack. + break; + } + + if (inlineCallFrame->isVarargs()) { + // Record how to read each argument and the argument count. + Availability argumentCount = + m_availability.m_locals.operand(inlineCallFrame->stackOffset + JSStack::ArgumentCount); + + m_availability.m_heap.set(PromotedHeapLocation(ArgumentCountPLoc, node), argumentCount); + } + + if (inlineCallFrame->isClosureCall) { + Availability callee = m_availability.m_locals.operand( + inlineCallFrame->stackOffset + JSStack::Callee); + m_availability.m_heap.set(PromotedHeapLocation(ArgumentsCalleePLoc, node), callee); + } + + for (unsigned i = 0; i < inlineCallFrame->arguments.size() - 1; ++i) { + Availability argument = m_availability.m_locals.operand( + inlineCallFrame->stackOffset + CallFrame::argumentOffset(i)); + + m_availability.m_heap.set(PromotedHeapLocation(ArgumentPLoc, node, i), argument); + } + break; + } + + case PutHint: { + m_availability.m_heap.set( + PromotedHeapLocation(node->child1().node(), node->promotedLocationDescriptor()), + Availability(node->child2().node())); + break; + } + + default: + break; + } +} + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGOSRAvailabilityAnalysisPhase.h b/dfg/DFGOSRAvailabilityAnalysisPhase.h index a5ec71b..064bec0 100644 --- a/dfg/DFGOSRAvailabilityAnalysisPhase.h +++ b/dfg/DFGOSRAvailabilityAnalysisPhase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,7 @@ #if ENABLE(DFG_JIT) +#include "DFGBasicBlock.h" #include "DFGCommon.h" namespace JSC { namespace DFG { @@ -35,10 +36,27 @@ namespace JSC { namespace DFG { class Graph; // Computes BasicBlock::ssa->availabiltiyAtHead/Tail. This is a forward flow type inference -// over MovHints and SetLocals. +// over MovHints and SetLocals. This analysis is run directly by the Plan for preparing for +// lowering to LLVM IR, but it can also be used as a utility. Note that if you run it before +// stack layout, all of the flush availability will omit the virtual register - but it will +// tell you the format. bool performOSRAvailabilityAnalysis(Graph&); +// Local calculator for figuring out the availability at any node in a basic block. Requires +// having run the availability analysis. +class LocalOSRAvailabilityCalculator { +public: + LocalOSRAvailabilityCalculator(); + ~LocalOSRAvailabilityCalculator(); + + void beginBlock(BasicBlock*); + void endBlock(BasicBlock*); // Useful if you want to get data for the end of the block. You don't need to call this if you did beginBlock() and then executeNode() for every node. + void executeNode(Node*); + + AvailabilityMap m_availability; +}; + } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGOSREntry.cpp b/dfg/DFGOSREntry.cpp index e5cd42d..a2142e8 100644 --- a/dfg/DFGOSREntry.cpp +++ b/dfg/DFGOSREntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,9 +35,61 @@ #include "JIT.h" #include "JSStackInlines.h" #include "JSCInlines.h" +#include <wtf/CommaPrinter.h> namespace JSC { namespace DFG { +void OSREntryData::dumpInContext(PrintStream& out, DumpContext* context) const +{ + out.print("bc#", m_bytecodeIndex, ", machine code offset = ", m_machineCodeOffset); + out.print(", stack rules = ["); + + auto printOperand = [&] (VirtualRegister reg) { + out.print(inContext(m_expectedValues.operand(reg), context), " ("); + VirtualRegister toReg; + bool overwritten = false; + for (OSREntryReshuffling reshuffling : m_reshufflings) { + if (reg == VirtualRegister(reshuffling.fromOffset)) { + toReg = VirtualRegister(reshuffling.toOffset); + break; + } + if (reg == VirtualRegister(reshuffling.toOffset)) + overwritten = true; + } + if (!overwritten && !toReg.isValid()) + toReg = reg; + if (toReg.isValid()) { + if (toReg.isLocal() && !m_machineStackUsed.get(toReg.toLocal())) + out.print("ignored"); + else + out.print("maps to ", toReg); + } else + out.print("overwritten"); + if (reg.isLocal() && m_localsForcedDouble.get(reg.toLocal())) + out.print(", forced double"); + if (reg.isLocal() && m_localsForcedMachineInt.get(reg.toLocal())) + out.print(", forced machine int"); + out.print(")"); + }; + + CommaPrinter comma; + for (size_t argumentIndex = m_expectedValues.numberOfArguments(); argumentIndex--;) { + out.print(comma, "arg", argumentIndex, ":"); + printOperand(virtualRegisterForArgument(argumentIndex)); + } + for (size_t localIndex = 0; localIndex < m_expectedValues.numberOfLocals(); ++localIndex) { + out.print(comma, "loc", localIndex, ":"); + printOperand(virtualRegisterForLocal(localIndex)); + } + + out.print("], machine stack used = ", m_machineStackUsed); +} + +void OSREntryData::dump(PrintStream& out) const +{ + dumpInContext(out, nullptr); +} + void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex) { ASSERT(JITCode::isOptimizingJIT(codeBlock->jitType())); @@ -58,6 +110,9 @@ void* prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIn sanitizeStackForVM(vm); + if (bytecodeIndex) + codeBlock->ownerExecutable()->setDidTryToEnterInLoop(true); + if (codeBlock->jitType() != JITCode::DFGJIT) { RELEASE_ASSERT(codeBlock->jitType() == JITCode::FTLJIT); diff --git a/dfg/DFGOSREntry.h b/dfg/DFGOSREntry.h index 4f860a2..04aaabf 100644 --- a/dfg/DFGOSREntry.h +++ b/dfg/DFGOSREntry.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,6 +60,9 @@ struct OSREntryData { BitVector m_localsForcedMachineInt; Vector<OSREntryReshuffling> m_reshufflings; BitVector m_machineStackUsed; + + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; }; inline unsigned getOSREntryDataBytecodeIndex(OSREntryData* osrEntryData) diff --git a/dfg/DFGOSRExit.h b/dfg/DFGOSRExit.h index a023534..d336d04 100644 --- a/dfg/DFGOSRExit.h +++ b/dfg/DFGOSRExit.h @@ -32,7 +32,6 @@ #include "DFGCommon.h" #include "DFGExitProfile.h" #include "DFGOSRExitBase.h" -#include "DFGValueRecoveryOverride.h" #include "GPRInfo.h" #include "MacroAssembler.h" #include "MethodOfGettingAValueProfile.h" @@ -102,11 +101,9 @@ struct OSRExit : public OSRExitBase { unsigned m_streamIndex; - RefPtr<ValueRecoveryOverride> m_valueRecoveryOverride; - - bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock) + void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock) { - return OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromDFG); + OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromDFG); } }; diff --git a/dfg/DFGOSRExitBase.cpp b/dfg/DFGOSRExitBase.cpp index e2f2066..afc50e8 100644 --- a/dfg/DFGOSRExitBase.cpp +++ b/dfg/DFGOSRExitBase.cpp @@ -35,15 +35,13 @@ namespace JSC { namespace DFG { -bool OSRExitBase::considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock, ExitingJITType jitType) +void OSRExitBase::considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock, ExitingJITType jitType) { CodeBlock* sourceProfiledCodeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock( m_codeOriginForExitProfile, profiledCodeBlock); - if (!sourceProfiledCodeBlock) - return false; - return sourceProfiledCodeBlock->addFrequentExitSite( - FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType)); + if (sourceProfiledCodeBlock) + sourceProfiledCodeBlock->addFrequentExitSite(FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType)); } } } // namespace JSC::DFG diff --git a/dfg/DFGOSRExitBase.h b/dfg/DFGOSRExitBase.h index 03df1db..099b2d5 100644 --- a/dfg/DFGOSRExitBase.h +++ b/dfg/DFGOSRExitBase.h @@ -57,15 +57,14 @@ struct OSRExitBase { CodeOrigin m_codeOriginForExitProfile; protected: - bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock, ExitingJITType jitType) + void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock, ExitingJITType jitType) { - if (!m_count) - return false; - return considerAddingAsFrequentExitSiteSlow(profiledCodeBlock, jitType); + if (m_count) + considerAddingAsFrequentExitSiteSlow(profiledCodeBlock, jitType); } private: - bool considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock, ExitingJITType); + void considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock, ExitingJITType); }; } } // namespace JSC::DFG diff --git a/dfg/DFGOSRExitCompiler.cpp b/dfg/DFGOSRExitCompiler.cpp index 6f7ef0d..23d51c6 100644 --- a/dfg/DFGOSRExitCompiler.cpp +++ b/dfg/DFGOSRExitCompiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011-2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,6 +40,75 @@ namespace JSC { namespace DFG { +void OSRExitCompiler::emitRestoreArguments(const Operands<ValueRecovery>& operands) +{ + HashMap<MinifiedID, int> alreadyAllocatedArguments; // Maps phantom arguments node ID to operand. + for (size_t index = 0; index < operands.size(); ++index) { + const ValueRecovery& recovery = operands[index]; + int operand = operands.operandForIndex(index); + + if (recovery.technique() != DirectArgumentsThatWereNotCreated + && recovery.technique() != ClonedArgumentsThatWereNotCreated) + continue; + + MinifiedID id = recovery.nodeID(); + auto iter = alreadyAllocatedArguments.find(id); + if (iter != alreadyAllocatedArguments.end()) { + JSValueRegs regs = JSValueRegs::withTwoAvailableRegs(GPRInfo::regT0, GPRInfo::regT1); + m_jit.loadValue(CCallHelpers::addressFor(iter->value), regs); + m_jit.storeValue(regs, CCallHelpers::addressFor(operand)); + continue; + } + + InlineCallFrame* inlineCallFrame = + m_jit.codeBlock()->jitCode()->dfg()->minifiedDFG.at(id)->inlineCallFrame(); + + int stackOffset; + if (inlineCallFrame) + stackOffset = inlineCallFrame->stackOffset; + else + stackOffset = 0; + + if (!inlineCallFrame || inlineCallFrame->isClosureCall) { + m_jit.loadPtr( + AssemblyHelpers::addressFor(stackOffset + JSStack::Callee), + GPRInfo::regT0); + } else { + m_jit.move( + AssemblyHelpers::TrustedImmPtr(inlineCallFrame->calleeRecovery.constant().asCell()), + GPRInfo::regT0); + } + + if (!inlineCallFrame || inlineCallFrame->isVarargs()) { + m_jit.load32( + AssemblyHelpers::payloadFor(stackOffset + JSStack::ArgumentCount), + GPRInfo::regT1); + } else { + m_jit.move( + AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), + GPRInfo::regT1); + } + + m_jit.setupArgumentsWithExecState( + AssemblyHelpers::TrustedImmPtr(inlineCallFrame), GPRInfo::regT0, GPRInfo::regT1); + switch (recovery.technique()) { + case DirectArgumentsThatWereNotCreated: + m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCreateDirectArgumentsDuringExit)), GPRInfo::nonArgGPR0); + break; + case ClonedArgumentsThatWereNotCreated: + m_jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCreateClonedArgumentsDuringExit)), GPRInfo::nonArgGPR0); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + m_jit.call(GPRInfo::nonArgGPR0); + m_jit.storeCell(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(operand)); + + alreadyAllocatedArguments.add(id, operand); + } +} + extern "C" { void compileOSRExit(ExecState* exec) @@ -66,12 +135,6 @@ void compileOSRExit(ExecState* exec) Operands<ValueRecovery> operands; codeBlock->jitCode()->dfg()->variableEventStream.reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->jitCode()->dfg()->minifiedDFG, exit.m_streamIndex, operands); - // There may be an override, for forward speculations. - if (!!exit.m_valueRecoveryOverride) { - operands.setOperand( - exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery); - } - SpeculationRecovery* recovery = 0; if (exit.m_recoveryIndex != UINT_MAX) recovery = &codeBlock->jitCode()->dfg()->speculationRecovery[exit.m_recoveryIndex]; @@ -88,7 +151,7 @@ void compileOSRExit(ExecState* exec) Profiler::OSRExit* profilerExit = compilation->addOSRExit( exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin), - exit.m_kind, isWatchpoint(exit.m_kind)); + exit.m_kind, exit.m_kind == UncountableInvalidation); jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress())); } diff --git a/dfg/DFGOSRExitCompiler.h b/dfg/DFGOSRExitCompiler.h index 556fe0b..cb262d4 100644 --- a/dfg/DFGOSRExitCompiler.h +++ b/dfg/DFGOSRExitCompiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -49,28 +49,9 @@ public: void compileExit(const OSRExit&, const Operands<ValueRecovery>&, SpeculationRecovery*); private: -#if !ASSERT_DISABLED - static unsigned badIndex() { return static_cast<unsigned>(-1); }; -#endif - - void initializePoisoned(unsigned size) - { -#if ASSERT_DISABLED - m_poisonScratchIndices.resize(size); -#else - m_poisonScratchIndices.fill(badIndex(), size); -#endif - } - - unsigned poisonIndex(unsigned index) - { - unsigned result = m_poisonScratchIndices[index]; - ASSERT(result != badIndex()); - return result; - } + void emitRestoreArguments(const Operands<ValueRecovery>&); CCallHelpers& m_jit; - Vector<unsigned> m_poisonScratchIndices; }; extern "C" { diff --git a/dfg/DFGOSRExitCompiler32_64.cpp b/dfg/DFGOSRExitCompiler32_64.cpp index 346eeb5..0851a58 100644 --- a/dfg/DFGOSRExitCompiler32_64.cpp +++ b/dfg/DFGOSRExitCompiler32_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,7 +38,7 @@ namespace JSC { namespace DFG { void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecovery>& operands, SpeculationRecovery* recovery) { - // 1) Pro-forma stuff. + // Pro-forma stuff. if (Options::printEachOSRExit()) { SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo; debugInfo->codeBlock = m_jit.codeBlock(); @@ -48,14 +48,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov m_jit.debugCall(debugOperationPrintSpeculationFailure, debugInfo); } - // Need to ensure that the stack pointer accounts for the worst-case stack usage at exit. - m_jit.addPtr( - CCallHelpers::TrustedImm32( - -m_jit.codeBlock()->jitCode()->dfgCommon()->requiredRegisterCountForExit * sizeof(Register)), - CCallHelpers::framePointerRegister, CCallHelpers::stackPointerRegister); - - // 2) Perform speculation recovery. This only comes into play when an operation - // starts mutating state before verifying the speculation it has already made. + // Perform speculation recovery. This only comes into play when an operation + // starts mutating state before verifying the speculation it has already made. if (recovery) { switch (recovery->type()) { @@ -71,7 +65,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov } } - // 3) Refine some value profile, if appropriate. + // Refine some value profile, if appropriate. if (!!exit.m_jsValueSource) { if (exit.m_kind == BadCache || exit.m_kind == BadIndexingType) { @@ -108,13 +102,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov scratch1 = AssemblyHelpers::selectScratchGPR(usedRegister1, usedRegister2); scratch2 = AssemblyHelpers::selectScratchGPR(usedRegister1, usedRegister2, scratch1); -#if CPU(ARM64) - m_jit.pushToSave(scratch1); - m_jit.pushToSave(scratch2); -#else m_jit.push(scratch1); m_jit.push(scratch2); -#endif GPRReg value; if (exit.m_jsValueSource.isAddress()) { @@ -130,13 +119,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov m_jit.lshift32(scratch1, scratch2); m_jit.or32(scratch2, AssemblyHelpers::AbsoluteAddress(arrayProfile->addressOfArrayModes())); -#if CPU(ARM64) - m_jit.popToRestore(scratch2); - m_jit.popToRestore(scratch1); -#else m_jit.pop(scratch2); m_jit.pop(scratch1); -#endif } } @@ -147,22 +131,14 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // Save a register so we can use it. GPRReg scratch = AssemblyHelpers::selectScratchGPR(exit.m_jsValueSource.base()); -#if CPU(ARM64) - m_jit.pushToSave(scratch); -#else m_jit.push(scratch); -#endif m_jit.load32(exit.m_jsValueSource.asAddress(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), scratch); m_jit.store32(scratch, &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag); m_jit.load32(exit.m_jsValueSource.asAddress(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), scratch); m_jit.store32(scratch, &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload); -#if CPU(ARM64) - m_jit.popToRestore(scratch); -#else m_jit.pop(scratch); -#endif } else if (exit.m_jsValueSource.hasKnownTag()) { m_jit.store32(AssemblyHelpers::TrustedImm32(exit.m_jsValueSource.tag()), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.tag); m_jit.store32(exit.m_jsValueSource.payloadGPR(), &bitwise_cast<EncodedValueDescriptor*>(bucket)->asBits.payload); @@ -176,7 +152,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // Do a simplified OSR exit. See DFGOSRExitCompiler64.cpp's comment regarding how and wny we // do this simple approach. - // 4) Save all state from GPRs into the scratch buffer. + // Save all state from GPRs into the scratch buffer. ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(sizeof(EncodedJSValue) * operands.size()); EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; @@ -209,7 +185,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // Now all GPRs are free to reuse. - // 5) Save all state from FPRs into the scratch buffer. + // Save all state from FPRs into the scratch buffer. for (size_t index = 0; index < operands.size(); ++index) { const ValueRecovery& recovery = operands[index]; @@ -227,9 +203,9 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // Now all FPRs are free to reuse. - // 6) Save all state from the stack into the scratch buffer. For simplicity we - // do this even for state that's already in the right place on the stack. - // It makes things simpler later. + // Save all state from the stack into the scratch buffer. For simplicity we + // do this even for state that's already in the right place on the stack. + // It makes things simpler later. for (size_t index = 0; index < operands.size(); ++index) { const ValueRecovery& recovery = operands[index]; @@ -259,9 +235,15 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov } } - // 7) Do all data format conversions and store the results into the stack. + // Need to ensure that the stack pointer accounts for the worst-case stack usage at exit. This + // could toast some stack that the DFG used. We need to do it before storing to stack offsets + // used by baseline. + m_jit.addPtr( + CCallHelpers::TrustedImm32( + -m_jit.codeBlock()->jitCode()->dfgCommon()->requiredRegisterCountForExit * sizeof(Register)), + CCallHelpers::framePointerRegister, CCallHelpers::stackPointerRegister); - bool haveArguments = false; + // Do all data format conversions and store the results into the stack. for (size_t index = 0; index < operands.size(); ++index) { const ValueRecovery& recovery = operands[index]; @@ -340,14 +322,9 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov AssemblyHelpers::payloadFor(operand)); break; - case ArgumentsThatWereNotCreated: - haveArguments = true; - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue().tag()), - AssemblyHelpers::tagFor(operand)); - m_jit.store32( - AssemblyHelpers::TrustedImm32(JSValue().payload()), - AssemblyHelpers::payloadFor(operand)); + case DirectArgumentsThatWereNotCreated: + case ClonedArgumentsThatWereNotCreated: + // Don't do this, yet. break; default: @@ -355,64 +332,57 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov } } - // 8) Adjust the old JIT's execute counter. Since we are exiting OSR, we know - // that all new calls into this code will go to the new JIT, so the execute - // counter only affects call frames that performed OSR exit and call frames - // that were still executing the old JIT at the time of another call frame's - // OSR exit. We want to ensure that the following is true: + // Now that things on the stack are recovered, do the arguments recovery. We assume that arguments + // recoveries don't recursively refer to each other. But, we don't try to assume that they only + // refer to certain ranges of locals. Hence why we need to do this here, once the stack is sensible. + // Note that we also roughly assume that the arguments might still be materialized outside of its + // inline call frame scope - but for now the DFG wouldn't do that. + + emitRestoreArguments(operands); + + // Adjust the old JIT's execute counter. Since we are exiting OSR, we know + // that all new calls into this code will go to the new JIT, so the execute + // counter only affects call frames that performed OSR exit and call frames + // that were still executing the old JIT at the time of another call frame's + // OSR exit. We want to ensure that the following is true: // - // (a) Code the performs an OSR exit gets a chance to reenter optimized - // code eventually, since optimized code is faster. But we don't - // want to do such reentery too aggressively (see (c) below). + // (a) Code the performs an OSR exit gets a chance to reenter optimized + // code eventually, since optimized code is faster. But we don't + // want to do such reentery too aggressively (see (c) below). // - // (b) If there is code on the call stack that is still running the old - // JIT's code and has never OSR'd, then it should get a chance to - // perform OSR entry despite the fact that we've exited. + // (b) If there is code on the call stack that is still running the old + // JIT's code and has never OSR'd, then it should get a chance to + // perform OSR entry despite the fact that we've exited. // - // (c) Code the performs an OSR exit should not immediately retry OSR - // entry, since both forms of OSR are expensive. OSR entry is - // particularly expensive. + // (c) Code the performs an OSR exit should not immediately retry OSR + // entry, since both forms of OSR are expensive. OSR entry is + // particularly expensive. // - // (d) Frequent OSR failures, even those that do not result in the code - // running in a hot loop, result in recompilation getting triggered. + // (d) Frequent OSR failures, even those that do not result in the code + // running in a hot loop, result in recompilation getting triggered. // - // To ensure (c), we'd like to set the execute counter to - // counterValueForOptimizeAfterWarmUp(). This seems like it would endanger - // (a) and (b), since then every OSR exit would delay the opportunity for - // every call frame to perform OSR entry. Essentially, if OSR exit happens - // frequently and the function has few loops, then the counter will never - // become non-negative and OSR entry will never be triggered. OSR entry - // will only happen if a loop gets hot in the old JIT, which does a pretty - // good job of ensuring (a) and (b). But that doesn't take care of (d), - // since each speculation failure would reset the execute counter. - // So we check here if the number of speculation failures is significantly - // larger than the number of successes (we want 90% success rate), and if - // there have been a large enough number of failures. If so, we set the - // counter to 0; otherwise we set the counter to - // counterValueForOptimizeAfterWarmUp(). + // To ensure (c), we'd like to set the execute counter to + // counterValueForOptimizeAfterWarmUp(). This seems like it would endanger + // (a) and (b), since then every OSR exit would delay the opportunity for + // every call frame to perform OSR entry. Essentially, if OSR exit happens + // frequently and the function has few loops, then the counter will never + // become non-negative and OSR entry will never be triggered. OSR entry + // will only happen if a loop gets hot in the old JIT, which does a pretty + // good job of ensuring (a) and (b). But that doesn't take care of (d), + // since each speculation failure would reset the execute counter. + // So we check here if the number of speculation failures is significantly + // larger than the number of successes (we want 90% success rate), and if + // there have been a large enough number of failures. If so, we set the + // counter to 0; otherwise we set the counter to + // counterValueForOptimizeAfterWarmUp(). handleExitCounts(m_jit, exit); - // 9) Reify inlined call frames. + // Reify inlined call frames. reifyInlinedCallFrames(m_jit, exit); - // 10) Create arguments if necessary and place them into the appropriate aliased - // registers. - - if (haveArguments) { - ArgumentsRecoveryGenerator argumentsRecovery; - - for (size_t index = 0; index < operands.size(); ++index) { - const ValueRecovery& recovery = operands[index]; - if (recovery.technique() != ArgumentsThatWereNotCreated) - continue; - argumentsRecovery.generateFor( - operands.operandForIndex(index), exit.m_codeOrigin, m_jit); - } - } - - // 12) And finish. + // And finish. adjustAndJumpToTarget(m_jit, exit); } diff --git a/dfg/DFGOSRExitCompiler64.cpp b/dfg/DFGOSRExitCompiler64.cpp index 3e2c4a6..5bb0a4f 100644 --- a/dfg/DFGOSRExitCompiler64.cpp +++ b/dfg/DFGOSRExitCompiler64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,7 +42,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov { m_jit.jitAssertTagsInPlace(); - // 1) Pro-forma stuff. + // Pro-forma stuff. if (Options::printEachOSRExit()) { SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo; debugInfo->codeBlock = m_jit.codeBlock(); @@ -52,14 +52,8 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov m_jit.debugCall(debugOperationPrintSpeculationFailure, debugInfo); } - // Need to ensure that the stack pointer accounts for the worst-case stack usage at exit. - m_jit.addPtr( - CCallHelpers::TrustedImm32( - -m_jit.codeBlock()->jitCode()->dfgCommon()->requiredRegisterCountForExit * sizeof(Register)), - CCallHelpers::framePointerRegister, CCallHelpers::stackPointerRegister); - - // 2) Perform speculation recovery. This only comes into play when an operation - // starts mutating state before verifying the speculation it has already made. + // Perform speculation recovery. This only comes into play when an operation + // starts mutating state before verifying the speculation it has already made. if (recovery) { switch (recovery->type()) { @@ -77,7 +71,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov } } - // 3) Refine some array and/or value profile, if appropriate. + // Refine some array and/or value profile, if appropriate. if (!!exit.m_jsValueSource) { if (exit.m_kind == BadCache || exit.m_kind == BadIndexingType) { @@ -103,13 +97,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov scratch1 = AssemblyHelpers::selectScratchGPR(usedRegister); scratch2 = AssemblyHelpers::selectScratchGPR(usedRegister, scratch1); -#if CPU(ARM64) - m_jit.pushToSave(scratch1); - m_jit.pushToSave(scratch2); -#else - m_jit.push(scratch1); - m_jit.push(scratch2); -#endif + if (isARM64()) { + m_jit.pushToSave(scratch1); + m_jit.pushToSave(scratch2); + } else { + m_jit.push(scratch1); + m_jit.push(scratch2); + } GPRReg value; if (exit.m_jsValueSource.isAddress()) { @@ -125,13 +119,13 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov m_jit.lshift32(scratch1, scratch2); m_jit.or32(scratch2, AssemblyHelpers::AbsoluteAddress(arrayProfile->addressOfArrayModes())); -#if CPU(ARM64) - m_jit.popToRestore(scratch2); - m_jit.popToRestore(scratch1); -#else - m_jit.pop(scratch2); - m_jit.pop(scratch1); -#endif + if (isARM64()) { + m_jit.popToRestore(scratch2); + m_jit.popToRestore(scratch1); + } else { + m_jit.pop(scratch2); + m_jit.pop(scratch1); + } } } @@ -185,7 +179,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // variable" from "how was it represented", which will make it more difficult to add // features in the future and it will make it harder to reason about bugs. - // 4) Save all state from GPRs into the scratch buffer. + // Save all state from GPRs into the scratch buffer. ScratchBuffer* scratchBuffer = m_jit.vm()->scratchBufferForSize(sizeof(EncodedJSValue) * operands.size()); EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; @@ -209,7 +203,7 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // And voila, all GPRs are free to reuse. - // 5) Save all state from FPRs into the scratch buffer. + // Save all state from FPRs into the scratch buffer. for (size_t index = 0; index < operands.size(); ++index) { const ValueRecovery& recovery = operands[index]; @@ -227,9 +221,9 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov // Now, all FPRs are also free. - // 6) Save all state from the stack into the scratch buffer. For simplicity we - // do this even for state that's already in the right place on the stack. - // It makes things simpler later. + // Save all state from the stack into the scratch buffer. For simplicity we + // do this even for state that's already in the right place on the stack. + // It makes things simpler later. for (size_t index = 0; index < operands.size(); ++index) { const ValueRecovery& recovery = operands[index]; @@ -251,9 +245,15 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov } } - // 7) Do all data format conversions and store the results into the stack. + // Need to ensure that the stack pointer accounts for the worst-case stack usage at exit. This + // could toast some stack that the DFG used. We need to do it before storing to stack offsets + // used by baseline. + m_jit.addPtr( + CCallHelpers::TrustedImm32( + -m_jit.codeBlock()->jitCode()->dfgCommon()->requiredRegisterCountForExit * sizeof(Register)), + CCallHelpers::framePointerRegister, CCallHelpers::stackPointerRegister); - bool haveArguments = false; + // Do all data format conversions and store the results into the stack. for (size_t index = 0; index < operands.size(); ++index) { const ValueRecovery& recovery = operands[index]; @@ -308,78 +308,68 @@ void OSRExitCompiler::compileExit(const OSRExit& exit, const Operands<ValueRecov AssemblyHelpers::addressFor(operand)); break; - case ArgumentsThatWereNotCreated: - haveArguments = true; - // We can't restore this yet but we can make sure that the stack appears - // sane. - m_jit.store64( - AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue())), - AssemblyHelpers::addressFor(operand)); + case DirectArgumentsThatWereNotCreated: + case ClonedArgumentsThatWereNotCreated: + // Don't do this, yet. break; default: + RELEASE_ASSERT_NOT_REACHED(); break; } } - // 8) Adjust the old JIT's execute counter. Since we are exiting OSR, we know - // that all new calls into this code will go to the new JIT, so the execute - // counter only affects call frames that performed OSR exit and call frames - // that were still executing the old JIT at the time of another call frame's - // OSR exit. We want to ensure that the following is true: + // Now that things on the stack are recovered, do the arguments recovery. We assume that arguments + // recoveries don't recursively refer to each other. But, we don't try to assume that they only + // refer to certain ranges of locals. Hence why we need to do this here, once the stack is sensible. + // Note that we also roughly assume that the arguments might still be materialized outside of its + // inline call frame scope - but for now the DFG wouldn't do that. + + emitRestoreArguments(operands); + + // Adjust the old JIT's execute counter. Since we are exiting OSR, we know + // that all new calls into this code will go to the new JIT, so the execute + // counter only affects call frames that performed OSR exit and call frames + // that were still executing the old JIT at the time of another call frame's + // OSR exit. We want to ensure that the following is true: // - // (a) Code the performs an OSR exit gets a chance to reenter optimized - // code eventually, since optimized code is faster. But we don't - // want to do such reentery too aggressively (see (c) below). + // (a) Code the performs an OSR exit gets a chance to reenter optimized + // code eventually, since optimized code is faster. But we don't + // want to do such reentery too aggressively (see (c) below). // - // (b) If there is code on the call stack that is still running the old - // JIT's code and has never OSR'd, then it should get a chance to - // perform OSR entry despite the fact that we've exited. + // (b) If there is code on the call stack that is still running the old + // JIT's code and has never OSR'd, then it should get a chance to + // perform OSR entry despite the fact that we've exited. // - // (c) Code the performs an OSR exit should not immediately retry OSR - // entry, since both forms of OSR are expensive. OSR entry is - // particularly expensive. + // (c) Code the performs an OSR exit should not immediately retry OSR + // entry, since both forms of OSR are expensive. OSR entry is + // particularly expensive. // - // (d) Frequent OSR failures, even those that do not result in the code - // running in a hot loop, result in recompilation getting triggered. + // (d) Frequent OSR failures, even those that do not result in the code + // running in a hot loop, result in recompilation getting triggered. // - // To ensure (c), we'd like to set the execute counter to - // counterValueForOptimizeAfterWarmUp(). This seems like it would endanger - // (a) and (b), since then every OSR exit would delay the opportunity for - // every call frame to perform OSR entry. Essentially, if OSR exit happens - // frequently and the function has few loops, then the counter will never - // become non-negative and OSR entry will never be triggered. OSR entry - // will only happen if a loop gets hot in the old JIT, which does a pretty - // good job of ensuring (a) and (b). But that doesn't take care of (d), - // since each speculation failure would reset the execute counter. - // So we check here if the number of speculation failures is significantly - // larger than the number of successes (we want 90% success rate), and if - // there have been a large enough number of failures. If so, we set the - // counter to 0; otherwise we set the counter to - // counterValueForOptimizeAfterWarmUp(). + // To ensure (c), we'd like to set the execute counter to + // counterValueForOptimizeAfterWarmUp(). This seems like it would endanger + // (a) and (b), since then every OSR exit would delay the opportunity for + // every call frame to perform OSR entry. Essentially, if OSR exit happens + // frequently and the function has few loops, then the counter will never + // become non-negative and OSR entry will never be triggered. OSR entry + // will only happen if a loop gets hot in the old JIT, which does a pretty + // good job of ensuring (a) and (b). But that doesn't take care of (d), + // since each speculation failure would reset the execute counter. + // So we check here if the number of speculation failures is significantly + // larger than the number of successes (we want 90% success rate), and if + // there have been a large enough number of failures. If so, we set the + // counter to 0; otherwise we set the counter to + // counterValueForOptimizeAfterWarmUp(). handleExitCounts(m_jit, exit); - // 9) Reify inlined call frames. + // Reify inlined call frames. reifyInlinedCallFrames(m_jit, exit); - // 10) Create arguments if necessary and place them into the appropriate aliased - // registers. - - if (haveArguments) { - ArgumentsRecoveryGenerator argumentsRecovery; - - for (size_t index = 0; index < operands.size(); ++index) { - const ValueRecovery& recovery = operands[index]; - if (recovery.technique() != ArgumentsThatWereNotCreated) - continue; - argumentsRecovery.generateFor( - operands.operandForIndex(index), exit.m_codeOrigin, m_jit); - } - } - - // 12) And finish. + // And finish. adjustAndJumpToTarget(m_jit, exit); } diff --git a/dfg/DFGOSRExitCompilerCommon.cpp b/dfg/DFGOSRExitCompilerCommon.cpp index 5b78cb2..39b5bb5 100644 --- a/dfg/DFGOSRExitCompilerCommon.cpp +++ b/dfg/DFGOSRExitCompilerCommon.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,6 @@ #if ENABLE(DFG_JIT) -#include "Arguments.h" #include "DFGJITCode.h" #include "DFGOperations.h" #include "JIT.h" @@ -54,20 +53,55 @@ void handleExitCounts(CCallHelpers& jit, const OSRExitBase& exit) AssemblyHelpers::GreaterThanOrEqual, AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter()), AssemblyHelpers::TrustedImm32(0)); + + // We want to figure out if there's a possibility that we're in a loop. For the outermost + // code block in the inline stack, we handle this appropriately by having the loop OSR trigger + // check the exit count of the replacement of the CodeBlock from which we are OSRing. The + // problem is the inlined functions, which might also have loops, but whose baseline versions + // don't know where to look for the exit count. Figure out if those loops are severe enough + // that we had tried to OSR enter. If so, then we should use the loop reoptimization trigger. + // Otherwise, we should use the normal reoptimization trigger. + + AssemblyHelpers::JumpList loopThreshold; + + for (InlineCallFrame* inlineCallFrame = exit.m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) { + loopThreshold.append( + jit.branchTest8( + AssemblyHelpers::NonZero, + AssemblyHelpers::AbsoluteAddress( + inlineCallFrame->executable->addressOfDidTryToEnterInLoop()))); + } + + jit.move( + AssemblyHelpers::TrustedImm32(jit.codeBlock()->exitCountThresholdForReoptimization()), + GPRInfo::regT1); + + if (!loopThreshold.empty()) { + AssemblyHelpers::Jump done = jit.jump(); + + loopThreshold.link(&jit); + jit.move( + AssemblyHelpers::TrustedImm32( + jit.codeBlock()->exitCountThresholdForReoptimizationFromLoop()), + GPRInfo::regT1); - tooFewFails = jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, AssemblyHelpers::TrustedImm32(jit.codeBlock()->exitCountThresholdForReoptimization())); + done.link(&jit); + } + + tooFewFails = jit.branch32(AssemblyHelpers::BelowOrEqual, GPRInfo::regT2, GPRInfo::regT1); reoptimizeNow.link(&jit); // Reoptimize as soon as possible. #if !NUMBER_OF_ARGUMENT_REGISTERS jit.poke(GPRInfo::regT0); + jit.poke(AssemblyHelpers::TrustedImmPtr(&exit), 1); #else jit.move(GPRInfo::regT0, GPRInfo::argumentGPR0); - ASSERT(GPRInfo::argumentGPR0 != GPRInfo::regT1); + jit.move(AssemblyHelpers::TrustedImmPtr(&exit), GPRInfo::argumentGPR1); #endif - jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(triggerReoptimizationNow)), GPRInfo::regT1); - jit.call(GPRInfo::regT1); + jit.move(AssemblyHelpers::TrustedImmPtr(bitwise_cast<void*>(triggerReoptimizationNow)), GPRInfo::nonArgGPR0); + jit.call(GPRInfo::nonArgGPR0); AssemblyHelpers::Jump doneAdjusting = jit.jump(); tooFewFails.link(&jit); @@ -88,7 +122,9 @@ void handleExitCounts(CCallHelpers& jit, const OSRExitBase& exit) break; default: RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) clippedValue = 0; // Make some compilers, and mhahnenberg, happy. +#endif break; } jit.store32(AssemblyHelpers::TrustedImm32(-clippedValue), AssemblyHelpers::Address(GPRInfo::regT0, CodeBlock::offsetOfJITExecuteCounter())); @@ -108,12 +144,46 @@ void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit) InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin); CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame->caller); + void* jumpTarget = nullptr; + void* trueReturnPC = nullptr; + unsigned callBytecodeIndex = inlineCallFrame->caller.bytecodeIndex; - CallLinkInfo* callLinkInfo = - baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex); - RELEASE_ASSERT(callLinkInfo); - void* jumpTarget = callLinkInfo->callReturnLocation.executableAddress(); + switch (inlineCallFrame->kind) { + case InlineCallFrame::Call: + case InlineCallFrame::Construct: + case InlineCallFrame::CallVarargs: + case InlineCallFrame::ConstructVarargs: { + CallLinkInfo* callLinkInfo = + baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex); + RELEASE_ASSERT(callLinkInfo); + + jumpTarget = callLinkInfo->callReturnLocation().executableAddress(); + break; + } + + case InlineCallFrame::GetterCall: + case InlineCallFrame::SetterCall: { + StructureStubInfo* stubInfo = + baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex)); + RELEASE_ASSERT(stubInfo); + + switch (inlineCallFrame->kind) { + case InlineCallFrame::GetterCall: + jumpTarget = jit.vm()->getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress(); + break; + case InlineCallFrame::SetterCall: + jumpTarget = jit.vm()->getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress(); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + + trueReturnPC = stubInfo->callReturnLocation.labelAtOffset( + stubInfo->patch.deltaCallToDone).executableAddress(); + break; + } } GPRReg callerFrameGPR; if (inlineCallFrame->caller.inlineCallFrame) { @@ -122,47 +192,28 @@ void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit) } else callerFrameGPR = GPRInfo::callFrameRegister; -#if USE(JSVALUE64) + jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); + if (trueReturnPC) + jit.storePtr(AssemblyHelpers::TrustedImmPtr(trueReturnPC), AssemblyHelpers::addressFor(inlineCallFrame->stackOffset + virtualRegisterForArgument(inlineCallFrame->arguments.size()).offset())); + jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CodeBlock))); - if (!inlineCallFrame->isClosureCall) - jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->calleeConstant()->scope()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain))); + if (!inlineCallFrame->isVarargs()) + jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); +#if USE(JSVALUE64) jit.store64(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset())); - jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin.bytecodeIndex); jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); - jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); if (!inlineCallFrame->isClosureCall) jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->calleeConstant()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee))); - - // Leave the captured arguments in regT3. - if (baselineCodeBlock->usesArguments()) - jit.loadPtr(AssemblyHelpers::addressFor(VirtualRegister(inlineCallFrame->stackOffset + unmodifiedArgumentsRegister(baselineCodeBlock->argumentsRegister()).offset())), GPRInfo::regT3); #else // USE(JSVALUE64) // so this is the 32-bit part - jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CodeBlock))); - jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain))); - if (!inlineCallFrame->isClosureCall) - jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->calleeConstant()->scope()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain))); jit.storePtr(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset())); - jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); Instruction* instruction = baselineCodeBlock->instructions().begin() + codeOrigin.bytecodeIndex; uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); - jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee))); if (!inlineCallFrame->isClosureCall) jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->calleeConstant()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee))); - - // Leave the captured arguments in regT3. - if (baselineCodeBlock->usesArguments()) - jit.loadPtr(AssemblyHelpers::payloadFor(VirtualRegister(inlineCallFrame->stackOffset + unmodifiedArgumentsRegister(baselineCodeBlock->argumentsRegister()).offset())), GPRInfo::regT3); #endif // USE(JSVALUE64) // ending the #else part, so directly above is the 32-bit part - - if (baselineCodeBlock->usesArguments()) { - AssemblyHelpers::Jump noArguments = jit.branchTestPtr(AssemblyHelpers::Zero, GPRInfo::regT3); - jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT0); - jit.storePtr(GPRInfo::regT0, AssemblyHelpers::Address(GPRInfo::regT3, Arguments::offsetOfRegisters())); - noArguments.link(&jit); - } } #if USE(JSVALUE64) @@ -177,7 +228,7 @@ void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit) #if ENABLE(GGC) static void osrWriteBarrier(CCallHelpers& jit, GPRReg owner, GPRReg scratch) { - AssemblyHelpers::Jump ownerNotMarkedOrAlreadyRemembered = jit.checkMarkByte(owner); + AssemblyHelpers::Jump ownerIsRememberedOrInEden = jit.jumpIfIsRememberedOrInEden(owner); // We need these extra slots because setupArgumentsWithExecState will use poke on x86. #if CPU(X86) @@ -192,14 +243,13 @@ static void osrWriteBarrier(CCallHelpers& jit, GPRReg owner, GPRReg scratch) jit.addPtr(MacroAssembler::TrustedImm32(sizeof(void*) * 3), MacroAssembler::stackPointerRegister); #endif - ownerNotMarkedOrAlreadyRemembered.link(&jit); + ownerIsRememberedOrInEden.link(&jit); } #endif // ENABLE(GGC) void adjustAndJumpToTarget(CCallHelpers& jit, const OSRExitBase& exit) { #if ENABLE(GGC) - // 11) Write barrier the owner executables because we're jumping into a different block. jit.move(AssemblyHelpers::TrustedImmPtr(jit.codeBlock()->ownerExecutable()), GPRInfo::nonArgGPR0); osrWriteBarrier(jit, GPRInfo::nonArgGPR0, GPRInfo::nonArgGPR1); InlineCallFrameSet* inlineCallFrames = jit.codeBlock()->jitCode()->dfgCommon()->inlineCallFrames.get(); @@ -233,89 +283,6 @@ void adjustAndJumpToTarget(CCallHelpers& jit, const OSRExitBase& exit) jit.jump(GPRInfo::regT2); } -ArgumentsRecoveryGenerator::ArgumentsRecoveryGenerator() { } -ArgumentsRecoveryGenerator::~ArgumentsRecoveryGenerator() { } - -void ArgumentsRecoveryGenerator::generateFor( - int operand, CodeOrigin codeOrigin, CCallHelpers& jit) -{ - // Find the right inline call frame. - InlineCallFrame* inlineCallFrame = 0; - for (InlineCallFrame* current = codeOrigin.inlineCallFrame; - current; - current = current->caller.inlineCallFrame) { - if (current->stackOffset >= operand) { - inlineCallFrame = current; - break; - } - } - - if (!jit.baselineCodeBlockFor(inlineCallFrame)->usesArguments()) - return; - VirtualRegister argumentsRegister = jit.baselineArgumentsRegisterFor(inlineCallFrame); - if (m_didCreateArgumentsObject.add(inlineCallFrame).isNewEntry) { - // We know this call frame optimized out an arguments object that - // the baseline JIT would have created. Do that creation now. -#if USE(JSVALUE64) - if (inlineCallFrame) { - jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT0); - jit.setupArguments(GPRInfo::regT0); - } else - jit.setupArgumentsExecState(); - jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateArgumentsDuringOSRExit)), - GPRInfo::nonArgGPR0); - jit.call(GPRInfo::nonArgGPR0); - jit.store64(GPRInfo::returnValueGPR, AssemblyHelpers::addressFor(argumentsRegister)); - jit.store64( - GPRInfo::returnValueGPR, - AssemblyHelpers::addressFor(unmodifiedArgumentsRegister(argumentsRegister))); - jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. -#else // USE(JSVALUE64) -> so the 32_64 part - if (inlineCallFrame) { - jit.setupArgumentsWithExecState( - AssemblyHelpers::TrustedImmPtr(inlineCallFrame)); - jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateInlinedArgumentsDuringOSRExit)), - GPRInfo::nonArgGPR0); - } else { - jit.setupArgumentsExecState(); - jit.move( - AssemblyHelpers::TrustedImmPtr( - bitwise_cast<void*>(operationCreateArgumentsDuringOSRExit)), - GPRInfo::nonArgGPR0); - } - jit.call(GPRInfo::nonArgGPR0); - jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(argumentsRegister)); - jit.store32( - GPRInfo::returnValueGPR, - AssemblyHelpers::payloadFor(argumentsRegister)); - jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(unmodifiedArgumentsRegister(argumentsRegister))); - jit.store32( - GPRInfo::returnValueGPR, - AssemblyHelpers::payloadFor(unmodifiedArgumentsRegister(argumentsRegister))); - jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // no-op move on almost all platforms. -#endif // USE(JSVALUE64) - } - -#if USE(JSVALUE64) - jit.load64(AssemblyHelpers::addressFor(argumentsRegister), GPRInfo::regT0); - jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(operand)); -#else // USE(JSVALUE64) -> so the 32_64 part - jit.load32(AssemblyHelpers::payloadFor(argumentsRegister), GPRInfo::regT0); - jit.store32( - AssemblyHelpers::TrustedImm32(JSValue::CellTag), - AssemblyHelpers::tagFor(operand)); - jit.store32(GPRInfo::regT0, AssemblyHelpers::payloadFor(operand)); -#endif // USE(JSVALUE64) -} - } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGOSRExitCompilerCommon.h b/dfg/DFGOSRExitCompilerCommon.h index 93ecf47..ce1836f 100644 --- a/dfg/DFGOSRExitCompilerCommon.h +++ b/dfg/DFGOSRExitCompilerCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,18 +37,6 @@ void handleExitCounts(CCallHelpers&, const OSRExitBase&); void reifyInlinedCallFrames(CCallHelpers&, const OSRExitBase&); void adjustAndJumpToTarget(CCallHelpers&, const OSRExitBase&); -class ArgumentsRecoveryGenerator { -public: - ArgumentsRecoveryGenerator(); - ~ArgumentsRecoveryGenerator(); - - void generateFor(int operand, CodeOrigin, CCallHelpers&); - -private: - HashSet<InlineCallFrame*, DefaultHash<InlineCallFrame*>::Hash, - NullableHashTraits<InlineCallFrame*>> m_didCreateArgumentsObject; -}; - } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGOSRExitFuzz.cpp b/dfg/DFGOSRExitFuzz.cpp new file mode 100644 index 0000000..570a6a0 --- /dev/null +++ b/dfg/DFGOSRExitFuzz.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 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 "DFGOSRExitFuzz.h" + +#include "TestRunnerUtils.h" + +namespace JSC { namespace DFG { + +unsigned g_numberOfStaticOSRExitFuzzChecks; +unsigned g_numberOfOSRExitFuzzChecks; + +} // namespace DFG + +unsigned numberOfStaticOSRExitFuzzChecks() +{ + return DFG::g_numberOfStaticOSRExitFuzzChecks; +} + +unsigned numberOfOSRExitFuzzChecks() +{ + return DFG::g_numberOfOSRExitFuzzChecks; +} + +} // namespace JSC + + diff --git a/dfg/DFGOSRExitFuzz.h b/dfg/DFGOSRExitFuzz.h new file mode 100644 index 0000000..2feee59 --- /dev/null +++ b/dfg/DFGOSRExitFuzz.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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 DFGOSRExitFuzz_h +#define DFGOSRExitFuzz_h + +#include "Options.h" + +namespace JSC { namespace DFG { + +extern unsigned g_numberOfStaticOSRExitFuzzChecks; + +inline bool doOSRExitFuzzing() +{ + if (!Options::enableOSRExitFuzz()) + return false; + + g_numberOfStaticOSRExitFuzzChecks++; + if (unsigned atStatic = Options::fireOSRExitFuzzAtStatic()) + return atStatic == g_numberOfStaticOSRExitFuzzChecks; + + return true; +} + +// DFG- and FTL-generated code will query this on every speculation. +extern unsigned g_numberOfOSRExitFuzzChecks; + +} } // namespace JSC::DFG + +#endif // DFGOSRExitFuzz_h + diff --git a/dfg/DFGOSRExitPreparation.cpp b/dfg/DFGOSRExitPreparation.cpp index 43dd9f3..51d6e5a 100644 --- a/dfg/DFGOSRExitPreparation.cpp +++ b/dfg/DFGOSRExitPreparation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,7 +45,7 @@ void prepareCodeOriginForOSRExit(ExecState* exec, CodeOrigin codeOrigin) FunctionExecutable* executable = static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get()); CodeBlock* codeBlock = executable->baselineCodeBlockFor( - codeOrigin.inlineCallFrame->isCall ? CodeForCall : CodeForConstruct); + codeOrigin.inlineCallFrame->specializationKind()); if (codeBlock->jitType() == JSC::JITCode::BaselineJIT) continue; diff --git a/dfg/DFGObjectAllocationSinkingPhase.cpp b/dfg/DFGObjectAllocationSinkingPhase.cpp new file mode 100644 index 0000000..422382f --- /dev/null +++ b/dfg/DFGObjectAllocationSinkingPhase.cpp @@ -0,0 +1,1165 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGObjectAllocationSinkingPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGAbstractHeap.h" +#include "DFGBlockMapInlines.h" +#include "DFGClobberize.h" +#include "DFGCombinedLiveness.h" +#include "DFGGraph.h" +#include "DFGInsertOSRHintsForUpdate.h" +#include "DFGInsertionSet.h" +#include "DFGLivenessAnalysisPhase.h" +#include "DFGOSRAvailabilityAnalysisPhase.h" +#include "DFGPhase.h" +#include "DFGPromoteHeapAccess.h" +#include "DFGSSACalculator.h" +#include "DFGValidate.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +static bool verbose = false; + +class ObjectAllocationSinkingPhase : public Phase { +public: + ObjectAllocationSinkingPhase(Graph& graph) + : Phase(graph, "object allocation sinking") + , m_ssaCalculator(graph) + , m_insertionSet(graph) + { + } + + bool run() + { + ASSERT(m_graph.m_fixpointState == FixpointNotConverged); + + m_graph.m_dominators.computeIfNecessary(m_graph); + + // Logically we wish to consider every NewObject and sink it. However it's probably not + // profitable to sink a NewObject that will always escape. So, first we do a very simple + // forward flow analysis that determines the set of NewObject nodes that have any chance + // of benefiting from object allocation sinking. Then we fixpoint the following rules: + // + // - For each NewObject, we turn the original NewObject into a PhantomNewObject and then + // we insert MaterializeNewObject just before those escaping sites that come before any + // other escaping sites - that is, there is no path between the allocation and those sites + // that would see any other escape. Note that Upsilons constitute escaping sites. Then we + // insert additional MaterializeNewObject nodes on Upsilons that feed into Phis that mix + // materializations and the original PhantomNewObject. We then turn each PutByOffset over a + // PhantomNewObject into a PutHint. + // + // - We perform the same optimization for MaterializeNewObject. This allows us to cover + // cases where we had MaterializeNewObject flowing into a PutHint. + // + // We could also add this rule: + // + // - If all of the Upsilons of a Phi have a MaterializeNewObject that isn't used by anyone + // else, then replace the Phi with the MaterializeNewObject. + // + // FIXME: Implement this. Note that this totally doable but it requires some gnarly + // code, and to be effective the pruner needs to be aware of it. Currently any Upsilon + // is considered to be an escape even by the pruner, so it's unlikely that we'll see + // many cases of Phi over Materializations. + // https://bugs.webkit.org/show_bug.cgi?id=136927 + + if (!performSinking()) + return false; + + while (performSinking()) { } + + if (verbose) { + dataLog("Graph after sinking:\n"); + m_graph.dump(); + } + + return true; + } + +private: + bool performSinking() + { + m_graph.computeRefCounts(); + performLivenessAnalysis(m_graph); + performOSRAvailabilityAnalysis(m_graph); + m_combinedLiveness = CombinedLiveness(m_graph); + + CString graphBeforeSinking; + if (Options::verboseValidationFailure() && Options::validateGraphAtEachPhase()) { + StringPrintStream out; + m_graph.dump(out); + graphBeforeSinking = out.toCString(); + } + + if (verbose) { + dataLog("Graph before sinking:\n"); + m_graph.dump(); + } + + determineMaterializationPoints(); + if (m_sinkCandidates.isEmpty()) + return false; + + // At this point we are committed to sinking the sinking candidates. + placeMaterializationPoints(); + lowerNonReadingOperationsOnPhantomAllocations(); + promoteSunkenFields(); + + if (Options::validateGraphAtEachPhase()) + validate(m_graph, DumpGraph, graphBeforeSinking); + + if (verbose) + dataLog("Sinking iteration changed the graph.\n"); + return true; + } + + void determineMaterializationPoints() + { + // The premise of this pass is that if there exists a point in the program where some + // path from a phantom allocation site to that point causes materialization, then *all* + // paths cause materialization. This should mean that there are never any redundant + // materializations. + + m_sinkCandidates.clear(); + m_materializationToEscapee.clear(); + m_materializationSiteToMaterializations.clear(); + + BlockMap<HashMap<Node*, bool>> materializedAtHead(m_graph); + BlockMap<HashMap<Node*, bool>> materializedAtTail(m_graph); + + bool changed; + do { + if (verbose) + dataLog("Doing iteration of materialization point placement.\n"); + changed = false; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + HashMap<Node*, bool> materialized = materializedAtHead[block]; + if (verbose) + dataLog(" Looking at block ", pointerDump(block), "\n"); + for (Node* node : *block) { + handleNode( + node, + [&] () { + materialized.add(node, false); + }, + [&] (Node* escapee) { + auto iter = materialized.find(escapee); + if (iter != materialized.end()) { + if (verbose) + dataLog(" ", escapee, " escapes at ", node, "\n"); + iter->value = true; + } + }); + } + + if (verbose) + dataLog(" Materialized at tail of ", pointerDump(block), ": ", mapDump(materialized), "\n"); + + if (materialized == materializedAtTail[block]) + continue; + + materializedAtTail[block] = materialized; + changed = true; + + // Only propagate things to our successors if they are alive in all successors. + // So, we prune materialized-at-tail to only include things that are live. + Vector<Node*> toRemove; + for (auto pair : materialized) { + if (!m_combinedLiveness.liveAtTail[block].contains(pair.key)) + toRemove.append(pair.key); + } + for (Node* key : toRemove) + materialized.remove(key); + + for (BasicBlock* successorBlock : block->successors()) { + for (auto pair : materialized) { + materializedAtHead[successorBlock].add( + pair.key, false).iterator->value |= pair.value; + } + } + } + } while (changed); + + // Determine the sink candidates. Broadly, a sink candidate is a node that handleNode() + // believes is sinkable, and one of the following is true: + // + // 1) There exists a basic block with only backward outgoing edges (or no outgoing edges) + // in which the node wasn't materialized. This is meant to catch effectively-infinite + // loops in which we don't need to have allocated the object. + // + // 2) There exists a basic block at the tail of which the node is not materialized and the + // node is dead. + // + // 3) The sum of execution counts of the materializations is less than the sum of + // execution counts of the original node. + // + // We currently implement only rule #2. + // FIXME: Implement the two other rules. + // https://bugs.webkit.org/show_bug.cgi?id=137073 (rule #1) + // https://bugs.webkit.org/show_bug.cgi?id=137074 (rule #3) + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (auto pair : materializedAtTail[block]) { + if (pair.value) + continue; // It was materialized. + + if (m_combinedLiveness.liveAtTail[block].contains(pair.key)) + continue; // It might still get materialized in all of the successors. + + // We know that it died in this block and it wasn't materialized. That means that + // if we sink this allocation, then *this* will be a path along which we never + // have to allocate. Profit! + m_sinkCandidates.add(pair.key); + } + } + + if (m_sinkCandidates.isEmpty()) + return; + + // A materialization edge exists at any point where a node escapes but hasn't been + // materialized yet. We do this in two parts. First we find all of the nodes that cause + // escaping to happen, where the escapee had not yet been materialized. This catches + // everything but loops. We then catch loops - as well as weirder control flow constructs - + // in a subsequent pass that looks at places in the CFG where an edge exists from a block + // that hasn't materialized to a block that has. We insert the materialization along such an + // edge, and we rely on the fact that critical edges were already broken so that we actually + // either insert the materialization at the head of the successor or the tail of the + // predecessor. + // + // FIXME: This can create duplicate allocations when we really only needed to perform one. + // For example: + // + // var o = new Object(); + // if (rare) { + // if (stuff) + // call(o); // o escapes here. + // return; + // } + // // o doesn't escape down here. + // + // In this example, we would place a materialization point at call(o) and then we would find + // ourselves having to insert another one at the implicit else case of that if statement + // ('cause we've broken critical edges). We would instead really like to just have one + // materialization point right at the top of the then case of "if (rare)". To do this, we can + // find the LCA of the various materializations in the dom tree. + // https://bugs.webkit.org/show_bug.cgi?id=137124 + + // First pass: find intra-block materialization points. + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + HashSet<Node*> materialized; + for (auto pair : materializedAtHead[block]) { + if (pair.value && m_sinkCandidates.contains(pair.key)) + materialized.add(pair.key); + } + + if (verbose) + dataLog("Placing materialization points in ", pointerDump(block), " with materialization set ", listDump(materialized), "\n"); + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + + handleNode( + node, + [&] () { }, + [&] (Node* escapee) { + if (verbose) + dataLog("Seeing ", escapee, " escape at ", node, "\n"); + + if (!m_sinkCandidates.contains(escapee)) { + if (verbose) + dataLog(" It's not a sink candidate.\n"); + return; + } + + if (!materialized.add(escapee).isNewEntry) { + if (verbose) + dataLog(" It's already materialized.\n"); + return; + } + + createMaterialize(escapee, node); + }); + } + } + + // Second pass: find CFG edge materialization points. + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (BasicBlock* successorBlock : block->successors()) { + for (auto pair : materializedAtHead[successorBlock]) { + Node* allocation = pair.key; + + // We only care if it is materialized in the successor. + if (!pair.value) + continue; + + // We only care about sinking candidates. + if (!m_sinkCandidates.contains(allocation)) + continue; + + // We only care if it isn't materialized in the predecessor. + if (materializedAtTail[block].get(allocation)) + continue; + + // We need to decide if we put the materialization at the head of the successor, + // or the tail of the predecessor. It needs to be placed so that the allocation + // is never materialized before, and always materialized after. + + // Is it never materialized in any of successor's predecessors? I like to think + // of "successors' predecessors" and "predecessor's successors" as the "shadow", + // because of what it looks like when you draw it. + bool neverMaterializedInShadow = true; + for (BasicBlock* shadowBlock : successorBlock->predecessors) { + if (materializedAtTail[shadowBlock].get(allocation)) { + neverMaterializedInShadow = false; + break; + } + } + + if (neverMaterializedInShadow) { + createMaterialize(allocation, successorBlock->firstOriginNode()); + continue; + } + + // Because we had broken critical edges, it must be the case that the + // predecessor's successors all materialize the object. This is because the + // previous case is guaranteed to catch the case where the successor only has + // one predecessor. When critical edges are broken, this is also the only case + // where the predecessor could have had multiple successors. Therefore we have + // already handled the case where the predecessor has multiple successors. + DFG_ASSERT(m_graph, block, block->numSuccessors() == 1); + + createMaterialize(allocation, block->terminal()); + } + } + } + } + + void placeMaterializationPoints() + { + m_ssaCalculator.reset(); + + // The "variables" are the object allocations that we are sinking. So, nodeToVariable maps + // sink candidates (aka escapees) to the SSACalculator's notion of Variable, and indexToNode + // maps in the opposite direction using the SSACalculator::Variable::index() as the key. + HashMap<Node*, SSACalculator::Variable*> nodeToVariable; + Vector<Node*> indexToNode; + + for (Node* node : m_sinkCandidates) { + SSACalculator::Variable* variable = m_ssaCalculator.newVariable(); + nodeToVariable.add(node, variable); + ASSERT(indexToNode.size() == variable->index()); + indexToNode.append(node); + } + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + if (SSACalculator::Variable* variable = nodeToVariable.get(node)) + m_ssaCalculator.newDef(variable, block, node); + + for (Node* materialize : m_materializationSiteToMaterializations.get(node)) { + m_ssaCalculator.newDef( + nodeToVariable.get(m_materializationToEscapee.get(materialize)), + block, materialize); + } + } + } + + m_ssaCalculator.computePhis( + [&] (SSACalculator::Variable* variable, BasicBlock* block) -> Node* { + Node* allocation = indexToNode[variable->index()]; + if (!m_combinedLiveness.liveAtHead[block].contains(allocation)) + return nullptr; + + Node* phiNode = m_graph.addNode(allocation->prediction(), Phi, NodeOrigin()); + phiNode->mergeFlags(NodeResultJS); + return phiNode; + }); + + // Place Phis in the right places. Replace all uses of any allocation with the appropriate + // materialization. Create the appropriate Upsilon nodes. + LocalOSRAvailabilityCalculator availabilityCalculator; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + HashMap<Node*, Node*> mapping; + + for (Node* candidate : m_combinedLiveness.liveAtHead[block]) { + SSACalculator::Variable* variable = nodeToVariable.get(candidate); + if (!variable) + continue; + + SSACalculator::Def* def = m_ssaCalculator.reachingDefAtHead(block, variable); + if (!def) + continue; + + mapping.set(indexToNode[variable->index()], def->value()); + } + + availabilityCalculator.beginBlock(block); + for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(block)) { + m_insertionSet.insert(0, phiDef->value()); + + Node* originalNode = indexToNode[phiDef->variable()->index()]; + insertOSRHintsForUpdate( + m_insertionSet, 0, NodeOrigin(), availabilityCalculator.m_availability, + originalNode, phiDef->value()); + + mapping.set(originalNode, phiDef->value()); + } + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + + for (Node* materialize : m_materializationSiteToMaterializations.get(node)) { + Node* escapee = m_materializationToEscapee.get(materialize); + m_insertionSet.insert(nodeIndex, materialize); + insertOSRHintsForUpdate( + m_insertionSet, nodeIndex, node->origin, + availabilityCalculator.m_availability, escapee, materialize); + mapping.set(escapee, materialize); + } + + availabilityCalculator.executeNode(node); + + m_graph.doToChildren( + node, + [&] (Edge& edge) { + if (Node* materialize = mapping.get(edge.node())) + edge.setNode(materialize); + }); + + // If you cause an escape, you shouldn't see the original escapee. + if (validationEnabled()) { + handleNode( + node, + [&] () { }, + [&] (Node* escapee) { + DFG_ASSERT(m_graph, node, !m_sinkCandidates.contains(escapee)); + }); + } + } + + NodeAndIndex terminal = block->findTerminal(); + size_t upsilonInsertionPoint = terminal.index; + Node* upsilonWhere = terminal.node; + NodeOrigin upsilonOrigin = upsilonWhere->origin; + for (BasicBlock* successorBlock : block->successors()) { + for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) { + Node* phiNode = phiDef->value(); + SSACalculator::Variable* variable = phiDef->variable(); + Node* allocation = indexToNode[variable->index()]; + + Node* incoming = mapping.get(allocation); + DFG_ASSERT(m_graph, incoming, incoming != allocation); + + m_insertionSet.insertNode( + upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin, + OpInfo(phiNode), incoming->defaultEdge()); + } + } + + m_insertionSet.execute(block); + } + + // At this point we have dummy materialization nodes along with edges to them. This means + // that the part of the control flow graph that prefers to see actual object allocations + // is completely fixed up, except for the materializations themselves. + } + + void lowerNonReadingOperationsOnPhantomAllocations() + { + // Lower everything but reading operations on phantom allocations. We absolutely have to + // lower all writes so as to reveal them to the SSA calculator. We cannot lower reads + // because the whole point is that those go away completely. + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + switch (node->op()) { + case PutByOffset: { + Node* target = node->child2().node(); + if (m_sinkCandidates.contains(target)) { + ASSERT(target->isPhantomObjectAllocation()); + node->convertToPutByOffsetHint(); + } + break; + } + + case PutClosureVar: { + Node* target = node->child1().node(); + if (m_sinkCandidates.contains(target)) { + ASSERT(target->isPhantomActivationAllocation()); + node->convertToPutClosureVarHint(); + } + break; + } + + case PutStructure: { + Node* target = node->child1().node(); + if (m_sinkCandidates.contains(target)) { + ASSERT(target->isPhantomObjectAllocation()); + Node* structure = m_insertionSet.insertConstant( + nodeIndex, node->origin, JSValue(node->transition()->next)); + node->convertToPutStructureHint(structure); + } + break; + } + + case NewObject: { + if (m_sinkCandidates.contains(node)) { + Node* structure = m_insertionSet.insertConstant( + nodeIndex + 1, node->origin, JSValue(node->structure())); + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(StructurePLoc, node).createHint( + m_graph, node->origin, structure)); + node->convertToPhantomNewObject(); + } + break; + } + + case MaterializeNewObject: { + if (m_sinkCandidates.contains(node)) { + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(StructurePLoc, node).createHint( + m_graph, node->origin, m_graph.varArgChild(node, 0).node())); + for (unsigned i = 0; i < node->objectMaterializationData().m_properties.size(); ++i) { + unsigned identifierNumber = + node->objectMaterializationData().m_properties[i].m_identifierNumber; + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation( + NamedPropertyPLoc, node, identifierNumber).createHint( + m_graph, node->origin, + m_graph.varArgChild(node, i + 1).node())); + } + node->convertToPhantomNewObject(); + } + break; + } + + case NewFunction: { + if (m_sinkCandidates.contains(node)) { + Node* executable = m_insertionSet.insertConstant( + nodeIndex + 1, node->origin, node->cellOperand()); + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(FunctionExecutablePLoc, node).createHint( + m_graph, node->origin, executable)); + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(FunctionActivationPLoc, node).createHint( + m_graph, node->origin, node->child1().node())); + node->convertToPhantomNewFunction(); + } + break; + } + + case CreateActivation: { + if (m_sinkCandidates.contains(node)) { + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(ActivationScopePLoc, node).createHint( + m_graph, node->origin, node->child1().node())); + Node* symbolTableNode = m_insertionSet.insertConstant( + nodeIndex + 1, node->origin, node->cellOperand()); + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(ActivationSymbolTablePLoc, node).createHint( + m_graph, node->origin, symbolTableNode)); + + { + SymbolTable* symbolTable = node->castOperand<SymbolTable*>(); + Node* undefined = m_insertionSet.insertConstant( + nodeIndex + 1, node->origin, jsUndefined()); + ConcurrentJITLocker locker(symbolTable->m_lock); + for (auto iter = symbolTable->begin(locker), end = symbolTable->end(locker); iter != end; ++iter) { + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation( + ClosureVarPLoc, node, iter->value.scopeOffset().offset()).createHint( + m_graph, node->origin, undefined)); + } + } + + node->convertToPhantomCreateActivation(); + } + break; + } + + case MaterializeCreateActivation: { + if (m_sinkCandidates.contains(node)) { + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(ActivationScopePLoc, node).createHint( + m_graph, node->origin, m_graph.varArgChild(node, 0).node())); + Node* symbolTableNode = m_insertionSet.insertConstant( + nodeIndex + 1, node->origin, node->cellOperand()); + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation(ActivationSymbolTablePLoc, node).createHint( + m_graph, node->origin, symbolTableNode)); + ObjectMaterializationData& data = node->objectMaterializationData(); + for (unsigned i = 0; i < data.m_properties.size(); ++i) { + unsigned identifierNumber = data.m_properties[i].m_identifierNumber; + m_insertionSet.insert( + nodeIndex + 1, + PromotedHeapLocation( + ClosureVarPLoc, node, identifierNumber).createHint( + m_graph, node->origin, + m_graph.varArgChild(node, i + 1).node())); + } + node->convertToPhantomCreateActivation(); + } + break; + } + + case StoreBarrier: { + DFG_CRASH(m_graph, node, "Unexpected store barrier during sinking."); + break; + } + + default: + break; + } + + m_graph.doToChildren( + node, + [&] (Edge& edge) { + if (m_sinkCandidates.contains(edge.node())) + edge.setUseKind(KnownCellUse); + }); + } + m_insertionSet.execute(block); + } + } + + void promoteSunkenFields() + { + // Collect the set of heap locations that we will be operating over. + HashSet<PromotedHeapLocation> locations; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + promoteHeapAccess( + node, + [&] (PromotedHeapLocation location, Edge) { + if (m_sinkCandidates.contains(location.base())) + locations.add(location); + }, + [&] (PromotedHeapLocation location) { + if (m_sinkCandidates.contains(location.base())) + locations.add(location); + }); + } + } + + // Figure out which locations belong to which allocations. + m_locationsForAllocation.clear(); + for (PromotedHeapLocation location : locations) { + auto result = m_locationsForAllocation.add(location.base(), Vector<PromotedHeapLocation>()); + ASSERT(!result.iterator->value.contains(location)); + result.iterator->value.append(location); + } + + // For each sunken thingy, make sure we create Bottom values for all of its fields. + // Note that this has the hilarious slight inefficiency of creating redundant hints for + // things that were previously materializations. This should only impact compile times and + // not code quality, and it's necessary for soundness without some data structure hackage. + // For example, a MaterializeNewObject that we choose to sink may have new fields added to + // it conditionally. That would necessitate Bottoms. + Node* bottom = nullptr; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + if (block == m_graph.block(0)) + bottom = m_insertionSet.insertConstant(0, NodeOrigin(), jsUndefined()); + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + for (PromotedHeapLocation location : m_locationsForAllocation.get(node)) { + m_insertionSet.insert( + nodeIndex + 1, location.createHint(m_graph, node->origin, bottom)); + } + } + m_insertionSet.execute(block); + } + + m_ssaCalculator.reset(); + + // Collect the set of "variables" that we will be sinking. + m_locationToVariable.clear(); + m_indexToLocation.clear(); + for (PromotedHeapLocation location : locations) { + SSACalculator::Variable* variable = m_ssaCalculator.newVariable(); + m_locationToVariable.add(location, variable); + ASSERT(m_indexToLocation.size() == variable->index()); + m_indexToLocation.append(location); + } + + // Create Defs from the existing hints. + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + promoteHeapAccess( + node, + [&] (PromotedHeapLocation location, Edge value) { + if (!m_sinkCandidates.contains(location.base())) + return; + SSACalculator::Variable* variable = m_locationToVariable.get(location); + m_ssaCalculator.newDef(variable, block, value.node()); + }, + [&] (PromotedHeapLocation) { }); + } + } + + // OMG run the SSA calculator to create Phis! + m_ssaCalculator.computePhis( + [&] (SSACalculator::Variable* variable, BasicBlock* block) -> Node* { + PromotedHeapLocation location = m_indexToLocation[variable->index()]; + if (!m_combinedLiveness.liveAtHead[block].contains(location.base())) + return nullptr; + + Node* phiNode = m_graph.addNode(SpecHeapTop, Phi, NodeOrigin()); + phiNode->mergeFlags(NodeResultJS); + return phiNode; + }); + + // Place Phis in the right places, replace all uses of any load with the appropriate + // value, and create the appropriate Upsilon nodes. + m_graph.clearReplacements(); + for (BasicBlock* block : m_graph.blocksInPreOrder()) { + // This mapping table is intended to be lazy. If something is omitted from the table, + // it means that there haven't been any local stores to that promoted heap location. + m_localMapping.clear(); + + // Insert the Phi functions that we had previously created. + for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(block)) { + PromotedHeapLocation location = m_indexToLocation[phiDef->variable()->index()]; + + m_insertionSet.insert( + 0, phiDef->value()); + m_insertionSet.insert( + 0, location.createHint(m_graph, NodeOrigin(), phiDef->value())); + m_localMapping.add(location, phiDef->value()); + } + + if (verbose) + dataLog("Local mapping at ", pointerDump(block), ": ", mapDump(m_localMapping), "\n"); + + // Process the block and replace all uses of loads with the promoted value. + for (Node* node : *block) { + m_graph.performSubstitution(node); + + if (Node* escapee = m_materializationToEscapee.get(node)) + populateMaterialize(block, node, escapee); + + promoteHeapAccess( + node, + [&] (PromotedHeapLocation location, Edge value) { + if (m_sinkCandidates.contains(location.base())) + m_localMapping.set(location, value.node()); + }, + [&] (PromotedHeapLocation location) { + if (m_sinkCandidates.contains(location.base())) { + switch (node->op()) { + case CheckStructure: + node->convertToCheckStructureImmediate(resolve(block, location)); + break; + + default: + node->replaceWith(resolve(block, location)); + break; + } + } + }); + } + + // Gotta drop some Upsilons. + NodeAndIndex terminal = block->findTerminal(); + size_t upsilonInsertionPoint = terminal.index; + NodeOrigin upsilonOrigin = terminal.node->origin; + for (BasicBlock* successorBlock : block->successors()) { + for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) { + Node* phiNode = phiDef->value(); + SSACalculator::Variable* variable = phiDef->variable(); + PromotedHeapLocation location = m_indexToLocation[variable->index()]; + Node* incoming = resolve(block, location); + + m_insertionSet.insertNode( + upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin, + OpInfo(phiNode), incoming->defaultEdge()); + } + } + + m_insertionSet.execute(block); + } + } + + Node* resolve(BasicBlock* block, PromotedHeapLocation location) + { + if (Node* result = m_localMapping.get(location)) + return result; + + // This implies that there is no local mapping. Find a non-local mapping. + SSACalculator::Def* def = m_ssaCalculator.nonLocalReachingDef( + block, m_locationToVariable.get(location)); + ASSERT(def); + ASSERT(def->value()); + m_localMapping.add(location, def->value()); + return def->value(); + } + + template<typename SinkCandidateFunctor, typename EscapeFunctor> + void handleNode( + Node* node, + const SinkCandidateFunctor& sinkCandidate, + const EscapeFunctor& escape) + { + switch (node->op()) { + case NewObject: + case MaterializeNewObject: + case MaterializeCreateActivation: + sinkCandidate(); + m_graph.doToChildren( + node, + [&] (Edge edge) { + escape(edge.node()); + }); + break; + + case NewFunction: + if (!node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid()) + sinkCandidate(); + escape(node->child1().node()); + break; + + case CreateActivation: + if (!node->castOperand<SymbolTable*>()->singletonScope()->isStillValid()) + sinkCandidate(); + escape(node->child1().node()); + break; + + case Check: + m_graph.doToChildren( + node, + [&] (Edge edge) { + if (edge.willNotHaveCheck()) + return; + + if (alreadyChecked(edge.useKind(), SpecObject)) + return; + + escape(edge.node()); + }); + break; + + case MovHint: + case PutHint: + break; + + case PutStructure: + case CheckStructure: + case GetByOffset: + case MultiGetByOffset: + case GetGetterSetterByOffset: { + Node* target = node->child1().node(); + if (!target->isObjectAllocation()) + escape(target); + break; + } + + case PutByOffset: { + Node* target = node->child2().node(); + if (!target->isObjectAllocation()) { + escape(target); + escape(node->child1().node()); + } + escape(node->child3().node()); + break; + } + + case GetClosureVar: { + Node* target = node->child1().node(); + if (!target->isActivationAllocation()) + escape(target); + break; + } + + case PutClosureVar: { + Node* target = node->child1().node(); + if (!target->isActivationAllocation()) + escape(target); + escape(node->child2().node()); + break; + } + + case GetScope: { + Node* target = node->child1().node(); + if (!target->isFunctionAllocation()) + escape(target); + break; + } + + case GetExecutable: { + Node* target = node->child1().node(); + if (!target->isFunctionAllocation()) + escape(target); + break; + } + + case SkipScope: { + Node* target = node->child1().node(); + if (!target->isActivationAllocation()) + escape(target); + break; + } + + case MultiPutByOffset: + // FIXME: In the future we should be able to handle this. It's just a matter of + // building the appropriate *Hint variant of this instruction, along with a + // PhantomStructureSelect node - since this transforms the Structure in a conditional + // way. + // https://bugs.webkit.org/show_bug.cgi?id=136924 + escape(node->child1().node()); + escape(node->child2().node()); + break; + + default: + m_graph.doToChildren( + node, + [&] (Edge edge) { + escape(edge.node()); + }); + break; + } + } + + Node* createMaterialize(Node* escapee, Node* where) + { + Node* result = nullptr; + + switch (escapee->op()) { + case NewObject: + case MaterializeNewObject: { + ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add(); + + result = m_graph.addNode( + escapee->prediction(), Node::VarArg, MaterializeNewObject, + NodeOrigin( + escapee->origin.semantic, + where->origin.forExit), + OpInfo(data), OpInfo(), 0, 0); + break; + } + + case NewFunction: + result = m_graph.addNode( + escapee->prediction(), NewFunction, + NodeOrigin( + escapee->origin.semantic, + where->origin.forExit), + OpInfo(escapee->cellOperand()), + escapee->child1()); + break; + + case CreateActivation: + case MaterializeCreateActivation: { + ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add(); + FrozenValue* symbolTable = escapee->cellOperand(); + result = m_graph.addNode( + escapee->prediction(), Node::VarArg, MaterializeCreateActivation, + NodeOrigin( + escapee->origin.semantic, + where->origin.forExit), + OpInfo(data), OpInfo(symbolTable), 0, 0); + break; + } + + default: + DFG_CRASH(m_graph, escapee, "Bad escapee op"); + break; + } + + if (verbose) + dataLog("Creating materialization point at ", where, " for ", escapee, ": ", result, "\n"); + + m_materializationToEscapee.add(result, escapee); + m_materializationSiteToMaterializations.add( + where, Vector<Node*>()).iterator->value.append(result); + + return result; + } + + void populateMaterialize(BasicBlock* block, Node* node, Node* escapee) + { + switch (node->op()) { + case MaterializeNewObject: { + ObjectMaterializationData& data = node->objectMaterializationData(); + unsigned firstChild = m_graph.m_varArgChildren.size(); + + Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee); + + PromotedHeapLocation structure(StructurePLoc, escapee); + ASSERT(locations.contains(structure)); + + m_graph.m_varArgChildren.append(Edge(resolve(block, structure), KnownCellUse)); + + for (unsigned i = 0; i < locations.size(); ++i) { + switch (locations[i].kind()) { + case StructurePLoc: { + ASSERT(locations[i] == structure); + break; + } + + case NamedPropertyPLoc: { + Node* value = resolve(block, locations[i]); + if (value->op() == BottomValue) { + // We can skip Bottoms entirely. + break; + } + + data.m_properties.append(PhantomPropertyValue(locations[i].info())); + m_graph.m_varArgChildren.append(value); + break; + } + + default: + DFG_CRASH(m_graph, node, "Bad location kind"); + } + } + + node->children = AdjacencyList( + AdjacencyList::Variable, + firstChild, m_graph.m_varArgChildren.size() - firstChild); + break; + } + + case MaterializeCreateActivation: { + ObjectMaterializationData& data = node->objectMaterializationData(); + + unsigned firstChild = m_graph.m_varArgChildren.size(); + + Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee); + + PromotedHeapLocation scope(ActivationScopePLoc, escapee); + PromotedHeapLocation symbolTable(ActivationSymbolTablePLoc, escapee); + ASSERT(locations.contains(scope)); + + m_graph.m_varArgChildren.append(Edge(resolve(block, scope), KnownCellUse)); + + for (unsigned i = 0; i < locations.size(); ++i) { + switch (locations[i].kind()) { + case ActivationScopePLoc: { + ASSERT(locations[i] == scope); + break; + } + + case ActivationSymbolTablePLoc: { + ASSERT(locations[i] == symbolTable); + break; + } + + case ClosureVarPLoc: { + Node* value = resolve(block, locations[i]); + if (value->op() == BottomValue) + break; + + data.m_properties.append(PhantomPropertyValue(locations[i].info())); + m_graph.m_varArgChildren.append(value); + break; + } + + default: + DFG_CRASH(m_graph, node, "Bad location kind"); + } + } + + node->children = AdjacencyList( + AdjacencyList::Variable, + firstChild, m_graph.m_varArgChildren.size() - firstChild); + break; + } + + case NewFunction: { + if (!ASSERT_DISABLED) { + Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee); + + ASSERT(locations.size() == 2); + + PromotedHeapLocation executable(FunctionExecutablePLoc, escapee); + ASSERT(locations.contains(executable)); + + PromotedHeapLocation activation(FunctionActivationPLoc, escapee); + ASSERT(locations.contains(activation)); + + for (unsigned i = 0; i < locations.size(); ++i) { + switch (locations[i].kind()) { + case FunctionExecutablePLoc: { + ASSERT(locations[i] == executable); + break; + } + + case FunctionActivationPLoc: { + ASSERT(locations[i] == activation); + break; + } + + default: + DFG_CRASH(m_graph, node, "Bad location kind"); + } + } + } + + break; + } + + default: + DFG_CRASH(m_graph, node, "Bad materialize op"); + break; + } + } + + CombinedLiveness m_combinedLiveness; + SSACalculator m_ssaCalculator; + HashSet<Node*> m_sinkCandidates; + HashMap<Node*, Node*> m_materializationToEscapee; + HashMap<Node*, Vector<Node*>> m_materializationSiteToMaterializations; + HashMap<Node*, Vector<PromotedHeapLocation>> m_locationsForAllocation; + HashMap<PromotedHeapLocation, SSACalculator::Variable*> m_locationToVariable; + Vector<PromotedHeapLocation> m_indexToLocation; + HashMap<PromotedHeapLocation, Node*> m_localMapping; + InsertionSet m_insertionSet; +}; + +bool performObjectAllocationSinking(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Object Allocation Sinking Phase"); + return runPhase<ObjectAllocationSinkingPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGObjectAllocationSinkingPhase.h b/dfg/DFGObjectAllocationSinkingPhase.h new file mode 100644 index 0000000..1630f66 --- /dev/null +++ b/dfg/DFGObjectAllocationSinkingPhase.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 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 DFGObjectAllocationSinkingPhase_h +#define DFGObjectAllocationSinkingPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Sinks object allocations down to their uses. This will sink the allocations over OSR exits, by +// replacing all stores to those objects with store hints so that OSR exit can materialize the +// object. This may sink allocations past returns, creating control flow paths along which the +// objects are not allocated at all. Replaces all uses of the objects' fields with SSA data flow. + +bool performObjectAllocationSinking(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGObjectAllocationSinkingPhase_h + diff --git a/dfg/DFGObjectMaterializationData.cpp b/dfg/DFGObjectMaterializationData.cpp new file mode 100644 index 0000000..3abdbe6 --- /dev/null +++ b/dfg/DFGObjectMaterializationData.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 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 "DFGObjectMaterializationData.h" + +#if ENABLE(DFG_JIT) + +#include <wtf/ListDump.h> + +namespace JSC { namespace DFG { + +void PhantomPropertyValue::dump(PrintStream& out) const +{ + out.print("id", m_identifierNumber); +} + +void ObjectMaterializationData::dump(PrintStream& out) const +{ + out.print("[", listDump(m_properties), "]"); +} + +float ObjectMaterializationData::oneWaySimilarityScore( + const ObjectMaterializationData& other) const +{ + unsigned numHits = 0; + for (PhantomPropertyValue value : m_properties) { + if (other.m_properties.contains(value)) + numHits++; + } + return static_cast<float>(numHits) / static_cast<float>(m_properties.size()); +} + +float ObjectMaterializationData::similarityScore(const ObjectMaterializationData& other) const +{ + return std::min(oneWaySimilarityScore(other), other.oneWaySimilarityScore(*this)); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGObjectMaterializationData.h b/dfg/DFGObjectMaterializationData.h new file mode 100644 index 0000000..1c4febe --- /dev/null +++ b/dfg/DFGObjectMaterializationData.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 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 DFGObjectMaterializationData_h +#define DFGObjectMaterializationData_h + +#if ENABLE(DFG_JIT) + +#include <limits.h> +#include <wtf/MathExtras.h> +#include <wtf/PrintStream.h> +#include <wtf/Vector.h> + +namespace JSC { namespace DFG { + +struct PhantomPropertyValue { + PhantomPropertyValue() + : m_identifierNumber(UINT_MAX) + { + } + + PhantomPropertyValue(unsigned identifierNumber) + : m_identifierNumber(identifierNumber) + { + } + + unsigned m_identifierNumber; + + bool operator==(const PhantomPropertyValue& other) const + { + return m_identifierNumber == other.m_identifierNumber; + } + + void dump(PrintStream&) const; +}; + +struct ObjectMaterializationData { + // Determines the meaning of the passed nodes. + Vector<PhantomPropertyValue> m_properties; + + void dump(PrintStream&) const; + + // The fraction of my properties that the other data has. + float oneWaySimilarityScore(const ObjectMaterializationData&) const; + + // The minimum of the two possible one-way scores. + float similarityScore(const ObjectMaterializationData&) const; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGObjectMaterializationData_h + diff --git a/dfg/DFGOperations.cpp b/dfg/DFGOperations.cpp index 15cb4f5..6f9512b 100644 --- a/dfg/DFGOperations.cpp +++ b/dfg/DFGOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,8 +26,8 @@ #include "config.h" #include "DFGOperations.h" -#include "Arguments.h" #include "ButterflyInlines.h" +#include "ClonedArguments.h" #include "CodeBlock.h" #include "CommonSlowPaths.h" #include "CopiedSpaceInlines.h" @@ -38,6 +38,7 @@ #include "DFGToFTLDeferredCompilationCallback.h" #include "DFGToFTLForOSREntryDeferredCompilationCallback.h" #include "DFGWorklist.h" +#include "DirectArguments.h" #include "FTLForOSREntryJITCode.h" #include "FTLOSREntry.h" #include "HostCallReturnValue.h" @@ -45,15 +46,17 @@ #include "Interpreter.h" #include "JIT.h" #include "JITExceptions.h" -#include "JSActivation.h" -#include "VM.h" +#include "JSCInlines.h" +#include "JSLexicalEnvironment.h" #include "JSNameScope.h" -#include "NameInstance.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" #include "Repatch.h" +#include "ScopedArguments.h" #include "StringConstructor.h" +#include "Symbol.h" +#include "TypeProfilerLog.h" #include "TypedArrayInlines.h" +#include "VM.h" #include <wtf/InlineASM.h> #if ENABLE(JIT) @@ -66,6 +69,7 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); + ASSERT(isIndex(index)); if (direct) { RELEASE_ASSERT(baseValue.isObject()); asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); @@ -96,6 +100,8 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { + // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. + ASSERT(isIndex(property.asUInt32())); putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); return; } @@ -103,32 +109,26 @@ ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exe if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); - if (propertyAsDouble == propertyAsUInt32) { + if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) { putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); return; } } - if (isName(property)) { - PutPropertySlot slot(baseValue, strict); - if (direct) { - RELEASE_ASSERT(baseValue.isObject()); - asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot); - } else - baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot); + // Don't put to an object if toString throws an exception. + auto propertyName = property.toPropertyKey(exec); + if (vm->exception()) return; - } - // Don't put to an object if toString throws an exception. - Identifier ident = property.toString(exec)->toIdentifier(exec); - if (!vm->exception()) { - PutPropertySlot slot(baseValue, strict); - if (direct) { - RELEASE_ASSERT(baseValue.isObject()); - asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot); - } else - baseValue.put(exec, ident, value, slot); - } + PutPropertySlot slot(baseValue, strict); + if (direct) { + RELEASE_ASSERT(baseValue.isObject()); + if (Optional<uint32_t> index = parseIndex(propertyName)) + asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); + else + asObject(baseValue)->putDirect(*vm, propertyName, value, slot); + } else + baseValue.put(exec, propertyName, value, slot); } template<typename ViewClass> @@ -137,7 +137,7 @@ char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size) VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); if (size < 0) { - vm.throwException(exec, createRangeError(exec, "Requested length is negative")); + vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); return 0; } return bitwise_cast<char*>(ViewClass::create(exec, structure, size)); @@ -156,7 +156,7 @@ char* newTypedArrayWithOneArgument( RefPtr<ArrayBuffer> buffer = jsBuffer->impl(); if (buffer->byteLength() % ViewClass::elementSize) { - vm.throwException(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size")); + vm.throwException(exec, createRangeError(exec, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size"))); return 0; } return bitwise_cast<char*>( @@ -183,18 +183,18 @@ char* newTypedArrayWithOneArgument( if (value.isInt32()) length = value.asInt32(); else if (!value.isNumber()) { - vm.throwException(exec, createTypeError(exec, "Invalid array length argument")); + vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument"))); return 0; } else { length = static_cast<int>(value.asNumber()); if (length != value.asNumber()) { - vm.throwException(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)")); + vm.throwException(exec, createTypeError(exec, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)"))); return 0; } } if (length < 0) { - vm.throwException(exec, createRangeError(exec, "Requested length is negative")); + vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); return 0; } @@ -229,7 +229,7 @@ JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor ASSERT(jsCast<JSFunction*>(constructor)->methodTable(vm)->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS); #endif - return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->allocationProfile(exec, inlineCapacity)->structure()); + return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->rareData(exec, inlineCapacity)->allocationProfile()->structure()); } EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) @@ -292,22 +292,26 @@ EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue e } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); - if (propertyAsUInt32 == propertyAsDouble) + if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32)) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { Structure& structure = *base->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { - if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec))) - return JSValue::encode(result); + if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) { + if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get())) + return JSValue::encode(result); + } } } } - if (isName(property)) - return JSValue::encode(baseValue.get(exec, jsCast<NameInstance*>(property.asCell())->privateName())); - - Identifier ident = property.toString(exec)->toIdentifier(exec); - return JSValue::encode(baseValue.get(exec, ident)); + baseValue.requireObjectCoercible(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + auto propertyName = property.toPropertyKey(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + return JSValue::encode(baseValue.get(exec, propertyName)); } EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) @@ -327,16 +331,17 @@ EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base } else if (property.isString()) { Structure& structure = *base->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { - if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec))) - return JSValue::encode(result); + if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) { + if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get())) + return JSValue::encode(result); + } } } - if (isName(property)) - return JSValue::encode(JSValue(base).get(exec, jsCast<NameInstance*>(property.asCell())->privateName())); - - Identifier ident = property.toString(exec)->toIdentifier(exec); - return JSValue::encode(JSValue(base).get(exec, ident)); + auto propertyName = property.toPropertyKey(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + return JSValue::encode(JSValue(base).get(exec, propertyName)); } ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index) @@ -757,87 +762,182 @@ char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument( return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue); } -JSCell* JIT_OPERATION operationCreateInlinedArguments( - ExecState* exec, InlineCallFrame* inlineCallFrame) +JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - // NB: This needs to be exceedingly careful with top call frame tracking, since it - // may be called from OSR exit, while the state of the call stack is bizarre. - Arguments* result = Arguments::create(vm, exec, inlineCallFrame); - ASSERT(!vm.exception()); + return JSLexicalEnvironment::create(vm, structure, scope, table); +} + +JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, int32_t length, int32_t minCapacity) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer target(&vm, exec); + DirectArguments* result = DirectArguments::create( + vm, structure, length, std::max(length, minCapacity)); + // The caller will store to this object without barriers. Most likely, at this point, this is + // still a young object and so no barriers are needed. But it's good to be careful anyway, + // since the GC should be allowed to do crazy (like pretenuring, for example). + vm.heap.writeBarrier(result); return result; } -JSCell* JIT_OPERATION operationCreateInlinedArgumentsDuringOSRExit(ExecState* exec, InlineCallFrame* inlineCallFrame) +JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment* scope) { - DeferGCForAWhile(exec->vm().heap); - return operationCreateInlinedArguments(exec, inlineCallFrame); + VM& vm = exec->vm(); + NativeCallFrameTracer target(&vm, exec); + + // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I + // didn't feel like changing the max number of arguments for a slow path call from 6 to 7. + ScopedArgumentsTable* table = scope->symbolTable()->arguments(); + + return ScopedArguments::createByCopyingFrom( + vm, structure, argumentStart, length, callee, table, scope); } -void JIT_OPERATION operationTearOffInlinedArguments( - ExecState* exec, JSCell* argumentsCell, JSCell* activationCell, InlineCallFrame* inlineCallFrame) +JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee) { - ASSERT_UNUSED(activationCell, !activationCell); // Currently, we don't inline functions with activations. - jsCast<Arguments*>(argumentsCell)->tearOff(exec, inlineCallFrame); + VM& vm = exec->vm(); + NativeCallFrameTracer target(&vm, exec); + return ClonedArguments::createByCopyingFrom( + exec, structure, argumentStart, length, callee); } -EncodedJSValue JIT_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index) +JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount) { VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); + NativeCallFrameTracer target(&vm, exec); + + DeferGCForAWhile deferGC(vm.heap); + + CodeBlock* codeBlock; + if (inlineCallFrame) + codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); + else + codeBlock = exec->codeBlock(); + + unsigned length = argumentCount - 1; + unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1)); + DirectArguments* result = DirectArguments::create( + vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity); + + result->callee().set(vm, result, callee); + + Register* arguments = + exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) + + CallFrame::argumentOffset(0); + for (unsigned i = length; i--;) + result->setIndexQuickly(vm, i, arguments[i].jsValue()); + + return result; +} - JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); +JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer target(&vm, exec); + + DeferGCForAWhile deferGC(vm.heap); - // If there are no arguments, and we're accessing out of bounds, then we have to create the - // arguments in case someone has installed a getter on a numeric property. - if (!argumentsValue) - exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->vm(), exec); + CodeBlock* codeBlock; + if (inlineCallFrame) + codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); + else + codeBlock = exec->codeBlock(); - return JSValue::encode(argumentsValue.get(exec, index)); + unsigned length = argumentCount - 1; + ClonedArguments* result = ClonedArguments::createEmpty( + vm, codeBlock->globalObject()->outOfBandArgumentsStructure(), callee); + + Register* arguments = + exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) + + CallFrame::argumentOffset(0); + for (unsigned i = length; i--;) + result->putDirectIndex(exec, i, arguments[i].jsValue()); + + result->putDirect(vm, vm.propertyNames->length, jsNumber(length)); + + return result; } -EncodedJSValue JIT_OPERATION operationGetInlinedArgumentByVal( - ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index) +size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + ASSERT(jsDynamicCast<JSObject*>(object)); - // If there are no arguments, and we're accessing out of bounds, then we have to create the - // arguments in case someone has installed a getter on a numeric property. - if (!argumentsValue) { - exec->uncheckedR(argumentsRegister) = argumentsValue = - Arguments::create(exec->vm(), exec, inlineCallFrame); + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return false; + if (object->type() == JSFunctionType) + return false; + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return false; } - return JSValue::encode(argumentsValue.get(exec, index)); + return true; } -JSCell* JIT_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable) +size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { - ASSERT(functionExecutable->inherits(FunctionExecutable::info())); VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - return JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), exec->scope()); -} -size_t JIT_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value) -{ - return jsIsObjectType(exec, JSValue::decode(value)); + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return false; + if (object->type() == JSFunctionType) + return true; + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return true; + } + + return false; } -size_t JIT_OPERATION operationIsFunction(EncodedJSValue value) +JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { - return jsIsFunctionType(JSValue::decode(value)); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return vm.smallStrings.undefinedString(); + if (object->type() == JSFunctionType) + return vm.smallStrings.functionString(); + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return vm.smallStrings.functionString(); + } + + return vm.smallStrings.objectString(); } -JSCell* JIT_OPERATION operationTypeOf(ExecState* exec, JSCell* value) +int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - return jsTypeStringForValue(exec, JSValue(value)).asCell(); + + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return static_cast<int32_t>(TypeofType::Undefined); + if (object->type() == JSFunctionType) + return static_cast<int32_t>(TypeofType::Function); + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return static_cast<int32_t>(TypeofType::Function); + } + + return static_cast<int32_t>(TypeofType::Object); } char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec) @@ -914,17 +1014,6 @@ char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data()); } -char* JIT_OPERATION operationRageEnsureContiguous(ExecState* exec, JSCell* cell) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - if (!cell->isObject()) - return 0; - - return reinterpret_cast<char*>(asObject(cell)->rageEnsureContiguous(vm).data()); -} - char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) { VM& vm = exec->vm(); @@ -976,6 +1065,22 @@ JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value) return JSValue::decode(value).toString(exec); } +JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return stringConstructor(exec, cell); +} + +JSCell* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return stringConstructor(exec, JSValue::decode(value)); +} + JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right) { VM& vm = exec->vm(); @@ -1024,13 +1129,48 @@ char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JS return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress()); } -void JIT_OPERATION operationNotifyWrite(ExecState* exec, VariableWatchpointSet* set, EncodedJSValue encodedValue) +int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - JSValue value = JSValue::decode(encodedValue); - set->notifyWrite(vm, value); + return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min()); +} + +void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + set->touch("Executed NotifyWrite"); +} + +void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + throwStackOverflowError(exec); +} + +int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstVarArgOffset) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + JSValue arguments = JSValue::decode(encodedArguments); + + return sizeOfVarargs(exec, arguments, firstVarArgOffset); +} + +void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + JSValue arguments = JSValue::decode(encodedArguments); + + loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length); + + for (int32_t i = length; i < mandatoryMinimum; ++i) + exec->r(firstElementDest + i) = jsUndefined(); } double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b) @@ -1058,6 +1198,11 @@ int64_t JIT_OPERATION operationConvertDoubleToInt52(double value) return tryConvertToInt52(value); } +void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec) +{ + exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside DFG.")); +} + size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) { VM* vm = &exec->vm(); @@ -1105,7 +1250,7 @@ void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* dataLog("\n"); } -extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock) +extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, OSRExitBase* exit) { // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't // really be profitable. @@ -1129,13 +1274,21 @@ extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock) ASSERT(codeBlock->hasOptimizedReplacement()); CodeBlock* optimizedCodeBlock = codeBlock->replacement(); ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType())); + + bool didTryToEnterIntoInlinedLoops = false; + for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) { + if (inlineCallFrame->executable->didTryToEnterInLoop()) { + didTryToEnterIntoInlinedLoops = true; + break; + } + } // In order to trigger reoptimization, one of two things must have happened: // 1) We exited more than some number of times. // 2) We exited and got stuck in a loop, and now we're exiting again. bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow(); bool didGetStuckInLoop = - codeBlock->checkIfOptimizationThresholdReached() + (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops) && optimizedCodeBlock->shouldReoptimizeFromLoopNow(); if (!didExitABunch && !didGetStuckInLoop) { @@ -1198,13 +1351,18 @@ static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock)); } -void JIT_OPERATION triggerTierUpNow(ExecState* exec) +static void triggerTierUpNowCommon(ExecState* exec, bool inLoop) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); DeferGC deferGC(vm->heap); CodeBlock* codeBlock = exec->codeBlock(); + if (codeBlock->jitType() != JITCode::DFGJIT) { + dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n"); + RELEASE_ASSERT_NOT_REACHED(); + } + JITCode* jitCode = codeBlock->jitCode()->dfg(); if (Options::verboseOSR()) { @@ -1212,10 +1370,22 @@ void JIT_OPERATION triggerTierUpNow(ExecState* exec) *codeBlock, ": Entered triggerTierUpNow with executeCounter = ", jitCode->tierUpCounter, "\n"); } - + if (inLoop) + jitCode->nestedTriggerIsSet = 1; + triggerFTLReplacementCompile(vm, codeBlock, jitCode); } +void JIT_OPERATION triggerTierUpNow(ExecState* exec) +{ + triggerTierUpNowCommon(exec, false); +} + +void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec) +{ + triggerTierUpNowCommon(exec, true); +} + char* JIT_OPERATION triggerOSREntryNow( ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex) { @@ -1224,11 +1394,17 @@ char* JIT_OPERATION triggerOSREntryNow( DeferGC deferGC(vm->heap); CodeBlock* codeBlock = exec->codeBlock(); + if (codeBlock->jitType() != JITCode::DFGJIT) { + dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n"); + RELEASE_ASSERT_NOT_REACHED(); + } + JITCode* jitCode = codeBlock->jitCode()->dfg(); + jitCode->nestedTriggerIsSet = 0; if (Options::verboseOSR()) { dataLog( - *codeBlock, ": Entered triggerTierUpNow with executeCounter = ", + *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ", jitCode->tierUpCounter, "\n"); } @@ -1271,7 +1447,7 @@ char* JIT_OPERATION triggerOSREntryNow( // OSR entry failed. Oh no! This implies that we need to retry. We retry // without exponential backoff and we only do this for the entry code block. - jitCode->osrEntryBlock.clear(); + jitCode->osrEntryBlock = nullptr; jitCode->osrEntryRetry = 0; return 0; } diff --git a/dfg/DFGOperations.h b/dfg/DFGOperations.h index 720b60a..c102b87 100644 --- a/dfg/DFGOperations.h +++ b/dfg/DFGOperations.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 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,9 +31,9 @@ #include "JITOperations.h" #include "PutKind.h" -namespace JSC { +namespace JSC { namespace DFG { -namespace DFG { +struct OSRExitBase; extern "C" { @@ -96,16 +96,17 @@ EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSCell*, JSCell*) W size_t JIT_OPERATION operationRegExpTest(ExecState*, JSCell*, JSCell*) WTF_INTERNAL; size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; size_t JIT_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; -JSCell* JIT_OPERATION operationCreateInlinedArguments(ExecState*, InlineCallFrame*) WTF_INTERNAL; -JSCell* JIT_OPERATION operationCreateInlinedArgumentsDuringOSRExit(ExecState*, InlineCallFrame*) WTF_INTERNAL; -void JIT_OPERATION operationTearOffInlinedArguments(ExecState*, JSCell*, JSCell*, InlineCallFrame*) WTF_INTERNAL; -EncodedJSValue JIT_OPERATION operationGetInlinedArgumentByVal(ExecState*, int32_t, InlineCallFrame*, int32_t) WTF_INTERNAL; -EncodedJSValue JIT_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t) WTF_INTERNAL; -JSCell* JIT_OPERATION operationNewFunctionNoCheck(ExecState*, JSCell*) WTF_INTERNAL; +JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*); +JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState*, Structure*, int32_t length, int32_t minCapacity); +JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, int32_t argumentCount); +JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState*, Structure*, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment*); +JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, int32_t argumentCount); +JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState*, Structure*, Register* argumentStart, int32_t length, JSFunction* callee); double JIT_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL; -size_t JIT_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL; -size_t JIT_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL; -JSCell* JIT_OPERATION operationTypeOf(ExecState*, JSCell*) WTF_INTERNAL; +size_t JIT_OPERATION operationObjectIsObject(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL; +size_t JIT_OPERATION operationObjectIsFunction(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL; +JSCell* JIT_OPERATION operationTypeOfObject(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL; +int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL; char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL; char* JIT_OPERATION operationAllocatePropertyStorage(ExecState*, size_t newSize) WTF_INTERNAL; char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState*, JSObject*) WTF_INTERNAL; @@ -113,7 +114,6 @@ char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* char* JIT_OPERATION operationEnsureInt32(ExecState*, JSCell*); char* JIT_OPERATION operationEnsureDouble(ExecState*, JSCell*); char* JIT_OPERATION operationEnsureContiguous(ExecState*, JSCell*); -char* JIT_OPERATION operationRageEnsureContiguous(ExecState*, JSCell*); char* JIT_OPERATION operationEnsureArrayStorage(ExecState*, JSCell*); StringImpl* JIT_OPERATION operationResolveRope(ExecState*, JSString*); JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t); @@ -121,25 +121,34 @@ JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t); JSCell* JIT_OPERATION operationNewStringObject(ExecState*, JSString*, Structure*); JSCell* JIT_OPERATION operationToStringOnCell(ExecState*, JSCell*); JSCell* JIT_OPERATION operationToString(ExecState*, EncodedJSValue); +JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState*, JSCell*); +JSCell* JIT_OPERATION operationCallStringConstructor(ExecState*, EncodedJSValue); JSCell* JIT_OPERATION operationMakeRope2(ExecState*, JSString*, JSString*); JSCell* JIT_OPERATION operationMakeRope3(ExecState*, JSString*, JSString*, JSString*); char* JIT_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex); char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*); -void JIT_OPERATION operationNotifyWrite(ExecState*, VariableWatchpointSet*, EncodedJSValue); +int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState*, size_t tableIndex, JSString*); +void JIT_OPERATION operationNotifyWrite(ExecState*, WatchpointSet*); +void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState*) WTF_INTERNAL; +int32_t JIT_OPERATION operationSizeOfVarargs(ExecState*, EncodedJSValue arguments, int32_t firstVarArgOffset); +void JIT_OPERATION operationLoadVarargs(ExecState*, int32_t firstElementDest, EncodedJSValue arguments, int32_t offset, int32_t length, int32_t mandatoryMinimum); int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue); int64_t JIT_OPERATION operationConvertDoubleToInt52(double); +void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState*) WTF_INTERNAL; + // These operations implement the implicitly called ToInt32 and ToBoolean conversions from ES5. // This conversion returns an int32_t within a size_t such that the value is zero extended to fill the register. size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState*, EncodedJSValue) WTF_INTERNAL; void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void*, void*) WTF_INTERNAL; -void JIT_OPERATION triggerReoptimizationNow(CodeBlock*) WTF_INTERNAL; +void JIT_OPERATION triggerReoptimizationNow(CodeBlock*, OSRExitBase*) WTF_INTERNAL; #if ENABLE(FTL_JIT) void JIT_OPERATION triggerTierUpNow(ExecState*) WTF_INTERNAL; +void JIT_OPERATION triggerTierUpNowInLoop(ExecState*) WTF_INTERNAL; char* JIT_OPERATION triggerOSREntryNow(ExecState*, int32_t bytecodeIndex, int32_t streamIndex) WTF_INTERNAL; #endif // ENABLE(FTL_JIT) diff --git a/dfg/DFGPhantomInsertionPhase.cpp b/dfg/DFGPhantomInsertionPhase.cpp new file mode 100644 index 0000000..b9e023f --- /dev/null +++ b/dfg/DFGPhantomInsertionPhase.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2015 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 "DFGPhantomInsertionPhase.h" + +#if ENABLE(DFG_JIT) + +#include "BytecodeLivenessAnalysisInlines.h" +#include "DFGForAllKills.h" +#include "DFGGraph.h" +#include "DFGInsertionSet.h" +#include "DFGMayExit.h" +#include "DFGPhase.h" +#include "DFGPredictionPropagationPhase.h" +#include "DFGVariableAccessDataDump.h" +#include "JSCInlines.h" +#include "OperandsInlines.h" + +namespace JSC { namespace DFG { + +namespace { + +bool verbose = false; + +class PhantomInsertionPhase : public Phase { +public: + PhantomInsertionPhase(Graph& graph) + : Phase(graph, "phantom insertion") + , m_insertionSet(graph) + , m_values(OperandsLike, graph.block(0)->variablesAtHead) + { + } + + bool run() + { + // We assume that DCE has already run. If we run before DCE then we think that all + // SetLocals execute, which is inaccurate. That causes us to insert too few Phantoms. + DFG_ASSERT(m_graph, nullptr, m_graph.m_refCountState == ExactRefCount); + + if (verbose) { + dataLog("Graph before Phantom insertion:\n"); + m_graph.dump(); + } + + m_graph.clearEpochs(); + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) + handleBlock(block); + + if (verbose) { + dataLog("Graph after Phantom insertion:\n"); + m_graph.dump(); + } + + return true; + } + +private: + void handleBlock(BasicBlock* block) + { + // FIXME: For blocks that have low register pressure, it would make the most sense to + // simply insert Phantoms at the last point possible since that would obviate the need to + // query bytecode liveness: + // + // - If we MovHint @x into loc42 then put a Phantom on the last MovHinted value in loc42. + // - At the end of the block put Phantoms for each MovHinted value. + // + // This will definitely not work if there are any phantom allocations. For those blocks + // where this would be legal, it remains to be seen how profitable it would be even if there + // was high register pressure. After all, a Phantom would cause a spill but it wouldn't + // cause a fill. + // + // https://bugs.webkit.org/show_bug.cgi?id=144524 + + m_values.fill(nullptr); + + Epoch currentEpoch = Epoch::first(); + unsigned lastExitingIndex = 0; + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (verbose) + dataLog("Considering ", node, "\n"); + + switch (node->op()) { + case MovHint: + m_values.operand(node->unlinkedLocal()) = node->child1().node(); + break; + + case ZombieHint: + m_values.operand(node->unlinkedLocal()) = nullptr; + break; + + case SetLocal: + case GetLocal: + case SetArgument: + m_values.operand(node->local()) = nullptr; + break; + + default: + break; + } + + if (mayExit(m_graph, node)) { + currentEpoch.bump(); + lastExitingIndex = nodeIndex; + } + + m_graph.doToChildren( + node, + [&] (Edge edge) { + edge->setEpoch(currentEpoch); + }); + + node->setEpoch(currentEpoch); + + forAllKilledOperands( + m_graph, node, block->tryAt(nodeIndex + 1), + [&] (VirtualRegister reg) { + if (verbose) + dataLog(" Killed operand: ", reg, "\n"); + + Node* killedNode = m_values.operand(reg); + if (!killedNode) + return; + + // We only need to insert a Phantom if the node hasn't been used since the last + // exit, and was born before the last exit. + if (killedNode->epoch() == currentEpoch) + return; + + if (verbose) { + dataLog( + " Inserting Phantom on ", killedNode, " after ", + block->at(lastExitingIndex), "\n"); + } + + // We have exact ref counts, so creating a new use means that we have to + // increment the ref count. + killedNode->postfixRef(); + + m_insertionSet.insertNode( + lastExitingIndex + 1, SpecNone, Phantom, + block->at(lastExitingIndex)->origin, killedNode->defaultEdge()); + }); + } + + m_insertionSet.execute(block); + } + + InsertionSet m_insertionSet; + Operands<Node*> m_values; +}; + +} // anonymous namespace + +bool performPhantomInsertion(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Phantom Insertion Phase"); + return runPhase<PhantomInsertionPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGPhantomInsertionPhase.h b/dfg/DFGPhantomInsertionPhase.h new file mode 100644 index 0000000..902975b --- /dev/null +++ b/dfg/DFGPhantomInsertionPhase.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 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 DFGPhantomInsertionPhase_h +#define DFGPhantomInsertionPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Inserts Phantoms based on bytecode liveness. + +bool performPhantomInsertion(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPhantomInsertionPhase_h diff --git a/dfg/DFGPhase.cpp b/dfg/DFGPhase.cpp index 15c413a..c13c8c4 100644 --- a/dfg/DFGPhase.cpp +++ b/dfg/DFGPhase.cpp @@ -35,8 +35,15 @@ namespace JSC { namespace DFG { void Phase::beginPhase() { + if (Options::verboseValidationFailure()) { + StringPrintStream out; + m_graph.dump(out); + m_graphDumpBeforePhase = out.toCString(); + } + if (!shouldDumpGraphAtEachPhase()) return; + dataLog("Beginning DFG phase ", m_name, ".\n"); dataLog("Before ", m_name, ":\n"); m_graph.dump(); @@ -46,7 +53,7 @@ void Phase::endPhase() { if (!Options::validateGraphAtEachPhase()) return; - validate(m_graph, DumpGraph); + validate(m_graph, DumpGraph, m_graphDumpBeforePhase); } } } // namespace JSC::DFG diff --git a/dfg/DFGPhase.h b/dfg/DFGPhase.h index fc9e0d1..5e8b329 100644 --- a/dfg/DFGPhase.h +++ b/dfg/DFGPhase.h @@ -67,6 +67,8 @@ private: // Call these hooks when starting and finishing. void beginPhase(); void endPhase(); + + CString m_graphDumpBeforePhase; }; template<typename PhaseType> diff --git a/dfg/DFGPhiChildren.cpp b/dfg/DFGPhiChildren.cpp new file mode 100644 index 0000000..de078d0 --- /dev/null +++ b/dfg/DFGPhiChildren.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 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 "DFGPhiChildren.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +PhiChildren::PhiChildren() +{ +} + +PhiChildren::PhiChildren(Graph& graph) +{ + for (BasicBlock* block : graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + if (node->op() != Upsilon) + continue; + + m_children.add(node->phi(), List()).iterator->value.append(node); + } + } +} + +PhiChildren::~PhiChildren() +{ +} + +const PhiChildren::List& PhiChildren::upsilonsOf(Node* node) const +{ + ASSERT(node->op() == Phi); + return m_children.find(node)->value; +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGPhiChildren.h b/dfg/DFGPhiChildren.h new file mode 100644 index 0000000..808512e --- /dev/null +++ b/dfg/DFGPhiChildren.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 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 DFGPhiChildren_h +#define DFGPhiChildren_h + +#if ENABLE(DFG_JIT) + +#include "DFGNode.h" +#include <wtf/HashSet.h> +#include <wtf/Vector.h> + +namespace JSC { namespace DFG { + +class Graph; + +class PhiChildren { +public: + typedef Vector<Node*, 3> List; + + PhiChildren(); + PhiChildren(Graph&); + ~PhiChildren(); + + // The list of Upsilons that point to the children of the Phi. + const List& upsilonsOf(Node*) const; + + template<typename Functor> + void forAllIncomingValues(Node* node, const Functor& functor) + { + for (Node* upsilon : upsilonsOf(node)) + functor(upsilon->child1().node()); + } + + // This walks the Phi graph. + template<typename Functor> + void forAllTransitiveIncomingValues(Node* node, const Functor& functor) + { + if (node->op() != Phi) { + functor(node); + return; + } + HashSet<Node*> seen; + Vector<Node*> worklist; + seen.add(node); + worklist.append(node); + while (!worklist.isEmpty()) { + Node* currentNode = worklist.takeLast(); + forAllIncomingValues( + currentNode, + [&] (Node* incomingNode) { + if (incomingNode->op() == Phi) { + if (seen.add(incomingNode).isNewEntry) + worklist.append(incomingNode); + } else + functor(incomingNode); + }); + } + } + +private: + HashMap<Node*, List> m_children; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPhiChildren_h + diff --git a/dfg/DFGPlan.cpp b/dfg/DFGPlan.cpp index 6de782c..bf7b7dd 100644 --- a/dfg/DFGPlan.cpp +++ b/dfg/DFGPlan.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,46 +28,55 @@ #if ENABLE(DFG_JIT) -#include "DFGArgumentsSimplificationPhase.h" +#include "DFGArgumentsEliminationPhase.h" #include "DFGBackwardsPropagationPhase.h" #include "DFGByteCodeParser.h" #include "DFGCFAPhase.h" #include "DFGCFGSimplificationPhase.h" #include "DFGCPSRethreadingPhase.h" #include "DFGCSEPhase.h" +#include "DFGCleanUpPhase.h" #include "DFGConstantFoldingPhase.h" +#include "DFGConstantHoistingPhase.h" #include "DFGCriticalEdgeBreakingPhase.h" #include "DFGDCEPhase.h" #include "DFGFailedFinalizer.h" #include "DFGFixupPhase.h" #include "DFGGraphSafepoint.h" #include "DFGIntegerCheckCombiningPhase.h" +#include "DFGIntegerRangeOptimizationPhase.h" #include "DFGInvalidationPointInjectionPhase.h" #include "DFGJITCompiler.h" #include "DFGLICMPhase.h" #include "DFGLivenessAnalysisPhase.h" #include "DFGLoopPreHeaderCreationPhase.h" +#include "DFGMovHintRemovalPhase.h" #include "DFGOSRAvailabilityAnalysisPhase.h" #include "DFGOSREntrypointCreationPhase.h" +#include "DFGObjectAllocationSinkingPhase.h" +#include "DFGPhantomInsertionPhase.h" #include "DFGPredictionInjectionPhase.h" #include "DFGPredictionPropagationPhase.h" -#include "DFGResurrectionForValidationPhase.h" +#include "DFGPutStackSinkingPhase.h" #include "DFGSSAConversionPhase.h" #include "DFGSSALoweringPhase.h" #include "DFGStackLayoutPhase.h" #include "DFGStaticExecutionCountEstimationPhase.h" -#include "DFGStoreBarrierElisionPhase.h" +#include "DFGStoreBarrierInsertionPhase.h" #include "DFGStrengthReductionPhase.h" +#include "DFGStructureRegistrationPhase.h" #include "DFGTierUpCheckInjectionPhase.h" #include "DFGTypeCheckHoistingPhase.h" #include "DFGUnificationPhase.h" #include "DFGValidate.h" +#include "DFGVarargsForwardingPhase.h" #include "DFGVirtualRegisterAllocationPhase.h" #include "DFGWatchpointCollectionPhase.h" #include "Debugger.h" #include "JSCInlines.h" #include "OperandsInlines.h" #include "ProfilerDatabase.h" +#include "TrackedReferences.h" #include <wtf/CurrentTime.h> #if ENABLE(FTL_JIT) @@ -82,10 +91,10 @@ namespace JSC { namespace DFG { -static void dumpAndVerifyGraph(Graph& graph, const char* text) +static void dumpAndVerifyGraph(Graph& graph, const char* text, bool forceDump = false) { GraphDumpMode modeForFinalValidate = DumpGraph; - if (verboseCompilationEnabled(graph.m_plan.mode)) { + if (verboseCompilationEnabled(graph.m_plan.mode) || forceDump) { dataLog(text, "\n"); graph.dump(); modeForFinalValidate = DontDumpGraph; @@ -146,7 +155,7 @@ void Plan::compileInThread(LongLivedState& longLivedState, ThreadData* threadDat double before = 0; CString codeBlockName; if (reportCompileTimes()) { - before = currentTimeMS(); + before = monotonicallyIncreasingTimeMS(); codeBlockName = toCString(*codeBlock); } @@ -178,13 +187,15 @@ void Plan::compileInThread(LongLivedState& longLivedState, ThreadData* threadDat break; default: RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) pathName = ""; +#endif break; } - double now = currentTimeMS(); + double now = monotonicallyIncreasingTimeMS(); dataLog("Optimized ", codeBlockName, " using ", mode, " with ", pathName, " into ", finalizer ? finalizer->codeSize() : 0, " bytes in ", now - before, " ms"); if (path == FTLPath) - dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")"); + dataLog(" (DFG: ", m_timeBeforeFTL - before, ", LLVM: ", now - m_timeBeforeFTL, ")"); dataLog(".\n"); } } @@ -200,7 +211,7 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) Graph dfg(vm, *this, longLivedState); if (!parse(dfg)) { - finalizer = adoptPtr(new FailedFinalizer(*this)); + finalizer = std::make_unique<FailedFinalizer>(*this); return FailPath; } @@ -213,6 +224,11 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) if (validationEnabled()) validate(dfg); + if (Options::dumpGraphAfterParsing()) { + dataLog("Graph after parsing:\n"); + dfg.dump(); + } + performCPSRethreading(dfg); performUnification(dfg); performPredictionInjection(dfg); @@ -222,7 +238,7 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) if (mode == FTLForOSREntryMode) { bool result = performOSREntrypointCreation(dfg); if (!result) { - finalizer = adoptPtr(new FailedFinalizer(*this)); + finalizer = std::make_unique<FailedFinalizer>(*this); return FailPath; } performCPSRethreading(dfg); @@ -234,65 +250,89 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) performBackwardsPropagation(dfg); performPredictionPropagation(dfg); performFixup(dfg); + performStructureRegistration(dfg); performInvalidationPointInjection(dfg); performTypeCheckHoisting(dfg); - unsigned count = 1; dfg.m_fixpointState = FixpointNotConverged; - for (;; ++count) { - if (logCompilationChanges(mode)) - dataLogF("DFG beginning optimization fixpoint iteration #%u.\n", count); - bool changed = false; + + // For now we're back to avoiding a fixpoint. Note that we've ping-ponged on this decision + // many times. For maximum throughput, it's best to fixpoint. But the throughput benefit is + // small and not likely to show up in FTL anyway. On the other hand, not fixpointing means + // that the compiler compiles more quickly. We want the third tier to compile quickly, which + // not fixpointing accomplishes; and the fourth tier shouldn't need a fixpoint. + if (validationEnabled()) + validate(dfg); - if (validationEnabled()) - validate(dfg); + performStrengthReduction(dfg); + performLocalCSE(dfg); + performCPSRethreading(dfg); + performCFA(dfg); + performConstantFolding(dfg); + bool changed = false; + changed |= performCFGSimplification(dfg); + changed |= performLocalCSE(dfg); + + if (validationEnabled()) + validate(dfg); + + performCPSRethreading(dfg); + if (!isFTL(mode)) { + // Only run this if we're not FTLing, because currently for a LoadVarargs that is forwardable and + // in a non-varargs inlined call frame, this will generate ForwardVarargs while the FTL + // ArgumentsEliminationPhase will create a sequence of GetStack+PutStacks. The GetStack+PutStack + // sequence then gets sunk, eliminating anything that looks like an escape for subsequent phases, + // while the ForwardVarargs doesn't get simplified until later (or not at all) and looks like an + // escape for all of the arguments. This then disables object allocation sinking. + // + // So, for now, we just disable this phase for the FTL. + // + // If we wanted to enable it, we'd have to do any of the following: + // - Enable ForwardVarargs->GetStack+PutStack strength reduction, and have that run before + // PutStack sinking and object allocation sinking. + // - Make VarargsForwarding emit a GetLocal+SetLocal sequence, that we can later turn into + // GetStack+PutStack. + // + // But, it's not super valuable to enable those optimizations, since the FTL + // ArgumentsEliminationPhase does everything that this phase does, and it doesn't introduce this + // pathology. - changed |= performStrengthReduction(dfg); + changed |= performVarargsForwarding(dfg); // Do this after CFG simplification and CPS rethreading. + } + if (changed) { performCFA(dfg); - changed |= performConstantFolding(dfg); - changed |= performArgumentsSimplification(dfg); - changed |= performCFGSimplification(dfg); - changed |= performCSE(dfg); - - if (!changed) - break; - - performCPSRethreading(dfg); + performConstantFolding(dfg); } - if (logCompilationChanges(mode)) - dataLogF("DFG optimization fixpoint converged in %u iterations.\n", count); - - dfg.m_fixpointState = FixpointConverged; - // If we're doing validation, then run some analyses, to give them an opportunity // to self-validate. Now is as good a time as any to do this. if (validationEnabled()) { dfg.m_dominators.computeIfNecessary(dfg); dfg.m_naturalLoops.computeIfNecessary(dfg); + dfg.m_prePostNumbering.computeIfNecessary(dfg); } switch (mode) { case DFGMode: { + dfg.m_fixpointState = FixpointConverged; + performTierUpCheckInjection(dfg); - performStoreBarrierElision(dfg); - performStoreElimination(dfg); + performFastStoreBarrierInsertion(dfg); + performCleanUp(dfg); performCPSRethreading(dfg); performDCE(dfg); + performPhantomInsertion(dfg); performStackLayout(dfg); performVirtualRegisterAllocation(dfg); performWatchpointCollection(dfg); dumpAndVerifyGraph(dfg, "Graph after optimization:"); JITCompiler dataFlowJIT(dfg); - if (codeBlock->codeType() == FunctionCode) { + if (codeBlock->codeType() == FunctionCode) dataFlowJIT.compileFunction(); - dataFlowJIT.linkFunction(); - } else { + else dataFlowJIT.compile(); - dataFlowJIT.link(); - } return DFGPath; } @@ -301,37 +341,76 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) case FTLForOSREntryMode: { #if ENABLE(FTL_JIT) if (FTL::canCompile(dfg) == FTL::CannotCompile) { - finalizer = adoptPtr(new FailedFinalizer(*this)); + finalizer = std::make_unique<FailedFinalizer>(*this); return FailPath; } + performCleanUp(dfg); // Reduce the graph size a bit. performCriticalEdgeBreaking(dfg); performLoopPreHeaderCreation(dfg); performCPSRethreading(dfg); performSSAConversion(dfg); performSSALowering(dfg); - performCSE(dfg); + + // Ideally, these would be run to fixpoint with the object allocation sinking phase. + performArgumentsElimination(dfg); + performPutStackSinking(dfg); + + performConstantHoisting(dfg); + performGlobalCSE(dfg); + performLivenessAnalysis(dfg); + performIntegerRangeOptimization(dfg); performLivenessAnalysis(dfg); performCFA(dfg); + performConstantFolding(dfg); + performCleanUp(dfg); // Reduce the graph size a lot. + changed = false; + changed |= performStrengthReduction(dfg); + if (Options::enableObjectAllocationSinking()) { + changed |= performCriticalEdgeBreaking(dfg); + changed |= performObjectAllocationSinking(dfg); + } + if (changed) { + // State-at-tail and state-at-head will be invalid if we did strength reduction since + // it might increase live ranges. + performLivenessAnalysis(dfg); + performCFA(dfg); + performConstantFolding(dfg); + } + + // Currently, this relies on pre-headers still being valid. That precludes running CFG + // simplification before it, unless we re-created the pre-headers. There wouldn't be anything + // wrong with running LICM earlier, if we wanted to put other CFG transforms above this point. + // Alternatively, we could run loop pre-header creation after SSA conversion - but if we did that + // then we'd need to do some simple SSA fix-up. performLICM(dfg); + + performCleanUp(dfg); performIntegerCheckCombining(dfg); - performCSE(dfg); + performGlobalCSE(dfg); // At this point we're not allowed to do any further code motion because our reasoning // about code motion assumes that it's OK to insert GC points in random places. + dfg.m_fixpointState = FixpointConverged; - performStoreBarrierElision(dfg); performLivenessAnalysis(dfg); performCFA(dfg); - if (Options::validateFTLOSRExitLiveness()) - performResurrectionForValidation(dfg); - performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM. + performGlobalStoreBarrierInsertion(dfg); + if (Options::enableMovHintRemoval()) + performMovHintRemoval(dfg); + performCleanUp(dfg); + performDCE(dfg); // We rely on this to kill dead code that won't be recognized as dead by LLVM. performStackLayout(dfg); performLivenessAnalysis(dfg); performOSRAvailabilityAnalysis(dfg); performWatchpointCollection(dfg); - dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:"); + if (FTL::canCompile(dfg) == FTL::CannotCompile) { + finalizer = std::make_unique<FailedFinalizer>(*this); + return FailPath; + } + + dumpAndVerifyGraph(dfg, "Graph just before FTL lowering:", shouldShowDisassembly(mode)); bool haveLLVM; Safepoint::Result safepointResult; @@ -343,18 +422,19 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) return CancelPath; if (!haveLLVM) { - finalizer = adoptPtr(new FailedFinalizer(*this)); + if (Options::ftlCrashesIfCantInitializeLLVM()) { + dataLog("LLVM can't be initialized.\n"); + CRASH(); + } + finalizer = std::make_unique<FailedFinalizer>(*this); return FailPath; } - + FTL::State state(dfg); - if (!FTL::lowerDFGToLLVM(state)) { - FTL::fail(state); - return FTLPath; - } + FTL::lowerDFGToLLVM(state); if (reportCompileTimes()) - beforeFTL = currentTimeMS(); + m_timeBeforeFTL = monotonicallyIncreasingTimeMS(); if (Options::llvmAlwaysFailsBeforeCompile()) { FTL::fail(state); @@ -369,6 +449,11 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) FTL::fail(state); return FTLPath; } + + if (state.allocationFailed) { + FTL::fail(state); + return FTLPath; + } if (state.jitCode->stackmaps.stackSize() > Options::llvmMaxStackSize()) { FTL::fail(state); @@ -376,6 +461,12 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState) } FTL::link(state); + + if (state.allocationFailed) { + FTL::fail(state); + return FTLPath; + } + return FTLPath; #else RELEASE_ASSERT_NOT_REACHED(); @@ -402,8 +493,6 @@ bool Plan::isStillValid() return false; if (!watchpoints.areStillValid()) return false; - if (!chains.areStillValid()) - return false; return true; } @@ -448,6 +537,21 @@ CompilationResult Plan::finalizeWithoutNotifyingCallback() reallyAdd(codeBlock->jitCode()->dfgCommon()); + if (validationEnabled()) { + TrackedReferences trackedReferences; + + for (WriteBarrier<JSCell>& reference : codeBlock->jitCode()->dfgCommon()->weakReferences) + trackedReferences.add(reference.get()); + for (WriteBarrier<Structure>& reference : codeBlock->jitCode()->dfgCommon()->weakStructureReferences) + trackedReferences.add(reference.get()); + for (WriteBarrier<Unknown>& constant : codeBlock->constants()) + trackedReferences.add(constant.get()); + + // Check that any other references that we have anywhere in the JITCode are also + // tracked either strongly or weakly. + codeBlock->jitCode()->validateReferences(trackedReferences); + } + return CompilationSuccessful; } @@ -473,7 +577,6 @@ void Plan::checkLivenessAndVisitChildren(SlotVisitor& visitor, CodeBlockSet& cod codeBlocks.mark(codeBlock.get()); codeBlocks.mark(profiledDFGCodeBlock.get()); - chains.visitChildren(visitor); weakReferences.visitChildren(visitor); writeBarriers.visitChildren(visitor); transitions.visitChildren(visitor); @@ -498,11 +601,10 @@ void Plan::cancel() profiledDFGCodeBlock = nullptr; mustHandleValues.clear(); compilation = nullptr; - finalizer.clear(); + finalizer = nullptr; inlineCallFrames = nullptr; watchpoints = DesiredWatchpoints(); identifiers = DesiredIdentifiers(); - chains = DesiredStructureChains(); weakReferences = DesiredWeakReferences(); writeBarriers = DesiredWriteBarriers(); transitions = DesiredTransitions(); diff --git a/dfg/DFGPlan.h b/dfg/DFGPlan.h index a2fdced..6e7b53f 100644 --- a/dfg/DFGPlan.h +++ b/dfg/DFGPlan.h @@ -30,7 +30,6 @@ #include "DFGCompilationKey.h" #include "DFGCompilationMode.h" #include "DFGDesiredIdentifiers.h" -#include "DFGDesiredStructureChains.h" #include "DFGDesiredTransitions.h" #include "DFGDesiredWatchpoints.h" #include "DFGDesiredWeakReferences.h" @@ -87,20 +86,17 @@ struct Plan : public ThreadSafeRefCounted<Plan> { RefPtr<Profiler::Compilation> compilation; - OwnPtr<Finalizer> finalizer; + std::unique_ptr<Finalizer> finalizer; RefPtr<InlineCallFrameSet> inlineCallFrames; DesiredWatchpoints watchpoints; DesiredIdentifiers identifiers; - DesiredStructureChains chains; DesiredWeakReferences weakReferences; DesiredWriteBarriers writeBarriers; DesiredTransitions transitions; bool willTryToTierUp; - double beforeFTL; - enum Stage { Preparing, Compiling, Compiled, Ready, Cancelled }; Stage stage; @@ -114,6 +110,8 @@ private: bool isStillValid(); void reallyAdd(CommonData*); + + double m_timeBeforeFTL; }; #else // ENABLE(DFG_JIT) diff --git a/dfg/DFGPrePostNumbering.cpp b/dfg/DFGPrePostNumbering.cpp new file mode 100644 index 0000000..166ff45 --- /dev/null +++ b/dfg/DFGPrePostNumbering.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 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 "DFGPrePostNumbering.h" + +#if ENABLE(DFG_JIT) + +#include "DFGBlockMapInlines.h" +#include "DFGBlockWorklist.h" +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +PrePostNumbering::PrePostNumbering() { } +PrePostNumbering::~PrePostNumbering() { } + +void PrePostNumbering::compute(Graph& graph) +{ + m_map = BlockMap<Numbering>(graph); + + PostOrderBlockWorklist worklist; + worklist.push(graph.block(0)); + unsigned nextPreNumber = 0; + unsigned nextPostNumber = 0; + while (BlockWithOrder item = worklist.pop()) { + switch (item.order) { + case PreOrder: + m_map[item.block].m_preNumber = nextPreNumber++; + worklist.pushPost(item.block); + for (BasicBlock* successor : item.block->successors()) + worklist.push(successor); + break; + case PostOrder: + m_map[item.block].m_postNumber = nextPostNumber++; + break; + } + } +} + +} } // namespace JSC::DFG + +namespace WTF { + +using namespace JSC::DFG; + +void printInternal(PrintStream& out, EdgeKind kind) +{ + switch (kind) { + case ForwardEdge: + out.print("ForwardEdge"); + return; + case CrossEdge: + out.print("CrossEdge"); + return; + case BackEdge: + out.print("BackEdge"); + return; + } + + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGPrePostNumbering.h b/dfg/DFGPrePostNumbering.h new file mode 100644 index 0000000..286bf62 --- /dev/null +++ b/dfg/DFGPrePostNumbering.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2014 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 DFGPrePostNumbering_h +#define DFGPrePostNumbering_h + +#if ENABLE(DFG_JIT) + +#include "DFGAnalysis.h" +#include "DFGBasicBlock.h" +#include "DFGBlockMap.h" + +namespace JSC { namespace DFG { + +enum EdgeKind { + ForwardEdge, + CrossEdge, + BackEdge +}; + +class PrePostNumbering : public Analysis<PrePostNumbering> { +public: + PrePostNumbering(); + ~PrePostNumbering(); + + void compute(Graph&); + + unsigned preNumber(BasicBlock* block) const { return m_map[block].m_preNumber; } + unsigned postNumber(BasicBlock* block) const { return m_map[block].m_postNumber; } + + // Is from a strict ancestor of to? + bool isStrictAncestorOf(BasicBlock* from, BasicBlock* to) const + { + return preNumber(from) < preNumber(to) + && postNumber(from) > postNumber(to); + } + + bool isAncestorOf(BasicBlock* from, BasicBlock* to) const + { + return from == to || isStrictAncestorOf(from, to); + } + + bool isStrictDescendantOf(BasicBlock* from, BasicBlock* to) const + { + return isStrictAncestorOf(to, from); + } + + bool isDescendantOf(BasicBlock* from, BasicBlock* to) const + { + return isAncestorOf(to, from); + } + + // This will give a bogus answer if there is actually no such edge. If you want to determine + // if there is any such edge, you have to do it yourself. + EdgeKind edgeKind(BasicBlock* from, BasicBlock* to) const + { + if (isStrictDescendantOf(to, from)) + return ForwardEdge; + + if (isAncestorOf(to, from)) + return BackEdge; + + return CrossEdge; + } + +private: + struct Numbering { + unsigned m_preNumber; + unsigned m_postNumber; + }; + + BlockMap<Numbering> m_map; +}; + +} } // namespace JSC::DFG + +namespace WTF { + +void printInternal(PrintStream&, JSC::DFG::EdgeKind); + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPrePostNumbering_h + diff --git a/dfg/DFGPreciseLocalClobberize.h b/dfg/DFGPreciseLocalClobberize.h new file mode 100644 index 0000000..1cd6b09 --- /dev/null +++ b/dfg/DFGPreciseLocalClobberize.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2014, 2015 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 DFGPreciseLocalClobberize_h +#define DFGPreciseLocalClobberize_h + +#if ENABLE(DFG_JIT) + +#include "DFGClobberize.h" +#include "DFGMayExit.h" + +namespace JSC { namespace DFG { + +template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor> +class PreciseLocalClobberizeAdaptor { +public: + PreciseLocalClobberizeAdaptor( + Graph& graph, Node* node, + const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def) + : m_graph(graph) + , m_node(node) + , m_read(read) + , m_write(write) + , m_def(def) + { + } + + void read(AbstractHeap heap) + { + if (heap.kind() == Stack) { + if (heap.payload().isTop()) { + readTop(); + return; + } + + callIfAppropriate(m_read, VirtualRegister(heap.payload().value32())); + return; + } + + if (heap.overlaps(Stack)) { + readTop(); + return; + } + } + + void write(AbstractHeap heap) + { + // We expect stack writes to already be precisely characterized by DFG::clobberize(). + if (heap.kind() == Stack) { + RELEASE_ASSERT(!heap.payload().isTop()); + callIfAppropriate(m_write, VirtualRegister(heap.payload().value32())); + return; + } + + RELEASE_ASSERT(!heap.overlaps(Stack)); + } + + void def(PureValue) + { + // PureValue defs never have anything to do with locals, so ignore this. + } + + void def(HeapLocation location, LazyNode node) + { + if (location.kind() != StackLoc) + return; + + RELEASE_ASSERT(location.heap().kind() == Stack); + + m_def(VirtualRegister(location.heap().payload().value32()), node); + } + +private: + template<typename Functor> + void callIfAppropriate(const Functor& functor, VirtualRegister operand) + { + if (operand.isLocal() && static_cast<unsigned>(operand.toLocal()) >= m_graph.block(0)->variablesAtHead.numberOfLocals()) + return; + + if (operand.isArgument() && !operand.isHeader() && static_cast<unsigned>(operand.toArgument()) >= m_graph.block(0)->variablesAtHead.numberOfArguments()) + return; + + functor(operand); + } + + void readTop() + { + switch (m_node->op()) { + case GetMyArgumentByVal: + case ForwardVarargs: + case CallForwardVarargs: + case ConstructForwardVarargs: { + InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame; + if (!inlineCallFrame) { + // Read the outermost arguments and argument count. + for (unsigned i = m_graph.m_codeBlock->numParameters(); i-- > 1;) + m_read(virtualRegisterForArgument(i)); + m_read(VirtualRegister(JSStack::ArgumentCount)); + break; + } + + for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;) + m_read(VirtualRegister(inlineCallFrame->stackOffset + virtualRegisterForArgument(i).offset())); + if (inlineCallFrame->isVarargs()) + m_read(VirtualRegister(inlineCallFrame->stackOffset + JSStack::ArgumentCount)); + break; + } + + default: { + // All of the outermost arguments, except this, are definitely read. + for (unsigned i = m_graph.m_codeBlock->numParameters(); i-- > 1;) + m_read(virtualRegisterForArgument(i)); + + // The stack header is read. + for (unsigned i = 0; i < JSStack::ThisArgument; ++i) + m_read(VirtualRegister(i)); + + // Read all of the inline arguments and call frame headers that we didn't already capture. + for (InlineCallFrame* inlineCallFrame = m_node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) { + for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;) + m_read(VirtualRegister(inlineCallFrame->stackOffset + virtualRegisterForArgument(i).offset())); + if (inlineCallFrame->isClosureCall) + m_read(VirtualRegister(inlineCallFrame->stackOffset + JSStack::Callee)); + if (inlineCallFrame->isVarargs()) + m_read(VirtualRegister(inlineCallFrame->stackOffset + JSStack::ArgumentCount)); + } + break; + } } + } + + Graph& m_graph; + Node* m_node; + const ReadFunctor& m_read; + const WriteFunctor& m_write; + const DefFunctor& m_def; +}; + +template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor> +void preciseLocalClobberize( + Graph& graph, Node* node, + const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def) +{ + PreciseLocalClobberizeAdaptor<ReadFunctor, WriteFunctor, DefFunctor> + adaptor(graph, node, read, write, def); + clobberize(graph, node, adaptor); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPreciseLocalClobberize_h + diff --git a/dfg/DFGPredictionPropagationPhase.cpp b/dfg/DFGPredictionPropagationPhase.cpp index 6a35b9c..cde09bf 100644 --- a/dfg/DFGPredictionPropagationPhase.cpp +++ b/dfg/DFGPredictionPropagationPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -57,6 +57,8 @@ public: ASSERT(m_graph.m_form == ThreadedCPS); ASSERT(m_graph.m_unificationState == GloballyUnified); + propagateThroughArgumentPositions(); + m_pass = PrimaryPass; propagateToFixpoint(); @@ -141,14 +143,18 @@ private: bool changed = false; switch (op) { - case JSConstant: - case WeakJSConstant: { - SpeculatedType type = speculationFromValue(m_graph.valueOfJSConstant(node)); + case JSConstant: { + SpeculatedType type = speculationFromValue(node->asJSValue()); if (type == SpecInt52AsDouble && enableInt52()) type = SpecInt52; changed |= setPrediction(type); break; } + case DoubleConstant: { + SpeculatedType type = speculationFromValue(node->asJSValue()); + changed |= setPrediction(type); + break; + } case GetLocal: { VariableAccessData* variable = node->variableAccessData(); @@ -172,7 +178,8 @@ private: case BitRShift: case BitLShift: case BitURShift: - case ArithIMul: { + case ArithIMul: + case ArithClz32: { changed |= setPrediction(SpecInt32); break; } @@ -183,16 +190,42 @@ private: case RegExpTest: case GetById: case GetByIdFlush: - case GetMyArgumentByValSafe: case GetByOffset: case MultiGetByOffset: + case GetDirectPname: case Call: case Construct: + case CallVarargs: + case ConstructVarargs: + case CallForwardVarargs: + case ConstructForwardVarargs: + case NativeCall: + case NativeConstruct: case GetGlobalVar: - case GetClosureVar: { + case GetClosureVar: + case GetFromArguments: { changed |= setPrediction(node->getHeapPrediction()); break; } + + case GetGetterSetterByOffset: + case GetExecutable: { + changed |= setPrediction(SpecCellOther); + break; + } + + case GetGetter: + case GetSetter: + case GetCallee: + case NewFunction: { + changed |= setPrediction(SpecFunction); + break; + } + + case GetArgumentCount: { + changed |= setPrediction(SpecInt32); + break; + } case StringCharCodeAt: { changed |= setPrediction(SpecInt32); @@ -232,22 +265,8 @@ private: } break; } - - case ArithAdd: { - SpeculatedType left = node->child1()->prediction(); - SpeculatedType right = node->child2()->prediction(); - - if (left && right) { - if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32) - changed |= mergePrediction(SpecInt32); - else if (m_graph.addShouldSpeculateMachineInt(node)) - changed |= mergePrediction(SpecInt52); - else - changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); - } - break; - } - + + case ArithAdd: case ArithSub: { SpeculatedType left = node->child1()->prediction(); SpeculatedType right = node->child2()->prediction(); @@ -303,21 +322,8 @@ private: } break; } - - case ArithDiv: { - SpeculatedType left = node->child1()->prediction(); - SpeculatedType right = node->child2()->prediction(); - - if (left && right) { - if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) - && node->canSpeculateInt32(m_pass)) - changed |= mergePrediction(SpecInt32); - else - changed |= mergePrediction(SpecBytecodeDouble); - } - break; - } - + + case ArithDiv: case ArithMod: { SpeculatedType left = node->child1()->prediction(); SpeculatedType right = node->child2()->prediction(); @@ -331,15 +337,25 @@ private: } break; } - + + case ArithPow: case ArithSqrt: case ArithFRound: case ArithSin: - case ArithCos: { + case ArithCos: + case ArithLog: { changed |= setPrediction(SpecBytecodeDouble); break; } - + + case ArithRound: { + if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, m_pass)) + changed |= setPrediction(SpecInt32); + else + changed |= setPrediction(SpecBytecodeDouble); + break; + } + case ArithAbs: { SpeculatedType child = node->child1()->prediction(); if (isInt32OrBooleanSpeculationForArithmetic(child) @@ -364,13 +380,14 @@ private: case IsNumber: case IsString: case IsObject: + case IsObjectOrNull: case IsFunction: { changed |= setPrediction(SpecBoolean); break; } case TypeOf: { - changed |= setPrediction(SpecString); + changed |= setPrediction(SpecStringIdent); break; } @@ -382,9 +399,15 @@ private: m_graph, node, node->child1()->prediction(), node->child2()->prediction(), - SpecNone, node->flags()); + SpecNone); switch (arrayMode.type()) { + case Array::Int32: + if (arrayMode.isOutOfBounds()) + changed |= mergePrediction(node->getHeapPrediction() | SpecInt32); + else + changed |= mergePrediction(SpecInt32); + break; case Array::Double: if (arrayMode.isOutOfBounds()) changed |= mergePrediction(node->getHeapPrediction() | SpecDoubleReal); @@ -396,13 +419,20 @@ private: changed |= mergePrediction(SpecFullDouble); break; case Array::Uint32Array: - if (isInt32Speculation(node->getHeapPrediction())) + if (isInt32SpeculationForArithmetic(node->getHeapPrediction())) changed |= mergePrediction(SpecInt32); else if (enableInt52()) changed |= mergePrediction(SpecMachineInt); else changed |= mergePrediction(SpecInt32 | SpecInt52AsDouble); break; + case Array::Int8Array: + case Array::Uint8Array: + case Array::Int16Array: + case Array::Uint16Array: + case Array::Int32Array: + changed |= mergePrediction(SpecInt32); + break; default: changed |= mergePrediction(node->getHeapPrediction()); break; @@ -410,12 +440,6 @@ private: break; } - case GetMyArgumentsLengthSafe: { - changed |= setPrediction(SpecInt32); - break; - } - - case GetClosureRegisters: case GetButterfly: case GetIndexedPropertyStorage: case AllocatePropertyStorage: @@ -436,18 +460,11 @@ private: break; } - case GetMyScope: - case SkipTopScope: case SkipScope: { changed |= setPrediction(SpecObjectOther); break; } - case GetCallee: { - changed |= setPrediction(SpecFunction); - break; - } - case CreateThis: case NewObject: { changed |= setPrediction(SpecFinalObject); @@ -478,6 +495,7 @@ private: break; } case StringCharAt: + case CallStringConstructor: case ToString: case MakeRope: { changed |= setPrediction(SpecString); @@ -496,23 +514,18 @@ private: break; } - case CreateArguments: { - changed |= setPrediction(SpecArguments); + case CreateDirectArguments: { + changed |= setPrediction(SpecDirectArguments); break; } - case NewFunction: { - SpeculatedType child = node->child1()->prediction(); - if (child & SpecEmpty) - changed |= mergePrediction((child & ~SpecEmpty) | SpecFunction); - else - changed |= mergePrediction(child); + case CreateScopedArguments: { + changed |= setPrediction(SpecScopedArguments); break; } - case NewFunctionNoCheck: - case NewFunctionExpression: { - changed |= setPrediction(SpecFunction); + case CreateClonedArguments: { + changed |= setPrediction(SpecObjectOther); break; } @@ -527,30 +540,40 @@ private: case GetTypedArrayByteOffset: case DoubleAsInt32: case GetLocalUnlinked: - case GetMyArgumentsLength: - case GetMyArgumentByVal: - case PhantomPutStructure: - case PhantomArguments: case CheckArray: case Arrayify: case ArrayifyToStructure: case CheckTierUpInLoop: case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: case InvalidationPoint: case CheckInBounds: case ValueToInt32: - case HardPhantom: case DoubleRep: case ValueRep: case Int52Rep: - case DoubleConstant: case Int52Constant: case Identity: - case BooleanToNumber: { + case BooleanToNumber: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case GetMyArgumentByVal: + case ForwardVarargs: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PutStack: + case KillStack: + case StoreBarrier: + case GetStack: { // This node should never be visible at this stage of compilation. It is // inserted by fixup(), which follows this phase. - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_graph, node, "Unexpected node during prediction propagation"); break; } @@ -561,7 +584,6 @@ private: break; case Upsilon: - case GetArgument: // These don't get inserted until we go into SSA. RELEASE_ASSERT_NOT_REACHED(); break; @@ -574,13 +596,39 @@ private: changed |= setPrediction(SpecBoolean); break; + case GetEnumerableLength: { + changed |= setPrediction(SpecInt32); + break; + } + case HasGenericProperty: + case HasStructureProperty: + case HasIndexedProperty: { + changed |= setPrediction(SpecBoolean); + break; + } + case GetPropertyEnumerator: { + changed |= setPrediction(SpecCell); + break; + } + case GetEnumeratorStructurePname: { + changed |= setPrediction(SpecCell | SpecOther); + break; + } + case GetEnumeratorGenericPname: { + changed |= setPrediction(SpecCell | SpecOther); + break; + } + case ToIndexString: { + changed |= setPrediction(SpecString); + break; + } + #ifndef NDEBUG // These get ignored because they don't return anything. - case StoreBarrier: - case StoreBarrierWithNullCheck: case PutByValDirect: case PutByVal: case PutClosureVar: + case PutToArguments: case Return: case Throw: case PutById: @@ -594,21 +642,18 @@ private: case Breakpoint: case ProfileWillCall: case ProfileDidCall: + case ProfileType: + case ProfileControlFlow: case CheckHasInstance: case ThrowReferenceError: case ForceOSRExit: case SetArgument: case CheckStructure: - case CheckExecutable: - case StructureTransitionWatchpoint: - case CheckFunction: + case CheckCell: + case CheckNotEmpty: + case CheckBadCell: case PutStructure: - case TearOffActivation: - case TearOffArguments: - case CheckArgumentsNotCreated: - case VariableWatchpoint: case VarInjectionWatchpoint: - case AllocationProfileWatchpoint: case Phantom: case Check: case PutGlobalVar: @@ -616,11 +661,14 @@ private: case Unreachable: case LoopHint: case NotifyWrite: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: case ConstantStoragePointer: case MovHint: case ZombieHint: + case LoadVarargs: + break; + + // This gets ignored because it only pretends to produce a value. + case BottomValue: break; // This gets ignored because it already has a prediction. @@ -757,6 +805,7 @@ private: case ArithSqrt: case ArithCos: case ArithSin: + case ArithLog: if (node->child1()->shouldSpeculateNumber()) m_graph.voteNode(node->child1(), VoteDouble, weight); else @@ -823,8 +872,7 @@ private: continue; m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat(); } - for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i) - m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness(); + propagateThroughArgumentPositions(); for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i]; if (!variableAccessData->isRoot()) @@ -833,6 +881,12 @@ private: } } + void propagateThroughArgumentPositions() + { + for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i) + m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness(); + } + Node* m_currentNode; bool m_changed; PredictionPass m_pass; // We use different logic for considering predictions depending on how far along we are in propagation. diff --git a/dfg/DFGPromoteHeapAccess.h b/dfg/DFGPromoteHeapAccess.h new file mode 100644 index 0000000..2bf2875 --- /dev/null +++ b/dfg/DFGPromoteHeapAccess.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014, 2015 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 DFGPromoteHeapAccess_h +#define DFGPromoteHeapAccess_h + +#if ENABLE(DFG_JIT) + +#include "DFGNode.h" +#include "DFGPromotedHeapLocation.h" + +namespace JSC { namespace DFG { + +template<typename WriteFunctor, typename ReadFunctor> +void promoteHeapAccess(Node* node, const WriteFunctor& write, const ReadFunctor& read) +{ + switch (node->op()) { + case CheckStructure: { + if (node->child1()->isPhantomObjectAllocation()) + read(PromotedHeapLocation(StructurePLoc, node->child1())); + break; + } + + case GetByOffset: + case GetGetterSetterByOffset: { + if (node->child2()->isPhantomObjectAllocation()) { + unsigned identifierNumber = node->storageAccessData().identifierNumber; + read(PromotedHeapLocation(NamedPropertyPLoc, node->child2(), identifierNumber)); + } + break; + } + + case MultiGetByOffset: { + if (node->child1()->isPhantomObjectAllocation()) { + unsigned identifierNumber = node->multiGetByOffsetData().identifierNumber; + read(PromotedHeapLocation(NamedPropertyPLoc, node->child1(), identifierNumber)); + } + break; + } + + case GetClosureVar: + if (node->child1()->isPhantomActivationAllocation()) + read(PromotedHeapLocation(ClosureVarPLoc, node->child1(), node->scopeOffset().offset())); + break; + + case SkipScope: + if (node->child1()->isPhantomActivationAllocation()) + read(PromotedHeapLocation(ActivationScopePLoc, node->child1())); + break; + + case GetScope: + if (node->child1()->isPhantomFunctionAllocation()) + read(PromotedHeapLocation(FunctionActivationPLoc, node->child1())); + break; + + case GetExecutable: + if (node->child1()->isPhantomFunctionAllocation()) + read(PromotedHeapLocation(FunctionExecutablePLoc, node->child1())); + break; + + case PutHint: { + ASSERT(node->child1()->isPhantomAllocation()); + write( + PromotedHeapLocation(node->child1().node(), node->promotedLocationDescriptor()), + node->child2()); + break; + } + + default: + break; + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPromoteHeapAccess_h + diff --git a/dfg/DFGPromotedHeapLocation.cpp b/dfg/DFGPromotedHeapLocation.cpp new file mode 100644 index 0000000..24f6977 --- /dev/null +++ b/dfg/DFGPromotedHeapLocation.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGPromotedHeapLocation.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +void PromotedLocationDescriptor::dump(PrintStream& out) const +{ + out.print(m_kind, "(", m_info, ")"); +} + +Node* PromotedHeapLocation::createHint(Graph& graph, NodeOrigin origin, Node* value) +{ + return graph.addNode( + SpecNone, PutHint, origin, OpInfo(descriptor().imm1()), OpInfo(descriptor().imm2()), + base()->defaultEdge(), value->defaultEdge()); +} + +void PromotedHeapLocation::dump(PrintStream& out) const +{ + out.print(kind(), "(", m_base, ", ", info(), ")"); +} + +} } // namespace JSC::DFG + +namespace WTF { + +using namespace JSC::DFG; + +void printInternal(PrintStream& out, PromotedLocationKind kind) +{ + switch (kind) { + case InvalidPromotedLocationKind: + out.print("InvalidPromotedLocationKind"); + return; + + case StructurePLoc: + out.print("StructurePLoc"); + return; + + case ActivationSymbolTablePLoc: + out.print("ActivationSymbolTablePLoc"); + return; + + case NamedPropertyPLoc: + out.print("NamedPropertyPLoc"); + return; + + case ArgumentPLoc: + out.print("ArgumentPLoc"); + return; + + case ArgumentCountPLoc: + out.print("ArgumentCountPLoc"); + return; + + case ArgumentsCalleePLoc: + out.print("ArgumentsCalleePLoc"); + return; + + case FunctionExecutablePLoc: + out.print("FunctionExecutablePLoc"); + return; + + case FunctionActivationPLoc: + out.print("FunctionActivationPLoc"); + return; + + case ActivationScopePLoc: + out.print("ActivationScopePLoc"); + return; + + case ClosureVarPLoc: + out.print("ClosureVarPLoc"); + return; + } + + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF; + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGPromotedHeapLocation.h b/dfg/DFGPromotedHeapLocation.h new file mode 100644 index 0000000..bc15158 --- /dev/null +++ b/dfg/DFGPromotedHeapLocation.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014, 2015 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 DFGPromotedHeapLocation_h +#define DFGPromotedHeapLocation_h + +#if ENABLE(DFG_JIT) + +#include "DFGNode.h" +#include <wtf/PrintStream.h> + +namespace JSC { namespace DFG { + +enum PromotedLocationKind { + InvalidPromotedLocationKind, + + StructurePLoc, + ActivationSymbolTablePLoc, + NamedPropertyPLoc, + ArgumentPLoc, + ArgumentCountPLoc, + ArgumentsCalleePLoc, + + FunctionExecutablePLoc, + FunctionActivationPLoc, + ActivationScopePLoc, + ClosureVarPLoc, +}; + +class PromotedLocationDescriptor { +public: + PromotedLocationDescriptor( + PromotedLocationKind kind = InvalidPromotedLocationKind, unsigned info = 0) + : m_kind(kind) + , m_info(info) + { + } + + bool operator!() const { return m_kind == InvalidPromotedLocationKind; } + + PromotedLocationKind kind() const { return m_kind; } + unsigned info() const { return m_info; } + + OpInfo imm1() const { return OpInfo(static_cast<uint32_t>(m_kind)); } + OpInfo imm2() const { return OpInfo(static_cast<uint32_t>(m_info)); } + + unsigned hash() const + { + return m_kind + m_info; + } + + bool operator==(const PromotedLocationDescriptor& other) const + { + return m_kind == other.m_kind + && m_info == other.m_info; + } + + bool operator!=(const PromotedLocationDescriptor& other) const + { + return !(*this == other); + } + + bool isHashTableDeletedValue() const + { + return m_kind == InvalidPromotedLocationKind && m_info; + } + + void dump(PrintStream& out) const; + +private: + PromotedLocationKind m_kind; + unsigned m_info; +}; + +class PromotedHeapLocation { +public: + PromotedHeapLocation( + PromotedLocationKind kind = InvalidPromotedLocationKind, + Node* base = nullptr, unsigned info = 0) + : m_base(base) + , m_meta(kind, info) + { + } + + PromotedHeapLocation( + PromotedLocationKind kind, Edge base, unsigned info = 0) + : PromotedHeapLocation(kind, base.node(), info) + { + } + + PromotedHeapLocation(Node* base, PromotedLocationDescriptor meta) + : m_base(base) + , m_meta(meta) + { + } + + PromotedHeapLocation(WTF::HashTableDeletedValueType) + : m_base(nullptr) + , m_meta(InvalidPromotedLocationKind, 1) + { + } + + Node* createHint(Graph&, NodeOrigin, Node* value); + + bool operator!() const { return kind() == InvalidPromotedLocationKind; } + + PromotedLocationKind kind() const { return m_meta.kind(); } + Node* base() const { return m_base; } + unsigned info() const { return m_meta.info(); } + PromotedLocationDescriptor descriptor() const { return m_meta; } + + unsigned hash() const + { + return m_meta.hash() + WTF::PtrHash<Node*>::hash(m_base); + } + + bool operator==(const PromotedHeapLocation& other) const + { + return m_base == other.m_base + && m_meta == other.m_meta; + } + + bool isHashTableDeletedValue() const + { + return m_meta.isHashTableDeletedValue(); + } + + void dump(PrintStream& out) const; + +private: + Node* m_base; + PromotedLocationDescriptor m_meta; +}; + +struct PromotedHeapLocationHash { + static unsigned hash(const PromotedHeapLocation& key) { return key.hash(); } + static bool equal(const PromotedHeapLocation& a, const PromotedHeapLocation& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} } // namespace JSC::DFG + +namespace WTF { + +void printInternal(PrintStream&, JSC::DFG::PromotedLocationKind); + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::DFG::PromotedHeapLocation> { + typedef JSC::DFG::PromotedHeapLocationHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::DFG::PromotedHeapLocation> : SimpleClassHashTraits<JSC::DFG::PromotedHeapLocation> { + static const bool emptyValueIsZero = false; +}; + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPromotedHeapLocation_h + diff --git a/dfg/DFGPureValue.cpp b/dfg/DFGPureValue.cpp new file mode 100644 index 0000000..4c9f60c --- /dev/null +++ b/dfg/DFGPureValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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 "DFGPureValue.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +void PureValue::dump(PrintStream& out) const +{ + out.print(Graph::opName(op())); + out.print("("); + CommaPrinter comma; + for (unsigned i = 0; i < AdjacencyList::Size; ++i) { + if (children().child(i)) + out.print(comma, children().child(i)); + } + if (m_info) + out.print(comma, m_info); + out.print(")"); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGPureValue.h b/dfg/DFGPureValue.h new file mode 100644 index 0000000..e7d6a3d --- /dev/null +++ b/dfg/DFGPureValue.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 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 DFGPureValue_h +#define DFGPureValue_h + +#if ENABLE(DFG_JIT) + +#include "DFGNode.h" + +namespace JSC { namespace DFG { + +class PureValue { +public: + PureValue() + : m_op(LastNodeType) + , m_info(0) + { + } + + PureValue(NodeType op, const AdjacencyList& children, uintptr_t info) + : m_op(op) + , m_children(children.sanitized()) + , m_info(info) + { + ASSERT(!(defaultFlags(op) & NodeHasVarArgs)); + } + + PureValue(NodeType op, const AdjacencyList& children, const void* ptr) + : PureValue(op, children, bitwise_cast<uintptr_t>(ptr)) + { + } + + PureValue(NodeType op, const AdjacencyList& children) + : PureValue(op, children, static_cast<uintptr_t>(0)) + { + } + + PureValue(Node* node, uintptr_t info) + : PureValue(node->op(), node->children, info) + { + } + + PureValue(Node* node, const void* ptr) + : PureValue(node->op(), node->children, ptr) + { + } + + PureValue(Node* node) + : PureValue(node->op(), node->children) + { + } + + PureValue(WTF::HashTableDeletedValueType) + : m_op(LastNodeType) + , m_info(1) + { + } + + bool operator!() const { return m_op == LastNodeType && !m_info; } + + NodeType op() const { return m_op; } + const AdjacencyList& children() const { return m_children; } + uintptr_t info() const { return m_info; } + + unsigned hash() const + { + return WTF::IntHash<int>::hash(static_cast<int>(m_op)) + m_children.hash() + m_info; + } + + bool operator==(const PureValue& other) const + { + return m_op == other.m_op + && m_children == other.m_children + && m_info == other.m_info; + } + + bool isHashTableDeletedValue() const + { + return m_op == LastNodeType && m_info; + } + + void dump(PrintStream& out) const; + +private: + NodeType m_op; + AdjacencyList m_children; + uintptr_t m_info; +}; + +struct PureValueHash { + static unsigned hash(const PureValue& key) { return key.hash(); } + static bool equal(const PureValue& a, const PureValue& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} } // namespace JSC::DFG + +namespace WTF { + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::DFG::PureValue> { + typedef JSC::DFG::PureValueHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::DFG::PureValue> : SimpleClassHashTraits<JSC::DFG::PureValue> { + static const bool emptyValueIsZero = false; +}; + +} // namespace WTF + +namespace JSC { namespace DFG { + +typedef HashMap<PureValue, Node*> PureMap; +typedef HashMap<PureValue, Vector<Node*>> PureMultiMap; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPureValue_h + diff --git a/dfg/DFGPutStackSinkingPhase.cpp b/dfg/DFGPutStackSinkingPhase.cpp new file mode 100644 index 0000000..06bd4e2 --- /dev/null +++ b/dfg/DFGPutStackSinkingPhase.cpp @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGPutStackSinkingPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGBlockMapInlines.h" +#include "DFGGraph.h" +#include "DFGInsertionSet.h" +#include "DFGPhase.h" +#include "DFGPreciseLocalClobberize.h" +#include "DFGSSACalculator.h" +#include "DFGValidate.h" +#include "JSCInlines.h" +#include "OperandsInlines.h" + +namespace JSC { namespace DFG { + +namespace { + +bool verbose = false; + +class PutStackSinkingPhase : public Phase { +public: + PutStackSinkingPhase(Graph& graph) + : Phase(graph, "PutStack sinking") + { + } + + bool run() + { + // FIXME: One of the problems of this approach is that it will create a duplicate Phi graph + // for sunken PutStacks in the presence of interesting control flow merges, and where the + // value being PutStack'd is also otherwise live in the DFG code. We could work around this + // by doing the sinking over CPS, or maybe just by doing really smart hoisting. It's also + // possible that the duplicate Phi graph can be deduplicated by LLVM. It would be best if we + // could observe that there is already a Phi graph in place that does what we want. In + // principle if we have a request to place a Phi at a particular place, we could just check + // if there is already a Phi that does what we want. Because PutStackSinkingPhase runs just + // after SSA conversion, we have almost a guarantee that the Phi graph we produce here would + // be trivially redundant to the one we already have. + + // FIXME: This phase doesn't adequately use KillStacks. KillStack can be viewed as a def. + // This is mostly inconsequential; it would be a bug to have a local live at a KillStack. + // More important is that KillStack should swallow any deferral. After a KillStack, the + // local should behave like a TOP deferral because it would be invalid for anyone to trust + // the stack. It's not clear to me if this is important or not. + // https://bugs.webkit.org/show_bug.cgi?id=145296 + + if (verbose) { + dataLog("Graph before PutStack sinking:\n"); + m_graph.dump(); + } + + SSACalculator ssaCalculator(m_graph); + InsertionSet insertionSet(m_graph); + + // First figure out where various locals are live. + BlockMap<Operands<bool>> liveAtHead(m_graph); + BlockMap<Operands<bool>> liveAtTail(m_graph); + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + liveAtHead[block] = Operands<bool>(OperandsLike, block->variablesAtHead); + liveAtTail[block] = Operands<bool>(OperandsLike, block->variablesAtHead); + + liveAtHead[block].fill(false); + liveAtTail[block].fill(false); + } + + bool changed; + do { + changed = false; + + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + Operands<bool> live = liveAtTail[block]; + for (unsigned nodeIndex = block->size(); nodeIndex--;) { + Node* node = block->at(nodeIndex); + if (verbose) + dataLog("Live at ", node, ": ", live, "\n"); + + auto escapeHandler = [&] (VirtualRegister operand) { + if (operand.isHeader()) + return; + if (verbose) + dataLog(" ", operand, " is live at ", node, "\n"); + live.operand(operand) = true; + }; + + // FIXME: This might mishandle LoadVarargs and ForwardVarargs. It might make us + // think that the locals being written are stack-live here. They aren't. This + // should be harmless since we overwrite them anyway, but still, it's sloppy. + // https://bugs.webkit.org/show_bug.cgi?id=145295 + preciseLocalClobberize( + m_graph, node, escapeHandler, escapeHandler, + [&] (VirtualRegister operand, LazyNode source) { + RELEASE_ASSERT(source.isNode()); + + if (source.asNode() == node) { + // This is a load. Ignore it. + return; + } + + RELEASE_ASSERT(node->op() == PutStack); + live.operand(operand) = false; + }); + } + + if (live == liveAtHead[block]) + continue; + + liveAtHead[block] = live; + changed = true; + + for (BasicBlock* predecessor : block->predecessors) { + for (size_t i = live.size(); i--;) + liveAtTail[predecessor][i] |= live[i]; + } + } + + } while (changed); + + // All of the arguments should be live at head of root. Note that we may find that some + // locals are live at head of root. This seems wrong but isn't. This will happen for example + // if the function accesses closure variable #42 for some other function and we either don't + // have variable #42 at all or we haven't set it at root, for whatever reason. Basically this + // arises since our aliasing for closure variables is conservatively based on variable number + // and ignores the owning symbol table. We should probably fix this eventually and make our + // aliasing more precise. + // + // For our purposes here, the imprecision in the aliasing is harmless. It just means that we + // may not do as much Phi pruning as we wanted. + for (size_t i = liveAtHead.atIndex(0).numberOfArguments(); i--;) + DFG_ASSERT(m_graph, nullptr, liveAtHead.atIndex(0).argument(i)); + + // Next identify where we would want to sink PutStacks to. We say that there is a deferred + // flush if we had a PutStack with a given FlushFormat but it hasn't been materialized yet. + // Deferrals have the following lattice; but it's worth noting that the TOP part of the + // lattice serves an entirely different purpose than the rest of the lattice: it just means + // that we're in a region of code where nobody should have been relying on the value. The + // rest of the lattice means that we either have a PutStack that is deferred (i.e. still + // needs to be executed) or there isn't one (because we've alraedy executed it). + // + // Bottom: + // Represented as DeadFlush. + // Means that all previous PutStacks have been executed so there is nothing deferred. + // During merging this is subordinate to the other kinds of deferrals, because it + // represents the fact that we've already executed all necessary PutStacks. This implies + // that there *had* been some PutStacks that we should have executed. + // + // Top: + // Represented as ConflictingFlush. + // Represents the fact that we know, via forward flow, that there isn't any value in the + // given local that anyone should have been relying on. This comes into play at the + // prologue (because in SSA form at the prologue no local has any value) or when we merge + // deferrals for different formats's. A lexical scope in which a local had some semantic + // meaning will by this point share the same format; if we had stores from different + // lexical scopes that got merged together then we may have a conflicting format. Hence + // a conflicting format proves that we're no longer in an area in which the variable was + // in scope. Note that this is all approximate and only precise enough to later answer + // questions pertinent to sinking. For example, this doesn't always detect when a local + // is no longer semantically relevant - we may well have a deferral from inside some + // inlined call survive outside of that inlined code, and this is generally OK. In the + // worst case it means that we might think that a deferral that is actually dead must + // still be executed. But we usually catch that with liveness. Liveness usually catches + // such cases, but that's not guaranteed since liveness is conservative. + // + // What Top does give us is detects situations where we both don't need to care about a + // deferral and there is no way that we could reason about it anyway. If we merged + // deferrals for different formats then we wouldn't know the format to use. So, we use + // Top in that case because that's also a case where we know that we can ignore the + // deferral. + // + // Deferral with a concrete format: + // Represented by format values other than DeadFlush or ConflictingFlush. + // Represents the fact that the original code would have done a PutStack but we haven't + // identified an operation that would have observed that PutStack. + // + // This code has some interesting quirks because of the fact that neither liveness nor + // deferrals are very precise. They are only precise enough to be able to correctly tell us + // when we may [sic] need to execute PutStacks. This means that they may report the need to + // execute a PutStack in cases where we actually don't really need it, and that's totally OK. + BlockMap<Operands<FlushFormat>> deferredAtHead(m_graph); + BlockMap<Operands<FlushFormat>> deferredAtTail(m_graph); + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + deferredAtHead[block] = + Operands<FlushFormat>(OperandsLike, block->variablesAtHead); + deferredAtTail[block] = + Operands<FlushFormat>(OperandsLike, block->variablesAtHead); + } + + deferredAtHead.atIndex(0).fill(ConflictingFlush); + + do { + changed = false; + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + Operands<FlushFormat> deferred = deferredAtHead[block]; + + for (Node* node : *block) { + if (verbose) + dataLog("Deferred at ", node, ":", deferred, "\n"); + + if (node->op() == GetStack) { + // A GetStack doesn't affect anything, since we know which local we are reading + // from. + continue; + } + + auto escapeHandler = [&] (VirtualRegister operand) { + if (operand.isHeader()) + return; + // We will materialize just before any reads. + deferred.operand(operand) = DeadFlush; + }; + + preciseLocalClobberize( + m_graph, node, escapeHandler, escapeHandler, + [&] (VirtualRegister operand, LazyNode source) { + RELEASE_ASSERT(source.isNode()); + + if (source.asNode() == node) { + // This is a load. Ignore it. + return; + } + + deferred.operand(operand) = node->stackAccessData()->format; + }); + } + + if (deferred == deferredAtTail[block]) + continue; + + deferredAtTail[block] = deferred; + changed = true; + + for (BasicBlock* successor : block->successors()) { + for (size_t i = deferred.size(); i--;) { + if (verbose) + dataLog("Considering ", VirtualRegister(deferred.operandForIndex(i)), " at ", pointerDump(block), "->", pointerDump(successor), ": ", deferred[i], " and ", deferredAtHead[successor][i], " merges to "); + + deferredAtHead[successor][i] = + merge(deferredAtHead[successor][i], deferred[i]); + + if (verbose) + dataLog(deferredAtHead[successor][i], "\n"); + } + } + } + + } while (changed); + + // We wish to insert PutStacks at all of the materialization points, which are defined + // implicitly as the places where we set deferred to Dead while it was previously not Dead. + // To do this, we may need to build some Phi functions to handle stuff like this: + // + // Before: + // + // if (p) + // PutStack(r42, @x) + // else + // PutStack(r42, @y) + // + // After: + // + // if (p) + // Upsilon(@x, ^z) + // else + // Upsilon(@y, ^z) + // z: Phi() + // PutStack(r42, @z) + // + // This means that we have an SSACalculator::Variable for each local, and a Def is any + // PutStack in the original program. The original PutStacks will simply vanish. + + Operands<SSACalculator::Variable*> operandToVariable( + OperandsLike, m_graph.block(0)->variablesAtHead); + Vector<VirtualRegister> indexToOperand; + for (size_t i = m_graph.block(0)->variablesAtHead.size(); i--;) { + VirtualRegister operand(m_graph.block(0)->variablesAtHead.operandForIndex(i)); + + SSACalculator::Variable* variable = ssaCalculator.newVariable(); + operandToVariable.operand(operand) = variable; + ASSERT(indexToOperand.size() == variable->index()); + indexToOperand.append(operand); + } + + HashSet<Node*> putLocalsToSink; + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (Node* node : *block) { + switch (node->op()) { + case PutStack: + putLocalsToSink.add(node); + ssaCalculator.newDef( + operandToVariable.operand(node->stackAccessData()->local), + block, node->child1().node()); + break; + case GetStack: + ssaCalculator.newDef( + operandToVariable.operand(node->stackAccessData()->local), + block, node); + break; + default: + break; + } + } + } + + ssaCalculator.computePhis( + [&] (SSACalculator::Variable* variable, BasicBlock* block) -> Node* { + VirtualRegister operand = indexToOperand[variable->index()]; + + if (!liveAtHead[block].operand(operand)) + return nullptr; + + FlushFormat format = deferredAtHead[block].operand(operand); + + // We could have an invalid deferral because liveness is imprecise. + if (!isConcrete(format)) + return nullptr; + + if (verbose) + dataLog("Adding Phi for ", operand, " at ", pointerDump(block), "\n"); + + Node* phiNode = m_graph.addNode(SpecHeapTop, Phi, NodeOrigin()); + phiNode->mergeFlags(resultFor(format)); + return phiNode; + }); + + Operands<Node*> mapping(OperandsLike, m_graph.block(0)->variablesAtHead); + Operands<FlushFormat> deferred; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + mapping.fill(nullptr); + + for (size_t i = mapping.size(); i--;) { + VirtualRegister operand(mapping.operandForIndex(i)); + + SSACalculator::Variable* variable = operandToVariable.operand(operand); + SSACalculator::Def* def = ssaCalculator.reachingDefAtHead(block, variable); + if (!def) + continue; + + mapping.operand(operand) = def->value(); + } + + if (verbose) + dataLog("Mapping at top of ", pointerDump(block), ": ", mapping, "\n"); + + for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(block)) { + VirtualRegister operand = indexToOperand[phiDef->variable()->index()]; + + insertionSet.insert(0, phiDef->value()); + + if (verbose) + dataLog(" Mapping ", operand, " to ", phiDef->value(), "\n"); + mapping.operand(operand) = phiDef->value(); + } + + deferred = deferredAtHead[block]; + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (verbose) + dataLog("Deferred at ", node, ":", deferred, "\n"); + + switch (node->op()) { + case PutStack: { + StackAccessData* data = node->stackAccessData(); + VirtualRegister operand = data->local; + deferred.operand(operand) = data->format; + if (verbose) + dataLog(" Mapping ", operand, " to ", node->child1().node(), " at ", node, "\n"); + mapping.operand(operand) = node->child1().node(); + break; + } + + case GetStack: { + StackAccessData* data = node->stackAccessData(); + FlushFormat format = deferred.operand(data->local); + if (!isConcrete(format)) { + // This means there is no deferral. No deferral means that the most + // authoritative value for this stack slot is what is stored in the stack. So, + // keep the GetStack. + mapping.operand(data->local) = node; + break; + } + + // We have a concrete deferral, which means a PutStack that hasn't executed yet. It + // would have stored a value with a certain format. That format must match our + // format. But more importantly, we can simply use the value that the PutStack would + // have stored and get rid of the GetStack. + DFG_ASSERT(m_graph, node, format == data->format); + + Node* incoming = mapping.operand(data->local); + node->child1() = incoming->defaultEdge(); + node->convertToIdentity(); + break; + } + + default: { + auto escapeHandler = [&] (VirtualRegister operand) { + if (operand.isHeader()) + return; + + FlushFormat format = deferred.operand(operand); + if (!isConcrete(format)) + return; + + // Gotta insert a PutStack. + if (verbose) + dataLog("Inserting a PutStack for ", operand, " at ", node, "\n"); + + Node* incoming = mapping.operand(operand); + DFG_ASSERT(m_graph, node, incoming); + + insertionSet.insertNode( + nodeIndex, SpecNone, PutStack, node->origin, + OpInfo(m_graph.m_stackAccessData.add(operand, format)), + Edge(incoming, useKindFor(format))); + + deferred.operand(operand) = DeadFlush; + }; + + preciseLocalClobberize( + m_graph, node, escapeHandler, escapeHandler, + [&] (VirtualRegister, LazyNode) { }); + break; + } } + } + + NodeAndIndex terminal = block->findTerminal(); + size_t upsilonInsertionPoint = terminal.index; + NodeOrigin upsilonOrigin = terminal.node->origin; + for (BasicBlock* successorBlock : block->successors()) { + for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(successorBlock)) { + Node* phiNode = phiDef->value(); + SSACalculator::Variable* variable = phiDef->variable(); + VirtualRegister operand = indexToOperand[variable->index()]; + if (verbose) + dataLog("Creating Upsilon for ", operand, " at ", pointerDump(block), "->", pointerDump(successorBlock), "\n"); + FlushFormat format = deferredAtHead[successorBlock].operand(operand); + DFG_ASSERT(m_graph, nullptr, isConcrete(format)); + UseKind useKind = useKindFor(format); + + // We need to get a value for the stack slot. This phase doesn't really have a + // good way of determining if a stack location got clobbered. It just knows if + // there is a deferral. The lack of a deferral might mean that a PutStack or + // GetStack had never happened, or it might mean that the value was read, or + // that it was written. It's OK for us to make some bad decisions here, since + // GCSE will clean it up anyway. + Node* incoming; + if (isConcrete(deferred.operand(operand))) { + incoming = mapping.operand(operand); + DFG_ASSERT(m_graph, phiNode, incoming); + } else { + // Issue a GetStack to get the value. This might introduce some redundancy + // into the code, but if it's bad enough, GCSE will clean it up. + incoming = insertionSet.insertNode( + upsilonInsertionPoint, SpecNone, GetStack, upsilonOrigin, + OpInfo(m_graph.m_stackAccessData.add(operand, format))); + incoming->setResult(resultFor(format)); + } + + insertionSet.insertNode( + upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin, + OpInfo(phiNode), Edge(incoming, useKind)); + } + } + + insertionSet.execute(block); + } + + // Finally eliminate the sunken PutStacks by turning them into Checks. This keeps whatever + // type check they were doing. Also prepend KillStacks to them to ensure that we know that + // the relevant value was *not* stored to the stack. + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + + if (!putLocalsToSink.contains(node)) + continue; + + insertionSet.insertNode( + nodeIndex, SpecNone, KillStack, node->origin, OpInfo(node->stackAccessData()->local.offset())); + node->remove(); + } + + insertionSet.execute(block); + } + + if (verbose) { + dataLog("Graph after PutStack sinking:\n"); + m_graph.dump(); + } + + return true; + } +}; + +} // anonymous namespace + +bool performPutStackSinking(Graph& graph) +{ + SamplingRegion samplingRegion("DFG PutStack Sinking Phase"); + return runPhase<PutStackSinkingPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGPutStackSinkingPhase.h b/dfg/DFGPutStackSinkingPhase.h new file mode 100644 index 0000000..24bbb81 --- /dev/null +++ b/dfg/DFGPutStackSinkingPhase.h @@ -0,0 +1,46 @@ + /* + * Copyright (C) 2014, 2015 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 DFGPutStackSinkingPhase_h +#define DFGPutStackSinkingPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Sinks PutStacks to the absolute latest point where they can possibly happen, which is usually +// side-effects that may observe them. This eliminates PutStacks if it sinks them past the point of +// their deaths. + +bool performPutStackSinking(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGPutStackSinkingPhase_h + diff --git a/dfg/DFGSSACalculator.cpp b/dfg/DFGSSACalculator.cpp new file mode 100644 index 0000000..263cd2a --- /dev/null +++ b/dfg/DFGSSACalculator.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2014 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 "DFGSSACalculator.h" + +#if ENABLE(DFG_JIT) + +#include "DFGBlockMapInlines.h" +#include <wtf/CommaPrinter.h> +#include <wtf/ListDump.h> + +namespace JSC { namespace DFG { + +void SSACalculator::Variable::dump(PrintStream& out) const +{ + out.print("var", m_index); +} + +void SSACalculator::Variable::dumpVerbose(PrintStream& out) const +{ + dump(out); + if (!m_blocksWithDefs.isEmpty()) { + out.print("(defs: "); + CommaPrinter comma; + for (BasicBlock* block : m_blocksWithDefs) + out.print(comma, *block); + out.print(")"); + } +} + +void SSACalculator::Def::dump(PrintStream& out) const +{ + out.print("def(", *m_variable, ", ", *m_block, ", ", m_value, ")"); +} + +SSACalculator::SSACalculator(Graph& graph) + : m_data(graph) + , m_graph(graph) +{ +} + +SSACalculator::~SSACalculator() +{ +} + +void SSACalculator::reset() +{ + m_variables.clear(); + m_defs.clear(); + m_phis.clear(); + for (BlockIndex blockIndex = m_data.size(); blockIndex--;) { + m_data[blockIndex].m_defs.clear(); + m_data[blockIndex].m_phis.clear(); + } +} + +SSACalculator::Variable* SSACalculator::newVariable() +{ + return &m_variables.alloc(Variable(m_variables.size())); +} + +SSACalculator::Def* SSACalculator::newDef(Variable* variable, BasicBlock* block, Node* value) +{ + Def* def = m_defs.add(Def(variable, block, value)); + auto result = m_data[block].m_defs.add(variable, def); + if (result.isNewEntry) + variable->m_blocksWithDefs.append(block); + else + result.iterator->value = def; + return def; +} + +SSACalculator::Def* SSACalculator::nonLocalReachingDef(BasicBlock* block, Variable* variable) +{ + return reachingDefAtTail(m_graph.m_dominators.immediateDominatorOf(block), variable); +} + +SSACalculator::Def* SSACalculator::reachingDefAtTail(BasicBlock* block, Variable* variable) +{ + for (; block; block = m_graph.m_dominators.immediateDominatorOf(block)) { + if (Def* def = m_data[block].m_defs.get(variable)) + return def; + } + return nullptr; +} + +void SSACalculator::dump(PrintStream& out) const +{ + out.print("<Variables: ["); + CommaPrinter comma; + for (unsigned i = 0; i < m_variables.size(); ++i) { + out.print(comma); + m_variables[i].dumpVerbose(out); + } + out.print("], Defs: ["); + comma = CommaPrinter(); + for (Def* def : const_cast<SSACalculator*>(this)->m_defs) + out.print(comma, *def); + out.print("], Phis: ["); + comma = CommaPrinter(); + for (Def* def : const_cast<SSACalculator*>(this)->m_phis) + out.print(comma, *def); + out.print("], Block data: ["); + comma = CommaPrinter(); + for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + out.print(comma, *block, "=>("); + out.print("Defs: {"); + CommaPrinter innerComma; + for (auto entry : m_data[block].m_defs) + out.print(innerComma, *entry.key, "->", *entry.value); + out.print("}, Phis: {"); + innerComma = CommaPrinter(); + for (Def* def : m_data[block].m_phis) + out.print(innerComma, *def); + out.print("})"); + } + out.print("]>"); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGSSACalculator.h b/dfg/DFGSSACalculator.h new file mode 100644 index 0000000..4f4f865 --- /dev/null +++ b/dfg/DFGSSACalculator.h @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2014 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 DFGSSACalculator_h +#define DFGSSACalculator_h + +#if ENABLE(DFG_JIT) + +#include "DFGDominators.h" +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +// SSACalculator provides a reusable tool for using the Cytron, Ferrante, Rosen, Wegman, and +// Zadeck "Efficiently Computing Static Single Assignment Form and the Control Dependence Graph" +// (TOPLAS'91) algorithm for computing SSA. SSACalculator doesn't magically do everything for you +// but it maintains the major data structures and handles most of the non-local reasoning. Here's +// the workflow of using SSACalculator to execute this algorithm: +// +// 0) Create a fresh SSACalculator instance. You will need this instance only for as long as +// you're not yet done computing SSA. +// +// 1) Create an SSACalculator::Variable for every variable that you want to do Phi insertion +// on. SSACalculator::Variable::index() is a dense indexing of the Variables that you +// created, so you can easily use a Vector to map the SSACalculator::Variables to your +// variables. +// +// 2) Create a SSACalculator::Def for every assignment to those variables. A Def knows about the +// variable, the block, and the DFG::Node* that has the value being put into the variable. +// Note that creating a Def in block B for variable V if block B already has a def for variable +// V will overwrite the previous Def's DFG::Node* value. This enables you to create Defs by +// processing basic blocks in forward order. If a block has multiple Defs of a variable, this +// "just works" because each block will then remember the last Def of each variable. +// +// 3) Call SSACalculator::computePhis(). This takes a functor that will create the Phi nodes. The +// functor returns either the Phi node it created, or nullptr, if it chooses to prune. (As an +// aside, it's always sound not to prune, and the safest reason for pruning is liveness.) The +// computePhis() code will record the created Phi nodes as Defs, and it will separately record +// the list of Phis inserted at each block. It's OK for the functor you pass here to modify the +// DFG::Graph on the fly, but the easiest way to write this is to just create the Phi nodes by +// doing Graph::addNode() and return them. It's then best to insert all Phi nodes for a block +// in bulk as part of the pass you do below, in step (4). +// +// 4) Modify the graph to create the SSA data flow. For each block, this should: +// +// 4.0) Compute the set of reaching defs (aka available values) for each variable by calling +// SSACalculator::reachingDefAtHead() for each variable. Record this in a local table that +// will be incrementally updated as you proceed through the block in forward order in the +// next steps: +// +// FIXME: It might be better to compute reaching defs for all live variables in one go, to +// avoid doing repeated dom tree traversals. +// https://bugs.webkit.org/show_bug.cgi?id=136610 +// +// 4.1) Insert all of the Phi nodes for the block by using SSACalculator::phisForBlock(), and +// record those Phi nodes as being available values. +// +// 4.2) Process the block in forward order. For each load from a variable, replace it with the +// available SSA value for that variable. For each store, delete it and record the stored +// value as being available. +// +// Note that you have two options of how to replace loads with SSA values. You can replace +// the load with an Identity node; this will end up working fairly naturally so long as +// you run GCSE after your phase. Or, you can replace all uses of the load with the SSA +// value yourself (using the Graph::performSubstitution() idiom), but that requires that +// your loop over basic blocks proceeds in the appropriate graph order, for example +// preorder. +// +// FIXME: Make it easier to do this, that doesn't involve rerunning GCSE. +// https://bugs.webkit.org/show_bug.cgi?id=136639 +// +// 4.3) Insert Upsilons for each Phi in each successor block. Use the available values table to +// decide the source value for each Phi's variable. Note that you could also use +// SSACalculator::reachingDefAtTail() instead of the available values table, though your +// local available values table is likely to be more efficient. +// +// The most obvious use of SSACalculator is for the CPS->SSA conversion itself, but it's meant to +// also be used for SSA update and for things like the promotion of heap fields to local SSA +// variables. + +class SSACalculator { +public: + SSACalculator(Graph&); + ~SSACalculator(); + + void reset(); + + class Variable { + public: + unsigned index() const { return m_index; } + + void dump(PrintStream&) const; + void dumpVerbose(PrintStream&) const; + + private: + friend class SSACalculator; + + Variable() + : m_index(UINT_MAX) + { + } + + Variable(unsigned index) + : m_index(index) + { + } + + BlockList m_blocksWithDefs; + unsigned m_index; + }; + + class Def { + public: + Variable* variable() const { return m_variable; } + BasicBlock* block() const { return m_block; } + + Node* value() const { return m_value; } + + void dump(PrintStream&) const; + + private: + friend class SSACalculator; + + Def() + : m_variable(nullptr) + , m_block(nullptr) + , m_value(nullptr) + { + } + + Def(Variable* variable, BasicBlock* block, Node* value) + : m_variable(variable) + , m_block(block) + , m_value(value) + { + } + + Variable* m_variable; + BasicBlock* m_block; + Node* m_value; + }; + + Variable* newVariable(); + Def* newDef(Variable*, BasicBlock*, Node*); + + Variable* variable(unsigned index) { return &m_variables[index]; } + + // The PhiInsertionFunctor takes a Variable and a BasicBlock and either inserts a Phi and + // returns the Node for that Phi, or it decides that it's not worth it to insert a Phi at that + // block because of some additional pruning condition (typically liveness) and returns + // nullptr. If a non-null Node* is returned, a new Def is created, so that + // nonLocalReachingDef() will find it later. Note that it is generally always sound to not + // prune any Phis (that is, to always have the functor insert a Phi and never return nullptr). + template<typename PhiInsertionFunctor> + void computePhis(const PhiInsertionFunctor& functor) + { + DFG_ASSERT(m_graph, nullptr, m_graph.m_dominators.isValid()); + + for (Variable& variable : m_variables) { + m_graph.m_dominators.forAllBlocksInPrunedIteratedDominanceFrontierOf( + variable.m_blocksWithDefs, + [&] (BasicBlock* block) -> bool { + Node* phiNode = functor(&variable, block); + if (!phiNode) + return false; + + BlockData& data = m_data[block]; + Def* phiDef = m_phis.add(Def(&variable, block, phiNode)); + data.m_phis.append(phiDef); + + // Note that it's possible to have a block that looks like this before SSA + // conversion: + // + // label: + // print(x); + // ... + // x = 42; + // goto label; + // + // And it may look like this after SSA conversion: + // + // label: + // x1: Phi() + // ... + // Upsilon(42, ^x1) + // goto label; + // + // In this case, we will want to insert a Phi in this block, and the block + // will already have a Def for the variable. When this happens, we don't want + // the Phi to override the original Def, since the Phi is at the top, the + // original Def in the m_defs table would have been at the bottom, and we want + // m_defs to tell us about defs at tail. + // + // So, we rely on the fact that HashMap::add() does nothing if the key was + // already present. + data.m_defs.add(&variable, phiDef); + return true; + }); + } + } + + const Vector<Def*>& phisForBlock(BasicBlock* block) + { + return m_data[block].m_phis; + } + + // Ignores defs within the given block; it assumes that you've taken care of those + // yourself. + Def* nonLocalReachingDef(BasicBlock*, Variable*); + Def* reachingDefAtHead(BasicBlock* block, Variable* variable) + { + return nonLocalReachingDef(block, variable); + } + + // Considers the def within the given block, but only works at the tail of the block. + Def* reachingDefAtTail(BasicBlock*, Variable*); + + void dump(PrintStream&) const; + +private: + SegmentedVector<Variable> m_variables; + Bag<Def> m_defs; + + Bag<Def> m_phis; + + struct BlockData { + HashMap<Variable*, Def*> m_defs; + Vector<Def*> m_phis; + }; + + BlockMap<BlockData> m_data; + + Graph& m_graph; +}; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGSSACalculator_h + diff --git a/dfg/DFGSSAConversionPhase.cpp b/dfg/DFGSSAConversionPhase.cpp index e194ea8..6993bfc 100644 --- a/dfg/DFGSSAConversionPhase.cpp +++ b/dfg/DFGSSAConversionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,19 +32,20 @@ #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" +#include "DFGSSACalculator.h" +#include "DFGVariableAccessDataDump.h" #include "JSCInlines.h" namespace JSC { namespace DFG { class SSAConversionPhase : public Phase { static const bool verbose = false; - static const bool dumpGraph = false; public: SSAConversionPhase(Graph& graph) : Phase(graph, "SSA conversion") + , m_calculator(graph) , m_insertionSet(graph) - , m_changed(false) { } @@ -52,338 +53,310 @@ public: { RELEASE_ASSERT(m_graph.m_form == ThreadedCPS); - if (dumpGraph) { - dataLog("Graph dump at top of SSA conversion:\n"); + m_graph.clearReplacements(); + m_graph.m_dominators.computeIfNecessary(m_graph); + + if (verbose) { + dataLog("Graph before SSA transformation:\n"); m_graph.dump(); } + + // Create a SSACalculator::Variable for every root VariableAccessData. + for (VariableAccessData& variable : m_graph.m_variableAccessData) { + if (!variable.isRoot()) + continue; + + SSACalculator::Variable* ssaVariable = m_calculator.newVariable(); + ASSERT(ssaVariable->index() == m_variableForSSAIndex.size()); + m_variableForSSAIndex.append(&variable); + m_ssaVariableForVariable.add(&variable, ssaVariable); + } - // Eliminate all duplicate or self-pointing Phi edges. This means that - // we transform: - // - // p: Phi(@n1, @n2, @n3) - // - // into: - // - // p: Phi(@x) - // - // if each @ni in {@n1, @n2, @n3} is either equal to @p to is equal - // to @x, for exactly one other @x. Additionally, trivial Phis (i.e. - // p: Phi(@x)) are forwarded, so that if have an edge to such @p, we - // replace it with @x. This loop does this for Phis only; later we do - // such forwarding for Phi references found in other nodes. - // - // See Aycock and Horspool in CC'00 for a better description of what - // we're doing here. - do { - m_changed = false; - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned phiIndex = block->phis.size(); phiIndex--;) { - Node* phi = block->phis[phiIndex]; - if (phi->variableAccessData()->isCaptured()) - continue; - forwardPhiChildren(phi); - deduplicateChildren(phi); - } - } - } while (m_changed); - - // For each basic block, for each local live at the head of that block, - // figure out what node we should be referring to instead of that local. - // If it turns out to be a non-trivial Phi, make sure that we create an - // SSA Phi and Upsilons in predecessor blocks. We reuse - // BasicBlock::variablesAtHead for tracking which nodes to refer to. - Operands<bool> nonTrivialPhis(OperandsLike, m_graph.block(0)->variablesAtHead); + // Find all SetLocals and create Defs for them. We handle SetArgument by creating a + // GetLocal, and recording the flush format. for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; - - nonTrivialPhis.fill(false); - for (unsigned i = block->phis.size(); i--;) { - Node* phi = block->phis[i]; - if (!phi->children.justOneChild()) - nonTrivialPhis.operand(phi->local()) = true; - } - - for (unsigned i = block->variablesAtHead.size(); i--;) { - Node* node = block->variablesAtHead[i]; - if (!node) + + // Must process the block in forward direction because we want to see the last + // assignment for every local. + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (node->op() != SetLocal && node->op() != SetArgument) continue; - if (verbose) - dataLog("At block #", blockIndex, " for operand r", block->variablesAtHead.operandForIndex(i), " have node ", node, "\n"); - VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) { - // Poison this entry in variablesAtHead because we don't - // want anyone to try to refer to it, if the variable is - // captured. - block->variablesAtHead[i] = 0; - continue; - } - - switch (node->op()) { - case Phi: - case SetArgument: - break; - case Flush: - case GetLocal: - case PhantomLocal: - node = node->child1().node(); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - RELEASE_ASSERT(node->op() == Phi || node->op() == SetArgument); - - bool isFlushed = !!(node->flags() & NodeIsFlushed); - if (node->op() == Phi) { - if (!nonTrivialPhis.operand(node->local())) { - Edge edge = node->children.justOneChild(); - ASSERT(edge); - if (verbose) - dataLog(" One child: ", edge, ", ", RawPointer(edge.node()), "\n"); - node = edge.node(); // It's something from a different basic block. - } else { - if (verbose) - dataLog(" Non-trivial.\n"); - // It's a non-trivial Phi. - FlushFormat format = variable->flushFormat(); - NodeFlags result = resultFor(format); - UseKind useKind = useKindFor(format); - - node = m_insertionSet.insertNode(0, SpecNone, Phi, NodeOrigin()); - if (verbose) - dataLog(" Inserted new node: ", node, "\n"); - node->mergeFlags(result); - RELEASE_ASSERT((node->flags() & NodeResultMask) == result); - - for (unsigned j = block->predecessors.size(); j--;) { - BasicBlock* predecessor = block->predecessors[j]; - predecessor->appendNonTerminal( - m_graph, SpecNone, Upsilon, predecessor->last()->origin, - OpInfo(node), Edge(predecessor->variablesAtTail[i], useKind)); - } - - if (isFlushed) { - // Do nothing. For multiple reasons. - - // Reason #1: If the local is flushed then we don't need to bother - // with a MovHint since every path to this point in the code will - // have flushed the bytecode variable using a SetLocal and hence - // the Availability::flushedAt() will agree, and that will be - // sufficient for figuring out how to recover the variable's value. - - // Reason #2: If we had inserted a MovHint and the Phi function had - // died (because the only user of the value was the "flush" - i.e. - // some asynchronous runtime thingy) then the MovHint would turn - // into a ZombieHint, which would fool us into thinking that the - // variable is dead. - - // Reason #3: If we had inserted a MovHint then even if the Phi - // stayed alive, we would still end up generating inefficient code - // since we would be telling the OSR exit compiler to use some SSA - // value for the bytecode variable rather than just telling it that - // the value was already on the stack. - } else { - m_insertionSet.insertNode( - 0, SpecNone, MovHint, NodeOrigin(), - OpInfo(variable->local().offset()), node->defaultEdge()); - } - } + Node* childNode; + if (node->op() == SetLocal) + childNode = node->child1().node(); + else { + ASSERT(node->op() == SetArgument); + childNode = m_insertionSet.insertNode( + nodeIndex, node->variableAccessData()->prediction(), + GetStack, node->origin, + OpInfo(m_graph.m_stackAccessData.add(variable->local(), variable->flushFormat()))); + if (!ASSERT_DISABLED) + m_argumentGetters.add(childNode); + m_argumentMapping.add(node, childNode); } - block->variablesAtHead[i] = node; + m_calculator.newDef( + m_ssaVariableForVariable.get(variable), block, childNode); } - + m_insertionSet.execute(block); } + // Decide where Phis are to be inserted. This creates the Phi's but doesn't insert them + // yet. We will later know where to insert them because SSACalculator is such a bro. + m_calculator.computePhis( + [&] (SSACalculator::Variable* ssaVariable, BasicBlock* block) -> Node* { + VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()]; + + // Prune by liveness. This doesn't buy us much other than compile times. + Node* headNode = block->variablesAtHead.operand(variable->local()); + if (!headNode) + return nullptr; + + // There is the possibiltiy of "rebirths". The SSA calculator will already prune + // rebirths for the same VariableAccessData. But it will not be able to prune + // rebirths that arose from the same local variable number but a different + // VariableAccessData. We do that pruning here. + // + // Here's an example of a rebirth that this would catch: + // + // var x; + // if (foo) { + // if (bar) { + // x = 42; + // } else { + // x = 43; + // } + // print(x); + // x = 44; + // } else { + // x = 45; + // } + // print(x); // Without this check, we'd have a Phi for x = 42|43 here. + // + // FIXME: Consider feeding local variable numbers, not VariableAccessData*'s, as + // the "variables" for SSACalculator. That would allow us to eliminate this + // special case. + // https://bugs.webkit.org/show_bug.cgi?id=136641 + if (headNode->variableAccessData() != variable) + return nullptr; + + Node* phiNode = m_graph.addNode( + variable->prediction(), Phi, NodeOrigin()); + FlushFormat format = variable->flushFormat(); + NodeFlags result = resultFor(format); + phiNode->mergeFlags(result); + return phiNode; + }); + if (verbose) { - dataLog("Variables at head after SSA Phi insertion:\n"); - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - dataLog(" ", *block, ": ", block->variablesAtHead, "\n"); - } + dataLog("Computed Phis, about to transform the graph.\n"); + dataLog("\n"); + dataLog("Graph:\n"); + m_graph.dump(); + dataLog("\n"); + dataLog("Mappings:\n"); + for (unsigned i = 0; i < m_variableForSSAIndex.size(); ++i) + dataLog(" ", i, ": ", VariableAccessDataDump(m_graph, m_variableForSSAIndex[i]), "\n"); + dataLog("\n"); + dataLog("SSA calculator: ", m_calculator, "\n"); } - // At this point variablesAtHead in each block refers to either: + // Do the bulk of the SSA conversion. For each block, this tracks the operand->Node + // mapping based on a combination of what the SSACalculator tells us, and us walking over + // the block in forward order. We use our own data structure, valueForOperand, for + // determining the local mapping, but we rely on SSACalculator for the non-local mapping. // - // 1) A new SSA phi in the current block. - // 2) A SetArgument, which will soon get converted into a GetArgument. - // 3) An old CPS phi in a different block. + // This does three things at once: // - // We don't have to do anything for (1) and (2), but we do need to - // do a replacement for (3). - - // Clear all replacements, since other phases may have used them. - m_graph.clearReplacements(); - - if (dumpGraph) { - dataLog("Graph just before identifying replacements:\n"); - m_graph.dump(); - } - - // For all of the old CPS Phis, figure out what they correspond to in SSA. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - if (verbose) - dataLog("Dealing with block #", blockIndex, "\n"); - for (unsigned phiIndex = block->phis.size(); phiIndex--;) { - Node* phi = block->phis[phiIndex]; - if (verbose) { - dataLog( - "Considering ", phi, " (", RawPointer(phi), "), for r", - phi->local(), ", and its replacement in ", *block, ", ", - block->variablesAtHead.operand(phi->local()), "\n"); - } - ASSERT(phi != block->variablesAtHead.operand(phi->local())); - phi->misc.replacement = block->variablesAtHead.operand(phi->local()); - } - } - - // Now make sure that all variablesAtHead in each block points to the - // canonical SSA value. Prior to this, variablesAtHead[local] may point to - // an old CPS Phi in a different block. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (size_t i = block->variablesAtHead.size(); i--;) { - Node* node = block->variablesAtHead[i]; - if (!node) - continue; - while (node->misc.replacement) { - ASSERT(node != node->misc.replacement); - node = node->misc.replacement; + // - Inserts the Phis in all of the places where they need to go. We've already created + // them and they are accounted for in the SSACalculator's data structures, but we + // haven't inserted them yet, mostly because we want to insert all of a block's Phis in + // one go to amortize the cost of node insertion. + // + // - Create and insert Upsilons. + // + // - Convert all of the preexisting SSA nodes (other than the old CPS Phi nodes) into SSA + // form by replacing as follows: + // + // - MovHint has KillLocal prepended to it. + // + // - GetLocal die and get replaced with references to the node specified by + // valueForOperand. + // + // - SetLocal turns into PutStack if it's flushed, or turns into a Check otherwise. + // + // - Flush loses its children and turns into a Phantom. + // + // - PhantomLocal becomes Phantom, and its child is whatever is specified by + // valueForOperand. + // + // - SetArgument is removed. Note that GetStack nodes have already been inserted. + Operands<Node*> valueForOperand(OperandsLike, m_graph.block(0)->variablesAtHead); + for (BasicBlock* block : m_graph.blocksInPreOrder()) { + valueForOperand.clear(); + + // CPS will claim that the root block has all arguments live. But we have already done + // the first step of SSA conversion: argument locals are no longer live at head; + // instead we have GetStack nodes for extracting the values of arguments. So, we + // skip the at-head available value calculation for the root block. + if (block != m_graph.block(0)) { + for (size_t i = valueForOperand.size(); i--;) { + Node* nodeAtHead = block->variablesAtHead[i]; + if (!nodeAtHead) + continue; + + VariableAccessData* variable = nodeAtHead->variableAccessData(); + + if (verbose) + dataLog("Considering live variable ", VariableAccessDataDump(m_graph, variable), " at head of block ", *block, "\n"); + + SSACalculator::Variable* ssaVariable = m_ssaVariableForVariable.get(variable); + SSACalculator::Def* def = m_calculator.reachingDefAtHead(block, ssaVariable); + if (!def) { + // If we are required to insert a Phi, then we won't have a reaching def + // at head. + continue; + } + + Node* node = def->value(); + if (node->replacement()) { + // This will occur when a SetLocal had a GetLocal as its source. The + // GetLocal would get replaced with an actual SSA value by the time we get + // here. Note that the SSA value with which the GetLocal got replaced + // would not in turn have a replacement. + node = node->replacement(); + ASSERT(!node->replacement()); + } + if (verbose) + dataLog("Mapping: ", VirtualRegister(valueForOperand.operandForIndex(i)), " -> ", node, "\n"); + valueForOperand[i] = node; } - block->variablesAtHead[i] = node; } - } - - if (verbose) { - dataLog("Variables at head after convergence:\n"); - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - dataLog(" ", *block, ": ", block->variablesAtHead, "\n"); - } - } - - // Convert operations over locals into operations over SSA nodes. - // - GetLocal over captured variables lose their phis. - // - GetLocal over uncaptured variables die and get replaced with references - // to the node specified by variablesAtHead. - // - SetLocal gets NodeMustGenerate if it's flushed, or turns into a - // Check otherwise. - // - Flush loses its children and turns into a Phantom. - // - PhantomLocal becomes Phantom, and its child is whatever is specified - // by variablesAtHead. - // - SetArgument turns into GetArgument unless it's a captured variable. - // - Upsilons get their children fixed to refer to the true value of that local - // at the end of the block. Prior to this loop, Upsilons will refer to - // variableAtTail[operand], which may be any of Flush, PhantomLocal, GetLocal, - // SetLocal, SetArgument, or Phi. We accomplish this by setting the - // replacement pointers of all of those nodes to refer to either - // variablesAtHead[operand], or the child of the SetLocal. - for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { - BasicBlock* block = m_graph.block(blockIndex); - if (!block) - continue; - for (unsigned phiIndex = block->phis.size(); phiIndex--;) { - block->phis[phiIndex]->misc.replacement = - block->variablesAtHead.operand(block->phis[phiIndex]->local()); + // Insert Phis by asking the calculator what phis there are in this block. Also update + // valueForOperand with those Phis. For Phis associated with variables that are not + // flushed, we also insert a MovHint. + size_t phiInsertionPoint = 0; + for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(block)) { + VariableAccessData* variable = m_variableForSSAIndex[phiDef->variable()->index()]; + + m_insertionSet.insert(phiInsertionPoint, phiDef->value()); + valueForOperand.operand(variable->local()) = phiDef->value(); + + m_insertionSet.insertNode( + phiInsertionPoint, SpecNone, MovHint, NodeOrigin(), + OpInfo(variable->local().offset()), phiDef->value()->defaultEdge()); } - for (unsigned nodeIndex = block->size(); nodeIndex--;) - ASSERT(!block->at(nodeIndex)->misc.replacement); for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { Node* node = block->at(nodeIndex); + if (verbose) { + dataLog("Processing node ", node, ":\n"); + m_graph.dump(WTF::dataFile(), " ", node); + } + m_graph.performSubstitution(node); switch (node->op()) { + case MovHint: { + m_insertionSet.insertNode( + nodeIndex, SpecNone, KillStack, node->origin, + OpInfo(node->unlinkedLocal().offset())); + break; + } + case SetLocal: { VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured() || !!(node->flags() & NodeIsFlushed)) - node->mergeFlags(NodeMustGenerate); - else - node->setOpAndDefaultFlags(Check); - node->misc.replacement = node->child1().node(); // Only for Upsilons. + Node* child = node->child1().node(); + + if (!!(node->flags() & NodeIsFlushed)) { + node->convertToPutStack( + m_graph.m_stackAccessData.add( + variable->local(), variable->flushFormat())); + } else + node->remove(); + + if (verbose) + dataLog("Mapping: ", variable->local(), " -> ", child, "\n"); + valueForOperand.operand(variable->local()) = child; + break; + } + + case GetStack: { + ASSERT(m_argumentGetters.contains(node)); + valueForOperand.operand(node->stackAccessData()->local) = node; break; } case GetLocal: { - // It seems tempting to just do forwardPhi(GetLocal), except that we - // could have created a new (SSA) Phi, and the GetLocal could still be - // referring to an old (CPS) Phi. Uses variablesAtHead to tell us what - // to refer to. - node->children.reset(); VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) - break; - node->convertToPhantom(); - node->misc.replacement = block->variablesAtHead.operand(variable->local()); + node->children.reset(); + + node->remove(); + if (verbose) + dataLog("Replacing node ", node, " with ", valueForOperand.operand(variable->local()), "\n"); + node->setReplacement(valueForOperand.operand(variable->local())); break; } case Flush: { node->children.reset(); - node->convertToPhantom(); - // This is only for Upsilons. An Upsilon will only refer to a Flush if - // there were no SetLocals or GetLocals in the block. - node->misc.replacement = block->variablesAtHead.operand(node->local()); + node->remove(); break; } case PhantomLocal: { ASSERT(node->child1().useKind() == UntypedUse); VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) { - // This is a fun case. We could have a captured variable that had some - // or all of its uses strength reduced to phantoms rather than flushes. - // SSA conversion will currently still treat it as flushed, in the sense - // that it will just keep the SetLocal. Therefore, there is nothing that - // needs to be done here: we don't need to also keep the source value - // alive. And even if we did want to keep the source value alive, we - // wouldn't be able to, because the variablesAtHead value for a captured - // local wouldn't have been computed by the Phi reduction algorithm - // above. - node->children.reset(); - } else { - node->child1() = - block->variablesAtHead.operand(variable->local())->defaultEdge(); - } - node->convertToPhantom(); - // This is only for Upsilons. An Upsilon will only refer to a - // PhantomLocal if there were no SetLocals or GetLocals in the block. - node->misc.replacement = block->variablesAtHead.operand(variable->local()); + node->child1() = valueForOperand.operand(variable->local())->defaultEdge(); + node->remove(); break; } case SetArgument: { - VariableAccessData* variable = node->variableAccessData(); - if (variable->isCaptured()) - break; - node->setOpAndDefaultFlags(GetArgument); - node->setResult(resultFor(node->variableAccessData()->flushFormat())); + node->remove(); break; } - + default: break; } } + + // We want to insert Upsilons just before the end of the block. On the surface this + // seems dangerous because the Upsilon will have a checking UseKind. But, we will not + // actually be performing the check at the point of the Upsilon; the check will + // already have been performed at the point where the original SetLocal was. + NodeAndIndex terminal = block->findTerminal(); + size_t upsilonInsertionPoint = terminal.index; + NodeOrigin upsilonOrigin = terminal.node->origin; + for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) { + BasicBlock* successorBlock = block->successor(successorIndex); + for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) { + Node* phiNode = phiDef->value(); + SSACalculator::Variable* ssaVariable = phiDef->variable(); + VariableAccessData* variable = m_variableForSSAIndex[ssaVariable->index()]; + FlushFormat format = variable->flushFormat(); + UseKind useKind = useKindFor(format); + + m_insertionSet.insertNode( + upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin, + OpInfo(phiNode), Edge( + valueForOperand.operand(variable->local()), + useKind)); + } + } + + m_insertionSet.execute(block); } // Free all CPS phis and reset variables vectors. @@ -398,80 +371,39 @@ public: block->variablesAtTail.clear(); block->valuesAtHead.clear(); block->valuesAtHead.clear(); - block->ssa = adoptPtr(new BasicBlock::SSAData(block)); + block->ssa = std::make_unique<BasicBlock::SSAData>(block); } - m_graph.m_arguments.clear(); + m_graph.m_argumentFormats.resize(m_graph.m_arguments.size()); + for (unsigned i = m_graph.m_arguments.size(); i--;) { + FlushFormat format = FlushedJSValue; + + Node* node = m_argumentMapping.get(m_graph.m_arguments[i]); + + RELEASE_ASSERT(node); + format = node->stackAccessData()->format; + + m_graph.m_argumentFormats[i] = format; + m_graph.m_arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling. + } m_graph.m_form = SSA; - return true; - } -private: - void forwardPhiChildren(Node* node) - { - for (unsigned i = 0; i < AdjacencyList::Size; ++i) { - Edge& edge = node->children.child(i); - if (!edge) - break; - m_changed |= forwardPhiEdge(edge); - } - } - - Node* forwardPhi(Node* node) - { - for (;;) { - switch (node->op()) { - case Phi: { - Edge edge = node->children.justOneChild(); - if (!edge) - return node; - node = edge.node(); - break; - } - case GetLocal: - case SetLocal: - if (node->variableAccessData()->isCaptured()) - return node; - node = node->child1().node(); - break; - default: - return node; - } + if (verbose) { + dataLog("Graph after SSA transformation:\n"); + m_graph.dump(); } - } - - bool forwardPhiEdge(Edge& edge) - { - Node* newNode = forwardPhi(edge.node()); - if (newNode == edge.node()) - return false; - edge.setNode(newNode); + return true; } - - void deduplicateChildren(Node* node) - { - for (unsigned i = 0; i < AdjacencyList::Size; ++i) { - Edge edge = node->children.child(i); - if (!edge) - break; - if (edge == node) { - node->children.removeEdge(i--); - m_changed = true; - continue; - } - for (unsigned j = i + 1; j < AdjacencyList::Size; ++j) { - if (node->children.child(j) == edge) { - node->children.removeEdge(j--); - m_changed = true; - } - } - } - } - + +private: + SSACalculator m_calculator; InsertionSet m_insertionSet; - bool m_changed; + HashMap<VariableAccessData*, SSACalculator::Variable*> m_ssaVariableForVariable; + HashMap<Node*, Node*> m_argumentMapping; + HashSet<Node*> m_argumentGetters; + Vector<VariableAccessData*> m_variableForSSAIndex; }; bool performSSAConversion(Graph& graph) diff --git a/dfg/DFGSSAConversionPhase.h b/dfg/DFGSSAConversionPhase.h index 42b24e5..86c999d 100644 --- a/dfg/DFGSSAConversionPhase.h +++ b/dfg/DFGSSAConversionPhase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,10 +34,9 @@ class Graph; // Convert ThreadedCPS form into SSA form. This results in a form that has: // -// - Roughly minimal Phi's. We use the Aycock & Horspool fixpoint for -// converting the CPS maximal Phis into SSA minimal Phis, with the caveat -// that irreducible control flow may result in some missed opportunities -// for Phi reduction. +// - Minimal Phi's. We use the the Cytron et al (TOPLAS'91) algorithm for +// Phi insertion. Most of the algorithm is implemented in SSACalculator +// and Dominators. // // - No uses of GetLocal/SetLocal except for captured variables and flushes. // After this, any remaining SetLocal means Flush. PhantomLocals become diff --git a/dfg/DFGSSALoweringPhase.cpp b/dfg/DFGSSALoweringPhase.cpp index 993ec1b..c4b67a3 100644 --- a/dfg/DFGSSALoweringPhase.cpp +++ b/dfg/DFGSSALoweringPhase.cpp @@ -69,6 +69,7 @@ private: { switch (m_node->op()) { case GetByVal: + case HasIndexedProperty: lowerBoundsCheck(m_node->child1(), m_node->child2(), m_node->child3()); break; diff --git a/dfg/DFGSafeToExecute.h b/dfg/DFGSafeToExecute.h index 52bbfe4..953b54c 100644 --- a/dfg/DFGSafeToExecute.h +++ b/dfg/DFGSafeToExecute.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -50,9 +50,11 @@ public: case DoubleRepRealUse: case Int52RepUse: case NumberUse: + case RealNumberUse: case BooleanUse: case CellUse: case ObjectUse: + case FunctionUse: case FinalObjectUse: case ObjectOrOtherUse: case StringIdentUse: @@ -111,18 +113,19 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case JSConstant: case DoubleConstant: case Int52Constant: - case WeakJSConstant: case Identity: case ToThis: case CreateThis: case GetCallee: + case GetArgumentCount: case GetLocal: case SetLocal: + case PutStack: + case KillStack: + case GetStack: case MovHint: case ZombieHint: - case GetArgument: case Phantom: - case HardPhantom: case Upsilon: case Phi: case Flush: @@ -139,6 +142,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case UInt32ToNumber: case DoubleAsInt32: case ArithAdd: + case ArithClz32: case ArithSub: case ArithNegate: case ArithMul: @@ -148,10 +152,13 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case ArithAbs: case ArithMin: case ArithMax: + case ArithPow: case ArithSqrt: case ArithFRound: + case ArithRound: case ArithSin: case ArithCos: + case ArithLog: case ValueAdd: case GetById: case GetByIdFlush: @@ -159,24 +166,21 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case PutByIdFlush: case PutByIdDirect: case CheckStructure: - case CheckExecutable: + case GetExecutable: case GetButterfly: case CheckArray: case Arrayify: case ArrayifyToStructure: case GetScope: - case GetMyScope: - case SkipTopScope: case SkipScope: - case GetClosureRegisters: case GetClosureVar: case PutClosureVar: case GetGlobalVar: case PutGlobalVar: - case VariableWatchpoint: case VarInjectionWatchpoint: - case CheckFunction: - case AllocationProfileWatchpoint: + case CheckCell: + case CheckBadCell: + case CheckNotEmpty: case RegExpExec: case RegExpTest: case CompareLess: @@ -188,6 +192,11 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case CompareStrictEq: case Call: case Construct: + case CallVarargs: + case ConstructVarargs: + case LoadVarargs: + case CallForwardVarargs: + case ConstructForwardVarargs: case NewObject: case NewArray: case NewArrayWithSize: @@ -196,6 +205,8 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case Breakpoint: case ProfileWillCall: case ProfileDidCall: + case ProfileType: + case ProfileControlFlow: case CheckHasInstance: case InstanceOf: case IsUndefined: @@ -203,27 +214,23 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case IsNumber: case IsString: case IsObject: + case IsObjectOrNull: case IsFunction: case TypeOf: case LogicalNot: case ToPrimitive: case ToString: + case CallStringConstructor: case NewStringObject: case MakeRope: case In: case CreateActivation: - case TearOffActivation: - case CreateArguments: - case PhantomArguments: - case TearOffArguments: - case GetMyArgumentsLength: - case GetMyArgumentByVal: - case GetMyArgumentsLengthSafe: - case GetMyArgumentByValSafe: - case CheckArgumentsNotCreated: - case NewFunctionNoCheck: + case CreateDirectArguments: + case CreateScopedArguments: + case CreateClonedArguments: + case GetFromArguments: + case PutToArguments: case NewFunction: - case NewFunctionExpression: case Jump: case Branch: case Switch: @@ -240,13 +247,11 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case CheckTierUpInLoop: case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: case LoopHint: case StoreBarrier: - case StoreBarrierWithNullCheck: case InvalidationPoint: case NotifyWrite: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: case CheckInBounds: case ConstantStoragePointer: case Check: @@ -257,8 +262,39 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) case Int52Rep: case BooleanToNumber: case FiatInt52: + case GetGetter: + case GetSetter: + case GetEnumerableLength: + case HasGenericProperty: + case HasStructureProperty: + case HasIndexedProperty: + case GetDirectPname: + case GetPropertyEnumerator: + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: + case ToIndexString: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case GetMyArgumentByVal: + case ForwardVarargs: return true; - + + case NativeCall: + case NativeConstruct: + return false; // TODO: add a check for already checked. https://bugs.webkit.org/show_bug.cgi?id=133769 + + case BottomValue: + // If in doubt, assume that this isn't safe to execute, just because we have no way of + // compiling this node. + return false; + case GetByVal: case GetIndexedPropertyStorage: case GetArrayLength: @@ -277,21 +313,25 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) return node->arrayMode().modeForPut().alreadyChecked( graph, node, state.forNode(graph.varArgChild(node, 0))); - case StructureTransitionWatchpoint: - return state.forNode(node->child1()).m_futurePossibleStructure.isSubsetOf( - StructureSet(node->structure())); - case PutStructure: - case PhantomPutStructure: case AllocatePropertyStorage: case ReallocatePropertyStorage: - return state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf( - StructureSet(node->structureTransitionData().previousStructure)); + return state.forNode(node->child1()).m_structure.isSubsetOf( + StructureSet(node->transition()->previous)); case GetByOffset: - case PutByOffset: - return state.forNode(node->child1()).m_currentKnownStructure.isValidOffset( - graph.m_storageAccessData[node->storageAccessDataIndex()].offset); + case GetGetterSetterByOffset: + case PutByOffset: { + StructureAbstractValue& value = state.forNode(node->child1()).m_structure; + if (value.isTop()) + return false; + PropertyOffset offset = node->storageAccessData().offset; + for (unsigned i = value.size(); i--;) { + if (!value[i]->isValidOffset(offset)) + return false; + } + return true; + } case LastNodeType: RELEASE_ASSERT_NOT_REACHED(); diff --git a/dfg/DFGScoreBoard.h b/dfg/DFGScoreBoard.h index 15af609..c8795c8 100644 --- a/dfg/DFGScoreBoard.h +++ b/dfg/DFGScoreBoard.h @@ -55,21 +55,27 @@ public: assertClear(); } + void sortFree() + { + std::sort(m_free.begin(), m_free.end()); + } + void assertClear() { -#if !ASSERT_DISABLED + if (ASSERT_DISABLED) + return; + // For every entry in the used list the use count of the virtual register should be zero, or max, due to it being a preserved local. for (size_t i = 0; i < m_used.size(); ++i) - ASSERT(!m_used[i] || m_used[i] == max()); + RELEASE_ASSERT(!m_used[i] || m_used[i] == max()); // For every entry in the free list, the use count should be zero. for (size_t i = 0; i < m_free.size(); ++i) - ASSERT(!m_used[m_free[i]]); + RELEASE_ASSERT(!m_used[m_free[i]]); // There must not be duplicates in the free list. for (size_t i = 0; i < m_free.size(); ++i) { for (size_t j = i + 1; j < m_free.size(); ++j) - ASSERT(m_free[i] != m_free[j]); + RELEASE_ASSERT(m_free[i] != m_free[j]); } -#endif } VirtualRegister allocate() diff --git a/dfg/DFGSlowPathGenerator.h b/dfg/DFGSlowPathGenerator.h index 4e87d4f..add1a23 100644 --- a/dfg/DFGSlowPathGenerator.h +++ b/dfg/DFGSlowPathGenerator.h @@ -32,7 +32,6 @@ #include "DFGSilentRegisterSavePlan.h" #include "DFGSpeculativeJIT.h" #include <wtf/FastMalloc.h> -#include <wtf/PassOwnPtr.h> namespace JSC { namespace DFG { @@ -329,94 +328,77 @@ protected: }; template<typename JumpType, typename FunctionType, typename ResultType> -inline PassOwnPtr<SlowPathGenerator> slowPathCall( +inline std::unique_ptr<SlowPathGenerator> slowPathCall( JumpType from, SpeculativeJIT* jit, FunctionType function, ResultType result, SpillRegistersMode spillMode = NeedToSpill) { - return adoptPtr( - new CallResultAndNoArgumentsSlowPathGenerator< - JumpType, FunctionType, ResultType>( - from, jit, function, spillMode, result)); + return std::make_unique<CallResultAndNoArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType>>( + from, jit, function, spillMode, result); } template< typename JumpType, typename FunctionType, typename ResultType, typename ArgumentType1> -inline PassOwnPtr<SlowPathGenerator> slowPathCall( +inline std::unique_ptr<SlowPathGenerator> slowPathCall( JumpType from, SpeculativeJIT* jit, FunctionType function, ResultType result, ArgumentType1 argument1, SpillRegistersMode spillMode = NeedToSpill) { - return adoptPtr( - new CallResultAndOneArgumentSlowPathGenerator< - JumpType, FunctionType, ResultType, ArgumentType1>( - from, jit, function, spillMode, result, argument1)); + return std::make_unique<CallResultAndOneArgumentSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1>>( + from, jit, function, spillMode, result, argument1); } template< typename JumpType, typename FunctionType, typename ResultType, typename ArgumentType1, typename ArgumentType2> -inline PassOwnPtr<SlowPathGenerator> slowPathCall( +inline std::unique_ptr<SlowPathGenerator> slowPathCall( JumpType from, SpeculativeJIT* jit, FunctionType function, ResultType result, ArgumentType1 argument1, ArgumentType2 argument2, SpillRegistersMode spillMode = NeedToSpill) { - return adoptPtr( - new CallResultAndTwoArgumentsSlowPathGenerator< - JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2>( - from, jit, function, spillMode, result, argument1, argument2)); + return std::make_unique<CallResultAndTwoArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2>>( + from, jit, function, spillMode, result, argument1, argument2); } template< typename JumpType, typename FunctionType, typename ResultType, typename ArgumentType1, typename ArgumentType2, typename ArgumentType3> -inline PassOwnPtr<SlowPathGenerator> slowPathCall( +inline std::unique_ptr<SlowPathGenerator> slowPathCall( JumpType from, SpeculativeJIT* jit, FunctionType function, ResultType result, ArgumentType1 argument1, ArgumentType2 argument2, ArgumentType3 argument3, SpillRegistersMode spillMode = NeedToSpill) { - return adoptPtr( - new CallResultAndThreeArgumentsSlowPathGenerator< - JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2, - ArgumentType3>( - from, jit, function, spillMode, result, argument1, argument2, - argument3)); + return std::make_unique<CallResultAndThreeArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2, + ArgumentType3>>(from, jit, function, spillMode, result, argument1, argument2, argument3); } template< typename JumpType, typename FunctionType, typename ResultType, typename ArgumentType1, typename ArgumentType2, typename ArgumentType3, typename ArgumentType4> -inline PassOwnPtr<SlowPathGenerator> slowPathCall( +inline std::unique_ptr<SlowPathGenerator> slowPathCall( JumpType from, SpeculativeJIT* jit, FunctionType function, ResultType result, ArgumentType1 argument1, ArgumentType2 argument2, ArgumentType3 argument3, ArgumentType4 argument4, SpillRegistersMode spillMode = NeedToSpill) { - return adoptPtr( - new CallResultAndFourArgumentsSlowPathGenerator< - JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2, - ArgumentType3, ArgumentType4>( - from, jit, function, spillMode, result, argument1, argument2, - argument3, argument4)); + return std::make_unique<CallResultAndFourArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2, + ArgumentType3, ArgumentType4>>(from, jit, function, spillMode, result, argument1, argument2, argument3, argument4); } template< typename JumpType, typename FunctionType, typename ResultType, typename ArgumentType1, typename ArgumentType2, typename ArgumentType3, typename ArgumentType4, typename ArgumentType5> -inline PassOwnPtr<SlowPathGenerator> slowPathCall( +inline std::unique_ptr<SlowPathGenerator> slowPathCall( JumpType from, SpeculativeJIT* jit, FunctionType function, ResultType result, ArgumentType1 argument1, ArgumentType2 argument2, ArgumentType3 argument3, ArgumentType4 argument4, ArgumentType5 argument5, SpillRegistersMode spillMode = NeedToSpill) { - return adoptPtr( - new CallResultAndFiveArgumentsSlowPathGenerator< - JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2, - ArgumentType3, ArgumentType4, ArgumentType5>( - from, jit, function, spillMode, result, argument1, argument2, - argument3, argument4, argument5)); + return std::make_unique<CallResultAndFiveArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2, + ArgumentType3, ArgumentType4, ArgumentType5>>(from, jit, function, spillMode, result, argument1, argument2, argument3, + argument4, argument5); } template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments> @@ -449,37 +431,31 @@ private: }; template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments> -inline PassOwnPtr<SlowPathGenerator> slowPathMove( +inline std::unique_ptr<SlowPathGenerator> slowPathMove( JumpType from, SpeculativeJIT* jit, SourceType source[numberOfAssignments], DestinationType destination[numberOfAssignments]) { - return adoptPtr( - new AssigningSlowPathGenerator< - JumpType, DestinationType, SourceType, numberOfAssignments>( - from, jit, destination, source)); + return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, numberOfAssignments>>( + from, jit, destination, source); } template<typename JumpType, typename DestinationType, typename SourceType> -inline PassOwnPtr<SlowPathGenerator> slowPathMove( +inline std::unique_ptr<SlowPathGenerator> slowPathMove( JumpType from, SpeculativeJIT* jit, SourceType source, DestinationType destination) { SourceType sourceArray[1] = { source }; DestinationType destinationArray[1] = { destination }; - return adoptPtr( - new AssigningSlowPathGenerator< - JumpType, DestinationType, SourceType, 1>( - from, jit, destinationArray, sourceArray)); + return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 1>>( + from, jit, destinationArray, sourceArray); } template<typename JumpType, typename DestinationType, typename SourceType> -inline PassOwnPtr<SlowPathGenerator> slowPathMove( +inline std::unique_ptr<SlowPathGenerator> slowPathMove( JumpType from, SpeculativeJIT* jit, SourceType source1, DestinationType destination1, SourceType source2, DestinationType destination2) { SourceType sourceArray[2] = { source1, source2 }; DestinationType destinationArray[2] = { destination1, destination2 }; - return adoptPtr( - new AssigningSlowPathGenerator< - JumpType, DestinationType, SourceType, 2>( - from, jit, destinationArray, sourceArray)); + return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 2>>( + from, jit, destinationArray, sourceArray); } } } // namespace JSC::DFG diff --git a/dfg/DFGSpeculativeJIT.cpp b/dfg/DFGSpeculativeJIT.cpp index 83b07e8..9644995 100644 --- a/dfg/DFGSpeculativeJIT.cpp +++ b/dfg/DFGSpeculativeJIT.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,15 +28,21 @@ #if ENABLE(DFG_JIT) -#include "Arguments.h" +#include "BinarySwitch.h" #include "DFGAbstractInterpreterInlines.h" #include "DFGArrayifySlowPathGenerator.h" -#include "DFGBinarySwitch.h" #include "DFGCallArrayAllocatorSlowPathGenerator.h" +#include "DFGCallCreateDirectArgumentsSlowPathGenerator.h" +#include "DFGMayExit.h" +#include "DFGOSRExitFuzz.h" #include "DFGSaneStringGetByValSlowPathGenerator.h" #include "DFGSlowPathGenerator.h" -#include "LinkBuffer.h" +#include "DirectArguments.h" #include "JSCInlines.h" +#include "JSEnvironmentRecord.h" +#include "JSLexicalEnvironment.h" +#include "LinkBuffer.h" +#include "ScopedArguments.h" #include "ScratchRegisterAllocator.h" #include "WriteBarrierBuffer.h" #include <wtf/MathExtras.h> @@ -101,33 +107,88 @@ void SpeculativeJIT::emitAllocateJSArray(GPRReg resultGPR, Structure* structure, // 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. :-/ - addSlowPathGenerator(adoptPtr( - new CallArrayAllocatorSlowPathGenerator( - slowCases, this, operationNewArrayWithSize, resultGPR, storageGPR, - structure, numElements))); + addSlowPathGenerator(std::make_unique<CallArrayAllocatorSlowPathGenerator>( + slowCases, this, operationNewArrayWithSize, resultGPR, storageGPR, + structure, numElements)); } -void SpeculativeJIT::emitAllocateArguments(GPRReg resultGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath) +void SpeculativeJIT::emitGetLength(InlineCallFrame* inlineCallFrame, GPRReg lengthGPR, bool includeThis) { - Structure* structure = m_jit.graph().globalObjectFor(m_currentNode->origin.semantic)->argumentsStructure(); - emitAllocateDestructibleObject<Arguments>(resultGPR, structure, scratchGPR1, scratchGPR2, slowPath); - - m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfActivation())); + if (inlineCallFrame && !inlineCallFrame->isVarargs()) + m_jit.move(TrustedImm32(inlineCallFrame->arguments.size() - !includeThis), lengthGPR); + else { + VirtualRegister argumentCountRegister; + if (!inlineCallFrame) + argumentCountRegister = VirtualRegister(JSStack::ArgumentCount); + else + argumentCountRegister = inlineCallFrame->argumentCountRegister; + m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR); + if (!includeThis) + m_jit.sub32(TrustedImm32(1), lengthGPR); + } +} - m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), scratchGPR1); - m_jit.sub32(TrustedImm32(1), scratchGPR1); - m_jit.store32(scratchGPR1, MacroAssembler::Address(resultGPR, Arguments::offsetOfNumArguments())); +void SpeculativeJIT::emitGetLength(CodeOrigin origin, GPRReg lengthGPR, bool includeThis) +{ + emitGetLength(origin.inlineCallFrame, lengthGPR, includeThis); +} - m_jit.store32(TrustedImm32(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfOverrodeLength())); - if (m_jit.isStrictModeFor(m_currentNode->origin.semantic)) - m_jit.store8(TrustedImm32(1), MacroAssembler::Address(resultGPR, Arguments::offsetOfIsStrictMode())); +void SpeculativeJIT::emitGetCallee(CodeOrigin origin, GPRReg calleeGPR) +{ + if (origin.inlineCallFrame) { + if (origin.inlineCallFrame->isClosureCall) { + m_jit.loadPtr( + JITCompiler::addressFor(origin.inlineCallFrame->calleeRecovery.virtualRegister()), + calleeGPR); + } else { + m_jit.move( + TrustedImmPtr(origin.inlineCallFrame->calleeRecovery.constant().asCell()), + calleeGPR); + } + } else + m_jit.loadPtr(JITCompiler::addressFor(JSStack::Callee), calleeGPR); +} - m_jit.storePtr(GPRInfo::callFrameRegister, MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisters())); - m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfRegisterArray())); - m_jit.storePtr(TrustedImmPtr(0), MacroAssembler::Address(resultGPR, Arguments::offsetOfSlowArgumentData())); +void SpeculativeJIT::emitGetArgumentStart(CodeOrigin origin, GPRReg startGPR) +{ + m_jit.addPtr( + TrustedImm32( + JITCompiler::argumentsStart(origin).offset() * static_cast<int>(sizeof(Register))), + GPRInfo::callFrameRegister, startGPR); +} - m_jit.loadPtr(JITCompiler::addressFor(JSStack::Callee), scratchGPR1); - m_jit.storePtr(scratchGPR1, MacroAssembler::Address(resultGPR, Arguments::offsetOfCallee())); +MacroAssembler::Jump SpeculativeJIT::emitOSRExitFuzzCheck() +{ + if (!doOSRExitFuzzing()) + return MacroAssembler::Jump(); + + MacroAssembler::Jump result; + + m_jit.pushToSave(GPRInfo::regT0); + m_jit.load32(&g_numberOfOSRExitFuzzChecks, GPRInfo::regT0); + m_jit.add32(TrustedImm32(1), GPRInfo::regT0); + m_jit.store32(GPRInfo::regT0, &g_numberOfOSRExitFuzzChecks); + unsigned atOrAfter = Options::fireOSRExitFuzzAtOrAfter(); + unsigned at = Options::fireOSRExitFuzzAt(); + if (at || atOrAfter) { + unsigned threshold; + MacroAssembler::RelationalCondition condition; + if (atOrAfter) { + threshold = atOrAfter; + condition = MacroAssembler::Below; + } else { + threshold = at; + condition = MacroAssembler::NotEqual; + } + MacroAssembler::Jump ok = m_jit.branch32( + condition, GPRInfo::regT0, MacroAssembler::TrustedImm32(threshold)); + m_jit.popToRestore(GPRInfo::regT0); + result = m_jit.jump(); + ok.link(&m_jit); + } + m_jit.popToRestore(GPRInfo::regT0); + + return result; } void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail) @@ -135,7 +196,14 @@ void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource if (!m_compileOkay) return; ASSERT(m_isCheckingArgumentTypes || m_canExit); - m_jit.appendExitInfo(jumpToFail); + JITCompiler::Jump fuzzJump = emitOSRExitFuzzCheck(); + if (fuzzJump.isSet()) { + JITCompiler::JumpList jumpsToFail; + jumpsToFail.append(fuzzJump); + jumpsToFail.append(jumpToFail); + m_jit.appendExitInfo(jumpsToFail); + } else + m_jit.appendExitInfo(jumpToFail); m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size())); } @@ -144,7 +212,14 @@ void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource if (!m_compileOkay) return; ASSERT(m_isCheckingArgumentTypes || m_canExit); - m_jit.appendExitInfo(jumpsToFail); + JITCompiler::Jump fuzzJump = emitOSRExitFuzzCheck(); + if (fuzzJump.isSet()) { + JITCompiler::JumpList myJumpsToFail; + myJumpsToFail.append(jumpsToFail); + myJumpsToFail.append(fuzzJump); + m_jit.appendExitInfo(myJumpsToFail); + } else + m_jit.appendExitInfo(jumpsToFail); m_jit.jitCode()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size())); } @@ -215,6 +290,8 @@ void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs js return; speculationCheck(kind, jsValueRegs, node, m_jit.jump()); m_compileOkay = false; + if (verboseCompilationEnabled()) + dataLog("Bailing compilation.\n"); } void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Edge nodeUse) @@ -250,9 +327,9 @@ RegisterSet SpeculativeJIT::usedRegisters() return result; } -void SpeculativeJIT::addSlowPathGenerator(PassOwnPtr<SlowPathGenerator> slowPathGenerator) +void SpeculativeJIT::addSlowPathGenerator(std::unique_ptr<SlowPathGenerator> slowPathGenerator) { - m_slowPathGenerators.append(slowPathGenerator); + m_slowPathGenerators.append(WTF::move(slowPathGenerator)); } void SpeculativeJIT::runSlowPathGenerators() @@ -321,18 +398,20 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil ASSERT(info.gpr() == source); ASSERT(isJSInt32(info.registerFormat())); if (node->hasConstant()) { - ASSERT(isInt32Constant(node)); + ASSERT(node->isInt32Constant()); fillAction = SetInt32Constant; } else fillAction = Load32Payload; } else if (registerFormat == DataFormatBoolean) { #if USE(JSVALUE64) RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) fillAction = DoNothingForFill; +#endif #elif USE(JSVALUE32_64) ASSERT(info.gpr() == source); if (node->hasConstant()) { - ASSERT(isBooleanConstant(node)); + ASSERT(node->isBooleanConstant()); fillAction = SetBooleanConstant; } else fillAction = Load32Payload; @@ -340,8 +419,8 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil } else if (registerFormat == DataFormatCell) { ASSERT(info.gpr() == source); if (node->hasConstant()) { - JSValue value = valueOfJSConstant(node); - ASSERT_UNUSED(value, value.isCell()); + DFG_ASSERT(m_jit.graph(), m_currentNode, node->isCellConstant()); + node->asCell(); // To get the assertion. fillAction = SetCellConstant; } else { #if USE(JSVALUE64) @@ -364,7 +443,9 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil fillAction = Load64; else { RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) fillAction = Load64; // Make GCC happy. +#endif } } else if (registerFormat == DataFormatStrictInt52) { if (node->hasConstant()) @@ -377,15 +458,18 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForGPR(VirtualRegister spil fillAction = Load64; else { RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) fillAction = Load64; // Make GCC happy. +#endif } } else { ASSERT(registerFormat & DataFormatJS); #if USE(JSVALUE64) ASSERT(info.gpr() == source); if (node->hasConstant()) { - if (valueOfJSConstant(node).isCell()) + if (node->isCellConstant()) fillAction = SetTrustedJSConstant; + else fillAction = SetJSConstant; } else if (info.spillFormat() == DataFormatInt32) { ASSERT(registerFormat == DataFormatJSInt32); @@ -443,7 +527,7 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForFPR(VirtualRegister spil #if USE(JSVALUE64) if (node->hasConstant()) { - ASSERT(isNumberConstant(node)); + node->asNumber(); // To get the assertion. fillAction = SetDoubleConstant; } else { ASSERT(info.spillFormat() == DataFormatNone || info.spillFormat() == DataFormatDouble); @@ -452,7 +536,7 @@ SilentRegisterSavePlan SpeculativeJIT::silentSavePlanForFPR(VirtualRegister spil #elif USE(JSVALUE32_64) ASSERT(info.registerFormat() == DataFormatDouble); if (node->hasConstant()) { - ASSERT(isNumberConstant(node)); + node->asNumber(); // To get the assertion. fillAction = SetDoubleConstant; } else fillAction = LoadDouble; @@ -497,21 +581,21 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr case DoNothingForFill: break; case SetInt32Constant: - m_jit.move(Imm32(valueOfInt32Constant(plan.node())), plan.gpr()); + m_jit.move(Imm32(plan.node()->asInt32()), plan.gpr()); break; #if USE(JSVALUE64) case SetInt52Constant: - m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt() << JSValue::int52ShiftAmount), plan.gpr()); + m_jit.move(Imm64(plan.node()->asMachineInt() << JSValue::int52ShiftAmount), plan.gpr()); break; case SetStrictInt52Constant: - m_jit.move(Imm64(valueOfJSConstant(plan.node()).asMachineInt()), plan.gpr()); + m_jit.move(Imm64(plan.node()->asMachineInt()), plan.gpr()); break; #endif // USE(JSVALUE64) case SetBooleanConstant: - m_jit.move(TrustedImm32(valueOfBooleanConstant(plan.node())), plan.gpr()); + m_jit.move(TrustedImm32(plan.node()->asBoolean()), plan.gpr()); break; case SetCellConstant: - m_jit.move(TrustedImmPtr(valueOfJSConstant(plan.node()).asCell()), plan.gpr()); + m_jit.move(TrustedImmPtr(plan.node()->asCell()), plan.gpr()); break; #if USE(JSVALUE64) case SetTrustedJSConstant: @@ -521,7 +605,7 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr m_jit.move(valueOfJSConstantAsImm64(plan.node()), plan.gpr()); break; case SetDoubleConstant: - m_jit.move(Imm64(reinterpretDoubleToInt64(valueOfNumberConstant(plan.node()))), canTrample); + m_jit.move(Imm64(reinterpretDoubleToInt64(plan.node()->asNumber())), canTrample); m_jit.move64ToDouble(canTrample, plan.fpr()); break; case Load32PayloadBoxInt: @@ -539,10 +623,10 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr break; #else case SetJSConstantTag: - m_jit.move(Imm32(valueOfJSConstant(plan.node()).tag()), plan.gpr()); + m_jit.move(Imm32(plan.node()->asJSValue().tag()), plan.gpr()); break; case SetJSConstantPayload: - m_jit.move(Imm32(valueOfJSConstant(plan.node()).payload()), plan.gpr()); + m_jit.move(Imm32(plan.node()->asJSValue().payload()), plan.gpr()); break; case SetInt32Tag: m_jit.move(TrustedImm32(JSValue::Int32Tag), plan.gpr()); @@ -554,7 +638,7 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan, GPRReg canTr m_jit.move(TrustedImm32(JSValue::BooleanTag), plan.gpr()); break; case SetDoubleConstant: - m_jit.loadDouble(TrustedImmPtr(addressOfDoubleConstant(plan.node())), plan.fpr()); + m_jit.loadDouble(TrustedImmPtr(m_jit.addressOfDoubleConstant(plan.node())), plan.fpr()); break; #endif case Load32Tag: @@ -592,8 +676,10 @@ JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, A switch (arrayMode.arrayClass()) { case Array::OriginalArray: { CRASH(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) 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; +#endif } case Array::Array: @@ -707,21 +793,18 @@ void SpeculativeJIT::checkArray(Node* node) noResult(m_currentNode); return; } - case Array::Arguments: - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node, - m_jit.branch8( - MacroAssembler::NotEqual, - MacroAssembler::Address(baseReg, JSCell::typeInfoTypeOffset()), - MacroAssembler::TrustedImm32(ArgumentsType))); - + case Array::DirectArguments: + speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, DirectArgumentsType); + noResult(m_currentNode); + return; + case Array::ScopedArguments: + speculateCellTypeWithoutTypeFiltering(node->child1(), baseReg, ScopedArgumentsType); noResult(m_currentNode); return; default: - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node, - m_jit.branch8( - MacroAssembler::NotEqual, - MacroAssembler::Address(baseReg, JSCell::typeInfoTypeOffset()), - MacroAssembler::TrustedImm32(typeForTypedArrayType(node->arrayMode().typedArrayType())))); + speculateCellTypeWithoutTypeFiltering( + node->child1(), baseReg, + typeForTypedArrayType(node->arrayMode().typedArrayType())); noResult(m_currentNode); return; } @@ -771,8 +854,8 @@ void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg) slowPath.append(jumpSlowForUnwantedArrayMode(tempGPR, node->arrayMode())); } - addSlowPathGenerator(adoptPtr(new ArrayifySlowPathGenerator( - slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR))); + addSlowPathGenerator(std::make_unique<ArrayifySlowPathGenerator>( + slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR)); noResult(m_currentNode); } @@ -856,12 +939,9 @@ void SpeculativeJIT::compileIn(Node* node) { SpeculateCellOperand base(this, node->child2()); GPRReg baseGPR = base.gpr(); - - if (isConstant(node->child1().node())) { - JSString* string = - jsDynamicCast<JSString*>(valueOfJSConstant(node->child1().node())); - if (string && string->tryGetValueImpl() - && string->tryGetValueImpl()->isAtomic()) { + + if (JSString* string = node->child1()->dynamicCastConstant<JSString*>()) { + if (string->tryGetValueImpl() && string->tryGetValueImpl()->isAtomic()) { StructureStubInfo* stubInfo = m_jit.codeBlock()->addStubInfo(); GPRTemporary result(this); @@ -872,31 +952,33 @@ void SpeculativeJIT::compileIn(Node* node) MacroAssembler::PatchableJump jump = m_jit.patchableJump(); MacroAssembler::Label done = m_jit.label(); - OwnPtr<SlowPathGenerator> slowPath = slowPathCall( + // Since this block is executed only when the result of string->tryGetValueImpl() is atomic, + // we can cast it to const AtomicStringImpl* safely. + auto slowPath = slowPathCall( jump.m_jump, this, operationInOptimize, JSValueRegs::payloadOnly(resultGPR), stubInfo, baseGPR, - string->tryGetValueImpl()); + static_cast<const AtomicStringImpl*>(string->tryGetValueImpl())); stubInfo->codeOrigin = node->origin.semantic; stubInfo->patch.baseGPR = static_cast<int8_t>(baseGPR); stubInfo->patch.valueGPR = static_cast<int8_t>(resultGPR); stubInfo->patch.usedRegisters = usedRegisters(); stubInfo->patch.spillMode = NeedToSpill; - + m_jit.addIn(InRecord(jump, done, slowPath.get(), stubInfo)); - addSlowPathGenerator(slowPath.release()); - + addSlowPathGenerator(WTF::move(slowPath)); + base.use(); - + blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly); return; } } - + JSValueOperand key(this, node->child1()); JSValueRegs regs = key.jsValueRegs(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); base.use(); @@ -1151,33 +1233,17 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode) if (masqueradesAsUndefinedWatchpointIsStillValid()) { if (m_state.forNode(node->child1()).m_type & ~SpecObject) { speculationCheck( - BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), - m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), m_jit.branchIfNotObject(op1GPR)); } if (m_state.forNode(node->child2()).m_type & ~SpecObject) { speculationCheck( - BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), - m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), m_jit.branchIfNotObject(op2GPR)); } } else { - GPRTemporary structure(this); - GPRTemporary temp(this); - GPRReg structureGPR = structure.gpr(); - - m_jit.emitLoadStructure(op1GPR, structureGPR, temp.gpr()); if (m_state.forNode(node->child1()).m_type & ~SpecObject) { speculationCheck( BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), - m_jit.branchPtr( - MacroAssembler::Equal, - structureGPR, - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(op1GPR)); } speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), m_jit.branchTest8( @@ -1185,14 +1251,10 @@ void SpeculativeJIT::compilePeepHoleObjectEquality(Node* node, Node* branchNode) MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(MasqueradesAsUndefined))); - m_jit.emitLoadStructure(op2GPR, structureGPR, temp.gpr()); if (m_state.forNode(node->child2()).m_type & ~SpecObject) { speculationCheck( BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), - m_jit.branchPtr( - MacroAssembler::Equal, - structureGPR, - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(op2GPR)); } speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), m_jit.branchTest8( @@ -1219,13 +1281,13 @@ void SpeculativeJIT::compilePeepHoleBooleanBranch(Node* node, Node* branchNode, notTaken = tmp; } - if (isBooleanConstant(node->child1().node())) { - bool imm = valueOfBooleanConstant(node->child1().node()); + if (node->child1()->isBooleanConstant()) { + bool imm = node->child1()->asBoolean(); SpeculateBooleanOperand op2(this, node->child2()); branch32(condition, JITCompiler::Imm32(static_cast<int32_t>(JSValue::encode(jsBoolean(imm)))), op2.gpr(), taken); - } else if (isBooleanConstant(node->child2().node())) { + } else if (node->child2()->isBooleanConstant()) { SpeculateBooleanOperand op1(this, node->child1()); - bool imm = valueOfBooleanConstant(node->child2().node()); + bool imm = node->child2()->asBoolean(); branch32(condition, op1.gpr(), JITCompiler::Imm32(static_cast<int32_t>(JSValue::encode(jsBoolean(imm)))), taken); } else { SpeculateBooleanOperand op1(this, node->child1()); @@ -1250,13 +1312,13 @@ void SpeculativeJIT::compilePeepHoleInt32Branch(Node* node, Node* branchNode, JI notTaken = tmp; } - if (isInt32Constant(node->child1().node())) { - int32_t imm = valueOfInt32Constant(node->child1().node()); + if (node->child1()->isInt32Constant()) { + int32_t imm = node->child1()->asInt32(); SpeculateInt32Operand op2(this, node->child2()); branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken); - } else if (isInt32Constant(node->child2().node())) { + } else if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); - int32_t imm = valueOfInt32Constant(node->child2().node()); + int32_t imm = node->child2()->asInt32(); branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken); } else { SpeculateInt32Operand op1(this, node->child1()); @@ -1341,6 +1403,8 @@ void SpeculativeJIT::compileMovHint(Node* node) void SpeculativeJIT::bail(AbortReason reason) { + if (verboseCompilationEnabled()) + dataLog("Bailing compilation.\n"); m_compileOkay = true; m_jit.abortWithReason(reason, m_lastGeneratedNode); clearGenerationInfo(); @@ -1357,7 +1421,7 @@ void SpeculativeJIT::compileCurrentBlock() m_jit.blockHeads()[m_block->index] = m_jit.label(); - if (!m_block->cfaHasVisited) { + if (!m_block->intersectionOfCFAHasVisited) { // Don't generate code for basic blocks that are unreachable according to CFA. // But to be sure that nobody has generated a jump to this block, drop in a // breakpoint here. @@ -1404,72 +1468,44 @@ void SpeculativeJIT::compileCurrentBlock() bail(DFGBailedAtTopOfBlock); return; } + + if (ASSERT_DISABLED) + m_canExit = true; // Essentially disable the assertions. + else + m_canExit = mayExit(m_jit.graph(), m_currentNode); - m_canExit = m_currentNode->canExit(); - bool shouldExecuteEffects = m_interpreter.startExecuting(m_currentNode); + m_interpreter.startExecuting(); m_jit.setForNode(m_currentNode); m_codeOriginForExitTarget = m_currentNode->origin.forExit; m_codeOriginForExitProfile = m_currentNode->origin.semantic; m_lastGeneratedNode = m_currentNode->op(); - if (!m_currentNode->shouldGenerate()) { - switch (m_currentNode->op()) { - case JSConstant: - m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); - break; - - case WeakJSConstant: - m_jit.addWeakReference(m_currentNode->weakConstant()); - m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); - break; - - case SetLocal: - RELEASE_ASSERT_NOT_REACHED(); - break; - - case MovHint: - compileMovHint(m_currentNode); - break; - - case ZombieHint: { - recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead); - break; - } - - default: - if (belongsInMinifiedGraph(m_currentNode->op())) - m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); - break; - } - } else { - - if (verboseCompilationEnabled()) { - dataLogF( - "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x", - (int)m_currentNode->index(), - m_currentNode->origin.semantic.bytecodeIndex, m_jit.debugOffset()); - dataLog("\n"); - } - - compile(m_currentNode); - + + ASSERT(m_currentNode->shouldGenerate()); + + if (verboseCompilationEnabled()) { + dataLogF( + "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x", + (int)m_currentNode->index(), + m_currentNode->origin.semantic.bytecodeIndex, m_jit.debugOffset()); + dataLog("\n"); + } + + compile(m_currentNode); + + if (belongsInMinifiedGraph(m_currentNode->op())) + m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); + #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION) - m_jit.clearRegisterAllocationOffsets(); + m_jit.clearRegisterAllocationOffsets(); #endif - - if (!m_compileOkay) { - bail(DFGBailedAtEndOfNode); - return; - } - - if (belongsInMinifiedGraph(m_currentNode->op())) { - m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode)); - noticeOSRBirth(m_currentNode); - } + + if (!m_compileOkay) { + bail(DFGBailedAtEndOfNode); + return; } // Make sure that the abstract state is rematerialized for the next node. - if (shouldExecuteEffects) - m_interpreter.executeEffects(m_indexInBlock); + m_interpreter.executeEffects(m_indexInBlock); } // Perform the most basic verification that children have been used correctly. @@ -1595,6 +1631,15 @@ void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer) m_jit.noticeOSREntry(*block, m_osrEntryHeads[osrEntryIndex++], linkBuffer); } ASSERT(osrEntryIndex == m_osrEntryHeads.size()); + + if (verboseCompilationEnabled()) { + DumpContext dumpContext; + dataLog("OSR Entries:\n"); + for (OSREntryData& entryData : m_jit.jitCode()->osrEntry) + dataLog(" ", inContext(entryData, &dumpContext), "\n"); + if (!dumpContext.isEmpty()) + dumpContext.dump(WTF::dataFile()); + } } void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property) @@ -1771,13 +1816,22 @@ void SpeculativeJIT::compileGetByValOnString(Node* node) JSGlobalObject* globalObject = m_jit.globalObjectFor(node->origin.semantic); if (globalObject->stringPrototypeChainIsSane()) { + // FIXME: This could be captured using a Speculation mode that means "out-of-bounds + // loads return a trivial value". Something like SaneChainOutOfBounds. This should + // speculate that we don't take negative out-of-bounds, or better yet, it should rely + // on a stringPrototypeChainIsSane() guaranteeing that the prototypes have no negative + // indexed properties either. + // https://bugs.webkit.org/show_bug.cgi?id=144668 + m_jit.graph().watchpoints().addLazily(globalObject->stringPrototype()->structure()->transitionWatchpointSet()); + m_jit.graph().watchpoints().addLazily(globalObject->objectPrototype()->structure()->transitionWatchpointSet()); + #if USE(JSVALUE64) - addSlowPathGenerator(adoptPtr(new SaneStringGetByValSlowPathGenerator( - outOfBounds, this, JSValueRegs(scratchReg), baseReg, propertyReg))); + addSlowPathGenerator(std::make_unique<SaneStringGetByValSlowPathGenerator>( + outOfBounds, this, JSValueRegs(scratchReg), baseReg, propertyReg)); #else - addSlowPathGenerator(adoptPtr(new SaneStringGetByValSlowPathGenerator( + addSlowPathGenerator(std::make_unique<SaneStringGetByValSlowPathGenerator>( outOfBounds, this, JSValueRegs(resultTagReg, scratchReg), - baseReg, propertyReg))); + baseReg, propertyReg)); #endif } else { #if USE(JSVALUE64) @@ -1912,7 +1966,7 @@ void SpeculativeJIT::compileValueToInt32(Node* node) JITCompiler::Jump isNumber = m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister); DFG_TYPE_CHECK( - JSValueRegs(gpr), node->child1(), ~SpecCell, branchIsCell(JSValueRegs(gpr))); + JSValueRegs(gpr), node->child1(), ~SpecCell, m_jit.branchIfCell(JSValueRegs(gpr))); // It's not a cell: so true turns into 1 and all else turns into 0. m_jit.compare64(JITCompiler::Equal, gpr, TrustedImm32(ValueTrue), resultGpr); @@ -1968,7 +2022,7 @@ void SpeculativeJIT::compileValueToInt32(Node* node) DFG_TYPE_CHECK( op1.jsValueRegs(), node->child1(), ~SpecCell, - branchIsCell(op1.jsValueRegs())); + m_jit.branchIfCell(op1.jsValueRegs())); // It's not a cell: so true turns into 1 and all else turns into 0. JITCompiler::Jump isBoolean = m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::BooleanTag)); @@ -2070,31 +2124,89 @@ void SpeculativeJIT::compileDoubleAsInt32(Node* node) void SpeculativeJIT::compileDoubleRep(Node* node) { switch (node->child1().useKind()) { - case NumberUse: { - ASSERT(!isNumberConstant(node->child1().node())); // This should have been constant folded. + case RealNumberUse: { + JSValueOperand op1(this, node->child1(), ManualOperandSpeculation); + FPRTemporary result(this); + + JSValueRegs op1Regs = op1.jsValueRegs(); + FPRReg resultFPR = result.fpr(); + +#if USE(JSVALUE64) + GPRTemporary temp(this); + GPRReg tempGPR = temp.gpr(); + m_jit.move(op1Regs.gpr(), tempGPR); + m_jit.unboxDoubleWithoutAssertions(tempGPR, resultFPR); +#else + FPRTemporary temp(this); + FPRReg tempFPR = temp.fpr(); + unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR); +#endif + + JITCompiler::Jump done = m_jit.branchDouble( + JITCompiler::DoubleEqual, resultFPR, resultFPR); + + DFG_TYPE_CHECK( + op1Regs, node->child1(), SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs)); + m_jit.convertInt32ToDouble(op1Regs.payloadGPR(), resultFPR); + + done.link(&m_jit); + + doubleResult(resultFPR, node); + return; + } - if (isInt32Speculation(m_state.forNode(node->child1()).m_type)) { + case NotCellUse: + case NumberUse: { + ASSERT(!node->child1()->isNumberConstant()); // This should have been constant folded. + + SpeculatedType possibleTypes = m_state.forNode(node->child1()).m_type; + if (isInt32Speculation(possibleTypes)) { SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation); FPRTemporary result(this); m_jit.convertInt32ToDouble(op1.gpr(), result.fpr()); doubleResult(result.fpr(), node); return; } - + JSValueOperand op1(this, node->child1(), ManualOperandSpeculation); FPRTemporary result(this); - + #if USE(JSVALUE64) GPRTemporary temp(this); GPRReg op1GPR = op1.gpr(); GPRReg tempGPR = temp.gpr(); FPRReg resultFPR = result.fpr(); - + JITCompiler::JumpList done; + JITCompiler::Jump isInteger = m_jit.branch64( MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister); - - if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) { + + if (node->child1().useKind() == NotCellUse) { + JITCompiler::Jump isNumber = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagTypeNumberRegister); + JITCompiler::Jump isUndefined = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueUndefined)); + + static const double zero = 0; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&zero), resultFPR); + + JITCompiler::Jump isNull = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueNull)); + done.append(isNull); + + DFG_TYPE_CHECK(JSValueRegs(op1GPR), node->child1(), ~SpecCell, + m_jit.branchTest64(JITCompiler::NonZero, op1GPR, TrustedImm32(static_cast<int32_t>(~1)))); + + JITCompiler::Jump isFalse = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueFalse)); + static const double one = 1; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&one), resultFPR); + done.append(isFalse); + + isUndefined.link(&m_jit); + static const double NaN = PNaN; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&NaN), resultFPR); + done.append(m_jit.jump()); + + isNumber.link(&m_jit); + } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) { typeCheck( JSValueRegs(op1GPR), node->child1(), SpecBytecodeNumber, m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister)); @@ -2102,7 +2214,7 @@ void SpeculativeJIT::compileDoubleRep(Node* node) m_jit.move(op1GPR, tempGPR); unboxDouble(tempGPR, resultFPR); - JITCompiler::Jump done = m_jit.jump(); + done.append(m_jit.jump()); isInteger.link(&m_jit); m_jit.convertInt32ToDouble(op1GPR, resultFPR); @@ -2114,18 +2226,42 @@ void SpeculativeJIT::compileDoubleRep(Node* node) GPRReg op1PayloadGPR = op1.payloadGPR(); FPRReg tempFPR = temp.fpr(); FPRReg resultFPR = result.fpr(); + JITCompiler::JumpList done; JITCompiler::Jump isInteger = m_jit.branch32( MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag)); - - if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) { + + if (node->child1().useKind() == NotCellUse) { + JITCompiler::Jump isNumber = m_jit.branch32(JITCompiler::Below, op1TagGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1)); + JITCompiler::Jump isUndefined = m_jit.branch32(JITCompiler::Equal, op1TagGPR, TrustedImm32(JSValue::UndefinedTag)); + + static const double zero = 0; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&zero), resultFPR); + + JITCompiler::Jump isNull = m_jit.branch32(JITCompiler::Equal, op1TagGPR, TrustedImm32(JSValue::NullTag)); + done.append(isNull); + + DFG_TYPE_CHECK(JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), ~SpecCell, m_jit.branch32(JITCompiler::NotEqual, op1TagGPR, TrustedImm32(JSValue::BooleanTag))); + + JITCompiler::Jump isFalse = m_jit.branchTest32(JITCompiler::Zero, op1PayloadGPR, TrustedImm32(1)); + static const double one = 1; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&one), resultFPR); + done.append(isFalse); + + isUndefined.link(&m_jit); + static const double NaN = PNaN; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&NaN), resultFPR); + done.append(m_jit.jump()); + + isNumber.link(&m_jit); + } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) { typeCheck( JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecBytecodeNumber, m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag))); } - + unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR); - JITCompiler::Jump done = m_jit.jump(); + done.append(m_jit.jump()); isInteger.link(&m_jit); m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR); @@ -2174,14 +2310,6 @@ void SpeculativeJIT::compileValueRep(Node* node) if (needsTypeCheck(node->child1(), ~SpecDoubleImpureNaN)) m_jit.purifyNaN(valueFPR); -#if CPU(X86) - // boxDouble() on X86 clobbers the source, so we need to copy. - // FIXME: Don't do that! https://bugs.webkit.org/show_bug.cgi?id=131690 - FPRTemporary temp(this); - m_jit.moveDouble(valueFPR, temp.fpr()); - valueFPR = temp.fpr(); -#endif - boxDouble(valueFPR, resultRegs); jsValueResult(resultRegs, node); @@ -2265,10 +2393,12 @@ JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayOutOfBounds(Node* node, GPRRe { if (node->op() == PutByValAlias) return JITCompiler::Jump(); - if (JSArrayBufferView* view = m_jit.graph().tryGetFoldableViewForChild1(node)) { + JSArrayBufferView* view = m_jit.graph().tryGetFoldableView( + m_state.forNode(m_jit.graph().child(node, 0)).m_value, node->arrayMode()); + if (view) { uint32_t length = view->length(); Node* indexNode = m_jit.graph().child(node, 1).node(); - if (m_jit.graph().isInt32Constant(indexNode) && static_cast<uint32_t>(m_jit.graph().valueOfInt32Constant(indexNode)) < length) + if (indexNode->isInt32Constant() && indexNode->asUInt32() < length) return JITCompiler::Jump(); return m_jit.branch32( MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Imm32(length)); @@ -2307,13 +2437,13 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType t switch (elementSize(type)) { case 1: if (isSigned(type)) - m_jit.load8Signed(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg); + m_jit.load8SignedExtendTo32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg); else m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg); break; case 2: if (isSigned(type)) - m_jit.load16Signed(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg); + m_jit.load16SignedExtendTo32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg); else m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg); break; @@ -2364,7 +2494,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg propert GPRReg valueGPR = InvalidGPRReg; if (valueUse->isConstant()) { - JSValue jsValue = valueOfJSConstant(valueUse.node()); + JSValue jsValue = valueUse->asJSValue(); if (!jsValue.isNumber()) { terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); noResult(node); @@ -2564,7 +2694,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(GPRReg base, GPRReg prope void SpeculativeJIT::compileInstanceOfForObject(Node*, GPRReg valueReg, GPRReg prototypeReg, GPRReg scratchReg, GPRReg scratch2Reg) { // Check that prototype is an object. - speculationCheck(BadType, JSValueRegs(), 0, m_jit.branchIfCellNotObject(prototypeReg)); + speculationCheck(BadType, JSValueRegs(), 0, m_jit.branchIfNotObject(prototypeReg)); // Initialize scratchReg with the value being checked. m_jit.move(valueReg, scratchReg); @@ -2575,7 +2705,7 @@ void SpeculativeJIT::compileInstanceOfForObject(Node*, GPRReg valueReg, GPRReg p m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset() + CellPayloadOffset), scratchReg); MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg); #if USE(JSVALUE64) - branchIsCell(JSValueRegs(scratchReg)).linkTo(loop, &m_jit); + m_jit.branchIfCell(JSValueRegs(scratchReg)).linkTo(loop, &m_jit); #else m_jit.branchTestPtr(MacroAssembler::NonZero, scratchReg).linkTo(loop, &m_jit); #endif @@ -2614,7 +2744,7 @@ void SpeculativeJIT::compileInstanceOf(Node* node) GPRReg scratchReg = scratch.gpr(); GPRReg scratch2Reg = scratch2.gpr(); - MacroAssembler::Jump isCell = branchIsCell(value.jsValueRegs()); + MacroAssembler::Jump isCell = m_jit.branchIfCell(value.jsValueRegs()); GPRReg valueReg = value.jsValueRegs().payloadGPR(); moveFalseTo(scratchReg); @@ -2652,8 +2782,8 @@ void SpeculativeJIT::compileAdd(Node* node) case Int32Use: { ASSERT(!shouldCheckNegativeZero(node->arithMode())); - if (isInt32Constant(node->child1().node())) { - int32_t imm1 = valueOfInt32Constant(node->child1().node()); + if (node->child1()->isInt32Constant()) { + int32_t imm1 = node->child1()->asInt32(); SpeculateInt32Operand op2(this, node->child2()); GPRTemporary result(this); @@ -2667,9 +2797,9 @@ void SpeculativeJIT::compileAdd(Node* node) return; } - if (isInt32Constant(node->child2().node())) { + if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); - int32_t imm2 = valueOfInt32Constant(node->child2().node()); + int32_t imm2 = node->child2()->asInt32(); GPRTemporary result(this); if (!shouldCheckOverflow(node->arithMode())) { @@ -2790,7 +2920,7 @@ void SpeculativeJIT::compileMakeRope(Node* node) GPRReg scratchGPR = scratch.gpr(); JITCompiler::JumpList slowPath; - MarkedAllocator& markedAllocator = m_jit.vm()->heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString)); + MarkedAllocator& markedAllocator = m_jit.vm()->heap.allocatorForObjectWithDestructor(sizeof(JSRopeString)); m_jit.move(TrustedImmPtr(&markedAllocator), allocatorGPR); emitAllocateJSCell(resultGPR, allocatorGPR, TrustedImmPtr(m_jit.vm()->stringStructure.get()), scratchGPR, slowPath); @@ -2842,15 +2972,26 @@ void SpeculativeJIT::compileMakeRope(Node* node) cellResult(resultGPR, node); } +void SpeculativeJIT::compileArithClz32(Node* node) +{ + ASSERT_WITH_MESSAGE(node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use, "The Fixup phase should have enforced a Int32 operand."); + SpeculateInt32Operand value(this, node->child1()); + GPRTemporary result(this, Reuse, value); + GPRReg valueReg = value.gpr(); + GPRReg resultReg = result.gpr(); + m_jit.countLeadingZeros32(valueReg, resultReg); + int32Result(resultReg, node); +} + void SpeculativeJIT::compileArithSub(Node* node) { switch (node->binaryUseKind()) { case Int32Use: { ASSERT(!shouldCheckNegativeZero(node->arithMode())); - if (isNumberConstant(node->child2().node())) { + if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); - int32_t imm2 = valueOfInt32Constant(node->child2().node()); + int32_t imm2 = node->child2()->asInt32(); GPRTemporary result(this); if (!shouldCheckOverflow(node->arithMode())) { @@ -2865,8 +3006,8 @@ void SpeculativeJIT::compileArithSub(Node* node) return; } - if (isNumberConstant(node->child1().node())) { - int32_t imm1 = valueOfInt32Constant(node->child1().node()); + if (node->child1()->isInt32Constant()) { + int32_t imm1 = node->child1()->asInt32(); SpeculateInt32Operand op2(this, node->child2()); GPRTemporary result(this); @@ -3220,7 +3361,7 @@ void SpeculativeJIT::compileArithDiv(Node* node) done.link(&m_jit); int32Result(eax.gpr(), node); -#elif CPU(APPLE_ARMV7S) || CPU(ARM64) +#elif HAVE(ARM_IDIV_INSTRUCTIONS) || CPU(ARM64) SpeculateInt32Operand op1(this, node->child1()); SpeculateInt32Operand op2(this, node->child2()); GPRReg op1GPR = op1.gpr(); @@ -3279,8 +3420,8 @@ void SpeculativeJIT::compileArithMod(Node* node) // (in case of |dividend| < |divisor|), so we speculate it as strict int32. SpeculateStrictInt32Operand op1(this, node->child1()); - if (isInt32Constant(node->child2().node())) { - int32_t divisor = valueOfInt32Constant(node->child2().node()); + if (node->child2()->isInt32Constant()) { + int32_t divisor = node->child2()->asInt32(); if (divisor > 1 && hasOneBitSet(divisor)) { unsigned logarithm = WTF::fastLog2(divisor); GPRReg dividendGPR = op1.gpr(); @@ -3341,8 +3482,8 @@ void SpeculativeJIT::compileArithMod(Node* node) } #if CPU(X86) || CPU(X86_64) - if (isInt32Constant(node->child2().node())) { - int32_t divisor = valueOfInt32Constant(node->child2().node()); + if (node->child2()->isInt32Constant()) { + int32_t divisor = node->child2()->asInt32(); if (divisor && divisor != -1) { GPRReg op1Gpr = op1.gpr(); @@ -3473,7 +3614,7 @@ void SpeculativeJIT::compileArithMod(Node* node) done.link(&m_jit); int32Result(edx.gpr(), node); -#elif CPU(ARM64) || CPU(APPLE_ARMV7S) +#elif HAVE(ARM_IDIV_INSTRUCTIONS) || CPU(ARM64) GPRTemporary temp(this); GPRTemporary quotientThenRemainder(this); GPRTemporary multiplyAnswer(this); @@ -3498,7 +3639,7 @@ void SpeculativeJIT::compileArithMod(Node* node) // arithMode() == Arith::Unchecked? // https://bugs.webkit.org/show_bug.cgi?id=126444 speculationCheck(Overflow, JSValueRegs(), 0, m_jit.branchMul32(JITCompiler::Overflow, quotientThenRemainderGPR, divisorGPR, multiplyAnswerGPR)); -#if CPU(APPLE_ARMV7S) +#if HAVE(ARM_IDIV_INSTRUCTIONS) m_jit.assembler().sub(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR); #else m_jit.assembler().sub<32>(quotientThenRemainderGPR, dividendGPR, multiplyAnswerGPR); @@ -3545,6 +3686,160 @@ void SpeculativeJIT::compileArithMod(Node* node) } } +void SpeculativeJIT::compileArithRound(Node* node) +{ + ASSERT(node->child1().useKind() == DoubleRepUse); + + SpeculateDoubleOperand value(this, node->child1()); + FPRReg valueFPR = value.fpr(); + + if (producesInteger(node->arithRoundingMode()) && !shouldCheckNegativeZero(node->arithRoundingMode())) { + FPRTemporary oneHalf(this); + GPRTemporary roundedResultAsInt32(this); + FPRReg oneHalfFPR = oneHalf.fpr(); + GPRReg resultGPR = roundedResultAsInt32.gpr(); + + static const double halfConstant = 0.5; + m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&halfConstant), oneHalfFPR); + m_jit.addDouble(valueFPR, oneHalfFPR); + + JITCompiler::Jump truncationFailed = m_jit.branchTruncateDoubleToInt32(oneHalfFPR, resultGPR); + speculationCheck(Overflow, JSValueRegs(), node, truncationFailed); + int32Result(resultGPR, node); + return; + } + + flushRegisters(); + FPRResult roundedResultAsDouble(this); + FPRReg resultFPR = roundedResultAsDouble.fpr(); + callOperation(jsRound, resultFPR, valueFPR); + if (producesInteger(node->arithRoundingMode())) { + GPRTemporary roundedResultAsInt32(this); + FPRTemporary scratch(this); + FPRReg scratchFPR = scratch.fpr(); + GPRReg resultGPR = roundedResultAsInt32.gpr(); + JITCompiler::JumpList failureCases; + m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR); + speculationCheck(Overflow, JSValueRegs(), node, failureCases); + + int32Result(resultGPR, node); + } else + doubleResult(resultFPR, node); +} + +void SpeculativeJIT::compileArithSqrt(Node* node) +{ + SpeculateDoubleOperand op1(this, node->child1()); + FPRReg op1FPR = op1.fpr(); + + if (!MacroAssembler::supportsFloatingPointSqrt() || !Options::enableArchitectureSpecificOptimizations()) { + flushRegisters(); + FPRResult result(this); + callOperation(sqrt, result.fpr(), op1FPR); + doubleResult(result.fpr(), node); + } else { + FPRTemporary result(this, op1); + m_jit.sqrtDouble(op1.fpr(), result.fpr()); + doubleResult(result.fpr(), node); + } +} + +// For small positive integers , it is worth doing a tiny inline loop to exponentiate the base. +// Every register is clobbered by this helper. +static MacroAssembler::Jump compileArithPowIntegerFastPath(JITCompiler& assembler, FPRReg xOperand, GPRReg yOperand, FPRReg result) +{ + MacroAssembler::JumpList skipFastPath; + skipFastPath.append(assembler.branch32(MacroAssembler::LessThan, yOperand, MacroAssembler::TrustedImm32(0))); + skipFastPath.append(assembler.branch32(MacroAssembler::GreaterThan, yOperand, MacroAssembler::TrustedImm32(1000))); + + static const double oneConstant = 1.0; + assembler.loadDouble(MacroAssembler::TrustedImmPtr(&oneConstant), result); + + MacroAssembler::Label startLoop(assembler.label()); + MacroAssembler::Jump exponentIsEven = assembler.branchTest32(MacroAssembler::Zero, yOperand, MacroAssembler::TrustedImm32(1)); + assembler.mulDouble(xOperand, result); + exponentIsEven.link(&assembler); + assembler.mulDouble(xOperand, xOperand); + assembler.rshift32(MacroAssembler::TrustedImm32(1), yOperand); + assembler.branchTest32(MacroAssembler::NonZero, yOperand).linkTo(startLoop, &assembler); + + MacroAssembler::Jump skipSlowPath = assembler.jump(); + skipFastPath.link(&assembler); + + return skipSlowPath; +} + +void SpeculativeJIT::compileArithPow(Node* node) +{ + if (node->child2().useKind() == Int32Use) { + SpeculateDoubleOperand xOperand(this, node->child1()); + SpeculateInt32Operand yOperand(this, node->child2()); + FPRReg xOperandfpr = xOperand.fpr(); + GPRReg yOperandGpr = yOperand.gpr(); + FPRTemporary yOperandfpr(this); + + flushRegisters(); + + FPRResult result(this); + FPRReg resultFpr = result.fpr(); + + FPRTemporary xOperandCopy(this); + FPRReg xOperandCopyFpr = xOperandCopy.fpr(); + m_jit.moveDouble(xOperandfpr, xOperandCopyFpr); + + GPRTemporary counter(this); + GPRReg counterGpr = counter.gpr(); + m_jit.move(yOperandGpr, counterGpr); + + MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, counterGpr, resultFpr); + m_jit.convertInt32ToDouble(yOperandGpr, yOperandfpr.fpr()); + callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr.fpr()); + + skipFallback.link(&m_jit); + doubleResult(resultFpr, node); + return; + } + + SpeculateDoubleOperand xOperand(this, node->child1()); + SpeculateDoubleOperand yOperand(this, node->child2()); + FPRReg xOperandfpr = xOperand.fpr(); + FPRReg yOperandfpr = yOperand.fpr(); + + flushRegisters(); + + FPRResult result(this); + FPRReg resultFpr = result.fpr(); + + FPRTemporary xOperandCopy(this); + FPRReg xOperandCopyFpr = xOperandCopy.fpr(); + + FPRTemporary scratch(this); + FPRReg scratchFpr = scratch.fpr(); + + GPRTemporary yOperandInteger(this); + GPRReg yOperandIntegerGpr = yOperandInteger.gpr(); + MacroAssembler::JumpList failedExponentConversionToInteger; + m_jit.branchConvertDoubleToInt32(yOperandfpr, yOperandIntegerGpr, failedExponentConversionToInteger, scratchFpr, false); + + m_jit.moveDouble(xOperandfpr, xOperandCopyFpr); + MacroAssembler::Jump skipFallback = compileArithPowIntegerFastPath(m_jit, xOperandCopyFpr, yOperandInteger.gpr(), resultFpr); + failedExponentConversionToInteger.link(&m_jit); + + callOperation(operationMathPow, resultFpr, xOperandfpr, yOperandfpr); + skipFallback.link(&m_jit); + doubleResult(resultFpr, node); +} + +void SpeculativeJIT::compileArithLog(Node* node) +{ + SpeculateDoubleOperand op1(this, node->child1()); + FPRReg op1FPR = op1.fpr(); + flushRegisters(); + FPRResult result(this); + callOperation(log, result.fpr(), op1FPR); + doubleResult(result.fpr(), node); +} + // Returns true if the compare is fused with a subsequent branch. bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation) { @@ -3678,6 +3973,36 @@ bool SpeculativeJIT::compileStrictEq(Node* node) return false; } + if (node->isBinaryUseKind(ObjectUse, UntypedUse)) { + unsigned branchIndexInBlock = detectPeepHoleBranch(); + if (branchIndexInBlock != UINT_MAX) { + Node* branchNode = m_block->at(branchIndexInBlock); + compilePeepHoleObjectStrictEquality(node->child1(), node->child2(), branchNode); + use(node->child1()); + use(node->child2()); + m_indexInBlock = branchIndexInBlock; + m_currentNode = branchNode; + return true; + } + compileObjectStrictEquality(node->child1(), node->child2()); + return false; + } + + if (node->isBinaryUseKind(UntypedUse, ObjectUse)) { + unsigned branchIndexInBlock = detectPeepHoleBranch(); + if (branchIndexInBlock != UINT_MAX) { + Node* branchNode = m_block->at(branchIndexInBlock); + compilePeepHoleObjectStrictEquality(node->child2(), node->child1(), branchNode); + use(node->child1()); + use(node->child2()); + m_indexInBlock = branchIndexInBlock; + m_currentNode = branchNode; + return true; + } + compileObjectStrictEquality(node->child2(), node->child1()); + return false; + } + if (node->isBinaryUseKind(ObjectUse)) { unsigned branchIndexInBlock = detectPeepHoleBranch(); if (branchIndexInBlock != UINT_MAX) { @@ -3855,17 +4180,14 @@ void SpeculativeJIT::compileStringToUntypedEquality(Node* node, Edge stringEdge, JITCompiler::JumpList fastTrue; JITCompiler::JumpList fastFalse; - fastFalse.append(branchNotCell(rightRegs)); + fastFalse.append(m_jit.branchIfNotCell(rightRegs)); // It's safe to branch around the type check below, since proving that the values are // equal does indeed prove that the right value is a string. fastTrue.append(m_jit.branchPtr( MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR())); - fastFalse.append(m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + fastFalse.append(m_jit.branchIfNotString(rightRegs.payloadGPR())); compileStringEquality( node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR, @@ -3912,11 +4234,8 @@ void SpeculativeJIT::compileStringIdentToNotStringVarEquality( moveFalseTo(rightTempGPR); JITCompiler::JumpList notString; - notString.append(branchNotCell(rightRegs)); - notString.append(m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + notString.append(m_jit.branchIfNotCell(rightRegs)); + notString.append(m_jit.branchIfNotString(rightRegs.payloadGPR())); speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR); @@ -3943,6 +4262,15 @@ void SpeculativeJIT::compileStringZeroLength(Node* node) unblessedBooleanResult(eqGPR, node); } +void SpeculativeJIT::emitStringBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken) +{ + SpeculateCellOperand str(this, nodeUse); + speculateString(nodeUse, str.gpr()); + branchTest32(JITCompiler::NonZero, MacroAssembler::Address(str.gpr(), JSString::offsetOfLength()), taken); + jump(notTaken); + noResult(m_currentNode); +} + void SpeculativeJIT::compileConstantStoragePointer(Node* node) { GPRTemporary storage(this); @@ -4013,7 +4341,7 @@ void SpeculativeJIT::compileGetTypedArrayByteOffset(Node* node) int32Result(vectorGPR, node); } -void SpeculativeJIT::compileGetByValOnArguments(Node* node) +void SpeculativeJIT::compileGetByValOnDirectArguments(Node* node) { SpeculateCellOperand base(this, node->child1()); SpeculateStrictInt32Operand property(this, node->child2()); @@ -4021,87 +4349,134 @@ void SpeculativeJIT::compileGetByValOnArguments(Node* node) #if USE(JSVALUE32_64) GPRTemporary resultTag(this); #endif - GPRTemporary scratch(this); GPRReg baseReg = base.gpr(); GPRReg propertyReg = property.gpr(); GPRReg resultReg = result.gpr(); #if USE(JSVALUE32_64) GPRReg resultTagReg = resultTag.gpr(); + JSValueRegs resultRegs = JSValueRegs(resultTagReg, resultReg); +#else + JSValueRegs resultRegs = JSValueRegs(resultReg); #endif - GPRReg scratchReg = scratch.gpr(); if (!m_compileOkay) return; - - ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); - // Two really lame checks. - speculationCheck( - Uncountable, JSValueSource(), 0, - m_jit.branch32( - MacroAssembler::AboveOrEqual, propertyReg, - MacroAssembler::Address(baseReg, Arguments::offsetOfNumArguments()))); + ASSERT(ArrayMode(Array::DirectArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); + speculationCheck( - Uncountable, JSValueSource(), 0, + ExoticObjectMode, JSValueSource(), 0, m_jit.branchTestPtr( MacroAssembler::NonZero, - MacroAssembler::Address( - baseReg, Arguments::offsetOfSlowArgumentData()))); + MacroAssembler::Address(baseReg, DirectArguments::offsetOfOverrides()))); + speculationCheck( + ExoticObjectMode, JSValueSource(), 0, + m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, + MacroAssembler::Address(baseReg, DirectArguments::offsetOfLength()))); - m_jit.move(propertyReg, resultReg); - m_jit.signExtend32ToPtr(resultReg, resultReg); - m_jit.loadPtr( - MacroAssembler::Address(baseReg, Arguments::offsetOfRegisters()), - scratchReg); + m_jit.loadValue( + MacroAssembler::BaseIndex( + baseReg, propertyReg, MacroAssembler::TimesEight, DirectArguments::storageOffset()), + resultRegs); -#if USE(JSVALUE32_64) - m_jit.load32( - MacroAssembler::BaseIndex( - scratchReg, resultReg, MacroAssembler::TimesEight, - CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register) + - OBJECT_OFFSETOF(JSValue, u.asBits.tag)), - resultTagReg); - m_jit.load32( - MacroAssembler::BaseIndex( - scratchReg, resultReg, MacroAssembler::TimesEight, - CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register) + - OBJECT_OFFSETOF(JSValue, u.asBits.payload)), - resultReg); - jsValueResult(resultTagReg, resultReg, node); -#else - m_jit.load64( - MacroAssembler::BaseIndex( - scratchReg, resultReg, MacroAssembler::TimesEight, - CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register)), - resultReg); - jsValueResult(resultReg, node); -#endif + jsValueResult(resultRegs, node); } -void SpeculativeJIT::compileGetArgumentsLength(Node* node) +void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node) { SpeculateCellOperand base(this, node->child1()); - GPRTemporary result(this, Reuse, base); + SpeculateStrictInt32Operand property(this, node->child2()); + GPRTemporary result(this); +#if USE(JSVALUE32_64) + GPRTemporary resultTag(this); +#endif + GPRTemporary scratch(this); + GPRTemporary scratch2(this); GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); GPRReg resultReg = result.gpr(); +#if USE(JSVALUE32_64) + GPRReg resultTagReg = resultTag.gpr(); + JSValueRegs resultRegs = JSValueRegs(resultTagReg, resultReg); +#else + JSValueRegs resultRegs = JSValueRegs(resultReg); +#endif + GPRReg scratchReg = scratch.gpr(); + GPRReg scratch2Reg = scratch2.gpr(); if (!m_compileOkay) return; - ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); + ASSERT(ArrayMode(Array::ScopedArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); speculationCheck( - Uncountable, JSValueSource(), 0, - m_jit.branchTest8( - MacroAssembler::NonZero, - MacroAssembler::Address(baseReg, Arguments::offsetOfOverrodeLength()))); + ExoticObjectMode, JSValueSource(), nullptr, + m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, + MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTotalLength()))); + m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTable()), scratchReg); m_jit.load32( - MacroAssembler::Address(baseReg, Arguments::offsetOfNumArguments()), - resultReg); - int32Result(resultReg, node); + MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfLength()), scratch2Reg); + + MacroAssembler::Jump overflowArgument = m_jit.branch32( + MacroAssembler::AboveOrEqual, propertyReg, scratch2Reg); + + m_jit.loadPtr(MacroAssembler::Address(baseReg, ScopedArguments::offsetOfScope()), scratch2Reg); + + m_jit.loadPtr( + MacroAssembler::Address(scratchReg, ScopedArgumentsTable::offsetOfArguments()), + scratchReg); + m_jit.load32( + MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesFour), + scratchReg); + + speculationCheck( + ExoticObjectMode, JSValueSource(), nullptr, + m_jit.branch32( + MacroAssembler::Equal, scratchReg, TrustedImm32(ScopeOffset::invalidOffset))); + + m_jit.loadValue( + MacroAssembler::BaseIndex( + scratch2Reg, propertyReg, MacroAssembler::TimesEight, + JSEnvironmentRecord::offsetOfVariables()), + resultRegs); + + MacroAssembler::Jump done = m_jit.jump(); + overflowArgument.link(&m_jit); + + m_jit.sub32(propertyReg, scratch2Reg); + m_jit.neg32(scratch2Reg); + + m_jit.loadValue( + MacroAssembler::BaseIndex( + baseReg, scratch2Reg, MacroAssembler::TimesEight, + ScopedArguments::overflowStorageOffset()), + resultRegs); + speculationCheck(ExoticObjectMode, JSValueSource(), nullptr, m_jit.branchIfEmpty(resultRegs)); + + done.link(&m_jit); + + jsValueResult(resultRegs, node); +} + +void SpeculativeJIT::compileGetScope(Node* node) +{ + SpeculateCellOperand function(this, node->child1()); + GPRTemporary result(this, Reuse, function); + m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr()); + cellResult(result.gpr(), node); +} + +void SpeculativeJIT::compileSkipScope(Node* node) +{ + SpeculateCellOperand scope(this, node->child1()); + GPRTemporary result(this, Reuse, scope); + m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr()); + cellResult(result.gpr(), node); } void SpeculativeJIT::compileGetArrayLength(Node* node) @@ -4141,8 +4516,52 @@ void SpeculativeJIT::compileGetArrayLength(Node* node) int32Result(resultGPR, node); break; } - case Array::Arguments: { - compileGetArgumentsLength(node); + case Array::DirectArguments: { + SpeculateCellOperand base(this, node->child1()); + GPRTemporary result(this, Reuse, base); + + GPRReg baseReg = base.gpr(); + GPRReg resultReg = result.gpr(); + + if (!m_compileOkay) + return; + + ASSERT(ArrayMode(Array::DirectArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); + + speculationCheck( + ExoticObjectMode, JSValueSource(), 0, + m_jit.branchTestPtr( + MacroAssembler::NonZero, + MacroAssembler::Address(baseReg, DirectArguments::offsetOfOverrides()))); + + m_jit.load32( + MacroAssembler::Address(baseReg, DirectArguments::offsetOfLength()), resultReg); + + int32Result(resultReg, node); + break; + } + case Array::ScopedArguments: { + SpeculateCellOperand base(this, node->child1()); + GPRTemporary result(this, Reuse, base); + + GPRReg baseReg = base.gpr(); + GPRReg resultReg = result.gpr(); + + if (!m_compileOkay) + return; + + ASSERT(ArrayMode(Array::ScopedArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); + + speculationCheck( + ExoticObjectMode, JSValueSource(), 0, + m_jit.branchTest8( + MacroAssembler::NonZero, + MacroAssembler::Address(baseReg, ScopedArguments::offsetOfOverrodeThings()))); + + m_jit.load32( + MacroAssembler::Address(baseReg, ScopedArguments::offsetOfTotalLength()), resultReg); + + int32Result(resultReg, node); break; } default: { @@ -4157,28 +4576,428 @@ void SpeculativeJIT::compileGetArrayLength(Node* node) } } } -void SpeculativeJIT::compileNewFunctionNoCheck(Node* node) +void SpeculativeJIT::compileNewFunction(Node* node) +{ + SpeculateCellOperand scope(this, node->child1()); + GPRReg scopeGPR = scope.gpr(); + + FunctionExecutable* executable = node->castOperand<FunctionExecutable*>(); + + if (executable->singletonFunction()->isStillValid()) { + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + + callOperation(operationNewFunction, resultGPR, scopeGPR, executable); + cellResult(resultGPR, node); + return; + } + + Structure* structure = m_jit.graph().globalObjectFor( + node->origin.semantic)->functionStructure(); + + GPRTemporary result(this); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + GPRReg resultGPR = result.gpr(); + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg scratch2GPR = scratch2.gpr(); + + JITCompiler::JumpList slowPath; + emitAllocateJSObjectWithKnownSize<JSFunction>( + resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), + scratch1GPR, scratch2GPR, slowPath, JSFunction::allocationSize(0)); + + // Don't need a memory barriers since we just fast-created the function, so it + // must be young. + m_jit.storePtr( + scopeGPR, + JITCompiler::Address(resultGPR, JSFunction::offsetOfScopeChain())); + m_jit.storePtr( + TrustedImmPtr(executable), + JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable())); + m_jit.storePtr( + TrustedImmPtr(0), + JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData())); + + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationNewFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable)); + + cellResult(resultGPR, node); +} + +void SpeculativeJIT::compileForwardVarargs(Node* node) +{ + LoadVarargsData* data = node->loadVarargsData(); + InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame; + + GPRTemporary length(this); + JSValueRegsTemporary temp(this); + GPRReg lengthGPR = length.gpr(); + JSValueRegs tempRegs = temp.regs(); + + emitGetLength(inlineCallFrame, lengthGPR, /* includeThis = */ true); + if (data->offset) + m_jit.sub32(TrustedImm32(data->offset), lengthGPR); + + speculationCheck( + VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32( + MacroAssembler::Above, + lengthGPR, TrustedImm32(data->limit))); + + m_jit.store32(lengthGPR, JITCompiler::payloadFor(data->machineCount)); + + VirtualRegister sourceStart = JITCompiler::argumentsStart(inlineCallFrame) + data->offset; + VirtualRegister targetStart = data->machineStart; + + m_jit.sub32(TrustedImm32(1), lengthGPR); + + // First have a loop that fills in the undefined slots in case of an arity check failure. + m_jit.move(TrustedImm32(data->mandatoryMinimum), tempRegs.payloadGPR()); + JITCompiler::Jump done = m_jit.branch32(JITCompiler::BelowOrEqual, tempRegs.payloadGPR(), lengthGPR); + + JITCompiler::Label loop = m_jit.label(); + m_jit.sub32(TrustedImm32(1), tempRegs.payloadGPR()); + m_jit.storeTrustedValue( + jsUndefined(), + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, tempRegs.payloadGPR(), JITCompiler::TimesEight, + targetStart.offset() * sizeof(EncodedJSValue))); + m_jit.branch32(JITCompiler::Above, tempRegs.payloadGPR(), lengthGPR).linkTo(loop, &m_jit); + done.link(&m_jit); + + // And then fill in the actual argument values. + done = m_jit.branchTest32(JITCompiler::Zero, lengthGPR); + + loop = m_jit.label(); + m_jit.sub32(TrustedImm32(1), lengthGPR); + m_jit.loadValue( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight, + sourceStart.offset() * sizeof(EncodedJSValue)), + tempRegs); + m_jit.storeValue( + tempRegs, + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight, + targetStart.offset() * sizeof(EncodedJSValue))); + m_jit.branchTest32(JITCompiler::NonZero, lengthGPR).linkTo(loop, &m_jit); + + done.link(&m_jit); + + noResult(node); +} + +void SpeculativeJIT::compileCreateActivation(Node* node) +{ + SymbolTable* table = node->castOperand<SymbolTable*>(); + Structure* structure = m_jit.graph().globalObjectFor( + node->origin.semantic)->activationStructure(); + + SpeculateCellOperand scope(this, node->child1()); + GPRReg scopeGPR = scope.gpr(); + + if (table->singletonScope()->isStillValid()) { + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + + callOperation(operationCreateActivationDirect, resultGPR, structure, scopeGPR, table); + cellResult(resultGPR, node); + return; + } + + GPRTemporary result(this); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + GPRReg resultGPR = result.gpr(); + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg scratch2GPR = scratch2.gpr(); + + JITCompiler::JumpList slowPath; + emitAllocateJSObjectWithKnownSize<JSLexicalEnvironment>( + resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratch1GPR, scratch2GPR, + slowPath, JSLexicalEnvironment::allocationSize(table)); + + // Don't need a memory barriers since we just fast-created the activation, so the + // activation must be young. + m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSScope::offsetOfNext())); + m_jit.storePtr( + TrustedImmPtr(table), + JITCompiler::Address(resultGPR, JSLexicalEnvironment::offsetOfSymbolTable())); + + // Must initialize all members to undefined. + for (unsigned i = 0; i < table->scopeSize(); ++i) { + m_jit.storeTrustedValue( + jsUndefined(), + JITCompiler::Address( + resultGPR, JSLexicalEnvironment::offsetOfVariable(ScopeOffset(i)))); + } + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationCreateActivationDirect, resultGPR, structure, scopeGPR, table)); + + cellResult(resultGPR, node); +} + +void SpeculativeJIT::compileCreateDirectArguments(Node* node) { - GPRResult result(this); + // FIXME: A more effective way of dealing with the argument count and callee is to have + // them be explicit arguments to this node. + // https://bugs.webkit.org/show_bug.cgi?id=142207 + + GPRTemporary result(this); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + GPRTemporary length; + GPRReg resultGPR = result.gpr(); + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg scratch2GPR = scratch2.gpr(); + GPRReg lengthGPR = InvalidGPRReg; + JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR); + + unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1; + + unsigned knownLength; + bool lengthIsKnown; // if false, lengthGPR will have the length. + if (node->origin.semantic.inlineCallFrame + && !node->origin.semantic.inlineCallFrame->isVarargs()) { + knownLength = node->origin.semantic.inlineCallFrame->arguments.size() - 1; + lengthIsKnown = true; + } else { + knownLength = UINT_MAX; + lengthIsKnown = false; + + GPRTemporary realLength(this); + length.adopt(realLength); + lengthGPR = length.gpr(); + + VirtualRegister argumentCountRegister; + if (!node->origin.semantic.inlineCallFrame) + argumentCountRegister = VirtualRegister(JSStack::ArgumentCount); + else + argumentCountRegister = node->origin.semantic.inlineCallFrame->argumentCountRegister; + m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR); + m_jit.sub32(TrustedImm32(1), lengthGPR); + } + + Structure* structure = + m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure(); + + // Use a different strategy for allocating the object depending on whether we know its + // size statically. + JITCompiler::JumpList slowPath; + if (lengthIsKnown) { + emitAllocateJSObjectWithKnownSize<DirectArguments>( + resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratch1GPR, scratch2GPR, + slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity))); + + m_jit.store32( + TrustedImm32(knownLength), + JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength())); + } else { + JITCompiler::Jump tooFewArguments; + if (minCapacity) { + tooFewArguments = + m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity)); + } + m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR); + m_jit.add32(TrustedImm32(DirectArguments::storageOffset()), scratch1GPR); + if (minCapacity) { + JITCompiler::Jump done = m_jit.jump(); + tooFewArguments.link(&m_jit); + m_jit.move(TrustedImm32(DirectArguments::allocationSize(minCapacity)), scratch1GPR); + done.link(&m_jit); + } + + emitAllocateVariableSizedJSObject<DirectArguments>( + resultGPR, TrustedImmPtr(structure), scratch1GPR, scratch1GPR, scratch2GPR, + slowPath); + + m_jit.store32( + lengthGPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength())); + } + + m_jit.store32( + TrustedImm32(minCapacity), + JITCompiler::Address(resultGPR, DirectArguments::offsetOfMinCapacity())); + + m_jit.storePtr( + TrustedImmPtr(0), JITCompiler::Address(resultGPR, DirectArguments::offsetOfOverrides())); + + if (lengthIsKnown) { + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationCreateDirectArguments, resultGPR, structure, + knownLength, minCapacity)); + } else { + auto generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>( + slowPath, this, resultGPR, structure, lengthGPR, minCapacity); + addSlowPathGenerator(WTF::move(generator)); + } + + if (node->origin.semantic.inlineCallFrame) { + if (node->origin.semantic.inlineCallFrame->isClosureCall) { + m_jit.loadPtr( + JITCompiler::addressFor( + node->origin.semantic.inlineCallFrame->calleeRecovery.virtualRegister()), + scratch1GPR); + } else { + m_jit.move( + TrustedImmPtr( + node->origin.semantic.inlineCallFrame->calleeRecovery.constant().asCell()), + scratch1GPR); + } + } else + m_jit.loadPtr(JITCompiler::addressFor(JSStack::Callee), scratch1GPR); + + // Don't need a memory barriers since we just fast-created the activation, so the + // activation must be young. + m_jit.storePtr( + scratch1GPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfCallee())); + + VirtualRegister start = m_jit.argumentsStart(node->origin.semantic); + if (lengthIsKnown) { + for (unsigned i = 0; i < std::max(knownLength, minCapacity); ++i) { + m_jit.loadValue(JITCompiler::addressFor(start + i), valueRegs); + m_jit.storeValue( + valueRegs, JITCompiler::Address(resultGPR, DirectArguments::offsetOfSlot(i))); + } + } else { + JITCompiler::Jump done; + if (minCapacity) { + JITCompiler::Jump startLoop = m_jit.branch32( + JITCompiler::AboveOrEqual, lengthGPR, TrustedImm32(minCapacity)); + m_jit.move(TrustedImm32(minCapacity), lengthGPR); + startLoop.link(&m_jit); + } else + done = m_jit.branchTest32(MacroAssembler::Zero, lengthGPR); + JITCompiler::Label loop = m_jit.label(); + m_jit.sub32(TrustedImm32(1), lengthGPR); + m_jit.loadValue( + JITCompiler::BaseIndex( + GPRInfo::callFrameRegister, lengthGPR, JITCompiler::TimesEight, + start.offset() * static_cast<int>(sizeof(Register))), + valueRegs); + m_jit.storeValue( + valueRegs, + JITCompiler::BaseIndex( + resultGPR, lengthGPR, JITCompiler::TimesEight, + DirectArguments::storageOffset())); + m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit); + if (done.isSet()) + done.link(&m_jit); + } + + cellResult(resultGPR, node); +} + +void SpeculativeJIT::compileGetFromArguments(Node* node) +{ + SpeculateCellOperand arguments(this, node->child1()); + JSValueRegsTemporary result(this); + + GPRReg argumentsGPR = arguments.gpr(); + JSValueRegs resultRegs = result.regs(); + + m_jit.loadValue(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())), resultRegs); + jsValueResult(resultRegs, node); +} + +void SpeculativeJIT::compilePutToArguments(Node* node) +{ + SpeculateCellOperand arguments(this, node->child1()); + JSValueOperand value(this, node->child2()); + + GPRReg argumentsGPR = arguments.gpr(); + JSValueRegs valueRegs = value.jsValueRegs(); + + m_jit.storeValue(valueRegs, JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset()))); + noResult(node); +} + +void SpeculativeJIT::compileCreateScopedArguments(Node* node) +{ + SpeculateCellOperand scope(this, node->child1()); + GPRReg scopeGPR = scope.gpr(); + + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); flushRegisters(); - callOperation( - operationNewFunctionNoCheck, resultGPR, m_jit.codeBlock()->functionDecl(node->functionDeclIndex())); + + // We set up the arguments ourselves, because we have the whole register file and we can + // set them up directly into the argument registers. This also means that we don't have to + // invent a four-argument-register shuffle. + + // Arguments: 0:exec, 1:structure, 2:start, 3:length, 4:callee, 5:scope + + // Do the scopeGPR first, since it might alias an argument register. + m_jit.setupArgument(5, [&] (GPRReg destGPR) { m_jit.move(scopeGPR, destGPR); }); + + // These other things could be done in any order. + m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); }); + m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); }); + m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); }); + m_jit.setupArgument( + 1, [&] (GPRReg destGPR) { + m_jit.move( + TrustedImmPtr(m_jit.globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()), + destGPR); + }); + m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); }); + + appendCallWithExceptionCheckSetResult(operationCreateScopedArguments, resultGPR); + cellResult(resultGPR, node); } -void SpeculativeJIT::compileNewFunctionExpression(Node* node) +void SpeculativeJIT::compileCreateClonedArguments(Node* node) { - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); flushRegisters(); - callOperation( - operationNewFunctionNoCheck, - resultGPR, - m_jit.codeBlock()->functionExpr(node->functionExprIndex())); + + // We set up the arguments ourselves, because we have the whole register file and we can + // set them up directly into the argument registers. + + // Arguments: 0:exec, 1:structure, 2:start, 3:length, 4:callee + m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetCallee(node->origin.semantic, destGPR); }); + m_jit.setupArgument(3, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); }); + m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); }); + m_jit.setupArgument( + 1, [&] (GPRReg destGPR) { + m_jit.move( + TrustedImmPtr( + m_jit.globalObjectFor(node->origin.semantic)->outOfBandArgumentsStructure()), + destGPR); + }); + m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); }); + + appendCallWithExceptionCheckSetResult(operationCreateClonedArguments, resultGPR); + cellResult(resultGPR, node); } +void SpeculativeJIT::compileNotifyWrite(Node* node) +{ + WatchpointSet* set = node->watchpointSet(); + + JITCompiler::Jump slowCase = m_jit.branch8( + JITCompiler::NotEqual, + JITCompiler::AbsoluteAddress(set->addressOfState()), + TrustedImm32(IsInvalidated)); + + addSlowPathGenerator( + slowPathCall(slowCase, this, operationNotifyWrite, NoResult, set)); + + noResult(node); +} + bool SpeculativeJIT::compileRegExpExec(Node* node) { unsigned branchIndexInBlock = detectPeepHoleBranch(); @@ -4204,7 +5023,7 @@ bool SpeculativeJIT::compileRegExpExec(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR); branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, result.gpr(), taken); @@ -4218,16 +5037,128 @@ bool SpeculativeJIT::compileRegExpExec(Node* node) return true; } +void SpeculativeJIT::compileIsObjectOrNull(Node* node) +{ + JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); + + JSValueOperand value(this, node->child1()); + JSValueRegs valueRegs = value.jsValueRegs(); + + GPRTemporary result(this); + GPRReg resultGPR = result.gpr(); + + JITCompiler::Jump isCell = m_jit.branchIfCell(valueRegs); + + JITCompiler::Jump isNull = m_jit.branchIfEqual(valueRegs, jsNull()); + JITCompiler::Jump isNonNullNonCell = m_jit.jump(); + + isCell.link(&m_jit); + JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR()); + JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR()); + + JITCompiler::Jump slowPath = m_jit.branchTest8( + JITCompiler::NonZero, + JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()), + TrustedImm32(MasqueradesAsUndefined | TypeOfShouldCallGetCallData)); + + isNull.link(&m_jit); + m_jit.move(TrustedImm32(1), resultGPR); + JITCompiler::Jump done = m_jit.jump(); + + isNonNullNonCell.link(&m_jit); + isFunction.link(&m_jit); + notObject.link(&m_jit); + m_jit.move(TrustedImm32(0), resultGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationObjectIsObject, resultGPR, globalObject, + valueRegs.payloadGPR())); + + done.link(&m_jit); + + unblessedBooleanResult(resultGPR, node); +} + +void SpeculativeJIT::compileIsFunction(Node* node) +{ + JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); + + JSValueOperand value(this, node->child1()); + JSValueRegs valueRegs = value.jsValueRegs(); + + GPRTemporary result(this); + GPRReg resultGPR = result.gpr(); + + JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs); + JITCompiler::Jump isFunction = m_jit.branchIfFunction(valueRegs.payloadGPR()); + JITCompiler::Jump notObject = m_jit.branchIfNotObject(valueRegs.payloadGPR()); + + JITCompiler::Jump slowPath = m_jit.branchTest8( + JITCompiler::NonZero, + JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoFlagsOffset()), + TrustedImm32(MasqueradesAsUndefined | TypeOfShouldCallGetCallData)); + + notCell.link(&m_jit); + notObject.link(&m_jit); + m_jit.move(TrustedImm32(0), resultGPR); + JITCompiler::Jump done = m_jit.jump(); + + isFunction.link(&m_jit); + m_jit.move(TrustedImm32(1), resultGPR); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationObjectIsFunction, resultGPR, globalObject, + valueRegs.payloadGPR())); + + done.link(&m_jit); + + unblessedBooleanResult(resultGPR, node); +} + +void SpeculativeJIT::compileTypeOf(Node* node) +{ + JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); + + JSValueOperand value(this, node->child1()); + JSValueRegs valueRegs = value.jsValueRegs(); + + GPRTemporary result(this); + GPRReg resultGPR = result.gpr(); + + JITCompiler::JumpList done; + JITCompiler::Jump slowPath; + m_jit.emitTypeOf( + valueRegs, resultGPR, + [&] (TypeofType type, bool fallsThrough) { + m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.typeString(type)), resultGPR); + if (!fallsThrough) + done.append(m_jit.jump()); + }, + [&] (JITCompiler::Jump theSlowPath) { + slowPath = theSlowPath; + }); + done.link(&m_jit); + + addSlowPathGenerator( + slowPathCall( + slowPath, this, operationTypeOfObject, resultGPR, globalObject, + valueRegs.payloadGPR())); + + cellResult(resultGPR, node); +} + void SpeculativeJIT::compileAllocatePropertyStorage(Node* node) { - if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) { + if (node->transition()->previous->couldHaveIndexingHeader()) { SpeculateCellOperand base(this, node->child1()); GPRReg baseGPR = base.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationReallocateButterflyToHavePropertyStorageWithInitialCapacity, result.gpr(), baseGPR); storageResult(result.gpr(), node); @@ -4240,8 +5171,8 @@ void SpeculativeJIT::compileAllocatePropertyStorage(Node* node) GPRReg baseGPR = base.gpr(); GPRReg scratchGPR1 = scratch1.gpr(); - ASSERT(!node->structureTransitionData().previousStructure->outOfLineCapacity()); - ASSERT(initialOutOfLineCapacity == node->structureTransitionData().newStructure->outOfLineCapacity()); + ASSERT(!node->transition()->previous->outOfLineCapacity()); + ASSERT(initialOutOfLineCapacity == node->transition()->next->outOfLineCapacity()); JITCompiler::Jump slowPath = emitAllocateBasicStorage( @@ -4259,18 +5190,18 @@ void SpeculativeJIT::compileAllocatePropertyStorage(Node* node) void SpeculativeJIT::compileReallocatePropertyStorage(Node* node) { - size_t oldSize = node->structureTransitionData().previousStructure->outOfLineCapacity() * sizeof(JSValue); + size_t oldSize = node->transition()->previous->outOfLineCapacity() * sizeof(JSValue); size_t newSize = oldSize * outOfLineGrowthFactor; - ASSERT(newSize == node->structureTransitionData().newStructure->outOfLineCapacity() * sizeof(JSValue)); + ASSERT(newSize == node->transition()->next->outOfLineCapacity() * sizeof(JSValue)); - if (node->structureTransitionData().previousStructure->couldHaveIndexingHeader()) { + if (node->transition()->previous->couldHaveIndexingHeader()) { SpeculateCellOperand base(this, node->child1()); GPRReg baseGPR = base.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationReallocateButterflyToGrowPropertyStorage, result.gpr(), baseGPR, newSize / sizeof(JSValue)); storageResult(result.gpr(), node); @@ -4315,7 +5246,7 @@ GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, Arr return temporary.gpr(); } -void SpeculativeJIT::compileToStringOnCell(Node* node) +void SpeculativeJIT::compileToStringOrCallStringConstructorOnCell(Node* node) { SpeculateCellOperand op1(this, node->child1()); GPRReg op1GPR = op1.gpr(); @@ -4339,10 +5270,10 @@ void SpeculativeJIT::compileToStringOnCell(Node* node) m_jit.load32(JITCompiler::Address(op1GPR, JSCell::structureIDOffset()), resultGPR); JITCompiler::Jump isString = m_jit.branchStructurePtr( - JITCompiler::Equal, + JITCompiler::Equal, resultGPR, m_jit.vm()->stringStructure.get()); - + speculateStringObjectForStructure(node->child1(), resultGPR); m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR); @@ -4359,7 +5290,7 @@ void SpeculativeJIT::compileToStringOnCell(Node* node) } case CellUse: { - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); // We flush registers instead of silent spill/fill because in this mode we @@ -4368,15 +5299,17 @@ void SpeculativeJIT::compileToStringOnCell(Node* node) flushRegisters(); JITCompiler::Jump done; if (node->child1()->prediction() & SpecString) { - JITCompiler::Jump needCall = m_jit.branchStructurePtr( - JITCompiler::NotEqual, - JITCompiler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get()); + JITCompiler::Jump needCall = m_jit.branchIfNotString(op1GPR); m_jit.move(op1GPR, resultGPR); done = m_jit.jump(); needCall.link(&m_jit); } - callOperation(operationToStringOnCell, resultGPR, op1GPR); + if (node->op() == ToString) + callOperation(operationToStringOnCell, resultGPR, op1GPR); + else { + ASSERT(node->op() == CallStringConstructor); + callOperation(operationCallStringConstructorOnCell, resultGPR, op1GPR); + } if (done.isSet()) done.link(&m_jit); cellResult(resultGPR, node); @@ -4506,6 +5439,28 @@ void SpeculativeJIT::compileNewTypedArray(Node* node) cellResult(resultGPR, node); } +void SpeculativeJIT::speculateCellTypeWithoutTypeFiltering( + Edge edge, GPRReg cellGPR, JSType jsType) +{ + speculationCheck( + BadType, JSValueSource::unboxedCell(cellGPR), edge, + m_jit.branch8( + MacroAssembler::NotEqual, + MacroAssembler::Address(cellGPR, JSCell::typeInfoTypeOffset()), + MacroAssembler::TrustedImm32(jsType))); +} + +void SpeculativeJIT::speculateCellType( + Edge edge, GPRReg cellGPR, SpeculatedType specType, JSType jsType) +{ + DFG_TYPE_CHECK( + JSValueSource::unboxedCell(cellGPR), edge, specType, + m_jit.branch8( + MacroAssembler::NotEqual, + MacroAssembler::Address(cellGPR, JSCell::typeInfoTypeOffset()), + TrustedImm32(jsType))); +} + void SpeculativeJIT::speculateInt32(Edge edge) { if (!needsTypeCheck(edge, SpecInt32)) @@ -4536,7 +5491,37 @@ void SpeculativeJIT::speculateNumber(Edge edge) #endif } -void SpeculativeJIT::speculateDoubleReal(Edge edge) +void SpeculativeJIT::speculateRealNumber(Edge edge) +{ + if (!needsTypeCheck(edge, SpecBytecodeRealNumber)) + return; + + JSValueOperand op1(this, edge, ManualOperandSpeculation); + FPRTemporary result(this); + + JSValueRegs op1Regs = op1.jsValueRegs(); + FPRReg resultFPR = result.fpr(); + +#if USE(JSVALUE64) + GPRTemporary temp(this); + GPRReg tempGPR = temp.gpr(); + m_jit.move(op1Regs.gpr(), tempGPR); + m_jit.unboxDoubleWithoutAssertions(tempGPR, resultFPR); +#else + FPRTemporary temp(this); + FPRReg tempFPR = temp.fpr(); + unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR); +#endif + + JITCompiler::Jump done = m_jit.branchDouble( + JITCompiler::DoubleEqual, resultFPR, resultFPR); + + typeCheck(op1Regs, edge, SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs)); + + done.link(&m_jit); +} + +void SpeculativeJIT::speculateDoubleRepReal(Edge edge) { if (!needsTypeCheck(edge, SpecDoubleReal)) return; @@ -4573,10 +5558,16 @@ void SpeculativeJIT::speculateObject(Edge edge) SpeculateCellOperand operand(this, edge); GPRReg gpr = operand.gpr(); DFG_TYPE_CHECK( - JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(gpr, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchIfNotObject(gpr)); +} + +void SpeculativeJIT::speculateFunction(Edge edge) +{ + if (!needsTypeCheck(edge, SpecFunction)) + return; + + SpeculateCellOperand operand(this, edge); + speculateCellType(edge, operand.gpr(), SpecFunction, JSFunctionType); } void SpeculativeJIT::speculateFinalObject(Edge edge) @@ -4585,12 +5576,7 @@ void SpeculativeJIT::speculateFinalObject(Edge edge) return; SpeculateCellOperand operand(this, edge); - GPRReg gpr = operand.gpr(); - DFG_TYPE_CHECK( - JSValueSource::unboxedCell(gpr), edge, SpecFinalObject, m_jit.branch8( - MacroAssembler::NotEqual, - MacroAssembler::Address(gpr, JSCell::typeInfoTypeOffset()), - TrustedImm32(FinalObjectType))); + speculateCellType(edge, operand.gpr(), SpecFinalObject, FinalObjectType); } void SpeculativeJIT::speculateObjectOrOther(Edge edge) @@ -4601,19 +5587,16 @@ void SpeculativeJIT::speculateObjectOrOther(Edge edge) JSValueOperand operand(this, edge, ManualOperandSpeculation); GPRTemporary temp(this); GPRReg tempGPR = temp.gpr(); - MacroAssembler::Jump notCell = branchNotCell(operand.jsValueRegs()); + MacroAssembler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs()); GPRReg gpr = operand.jsValueRegs().payloadGPR(); DFG_TYPE_CHECK( - operand.jsValueRegs(), edge, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(gpr, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + operand.jsValueRegs(), edge, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(gpr)); MacroAssembler::Jump done = m_jit.jump(); notCell.link(&m_jit); if (needsTypeCheck(edge, SpecCell | SpecOther)) { typeCheck( operand.jsValueRegs(), edge, SpecCell | SpecOther, - branchNotOther(operand.jsValueRegs(), tempGPR)); + m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR)); } done.link(&m_jit); } @@ -4621,11 +5604,7 @@ void SpeculativeJIT::speculateObjectOrOther(Edge edge) void SpeculativeJIT::speculateString(Edge edge, GPRReg cell) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCell, - m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(cell, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCell, m_jit.branchIfNotString(cell)); } void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage) @@ -4727,13 +5706,10 @@ void SpeculativeJIT::speculateNotStringVar(Edge edge) GPRTemporary temp(this); GPRReg tempGPR = temp.gpr(); - JITCompiler::Jump notCell = branchNotCell(operand.jsValueRegs()); + JITCompiler::Jump notCell = m_jit.branchIfNotCell(operand.jsValueRegs()); GPRReg cell = operand.jsValueRegs().payloadGPR(); - JITCompiler::Jump notString = m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(cell, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get()); + JITCompiler::Jump notString = m_jit.branchIfNotString(cell); speculateStringIdentAndLoadStorage(edge, cell, tempGPR); @@ -4747,7 +5723,7 @@ void SpeculativeJIT::speculateNotCell(Edge edge) return; JSValueOperand operand(this, edge, ManualOperandSpeculation); - typeCheck(operand.jsValueRegs(), edge, ~SpecCell, branchIsCell(operand.jsValueRegs())); + typeCheck(operand.jsValueRegs(), edge, ~SpecCell, m_jit.branchIfCell(operand.jsValueRegs())); } void SpeculativeJIT::speculateOther(Edge edge) @@ -4760,7 +5736,7 @@ void SpeculativeJIT::speculateOther(Edge edge) GPRReg tempGPR = temp.gpr(); typeCheck( operand.jsValueRegs(), edge, SpecOther, - branchNotOther(operand.jsValueRegs(), tempGPR)); + m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR)); } void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs) @@ -4814,8 +5790,11 @@ void SpeculativeJIT::speculate(Node*, Edge edge) case NumberUse: speculateNumber(edge); break; + case RealNumberUse: + speculateRealNumber(edge); + break; case DoubleRepRealUse: - speculateDoubleReal(edge); + speculateDoubleRepReal(edge); break; #if USE(JSVALUE64) case MachineIntUse: @@ -4834,6 +5813,9 @@ void SpeculativeJIT::speculate(Node*, Edge edge) case ObjectUse: speculateObject(edge); break; + case FunctionUse: + speculateFunction(edge); + break; case FinalObjectUse: speculateFinalObject(edge); break; @@ -5004,14 +5986,9 @@ void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data) op1.use(); - addBranch(branchNotCell(op1Regs), data->fallThrough.block); + addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block); - addBranch( - m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get()), - data->fallThrough.block); + addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block); emitSwitchCharStringJump(data, op1Regs.payloadGPR(), tempGPR); noResult(node, UseChildrenCalledExplicitly); @@ -5024,18 +6001,6 @@ void SpeculativeJIT::emitSwitchChar(Node* node, SwitchData* data) } } -bool SpeculativeJIT::StringSwitchCase::operator<( - const SpeculativeJIT::StringSwitchCase& other) const -{ - unsigned minLength = std::min(string->length(), other.string->length()); - for (unsigned i = 0; i < minLength; ++i) { - if (string->at(i) == other.string->at(i)) - continue; - return string->at(i) < other.string->at(i); - } - return string->length() < other.string->length(); -} - namespace { struct CharacterCase { @@ -5294,14 +6259,9 @@ void SpeculativeJIT::emitSwitchString(Node* node, SwitchData* data) op1.use(); - addBranch(branchNotCell(op1Regs), data->fallThrough.block); + addBranch(m_jit.branchIfNotCell(op1Regs), data->fallThrough.block); - addBranch( - m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(op1Regs.payloadGPR(), JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get()), - data->fallThrough.block); + addBranch(m_jit.branchIfNotString(op1Regs.payloadGPR()), data->fallThrough.block); emitSwitchStringOnString(data, op1Regs.payloadGPR()); noResult(node, UseChildrenCalledExplicitly); @@ -5329,6 +6289,10 @@ void SpeculativeJIT::emitSwitch(Node* node) case SwitchString: { emitSwitchString(node, data); return; + } + case SwitchCell: { + DFG_CRASH(m_jit.graph(), node, "Bad switch kind"); + return; } } RELEASE_ASSERT_NOT_REACHED(); } @@ -5350,36 +6314,13 @@ void SpeculativeJIT::linkBranches() #if ENABLE(GGC) void SpeculativeJIT::compileStoreBarrier(Node* node) { - switch (node->op()) { - case StoreBarrier: { - SpeculateCellOperand base(this, node->child1()); - GPRTemporary scratch1(this); - GPRTemporary scratch2(this); + ASSERT(node->op() == StoreBarrier); - writeBarrier(base.gpr(), scratch1.gpr(), scratch2.gpr()); - break; - } - - case StoreBarrierWithNullCheck: { - JSValueOperand base(this, node->child1()); - GPRTemporary scratch1(this); - GPRTemporary scratch2(this); + SpeculateCellOperand base(this, node->child1()); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); -#if USE(JSVALUE64) - JITCompiler::Jump isNull = m_jit.branchTest64(JITCompiler::Zero, base.gpr()); - writeBarrier(base.gpr(), scratch1.gpr(), scratch2.gpr()); -#else - JITCompiler::Jump isNull = m_jit.branch32(JITCompiler::Equal, base.tagGPR(), TrustedImm32(JSValue::EmptyValueTag)); - writeBarrier(base.payloadGPR(), scratch1.gpr(), scratch2.gpr()); -#endif - isNull.link(&m_jit); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } + writeBarrier(base.gpr(), scratch1.gpr(), scratch2.gpr()); noResult(node); } @@ -5387,15 +6328,14 @@ void SpeculativeJIT::compileStoreBarrier(Node* node) void SpeculativeJIT::storeToWriteBarrierBuffer(GPRReg cell, GPRReg scratch1, GPRReg scratch2) { ASSERT(scratch1 != scratch2); - WriteBarrierBuffer* writeBarrierBuffer = &m_jit.vm()->heap.m_writeBarrierBuffer; - m_jit.move(TrustedImmPtr(writeBarrierBuffer), scratch1); - m_jit.load32(MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset()), scratch2); - JITCompiler::Jump needToFlush = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::capacityOffset())); + WriteBarrierBuffer& writeBarrierBuffer = m_jit.vm()->heap.m_writeBarrierBuffer; + m_jit.load32(writeBarrierBuffer.currentIndexAddress(), scratch2); + JITCompiler::Jump needToFlush = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, MacroAssembler::TrustedImm32(writeBarrierBuffer.capacity())); m_jit.add32(TrustedImm32(1), scratch2); - m_jit.store32(scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset())); + m_jit.store32(scratch2, writeBarrierBuffer.currentIndexAddress()); - m_jit.loadPtr(MacroAssembler::Address(scratch1, WriteBarrierBuffer::bufferOffset()), scratch1); + m_jit.move(TrustedImmPtr(writeBarrierBuffer.buffer()), scratch1); // We use an offset of -sizeof(void*) because we already added 1 to scratch2. m_jit.storePtr(cell, MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::ScalePtr, static_cast<int32_t>(-sizeof(void*)))); @@ -5409,47 +6349,11 @@ void SpeculativeJIT::storeToWriteBarrierBuffer(GPRReg cell, GPRReg scratch1, GPR done.link(&m_jit); } -void SpeculativeJIT::storeToWriteBarrierBuffer(JSCell* cell, GPRReg scratch1, GPRReg scratch2) -{ - ASSERT(scratch1 != scratch2); - WriteBarrierBuffer* writeBarrierBuffer = &m_jit.vm()->heap.m_writeBarrierBuffer; - m_jit.move(TrustedImmPtr(writeBarrierBuffer), scratch1); - m_jit.load32(MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset()), scratch2); - JITCompiler::Jump needToFlush = m_jit.branch32(MacroAssembler::AboveOrEqual, scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::capacityOffset())); - - m_jit.add32(TrustedImm32(1), scratch2); - m_jit.store32(scratch2, MacroAssembler::Address(scratch1, WriteBarrierBuffer::currentIndexOffset())); - - m_jit.loadPtr(MacroAssembler::Address(scratch1, WriteBarrierBuffer::bufferOffset()), scratch1); - // We use an offset of -sizeof(void*) because we already added 1 to scratch2. - m_jit.storePtr(TrustedImmPtr(cell), MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::ScalePtr, static_cast<int32_t>(-sizeof(void*)))); - - JITCompiler::Jump done = m_jit.jump(); - needToFlush.link(&m_jit); - - // Call C slow path - silentSpillAllRegisters(InvalidGPRReg); - callOperation(operationFlushWriteBarrierBuffer, cell); - silentFillAllRegisters(InvalidGPRReg); - - done.link(&m_jit); -} - -void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, JSCell* value, GPRReg scratch1, GPRReg scratch2) -{ - if (Heap::isMarked(value)) - return; - - JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR); - storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2); - ownerNotMarkedOrAlreadyRemembered.link(&m_jit); -} - void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg scratch1, GPRReg scratch2) { - JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR); + JITCompiler::Jump ownerIsRememberedOrInEden = m_jit.jumpIfIsRememberedOrInEden(ownerGPR); storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2); - ownerNotMarkedOrAlreadyRemembered.link(&m_jit); + ownerIsRememberedOrInEden.link(&m_jit); } #else void SpeculativeJIT::compileStoreBarrier(Node* node) diff --git a/dfg/DFGSpeculativeJIT.h b/dfg/DFGSpeculativeJIT.h index da17fb3..8798b6d 100644 --- a/dfg/DFGSpeculativeJIT.h +++ b/dfg/DFGSpeculativeJIT.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -291,13 +291,10 @@ public: #if ENABLE(GGC) void storeToWriteBarrierBuffer(GPRReg cell, GPRReg scratch1, GPRReg scratch2); - void storeToWriteBarrierBuffer(JSCell*, GPRReg scratch1, GPRReg scratch2); void writeBarrier(GPRReg owner, GPRReg scratch1, GPRReg scratch2); - void writeBarrier(GPRReg owner, JSCell* value, GPRReg scratch1, GPRReg scratch2); void writeBarrier(GPRReg owner, GPRReg value, Edge valueUse, GPRReg scratch1, GPRReg scratch2); - void writeBarrier(JSCell* owner, GPRReg value, Edge valueUse, GPRReg scratch1, GPRReg scratch2); #endif void compileStoreBarrier(Node*); @@ -316,7 +313,7 @@ public: GPRReg fillSpeculateBoolean(Edge); GeneratedOperandType checkGeneratedTypeForToInt32(Node*); - void addSlowPathGenerator(PassOwnPtr<SlowPathGenerator>); + void addSlowPathGenerator(std::unique_ptr<SlowPathGenerator>); void runSlowPathGenerators(); void compile(Node*); @@ -556,30 +553,7 @@ public: bool isKnownNotNumber(Node* node) { return !(m_state.forNode(node).m_type & SpecFullNumber); } bool isKnownNotCell(Node* node) { return !(m_state.forNode(node).m_type & SpecCell); } - // Checks/accessors for constant values. - bool isConstant(Node* node) { return m_jit.graph().isConstant(node); } - bool isJSConstant(Node* node) { return m_jit.graph().isJSConstant(node); } - bool isInt32Constant(Node* node) { return m_jit.graph().isInt32Constant(node); } - bool isDoubleConstant(Node* node) { return m_jit.graph().isDoubleConstant(node); } - bool isNumberConstant(Node* node) { return m_jit.graph().isNumberConstant(node); } - bool isBooleanConstant(Node* node) { return m_jit.graph().isBooleanConstant(node); } - bool isFunctionConstant(Node* node) { return m_jit.graph().isFunctionConstant(node); } - int32_t valueOfInt32Constant(Node* node) { return m_jit.graph().valueOfInt32Constant(node); } - double valueOfNumberConstant(Node* node) { return m_jit.graph().valueOfNumberConstant(node); } -#if USE(JSVALUE32_64) - void* addressOfDoubleConstant(Node* node) { return m_jit.addressOfDoubleConstant(node); } -#endif - JSValue valueOfJSConstant(Node* node) { return m_jit.graph().valueOfJSConstant(node); } - bool valueOfBooleanConstant(Node* node) { return m_jit.graph().valueOfBooleanConstant(node); } - JSFunction* valueOfFunctionConstant(Node* node) { return m_jit.graph().valueOfFunctionConstant(node); } - bool isNullConstant(Node* node) - { - if (!isConstant(node)) - return false; - return valueOfJSConstant(node).isNull(); - } - - StringImpl* identifierUID(unsigned index) + UniquedStringImpl* identifierUID(unsigned index) { return m_jit.graph().identifiers()[index]; } @@ -601,7 +575,6 @@ public: } } -#ifndef NDEBUG // Used to ASSERT flushRegisters() has been called prior to // calling out from JIT code to a C helper function. bool isFlushed() @@ -616,12 +589,11 @@ public: } return true; } -#endif #if USE(JSVALUE64) - MacroAssembler::Imm64 valueOfJSConstantAsImm64(Node* node) + static MacroAssembler::Imm64 valueOfJSConstantAsImm64(Node* node) { - return MacroAssembler::Imm64(JSValue::encode(valueOfJSConstant(node))); + return MacroAssembler::Imm64(JSValue::encode(node->asJSValue())); } #endif @@ -706,7 +678,7 @@ public: } // Check if the lastNode is a branch on this node. - Node* lastNode = m_block->last(); + Node* lastNode = m_block->terminal(); return lastNode->op() == Branch && lastNode->child1() == m_currentNode ? m_block->size() - 1 : UINT_MAX; } @@ -740,57 +712,8 @@ public: void compileInstanceOfForObject(Node*, GPRReg valueReg, GPRReg prototypeReg, GPRReg scratchAndResultReg, GPRReg scratch2Reg); void compileInstanceOf(Node*); - ptrdiff_t calleeFrameOffset(int numArgs) - { - return virtualRegisterForLocal(m_jit.graph().m_nextMachineLocal - 1 + JSStack::CallFrameHeaderSize + numArgs).offset() * sizeof(Register); - } - - // Access to our fixed callee CallFrame. - MacroAssembler::Address calleeFrameSlot(int slot) - { - ASSERT(slot >= JSStack::CallerFrameAndPCSize); - return MacroAssembler::Address(MacroAssembler::stackPointerRegister, sizeof(Register) * (slot - JSStack::CallerFrameAndPCSize)); - } - - // Access to our fixed callee CallFrame. - MacroAssembler::Address calleeArgumentSlot(int argument) - { - return calleeFrameSlot(virtualRegisterForArgument(argument).offset()); - } - - MacroAssembler::Address calleeFrameTagSlot(int slot) - { - return calleeFrameSlot(slot).withOffset(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - } - - MacroAssembler::Address calleeFramePayloadSlot(int slot) - { - return calleeFrameSlot(slot).withOffset(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - } - - MacroAssembler::Address calleeArgumentTagSlot(int argument) - { - return calleeArgumentSlot(argument).withOffset(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)); - } - - MacroAssembler::Address calleeArgumentPayloadSlot(int argument) - { - return calleeArgumentSlot(argument).withOffset(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)); - } - - MacroAssembler::Address calleeFrameCallerFrame() - { - return calleeFrameSlot(0).withOffset(CallFrame::callerFrameOffset()); - } - void emitCall(Node*); - int32_t framePointerOffsetToGetActivationRegisters() - { - return m_jit.codeBlock()->framePointerOffsetToGetActivationRegisters( - m_jit.graph().m_machineCaptureStart); - } - // Called once a node has completed code generation but prior to setting // its result, to free up its children. (This must happen prior to setting // the nodes result, since the node may have the same VirtualRegister as @@ -866,13 +789,7 @@ public: #if USE(JSVALUE64) jsValueResult(reg, node, DataFormatJSBoolean, mode); #else - if (mode == CallUseChildren) - useChildren(node); - - VirtualRegister virtualRegister = node->virtualRegister(); - m_gprs.retain(reg, virtualRegister, SpillOrderBoolean); - GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); - info.initBoolean(node, node->refCount(), reg); + booleanResult(reg, node, mode); #endif } void unblessedBooleanResult(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren) @@ -957,7 +874,7 @@ public: } void initConstantInfo(Node* node) { - ASSERT(isInt32Constant(node) || isNumberConstant(node) || isJSConstant(node)); + ASSERT(node->hasConstant()); generationInfo(node).initConstant(node, node->refCount()); } @@ -967,6 +884,11 @@ public: // machine registers, and delegate the calling convention specific // decision as to how to fill the regsiters to setupArguments* methods. + JITCompiler::Call callOperation(V_JITOperation_E operation) + { + m_jit.setupArgumentsExecState(); + return appendCallWithExceptionCheck(operation); + } JITCompiler::Call callOperation(P_JITOperation_E operation, GPRReg result) { m_jit.setupArgumentsExecState(); @@ -1057,7 +979,17 @@ public: m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell)); return appendCallWithExceptionCheckSetResult(operation, result); } - JITCompiler::Call callOperation(C_JITOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell) + JITCompiler::Call callOperation(C_JITOperation_ECZ operation, GPRReg result, GPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_ECZC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EJscC operation, GPRReg result, GPRReg arg1, JSCell* cell) { m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); return appendCallWithExceptionCheckSetResult(operation, result); @@ -1072,6 +1004,31 @@ public: m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure)); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(C_JITOperation_EStJscSymtab operation, GPRReg result, Structure* structure, GPRReg scope, SymbolTable* table) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), scope, TrustedImmPtr(table)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EStZ operation, GPRReg result, Structure* structure, unsigned knownLength) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImm32(knownLength)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EStZZ operation, GPRReg result, Structure* structure, unsigned knownLength, unsigned minCapacity) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImm32(knownLength), TrustedImm32(minCapacity)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EStZ operation, GPRReg result, Structure* structure, GPRReg length) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), length); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EStZZ operation, GPRReg result, Structure* structure, GPRReg length, unsigned minCapacity) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), length, TrustedImm32(minCapacity)); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(C_JITOperation_EJssSt operation, GPRReg result, GPRReg arg1, Structure* structure) { m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(structure)); @@ -1094,6 +1051,18 @@ public: return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(S_JITOperation_EGC operation, GPRReg result, JSGlobalObject* globalObject, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(globalObject), arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + + JITCompiler::Call callOperation(C_JITOperation_EGC operation, GPRReg result, JSGlobalObject* globalObject, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(globalObject), arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(Jss_JITOperation_EZ operation, GPRReg result, GPRReg arg1) { m_jit.setupArgumentsWithExecState(arg1); @@ -1155,7 +1124,17 @@ public: m_jit.setupArgumentsExecState(); return appendCallWithCallFrameRollbackOnExceptionSetResult(operation, result); } + JITCompiler::Call callOperation(Z_JITOperation_EC operation, GPRReg result, GPRReg arg1) + { + m_jit.setupArgumentsWithExecState(arg1); + return appendCallWithExceptionCheckSetResult(operation, result); + } + template<typename FunctionType> + JITCompiler::Call callOperation(FunctionType operation, NoResultTag) + { + return callOperation(operation); + } template<typename FunctionType, typename ArgumentType1> JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1) { @@ -1197,11 +1176,16 @@ public: m_jit.setupArguments(arg1, arg2); return appendCallSetResult(operation, result); } - JITCompiler::Call callOperation(I_JITOperation_EJss operation, GPRReg result, GPRReg arg1) + JITCompiler::Call callOperation(T_JITOperation_EJss operation, GPRReg result, GPRReg arg1) { m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(C_JITOperation_EJscZ operation, GPRReg result, GPRReg arg1, int32_t arg2) + { + m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2)); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(C_JITOperation_EZ operation, GPRReg result, GPRReg arg1) { m_jit.setupArgumentsWithExecState(arg1); @@ -1213,6 +1197,18 @@ public: return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(J_JITOperation_EJscC operation, GPRReg result, GPRReg arg1, JSCell* cell) + { + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + + JITCompiler::Call callOperation(V_JITOperation_EWs operation, WatchpointSet* watchpointSet) + { + m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet)); + return appendCall(operation); + } + #if USE(JSVALUE64) JITCompiler::Call callOperation(J_JITOperation_E operation, GPRReg result) { @@ -1241,7 +1237,7 @@ public: m_jit.setupArguments(value); return appendCallSetResult(operation, result); } - JITCompiler::Call callOperation(J_JITOperation_EI operation, GPRReg result, StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_EI operation, GPRReg result, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, result); @@ -1281,12 +1277,17 @@ public: m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell)); return appendCallWithExceptionCheckSetResult(operation, result); } - JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg result, StructureStubInfo* stubInfo, GPRReg arg1, const StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_ECZ operation, GPRReg result, GPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg result, StructureStubInfo* stubInfo, GPRReg arg1, const UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, result); } - JITCompiler::Call callOperation(J_JITOperation_ESsiJI operation, GPRReg result, StructureStubInfo* stubInfo, GPRReg arg1, StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_ESsiJI operation, GPRReg result, StructureStubInfo* stubInfo, GPRReg arg1, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, result); @@ -1296,6 +1297,16 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(J_JITOperation_EJC operation, GPRReg result, GPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(J_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(J_JITOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2) { m_jit.setupArgumentsWithExecState(arg1, arg2); @@ -1344,6 +1355,21 @@ public: m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(C_JITOperation_EJJC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(C_JITOperation_EJZC operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); + return appendCallWithExceptionCheckSetResult(operation, result); + } JITCompiler::Call callOperation(S_JITOperation_J operation, GPRReg result, GPRReg arg1) { m_jit.setupArguments(arg1); @@ -1416,7 +1442,7 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(pointer)); return appendCallWithExceptionCheck(operation); } - JITCompiler::Call callOperation(V_JITOperation_ESsiJJI operation, StructureStubInfo* stubInfo, GPRReg arg1, GPRReg arg2, StringImpl* uid) + JITCompiler::Call callOperation(V_JITOperation_ESsiJJI operation, StructureStubInfo* stubInfo, GPRReg arg1, GPRReg arg2, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, arg2, TrustedImmPtr(uid)); return appendCallWithExceptionCheck(operation); @@ -1443,18 +1469,32 @@ public: return appendCallWithExceptionCheck(operation); } - JITCompiler::Call callOperation(V_JITOperation_EVwsJ operation, VariableWatchpointSet* watchpointSet, GPRReg arg) - { - m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet), arg); - return appendCall(operation); - } - JITCompiler::Call callOperation(D_JITOperation_EJ operation, FPRReg result, GPRReg arg1) { m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(Z_JITOperation_EJZZ operation, GPRReg result, GPRReg arg1, unsigned arg2, unsigned arg3) + { + m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2), TrustedImm32(arg3)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(F_JITOperation_EFJZZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, unsigned arg3, GPRReg arg4) + { + m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImm32(arg3), arg4); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(Z_JITOperation_EJZ operation, GPRReg result, GPRReg arg1, unsigned arg2) + { + m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(V_JITOperation_EZJZZZ operation, unsigned arg1, GPRReg arg2, unsigned arg3, GPRReg arg4, unsigned arg5) + { + m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2, TrustedImm32(arg3), arg4, TrustedImm32(arg5)); + return appendCallWithExceptionCheck(operation); + } #else // USE(JSVALUE32_64) // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). @@ -1502,7 +1542,7 @@ public: m_jit.setupArgumentsWithExecState(arg1); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } - JITCompiler::Call callOperation(J_JITOperation_EI operation, GPRReg resultTag, GPRReg resultPayload, StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_EI operation, GPRReg resultTag, GPRReg resultPayload, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); @@ -1517,6 +1557,16 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_JITOperation_EJ operation, GPRReg resultPayload, GPRReg resultTag, GPRReg arg1) + { + m_jit.setupArgumentsWithExecState(arg1); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } + JITCompiler::Call callOperation(J_JITOperation_EJC 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_JITOperation_EJssZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2) { m_jit.setupArgumentsWithExecState(arg1, arg2); @@ -1548,17 +1598,27 @@ public: m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } - JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1, const StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_ECZ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2) + { + m_jit.setupArgumentsWithExecState(arg1, arg2); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } + JITCompiler::Call callOperation(J_JITOperation_EJscC operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, JSCell* cell) + { + m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell)); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } + JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1, const UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } - JITCompiler::Call callOperation(J_JITOperation_ESsiJI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1Tag, GPRReg arg1Payload, StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_ESsiJI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1Tag, GPRReg arg1Payload, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1Payload, arg1Tag, TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } - JITCompiler::Call callOperation(J_JITOperation_ESsiJI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, int32_t arg1Tag, GPRReg arg1Payload, StringImpl* uid) + JITCompiler::Call callOperation(J_JITOperation_ESsiJI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, int32_t arg1Tag, GPRReg arg1Payload, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(uid)); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); @@ -1658,6 +1718,11 @@ public: m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag); return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); } + JITCompiler::Call callOperation(J_JITOperation_ECJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Payload) + { + m_jit.setupArgumentsWithExecState(arg1, arg2Payload, MacroAssembler::TrustedImm32(JSValue::CellTag)); + return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag); + } JITCompiler::Call callOperation(J_JITOperation_ECJ operation, JSValueRegs result, GPRReg arg1, JSValueRegs arg2) { m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR()); @@ -1686,7 +1751,7 @@ public: m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, arg2, TrustedImmPtr(pointer)); return appendCallWithExceptionCheck(operation); } - JITCompiler::Call callOperation(V_JITOperation_ESsiJJI operation, StructureStubInfo* stubInfo, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Payload, StringImpl* uid) + JITCompiler::Call callOperation(V_JITOperation_ESsiJJI operation, StructureStubInfo* stubInfo, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Payload, UniquedStringImpl* uid) { m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1Payload, arg1Tag, arg2Payload, TrustedImm32(JSValue::CellTag), TrustedImmPtr(uid)); return appendCallWithExceptionCheck(operation); @@ -1714,18 +1779,32 @@ public: return appendCallWithExceptionCheck(operation); } - JITCompiler::Call callOperation(V_JITOperation_EVwsJ operation, VariableWatchpointSet* watchpointSet, GPRReg argTag, GPRReg argPayload) - { - m_jit.setupArgumentsWithExecState(TrustedImmPtr(watchpointSet), argPayload, argTag); - return appendCall(operation); - } - JITCompiler::Call callOperation(D_JITOperation_EJ operation, FPRReg result, GPRReg arg1Tag, GPRReg arg1Payload) { m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag); return appendCallWithExceptionCheckSetResult(operation, result); } + JITCompiler::Call callOperation(Z_JITOperation_EJZZ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload, unsigned arg2, unsigned arg3) + { + m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, TrustedImm32(arg2), TrustedImm32(arg3)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(F_JITOperation_EFJZZ operation, GPRReg result, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, unsigned arg3, GPRReg arg4) + { + m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, TrustedImm32(arg3), arg4); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(Z_JITOperation_EJZ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload, unsigned arg2) + { + m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, TrustedImm32(arg2)); + return appendCallWithExceptionCheckSetResult(operation, result); + } + JITCompiler::Call callOperation(V_JITOperation_EZJZZZ operation, unsigned arg1, GPRReg arg2Tag, GPRReg arg2Payload, unsigned arg3, GPRReg arg4, unsigned arg5) + { + m_jit.setupArgumentsWithExecState(TrustedImm32(arg1), arg2Payload, arg2Tag, TrustedImm32(arg3), arg4, TrustedImm32(arg5)); + return appendCallWithExceptionCheck(operation); + } #undef EABI_32BIT_DUMMY_ARG #undef SH4_32BIT_DUMMY_ARG @@ -1993,17 +2072,6 @@ public: void dump(const char* label = 0); - bool isInteger(Node* node) - { - if (node->hasInt32Result()) - return true; - - if (isInt32Constant(node)) - return true; - - return generationInfo(node).isJSInt32(); - } - bool betterUseStrictInt52(Node* node) { return !generationInfo(node).isInt52(); @@ -2020,8 +2088,10 @@ public: void compilePeepHoleBooleanBranch(Node*, Node* branchNode, JITCompiler::RelationalCondition); void compilePeepHoleDoubleBranch(Node*, Node* branchNode, JITCompiler::DoubleCondition); void compilePeepHoleObjectEquality(Node*, Node* branchNode); + void compilePeepHoleObjectStrictEquality(Edge objectChild, Edge otherChild, Node* branchNode); void compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild, Node* branchNode); void compileObjectEquality(Node*); + void compileObjectStrictEquality(Edge objectChild, Edge otherChild); void compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild); void compileObjectOrOtherLogicalNot(Edge value); void compileLogicalNot(Node*); @@ -2038,6 +2108,7 @@ public: void compileMiscStrictEq(Node*); void emitObjectOrOtherBranch(Edge value, BasicBlock* taken, BasicBlock* notTaken); + void emitStringBranch(Edge value, BasicBlock* taken, BasicBlock* notTaken); void emitBranch(Node*); struct StringSwitchCase { @@ -2049,7 +2120,10 @@ public: { } - bool operator<(const StringSwitchCase& other) const; + bool operator<(const StringSwitchCase& other) const + { + return stringLessThan(*string, *other.string); + } StringImpl* string; BasicBlock* target; @@ -2067,7 +2141,7 @@ public: void emitSwitchString(Node*, SwitchData*); void emitSwitch(Node*); - void compileToStringOnCell(Node*); + void compileToStringOrCallStringConstructorOnCell(Node*); void compileNewStringObject(Node*); void compileNewTypedArray(Node*); @@ -2101,9 +2175,12 @@ public: void compileGetByValOnString(Node*); void compileFromCharCode(Node*); - void compileGetByValOnArguments(Node*); - void compileGetArgumentsLength(Node*); + void compileGetByValOnDirectArguments(Node*); + void compileGetByValOnScopedArguments(Node*); + void compileGetScope(Node*); + void compileSkipScope(Node*); + void compileGetArrayLength(Node*); void compileValueRep(Node*); @@ -2114,11 +2191,16 @@ public: void compileDoubleAsInt32(Node*); void compileAdd(Node*); void compileMakeRope(Node*); + void compileArithClz32(Node*); void compileArithSub(Node*); void compileArithNegate(Node*); void compileArithMul(Node*); void compileArithDiv(Node*); void compileArithMod(Node*); + void compileArithPow(Node*); + void compileArithRound(Node*); + void compileArithSqrt(Node*); + void compileArithLog(Node*); void compileConstantStoragePointer(Node*); void compileGetIndexedPropertyStorage(Node*); JITCompiler::Jump jumpForTypedArrayOutOfBounds(Node*, GPRReg baseGPR, GPRReg indexGPR); @@ -2128,14 +2210,19 @@ public: void compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType); void compileGetByValOnFloatTypedArray(Node*, TypedArrayType); void compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType); - void compileNewFunctionNoCheck(Node*); - void compileNewFunctionExpression(Node*); + void compileNewFunction(Node*); + void compileForwardVarargs(Node*); + void compileCreateActivation(Node*); + void compileCreateDirectArguments(Node*); + void compileGetFromArguments(Node*); + void compilePutToArguments(Node*); + void compileCreateScopedArguments(Node*); + void compileCreateClonedArguments(Node*); + void compileNotifyWrite(Node*); bool compileRegExpExec(Node*); - - JITCompiler::Jump branchIsCell(JSValueRegs); - JITCompiler::Jump branchNotCell(JSValueRegs); - JITCompiler::Jump branchIsOther(JSValueRegs, GPRReg tempGPR); - JITCompiler::Jump branchNotOther(JSValueRegs, GPRReg tempGPR); + void compileIsObjectOrNull(Node*); + void compileIsFunction(Node*); + void compileTypeOf(Node*); void moveTrueTo(GPRReg); void moveFalseTo(GPRReg); @@ -2194,21 +2281,49 @@ public: m_jit.storePtr(storage, MacroAssembler::Address(resultGPR, JSObject::butterflyOffset())); } + template <typename ClassType, typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr. + void emitAllocateJSObjectWithKnownSize( + GPRReg resultGPR, StructureType structure, StorageType storage, GPRReg scratchGPR1, + GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath, size_t size) + { + MarkedAllocator* allocator = &m_jit.vm()->heap.allocatorForObjectOfType<ClassType>(size); + m_jit.move(TrustedImmPtr(allocator), scratchGPR1); + emitAllocateJSObject(resultGPR, scratchGPR1, structure, storage, scratchGPR2, slowPath); + } + // Convenience allocator for a built-in object. template <typename ClassType, typename StructureType, typename StorageType> // StructureType and StorageType can be GPR or ImmPtr. void emitAllocateJSObject(GPRReg resultGPR, StructureType structure, StorageType storage, GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath) { - MarkedAllocator* allocator = 0; - size_t size = ClassType::allocationSize(0); - if (ClassType::needsDestruction && ClassType::hasImmortalStructure) - allocator = &m_jit.vm()->heap.allocatorForObjectWithImmortalStructureDestructor(size); - else if (ClassType::needsDestruction) - allocator = &m_jit.vm()->heap.allocatorForObjectWithNormalDestructor(size); - else - allocator = &m_jit.vm()->heap.allocatorForObjectWithoutDestructor(size); - m_jit.move(TrustedImmPtr(allocator), scratchGPR1); - emitAllocateJSObject(resultGPR, scratchGPR1, structure, storage, scratchGPR2, slowPath); + emitAllocateJSObjectWithKnownSize<ClassType>( + resultGPR, structure, storage, scratchGPR1, scratchGPR2, slowPath, + ClassType::allocationSize(0)); + } + + template <typename ClassType, typename StructureType> // StructureType and StorageType can be GPR or ImmPtr. + void emitAllocateVariableSizedJSObject(GPRReg resultGPR, StructureType structure, GPRReg allocationSize, GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath) + { + static_assert(!(MarkedSpace::preciseStep & (MarkedSpace::preciseStep - 1)), "MarkedSpace::preciseStep must be a power of two."); + static_assert(!(MarkedSpace::impreciseStep & (MarkedSpace::impreciseStep - 1)), "MarkedSpace::impreciseStep must be a power of two."); + + MarkedSpace::Subspace& subspace = m_jit.vm()->heap.subspaceForObjectOfType<ClassType>(); + m_jit.add32(TrustedImm32(MarkedSpace::preciseStep - 1), allocationSize); + MacroAssembler::Jump notSmall = m_jit.branch32(MacroAssembler::AboveOrEqual, allocationSize, TrustedImm32(MarkedSpace::preciseCutoff)); + m_jit.rshift32(allocationSize, TrustedImm32(getLSBSet(MarkedSpace::preciseStep)), scratchGPR1); + m_jit.mul32(TrustedImm32(sizeof(MarkedAllocator)), scratchGPR1, scratchGPR1); + m_jit.addPtr(MacroAssembler::TrustedImmPtr(&subspace.preciseAllocators[0]), scratchGPR1); + + MacroAssembler::Jump selectedSmallSpace = m_jit.jump(); + notSmall.link(&m_jit); + slowPath.append(m_jit.branch32(MacroAssembler::AboveOrEqual, allocationSize, TrustedImm32(MarkedSpace::impreciseCutoff))); + m_jit.rshift32(allocationSize, TrustedImm32(getLSBSet(MarkedSpace::impreciseStep)), scratchGPR1); + m_jit.mul32(TrustedImm32(sizeof(MarkedAllocator)), scratchGPR1, scratchGPR1); + m_jit.addPtr(MacroAssembler::TrustedImmPtr(&subspace.impreciseAllocators[0]), scratchGPR1); + + selectedSmallSpace.link(&m_jit); + + emitAllocateJSObject(resultGPR, scratchGPR1, structure, TrustedImmPtr(0), scratchGPR2, slowPath); } template <typename T> @@ -2220,8 +2335,16 @@ public: } void emitAllocateJSArray(GPRReg resultGPR, Structure*, GPRReg storageGPR, unsigned numElements); - void emitAllocateArguments(GPRReg resultGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, MacroAssembler::JumpList& slowPath); - + + void emitGetLength(InlineCallFrame*, GPRReg lengthGPR, bool includeThis = false); + void emitGetLength(CodeOrigin, GPRReg lengthGPR, bool includeThis = false); + void emitGetCallee(CodeOrigin, GPRReg calleeGPR); + void emitGetArgumentStart(CodeOrigin, GPRReg startGPR); + + // Generate an OSR exit fuzz check. Returns Jump() if OSR exit fuzz is not enabled, or if + // it's in training mode. + MacroAssembler::Jump emitOSRExitFuzzCheck(); + // Add a speculation check. void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail); void speculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail); @@ -2245,6 +2368,9 @@ public: bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_interpreter.needsTypeCheck(edge, typesPassedThrough); } void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail); + void speculateCellTypeWithoutTypeFiltering(Edge, GPRReg cellGPR, JSType); + void speculateCellType(Edge, GPRReg cellGPR, SpeculatedType, JSType); + void speculateInt32(Edge); #if USE(JSVALUE64) void convertMachineInt(Edge, GPRReg resultGPR); @@ -2252,10 +2378,12 @@ public: void speculateDoubleRepMachineInt(Edge); #endif // USE(JSVALUE64) void speculateNumber(Edge); - void speculateDoubleReal(Edge); + void speculateRealNumber(Edge); + void speculateDoubleRepReal(Edge); void speculateBoolean(Edge); void speculateCell(Edge); void speculateObject(Edge); + void speculateFunction(Edge); void speculateFinalObject(Edge); void speculateObjectOrOther(Edge); void speculateString(Edge edge, GPRReg cell); @@ -2356,7 +2484,7 @@ public: bool m_isCheckingArgumentTypes; - Vector<OwnPtr<SlowPathGenerator>, 8> m_slowPathGenerators; + Vector<std::unique_ptr<SlowPathGenerator>, 8> m_slowPathGenerators; Vector<SilentRegisterSavePlan> m_plans; }; @@ -2655,18 +2783,18 @@ private: // // These classes lock the result of a call to a C++ helper function. -class GPRResult : public GPRTemporary { +class GPRFlushedCallResult : public GPRTemporary { public: - GPRResult(SpeculativeJIT* jit) + GPRFlushedCallResult(SpeculativeJIT* jit) : GPRTemporary(jit, GPRInfo::returnValueGPR) { } }; #if USE(JSVALUE32_64) -class GPRResult2 : public GPRTemporary { +class GPRFlushedCallResult2 : public GPRTemporary { public: - GPRResult2(SpeculativeJIT* jit) + GPRFlushedCallResult2(SpeculativeJIT* jit) : GPRTemporary(jit, GPRInfo::returnValueGPR2) { } @@ -3130,7 +3258,7 @@ void SpeculativeJIT::speculateStringObjectForStructure(Edge edge, StructureLocat Structure* stringObjectStructure = m_jit.globalObjectFor(m_currentNode->origin.semantic)->stringObjectStructure(); - if (!m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure))) { + if (!m_state.forNode(edge).m_structure.isSubsetOf(StructureSet(stringObjectStructure))) { speculationCheck( NotStringObject, JSValueRegs(), 0, m_jit.branchStructurePtr( diff --git a/dfg/DFGSpeculativeJIT32_64.cpp b/dfg/DFGSpeculativeJIT32_64.cpp index 8b2b696..7e08d9b 100644 --- a/dfg/DFGSpeculativeJIT32_64.cpp +++ b/dfg/DFGSpeculativeJIT32_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * Copyright (C) 2011 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,9 +35,15 @@ #include "DFGOperations.h" #include "DFGSlowPathGenerator.h" #include "Debugger.h" -#include "JSActivation.h" +#include "DirectArguments.h" +#include "GetterSetter.h" +#include "JSEnvironmentRecord.h" +#include "JSLexicalEnvironment.h" +#include "JSPropertyNameEnumerator.h" #include "ObjectPrototype.h" #include "JSCInlines.h" +#include "SetupVarargsFrame.h" +#include "TypeProfilerLog.h" namespace JSC { namespace DFG { @@ -57,11 +63,12 @@ bool SpeculativeJIT::fillJSValue(Edge edge, GPRReg& tagGPR, GPRReg& payloadGPR, if (edge->hasConstant()) { tagGPR = allocate(); payloadGPR = allocate(); - m_jit.move(Imm32(valueOfJSConstant(edge.node()).tag()), tagGPR); - m_jit.move(Imm32(valueOfJSConstant(edge.node()).payload()), payloadGPR); + JSValue value = edge->asJSValue(); + m_jit.move(Imm32(value.tag()), tagGPR); + m_jit.move(Imm32(value.payload()), payloadGPR); m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant); m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant); - info.fillJSValue(*m_stream, tagGPR, payloadGPR, isInt32Constant(edge.node()) ? DataFormatJSInt32 : DataFormatJS); + info.fillJSValue(*m_stream, tagGPR, payloadGPR, DataFormatJS); } else { DataFormat spillFormat = info.spillFormat(); ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage); @@ -106,7 +113,7 @@ bool SpeculativeJIT::fillJSValue(Edge edge, GPRReg& tagGPR, GPRReg& payloadGPR, m_gprs.lock(gpr); } tagGPR = allocate(); - uint32_t tag = JSValue::EmptyValueTag; + int32_t tag = JSValue::EmptyValueTag; DataFormat fillFormat = DataFormatJS; switch (info.registerFormat()) { case DataFormatInt32: @@ -185,8 +192,8 @@ void SpeculativeJIT::cachedGetById( if (slowPathTarget.isSet()) slowCases.append(slowPathTarget); slowCases.append(gen.slowPathJump()); - - OwnPtr<SlowPathGenerator> slowPath; + + std::unique_ptr<SlowPathGenerator> slowPath; if (baseTagGPROrNone == InvalidGPRReg) { slowPath = slowPathCall( slowCases, this, operationGetByIdOptimize, @@ -199,9 +206,9 @@ void SpeculativeJIT::cachedGetById( JSValueRegs(resultTagGPR, resultPayloadGPR), gen.stubInfo(), baseTagGPROrNone, basePayloadGPR, identifierUID(identifierNumber)); } - + m_jit.addGetById(gen, slowPath.get()); - addSlowPathGenerator(slowPath.release()); + addSlowPathGenerator(WTF::move(slowPath)); } void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode) @@ -218,12 +225,12 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, slowCases.append(slowPathTarget); slowCases.append(gen.slowPathJump()); - OwnPtr<SlowPathGenerator> slowPath = slowPathCall( + auto slowPath = slowPathCall( slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueTagGPR, valuePayloadGPR, basePayloadGPR, identifierUID(identifierNumber)); m_jit.addPutById(gen, slowPath.get()); - addSlowPathGenerator(slowPath.release()); + addSlowPathGenerator(WTF::move(slowPath)); } void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert) @@ -239,7 +246,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv JITCompiler::Jump notMasqueradesAsUndefined; if (masqueradesAsUndefinedWatchpointIsStillValid()) { if (!isKnownCell(operand.node())) - notCell = branchNotCell(arg.jsValueRegs()); + notCell = m_jit.branchIfNotCell(arg.jsValueRegs()); m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR); notMasqueradesAsUndefined = m_jit.jump(); @@ -248,7 +255,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv GPRTemporary remoteGlobalObject(this); if (!isKnownCell(operand.node())) - notCell = branchNotCell(arg.jsValueRegs()); + notCell = m_jit.branchIfNotCell(arg.jsValueRegs()); JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8( JITCompiler::NonZero, @@ -273,8 +280,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv notCell.link(&m_jit); // null or undefined? COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag); - m_jit.move(argTagGPR, resultPayloadGPR); - m_jit.or32(TrustedImm32(1), resultPayloadGPR); + m_jit.or32(TrustedImm32(1), argTagGPR, resultPayloadGPR); m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultPayloadGPR, TrustedImm32(JSValue::NullTag), resultPayloadGPR); done.link(&m_jit); @@ -308,7 +314,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch if (masqueradesAsUndefinedWatchpointIsStillValid()) { if (!isKnownCell(operand.node())) - notCell = branchNotCell(arg.jsValueRegs()); + notCell = m_jit.branchIfNotCell(arg.jsValueRegs()); jump(invert ? taken : notTaken, ForceJump); } else { @@ -316,7 +322,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch GPRTemporary remoteGlobalObject(this); if (!isKnownCell(operand.node())) - notCell = branchNotCell(arg.jsValueRegs()); + notCell = m_jit.branchIfNotCell(arg.jsValueRegs()); branchTest8(JITCompiler::Zero, JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()), @@ -337,8 +343,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch notCell.link(&m_jit); // null or undefined? COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag); - m_jit.move(argTagGPR, resultGPR); - m_jit.or32(TrustedImm32(1), resultGPR); + m_jit.or32(TrustedImm32(1), argTagGPR, resultGPR); branch32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, resultGPR, JITCompiler::TrustedImm32(JSValue::NullTag), taken); } @@ -395,7 +400,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, JITCompiler::JumpList slowPath; if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) { - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); arg1.use(); @@ -486,7 +491,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler JITCompiler::JumpList slowPath; if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) { - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultPayloadGPR = result.gpr(); arg1.use(); @@ -511,10 +516,9 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler m_jit.compare32(cond, arg1PayloadGPR, arg2PayloadGPR, resultPayloadGPR); if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) { - addSlowPathGenerator(adoptPtr( - new CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>( + addSlowPathGenerator(std::make_unique<CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>>( slowPath, this, helperFunction, resultPayloadGPR, arg1TagGPR, - arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR))); + arg1PayloadGPR, arg2TagGPR, arg2PayloadGPR)); } booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly); @@ -637,46 +641,154 @@ void SpeculativeJIT::compileMiscStrictEq(Node* node) void SpeculativeJIT::emitCall(Node* node) { - if (node->op() != Call) - ASSERT(node->op() == Construct); + CallLinkInfo::CallType callType; + bool isVarargs = false; + bool isForwardVarargs = false; + switch (node->op()) { + case Call: + callType = CallLinkInfo::Call; + break; + case Construct: + callType = CallLinkInfo::Construct; + break; + case CallVarargs: + callType = CallLinkInfo::CallVarargs; + isVarargs = true; + break; + case ConstructVarargs: + callType = CallLinkInfo::ConstructVarargs; + isVarargs = true; + break; + case CallForwardVarargs: + callType = CallLinkInfo::CallVarargs; + isForwardVarargs = true; + break; + case ConstructForwardVarargs: + callType = CallLinkInfo::ConstructVarargs; + isForwardVarargs = true; + break; + default: + DFG_CRASH(m_jit.graph(), node, "bad node type"); + break; + } + + Edge calleeEdge = m_jit.graph().child(node, 0); + + // Gotta load the arguments somehow. Varargs is trickier. + if (isVarargs || isForwardVarargs) { + CallVarargsData* data = node->callVarargsData(); - // For constructors, the this argument is not passed but we have to make space - // for it. - int dummyThisArgument = node->op() == Call ? 0 : 1; + GPRReg resultGPR; + unsigned numUsedStackSlots = m_jit.graph().m_nextMachineLocal; + + if (isForwardVarargs) { + flushRegisters(); + use(node->child2()); + + GPRReg scratchGPR1; + GPRReg scratchGPR2; + GPRReg scratchGPR3; + + scratchGPR1 = JITCompiler::selectScratchGPR(); + scratchGPR2 = JITCompiler::selectScratchGPR(scratchGPR1); + scratchGPR3 = JITCompiler::selectScratchGPR(scratchGPR1, scratchGPR2); + + m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR2); + JITCompiler::JumpList slowCase; + emitSetupVarargsFrameFastCase(m_jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, node->child2()->origin.semantic.inlineCallFrame, data->firstVarArgOffset, slowCase); + JITCompiler::Jump done = m_jit.jump(); + slowCase.link(&m_jit); + callOperation(operationThrowStackOverflowForVarargs); + m_jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow); + done.link(&m_jit); + resultGPR = scratchGPR2; + } else { + GPRReg argumentsPayloadGPR; + GPRReg argumentsTagGPR; + GPRReg scratchGPR1; + GPRReg scratchGPR2; + GPRReg scratchGPR3; + + auto loadArgumentsGPR = [&] (GPRReg reservedGPR) { + if (reservedGPR != InvalidGPRReg) + lock(reservedGPR); + JSValueOperand arguments(this, node->child2()); + argumentsTagGPR = arguments.tagGPR(); + argumentsPayloadGPR = arguments.payloadGPR(); + if (reservedGPR != InvalidGPRReg) + unlock(reservedGPR); + flushRegisters(); + + scratchGPR1 = JITCompiler::selectScratchGPR(argumentsPayloadGPR, argumentsTagGPR, reservedGPR); + scratchGPR2 = JITCompiler::selectScratchGPR(argumentsPayloadGPR, argumentsTagGPR, scratchGPR1, reservedGPR); + scratchGPR3 = JITCompiler::selectScratchGPR(argumentsPayloadGPR, argumentsTagGPR, scratchGPR1, scratchGPR2, reservedGPR); + }; + + loadArgumentsGPR(InvalidGPRReg); + + DFG_ASSERT(m_jit.graph(), node, isFlushed()); - CallLinkInfo::CallType callType = node->op() == Call ? CallLinkInfo::Call : CallLinkInfo::Construct; + // Right now, arguments is in argumentsTagGPR/argumentsPayloadGPR and the register file is + // flushed. + callOperation(operationSizeFrameForVarargs, GPRInfo::returnValueGPR, argumentsTagGPR, argumentsPayloadGPR, numUsedStackSlots, data->firstVarArgOffset); + + // Now we have the argument count of the callee frame, but we've lost the arguments operand. + // Reconstruct the arguments operand while preserving the callee frame. + loadArgumentsGPR(GPRInfo::returnValueGPR); + m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR1); + emitSetVarargsFrame(m_jit, GPRInfo::returnValueGPR, false, scratchGPR1, scratchGPR1); + m_jit.addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 6 * sizeof(void*)))), scratchGPR1, JITCompiler::stackPointerRegister); + + callOperation(operationSetupVarargsFrame, GPRInfo::returnValueGPR, scratchGPR1, argumentsTagGPR, argumentsPayloadGPR, data->firstVarArgOffset, GPRInfo::returnValueGPR); + resultGPR = GPRInfo::returnValueGPR; + } + + m_jit.addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), resultGPR, JITCompiler::stackPointerRegister); + + DFG_ASSERT(m_jit.graph(), node, isFlushed()); + + // We don't need the arguments array anymore. + if (isVarargs) + use(node->child2()); + + // Now set up the "this" argument. + JSValueOperand thisArgument(this, node->child3()); + GPRReg thisArgumentTagGPR = thisArgument.tagGPR(); + GPRReg thisArgumentPayloadGPR = thisArgument.payloadGPR(); + thisArgument.use(); + + m_jit.store32(thisArgumentTagGPR, JITCompiler::calleeArgumentTagSlot(0)); + m_jit.store32(thisArgumentPayloadGPR, JITCompiler::calleeArgumentPayloadSlot(0)); + } else { + // The call instruction's first child is either the function (normal call) or the + // receiver (method call). subsequent children are the arguments. + int numPassedArgs = node->numChildren() - 1; + + m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), m_jit.calleeFramePayloadSlot(JSStack::ArgumentCount)); + + for (int i = 0; i < numPassedArgs; i++) { + Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i]; + JSValueOperand arg(this, argEdge); + GPRReg argTagGPR = arg.tagGPR(); + GPRReg argPayloadGPR = arg.payloadGPR(); + use(argEdge); + + m_jit.store32(argTagGPR, m_jit.calleeArgumentTagSlot(i)); + m_jit.store32(argPayloadGPR, m_jit.calleeArgumentPayloadSlot(i)); + } + } - Edge calleeEdge = m_jit.graph().m_varArgChildren[node->firstChild()]; JSValueOperand callee(this, calleeEdge); GPRReg calleeTagGPR = callee.tagGPR(); GPRReg calleePayloadGPR = callee.payloadGPR(); use(calleeEdge); - - // The call instruction's first child is either the function (normal call) or the - // receiver (method call). subsequent children are the arguments. - int numPassedArgs = node->numChildren() - 1; - - int numArgs = numPassedArgs + dummyThisArgument; - - m_jit.store32(MacroAssembler::TrustedImm32(numArgs), calleeFramePayloadSlot(JSStack::ArgumentCount)); - m_jit.store32(calleePayloadGPR, calleeFramePayloadSlot(JSStack::Callee)); - m_jit.store32(calleeTagGPR, calleeFrameTagSlot(JSStack::Callee)); - - for (int i = 0; i < numPassedArgs; i++) { - Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i]; - JSValueOperand arg(this, argEdge); - GPRReg argTagGPR = arg.tagGPR(); - GPRReg argPayloadGPR = arg.payloadGPR(); - use(argEdge); - - m_jit.store32(argTagGPR, calleeArgumentTagSlot(i + dummyThisArgument)); - m_jit.store32(argPayloadGPR, calleeArgumentPayloadSlot(i + dummyThisArgument)); - } + m_jit.store32(calleePayloadGPR, m_jit.calleeFramePayloadSlot(JSStack::Callee)); + m_jit.store32(calleeTagGPR, m_jit.calleeFrameTagSlot(JSStack::Callee)); flushRegisters(); - GPRResult resultPayload(this); - GPRResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); @@ -685,11 +797,10 @@ void SpeculativeJIT::emitCall(Node* node) m_jit.emitStoreCodeOrigin(node->origin.semantic); - slowPath.append(branchNotCell(callee.jsValueRegs())); + CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo(); + + slowPath.append(m_jit.branchIfNotCell(callee.jsValueRegs())); 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, calleeFramePayloadSlot(JSStack::ScopeChain)); - m_jit.storePtr(MacroAssembler::TrustedImm32(JSValue::CellTag), calleeFrameTagSlot(JSStack::ScopeChain)); JITCompiler::Call fastCall = m_jit.nearCall(); @@ -709,7 +820,6 @@ void SpeculativeJIT::emitCall(Node* node) m_jit.move(calleePayloadGPR, GPRInfo::regT0); m_jit.move(calleeTagGPR, GPRInfo::regT1); } - CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo(); m_jit.move(MacroAssembler::TrustedImmPtr(info), GPRInfo::regT2); JITCompiler::Call slowCall = m_jit.nearCall(); @@ -719,10 +829,12 @@ void SpeculativeJIT::emitCall(Node* node) jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly); - info->callType = callType; - info->codeOrigin = node->origin.semantic; - info->calleeGPR = calleePayloadGPR; + info->setUpCall(callType, node->origin.semantic, calleePayloadGPR); m_jit.addJSCall(fastCall, slowCall, targetToCheck, info); + + // If we were varargs, then after the calls are done, we need to reestablish our stack pointer. + if (isVarargs || isForwardVarargs) + m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister); } template<bool strict> @@ -731,22 +843,23 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF AbstractValue& value = m_state.forNode(edge); SpeculatedType type = value.m_type; ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32)); - m_interpreter.filter(value, SpecInt32); - VirtualRegister virtualRegister = edge->virtualRegister(); - GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); - if (edge->hasConstant() && !isInt32Constant(edge.node())) { + m_interpreter.filter(value, SpecInt32); + if (value.isClear()) { terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); returnFormat = DataFormatInt32; return allocate(); } - + + VirtualRegister virtualRegister = edge->virtualRegister(); + GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); + switch (info.registerFormat()) { case DataFormatNone: { if (edge->hasConstant()) { - ASSERT(isInt32Constant(edge.node())); + ASSERT(edge->isInt32Constant()); GPRReg gpr = allocate(); - m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr); + m_jit.move(MacroAssembler::Imm32(edge->asInt32()), gpr); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); info.fillInt32(*m_stream, gpr); returnFormat = DataFormatInt32; @@ -754,6 +867,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF } DataFormat spillFormat = info.spillFormat(); + ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32); // If we know this was spilled as an integer we can fill without checking. @@ -799,10 +913,6 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF case DataFormatJSDouble: case DataFormatJSCell: case DataFormatJSBoolean: - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - returnFormat = DataFormatInt32; - return allocate(); - case DataFormatDouble: case DataFormatStorage: default: @@ -834,9 +944,9 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge) if (info.registerFormat() == DataFormatNone) { if (edge->hasConstant()) { - RELEASE_ASSERT(isNumberConstant(edge.node())); + RELEASE_ASSERT(edge->isNumberConstant()); FPRReg fpr = fprAllocate(); - m_jit.loadDouble(TrustedImmPtr(addressOfDoubleConstant(edge.node())), fpr); + m_jit.loadDouble(TrustedImmPtr(m_jit.addressOfDoubleConstant(edge.node())), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderConstant); info.fillDouble(*m_stream, fpr); return fpr; @@ -861,27 +971,24 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) AbstractValue& value = m_state.forNode(edge); SpeculatedType type = value.m_type; ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell)); + m_interpreter.filter(value, SpecCell); + if (value.isClear()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + return allocate(); + } + VirtualRegister virtualRegister = edge->virtualRegister(); GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); switch (info.registerFormat()) { case DataFormatNone: { - if (info.spillFormat() == DataFormatInt32) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - } - if (edge->hasConstant()) { - JSValue jsValue = valueOfJSConstant(edge.node()); + JSValue jsValue = edge->asJSValue(); GPRReg gpr = allocate(); - if (jsValue.isCell()) { - m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr); - info.fillCell(*m_stream, gpr); - return gpr; - } - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr); + info.fillCell(*m_stream, gpr); return gpr; } @@ -918,7 +1025,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) if (type & ~SpecCell) { speculationCheck( BadType, JSValueRegs(tagGPR, payloadGPR), edge, - branchNotCell(info.jsValueRegs())); + m_jit.branchIfNotCell(info.jsValueRegs())); } m_gprs.unlock(tagGPR); m_gprs.release(tagGPR); @@ -933,9 +1040,6 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) case DataFormatJSDouble: case DataFormatJSBoolean: case DataFormatBoolean: - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - case DataFormatDouble: case DataFormatStorage: RELEASE_ASSERT_NOT_REACHED(); @@ -950,27 +1054,24 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge) { AbstractValue& value = m_state.forNode(edge); SpeculatedType type = value.m_type; + m_interpreter.filter(value, SpecBoolean); + if (value.isClear()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + return allocate(); + } + VirtualRegister virtualRegister = edge->virtualRegister(); GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); switch (info.registerFormat()) { case DataFormatNone: { - if (info.spillFormat() == DataFormatInt32) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - } - if (edge->hasConstant()) { - JSValue jsValue = valueOfJSConstant(edge.node()); + JSValue jsValue = edge->asJSValue(); GPRReg gpr = allocate(); - if (jsValue.isBoolean()) { - m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr); - info.fillBoolean(*m_stream, gpr); - return gpr; - } - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + m_jit.move(MacroAssembler::TrustedImm32(jsValue.asBoolean()), gpr); + info.fillBoolean(*m_stream, gpr); return gpr; } @@ -1014,9 +1115,6 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge) case DataFormatJSDouble: case DataFormatJSCell: case DataFormatCell: - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - case DataFormatDouble: case DataFormatStorage: RELEASE_ASSERT_NOT_REACHED(); @@ -1053,36 +1151,24 @@ void SpeculativeJIT::compileObjectEquality(Node* node) if (masqueradesAsUndefinedWatchpointIsStillValid()) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR)); DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR)); } else { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); - speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), + JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR)); + speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), m_jit.branchTest8( MacroAssembler::NonZero, - MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()), + MacroAssembler::Address(op1GPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(MasqueradesAsUndefined))); DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); - speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), + JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR)); + speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), m_jit.branchTest8( - MacroAssembler::NonZero, - MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()), + MacroAssembler::NonZero, + MacroAssembler::Address(op2GPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(MasqueradesAsUndefined))); } @@ -1099,6 +1185,57 @@ void SpeculativeJIT::compileObjectEquality(Node* node) booleanResult(resultPayloadGPR, node); } +void SpeculativeJIT::compileObjectStrictEquality(Edge objectChild, Edge otherChild) +{ + SpeculateCellOperand op1(this, objectChild); + JSValueOperand op2(this, otherChild); + + GPRReg op1GPR = op1.gpr(); + GPRReg op2GPR = op2.payloadGPR(); + + DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); + + GPRTemporary resultPayload(this, Reuse, op1); + GPRReg resultPayloadGPR = resultPayload.gpr(); + + MacroAssembler::Jump op2CellJump = m_jit.branchIfCell(op2.jsValueRegs()); + + m_jit.move(TrustedImm32(0), resultPayloadGPR); + MacroAssembler::Jump op2NotCellJump = m_jit.jump(); + + // At this point we know that we can perform a straight-forward equality comparison on pointer + // values because we are doing strict equality. + op2CellJump.link(&m_jit); + m_jit.compare32(MacroAssembler::Equal, op1GPR, op2GPR, resultPayloadGPR); + + op2NotCellJump.link(&m_jit); + booleanResult(resultPayloadGPR, m_currentNode); +} + +void SpeculativeJIT::compilePeepHoleObjectStrictEquality(Edge objectChild, Edge otherChild, Node* branchNode) +{ + BasicBlock* taken = branchNode->branchData()->taken.block; + BasicBlock* notTaken = branchNode->branchData()->notTaken.block; + + SpeculateCellOperand op1(this, objectChild); + JSValueOperand op2(this, otherChild); + + GPRReg op1GPR = op1.gpr(); + GPRReg op2GPR = op2.payloadGPR(); + + DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); + + branch32(MacroAssembler::NotEqual, op2.tagGPR(), TrustedImm32(JSValue::CellTag), notTaken); + + if (taken == nextBlock()) { + branch32(MacroAssembler::NotEqual, op1GPR, op2GPR, notTaken); + jump(taken); + } else { + branch32(MacroAssembler::Equal, op1GPR, op2GPR, taken); + jump(notTaken); + } +} + void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild) { SpeculateCellOperand op1(this, leftChild); @@ -1115,16 +1252,10 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); } else { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1135,23 +1266,15 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r // It seems that most of the time when programs do a == b where b may be either null/undefined // or an object, b is usually an object. Balance the branches to make that case fast. - MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs()); + MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(op2.jsValueRegs()); // We know that within this branch, rightChild must be a cell. if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2PayloadGPR)); } else { DFG_TYPE_CHECK( - JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2PayloadGPR)); speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1170,8 +1293,7 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r // We know that within this branch, rightChild must not be a cell. Check if that is enough to // prove that it is either null or undefined. if (needsTypeCheck(rightChild, SpecCell | SpecOther)) { - m_jit.move(op2TagGPR, resultGPR); - m_jit.or32(TrustedImm32(1), resultGPR); + m_jit.or32(TrustedImm32(1), op2TagGPR, resultGPR); typeCheck( JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther, @@ -1209,16 +1331,10 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); } else { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1228,23 +1344,17 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild // It seems that most of the time when programs do a == b where b may be either null/undefined // or an object, b is usually an object. Balance the branches to make that case fast. - MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs()); + MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(op2.jsValueRegs()); // We know that within this branch, rightChild must be a cell. if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(op2PayloadGPR)); } else { DFG_TYPE_CHECK( JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2PayloadGPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(op2PayloadGPR)); speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1265,8 +1375,7 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild jump(notTaken, ForceJump); rightNotCell.link(&m_jit); - m_jit.move(op2TagGPR, resultGPR); - m_jit.or32(TrustedImm32(1), resultGPR); + m_jit.or32(TrustedImm32(1), op2TagGPR, resultGPR); typeCheck( JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther, @@ -1325,23 +1434,15 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse) structureGPR = structure.gpr(); } - MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs()); + MacroAssembler::Jump notCell = m_jit.branchIfNotCell(value.jsValueRegs()); if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(valuePayloadGPR)); } else { - m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR); - DFG_TYPE_CHECK( JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - structureGPR, - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(valuePayloadGPR)); MacroAssembler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8( @@ -1349,6 +1450,7 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse) MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(MasqueradesAsUndefined)); + m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), structureGPR); speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branchPtr( MacroAssembler::Equal, @@ -1364,8 +1466,7 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse) COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag); if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) { - m_jit.move(valueTagGPR, resultPayloadGPR); - m_jit.or32(TrustedImm32(1), resultPayloadGPR); + m_jit.or32(TrustedImm32(1), valueTagGPR, resultPayloadGPR); typeCheck( JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther, m_jit.branch32( @@ -1455,29 +1556,22 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, Ba GPRReg valuePayloadGPR = value.payloadGPR(); GPRReg scratchGPR = scratch.gpr(); - MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs()); + MacroAssembler::Jump notCell = m_jit.branchIfNotCell(value.jsValueRegs()); if (masqueradesAsUndefinedWatchpointIsStillValid()) { DFG_TYPE_CHECK( JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(valuePayloadGPR)); } else { - m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR); - DFG_TYPE_CHECK( JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject, - m_jit.branchPtr( - MacroAssembler::Equal, - scratchGPR, - MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()))); + m_jit.branchIfNotObject(valuePayloadGPR)); JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8( JITCompiler::Zero, MacroAssembler::Address(valuePayloadGPR, JSCell::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)); + m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureIDOffset()), scratchGPR); speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branchPtr( MacroAssembler::Equal, @@ -1492,8 +1586,7 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, Ba COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag); if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) { - m_jit.move(valueTagGPR, scratchGPR); - m_jit.or32(TrustedImm32(1), scratchGPR); + m_jit.or32(TrustedImm32(1), valueTagGPR, scratchGPR); typeCheck( JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag))); @@ -1532,7 +1625,12 @@ void SpeculativeJIT::emitBranch(Node* node) emitObjectOrOtherBranch(node->child1(), taken, notTaken); return; } - + + case StringUse: { + emitStringBranch(node->child1(), taken, notTaken); + return; + } + case DoubleRepUse: case Int32Use: { if (node->child1().useKind() == Int32Use) { @@ -1675,20 +1773,32 @@ void SpeculativeJIT::compile(Node* node) switch (op) { case JSConstant: case DoubleConstant: - initConstantInfo(node); - break; - - case PhantomArguments: - initConstantInfo(node); - break; - - case WeakJSConstant: - m_jit.addWeakReference(node->weakConstant()); + case PhantomDirectArguments: + case PhantomClonedArguments: initConstantInfo(node); break; case Identity: { - RELEASE_ASSERT_NOT_REACHED(); + speculate(node, node->child1()); + switch (node->child1().useKind()) { + case DoubleRepUse: + case DoubleRepRealUse: { + SpeculateDoubleOperand op(this, node->child1()); + doubleResult(op.fpr(), node); + break; + } + case Int52RepUse: + case MachineIntUse: + case DoubleRepMachineIntUse: { + RELEASE_ASSERT_NOT_REACHED(); + break; + } + default: { + JSValueOperand op(this, node->child1()); + jsValueResult(op.tagGPR(), op.payloadGPR(), node); + break; + } + } // switch break; } @@ -1698,9 +1808,7 @@ void SpeculativeJIT::compile(Node* node) // If the CFA is tracking this variable and it found that the variable // cannot have been assigned, then don't attempt to proceed. if (value.isClear()) { - // FIXME: We should trap instead. - // https://bugs.webkit.org/show_bug.cgi?id=110383 - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0); + m_compileOkay = false; break; } @@ -1750,8 +1858,7 @@ void SpeculativeJIT::compile(Node* node) break; } - case FlushedJSValue: - case FlushedArguments: { + case FlushedJSValue: { GPRTemporary result(this); GPRTemporary tag(this); m_jit.load32(JITCompiler::payloadFor(node->machineLocal()), result.gpr()); @@ -1782,13 +1889,18 @@ void SpeculativeJIT::compile(Node* node) break; } - case MovHint: - case ZombieHint: - case Check: { - RELEASE_ASSERT_NOT_REACHED(); + case MovHint: { + compileMovHint(m_currentNode); + noResult(node); break; } - + + case ZombieHint: { + recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead); + noResult(node); + break; + } + case SetLocal: { switch (node->variableAccessData()->flushFormat()) { case FlushedDouble: { @@ -1827,8 +1939,7 @@ void SpeculativeJIT::compile(Node* node) break; } - case FlushedJSValue: - case FlushedArguments: { + case FlushedJSValue: { JSValueOperand value(this, node->child1()); m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node->machineLocal())); m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node->machineLocal())); @@ -1855,18 +1966,18 @@ void SpeculativeJIT::compile(Node* node) case BitAnd: case BitOr: case BitXor: - if (isInt32Constant(node->child1().node())) { + if (node->child1()->isInt32Constant()) { SpeculateInt32Operand op2(this, node->child2()); GPRTemporary result(this, Reuse, op2); - bitOp(op, valueOfInt32Constant(node->child1().node()), op2.gpr(), result.gpr()); + bitOp(op, node->child1()->asInt32(), op2.gpr(), result.gpr()); int32Result(result.gpr(), node); - } else if (isInt32Constant(node->child2().node())) { + } else if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); GPRTemporary result(this, Reuse, op1); - bitOp(op, valueOfInt32Constant(node->child2().node()), op1.gpr(), result.gpr()); + bitOp(op, node->child2()->asInt32(), op1.gpr(), result.gpr()); int32Result(result.gpr(), node); } else { @@ -1885,11 +1996,11 @@ void SpeculativeJIT::compile(Node* node) case BitRShift: case BitLShift: case BitURShift: - if (isInt32Constant(node->child2().node())) { + if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); GPRTemporary result(this, Reuse, op1); - shiftOp(op, op1.gpr(), valueOfInt32Constant(node->child2().node()) & 0x1f, result.gpr()); + shiftOp(op, op1.gpr(), node->child2()->asInt32() & 0x1f, result.gpr()); int32Result(result.gpr(), node); } else { @@ -1942,8 +2053,8 @@ void SpeculativeJIT::compile(Node* node) flushRegisters(); - GPRResult2 resultTag(this); - GPRResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node())) callOperation(operationValueAddNotNumber, resultTag.gpr(), resultPayload.gpr(), op1TagGPR, op1PayloadGPR, op2TagGPR, op2PayloadGPR); else @@ -1957,6 +2068,10 @@ void SpeculativeJIT::compile(Node* node) compileAdd(node); break; + case ArithClz32: + compileArithClz32(node); + break; + case MakeRope: compileMakeRope(node); break; @@ -1983,6 +2098,11 @@ void SpeculativeJIT::compile(Node* node) break; } + case ArithPow: { + compileArithPow(node); + break; + } + case ArithAbs: { switch (node->child1().useKind()) { case Int32Use: { @@ -2086,17 +2206,11 @@ void SpeculativeJIT::compile(Node* node) } break; } - - case ArithSqrt: { - SpeculateDoubleOperand op1(this, node->child1()); - FPRTemporary result(this, op1); - - m_jit.sqrtDouble(op1.fpr(), result.fpr()); - - doubleResult(result.fpr(), node); + + case ArithSqrt: + compileArithSqrt(node); break; - } - + case ArithFRound: { SpeculateDoubleOperand op1(this, node->child1()); FPRTemporary result(this, op1); @@ -2108,6 +2222,10 @@ void SpeculativeJIT::compile(Node* node) break; } + case ArithRound: + compileArithRound(node); + break; + case ArithSin: { SpeculateDoubleOperand op1(this, node->child1()); FPRReg op1FPR = op1.fpr(); @@ -2132,6 +2250,10 @@ void SpeculativeJIT::compile(Node* node) break; } + case ArithLog: + compileArithLog(node); + break; + case LogicalNot: compileLogicalNot(node); break; @@ -2157,7 +2279,7 @@ void SpeculativeJIT::compile(Node* node) break; case CompareEqConstant: - ASSERT(isNullConstant(node->child2().node())); + ASSERT(node->child2()->asJSValue().isNull()); if (nonSpeculativeCompareNull(node, node->child1())) return; break; @@ -2204,7 +2326,9 @@ void SpeculativeJIT::compile(Node* node) case Array::SelectUsingPredictions: case Array::ForceExit: RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0); +#endif break; case Array::Generic: { SpeculateCellOperand base(this, node->child1()); // Save a register, speculate cell. We'll probably be right. @@ -2214,8 +2338,8 @@ void SpeculativeJIT::compile(Node* node) GPRReg propertyPayloadGPR = property.payloadGPR(); flushRegisters(); - GPRResult2 resultTag(this); - GPRResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR); jsValueResult(resultTag.gpr(), resultPayload.gpr(), node); @@ -2237,21 +2361,46 @@ void SpeculativeJIT::compile(Node* node) GPRTemporary resultPayload(this); if (node->arrayMode().type() == Array::Int32) { + ASSERT(!node->arrayMode().isSaneChain()); + speculationCheck( OutOfBounds, JSValueRegs(), 0, m_jit.branch32( MacroAssembler::Equal, - MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), + MacroAssembler::BaseIndex( + storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::EmptyValueTag))); - m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); + m_jit.load32( + MacroAssembler::BaseIndex( + storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset), + resultPayload.gpr()); int32Result(resultPayload.gpr(), node); break; } GPRTemporary resultTag(this); - m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); - speculationCheck(LoadFromHole, JSValueRegs(), 0, 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()); + m_jit.load32( + MacroAssembler::BaseIndex( + storageReg, propertyReg, MacroAssembler::TimesEight, TagOffset), + resultTag.gpr()); + m_jit.load32( + MacroAssembler::BaseIndex( + storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset), + resultPayload.gpr()); + if (node->arrayMode().isSaneChain()) { + JITCompiler::Jump notHole = m_jit.branch32( + MacroAssembler::NotEqual, resultTag.gpr(), + TrustedImm32(JSValue::EmptyValueTag)); + m_jit.move(TrustedImm32(JSValue::UndefinedTag), resultTag.gpr()); + m_jit.move(TrustedImm32(0), resultPayload.gpr()); + notHole.link(&m_jit); + } else { + speculationCheck( + LoadFromHole, JSValueRegs(), 0, + m_jit.branch32( + MacroAssembler::Equal, resultTag.gpr(), + TrustedImm32(JSValue::EmptyValueTag))); + } jsValueResult(resultTag.gpr(), resultPayload.gpr(), node); break; } @@ -2406,8 +2555,11 @@ void SpeculativeJIT::compile(Node* node) case Array::String: compileGetByValOnString(node); break; - case Array::Arguments: - compileGetByValOnArguments(node); + case Array::DirectArguments: + compileGetByValOnDirectArguments(node); + break; + case Array::ScopedArguments: + compileGetByValOnScopedArguments(node); break; default: { TypedArrayType type = node->arrayMode().typedArrayType(); @@ -2434,8 +2586,10 @@ void SpeculativeJIT::compile(Node* node) case Array::SelectUsingPredictions: case Array::ForceExit: RELEASE_ASSERT_NOT_REACHED(); +#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE) terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0); alreadyHandled = true; +#endif break; case Array::Generic: { ASSERT(node->op() == PutByVal || node->op() == PutByValDirect); @@ -2584,12 +2738,6 @@ void SpeculativeJIT::compile(Node* node) break; } - case Array::Arguments: - // FIXME: we could at some point make this work. Right now we're assuming that the register - // pressure would be too great. - RELEASE_ASSERT_NOT_REACHED(); - break; - default: { TypedArrayType type = arrayMode.typedArrayType(); if (isInt(type)) @@ -2611,7 +2759,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR); // Must use jsValueResult because otherwise we screw up register @@ -2626,8 +2774,8 @@ void SpeculativeJIT::compile(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult2 resultTag(this); - GPRResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); callOperation(operationRegExpExec, resultTag.gpr(), resultPayload.gpr(), baseGPR, argumentGPR); jsValueResult(resultTag.gpr(), resultPayload.gpr(), node); @@ -2641,7 +2789,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR); // If we add a DataFormatBool, we should use it here. @@ -2962,6 +3110,18 @@ void SpeculativeJIT::compile(Node* node) case UntypedUse: { JSValueOperand value(this, node->child1()); + + if (!m_interpreter.needsTypeCheck(node->child1(), SpecBoolInt32 | SpecBoolean)) { + GPRTemporary result(this); + + GPRReg valueGPR = value.payloadGPR(); + GPRReg resultGPR = result.gpr(); + + m_jit.move(valueGPR, resultGPR); + int32Result(result.gpr(), node); + break; + } + GPRTemporary resultTag(this); GPRTemporary resultPayload(this); @@ -3007,8 +3167,8 @@ void SpeculativeJIT::compile(Node* node) m_jit.move(op1TagGPR, resultTagGPR); m_jit.move(op1PayloadGPR, resultPayloadGPR); } else { - MacroAssembler::Jump alreadyPrimitive = branchNotCell(op1.jsValueRegs()); - MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureIDOffset()), MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())); + MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(op1.jsValueRegs()); + MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(op1PayloadGPR); alreadyPrimitive.link(&m_jit); m_jit.move(op1TagGPR, resultTagGPR); @@ -3024,37 +3184,40 @@ void SpeculativeJIT::compile(Node* node) break; } - case ToString: { + case ToString: + case CallStringConstructor: { if (node->child1().useKind() == UntypedUse) { JSValueOperand op1(this, node->child1()); GPRReg op1PayloadGPR = op1.payloadGPR(); GPRReg op1TagGPR = op1.tagGPR(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); flushRegisters(); JITCompiler::Jump done; if (node->child1()->prediction() & SpecString) { - JITCompiler::Jump slowPath1 = branchNotCell(op1.jsValueRegs()); - JITCompiler::Jump slowPath2 = m_jit.branchPtr( - JITCompiler::NotEqual, - JITCompiler::Address(op1PayloadGPR, JSCell::structureIDOffset()), - TrustedImmPtr(m_jit.vm()->stringStructure.get())); + JITCompiler::Jump slowPath1 = m_jit.branchIfNotCell(op1.jsValueRegs()); + JITCompiler::Jump slowPath2 = m_jit.branchIfNotString(op1PayloadGPR); m_jit.move(op1PayloadGPR, resultGPR); done = m_jit.jump(); slowPath1.link(&m_jit); slowPath2.link(&m_jit); } - callOperation(operationToString, resultGPR, op1TagGPR, op1PayloadGPR); + if (op == ToString) + callOperation(operationToString, resultGPR, op1TagGPR, op1PayloadGPR); + else { + ASSERT(op == CallStringConstructor); + callOperation(operationCallStringConstructor, resultGPR, op1TagGPR, op1PayloadGPR); + } if (done.isSet()) done.link(&m_jit); cellResult(resultGPR, node); break; } - compileToStringOnCell(node); + compileToStringOrCallStringConstructorOnCell(node); break; } @@ -3139,7 +3302,7 @@ void SpeculativeJIT::compile(Node* node) if (!node->numChildren()) { flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation( operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); cellResult(result.gpr(), node); @@ -3214,7 +3377,7 @@ void SpeculativeJIT::compile(Node* node) m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr()); } - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation( operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), @@ -3247,7 +3410,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg scratch2GPR = scratch2.gpr(); MacroAssembler::JumpList slowCases; - slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH))); ASSERT((1 << 3) == sizeof(JSValue)); m_jit.move(sizeGPR, scratchGPR); @@ -3275,12 +3438,11 @@ void SpeculativeJIT::compile(Node* node) done.link(&m_jit); } - addSlowPathGenerator(adoptPtr( - new CallArrayAllocatorWithVariableSizeSlowPathGenerator( + addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>( slowCases, this, operationNewArrayWithSize, resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage), - sizeGPR))); + sizeGPR)); cellResult(resultGPR, node); break; @@ -3289,10 +3451,10 @@ void SpeculativeJIT::compile(Node* node) SpeculateStrictInt32Operand size(this, node->child1()); GPRReg sizeGPR = size.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); GPRReg structureGPR = selectScratchGPR(sizeGPR); - MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)); + MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)); m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())), structureGPR); MacroAssembler::Jump done = m_jit.jump(); bigLength.link(&m_jit); @@ -3342,7 +3504,7 @@ void SpeculativeJIT::compile(Node* node) } flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), node->startConstant(), node->numConstants()); @@ -3362,7 +3524,7 @@ void SpeculativeJIT::compile(Node* node) flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); @@ -3383,8 +3545,8 @@ void SpeculativeJIT::compile(Node* node) case NewRegexp: { flushRegisters(); - GPRResult resultPayload(this); - GPRResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); callOperation(operationNewRegexp, resultTag.gpr(), resultPayload.gpr(), m_jit.codeBlock()->regexp(node->regexpIndex())); @@ -3404,7 +3566,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg tempTagGPR = tempTag.gpr(); MacroAssembler::JumpList slowCases; - slowCases.append(branchNotCell(thisValue.jsValueRegs())); + slowCases.append(m_jit.branchIfNotCell(thisValue.jsValueRegs())); slowCases.append(m_jit.branch8( MacroAssembler::NotEqual, MacroAssembler::Address(thisValuePayloadGPR, JSCell::typeInfoTypeOffset()), @@ -3443,11 +3605,16 @@ void SpeculativeJIT::compile(Node* node) GPRReg allocatorGPR = allocator.gpr(); GPRReg structureGPR = structure.gpr(); GPRReg scratchGPR = scratch.gpr(); + // Rare data is only used to access the allocator & structure + // We can avoid using an additional GPR this way + GPRReg rareDataGPR = structureGPR; MacroAssembler::JumpList slowPath; - m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR); - m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR); + m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR); + slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR)); + m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR); + m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR); slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR)); emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath); @@ -3457,12 +3624,6 @@ void SpeculativeJIT::compile(Node* node) break; } - case AllocationProfileWatchpoint: - case TypedArrayWatchpoint: { - noResult(node); - break; - } - case NewObject: { GPRTemporary result(this); GPRTemporary allocator(this); @@ -3494,90 +3655,44 @@ void SpeculativeJIT::compile(Node* node) break; } - case GetScope: { - SpeculateCellOperand function(this, node->child1()); - GPRTemporary result(this, Reuse, function); - m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr()); - cellResult(result.gpr(), node); - break; - } - - case GetMyScope: { + case GetArgumentCount: { GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - - m_jit.loadPtr(JITCompiler::payloadFor(JSStack::ScopeChain), resultGPR); - cellResult(resultGPR, node); + m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), result.gpr()); + int32Result(result.gpr(), node); break; } - case SkipTopScope: { - SpeculateCellOperand scope(this, node->child1()); - GPRTemporary result(this, Reuse, scope); - GPRReg resultGPR = result.gpr(); - m_jit.move(scope.gpr(), resultGPR); - JITCompiler::Jump activationNotCreated = - m_jit.branchTestPtr( - JITCompiler::Zero, - JITCompiler::payloadFor( - static_cast<VirtualRegister>(m_jit.graph().machineActivationRegister()))); - m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR); - activationNotCreated.link(&m_jit); - cellResult(resultGPR, node); + case GetScope: + compileGetScope(node); break; - } - case SkipScope: { - SpeculateCellOperand scope(this, node->child1()); - GPRTemporary result(this, Reuse, scope); - m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr()); - cellResult(result.gpr(), node); + case SkipScope: + compileSkipScope(node); break; - } - - case GetClosureRegisters: { - if (WriteBarrierBase<Unknown>* registers = m_jit.graph().tryGetRegisters(node->child1().node())) { - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - m_jit.move(TrustedImmPtr(registers), resultGPR); - storageResult(resultGPR, node); - break; - } - SpeculateCellOperand scope(this, node->child1()); - GPRTemporary result(this); - GPRReg scopeGPR = scope.gpr(); - GPRReg resultGPR = result.gpr(); - - m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR); - storageResult(resultGPR, node); - break; - } case GetClosureVar: { - StorageOperand registers(this, node->child1()); + SpeculateCellOperand base(this, node->child1()); GPRTemporary resultTag(this); GPRTemporary resultPayload(this); - GPRReg registersGPR = registers.gpr(); + GPRReg baseGPR = base.gpr(); GPRReg resultTagGPR = resultTag.gpr(); GPRReg resultPayloadGPR = resultPayload.gpr(); - m_jit.load32(JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); - m_jit.load32(JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); + m_jit.load32(JITCompiler::Address(baseGPR, JSEnvironmentRecord::offsetOfVariable(node->scopeOffset()) + TagOffset), resultTagGPR); + m_jit.load32(JITCompiler::Address(baseGPR, JSEnvironmentRecord::offsetOfVariable(node->scopeOffset()) + PayloadOffset), resultPayloadGPR); jsValueResult(resultTagGPR, resultPayloadGPR, node); break; } + case PutClosureVar: { - StorageOperand registers(this, node->child2()); - JSValueOperand value(this, node->child3()); - GPRTemporary scratchRegister(this); + SpeculateCellOperand base(this, node->child1()); + JSValueOperand value(this, node->child2()); - GPRReg registersGPR = registers.gpr(); + GPRReg baseGPR = base.gpr(); GPRReg valueTagGPR = value.tagGPR(); GPRReg valuePayloadGPR = value.payloadGPR(); - speculate(node, node->child1()); - - m_jit.store32(valueTagGPR, JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); - m_jit.store32(valuePayloadGPR, JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); + m_jit.store32(valueTagGPR, JITCompiler::Address(baseGPR, JSEnvironmentRecord::offsetOfVariable(node->scopeOffset()) + TagOffset)); + m_jit.store32(valuePayloadGPR, JITCompiler::Address(baseGPR, JSEnvironmentRecord::offsetOfVariable(node->scopeOffset()) + PayloadOffset)); noResult(node); break; } @@ -3615,7 +3730,7 @@ void SpeculativeJIT::compile(Node* node) base.use(); - JITCompiler::Jump notCell = branchNotCell(base.jsValueRegs()); + JITCompiler::Jump notCell = m_jit.branchIfNotCell(base.jsValueRegs()); cachedGetById(node->origin.semantic, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell); @@ -3642,8 +3757,8 @@ void SpeculativeJIT::compile(Node* node) GPRReg baseGPR = base.gpr(); - GPRResult resultPayload(this); - GPRResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); @@ -3662,8 +3777,8 @@ void SpeculativeJIT::compile(Node* node) GPRReg baseTagGPR = base.tagGPR(); GPRReg basePayloadGPR = base.payloadGPR(); - GPRResult resultPayload(this); - GPRResult2 resultTag(this); + GPRFlushedCallResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); @@ -3671,7 +3786,7 @@ void SpeculativeJIT::compile(Node* node) flushRegisters(); - JITCompiler::Jump notCell = branchNotCell(base.jsValueRegs()); + JITCompiler::Jump notCell = m_jit.branchIfNotCell(base.jsValueRegs()); cachedGetById(node->origin.semantic, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell, DontSpill); @@ -3690,23 +3805,35 @@ void SpeculativeJIT::compile(Node* node) compileGetArrayLength(node); break; - case CheckFunction: { - SpeculateCellOperand function(this, node->child1()); - speculationCheck(BadFunction, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node->function())); + case CheckCell: { + SpeculateCellOperand cell(this, node->child1()); + speculationCheck(BadCell, JSValueSource::unboxedCell(cell.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, cell.gpr(), node->cellOperand()->cell())); noResult(node); break; } - case CheckExecutable: { - SpeculateCellOperand function(this, node->child1()); - speculationCheck(BadExecutable, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(function.gpr(), JSFunction::offsetOfExecutable()), node->executable())); + case CheckNotEmpty: { + JSValueOperand operand(this, node->child1()); + GPRReg tagGPR = operand.tagGPR(); + speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::EmptyValueTag))); noResult(node); break; } - - case CheckStructure: { - SpeculateCellOperand base(this, node->child1()); - + + case GetExecutable: { + SpeculateCellOperand function(this, node->child1()); + GPRTemporary result(this, Reuse, function); + GPRReg functionGPR = function.gpr(); + GPRReg resultGPR = result.gpr(); + speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType); + m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutable()), resultGPR); + cellResult(resultGPR, node); + break; + } + + case CheckStructure: { + SpeculateCellOperand base(this, node->child1()); + ASSERT(node->structureSet().size()); if (node->structureSet().size() == 1) { @@ -3738,43 +3865,19 @@ void SpeculativeJIT::compile(Node* node) break; } - case StructureTransitionWatchpoint: { - // There is a fascinating question here of what to do about array profiling. - // We *could* try to tell the OSR exit about where the base of the access is. - // The DFG will have kept it alive, though it may not be in a register, and - // we shouldn't really load it since that could be a waste. For now though, - // we'll just rely on the fact that when a watchpoint fires then that's - // quite a hint already. - - m_jit.addWeakReference(node->structure()); - -#if !ASSERT_DISABLED - SpeculateCellOperand op1(this, node->child1()); - JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), TrustedImmPtr(node->structure())); - m_jit.abortWithReason(DFGIneffectiveWatchpoint); - isOK.link(&m_jit); -#else - speculateCell(node->child1()); -#endif - - noResult(node); - break; - } - - case PhantomPutStructure: { - ASSERT(isKnownCell(node->child1().node())); - m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node); - noResult(node); - break; - } - case PutStructure: { + Structure* oldStructure = node->transition()->previous; + Structure* newStructure = node->transition()->next; + m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node); SpeculateCellOperand base(this, node->child1()); GPRReg baseGPR = base.gpr(); - m_jit.storePtr(MacroAssembler::TrustedImmPtr(node->structureTransitionData().newStructure), MacroAssembler::Address(baseGPR, JSCell::structureIDOffset())); + ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType()); + ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type()); + ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags()); + m_jit.storePtr(MacroAssembler::TrustedImmPtr(newStructure), MacroAssembler::Address(baseGPR, JSCell::structureIDOffset())); noResult(node); break; @@ -3825,7 +3928,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg resultTagGPR = resultTag.gpr(); GPRReg resultPayloadGPR = resultPayload.gpr(); - StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()]; + StorageAccessData& storageAccessData = node->storageAccessData(); m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR); @@ -3834,6 +3937,47 @@ void SpeculativeJIT::compile(Node* node) break; } + case GetGetterSetterByOffset: { + StorageOperand storage(this, node->child1()); + GPRTemporary resultPayload(this); + + GPRReg storageGPR = storage.gpr(); + GPRReg resultPayloadGPR = resultPayload.gpr(); + + StorageAccessData& storageAccessData = node->storageAccessData(); + + m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); + + cellResult(resultPayloadGPR, node); + break; + } + + case GetGetter: { + SpeculateCellOperand op1(this, node->child1()); + GPRTemporary result(this, Reuse, op1); + + GPRReg op1GPR = op1.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR); + + cellResult(resultGPR, node); + break; + } + + case GetSetter: { + SpeculateCellOperand op1(this, node->child1()); + GPRTemporary result(this, Reuse, op1); + + GPRReg op1GPR = op1.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR); + + cellResult(resultGPR, node); + break; + } + case PutByOffset: { StorageOperand storage(this, node->child1()); JSValueOperand value(this, node->child3()); @@ -3844,7 +3988,7 @@ void SpeculativeJIT::compile(Node* node) speculate(node, node->child2()); - StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()]; + StorageAccessData& storageAccessData = node->storageAccessData(); m_jit.storePtr(valueTagGPR, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); m_jit.storePtr(valuePayloadGPR, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); @@ -3906,7 +4050,7 @@ void SpeculativeJIT::compile(Node* node) GPRTemporary resultPayload(this); GPRTemporary resultTag(this); - m_jit.move(TrustedImmPtr(node->registerPointer()), resultPayload.gpr()); + m_jit.move(TrustedImmPtr(node->variablePointer()), resultPayload.gpr()); m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTag.gpr()); m_jit.load32(JITCompiler::Address(resultPayload.gpr(), OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayload.gpr()); @@ -3915,51 +4059,25 @@ void SpeculativeJIT::compile(Node* node) } case PutGlobalVar: { - JSValueOperand value(this, node->child1()); + JSValueOperand value(this, node->child2()); // FIXME: if we happen to have a spare register - and _ONLY_ if we happen to have // a spare register - a good optimization would be to put the register pointer into // a register and then do a zero offset store followed by a four-offset store (or // vice-versa depending on endianness). - m_jit.store32(value.tagGPR(), node->registerPointer()->tagPointer()); - m_jit.store32(value.payloadGPR(), node->registerPointer()->payloadPointer()); + m_jit.store32(value.tagGPR(), node->variablePointer()->tagPointer()); + m_jit.store32(value.payloadGPR(), node->variablePointer()->payloadPointer()); noResult(node); break; } case NotifyWrite: { - VariableWatchpointSet* set = node->variableWatchpointSet(); - - JSValueOperand value(this, node->child1()); - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); - - GPRTemporary temp(this); - GPRReg tempGPR = temp.gpr(); - - m_jit.load8(set->addressOfState(), tempGPR); - - JITCompiler::Jump isDone = m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)); - JITCompiler::JumpList notifySlow; - notifySlow.append(m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->payloadPointer()), - valuePayloadGPR)); - notifySlow.append(m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::AbsoluteAddress(set->addressOfInferredValue()->tagPointer()), - valueTagGPR)); - addSlowPathGenerator( - slowPathCall(notifySlow, this, operationNotifyWrite, NoResult, set, valueTagGPR, valuePayloadGPR)); - isDone.link(&m_jit); - - noResult(node); + compileNotifyWrite(node); break; } - case VarInjectionWatchpoint: - case VariableWatchpoint: { + case VarInjectionWatchpoint: { noResult(node); break; } @@ -3989,7 +4107,7 @@ void SpeculativeJIT::compile(Node* node) GPRTemporary localGlobalObject(this); GPRTemporary remoteGlobalObject(this); - JITCompiler::Jump isCell = branchIsCell(value.jsValueRegs()); + JITCompiler::Jump isCell = m_jit.branchIfCell(value.jsValueRegs()); m_jit.compare32(JITCompiler::Equal, value.tagGPR(), TrustedImm32(JSValue::UndefinedTag), result.gpr()); JITCompiler::Jump done = m_jit.jump(); @@ -4045,7 +4163,7 @@ void SpeculativeJIT::compile(Node* node) JSValueOperand value(this, node->child1()); GPRTemporary result(this, Reuse, value, TagWord); - JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs()); + JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(value.jsValueRegs()); m_jit.compare8(JITCompiler::Equal, JITCompiler::Address(value.payloadGPR(), JSCell::typeInfoTypeOffset()), @@ -4063,88 +4181,35 @@ void SpeculativeJIT::compile(Node* node) case IsObject: { JSValueOperand value(this, node->child1()); - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); - GPRResult result(this); - GPRReg resultGPR = result.gpr(); - flushRegisters(); - callOperation(operationIsObject, resultGPR, valueTagGPR, valuePayloadGPR); + GPRTemporary result(this, Reuse, value, TagWord); + + JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(value.jsValueRegs()); + + m_jit.compare8(JITCompiler::AboveOrEqual, + JITCompiler::Address(value.payloadGPR(), JSCell::typeInfoTypeOffset()), + TrustedImm32(ObjectType), + result.gpr()); + JITCompiler::Jump done = m_jit.jump(); + + isNotCell.link(&m_jit); + m_jit.move(TrustedImm32(0), result.gpr()); + + done.link(&m_jit); booleanResult(result.gpr(), node); break; } + case IsObjectOrNull: { + compileIsObjectOrNull(node); + break; + } + case IsFunction: { - JSValueOperand value(this, node->child1()); - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); - GPRResult result(this); - GPRReg resultGPR = result.gpr(); - flushRegisters(); - callOperation(operationIsFunction, resultGPR, valueTagGPR, valuePayloadGPR); - booleanResult(result.gpr(), node); + compileIsFunction(node); break; } case TypeOf: { - JSValueOperand value(this, node->child1(), ManualOperandSpeculation); - GPRReg tagGPR = value.tagGPR(); - GPRReg payloadGPR = value.payloadGPR(); - GPRTemporary temp(this); - GPRReg tempGPR = temp.gpr(); - GPRResult result(this); - GPRReg resultGPR = result.gpr(); - JITCompiler::JumpList doneJumps; - - flushRegisters(); - - ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse); - - JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs()); - if (node->child1().useKind() != UntypedUse) - DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecCell, isNotCell); - - if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) { - JITCompiler::Jump notString = m_jit.branch8( - JITCompiler::NotEqual, - JITCompiler::Address(payloadGPR, JSCell::typeInfoTypeOffset()), - TrustedImm32(StringType)); - if (node->child1().useKind() == StringUse) - DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecString, notString); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR); - doneJumps.append(m_jit.jump()); - if (node->child1().useKind() != StringUse) { - notString.link(&m_jit); - callOperation(operationTypeOf, resultGPR, payloadGPR); - doneJumps.append(m_jit.jump()); - } - } else { - callOperation(operationTypeOf, resultGPR, payloadGPR); - doneJumps.append(m_jit.jump()); - } - - if (node->child1().useKind() == UntypedUse) { - isNotCell.link(&m_jit); - - m_jit.add32(TrustedImm32(1), tagGPR, tempGPR); - JITCompiler::Jump notNumber = m_jit.branch32(JITCompiler::AboveOrEqual, tempGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1)); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.numberString()), resultGPR); - doneJumps.append(m_jit.jump()); - notNumber.link(&m_jit); - - JITCompiler::Jump notUndefined = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::UndefinedTag)); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.undefinedString()), resultGPR); - doneJumps.append(m_jit.jump()); - notUndefined.link(&m_jit); - - JITCompiler::Jump notNull = m_jit.branch32(JITCompiler::NotEqual, tagGPR, TrustedImm32(JSValue::NullTag)); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.objectString()), resultGPR); - doneJumps.append(m_jit.jump()); - notNull.link(&m_jit); - - // Only boolean left - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.booleanString()), resultGPR); - } - doneJumps.link(&m_jit); - cellResult(resultGPR, node); + compileTypeOf(node); break; } @@ -4153,433 +4218,410 @@ void SpeculativeJIT::compile(Node* node) case Call: case Construct: + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: emitCall(node); break; - case CreateActivation: { - JSValueOperand value(this, node->child1()); - GPRTemporary result(this, Reuse, value, PayloadWord); + case LoadVarargs: { + LoadVarargsData* data = node->loadVarargsData(); - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); - GPRReg resultGPR = result.gpr(); + GPRReg argumentsTagGPR; + GPRReg argumentsPayloadGPR; + { + JSValueOperand arguments(this, node->child1()); + argumentsTagGPR = arguments.tagGPR(); + argumentsPayloadGPR = arguments.payloadGPR(); + flushRegisters(); + } - m_jit.move(valuePayloadGPR, resultGPR); + callOperation(operationSizeOfVarargs, GPRInfo::returnValueGPR, argumentsTagGPR, argumentsPayloadGPR, data->offset); - JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag)); + lock(GPRInfo::returnValueGPR); + { + JSValueOperand arguments(this, node->child1()); + argumentsTagGPR = arguments.tagGPR(); + argumentsPayloadGPR = arguments.payloadGPR(); + flushRegisters(); + } + unlock(GPRInfo::returnValueGPR); - addSlowPathGenerator( - slowPathCall( - notCreated, this, operationCreateActivation, resultGPR, - framePointerOffsetToGetActivationRegisters())); + // FIXME: There is a chance that we will call an effectful length property twice. This is safe + // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance + // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right + // past the sizing. + // https://bugs.webkit.org/show_bug.cgi?id=141448 + + GPRReg argCountIncludingThisGPR = + JITCompiler::selectScratchGPR(GPRInfo::returnValueGPR, argumentsTagGPR, argumentsPayloadGPR); - cellResult(resultGPR, node); - break; - } + m_jit.add32(TrustedImm32(1), GPRInfo::returnValueGPR, argCountIncludingThisGPR); + speculationCheck( + VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32( + MacroAssembler::Above, + argCountIncludingThisGPR, + TrustedImm32(data->limit))); + + m_jit.store32(argCountIncludingThisGPR, JITCompiler::payloadFor(data->machineCount)); + + callOperation(operationLoadVarargs, data->machineStart.offset(), argumentsTagGPR, argumentsPayloadGPR, data->offset, GPRInfo::returnValueGPR, data->mandatoryMinimum); - case FunctionReentryWatchpoint: { noResult(node); break; } - case CreateArguments: { - JSValueOperand value(this, node->child1()); - GPRTemporary scratch1(this); - GPRTemporary scratch2(this); - GPRTemporary result(this, Reuse, value, PayloadWord); - - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); - GPRReg scratch1GPR = scratch1.gpr(); - GPRReg scratch2GPR = scratch2.gpr(); - GPRReg resultGPR = result.gpr(); - - m_jit.move(valuePayloadGPR, resultGPR); - - if (node->origin.semantic.inlineCallFrame) { - JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag)); - addSlowPathGenerator( - slowPathCall( - notCreated, this, operationCreateInlinedArguments, resultGPR, - node->origin.semantic.inlineCallFrame)); - cellResult(resultGPR, node); - break; - } - - FunctionExecutable* executable = jsCast<FunctionExecutable*>(m_jit.graph().executableFor(node->origin.semantic)); - if (m_jit.codeBlock()->hasSlowArguments() - || executable->isStrictMode() - || !executable->parameterCount()) { - JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag)); - addSlowPathGenerator( - slowPathCall(notCreated, this, operationCreateArguments, resultGPR)); - cellResult(resultGPR, node); - break; - } - - JITCompiler::Jump alreadyCreated = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag)); - - MacroAssembler::JumpList slowPaths; - emitAllocateArguments(resultGPR, scratch1GPR, scratch2GPR, slowPaths); - addSlowPathGenerator( - slowPathCall(slowPaths, this, operationCreateArguments, resultGPR)); - - alreadyCreated.link(&m_jit); - cellResult(resultGPR, node); + case ForwardVarargs: { + compileForwardVarargs(node); break; } - case TearOffActivation: { - JSValueOperand activationValue(this, node->child1()); - GPRTemporary scratch(this); - - GPRReg activationValueTagGPR = activationValue.tagGPR(); - GPRReg activationValuePayloadGPR = activationValue.payloadGPR(); - GPRReg scratchGPR = scratch.gpr(); - - JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, activationValueTagGPR, TrustedImm32(JSValue::EmptyValueTag)); - - SymbolTable* symbolTable = m_jit.symbolTableFor(node->origin.semantic); - int registersOffset = JSActivation::registersOffset(symbolTable); - - int bytecodeCaptureStart = symbolTable->captureStart(); - int machineCaptureStart = m_jit.graph().m_machineCaptureStart; - for (int i = symbolTable->captureCount(); i--;) { - m_jit.loadPtr( - JITCompiler::Address( - GPRInfo::callFrameRegister, (machineCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), - scratchGPR); - m_jit.storePtr( - scratchGPR, JITCompiler::Address( - activationValuePayloadGPR, registersOffset + (bytecodeCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); - m_jit.loadPtr( - JITCompiler::Address( - GPRInfo::callFrameRegister, (machineCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), - scratchGPR); - m_jit.storePtr( - scratchGPR, JITCompiler::Address( - activationValuePayloadGPR, registersOffset + (bytecodeCaptureStart - i) * sizeof(Register) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); - } - m_jit.addPtr(TrustedImm32(registersOffset), activationValuePayloadGPR, scratchGPR); - m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValuePayloadGPR, JSActivation::offsetOfRegisters())); - - notCreated.link(&m_jit); - noResult(node); + case CreateActivation: { + compileCreateActivation(node); break; } - case TearOffArguments: { - JSValueOperand unmodifiedArgumentsValue(this, node->child1()); - JSValueOperand activationValue(this, node->child2()); - GPRReg unmodifiedArgumentsValuePayloadGPR = unmodifiedArgumentsValue.payloadGPR(); - GPRReg activationValuePayloadGPR = activationValue.payloadGPR(); - - JITCompiler::Jump created = m_jit.branchTest32( - JITCompiler::NonZero, unmodifiedArgumentsValuePayloadGPR); + case CreateDirectArguments: { + compileCreateDirectArguments(node); + break; + } - if (node->origin.semantic.inlineCallFrame) { - addSlowPathGenerator( - slowPathCall( - created, this, operationTearOffInlinedArguments, NoResult, - unmodifiedArgumentsValuePayloadGPR, activationValuePayloadGPR, node->origin.semantic.inlineCallFrame)); - } else { - addSlowPathGenerator( - slowPathCall( - created, this, operationTearOffArguments, NoResult, - unmodifiedArgumentsValuePayloadGPR, activationValuePayloadGPR)); - } + case GetFromArguments: { + compileGetFromArguments(node); + break; + } - noResult(node); + case PutToArguments: { + compilePutToArguments(node); break; } - case CheckArgumentsNotCreated: { - ASSERT(!isEmptySpeculation( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)); - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)), - TrustedImm32(JSValue::EmptyValueTag))); - noResult(node); + case CreateScopedArguments: { + compileCreateScopedArguments(node); break; } - case GetMyArgumentsLength: { - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); + case CreateClonedArguments: { + compileCreateClonedArguments(node); + break; + } - if (!isEmptySpeculation( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)) { - speculationCheck( - ArgumentsEscaped, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)), - TrustedImm32(JSValue::EmptyValueTag))); - } + case NewFunction: + compileNewFunction(node); + break; - ASSERT(!node->origin.semantic.inlineCallFrame); - m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR); - m_jit.sub32(TrustedImm32(1), resultGPR); + case In: + compileIn(node); + break; + + case StoreBarrier: { + compileStoreBarrier(node); + break; + } + + case GetEnumerableLength: { + SpeculateCellOperand enumerator(this, node->child1()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR); int32Result(resultGPR, node); break; } - - case GetMyArgumentsLengthSafe: { + case HasGenericProperty: { + JSValueOperand base(this, node->child1()); + SpeculateCellOperand property(this, node->child2()); + GPRFlushedCallResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); + GPRReg basePayloadGPR = base.payloadGPR(); + GPRReg baseTagGPR = base.tagGPR(); + GPRReg resultPayloadGPR = resultPayload.gpr(); + GPRReg resultTagGPR = resultTag.gpr(); + + flushRegisters(); + callOperation(operationHasGenericProperty, resultTagGPR, resultPayloadGPR, baseTagGPR, basePayloadGPR, property.gpr()); + booleanResult(resultPayloadGPR, node); + break; + } + case HasStructureProperty: { + JSValueOperand base(this, node->child1()); + SpeculateCellOperand property(this, node->child2()); + SpeculateCellOperand enumerator(this, node->child3()); GPRTemporary resultPayload(this); GPRTemporary resultTag(this); + + GPRReg baseTagGPR = base.tagGPR(); + GPRReg basePayloadGPR = base.payloadGPR(); + GPRReg propertyGPR = property.gpr(); GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); - - JITCompiler::Jump created = m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)), - TrustedImm32(JSValue::EmptyValueTag)); - - if (node->origin.semantic.inlineCallFrame) { - m_jit.move( - Imm32(node->origin.semantic.inlineCallFrame->arguments.size() - 1), - resultPayloadGPR); - } else { - m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultPayloadGPR); - m_jit.sub32(TrustedImm32(1), resultPayloadGPR); - } - m_jit.move(TrustedImm32(JSValue::Int32Tag), resultTagGPR); - - // FIXME: the slow path generator should perform a forward speculation that the - // result is an integer. For now we postpone the speculation by having this return - // a JSValue. - - addSlowPathGenerator( - slowPathCall( - created, this, operationGetArgumentsLength, - JSValueRegs(resultTagGPR, resultPayloadGPR), - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset())); - - jsValueResult(resultTagGPR, resultPayloadGPR, node); + + m_jit.load32(MacroAssembler::Address(basePayloadGPR, JSCell::structureIDOffset()), resultTagGPR); + MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual, + resultTagGPR, + MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())); + + moveTrueTo(resultPayloadGPR); + MacroAssembler::Jump done = m_jit.jump(); + + done.link(&m_jit); + + addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultTagGPR, resultPayloadGPR, baseTagGPR, basePayloadGPR, propertyGPR)); + booleanResult(resultPayloadGPR, node); break; } - - case GetMyArgumentByVal: { - SpeculateStrictInt32Operand index(this, node->child1()); + case HasIndexedProperty: { + SpeculateCellOperand base(this, node->child1()); + SpeculateInt32Operand index(this, node->child2()); GPRTemporary resultPayload(this); GPRTemporary resultTag(this); + + GPRReg baseGPR = base.gpr(); GPRReg indexGPR = index.gpr(); GPRReg resultPayloadGPR = resultPayload.gpr(); GPRReg resultTagGPR = resultTag.gpr(); - - if (!isEmptySpeculation( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)) { - speculationCheck( - ArgumentsEscaped, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)), - TrustedImm32(JSValue::EmptyValueTag))); - } - - m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR); + + MacroAssembler::JumpList slowCases; + ArrayMode mode = node->arrayMode(); + switch (mode.type()) { + case Array::Int32: + case Array::Contiguous: { + ASSERT(!!node->child3()); + StorageOperand storage(this, node->child3()); + GPRTemporary scratch(this); - if (node->origin.semantic.inlineCallFrame) { - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultPayloadGPR, - Imm32(node->origin.semantic.inlineCallFrame->arguments.size()))); - } else { - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultPayloadGPR, - JITCompiler::payloadFor(JSStack::ArgumentCount))); + GPRReg storageGPR = storage.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()))); + m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR); + slowCases.append(m_jit.branch32(MacroAssembler::Equal, scratchGPR, TrustedImm32(JSValue::EmptyValueTag))); + break; } - - JITCompiler::JumpList slowArgument; - JITCompiler::JumpList slowArgumentOutOfBounds; - if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) { - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get(); - slowArgumentOutOfBounds.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, indexGPR, - Imm32(m_jit.symbolTableFor(node->origin.semantic)->parameterCount()))); + case Array::Double: { + ASSERT(!!node->child3()); + StorageOperand storage(this, node->child3()); + FPRTemporary scratch(this); + FPRReg scratchFPR = scratch.fpr(); + GPRReg storageGPR = storage.gpr(); - COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); - m_jit.move(ImmPtr(slowArguments), resultPayloadGPR); - m_jit.load32( - JITCompiler::BaseIndex( - resultPayloadGPR, indexGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(SlowArgument, index)), - resultPayloadGPR); + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()))); + m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR); + slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, scratchFPR, scratchFPR)); + break; + } + case Array::ArrayStorage: { + ASSERT(!!node->child3()); + StorageOperand storage(this, node->child3()); + GPRTemporary scratch(this); - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), - resultTagGPR); - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), - resultPayloadGPR); - slowArgument.append(m_jit.jump()); + GPRReg storageGPR = storage.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset()))); + m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR); + slowCases.append(m_jit.branch32(MacroAssembler::Equal, scratchGPR, TrustedImm32(JSValue::EmptyValueTag))); + break; } - slowArgumentOutOfBounds.link(&m_jit); - - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), - resultTagGPR); - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), - resultPayloadGPR); - - slowArgument.link(&m_jit); - jsValueResult(resultTagGPR, resultPayloadGPR, node); + default: { + slowCases.append(m_jit.jump()); + break; + } + } + + moveTrueTo(resultPayloadGPR); + MacroAssembler::Jump done = m_jit.jump(); + + addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedProperty, resultTagGPR, resultPayloadGPR, baseGPR, indexGPR)); + + done.link(&m_jit); + booleanResult(resultPayloadGPR, node); break; } - case GetMyArgumentByValSafe: { - SpeculateStrictInt32Operand index(this, node->child1()); + case GetDirectPname: { + Edge& baseEdge = m_jit.graph().varArgChild(node, 0); + Edge& propertyEdge = m_jit.graph().varArgChild(node, 1); + + SpeculateCellOperand base(this, baseEdge); + SpeculateCellOperand property(this, propertyEdge); + GPRReg baseGPR = base.gpr(); + GPRReg propertyGPR = property.gpr(); + +#if CPU(X86) + GPRFlushedCallResult resultPayload(this); + GPRFlushedCallResult2 resultTag(this); + GPRTemporary scratch(this); + + GPRReg resultTagGPR = resultTag.gpr(); + GPRReg resultPayloadGPR = resultPayload.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + // Not enough registers on X86 for this code, so always use the slow path. + flushRegisters(); + m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), scratchGPR); + callOperation(operationGetByValCell, resultTagGPR, resultPayloadGPR, baseGPR, scratchGPR, propertyGPR); +#else GPRTemporary resultPayload(this); GPRTemporary resultTag(this); - GPRReg indexGPR = index.gpr(); - GPRReg resultPayloadGPR = resultPayload.gpr(); + GPRTemporary scratch(this); + GPRReg resultTagGPR = resultTag.gpr(); + GPRReg resultPayloadGPR = resultPayload.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + Edge& indexEdge = m_jit.graph().varArgChild(node, 2); + Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3); + + SpeculateInt32Operand index(this, indexEdge); + SpeculateCellOperand enumerator(this, enumeratorEdge); + + GPRReg indexGPR = index.gpr(); + GPRReg enumeratorGPR = enumerator.gpr(); + + // Check the structure + m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratchGPR); + MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual, + scratchGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())); - JITCompiler::JumpList slowPath; - slowPath.append( - m_jit.branch32( - JITCompiler::NotEqual, - JITCompiler::tagFor(m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)), - TrustedImm32(JSValue::EmptyValueTag))); - - m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR); - if (node->origin.semantic.inlineCallFrame) { - slowPath.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultPayloadGPR, - Imm32(node->origin.semantic.inlineCallFrame->arguments.size()))); - } else { - slowPath.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultPayloadGPR, - JITCompiler::payloadFor(JSStack::ArgumentCount))); - } - - JITCompiler::JumpList slowArgument; - JITCompiler::JumpList slowArgumentOutOfBounds; - if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) { - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get(); - slowArgumentOutOfBounds.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, indexGPR, - Imm32(m_jit.symbolTableFor(node->origin.semantic)->parameterCount()))); + // Compute the offset + // If index is less than the enumerator's cached inline storage, then it's an inline access + MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual, + indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset())); - COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); - m_jit.move(ImmPtr(slowArguments), resultPayloadGPR); - m_jit.load32( - JITCompiler::BaseIndex( - resultPayloadGPR, indexGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(SlowArgument, index)), - resultPayloadGPR); - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), - resultTagGPR); - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), - resultPayloadGPR); - slowArgument.append(m_jit.jump()); - } - slowArgumentOutOfBounds.link(&m_jit); - - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), - resultTagGPR); - m_jit.load32( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultPayloadGPR, JITCompiler::TimesEight, - m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), - resultPayloadGPR); - - if (node->origin.semantic.inlineCallFrame) { - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetInlinedArgumentByVal, - JSValueRegs(resultTagGPR, resultPayloadGPR), - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset(), - node->origin.semantic.inlineCallFrame, indexGPR)); - } else { - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetArgumentByVal, - JSValueRegs(resultTagGPR, resultPayloadGPR), - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset(), - indexGPR)); - } + m_jit.move(indexGPR, scratchGPR); + m_jit.signExtend32ToPtr(scratchGPR, scratchGPR); + m_jit.load32(MacroAssembler::BaseIndex(baseGPR, scratchGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagGPR); + m_jit.load32(MacroAssembler::BaseIndex(baseGPR, scratchGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadGPR); + + MacroAssembler::Jump done = m_jit.jump(); - slowArgument.link(&m_jit); + // Otherwise it's out of line + outOfLineAccess.link(&m_jit); + m_jit.move(indexGPR, scratchGPR); + m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratchGPR); + m_jit.neg32(scratchGPR); + m_jit.signExtend32ToPtr(scratchGPR, scratchGPR); + // We use resultPayloadGPR as a temporary here. We have to make sure clobber it after getting the + // value out of indexGPR and enumeratorGPR because resultPayloadGPR could reuse either of those registers. + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), resultPayloadGPR); + int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue); + m_jit.load32(MacroAssembler::BaseIndex(resultPayloadGPR, scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTagGPR); + m_jit.load32(MacroAssembler::BaseIndex(resultPayloadGPR, scratchGPR, MacroAssembler::TimesEight, offsetOfFirstProperty + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayloadGPR); + + done.link(&m_jit); + + addSlowPathGenerator(slowPathCall(wrongStructure, this, operationGetByValCell, resultTagGPR, resultPayloadGPR, baseGPR, propertyGPR)); +#endif + jsValueResult(resultTagGPR, resultPayloadGPR, node); break; } - - case NewFunctionNoCheck: - compileNewFunctionNoCheck(node); + case GetPropertyEnumerator: { + SpeculateCellOperand base(this, node->child1()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + callOperation(operationGetPropertyEnumerator, resultGPR, base.gpr()); + cellResult(resultGPR, node); break; - - case NewFunction: { - JSValueOperand value(this, node->child1()); - GPRTemporary resultTag(this, Reuse, value, TagWord); - GPRTemporary resultPayload(this, Reuse, value, PayloadWord); - - GPRReg valueTagGPR = value.tagGPR(); - GPRReg valuePayloadGPR = value.payloadGPR(); + } + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: { + SpeculateCellOperand enumerator(this, node->child1()); + SpeculateInt32Operand index(this, node->child2()); + GPRTemporary scratch(this); + GPRTemporary resultPayload(this); + GPRTemporary resultTag(this); + + GPRReg enumeratorGPR = enumerator.gpr(); + GPRReg indexGPR = index.gpr(); + GPRReg scratchGPR = scratch.gpr(); GPRReg resultTagGPR = resultTag.gpr(); GPRReg resultPayloadGPR = resultPayload.gpr(); - - m_jit.move(valuePayloadGPR, resultPayloadGPR); - m_jit.move(valueTagGPR, resultTagGPR); - - JITCompiler::Jump notCreated = m_jit.branch32(JITCompiler::Equal, valueTagGPR, TrustedImm32(JSValue::EmptyValueTag)); - - addSlowPathGenerator( - slowPathCall( - notCreated, this, operationNewFunction, JSValueRegs(resultTagGPR, resultPayloadGPR), - m_jit.codeBlock()->functionDecl(node->functionDeclIndex()))); - + + MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR, + MacroAssembler::Address(enumeratorGPR, (op == GetEnumeratorStructurePname) + ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset() + : JSPropertyNameEnumerator::endGenericPropertyIndexOffset())); + + m_jit.move(MacroAssembler::TrustedImm32(JSValue::NullTag), resultTagGPR); + m_jit.move(MacroAssembler::TrustedImm32(0), resultPayloadGPR); + + MacroAssembler::Jump done = m_jit.jump(); + inBounds.link(&m_jit); + + m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratchGPR); + m_jit.loadPtr(MacroAssembler::BaseIndex(scratchGPR, indexGPR, MacroAssembler::ScalePtr), resultPayloadGPR); + m_jit.move(MacroAssembler::TrustedImm32(JSValue::CellTag), resultTagGPR); + + done.link(&m_jit); jsValueResult(resultTagGPR, resultPayloadGPR, node); break; } - - case NewFunctionExpression: - compileNewFunctionExpression(node); - break; - - case In: - compileIn(node); + case ToIndexString: { + SpeculateInt32Operand index(this, node->child1()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + callOperation(operationToIndexString, resultGPR, index.gpr()); + cellResult(resultGPR, node); break; + } + case ProfileType: { + JSValueOperand value(this, node->child1()); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + GPRTemporary scratch3(this); - case StoreBarrier: - case StoreBarrierWithNullCheck: { - compileStoreBarrier(node); + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg scratch2GPR = scratch2.gpr(); + GPRReg scratch3GPR = scratch3.gpr(); + + // Load the TypeProfilerLog into Scratch2. + TypeProfilerLog* cachedTypeProfilerLog = m_jit.vm()->typeProfilerLog(); + m_jit.move(TrustedImmPtr(cachedTypeProfilerLog), scratch2GPR); + + // Load the next LogEntry into Scratch1. + m_jit.loadPtr(MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()), scratch1GPR); + + // Store the JSValue onto the log entry. + m_jit.store32(value.tagGPR(), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(value.payloadGPR(), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::valueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + // Store the structureID of the cell if valueGPR is a cell, otherwise, store 0 on the log entry. + MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(value.jsValueRegs()); + m_jit.load32(MacroAssembler::Address(value.payloadGPR(), JSCell::structureIDOffset()), scratch3GPR); + m_jit.store32(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset())); + MacroAssembler::Jump skipIsCell = m_jit.jump(); + isNotCell.link(&m_jit); + m_jit.store32(TrustedImm32(0), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset())); + skipIsCell.link(&m_jit); + + // Store the typeLocation on the log entry. + TypeLocation* cachedTypeLocation = node->typeLocation(); + m_jit.move(TrustedImmPtr(cachedTypeLocation), scratch3GPR); + m_jit.storePtr(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::locationOffset())); + + // Increment the current log entry. + m_jit.addPtr(TrustedImm32(sizeof(TypeProfilerLog::LogEntry)), scratch1GPR); + m_jit.storePtr(scratch1GPR, MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset())); + MacroAssembler::Jump clearLog = m_jit.branchPtr(MacroAssembler::Equal, scratch1GPR, TrustedImmPtr(cachedTypeProfilerLog->logEndPtr())); + addSlowPathGenerator( + slowPathCall(clearLog, this, operationProcessTypeProfilerLogDFG, NoResult)); + + noResult(node); + break; + } + case ProfileControlFlow: { + BasicBlockLocation* basicBlockLocation = node->basicBlockLocation(); + if (!basicBlockLocation->hasExecuted()) { + GPRTemporary scratch1(this); + basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr()); + } + noResult(node); break; } @@ -4606,7 +4648,7 @@ void SpeculativeJIT::compile(Node* node) break; case Phantom: - case HardPhantom: + case Check: DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate); noResult(node); break; @@ -4619,7 +4661,8 @@ void SpeculativeJIT::compile(Node* node) // This is a no-op. noResult(node); break; - + + case Unreachable: RELEASE_ASSERT_NOT_REACHED(); break; @@ -4627,11 +4670,11 @@ void SpeculativeJIT::compile(Node* node) case LastNodeType: case Phi: case Upsilon: - case GetArgument: case ExtractOSREntryLocal: case CheckTierUpInLoop: case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: case Int52Rep: case FiatInt52: case Int52Constant: @@ -4639,7 +4682,22 @@ void SpeculativeJIT::compile(Node* node) case ArithIMul: case MultiGetByOffset: case MultiPutByOffset: - RELEASE_ASSERT_NOT_REACHED(); + case NativeCall: + case NativeConstruct: + case CheckBadCell: + case BottomValue: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PutStack: + case KillStack: + case GetStack: + case GetMyArgumentByVal: + DFG_CRASH(m_jit.graph(), node, "unexpected node in DFG backend"); break; } @@ -4657,57 +4715,15 @@ void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg valueTagGPR, Edge valu if (!isKnownCell(valueUse.node())) isNotCell = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::CellTag)); - JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR); + JITCompiler::Jump ownerIsRememberedOrInEden = m_jit.jumpIfIsRememberedOrInEden(ownerGPR); storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2); - ownerNotMarkedOrAlreadyRemembered.link(&m_jit); - - if (!isKnownCell(valueUse.node())) - isNotCell.link(&m_jit); -} - -void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueTagGPR, Edge valueUse, GPRReg scratch1, GPRReg scratch2) -{ - JITCompiler::Jump isNotCell; - if (!isKnownCell(valueUse.node())) - isNotCell = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::CellTag)); - - JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(owner); - storeToWriteBarrierBuffer(owner, scratch1, scratch2); - ownerNotMarkedOrAlreadyRemembered.link(&m_jit); + ownerIsRememberedOrInEden.link(&m_jit); if (!isKnownCell(valueUse.node())) isNotCell.link(&m_jit); } #endif // ENABLE(GGC) -JITCompiler::Jump SpeculativeJIT::branchIsCell(JSValueRegs regs) -{ - return m_jit.branch32(MacroAssembler::Equal, regs.tagGPR(), TrustedImm32(JSValue::CellTag)); -} - -JITCompiler::Jump SpeculativeJIT::branchNotCell(JSValueRegs regs) -{ - return m_jit.branch32(MacroAssembler::NotEqual, regs.tagGPR(), TrustedImm32(JSValue::CellTag)); -} - -JITCompiler::Jump SpeculativeJIT::branchIsOther(JSValueRegs regs, GPRReg tempGPR) -{ - m_jit.move(regs.tagGPR(), tempGPR); - m_jit.or32(TrustedImm32(1), tempGPR); - return m_jit.branch32( - MacroAssembler::Equal, tempGPR, - MacroAssembler::TrustedImm32(JSValue::NullTag)); -} - -JITCompiler::Jump SpeculativeJIT::branchNotOther(JSValueRegs regs, GPRReg tempGPR) -{ - m_jit.move(regs.tagGPR(), tempGPR); - m_jit.or32(TrustedImm32(1), tempGPR); - return m_jit.branch32( - MacroAssembler::NotEqual, tempGPR, - MacroAssembler::TrustedImm32(JSValue::NullTag)); -} - void SpeculativeJIT::moveTrueTo(GPRReg gpr) { m_jit.move(TrustedImm32(1), gpr); diff --git a/dfg/DFGSpeculativeJIT64.cpp b/dfg/DFGSpeculativeJIT64.cpp index eb11796..2c78f9a 100644 --- a/dfg/DFGSpeculativeJIT64.cpp +++ b/dfg/DFGSpeculativeJIT64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,16 +28,22 @@ #if ENABLE(DFG_JIT) -#include "Arguments.h" #include "ArrayPrototype.h" #include "DFGAbstractInterpreterInlines.h" #include "DFGCallArrayAllocatorSlowPathGenerator.h" #include "DFGOperations.h" #include "DFGSlowPathGenerator.h" #include "Debugger.h" +#include "DirectArguments.h" +#include "GetterSetter.h" #include "JSCInlines.h" +#include "JSEnvironmentRecord.h" +#include "JSLexicalEnvironment.h" +#include "JSPropertyNameEnumerator.h" #include "ObjectPrototype.h" +#include "SetupVarargsFrame.h" #include "SpillRegistersMode.h" +#include "TypeProfilerLog.h" namespace JSC { namespace DFG { @@ -79,21 +85,9 @@ GPRReg SpeculativeJIT::fillJSValue(Edge edge) GPRReg gpr = allocate(); if (edge->hasConstant()) { - if (isInt32Constant(edge.node())) { - info.fillJSValue(*m_stream, gpr, DataFormatJSInt32); - JSValue jsValue = jsNumber(valueOfInt32Constant(edge.node())); - m_jit.move(MacroAssembler::Imm64(JSValue::encode(jsValue)), gpr); - } else if (isNumberConstant(edge.node())) { - info.fillJSValue(*m_stream, gpr, DataFormatJSDouble); - JSValue jsValue(JSValue::EncodeAsDouble, valueOfNumberConstant(edge.node())); - m_jit.move(MacroAssembler::Imm64(JSValue::encode(jsValue)), gpr); - } else { - ASSERT(isJSConstant(edge.node())); - JSValue jsValue = valueOfJSConstant(edge.node()); - m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr); - info.fillJSValue(*m_stream, gpr, DataFormatJS); - } - + JSValue jsValue = edge->asJSValue(); + m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr); + info.fillJSValue(*m_stream, gpr, DataFormatJS); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); } else { DataFormat spillFormat = info.spillFormat(); @@ -108,7 +102,7 @@ GPRReg SpeculativeJIT::fillJSValue(Edge edge) default: m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); - RELEASE_ASSERT(spillFormat & DataFormatJS); + DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat & DataFormatJS); break; } info.fillJSValue(*m_stream, gpr, spillFormat); @@ -148,10 +142,10 @@ GPRReg SpeculativeJIT::fillJSValue(Edge edge) case DataFormatDouble: case DataFormatInt52: // this type currently never occurs - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format"); default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format"); return InvalidGPRReg; } } @@ -168,12 +162,12 @@ void SpeculativeJIT::cachedGetById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg slowCases.append(slowPathTarget); slowCases.append(gen.slowPathJump()); - OwnPtr<SlowPathGenerator> slowPath = slowPathCall( + auto slowPath = slowPathCall( slowCases, this, operationGetByIdOptimize, resultGPR, gen.stubInfo(), baseGPR, identifierUID(identifierNumber), spillMode); m_jit.addGetById(gen, slowPath.get()); - addSlowPathGenerator(slowPath.release()); + addSlowPathGenerator(WTF::move(slowPath)); } void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode) @@ -189,12 +183,12 @@ void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg slowCases.append(slowPathTarget); slowCases.append(gen.slowPathJump()); - OwnPtr<SlowPathGenerator> slowPath = slowPathCall( + auto slowPath = slowPathCall( slowCases, this, gen.slowPathFunction(), NoResult, gen.stubInfo(), valueGPR, baseGPR, identifierUID(identifierNumber)); m_jit.addPutById(gen, slowPath.get()); - addSlowPathGenerator(slowPath.release()); + addSlowPathGenerator(WTF::move(slowPath)); } void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool invert) @@ -210,7 +204,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv JITCompiler::Jump notMasqueradesAsUndefined; if (masqueradesAsUndefinedWatchpointIsStillValid()) { if (!isKnownCell(operand.node())) - notCell = branchNotCell(JSValueRegs(argGPR)); + notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR)); m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultGPR); notMasqueradesAsUndefined = m_jit.jump(); @@ -220,7 +214,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv GPRTemporary scratch(this); if (!isKnownCell(operand.node())) - notCell = branchNotCell(JSValueRegs(argGPR)); + notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR)); JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8( JITCompiler::NonZero, @@ -279,7 +273,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch if (masqueradesAsUndefinedWatchpointIsStillValid()) { if (!isKnownCell(operand.node())) - notCell = branchNotCell(JSValueRegs(argGPR)); + notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR)); jump(invert ? taken : notTaken, ForceJump); } else { @@ -288,7 +282,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, Node* branch GPRTemporary scratch(this); if (!isKnownCell(operand.node())) - notCell = branchNotCell(JSValueRegs(argGPR)); + notCell = m_jit.branchIfNotCell(JSValueRegs(argGPR)); branchTest8(JITCompiler::Zero, JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()), @@ -322,7 +316,7 @@ bool SpeculativeJIT::nonSpeculativeCompareNull(Node* node, Edge operand, bool in if (branchIndexInBlock != UINT_MAX) { Node* branchNode = m_block->at(branchIndexInBlock); - RELEASE_ASSERT(node->adjustedRefCount() == 1); + DFG_ASSERT(m_jit.graph(), node, node->adjustedRefCount() == 1); nonSpeculativePeepholeBranchNull(operand, branchNode, invert); @@ -364,7 +358,7 @@ void SpeculativeJIT::nonSpeculativePeepholeBranch(Node* node, Node* branchNode, JITCompiler::JumpList slowPath; if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) { - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); arg1.use(); @@ -447,7 +441,7 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler JITCompiler::JumpList slowPath; if (isKnownNotInteger(node->child1().node()) || isKnownNotInteger(node->child2().node())) { - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); arg1.use(); @@ -474,9 +468,8 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompare(Node* node, MacroAssembler m_jit.or32(TrustedImm32(ValueFalse), resultGPR); if (!isKnownInteger(node->child1().node()) || !isKnownInteger(node->child2().node())) { - addSlowPathGenerator(adoptPtr( - new CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>( - slowPath, this, helperFunction, resultGPR, arg1GPR, arg2GPR))); + addSlowPathGenerator(std::make_unique<CompareAndBoxBooleanSlowPathGenerator<JITCompiler::JumpList>>( + slowPath, this, helperFunction, resultGPR, arg1GPR, arg2GPR)); } jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean, UseChildrenCalledExplicitly); @@ -606,11 +599,9 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node* node, bool invert) m_jit.move(JITCompiler::TrustedImm64(JSValue::encode(jsBoolean(!invert))), resultGPR); - addSlowPathGenerator( - adoptPtr( - new CompareAndBoxBooleanSlowPathGenerator<MacroAssembler::JumpList>( + addSlowPathGenerator(std::make_unique<CompareAndBoxBooleanSlowPathGenerator<MacroAssembler::JumpList>>( slowPathCases, this, operationCompareStrictEq, resultGPR, arg1GPR, - arg2GPR))); + arg2GPR)); done.link(&m_jit); } @@ -636,41 +627,144 @@ void SpeculativeJIT::compileMiscStrictEq(Node* node) void SpeculativeJIT::emitCall(Node* node) { - if (node->op() != Call) - RELEASE_ASSERT(node->op() == Construct); + CallLinkInfo::CallType callType; + bool isVarargs = false; + bool isForwardVarargs = false; + switch (node->op()) { + case Call: + callType = CallLinkInfo::Call; + break; + case Construct: + callType = CallLinkInfo::Construct; + break; + case CallVarargs: + callType = CallLinkInfo::CallVarargs; + isVarargs = true; + break; + case ConstructVarargs: + callType = CallLinkInfo::ConstructVarargs; + isVarargs = true; + break; + case CallForwardVarargs: + callType = CallLinkInfo::CallVarargs; + isForwardVarargs = true; + break; + case ConstructForwardVarargs: + callType = CallLinkInfo::ConstructVarargs; + isForwardVarargs = true; + break; + default: + DFG_CRASH(m_jit.graph(), node, "bad node type"); + break; + } - // For constructors, the this argument is not passed but we have to make space - // for it. - int dummyThisArgument = node->op() == Call ? 0 : 1; - - CallLinkInfo::CallType callType = node->op() == Call ? CallLinkInfo::Call : CallLinkInfo::Construct; + Edge calleeEdge = m_jit.graph().child(node, 0); - Edge calleeEdge = m_jit.graph().m_varArgChildren[node->firstChild()]; - JSValueOperand callee(this, calleeEdge); - GPRReg calleeGPR = callee.gpr(); - use(calleeEdge); - - // The call instruction's first child is the function; the subsequent children are the - // arguments. - int numPassedArgs = node->numChildren() - 1; - - int numArgs = numPassedArgs + dummyThisArgument; - - m_jit.store32(MacroAssembler::TrustedImm32(numArgs), calleeFramePayloadSlot(JSStack::ArgumentCount)); - m_jit.store64(calleeGPR, calleeFrameSlot(JSStack::Callee)); + // Gotta load the arguments somehow. Varargs is trickier. + if (isVarargs || isForwardVarargs) { + CallVarargsData* data = node->callVarargsData(); + + GPRReg resultGPR; + unsigned numUsedStackSlots = m_jit.graph().m_nextMachineLocal; + + if (isForwardVarargs) { + flushRegisters(); + use(node->child2()); + + GPRReg scratchGPR1; + GPRReg scratchGPR2; + GPRReg scratchGPR3; + + scratchGPR1 = JITCompiler::selectScratchGPR(); + scratchGPR2 = JITCompiler::selectScratchGPR(scratchGPR1); + scratchGPR3 = JITCompiler::selectScratchGPR(scratchGPR1, scratchGPR2); + + m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR2); + JITCompiler::JumpList slowCase; + emitSetupVarargsFrameFastCase(m_jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, node->child2()->origin.semantic.inlineCallFrame, data->firstVarArgOffset, slowCase); + JITCompiler::Jump done = m_jit.jump(); + slowCase.link(&m_jit); + callOperation(operationThrowStackOverflowForVarargs); + m_jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow); + done.link(&m_jit); + resultGPR = scratchGPR2; + } else { + GPRReg argumentsGPR; + GPRReg scratchGPR1; + GPRReg scratchGPR2; + GPRReg scratchGPR3; + + auto loadArgumentsGPR = [&] (GPRReg reservedGPR) { + if (reservedGPR != InvalidGPRReg) + lock(reservedGPR); + JSValueOperand arguments(this, node->child2()); + argumentsGPR = arguments.gpr(); + if (reservedGPR != InvalidGPRReg) + unlock(reservedGPR); + flushRegisters(); + + scratchGPR1 = JITCompiler::selectScratchGPR(argumentsGPR, reservedGPR); + scratchGPR2 = JITCompiler::selectScratchGPR(argumentsGPR, scratchGPR1, reservedGPR); + scratchGPR3 = JITCompiler::selectScratchGPR(argumentsGPR, scratchGPR1, scratchGPR2, reservedGPR); + }; + + loadArgumentsGPR(InvalidGPRReg); + + DFG_ASSERT(m_jit.graph(), node, isFlushed()); + + // Right now, arguments is in argumentsGPR and the register file is flushed. + callOperation(operationSizeFrameForVarargs, GPRInfo::returnValueGPR, argumentsGPR, numUsedStackSlots, data->firstVarArgOffset); + + // Now we have the argument count of the callee frame, but we've lost the arguments operand. + // Reconstruct the arguments operand while preserving the callee frame. + loadArgumentsGPR(GPRInfo::returnValueGPR); + m_jit.move(TrustedImm32(numUsedStackSlots), scratchGPR1); + emitSetVarargsFrame(m_jit, GPRInfo::returnValueGPR, false, scratchGPR1, scratchGPR1); + m_jit.addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(void*)))), scratchGPR1, JITCompiler::stackPointerRegister); + + callOperation(operationSetupVarargsFrame, GPRInfo::returnValueGPR, scratchGPR1, argumentsGPR, data->firstVarArgOffset, GPRInfo::returnValueGPR); + resultGPR = GPRInfo::returnValueGPR; + } + + m_jit.addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), resultGPR, JITCompiler::stackPointerRegister); + + DFG_ASSERT(m_jit.graph(), node, isFlushed()); + + // We don't need the arguments array anymore. + if (isVarargs) + use(node->child2()); + + // Now set up the "this" argument. + JSValueOperand thisArgument(this, node->child3()); + GPRReg thisArgumentGPR = thisArgument.gpr(); + thisArgument.use(); + + m_jit.store64(thisArgumentGPR, JITCompiler::calleeArgumentSlot(0)); + } else { + // The call instruction's first child is the function; the subsequent children are the + // arguments. + int numPassedArgs = node->numChildren() - 1; + + m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(JSStack::ArgumentCount)); - for (int i = 0; i < numPassedArgs; i++) { - Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i]; - JSValueOperand arg(this, argEdge); - GPRReg argGPR = arg.gpr(); - use(argEdge); + for (int i = 0; i < numPassedArgs; i++) { + Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i]; + JSValueOperand arg(this, argEdge); + GPRReg argGPR = arg.gpr(); + use(argEdge); - m_jit.store64(argGPR, calleeArgumentSlot(i + dummyThisArgument)); + m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i)); + } } + JSValueOperand callee(this, calleeEdge); + GPRReg calleeGPR = callee.gpr(); + callee.use(); + m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(JSStack::Callee)); + flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); JITCompiler::DataLabelPtr targetToCheck; @@ -678,11 +772,10 @@ void SpeculativeJIT::emitCall(Node* node) m_jit.emitStoreCodeOrigin(node->origin.semantic); + CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo(); + slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0)); - m_jit.loadPtr(MacroAssembler::Address(calleeGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultGPR); - m_jit.store64(resultGPR, calleeFrameSlot(JSStack::ScopeChain)); - JITCompiler::Call fastCall = m_jit.nearCall(); JITCompiler::Jump done = m_jit.jump(); @@ -690,7 +783,6 @@ void SpeculativeJIT::emitCall(Node* node) slowPath.link(&m_jit); m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0 - CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo(); m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2 JITCompiler::Call slowCall = m_jit.nearCall(); @@ -700,11 +792,12 @@ void SpeculativeJIT::emitCall(Node* node) jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly); - callLinkInfo->callType = callType; - callLinkInfo->codeOrigin = m_currentNode->origin.semantic; - callLinkInfo->calleeGPR = calleeGPR; - + callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR); m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo); + + // If we were varargs, then after the calls are done, we need to reestablish our stack pointer. + if (isVarargs || isForwardVarargs) + m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister); } // Clang should allow unreachable [[clang::fallthrough]] in template functions if any template expansion uses it @@ -721,28 +814,25 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF AbstractValue& value = m_state.forNode(edge); SpeculatedType type = value.m_type; ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32)); - m_interpreter.filter(value, SpecInt32); - VirtualRegister virtualRegister = edge->virtualRegister(); - GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); - if (edge->hasConstant() && !isInt32Constant(edge.node())) { - // Protect the silent spill/fill logic by failing early. If we "speculate" on - // the constant then the silent filler may think that we have an int32 and a - // constant, so it will try to fill this as an int32 constant. Bad things will - // happen. + m_interpreter.filter(value, SpecInt32); + if (value.isClear()) { terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); returnFormat = DataFormatInt32; return allocate(); } - + + VirtualRegister virtualRegister = edge->virtualRegister(); + GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); + switch (info.registerFormat()) { case DataFormatNone: { GPRReg gpr = allocate(); if (edge->hasConstant()) { m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - ASSERT(isInt32Constant(edge.node())); - m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr); + ASSERT(edge->isInt32Constant()); + m_jit.move(MacroAssembler::Imm32(edge->asInt32()), gpr); info.fillInt32(*m_stream, gpr); returnFormat = DataFormatInt32; return gpr; @@ -750,7 +840,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF DataFormat spillFormat = info.spillFormat(); - RELEASE_ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatInt32); + DFG_ASSERT(m_jit.graph(), m_currentNode, (spillFormat & DataFormatJS) || spillFormat == DataFormatInt32); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); @@ -780,7 +870,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF } case DataFormatJS: { - RELEASE_ASSERT(!(type & SpecInt52)); + DFG_ASSERT(m_jit.graph(), m_currentNode, !(type & SpecInt52)); // Check the value is an integer. GPRReg gpr = info.gpr(); m_gprs.lock(gpr); @@ -833,20 +923,15 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Internal(Edge edge, DataFormat& returnF case DataFormatCell: case DataFormatBoolean: case DataFormatJSCell: - case DataFormatJSBoolean: { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - returnFormat = DataFormatInt32; - return allocate(); - } - + case DataFormatJSBoolean: case DataFormatDouble: case DataFormatStorage: case DataFormatInt52: case DataFormatStrictInt52: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format"); default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format"); return InvalidGPRReg; } } @@ -863,7 +948,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt32Strict(Edge edge) { DataFormat mustBeDataFormatInt32; GPRReg result = fillSpeculateInt32Internal<true>(edge, mustBeDataFormatInt32); - RELEASE_ASSERT(mustBeDataFormatInt32 == DataFormatInt32); + DFG_ASSERT(m_jit.graph(), m_currentNode, mustBeDataFormatInt32 == DataFormatInt32); return result; } @@ -871,21 +956,22 @@ GPRReg SpeculativeJIT::fillSpeculateInt52(Edge edge, DataFormat desiredFormat) { ASSERT(desiredFormat == DataFormatInt52 || desiredFormat == DataFormatStrictInt52); AbstractValue& value = m_state.forNode(edge); + m_interpreter.filter(value, SpecMachineInt); + if (value.isClear()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + return allocate(); + } + VirtualRegister virtualRegister = edge->virtualRegister(); GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); switch (info.registerFormat()) { case DataFormatNone: { - if ((edge->hasConstant() && !valueOfJSConstant(edge.node()).isMachineInt())) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - } - GPRReg gpr = allocate(); if (edge->hasConstant()) { - JSValue jsValue = valueOfJSConstant(edge.node()); + JSValue jsValue = edge->asJSValue(); ASSERT(jsValue.isMachineInt()); m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); int64_t value = jsValue.asMachineInt(); @@ -898,7 +984,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt52(Edge edge, DataFormat desiredFormat) DataFormat spillFormat = info.spillFormat(); - RELEASE_ASSERT(spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52); + DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); @@ -950,7 +1036,7 @@ GPRReg SpeculativeJIT::fillSpeculateInt52(Edge edge, DataFormat desiredFormat) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format"); return InvalidGPRReg; } } @@ -966,9 +1052,9 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge) if (edge->hasConstant()) { GPRReg gpr = allocate(); - if (isNumberConstant(edge.node())) { + if (edge->isNumberConstant()) { FPRReg fpr = fprAllocate(); - m_jit.move(MacroAssembler::Imm64(reinterpretDoubleToInt64(valueOfNumberConstant(edge.node()))), gpr); + m_jit.move(MacroAssembler::Imm64(reinterpretDoubleToInt64(edge->asNumber())), gpr); m_jit.move64ToDouble(gpr, fpr); unlock(gpr); @@ -981,7 +1067,13 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge) } DataFormat spillFormat = info.spillFormat(); - RELEASE_ASSERT(spillFormat == DataFormatDouble); + if (spillFormat != DataFormatDouble) { + DFG_CRASH( + m_jit.graph(), m_currentNode, toCString( + "Expected ", edge, " to have double format but instead it is spilled as ", + dataFormatToString(spillFormat)).data()); + } + DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatDouble); FPRReg fpr = fprAllocate(); m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr); m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); @@ -989,7 +1081,7 @@ FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge) return fpr; } - RELEASE_ASSERT(info.registerFormat() == DataFormatDouble); + DFG_ASSERT(m_jit.graph(), m_currentNode, info.registerFormat() == DataFormatDouble); FPRReg fpr = info.fpr(); m_fprs.lock(fpr); return fpr; @@ -1000,7 +1092,13 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) AbstractValue& value = m_state.forNode(edge); SpeculatedType type = value.m_type; ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell)); + m_interpreter.filter(value, SpecCell); + if (value.isClear()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + return allocate(); + } + VirtualRegister virtualRegister = edge->virtualRegister(); GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); @@ -1009,28 +1107,19 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) GPRReg gpr = allocate(); if (edge->hasConstant()) { - JSValue jsValue = valueOfJSConstant(edge.node()); - if (jsValue.isCell()) { - m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr); - info.fillJSValue(*m_stream, gpr, DataFormatJSCell); - return gpr; - } - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return gpr; - } - - if (!(info.spillFormat() & DataFormatJS)) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + JSValue jsValue = edge->asJSValue(); + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr); + info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } - + m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); info.fillJSValue(*m_stream, gpr, DataFormatJS); if (type & ~SpecCell) - speculationCheck(BadType, JSValueRegs(gpr), edge, branchNotCell(JSValueRegs(gpr))); + speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchIfNotCell(JSValueRegs(gpr))); info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } @@ -1040,7 +1129,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) GPRReg gpr = info.gpr(); m_gprs.lock(gpr); if (!ASSERT_DISABLED) { - MacroAssembler::Jump checkCell = branchIsCell(JSValueRegs(gpr)); + MacroAssembler::Jump checkCell = m_jit.branchIfCell(JSValueRegs(gpr)); m_jit.abortWithReason(DFGIsNotCell); checkCell.link(&m_jit); } @@ -1051,7 +1140,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) GPRReg gpr = info.gpr(); m_gprs.lock(gpr); if (type & ~SpecCell) - speculationCheck(BadType, JSValueRegs(gpr), edge, branchNotCell(JSValueRegs(gpr))); + speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchIfNotCell(JSValueRegs(gpr))); info.fillJSValue(*m_stream, gpr, DataFormatJSCell); return gpr; } @@ -1060,19 +1149,15 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge) case DataFormatInt32: case DataFormatJSDouble: case DataFormatJSBoolean: - case DataFormatBoolean: { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - } - + case DataFormatBoolean: case DataFormatDouble: case DataFormatStorage: case DataFormatInt52: case DataFormatStrictInt52: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format"); default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format"); return InvalidGPRReg; } } @@ -1081,31 +1166,28 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge) { AbstractValue& value = m_state.forNode(edge); SpeculatedType type = value.m_type; + m_interpreter.filter(value, SpecBoolean); + if (value.isClear()) { + terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + return allocate(); + } + VirtualRegister virtualRegister = edge->virtualRegister(); GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister); switch (info.registerFormat()) { case DataFormatNone: { - if (info.spillFormat() == DataFormatInt32) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - } - GPRReg gpr = allocate(); if (edge->hasConstant()) { - JSValue jsValue = valueOfJSConstant(edge.node()); - if (jsValue.isBoolean()) { - m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); - m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr); - info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); - return gpr; - } - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); + JSValue jsValue = edge->asJSValue(); + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr); + info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean); return gpr; } - RELEASE_ASSERT(info.spillFormat() & DataFormatJS); + DFG_ASSERT(m_jit.graph(), m_currentNode, info.spillFormat() & DataFormatJS); m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr); @@ -1143,17 +1225,14 @@ GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge) case DataFormatJSDouble: case DataFormatJSCell: case DataFormatCell: - terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0); - return allocate(); - case DataFormatDouble: case DataFormatStorage: case DataFormatInt52: case DataFormatStrictInt52: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format"); default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format"); return InvalidGPRReg; } } @@ -1187,21 +1266,12 @@ void SpeculativeJIT::compileObjectEquality(Node* node) if (masqueradesAsUndefinedWatchpointIsStillValid()) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR)); DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR)); } else { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchIfNotObject(op1GPR)); speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(), m_jit.branchTest8( MacroAssembler::NonZero, @@ -1209,10 +1279,7 @@ void SpeculativeJIT::compileObjectEquality(Node* node) MacroAssembler::TrustedImm32(MasqueradesAsUndefined))); DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchIfNotObject(op2GPR)); speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(), m_jit.branchTest8( MacroAssembler::NonZero, @@ -1230,6 +1297,47 @@ void SpeculativeJIT::compileObjectEquality(Node* node) jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean); } +void SpeculativeJIT::compileObjectStrictEquality(Edge objectChild, Edge otherChild) +{ + SpeculateCellOperand op1(this, objectChild); + JSValueOperand op2(this, otherChild); + GPRTemporary result(this); + + GPRReg op1GPR = op1.gpr(); + GPRReg op2GPR = op2.gpr(); + GPRReg resultGPR = result.gpr(); + + DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); + + // At this point we know that we can perform a straight-forward equality comparison on pointer + // values because we are doing strict equality. + m_jit.compare64(MacroAssembler::Equal, op1GPR, op2GPR, resultGPR); + m_jit.or32(TrustedImm32(ValueFalse), resultGPR); + jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean); +} + +void SpeculativeJIT::compilePeepHoleObjectStrictEquality(Edge objectChild, Edge otherChild, Node* branchNode) +{ + BasicBlock* taken = branchNode->branchData()->taken.block; + BasicBlock* notTaken = branchNode->branchData()->notTaken.block; + + SpeculateCellOperand op1(this, objectChild); + JSValueOperand op2(this, otherChild); + + GPRReg op1GPR = op1.gpr(); + GPRReg op2GPR = op2.gpr(); + + DFG_TYPE_CHECK(JSValueSource::unboxedCell(op1GPR), objectChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); + + if (taken == nextBlock()) { + branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR, notTaken); + jump(taken); + } else { + branchPtr(MacroAssembler::Equal, op1GPR, op2GPR, taken); + jump(notTaken); + } +} + void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild) { SpeculateCellOperand op1(this, leftChild); @@ -1245,16 +1353,10 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); } else { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1264,21 +1366,15 @@ void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge r // It seems that most of the time when programs do a == b where b may be either null/undefined // or an object, b is usually an object. Balance the branches to make that case fast. - MacroAssembler::Jump rightNotCell = branchNotCell(JSValueRegs(op2GPR)); + MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(JSValueRegs(op2GPR)); // We know that within this branch, rightChild must be a cell. if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2GPR)); } else { DFG_TYPE_CHECK( - JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2GPR)); speculationCheck(BadType, JSValueRegs(op2GPR), rightChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1335,16 +1431,10 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); } else { DFG_TYPE_CHECK( - JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchIfNotObject(op1GPR)); speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1354,21 +1444,15 @@ void SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality(Edge leftChild // It seems that most of the time when programs do a == b where b may be either null/undefined // or an object, b is usually an object. Balance the branches to make that case fast. - MacroAssembler::Jump rightNotCell = branchNotCell(JSValueRegs(op2GPR)); + MacroAssembler::Jump rightNotCell = m_jit.branchIfNotCell(JSValueRegs(op2GPR)); // We know that within this branch, rightChild must be a cell. if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2GPR)); } else { DFG_TYPE_CHECK( - JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(op2GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(op2GPR)); speculationCheck(BadType, JSValueRegs(op2GPR), rightChild, m_jit.branchTest8( MacroAssembler::NonZero, @@ -1487,19 +1571,13 @@ void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse) scratchGPR = scratch.gpr(); } - MacroAssembler::Jump notCell = branchNotCell(JSValueRegs(valueGPR)); + MacroAssembler::Jump notCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR)); if (masqueradesAsUndefinedWatchpointValid) { DFG_TYPE_CHECK( - JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(valueGPR)); } else { DFG_TYPE_CHECK( - JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(valueGPR)); MacroAssembler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8( @@ -1617,7 +1695,7 @@ void SpeculativeJIT::compileLogicalNot(Node* node) return compileStringZeroLength(node); default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } } @@ -1637,19 +1715,13 @@ void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BasicBlock* taken, Ba structureGPR = structure.gpr(); } - MacroAssembler::Jump notCell = branchNotCell(JSValueRegs(valueGPR)); + MacroAssembler::Jump notCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR)); if (masqueradesAsUndefinedWatchpointIsStillValid()) { DFG_TYPE_CHECK( - JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(valueGPR)); } else { DFG_TYPE_CHECK( - JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr( - MacroAssembler::Equal, - MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get())); + JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchIfNotObject(valueGPR)); JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8( JITCompiler::Zero, @@ -1718,6 +1790,11 @@ void SpeculativeJIT::emitBranch(Node* node) return; } + case StringUse: { + emitStringBranch(node->child1(), taken, notTaken); + return; + } + case UntypedUse: case BooleanUse: { JSValueOperand value(this, node->child1(), ManualOperandSpeculation); @@ -1772,7 +1849,7 @@ void SpeculativeJIT::emitBranch(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), m_currentNode, "Bad use kind"); } } @@ -1788,21 +1865,38 @@ void SpeculativeJIT::compile(Node* node) case JSConstant: case DoubleConstant: case Int52Constant: + case PhantomDirectArguments: + case PhantomClonedArguments: initConstantInfo(node); break; - case PhantomArguments: - initConstantInfo(node); - break; - - case WeakJSConstant: - m_jit.addWeakReference(node->weakConstant()); - initConstantInfo(node); - break; - case Identity: { - // CSE should always eliminate this. - RELEASE_ASSERT_NOT_REACHED(); + speculate(node, node->child1()); + switch (node->child1().useKind()) { + case DoubleRepUse: + case DoubleRepRealUse: + case DoubleRepMachineIntUse: { + SpeculateDoubleOperand op(this, node->child1()); + FPRTemporary scratch(this, op); + m_jit.moveDouble(op.fpr(), scratch.fpr()); + doubleResult(scratch.fpr(), node); + break; + } + case Int52RepUse: { + SpeculateInt52Operand op(this, node->child1()); + GPRTemporary result(this, Reuse, op); + m_jit.move(op.gpr(), result.gpr()); + int52Result(result.gpr(), node); + break; + } + default: { + JSValueOperand op(this, node->child1()); + GPRTemporary result(this, Reuse, op); + m_jit.move(op.gpr(), result.gpr()); + jsValueResult(result.gpr(), node); + break; + } + } // switch break; } @@ -1812,9 +1906,7 @@ void SpeculativeJIT::compile(Node* node) // If the CFA is tracking this variable and it found that the variable // cannot have been assigned, then don't attempt to proceed. if (value.isClear()) { - // FIXME: We should trap instead. - // https://bugs.webkit.org/show_bug.cgi?id=110383 - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0); + m_compileOkay = false; break; } @@ -1882,13 +1974,18 @@ void SpeculativeJIT::compile(Node* node) break; } - case MovHint: - case ZombieHint: - case Check: { - RELEASE_ASSERT_NOT_REACHED(); + case MovHint: { + compileMovHint(m_currentNode); + noResult(node); + break; + } + + case ZombieHint: { + recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead); + noResult(node); break; } - + case SetLocal: { switch (node->variableAccessData()->flushFormat()) { case FlushedDouble: { @@ -1935,8 +2032,7 @@ void SpeculativeJIT::compile(Node* node) break; } - case FlushedJSValue: - case FlushedArguments: { + case FlushedJSValue: { JSValueOperand value(this, node->child1()); m_jit.store64(value.gpr(), JITCompiler::addressFor(node->machineLocal())); noResult(node); @@ -1945,7 +2041,7 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad flush format"); break; } @@ -1963,18 +2059,18 @@ void SpeculativeJIT::compile(Node* node) case BitAnd: case BitOr: case BitXor: - if (isInt32Constant(node->child1().node())) { + if (node->child1()->isInt32Constant()) { SpeculateInt32Operand op2(this, node->child2()); GPRTemporary result(this, Reuse, op2); - bitOp(op, valueOfInt32Constant(node->child1().node()), op2.gpr(), result.gpr()); + bitOp(op, node->child1()->asInt32(), op2.gpr(), result.gpr()); int32Result(result.gpr(), node); - } else if (isInt32Constant(node->child2().node())) { + } else if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); GPRTemporary result(this, Reuse, op1); - bitOp(op, valueOfInt32Constant(node->child2().node()), op1.gpr(), result.gpr()); + bitOp(op, node->child2()->asInt32(), op1.gpr(), result.gpr()); int32Result(result.gpr(), node); } else { @@ -1993,11 +2089,11 @@ void SpeculativeJIT::compile(Node* node) case BitRShift: case BitLShift: case BitURShift: - if (isInt32Constant(node->child2().node())) { + if (node->child2()->isInt32Constant()) { SpeculateInt32Operand op1(this, node->child1()); GPRTemporary result(this, Reuse, op1); - shiftOp(op, op1.gpr(), valueOfInt32Constant(node->child2().node()) & 0x1f, result.gpr()); + shiftOp(op, op1.gpr(), node->child2()->asInt32() & 0x1f, result.gpr()); int32Result(result.gpr(), node); } else { @@ -2052,7 +2148,7 @@ void SpeculativeJIT::compile(Node* node) } case MachineIntUse: { - GPRResult result(this); + GPRTemporary result(this); GPRReg resultGPR = result.gpr(); convertMachineInt(node->child1(), resultGPR); @@ -2065,7 +2161,7 @@ void SpeculativeJIT::compile(Node* node) SpeculateDoubleOperand value(this, node->child1()); FPRReg valueFPR = value.fpr(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); flushRegisters(); @@ -2083,7 +2179,7 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); } break; } @@ -2097,7 +2193,7 @@ void SpeculativeJIT::compile(Node* node) flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); if (isKnownNotNumber(node->child1().node()) || isKnownNotNumber(node->child2().node())) callOperation(operationValueAddNotNumber, result.gpr(), op1GPR, op2GPR); else @@ -2110,6 +2206,10 @@ void SpeculativeJIT::compile(Node* node) case ArithAdd: compileAdd(node); break; + + case ArithClz32: + compileArithClz32(node); + break; case MakeRope: compileMakeRope(node); @@ -2163,7 +2263,7 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } break; @@ -2230,22 +2330,20 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } break; } - - case ArithSqrt: { - SpeculateDoubleOperand op1(this, node->child1()); - FPRTemporary result(this, op1); - - m_jit.sqrtDouble(op1.fpr(), result.fpr()); - - doubleResult(result.fpr(), node); + + case ArithPow: + compileArithPow(node); break; - } - + + case ArithSqrt: + compileArithSqrt(node); + break; + case ArithFRound: { SpeculateDoubleOperand op1(this, node->child1()); FPRTemporary result(this, op1); @@ -2257,6 +2355,10 @@ void SpeculativeJIT::compile(Node* node) break; } + case ArithRound: + compileArithRound(node); + break; + case ArithSin: { SpeculateDoubleOperand op1(this, node->child1()); FPRReg op1FPR = op1.fpr(); @@ -2281,6 +2383,10 @@ void SpeculativeJIT::compile(Node* node) break; } + case ArithLog: + compileArithLog(node); + break; + case LogicalNot: compileLogicalNot(node); break; @@ -2306,7 +2412,7 @@ void SpeculativeJIT::compile(Node* node) break; case CompareEqConstant: - ASSERT(isNullConstant(node->child2().node())); + ASSERT(node->child2()->asJSValue().isNull()); if (nonSpeculativeCompareNull(node, node->child1())) return; break; @@ -2352,8 +2458,7 @@ void SpeculativeJIT::compile(Node* node) switch (node->arrayMode().type()) { case Array::SelectUsingPredictions: case Array::ForceExit: - RELEASE_ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0); + DFG_CRASH(m_jit.graph(), node, "Bad array mode type"); break; case Array::Generic: { JSValueOperand base(this, node->child1()); @@ -2362,7 +2467,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg propertyGPR = property.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationGetByVal, result.gpr(), baseGPR, propertyGPR); jsValueResult(result.gpr(), node); @@ -2384,7 +2489,17 @@ void SpeculativeJIT::compile(Node* node) GPRTemporary result(this); m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr()); - speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchTest64(MacroAssembler::Zero, result.gpr())); + if (node->arrayMode().isSaneChain()) { + ASSERT(node->arrayMode().type() == Array::Contiguous); + JITCompiler::Jump notHole = m_jit.branchTest64( + MacroAssembler::NonZero, result.gpr()); + m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), result.gpr()); + notHole.link(&m_jit); + } else { + speculationCheck( + LoadFromHole, JSValueRegs(), 0, + m_jit.branchTest64(MacroAssembler::Zero, result.gpr())); + } jsValueResult(result.gpr(), node, node->arrayMode().type() == Array::Int32 ? DataFormatJSInt32 : DataFormatJS); break; } @@ -2527,8 +2642,11 @@ void SpeculativeJIT::compile(Node* node) case Array::String: compileGetByValOnString(node); break; - case Array::Arguments: - compileGetByValOnArguments(node); + case Array::DirectArguments: + compileGetByValOnDirectArguments(node); + break; + case Array::ScopedArguments: + compileGetByValOnScopedArguments(node); break; default: { TypedArrayType type = node->arrayMode().typedArrayType(); @@ -2554,12 +2672,10 @@ void SpeculativeJIT::compile(Node* node) switch (arrayMode.type()) { case Array::SelectUsingPredictions: case Array::ForceExit: - RELEASE_ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0); - alreadyHandled = true; + DFG_CRASH(m_jit.graph(), node, "Bad array mode type"); break; case Array::Generic: { - RELEASE_ASSERT(node->op() == PutByVal); + DFG_ASSERT(m_jit.graph(), node, node->op() == PutByVal || node->op() == PutByValDirect); JSValueOperand arg1(this, child1); JSValueOperand arg2(this, child2); @@ -2760,47 +2876,6 @@ void SpeculativeJIT::compile(Node* node) break; } - case Array::Arguments: { - JSValueOperand value(this, child3); - GPRTemporary scratch(this); - GPRTemporary scratch2(this); - - GPRReg valueReg = value.gpr(); - GPRReg scratchReg = scratch.gpr(); - GPRReg scratch2Reg = scratch2.gpr(); - - if (!m_compileOkay) - return; - - // Two really lame checks. - speculationCheck( - Uncountable, JSValueSource(), 0, - m_jit.branch32( - MacroAssembler::AboveOrEqual, propertyReg, - MacroAssembler::Address(baseReg, Arguments::offsetOfNumArguments()))); - speculationCheck( - Uncountable, JSValueSource(), 0, - m_jit.branchTestPtr( - MacroAssembler::NonZero, - MacroAssembler::Address( - baseReg, Arguments::offsetOfSlowArgumentData()))); - - m_jit.move(propertyReg, scratch2Reg); - m_jit.signExtend32ToPtr(scratch2Reg, scratch2Reg); - m_jit.loadPtr( - MacroAssembler::Address(baseReg, Arguments::offsetOfRegisters()), - scratchReg); - - m_jit.store64( - valueReg, - MacroAssembler::BaseIndex( - scratchReg, scratch2Reg, MacroAssembler::TimesEight, - CallFrame::thisArgumentOffset() * sizeof(Register) + sizeof(Register))); - - noResult(node); - break; - } - default: { TypedArrayType type = arrayMode.typedArrayType(); if (isInt(type)) @@ -2822,7 +2897,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR); // Must use jsValueResult because otherwise we screw up register @@ -2837,7 +2912,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationRegExpExec, result.gpr(), baseGPR, argumentGPR); jsValueResult(result.gpr(), node); @@ -2851,7 +2926,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg argumentGPR = argument.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR); // If we add a DataFormatBool, we should use it here. @@ -3117,6 +3192,13 @@ void SpeculativeJIT::compile(Node* node) JSValueOperand value(this, node->child1()); GPRTemporary result(this); + if (!m_interpreter.needsTypeCheck(node->child1(), SpecBoolInt32 | SpecBoolean)) { + m_jit.move(value.gpr(), result.gpr()); + m_jit.and32(TrustedImm32(1), result.gpr()); + int32Result(result.gpr(), node); + break; + } + m_jit.move(value.gpr(), result.gpr()); m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr()); JITCompiler::Jump isBoolean = m_jit.branchTest64( @@ -3132,14 +3214,14 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } break; } case ToPrimitive: { - RELEASE_ASSERT(node->child1().useKind() == UntypedUse); + DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse); JSValueOperand op1(this, node->child1()); GPRTemporary result(this, Reuse, op1); @@ -3148,11 +3230,8 @@ void SpeculativeJIT::compile(Node* node) op1.use(); - MacroAssembler::Jump alreadyPrimitive = branchNotCell(JSValueRegs(op1GPR)); - MacroAssembler::Jump notPrimitive = m_jit.branchStructurePtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get()); + MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(JSValueRegs(op1GPR)); + MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(op1GPR); alreadyPrimitive.link(&m_jit); m_jit.move(op1GPR, resultGPR); @@ -3164,36 +3243,39 @@ void SpeculativeJIT::compile(Node* node) break; } - case ToString: { + case ToString: + case CallStringConstructor: { if (node->child1().useKind() == UntypedUse) { JSValueOperand op1(this, node->child1()); GPRReg op1GPR = op1.gpr(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); flushRegisters(); JITCompiler::Jump done; if (node->child1()->prediction() & SpecString) { - JITCompiler::Jump slowPath1 = branchNotCell(JSValueRegs(op1GPR)); - JITCompiler::Jump slowPath2 = m_jit.branchStructurePtr( - JITCompiler::NotEqual, - JITCompiler::Address(op1GPR, JSCell::structureIDOffset()), - m_jit.vm()->stringStructure.get()); + JITCompiler::Jump slowPath1 = m_jit.branchIfNotCell(JSValueRegs(op1GPR)); + JITCompiler::Jump slowPath2 = m_jit.branchIfNotString(op1GPR); m_jit.move(op1GPR, resultGPR); done = m_jit.jump(); slowPath1.link(&m_jit); slowPath2.link(&m_jit); } - callOperation(operationToString, resultGPR, op1GPR); + if (op == ToString) + callOperation(operationToString, resultGPR, op1GPR); + else { + ASSERT(op == CallStringConstructor); + callOperation(operationCallStringConstructor, resultGPR, op1GPR); + } if (done.isSet()) done.link(&m_jit); cellResult(resultGPR, node); break; } - compileToStringOnCell(node); + compileToStringOrCallStringConstructorOnCell(node); break; } @@ -3206,7 +3288,7 @@ void SpeculativeJIT::compile(Node* node) JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(node->indexingType())) { Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()); - RELEASE_ASSERT(structure->indexingType() == node->indexingType()); + DFG_ASSERT(m_jit.graph(), node, structure->indexingType() == node->indexingType()); ASSERT( hasUndecided(structure->indexingType()) || hasInt32(structure->indexingType()) @@ -3277,7 +3359,7 @@ void SpeculativeJIT::compile(Node* node) if (!node->numChildren()) { flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationNewEmptyArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); cellResult(result.gpr(), node); break; @@ -3356,7 +3438,7 @@ void SpeculativeJIT::compile(Node* node) m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr()); } - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation( operationNewArray, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), @@ -3389,7 +3471,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg scratch2GPR = scratch2.gpr(); MacroAssembler::JumpList slowCases; - slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX))); + slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH))); ASSERT((1 << 3) == sizeof(JSValue)); m_jit.move(sizeGPR, scratchGPR); @@ -3415,12 +3497,11 @@ void SpeculativeJIT::compile(Node* node) done.link(&m_jit); } - addSlowPathGenerator(adoptPtr( - new CallArrayAllocatorWithVariableSizeSlowPathGenerator( + addSlowPathGenerator(std::make_unique<CallArrayAllocatorWithVariableSizeSlowPathGenerator>( slowCases, this, operationNewArrayWithSize, resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage), - sizeGPR))); + sizeGPR)); cellResult(resultGPR, node); break; @@ -3429,10 +3510,10 @@ void SpeculativeJIT::compile(Node* node) SpeculateStrictInt32Operand size(this, node->child1()); GPRReg sizeGPR = size.gpr(); flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); GPRReg structureGPR = selectScratchGPR(sizeGPR); - MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_SPARSE_ARRAY_INDEX)); + MacroAssembler::Jump bigLength = m_jit.branch32(MacroAssembler::AboveOrEqual, sizeGPR, TrustedImm32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)); m_jit.move(TrustedImmPtr(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())), structureGPR); MacroAssembler::Jump done = m_jit.jump(); bigLength.link(&m_jit); @@ -3457,7 +3538,7 @@ void SpeculativeJIT::compile(Node* node) emitAllocateJSArray(resultGPR, globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType), storageGPR, numElements); - RELEASE_ASSERT(indexingType & IsArray); + DFG_ASSERT(m_jit.graph(), node, indexingType & IsArray); JSValue* data = m_jit.codeBlock()->constantBuffer(node->startConstant()); if (indexingType == ArrayWithDouble) { for (unsigned index = 0; index < node->numConstants(); ++index) { @@ -3479,7 +3560,7 @@ void SpeculativeJIT::compile(Node* node) } flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationNewArrayBuffer, result.gpr(), globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()), node->startConstant(), node->numConstants()); @@ -3498,7 +3579,7 @@ void SpeculativeJIT::compile(Node* node) flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); @@ -3511,7 +3592,7 @@ void SpeculativeJIT::compile(Node* node) break; } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } break; @@ -3519,7 +3600,7 @@ void SpeculativeJIT::compile(Node* node) case NewRegexp: { flushRegisters(); - GPRResult result(this); + GPRFlushedCallResult result(this); callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node->regexpIndex())); @@ -3535,7 +3616,7 @@ void SpeculativeJIT::compile(Node* node) GPRReg tempGPR = temp.gpr(); MacroAssembler::JumpList slowCases; - slowCases.append(branchNotCell(JSValueRegs(thisValueGPR))); + slowCases.append(m_jit.branchIfNotCell(JSValueRegs(thisValueGPR))); slowCases.append(m_jit.branch8( MacroAssembler::NotEqual, MacroAssembler::Address(thisValueGPR, JSCell::typeInfoTypeOffset()), @@ -3571,11 +3652,16 @@ void SpeculativeJIT::compile(Node* node) GPRReg allocatorGPR = allocator.gpr(); GPRReg structureGPR = structure.gpr(); GPRReg scratchGPR = scratch.gpr(); + // Rare data is only used to access the allocator & structure + // We can avoid using an additional GPR this way + GPRReg rareDataGPR = structureGPR; MacroAssembler::JumpList slowPath; - m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR); - m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR); + m_jit.loadPtr(JITCompiler::Address(calleeGPR, JSFunction::offsetOfRareData()), rareDataGPR); + slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR)); + m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorGPR); + m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureGPR); slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, allocatorGPR)); emitAllocateJSObject(resultGPR, allocatorGPR, structureGPR, TrustedImmPtr(0), scratchGPR, slowPath); @@ -3585,12 +3671,6 @@ void SpeculativeJIT::compile(Node* node) break; } - case AllocationProfileWatchpoint: - case TypedArrayWatchpoint: { - noResult(node); - break; - } - case NewObject: { GPRTemporary result(this); GPRTemporary allocator(this); @@ -3622,85 +3702,39 @@ void SpeculativeJIT::compile(Node* node) break; } - case GetScope: { - SpeculateCellOperand function(this, node->child1()); - GPRTemporary result(this, Reuse, function); - m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr()); - cellResult(result.gpr(), node); - break; - } - - case GetMyScope: { + case GetArgumentCount: { GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - - m_jit.loadPtr(JITCompiler::addressFor(JSStack::ScopeChain), resultGPR); - cellResult(resultGPR, node); + m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), result.gpr()); + int32Result(result.gpr(), node); break; } - case SkipTopScope: { - SpeculateCellOperand scope(this, node->child1()); - GPRTemporary result(this, Reuse, scope); - GPRReg resultGPR = result.gpr(); - m_jit.move(scope.gpr(), resultGPR); - JITCompiler::Jump activationNotCreated = - m_jit.branchTest64( - JITCompiler::Zero, - JITCompiler::addressFor( - static_cast<VirtualRegister>(m_jit.graph().machineActivationRegister()))); - m_jit.loadPtr(JITCompiler::Address(resultGPR, JSScope::offsetOfNext()), resultGPR); - activationNotCreated.link(&m_jit); - cellResult(resultGPR, node); + case GetScope: + compileGetScope(node); break; - } - case SkipScope: { - SpeculateCellOperand scope(this, node->child1()); - GPRTemporary result(this, Reuse, scope); - m_jit.loadPtr(JITCompiler::Address(scope.gpr(), JSScope::offsetOfNext()), result.gpr()); - cellResult(result.gpr(), node); + case SkipScope: + compileSkipScope(node); break; - } - case GetClosureRegisters: { - if (WriteBarrierBase<Unknown>* registers = m_jit.graph().tryGetRegisters(node->child1().node())) { - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - m_jit.move(TrustedImmPtr(registers), resultGPR); - storageResult(resultGPR, node); - break; - } - - SpeculateCellOperand scope(this, node->child1()); + case GetClosureVar: { + SpeculateCellOperand base(this, node->child1()); GPRTemporary result(this); - GPRReg scopeGPR = scope.gpr(); + GPRReg baseGPR = base.gpr(); GPRReg resultGPR = result.gpr(); - m_jit.loadPtr(JITCompiler::Address(scopeGPR, JSVariableObject::offsetOfRegisters()), resultGPR); - storageResult(resultGPR, node); - break; - } - case GetClosureVar: { - StorageOperand registers(this, node->child1()); - GPRTemporary result(this); - GPRReg registersGPR = registers.gpr(); - GPRReg resultGPR = result.gpr(); - - m_jit.load64(JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register)), resultGPR); + m_jit.load64(JITCompiler::Address(baseGPR, JSEnvironmentRecord::offsetOfVariable(node->scopeOffset())), resultGPR); jsValueResult(resultGPR, node); break; } case PutClosureVar: { - StorageOperand registers(this, node->child2()); - JSValueOperand value(this, node->child3()); + SpeculateCellOperand base(this, node->child1()); + JSValueOperand value(this, node->child2()); - GPRReg registersGPR = registers.gpr(); + GPRReg baseGPR = base.gpr(); GPRReg valueGPR = value.gpr(); - speculate(node, node->child1()); - - m_jit.store64(valueGPR, JITCompiler::Address(registersGPR, node->varNumber() * sizeof(Register))); + m_jit.store64(valueGPR, JITCompiler::Address(baseGPR, JSEnvironmentRecord::offsetOfVariable(node->scopeOffset()))); noResult(node); break; } @@ -3732,7 +3766,7 @@ void SpeculativeJIT::compile(Node* node) base.use(); - JITCompiler::Jump notCell = branchNotCell(JSValueRegs(baseGPR)); + JITCompiler::Jump notCell = m_jit.branchIfNotCell(JSValueRegs(baseGPR)); cachedGetById(node->origin.semantic, baseGPR, resultGPR, node->identifierNumber(), notCell); @@ -3741,7 +3775,7 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } break; @@ -3758,7 +3792,7 @@ void SpeculativeJIT::compile(Node* node) SpeculateCellOperand base(this, node->child1()); GPRReg baseGPR = base.gpr(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); @@ -3776,13 +3810,13 @@ void SpeculativeJIT::compile(Node* node) JSValueOperand base(this, node->child1()); GPRReg baseGPR = base.gpr(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); base.use(); flushRegisters(); - JITCompiler::Jump notCell = branchNotCell(JSValueRegs(baseGPR)); + JITCompiler::Jump notCell = m_jit.branchIfNotCell(JSValueRegs(baseGPR)); cachedGetById(node->origin.semantic, baseGPR, resultGPR, node->identifierNumber(), notCell, DontSpill); @@ -3791,7 +3825,7 @@ void SpeculativeJIT::compile(Node* node) } default: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Bad use kind"); break; } break; @@ -3801,19 +3835,31 @@ void SpeculativeJIT::compile(Node* node) compileGetArrayLength(node); break; - case CheckFunction: { - SpeculateCellOperand function(this, node->child1()); - speculationCheck(BadFunction, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node->function())); + case CheckCell: { + SpeculateCellOperand cell(this, node->child1()); + speculationCheck(BadCell, JSValueSource::unboxedCell(cell.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, cell.gpr(), node->cellOperand()->cell())); noResult(node); break; } - - case CheckExecutable: { - SpeculateCellOperand function(this, node->child1()); - speculationCheck(BadExecutable, JSValueSource::unboxedCell(function.gpr()), node->child1(), m_jit.branchWeakPtr(JITCompiler::NotEqual, JITCompiler::Address(function.gpr(), JSFunction::offsetOfExecutable()), node->executable())); + + case CheckNotEmpty: { + JSValueOperand operand(this, node->child1()); + GPRReg gpr = operand.gpr(); + speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branchTest64(JITCompiler::Zero, gpr)); noResult(node); break; } + + case GetExecutable: { + SpeculateCellOperand function(this, node->child1()); + GPRTemporary result(this, Reuse, function); + GPRReg functionGPR = function.gpr(); + GPRReg resultGPR = result.gpr(); + speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType); + m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutable()), resultGPR); + cellResult(resultGPR, node); + break; + } case CheckStructure: { SpeculateCellOperand base(this, node->child1()); @@ -3821,8 +3867,8 @@ void SpeculativeJIT::compile(Node* node) ASSERT(node->structureSet().size()); ExitKind exitKind; - if (node->child1()->op() == WeakJSConstant) - exitKind = BadWeakConstantCache; + if (node->child1()->hasConstant()) + exitKind = BadConstantCache; else exitKind = BadCache; @@ -3851,42 +3897,9 @@ void SpeculativeJIT::compile(Node* node) break; } - case StructureTransitionWatchpoint: { - // There is a fascinating question here of what to do about array profiling. - // We *could* try to tell the OSR exit about where the base of the access is. - // The DFG will have kept it alive, though it may not be in a register, and - // we shouldn't really load it since that could be a waste. For now though, - // we'll just rely on the fact that when a watchpoint fires then that's - // quite a hint already. - - m_jit.addWeakReference(node->structure()); - -#if !ASSERT_DISABLED - SpeculateCellOperand op1(this, node->child1()); - JITCompiler::Jump isOK = m_jit.branchStructurePtr( - JITCompiler::Equal, - JITCompiler::Address(op1.gpr(), JSCell::structureIDOffset()), - node->structure()); - m_jit.abortWithReason(DFGIneffectiveWatchpoint); - isOK.link(&m_jit); -#else - speculateCell(node->child1()); -#endif - - noResult(node); - break; - } - - case PhantomPutStructure: { - ASSERT(isKnownCell(node->child1().node())); - m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node); - noResult(node); - break; - } - case PutStructure: { - Structure* oldStructure = node->structureTransitionData().previousStructure; - Structure* newStructure = node->structureTransitionData().newStructure; + Structure* oldStructure = node->transition()->previous; + Structure* newStructure = node->transition()->next; m_jit.jitCode()->common.notifyCompilingStructureTransition(m_jit.graph().m_plan, m_jit.codeBlock(), node); @@ -3938,14 +3951,15 @@ void SpeculativeJIT::compile(Node* node) break; } - case GetByOffset: { + case GetByOffset: + case GetGetterSetterByOffset: { StorageOperand storage(this, node->child1()); GPRTemporary result(this, Reuse, storage); GPRReg storageGPR = storage.gpr(); GPRReg resultGPR = result.gpr(); - StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()]; + StorageAccessData& storageAccessData = node->storageAccessData(); m_jit.load64(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset)), resultGPR); @@ -3953,6 +3967,32 @@ void SpeculativeJIT::compile(Node* node) break; } + case GetGetter: { + SpeculateCellOperand op1(this, node->child1()); + GPRTemporary result(this, Reuse, op1); + + GPRReg op1GPR = op1.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR); + + cellResult(resultGPR, node); + break; + } + + case GetSetter: { + SpeculateCellOperand op1(this, node->child1()); + GPRTemporary result(this, Reuse, op1); + + GPRReg op1GPR = op1.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR); + + cellResult(resultGPR, node); + break; + } + case PutByOffset: { StorageOperand storage(this, node->child1()); JSValueOperand value(this, node->child3()); @@ -3964,7 +4004,7 @@ void SpeculativeJIT::compile(Node* node) speculate(node, node->child2()); - StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()]; + StorageAccessData& storageAccessData = node->storageAccessData(); m_jit.store64(valueGPR, JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset))); @@ -4021,47 +4061,27 @@ void SpeculativeJIT::compile(Node* node) case GetGlobalVar: { GPRTemporary result(this); - m_jit.load64(node->registerPointer(), result.gpr()); + m_jit.load64(node->variablePointer(), result.gpr()); jsValueResult(result.gpr(), node); break; } case PutGlobalVar: { - JSValueOperand value(this, node->child1()); + JSValueOperand value(this, node->child2()); - m_jit.store64(value.gpr(), node->registerPointer()); + m_jit.store64(value.gpr(), node->variablePointer()); noResult(node); break; } case NotifyWrite: { - VariableWatchpointSet* set = node->variableWatchpointSet(); - - JSValueOperand value(this, node->child1()); - GPRReg valueGPR = value.gpr(); - - GPRTemporary temp(this); - GPRReg tempGPR = temp.gpr(); - - m_jit.load8(set->addressOfState(), tempGPR); - - JITCompiler::Jump isDone = - m_jit.branch32(JITCompiler::Equal, tempGPR, TrustedImm32(IsInvalidated)); - JITCompiler::Jump slowCase = m_jit.branch64(JITCompiler::NotEqual, - JITCompiler::AbsoluteAddress(set->addressOfInferredValue()), valueGPR); - isDone.link(&m_jit); - - addSlowPathGenerator( - slowPathCall(slowCase, this, operationNotifyWrite, NoResult, set, valueGPR)); - - noResult(node); + compileNotifyWrite(node); break; } - case VarInjectionWatchpoint: - case VariableWatchpoint: { + case VarInjectionWatchpoint: { noResult(node); break; } @@ -4092,7 +4112,7 @@ void SpeculativeJIT::compile(Node* node) GPRTemporary remoteGlobalObject(this); GPRTemporary scratch(this); - JITCompiler::Jump isCell = branchIsCell(value.jsValueRegs()); + JITCompiler::Jump isCell = m_jit.branchIfCell(value.jsValueRegs()); m_jit.compare64(JITCompiler::Equal, value.gpr(), TrustedImm32(ValueUndefined), result.gpr()); JITCompiler::Jump done = m_jit.jump(); @@ -4152,7 +4172,7 @@ void SpeculativeJIT::compile(Node* node) JSValueOperand value(this, node->child1()); GPRTemporary result(this, Reuse, value); - JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs()); + JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(value.jsValueRegs()); m_jit.compare8(JITCompiler::Equal, JITCompiler::Address(value.gpr(), JSCell::typeInfoTypeOffset()), @@ -4168,87 +4188,40 @@ void SpeculativeJIT::compile(Node* node) jsValueResult(result.gpr(), node, DataFormatJSBoolean); break; } - + case IsObject: { JSValueOperand value(this, node->child1()); - GPRReg valueGPR = value.gpr(); - GPRResult result(this); - GPRReg resultGPR = result.gpr(); - flushRegisters(); - callOperation(operationIsObject, resultGPR, valueGPR); - m_jit.or32(TrustedImm32(ValueFalse), resultGPR); + GPRTemporary result(this, Reuse, value); + + JITCompiler::Jump isNotCell = m_jit.branchIfNotCell(value.jsValueRegs()); + + m_jit.compare8(JITCompiler::AboveOrEqual, + JITCompiler::Address(value.gpr(), JSCell::typeInfoTypeOffset()), + TrustedImm32(ObjectType), + result.gpr()); + m_jit.or32(TrustedImm32(ValueFalse), result.gpr()); + JITCompiler::Jump done = m_jit.jump(); + + isNotCell.link(&m_jit); + m_jit.move(TrustedImm32(ValueFalse), result.gpr()); + + done.link(&m_jit); jsValueResult(result.gpr(), node, DataFormatJSBoolean); break; } + case IsObjectOrNull: { + compileIsObjectOrNull(node); + break; + } + case IsFunction: { - JSValueOperand value(this, node->child1()); - GPRReg valueGPR = value.gpr(); - GPRResult result(this); - GPRReg resultGPR = result.gpr(); - flushRegisters(); - callOperation(operationIsFunction, resultGPR, valueGPR); - m_jit.or32(TrustedImm32(ValueFalse), resultGPR); - jsValueResult(result.gpr(), node, DataFormatJSBoolean); + compileIsFunction(node); break; } case TypeOf: { - JSValueOperand value(this, node->child1(), ManualOperandSpeculation); - GPRReg valueGPR = value.gpr(); - GPRResult result(this); - GPRReg resultGPR = result.gpr(); - JITCompiler::JumpList doneJumps; - - flushRegisters(); - - ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse); - - JITCompiler::Jump isNotCell = branchNotCell(JSValueRegs(valueGPR)); - if (node->child1().useKind() != UntypedUse) - DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecCell, isNotCell); - - if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) { - JITCompiler::Jump notString = m_jit.branch8( - JITCompiler::NotEqual, - JITCompiler::Address(valueGPR, JSCell::typeInfoTypeOffset()), - TrustedImm32(StringType)); - if (node->child1().useKind() == StringUse) - DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecString, notString); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.stringString()), resultGPR); - doneJumps.append(m_jit.jump()); - if (node->child1().useKind() != StringUse) { - notString.link(&m_jit); - callOperation(operationTypeOf, resultGPR, valueGPR); - doneJumps.append(m_jit.jump()); - } - } else { - callOperation(operationTypeOf, resultGPR, valueGPR); - doneJumps.append(m_jit.jump()); - } - - if (node->child1().useKind() == UntypedUse) { - isNotCell.link(&m_jit); - JITCompiler::Jump notNumber = m_jit.branchTest64(JITCompiler::Zero, valueGPR, GPRInfo::tagTypeNumberRegister); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.numberString()), resultGPR); - doneJumps.append(m_jit.jump()); - notNumber.link(&m_jit); - - JITCompiler::Jump notUndefined = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueUndefined)); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.undefinedString()), resultGPR); - doneJumps.append(m_jit.jump()); - notUndefined.link(&m_jit); - - JITCompiler::Jump notNull = m_jit.branch64(JITCompiler::NotEqual, valueGPR, JITCompiler::TrustedImm64(ValueNull)); - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.objectString()), resultGPR); - doneJumps.append(m_jit.jump()); - notNull.link(&m_jit); - - // Only boolean left - m_jit.move(TrustedImmPtr(m_jit.vm()->smallStrings.booleanString()), resultGPR); - } - doneJumps.link(&m_jit); - cellResult(resultGPR, node); + compileTypeOf(node); break; } @@ -4257,389 +4230,94 @@ void SpeculativeJIT::compile(Node* node) case Call: case Construct: + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: emitCall(node); break; - - case CreateActivation: { - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - JSValueOperand value(this, node->child1()); - GPRTemporary result(this, Reuse, value); + case LoadVarargs: { + LoadVarargsData* data = node->loadVarargsData(); - GPRReg valueGPR = value.gpr(); - GPRReg resultGPR = result.gpr(); - - m_jit.move(valueGPR, resultGPR); - - JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, resultGPR); + GPRReg argumentsGPR; + { + JSValueOperand arguments(this, node->child1()); + argumentsGPR = arguments.gpr(); + flushRegisters(); + } - addSlowPathGenerator( - slowPathCall( - notCreated, this, operationCreateActivation, resultGPR, - framePointerOffsetToGetActivationRegisters())); + callOperation(operationSizeOfVarargs, GPRInfo::returnValueGPR, argumentsGPR, data->offset); - cellResult(resultGPR, node); - break; - } + lock(GPRInfo::returnValueGPR); + { + JSValueOperand arguments(this, node->child1()); + argumentsGPR = arguments.gpr(); + flushRegisters(); + } + unlock(GPRInfo::returnValueGPR); - case FunctionReentryWatchpoint: { - noResult(node); - break; - } + // FIXME: There is a chance that we will call an effectful length property twice. This is safe + // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance + // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right + // past the sizing. + // https://bugs.webkit.org/show_bug.cgi?id=141448 + + GPRReg argCountIncludingThisGPR = + JITCompiler::selectScratchGPR(GPRInfo::returnValueGPR, argumentsGPR); - case CreateArguments: { - JSValueOperand value(this, node->child1()); - GPRTemporary scratch1(this); - GPRTemporary scratch2(this); - GPRTemporary result(this, Reuse, value); + m_jit.add32(TrustedImm32(1), GPRInfo::returnValueGPR, argCountIncludingThisGPR); + speculationCheck( + VarargsOverflow, JSValueSource(), Edge(), m_jit.branch32( + MacroAssembler::Above, + argCountIncludingThisGPR, + TrustedImm32(data->limit))); - GPRReg valueGPR = value.gpr(); - GPRReg scratchGPR1 = scratch1.gpr(); - GPRReg scratchGPR2 = scratch2.gpr(); - GPRReg resultGPR = result.gpr(); + m_jit.store32(argCountIncludingThisGPR, JITCompiler::payloadFor(data->machineCount)); - m_jit.move(valueGPR, resultGPR); + callOperation(operationLoadVarargs, data->machineStart.offset(), argumentsGPR, data->offset, GPRInfo::returnValueGPR, data->mandatoryMinimum); - if (node->origin.semantic.inlineCallFrame) { - JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, resultGPR); - addSlowPathGenerator( - slowPathCall( - notCreated, this, operationCreateInlinedArguments, resultGPR, - node->origin.semantic.inlineCallFrame)); - cellResult(resultGPR, node); - break; - } - - FunctionExecutable* executable = jsCast<FunctionExecutable*>(m_jit.graph().executableFor(node->origin.semantic)); - if (m_jit.codeBlock()->hasSlowArguments() - || executable->isStrictMode() - || !executable->parameterCount()) { - JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, resultGPR); - addSlowPathGenerator( - slowPathCall(notCreated, this, operationCreateArguments, resultGPR)); - cellResult(resultGPR, node); - break; - } - - JITCompiler::Jump alreadyCreated = m_jit.branchTest64(JITCompiler::NonZero, resultGPR); - - MacroAssembler::JumpList slowPaths; - emitAllocateArguments(resultGPR, scratchGPR1, scratchGPR2, slowPaths); - addSlowPathGenerator( - slowPathCall(slowPaths, this, operationCreateArguments, resultGPR)); - - alreadyCreated.link(&m_jit); - cellResult(resultGPR, node); - break; - } - - case TearOffActivation: { - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - - JSValueOperand activationValue(this, node->child1()); - GPRTemporary scratch(this); - GPRReg activationValueGPR = activationValue.gpr(); - GPRReg scratchGPR = scratch.gpr(); - - JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, activationValueGPR); - - SymbolTable* symbolTable = m_jit.symbolTableFor(node->origin.semantic); - int registersOffset = JSActivation::registersOffset(symbolTable); - - int bytecodeCaptureStart = symbolTable->captureStart(); - int machineCaptureStart = m_jit.graph().m_machineCaptureStart; - for (int i = symbolTable->captureCount(); i--;) { - m_jit.load64( - JITCompiler::Address( - GPRInfo::callFrameRegister, - (machineCaptureStart - i) * sizeof(Register)), - scratchGPR); - m_jit.store64( - scratchGPR, - JITCompiler::Address( - activationValueGPR, - registersOffset + (bytecodeCaptureStart - i) * sizeof(Register))); - } - m_jit.addPtr(TrustedImm32(registersOffset), activationValueGPR, scratchGPR); - m_jit.storePtr(scratchGPR, JITCompiler::Address(activationValueGPR, JSActivation::offsetOfRegisters())); - - notCreated.link(&m_jit); noResult(node); break; } - - case TearOffArguments: { - JSValueOperand unmodifiedArgumentsValue(this, node->child1()); - JSValueOperand activationValue(this, node->child2()); - GPRReg unmodifiedArgumentsValueGPR = unmodifiedArgumentsValue.gpr(); - GPRReg activationValueGPR = activationValue.gpr(); - - JITCompiler::Jump created = m_jit.branchTest64(JITCompiler::NonZero, unmodifiedArgumentsValueGPR); - - if (node->origin.semantic.inlineCallFrame) { - addSlowPathGenerator( - slowPathCall( - created, this, operationTearOffInlinedArguments, NoResult, - unmodifiedArgumentsValueGPR, activationValueGPR, node->origin.semantic.inlineCallFrame)); - } else { - addSlowPathGenerator( - slowPathCall( - created, this, operationTearOffArguments, NoResult, unmodifiedArgumentsValueGPR, activationValueGPR)); - } - noResult(node); + case ForwardVarargs: { + compileForwardVarargs(node); break; } - case GetMyArgumentsLength: { - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - - if (!isEmptySpeculation( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)) { - speculationCheck( - ArgumentsEscaped, JSValueRegs(), 0, - m_jit.branchTest64( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)))); - } - - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR); - m_jit.sub32(TrustedImm32(1), resultGPR); - int32Result(resultGPR, node); + case CreateActivation: { + compileCreateActivation(node); break; } - case GetMyArgumentsLengthSafe: { - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - - JITCompiler::Jump created = m_jit.branchTest64( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic))); - - if (node->origin.semantic.inlineCallFrame) { - m_jit.move( - Imm64(JSValue::encode(jsNumber(node->origin.semantic.inlineCallFrame->arguments.size() - 1))), - resultGPR); - } else { - m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR); - m_jit.sub32(TrustedImm32(1), resultGPR); - m_jit.or64(GPRInfo::tagTypeNumberRegister, resultGPR); - } - - // FIXME: the slow path generator should perform a forward speculation that the - // result is an integer. For now we postpone the speculation by having this return - // a JSValue. - - addSlowPathGenerator( - slowPathCall( - created, this, operationGetArgumentsLength, resultGPR, - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset())); - - jsValueResult(resultGPR, node); + case CreateDirectArguments: { + compileCreateDirectArguments(node); break; } - case GetMyArgumentByVal: { - SpeculateStrictInt32Operand index(this, node->child1()); - GPRTemporary result(this); - GPRReg indexGPR = index.gpr(); - GPRReg resultGPR = result.gpr(); - - if (!isEmptySpeculation( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)) { - speculationCheck( - ArgumentsEscaped, JSValueRegs(), 0, - m_jit.branchTest64( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)))); - } - - m_jit.add32(TrustedImm32(1), indexGPR, resultGPR); - if (node->origin.semantic.inlineCallFrame) { - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultGPR, - Imm32(node->origin.semantic.inlineCallFrame->arguments.size()))); - } else { - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultGPR, - JITCompiler::payloadFor(JSStack::ArgumentCount))); - } - - JITCompiler::JumpList slowArgument; - JITCompiler::JumpList slowArgumentOutOfBounds; - if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) { - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get(); - - slowArgumentOutOfBounds.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, indexGPR, - Imm32(m_jit.symbolTableFor(node->origin.semantic)->parameterCount()))); - - COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); - m_jit.move(ImmPtr(slowArguments), resultGPR); - m_jit.load32( - JITCompiler::BaseIndex( - resultGPR, indexGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(SlowArgument, index)), - resultGPR); - m_jit.signExtend32ToPtr(resultGPR, resultGPR); - m_jit.load64( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight), - resultGPR); - slowArgument.append(m_jit.jump()); - } - slowArgumentOutOfBounds.link(&m_jit); - - m_jit.signExtend32ToPtr(resultGPR, resultGPR); - - m_jit.load64( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic)), - resultGPR); - - slowArgument.link(&m_jit); - jsValueResult(resultGPR, node); + case GetFromArguments: { + compileGetFromArguments(node); break; } - case GetMyArgumentByValSafe: { - SpeculateStrictInt32Operand index(this, node->child1()); - GPRTemporary result(this); - GPRReg indexGPR = index.gpr(); - GPRReg resultGPR = result.gpr(); - - JITCompiler::JumpList slowPath; - slowPath.append( - m_jit.branchTest64( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)))); - - m_jit.add32(TrustedImm32(1), indexGPR, resultGPR); - if (node->origin.semantic.inlineCallFrame) { - slowPath.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultGPR, - Imm32(node->origin.semantic.inlineCallFrame->arguments.size()))); - } else { - slowPath.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, - resultGPR, - JITCompiler::payloadFor(JSStack::ArgumentCount))); - } - - JITCompiler::JumpList slowArgument; - JITCompiler::JumpList slowArgumentOutOfBounds; - if (m_jit.symbolTableFor(node->origin.semantic)->slowArguments()) { - RELEASE_ASSERT(!node->origin.semantic.inlineCallFrame); - const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get(); - - slowArgumentOutOfBounds.append( - m_jit.branch32( - JITCompiler::AboveOrEqual, indexGPR, - Imm32(m_jit.symbolTableFor(node->origin.semantic)->parameterCount()))); - - COMPILE_ASSERT(sizeof(SlowArgument) == 8, SlowArgument_size_is_eight_bytes); - m_jit.move(ImmPtr(slowArguments), resultGPR); - m_jit.load32( - JITCompiler::BaseIndex( - resultGPR, indexGPR, JITCompiler::TimesEight, - OBJECT_OFFSETOF(SlowArgument, index)), - resultGPR); - m_jit.signExtend32ToPtr(resultGPR, resultGPR); - m_jit.load64( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight), - resultGPR); - slowArgument.append(m_jit.jump()); - } - slowArgumentOutOfBounds.link(&m_jit); - - m_jit.signExtend32ToPtr(resultGPR, resultGPR); - - m_jit.load64( - JITCompiler::BaseIndex( - GPRInfo::callFrameRegister, resultGPR, JITCompiler::TimesEight, m_jit.offsetOfArgumentsIncludingThis(node->origin.semantic)), - resultGPR); - - if (node->origin.semantic.inlineCallFrame) { - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetInlinedArgumentByVal, resultGPR, - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset(), - node->origin.semantic.inlineCallFrame, - indexGPR)); - } else { - addSlowPathGenerator( - slowPathCall( - slowPath, this, operationGetArgumentByVal, resultGPR, - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic).offset(), - indexGPR)); - } - - slowArgument.link(&m_jit); - jsValueResult(resultGPR, node); + case PutToArguments: { + compilePutToArguments(node); break; } - case CheckArgumentsNotCreated: { - ASSERT(!isEmptySpeculation( - m_state.variables().operand( - m_jit.graph().argumentsRegisterFor(node->origin.semantic)).m_type)); - speculationCheck( - ArgumentsEscaped, JSValueRegs(), 0, - m_jit.branchTest64( - JITCompiler::NonZero, - JITCompiler::addressFor( - m_jit.graph().machineArgumentsRegisterFor(node->origin.semantic)))); - noResult(node); + case CreateScopedArguments: { + compileCreateScopedArguments(node); break; } - case NewFunctionNoCheck: - compileNewFunctionNoCheck(node); - break; - - case NewFunction: { - JSValueOperand value(this, node->child1()); - GPRTemporary result(this, Reuse, value); - - GPRReg valueGPR = value.gpr(); - GPRReg resultGPR = result.gpr(); - - m_jit.move(valueGPR, resultGPR); - - JITCompiler::Jump notCreated = m_jit.branchTest64(JITCompiler::Zero, resultGPR); - - addSlowPathGenerator( - slowPathCall( - notCreated, this, operationNewFunction, - resultGPR, m_jit.codeBlock()->functionDecl(node->functionDeclIndex()))); - - jsValueResult(resultGPR, node); + case CreateClonedArguments: { + compileCreateClonedArguments(node); break; } - case NewFunctionExpression: - compileNewFunctionExpression(node); + case NewFunction: + compileNewFunction(node); break; case In: @@ -4669,7 +4347,7 @@ void SpeculativeJIT::compile(Node* node) break; case Phantom: - case HardPhantom: + case Check: DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate); noResult(node); break; @@ -4684,15 +4362,319 @@ void SpeculativeJIT::compile(Node* node) break; case Unreachable: - RELEASE_ASSERT_NOT_REACHED(); + DFG_CRASH(m_jit.graph(), node, "Unexpected Unreachable node"); break; - case StoreBarrier: - case StoreBarrierWithNullCheck: { + case StoreBarrier: { compileStoreBarrier(node); break; } + case GetEnumerableLength: { + SpeculateCellOperand enumerator(this, node->child1()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR); + int32Result(resultGPR, node); + break; + } + case HasGenericProperty: { + JSValueOperand base(this, node->child1()); + SpeculateCellOperand property(this, node->child2()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + callOperation(operationHasGenericProperty, resultGPR, base.gpr(), property.gpr()); + jsValueResult(resultGPR, node, DataFormatJSBoolean); + break; + } + case HasStructureProperty: { + JSValueOperand base(this, node->child1()); + SpeculateCellOperand property(this, node->child2()); + SpeculateCellOperand enumerator(this, node->child3()); + GPRTemporary result(this); + + GPRReg baseGPR = base.gpr(); + GPRReg propertyGPR = property.gpr(); + GPRReg resultGPR = result.gpr(); + + m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), resultGPR); + MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual, + resultGPR, + MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::cachedStructureIDOffset())); + + moveTrueTo(resultGPR); + MacroAssembler::Jump done = m_jit.jump(); + + done.link(&m_jit); + + addSlowPathGenerator(slowPathCall(wrongStructure, this, operationHasGenericProperty, resultGPR, baseGPR, propertyGPR)); + jsValueResult(resultGPR, node, DataFormatJSBoolean); + break; + } + case HasIndexedProperty: { + SpeculateCellOperand base(this, node->child1()); + SpeculateStrictInt32Operand index(this, node->child2()); + GPRTemporary result(this); + + GPRReg baseGPR = base.gpr(); + GPRReg indexGPR = index.gpr(); + GPRReg resultGPR = result.gpr(); + + MacroAssembler::JumpList slowCases; + ArrayMode mode = node->arrayMode(); + switch (mode.type()) { + case Array::Int32: + case Array::Contiguous: { + ASSERT(!!node->child3()); + StorageOperand storage(this, node->child3()); + GPRTemporary scratch(this); + + GPRReg storageGPR = storage.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + if (mode.isInBounds()) + speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds); + else + slowCases.append(outOfBounds); + + m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchGPR); + slowCases.append(m_jit.branchTest64(MacroAssembler::Zero, scratchGPR)); + moveTrueTo(resultGPR); + break; + } + case Array::Double: { + ASSERT(!!node->child3()); + StorageOperand storage(this, node->child3()); + FPRTemporary scratch(this); + FPRReg scratchFPR = scratch.fpr(); + GPRReg storageGPR = storage.gpr(); + + MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength())); + if (mode.isInBounds()) + speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds); + else + slowCases.append(outOfBounds); + + m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR); + slowCases.append(m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, scratchFPR, scratchFPR)); + moveTrueTo(resultGPR); + break; + } + case Array::ArrayStorage: { + ASSERT(!!node->child3()); + StorageOperand storage(this, node->child3()); + GPRTemporary scratch(this); + + GPRReg storageGPR = storage.gpr(); + GPRReg scratchGPR = scratch.gpr(); + + MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Address(storageGPR, ArrayStorage::vectorLengthOffset())); + if (mode.isInBounds()) + speculationCheck(OutOfBounds, JSValueRegs(), 0, outOfBounds); + else + slowCases.append(outOfBounds); + + m_jit.load64(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset()), scratchGPR); + slowCases.append(m_jit.branchTest64(MacroAssembler::Zero, scratchGPR)); + moveTrueTo(resultGPR); + break; + } + default: { + slowCases.append(m_jit.jump()); + break; + } + } + + addSlowPathGenerator(slowPathCall(slowCases, this, operationHasIndexedProperty, resultGPR, baseGPR, indexGPR)); + + jsValueResult(resultGPR, node, DataFormatJSBoolean); + break; + } + case GetDirectPname: { + Edge& baseEdge = m_jit.graph().varArgChild(node, 0); + Edge& propertyEdge = m_jit.graph().varArgChild(node, 1); + Edge& indexEdge = m_jit.graph().varArgChild(node, 2); + Edge& enumeratorEdge = m_jit.graph().varArgChild(node, 3); + + SpeculateCellOperand base(this, baseEdge); + SpeculateCellOperand property(this, propertyEdge); + SpeculateStrictInt32Operand index(this, indexEdge); + SpeculateCellOperand enumerator(this, enumeratorEdge); + GPRTemporary result(this); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + + GPRReg baseGPR = base.gpr(); + GPRReg propertyGPR = property.gpr(); + GPRReg indexGPR = index.gpr(); + GPRReg enumeratorGPR = enumerator.gpr(); + GPRReg resultGPR = result.gpr(); + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg scratch2GPR = scratch2.gpr(); + + // Check the structure + m_jit.load32(MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), scratch1GPR); + MacroAssembler::Jump wrongStructure = m_jit.branch32(MacroAssembler::NotEqual, + scratch1GPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedStructureIDOffset())); + + // Compute the offset + // If index is less than the enumerator's cached inline storage, then it's an inline access + MacroAssembler::Jump outOfLineAccess = m_jit.branch32(MacroAssembler::AboveOrEqual, + indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset())); + + m_jit.load64(MacroAssembler::BaseIndex(baseGPR, indexGPR, MacroAssembler::TimesEight, JSObject::offsetOfInlineStorage()), resultGPR); + + MacroAssembler::Jump done = m_jit.jump(); + + // Otherwise it's out of line + outOfLineAccess.link(&m_jit); + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratch2GPR); + m_jit.move(indexGPR, scratch1GPR); + m_jit.sub32(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedInlineCapacityOffset()), scratch1GPR); + m_jit.neg32(scratch1GPR); + m_jit.signExtend32ToPtr(scratch1GPR, scratch1GPR); + int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue); + m_jit.load64(MacroAssembler::BaseIndex(scratch2GPR, scratch1GPR, MacroAssembler::TimesEight, offsetOfFirstProperty), resultGPR); + + done.link(&m_jit); + + addSlowPathGenerator(slowPathCall(wrongStructure, this, operationGetByVal, resultGPR, baseGPR, propertyGPR)); + + jsValueResult(resultGPR, node); + break; + } + case GetPropertyEnumerator: { + SpeculateCellOperand base(this, node->child1()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + callOperation(operationGetPropertyEnumerator, resultGPR, base.gpr()); + cellResult(resultGPR, node); + break; + } + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: { + SpeculateCellOperand enumerator(this, node->child1()); + SpeculateStrictInt32Operand index(this, node->child2()); + GPRTemporary scratch1(this); + GPRTemporary result(this); + + GPRReg enumeratorGPR = enumerator.gpr(); + GPRReg indexGPR = index.gpr(); + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg resultGPR = result.gpr(); + + MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR, + MacroAssembler::Address(enumeratorGPR, (op == GetEnumeratorStructurePname) + ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset() + : JSPropertyNameEnumerator::endGenericPropertyIndexOffset())); + + m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsNull())), resultGPR); + + MacroAssembler::Jump done = m_jit.jump(); + inBounds.link(&m_jit); + + m_jit.loadPtr(MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), scratch1GPR); + m_jit.load64(MacroAssembler::BaseIndex(scratch1GPR, indexGPR, MacroAssembler::TimesEight), resultGPR); + + done.link(&m_jit); + jsValueResult(resultGPR, node); + break; + } + case ToIndexString: { + SpeculateInt32Operand index(this, node->child1()); + GPRFlushedCallResult result(this); + GPRReg resultGPR = result.gpr(); + + flushRegisters(); + callOperation(operationToIndexString, resultGPR, index.gpr()); + cellResult(resultGPR, node); + break; + } + case ProfileType: { + JSValueOperand value(this, node->child1()); + GPRTemporary scratch1(this); + GPRTemporary scratch2(this); + GPRTemporary scratch3(this); + + GPRReg scratch1GPR = scratch1.gpr(); + GPRReg scratch2GPR = scratch2.gpr(); + GPRReg scratch3GPR = scratch3.gpr(); + GPRReg valueGPR = value.gpr(); + + MacroAssembler::JumpList jumpToEnd; + + TypeLocation* cachedTypeLocation = node->typeLocation(); + // Compile in a predictive type check, if possible, to see if we can skip writing to the log. + // These typechecks are inlined to match those of the 64-bit JSValue type checks. + if (cachedTypeLocation->m_lastSeenType == TypeUndefined) + jumpToEnd.append(m_jit.branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())))); + else if (cachedTypeLocation->m_lastSeenType == TypeNull) + jumpToEnd.append(m_jit.branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsNull())))); + else if (cachedTypeLocation->m_lastSeenType == TypeBoolean) { + m_jit.move(valueGPR, scratch2GPR); + m_jit.and64(TrustedImm32(~1), scratch2GPR); + jumpToEnd.append(m_jit.branch64(MacroAssembler::Equal, scratch2GPR, MacroAssembler::TrustedImm64(ValueFalse))); + } else if (cachedTypeLocation->m_lastSeenType == TypeMachineInt) + jumpToEnd.append(m_jit.branch64(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister)); + else if (cachedTypeLocation->m_lastSeenType == TypeNumber) + jumpToEnd.append(m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagTypeNumberRegister)); + else if (cachedTypeLocation->m_lastSeenType == TypeString) { + MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR)); + jumpToEnd.append(m_jit.branchIfString(valueGPR)); + isNotCell.link(&m_jit); + } + + // Load the TypeProfilerLog into Scratch2. + TypeProfilerLog* cachedTypeProfilerLog = m_jit.vm()->typeProfilerLog(); + m_jit.move(TrustedImmPtr(cachedTypeProfilerLog), scratch2GPR); + + // Load the next LogEntry into Scratch1. + m_jit.loadPtr(MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset()), scratch1GPR); + + // Store the JSValue onto the log entry. + m_jit.store64(valueGPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::valueOffset())); + + // Store the structureID of the cell if valueGPR is a cell, otherwise, store 0 on the log entry. + MacroAssembler::Jump isNotCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR)); + m_jit.load32(MacroAssembler::Address(valueGPR, JSCell::structureIDOffset()), scratch3GPR); + m_jit.store32(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset())); + MacroAssembler::Jump skipIsCell = m_jit.jump(); + isNotCell.link(&m_jit); + m_jit.store32(TrustedImm32(0), MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::structureIDOffset())); + skipIsCell.link(&m_jit); + + // Store the typeLocation on the log entry. + m_jit.move(TrustedImmPtr(cachedTypeLocation), scratch3GPR); + m_jit.storePtr(scratch3GPR, MacroAssembler::Address(scratch1GPR, TypeProfilerLog::LogEntry::locationOffset())); + + // Increment the current log entry. + m_jit.addPtr(TrustedImm32(sizeof(TypeProfilerLog::LogEntry)), scratch1GPR); + m_jit.storePtr(scratch1GPR, MacroAssembler::Address(scratch2GPR, TypeProfilerLog::currentLogEntryOffset())); + MacroAssembler::Jump clearLog = m_jit.branchPtr(MacroAssembler::Equal, scratch1GPR, TrustedImmPtr(cachedTypeProfilerLog->logEndPtr())); + addSlowPathGenerator( + slowPathCall(clearLog, this, operationProcessTypeProfilerLogDFG, NoResult)); + + jumpToEnd.link(&m_jit); + + noResult(node); + break; + } + case ProfileControlFlow: { + BasicBlockLocation* basicBlockLocation = node->basicBlockLocation(); + if (!basicBlockLocation->hasExecuted()) { + GPRTemporary scratch1(this); + basicBlockLocation->emitExecuteCode(m_jit, scratch1.gpr()); + } + noResult(node); + break; + } + #if ENABLE(FTL_JIT) case CheckTierUpInLoop: { MacroAssembler::Jump done = m_jit.branchAdd32( @@ -4702,7 +4684,7 @@ void SpeculativeJIT::compile(Node* node) silentSpillAllRegisters(InvalidGPRReg); m_jit.setupArgumentsExecState(); - appendCall(triggerTierUpNow); + appendCall(triggerTierUpNowInLoop); silentFillAllRegisters(InvalidGPRReg); done.link(&m_jit); @@ -4724,17 +4706,24 @@ void SpeculativeJIT::compile(Node* node) break; } - case CheckTierUpAndOSREnter: { + case CheckTierUpAndOSREnter: + case CheckTierUpWithNestedTriggerAndOSREnter: { ASSERT(!node->origin.semantic.inlineCallFrame); GPRTemporary temp(this); GPRReg tempGPR = temp.gpr(); + + MacroAssembler::Jump forceOSREntry; + if (op == CheckTierUpWithNestedTriggerAndOSREnter) + forceOSREntry = m_jit.branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(&m_jit.jitCode()->nestedTriggerIsSet)); MacroAssembler::Jump done = m_jit.branchAdd32( MacroAssembler::Signed, TrustedImm32(Options::ftlTierUpCounterIncrementForLoop()), MacroAssembler::AbsoluteAddress(&m_jit.jitCode()->tierUpCounter.m_counter)); - + + if (forceOSREntry.isSet()) + forceOSREntry.link(&m_jit); silentSpillAllRegisters(tempGPR); m_jit.setupArgumentsWithExecState( TrustedImm32(node->origin.semantic.bytecodeIndex), @@ -4752,21 +4741,36 @@ void SpeculativeJIT::compile(Node* node) case CheckTierUpInLoop: case CheckTierUpAtReturn: case CheckTierUpAndOSREnter: - RELEASE_ASSERT_NOT_REACHED(); + case CheckTierUpWithNestedTriggerAndOSREnter: + DFG_CRASH(m_jit.graph(), node, "Unexpected tier-up node"); break; #endif // ENABLE(FTL_JIT) - + + case NativeCall: + case NativeConstruct: case LastNodeType: case Phi: case Upsilon: - case GetArgument: case ExtractOSREntryLocal: case CheckInBounds: case ArithIMul: case MultiGetByOffset: case MultiPutByOffset: case FiatInt52: - RELEASE_ASSERT_NOT_REACHED(); + case CheckBadCell: + case BottomValue: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case GetMyArgumentByVal: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PutStack: + case KillStack: + case GetStack: + DFG_CRASH(m_jit.graph(), node, "Unexpected node"); break; } @@ -4782,59 +4786,17 @@ void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, Edge valueUs { JITCompiler::Jump isNotCell; if (!isKnownCell(valueUse.node())) - isNotCell = branchNotCell(JSValueRegs(valueGPR)); + isNotCell = m_jit.branchIfNotCell(JSValueRegs(valueGPR)); - JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR); + JITCompiler::Jump ownerIsRememberedOrInEden = m_jit.jumpIfIsRememberedOrInEden(ownerGPR); storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2); - ownerNotMarkedOrAlreadyRemembered.link(&m_jit); - - if (!isKnownCell(valueUse.node())) - isNotCell.link(&m_jit); -} - -void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueGPR, Edge valueUse, GPRReg scratch1, GPRReg scratch2) -{ - JITCompiler::Jump isNotCell; - if (!isKnownCell(valueUse.node())) - isNotCell = branchNotCell(JSValueRegs(valueGPR)); - - JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(owner); - storeToWriteBarrierBuffer(owner, scratch1, scratch2); - ownerNotMarkedOrAlreadyRemembered.link(&m_jit); + ownerIsRememberedOrInEden.link(&m_jit); if (!isKnownCell(valueUse.node())) isNotCell.link(&m_jit); } #endif // ENABLE(GGC) -JITCompiler::Jump SpeculativeJIT::branchIsCell(JSValueRegs regs) -{ - return m_jit.branchTest64(MacroAssembler::Zero, regs.gpr(), GPRInfo::tagMaskRegister); -} - -JITCompiler::Jump SpeculativeJIT::branchNotCell(JSValueRegs regs) -{ - return m_jit.branchTest64(MacroAssembler::NonZero, regs.gpr(), GPRInfo::tagMaskRegister); -} - -JITCompiler::Jump SpeculativeJIT::branchIsOther(JSValueRegs regs, GPRReg tempGPR) -{ - m_jit.move(regs.gpr(), tempGPR); - m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR); - return m_jit.branch64( - MacroAssembler::Equal, tempGPR, - MacroAssembler::TrustedImm64(ValueNull)); -} - -JITCompiler::Jump SpeculativeJIT::branchNotOther(JSValueRegs regs, GPRReg tempGPR) -{ - m_jit.move(regs.gpr(), tempGPR); - m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR); - return m_jit.branch64( - MacroAssembler::NotEqual, tempGPR, - MacroAssembler::TrustedImm64(ValueNull)); -} - void SpeculativeJIT::moveTrueTo(GPRReg gpr) { m_jit.move(TrustedImm32(ValueTrue), gpr); @@ -4891,7 +4853,7 @@ void SpeculativeJIT::speculateDoubleRepMachineInt(Edge edge) SpeculateDoubleOperand value(this, edge); FPRReg valueFPR = value.fpr(); - GPRResult result(this); + GPRFlushedCallResult result(this); GPRReg resultGPR = result.gpr(); flushRegisters(); diff --git a/dfg/DFGStackLayoutPhase.cpp b/dfg/DFGStackLayoutPhase.cpp index 0722bfa..0713720 100644 --- a/dfg/DFGStackLayoutPhase.cpp +++ b/dfg/DFGStackLayoutPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,8 +46,6 @@ public: bool run() { - SymbolTable* symbolTable = codeBlock()->symbolTable(); - // This enumerates the locals that we actually care about and packs them. So for example // if we use local 1, 3, 4, 5, 7, then we remap them: 1->0, 3->1, 4->2, 5->3, 7->4. We // treat a variable as being "used" if there exists an access to it (SetLocal, GetLocal, @@ -56,7 +54,7 @@ public: BitVector usedLocals; // Collect those variables that are used from IR. - bool hasGetLocalUnlinked = false; + bool hasNodesThatNeedFixup = false; for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) @@ -80,7 +78,32 @@ public: if (operand.isArgument()) break; usedLocals.set(operand.toLocal()); - hasGetLocalUnlinked = true; + hasNodesThatNeedFixup = true; + break; + } + + case LoadVarargs: + case ForwardVarargs: { + LoadVarargsData* data = node->loadVarargsData(); + if (data->count.isLocal()) + usedLocals.set(data->count.toLocal()); + if (data->start.isLocal()) { + // This part really relies on the contiguity of stack layout + // assignments. + ASSERT(VirtualRegister(data->start.offset() + data->limit - 1).isLocal()); + for (unsigned i = data->limit; i--;) + usedLocals.set(VirtualRegister(data->start.offset() + i).toLocal()); + } // the else case shouldn't happen. + hasNodesThatNeedFixup = true; + break; + } + + case PutStack: + case GetStack: { + StackAccessData* stack = node->stackAccessData(); + if (stack->local.isArgument()) + break; + usedLocals.set(stack->local.toLocal()); break; } @@ -90,27 +113,13 @@ public: } } - // Ensure that captured variables and captured inline arguments are pinned down. - // They should have been because of flushes, except that the flushes can be optimized - // away. - if (symbolTable) { - for (int i = symbolTable->captureStart(); i > symbolTable->captureEnd(); i--) - usedLocals.set(VirtualRegister(i).toLocal()); - } - if (codeBlock()->usesArguments()) { - usedLocals.set(codeBlock()->argumentsRegister().toLocal()); - usedLocals.set(unmodifiedArgumentsRegister(codeBlock()->argumentsRegister()).toLocal()); - } - if (codeBlock()->uncheckedActivationRegister().isValid()) - usedLocals.set(codeBlock()->activationRegister().toLocal()); for (InlineCallFrameSet::iterator iter = m_graph.m_plan.inlineCallFrames->begin(); !!iter; ++iter) { InlineCallFrame* inlineCallFrame = *iter; - if (!m_graph.usesArguments(inlineCallFrame)) - continue; - VirtualRegister argumentsRegister = m_graph.argumentsRegisterFor(inlineCallFrame); - usedLocals.set(argumentsRegister.toLocal()); - usedLocals.set(unmodifiedArgumentsRegister(argumentsRegister).toLocal()); + if (inlineCallFrame->isVarargs()) { + usedLocals.set(VirtualRegister( + JSStack::ArgumentCount + inlineCallFrame->stackOffset).toLocal()); + } for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) { usedLocals.set(VirtualRegister( @@ -147,38 +156,37 @@ public: if (allocation[local] == UINT_MAX) continue; - variable->machineLocal() = virtualRegisterForLocal( - allocation[variable->local().toLocal()]); - } - - if (codeBlock()->usesArguments()) { - VirtualRegister argumentsRegister = virtualRegisterForLocal( - allocation[codeBlock()->argumentsRegister().toLocal()]); - RELEASE_ASSERT( - virtualRegisterForLocal(allocation[ - unmodifiedArgumentsRegister( - codeBlock()->argumentsRegister()).toLocal()]) - == unmodifiedArgumentsRegister(argumentsRegister)); - codeBlock()->setArgumentsRegister(argumentsRegister); + variable->machineLocal() = assign(allocation, variable->local()); } - if (codeBlock()->uncheckedActivationRegister().isValid()) { - codeBlock()->setActivationRegister( - virtualRegisterForLocal(allocation[codeBlock()->activationRegister().toLocal()])); + for (StackAccessData* data : m_graph.m_stackAccessData) { + if (!data->local.isLocal()) { + data->machineLocal = data->local; + continue; + } + + if (static_cast<size_t>(data->local.toLocal()) >= allocation.size()) + continue; + if (allocation[data->local.toLocal()] == UINT_MAX) + continue; + + data->machineLocal = assign(allocation, data->local); } + // This register is never valid for DFG code blocks. + codeBlock()->setActivationRegister(VirtualRegister()); + if (LIKELY(!m_graph.hasDebuggerEnabled())) + codeBlock()->setScopeRegister(VirtualRegister()); + else + codeBlock()->setScopeRegister(assign(allocation, codeBlock()->scopeRegister())); + for (unsigned i = m_graph.m_inlineVariableData.size(); i--;) { InlineVariableData data = m_graph.m_inlineVariableData[i]; InlineCallFrame* inlineCallFrame = data.inlineCallFrame; - if (m_graph.usesArguments(inlineCallFrame)) { - inlineCallFrame->argumentsRegister = virtualRegisterForLocal( - allocation[m_graph.argumentsRegisterFor(inlineCallFrame).toLocal()]); - - RELEASE_ASSERT( - virtualRegisterForLocal(allocation[unmodifiedArgumentsRegister( - m_graph.argumentsRegisterFor(inlineCallFrame)).toLocal()]) - == unmodifiedArgumentsRegister(inlineCallFrame->argumentsRegister)); + if (inlineCallFrame->isVarargs()) { + inlineCallFrame->argumentCountRegister = assign( + allocation, VirtualRegister(inlineCallFrame->stackOffset + JSStack::ArgumentCount)); } for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) { @@ -206,34 +214,8 @@ public: RELEASE_ASSERT(inlineCallFrame->calleeRecovery.isConstant()); } - if (symbolTable) { - if (symbolTable->captureCount()) { - unsigned captureStartLocal = allocation[ - VirtualRegister(codeBlock()->symbolTable()->captureStart()).toLocal()]; - ASSERT(captureStartLocal != UINT_MAX); - m_graph.m_machineCaptureStart = virtualRegisterForLocal(captureStartLocal).offset(); - } else - m_graph.m_machineCaptureStart = virtualRegisterForLocal(0).offset(); - - // This is an abomination. If we had captured an argument then the argument ends - // up being "slow", meaning that loads of the argument go through an extra lookup - // table. - if (const SlowArgument* slowArguments = symbolTable->slowArguments()) { - auto newSlowArguments = std::make_unique<SlowArgument[]>( - symbolTable->parameterCount()); - for (size_t i = symbolTable->parameterCount(); i--;) { - newSlowArguments[i] = slowArguments[i]; - VirtualRegister reg = VirtualRegister(slowArguments[i].index); - if (reg.isLocal()) - newSlowArguments[i].index = virtualRegisterForLocal(allocation[reg.toLocal()]).offset(); - } - - m_graph.m_slowArguments = WTF::move(newSlowArguments); - } - } - // Fix GetLocalUnlinked's variable references. - if (hasGetLocalUnlinked) { + if (hasNodesThatNeedFixup) { for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) @@ -242,10 +224,15 @@ public: Node* node = block->at(nodeIndex); switch (node->op()) { case GetLocalUnlinked: { - VirtualRegister operand = node->unlinkedLocal(); - if (operand.isLocal()) - operand = virtualRegisterForLocal(allocation[operand.toLocal()]); - node->setUnlinkedMachineLocal(operand); + node->setUnlinkedMachineLocal(assign(allocation, node->unlinkedLocal())); + break; + } + + case LoadVarargs: + case ForwardVarargs: { + LoadVarargsData* data = node->loadVarargsData(); + data->machineCount = assign(allocation, data->count); + data->machineStart = assign(allocation, data->start); break; } @@ -258,6 +245,20 @@ public: return true; } + +private: + VirtualRegister assign(const Vector<unsigned>& allocation, VirtualRegister src) + { + VirtualRegister result = src; + if (result.isLocal()) { + unsigned myAllocation = allocation[result.toLocal()]; + if (myAllocation == UINT_MAX) + result = VirtualRegister(); + else + result = virtualRegisterForLocal(myAllocation); + } + return result; + } }; bool performStackLayout(Graph& graph) diff --git a/dfg/DFGStaticExecutionCountEstimationPhase.cpp b/dfg/DFGStaticExecutionCountEstimationPhase.cpp index 6baa3ce..b5e1a36 100644 --- a/dfg/DFGStaticExecutionCountEstimationPhase.cpp +++ b/dfg/DFGStaticExecutionCountEstimationPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -63,16 +63,17 @@ public: if (!block) continue; - switch (block->last()->op()) { + Node* terminal = block->terminal(); + switch (terminal->op()) { case Branch: { - BranchData* data = block->last()->branchData(); + BranchData* data = terminal->branchData(); applyCounts(data->taken); applyCounts(data->notTaken); break; } case Switch: { - SwitchData* data = block->last()->switchData(); + SwitchData* data = terminal->switchData(); for (unsigned i = data->cases.size(); i--;) applyCounts(data->cases[i].target); applyCounts(data->fallThrough); diff --git a/dfg/DFGStoreBarrierElisionPhase.cpp b/dfg/DFGStoreBarrierElisionPhase.cpp deleted file mode 100644 index 4217552..0000000 --- a/dfg/DFGStoreBarrierElisionPhase.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DFGStoreBarrierElisionPhase.h" - -#if ENABLE(DFG_JIT) - -#include "DFGBasicBlock.h" -#include "DFGClobberize.h" -#include "DFGGraph.h" -#include "DFGPhase.h" -#include "JSCInlines.h" -#include <wtf/HashSet.h> - -namespace JSC { namespace DFG { - -class StoreBarrierElisionPhase : public Phase { -public: - StoreBarrierElisionPhase(Graph& graph) - : Phase(graph, "store barrier elision") - , m_currentBlock(0) - , m_currentIndex(0) - { - } - - bool run() - { - for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { - m_currentBlock = m_graph.block(blockIndex); - if (!m_currentBlock) - continue; - handleBlock(m_currentBlock); - } - return true; - } - -private: - bool couldCauseGC(Node* node) - { - return writesOverlap(m_graph, node, GCState); - } - - bool allocatesFreshObject(Node* node) - { - switch (node->op()) { - case NewObject: - case NewArray: - case NewArrayWithSize: - case NewArrayBuffer: - case NewTypedArray: - case NewRegexp: - return true; - default: - return false; - } - } - - void noticeFreshObject(HashSet<Node*>& dontNeedBarriers, Node* node) - { - ASSERT(allocatesFreshObject(node)); - dontNeedBarriers.add(node); - } - - Node* getBaseOfStore(Node* barrierNode) - { - ASSERT(barrierNode->isStoreBarrier()); - return barrierNode->child1().node(); - } - - bool shouldBeElided(HashSet<Node*>& dontNeedBarriers, Node* node) - { - ASSERT(node->isStoreBarrier()); - return dontNeedBarriers.contains(node->child1().node()); - } - - void elideBarrier(Node* node) - { - ASSERT(node->isStoreBarrier()); - node->convertToPhantom(); - } - - void handleNode(HashSet<Node*>& dontNeedBarriers, Node* node) - { - if (couldCauseGC(node)) - dontNeedBarriers.clear(); - - if (allocatesFreshObject(node)) - noticeFreshObject(dontNeedBarriers, node); - - if (!node->isStoreBarrier()) - return; - - if (shouldBeElided(dontNeedBarriers, node)) { - elideBarrier(node); - return; - } - - Node* base = getBaseOfStore(node); - if (!base) - return; - - if (dontNeedBarriers.contains(base)) - return; - dontNeedBarriers.add(base); - } - - bool handleBlock(BasicBlock* block) - { - HashSet<Node*> dontNeedBarriers; - for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { - m_currentIndex = indexInBlock; - Node* node = block->at(indexInBlock); - handleNode(dontNeedBarriers, node); - } - return true; - } - - BasicBlock* m_currentBlock; - unsigned m_currentIndex; -}; - -bool performStoreBarrierElision(Graph& graph) -{ - SamplingRegion samplingRegion("DFG Store Barrier Elision Phase"); - return runPhase<StoreBarrierElisionPhase>(graph); -} - - -} } // namespace JSC::DFG - -#endif // ENABLE(DFG_JIT) diff --git a/dfg/DFGStoreBarrierInsertionPhase.cpp b/dfg/DFGStoreBarrierInsertionPhase.cpp new file mode 100644 index 0000000..66acda2 --- /dev/null +++ b/dfg/DFGStoreBarrierInsertionPhase.cpp @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DFGStoreBarrierInsertionPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGAbstractInterpreterInlines.h" +#include "DFGBlockMapInlines.h" +#include "DFGDoesGC.h" +#include "DFGGraph.h" +#include "DFGInPlaceAbstractState.h" +#include "DFGInsertionSet.h" +#include "DFGPhase.h" +#include "JSCInlines.h" +#include <wtf/CommaPrinter.h> +#include <wtf/HashSet.h> + +namespace JSC { namespace DFG { + +namespace { + +bool verbose = false; + +enum class PhaseMode { + // Does only a local analysis for store barrier insertion and assumes that pointers live + // from predecessor blocks may need barriers. Assumes CPS conventions. Does not use AI for + // eliminating store barriers, but does a best effort to eliminate barriers when you're + // storing a non-cell value by using Node::result() and by looking at constants. The local + // analysis is based on GC epochs, so it will eliminate a lot of locally redundant barriers. + Fast, + + // Does a global analysis for store barrier insertion. Reuses the GC-epoch-based analysis + // used by Fast, but adds a conservative merge rule for propagating information from one + // block to the next. This will ensure for example that if a value V coming from multiple + // predecessors in B didn't need any more barriers at the end of each predecessor (either + // because it was the last allocated object in that predecessor or because it just had a + // barrier executed), then until we hit another GC point in B, we won't need another barrier + // on V. Uses AI for eliminating barriers when we know that the value being stored is not a + // cell. Assumes SSA conventions. + Global +}; + +template<PhaseMode mode> +class StoreBarrierInsertionPhase : public Phase { +public: + StoreBarrierInsertionPhase(Graph& graph) + : Phase(graph, mode == PhaseMode::Fast ? "fast store barrier insertion" : "global store barrier insertion") + , m_insertionSet(graph) + { + } + + bool run() + { + if (verbose) { + dataLog("Starting store barrier insertion:\n"); + m_graph.dump(); + } + + switch (mode) { + case PhaseMode::Fast: { + DFG_ASSERT(m_graph, nullptr, m_graph.m_form != SSA); + + m_graph.clearEpochs(); + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) + handleBlock(block); + return true; + } + + case PhaseMode::Global: { + DFG_ASSERT(m_graph, nullptr, m_graph.m_form == SSA); + + m_state = std::make_unique<InPlaceAbstractState>(m_graph); + m_interpreter = std::make_unique<AbstractInterpreter<InPlaceAbstractState>>(m_graph, *m_state); + + m_isConverged = false; + + // First run the analysis. Inside basic blocks we use an epoch-based analysis that + // is very precise. At block boundaries, we just propagate which nodes may need a + // barrier. This gives us a very nice bottom->top fixpoint: we start out assuming + // that no node needs any barriers at block boundaries, and then we converge + // towards believing that all nodes need barriers. "Needing a barrier" is like + // saying that the node is in a past epoch. "Not needing a barrier" is like saying + // that the node is in the current epoch. + m_stateAtHead = std::make_unique<BlockMap<HashSet<Node*>>>(m_graph); + m_stateAtTail = std::make_unique<BlockMap<HashSet<Node*>>>(m_graph); + + BlockList postOrder = m_graph.blocksInPostOrder(); + + bool changed = true; + while (changed) { + changed = false; + + // Intentional backwards loop because we are using RPO. + for (unsigned blockIndex = postOrder.size(); blockIndex--;) { + BasicBlock* block = postOrder[blockIndex]; + + if (!handleBlock(block)) { + // If the block didn't finish, then it cannot affect the fixpoint. + continue; + } + + // Construct the state-at-tail based on the epochs of live nodes and the + // current epoch. We grow state-at-tail monotonically to ensure convergence. + bool thisBlockChanged = false; + for (Node* node : block->ssa->liveAtTail) { + if (node->epoch() != m_currentEpoch) { + // If the node is older than the current epoch, then we may need to + // run a barrier on it in the future. So, add it to the state. + thisBlockChanged |= m_stateAtTail->at(block).add(node).isNewEntry; + } + } + + if (!thisBlockChanged) { + // This iteration didn't learn anything new about this block. + continue; + } + + // Changed things. Make sure that we loop one more time. + changed = true; + + for (BasicBlock* successor : block->successors()) { + for (Node* node : m_stateAtTail->at(block)) + m_stateAtHead->at(successor).add(node); + } + } + } + + // Tell handleBlock() that it's time to actually insert barriers for real. + m_isConverged = true; + + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) + handleBlock(block); + + return true; + } } + + RELEASE_ASSERT_NOT_REACHED(); + return false; + } + +private: + bool handleBlock(BasicBlock* block) + { + if (verbose) { + dataLog("Dealing with block ", pointerDump(block), "\n"); + if (reallyInsertBarriers()) + dataLog(" Really inserting barriers.\n"); + } + + m_currentEpoch = Epoch::first(); + + if (mode == PhaseMode::Global) { + if (!block->cfaHasVisited) + return false; + m_state->beginBasicBlock(block); + + for (Node* node : block->ssa->liveAtHead) { + if (m_stateAtHead->at(block).contains(node)) { + // If previous blocks tell us that this node may need a barrier in the + // future, then put it in the ancient primordial epoch. This forces us to + // emit a barrier on any possibly-cell store, regardless of the epoch of the + // stored value. + node->setEpoch(Epoch()); + } else { + // If previous blocks aren't requiring us to run a barrier on this node, + // then put it in the current epoch. This means that we will skip barriers + // on this node so long as we don't allocate. It also means that we won't + // run barriers on stores to on one such node into another such node. That's + // fine, because nodes would be excluded from the state set if at the tails + // of all predecessors they always had the current epoch. + node->setEpoch(m_currentEpoch); + } + } + } + + bool result = true; + + for (m_nodeIndex = 0; m_nodeIndex < block->size(); ++m_nodeIndex) { + m_node = block->at(m_nodeIndex); + + if (verbose) { + dataLog( + " ", m_currentEpoch, ": Looking at node ", m_node, " with children: "); + CommaPrinter comma; + m_graph.doToChildren( + m_node, + [&] (Edge edge) { + dataLog(comma, edge, " (", edge->epoch(), ")"); + }); + dataLog("\n"); + } + + if (mode == PhaseMode::Global) { + // Execute edges separately because we don't want to insert barriers if the + // operation doing the store does a check that ensures that the child is not + // a cell. + m_interpreter->startExecuting(); + m_interpreter->executeEdges(m_node); + } + + switch (m_node->op()) { + case PutByValDirect: + case PutByVal: + case PutByValAlias: { + switch (m_node->arrayMode().modeForPut().type()) { + case Array::Contiguous: + case Array::ArrayStorage: + case Array::SlowPutArrayStorage: { + Edge child1 = m_graph.varArgChild(m_node, 0); + Edge child3 = m_graph.varArgChild(m_node, 2); + considerBarrier(child1, child3); + break; + } + default: + break; + } + break; + } + + case ArrayPush: { + switch (m_node->arrayMode().type()) { + case Array::Contiguous: + case Array::ArrayStorage: + considerBarrier(m_node->child1(), m_node->child2()); + break; + default: + break; + } + break; + } + + case PutStructure: { + considerBarrier(m_node->child1()); + break; + } + + case PutClosureVar: + case PutToArguments: + case PutById: + case PutByIdFlush: + case PutByIdDirect: + case MultiPutByOffset: { + considerBarrier(m_node->child1(), m_node->child2()); + break; + } + + case PutByOffset: { + considerBarrier(m_node->child2(), m_node->child3()); + break; + } + + case PutGlobalVar: { + considerBarrier(m_node->child1(), m_node->child2()); + break; + } + + default: + break; + } + + if (doesGC(m_graph, m_node)) + m_currentEpoch.bump(); + + switch (m_node->op()) { + case NewObject: + case NewArray: + case NewArrayWithSize: + case NewArrayBuffer: + case NewTypedArray: + case NewRegexp: + case MaterializeNewObject: + case MaterializeCreateActivation: + case NewStringObject: + case MakeRope: + case CreateActivation: + case CreateDirectArguments: + case CreateScopedArguments: + case CreateClonedArguments: + case NewFunction: + // Nodes that allocate get to set their epoch because for those nodes we know + // that they will be the newest object in the heap. + m_node->setEpoch(m_currentEpoch); + break; + + case AllocatePropertyStorage: + case ReallocatePropertyStorage: + // These allocate but then run their own barrier. + insertBarrier(m_nodeIndex + 1, m_node->child1().node()); + m_node->setEpoch(Epoch()); + break; + + case Upsilon: + m_node->phi()->setEpoch(m_node->epoch()); + m_node->setEpoch(Epoch()); + break; + + default: + // For nodes that aren't guaranteed to allocate, we say that their return value + // (if there is one) could be arbitrarily old. + m_node->setEpoch(Epoch()); + break; + } + + if (verbose) { + dataLog( + " ", m_currentEpoch, ": Done with node ", m_node, " (", m_node->epoch(), + ") with children: "); + CommaPrinter comma; + m_graph.doToChildren( + m_node, + [&] (Edge edge) { + dataLog(comma, edge, " (", edge->epoch(), ")"); + }); + dataLog("\n"); + } + + if (mode == PhaseMode::Global) { + if (!m_interpreter->executeEffects(m_nodeIndex, m_node)) { + result = false; + break; + } + } + } + + if (mode == PhaseMode::Global) + m_state->reset(); + + if (reallyInsertBarriers()) + m_insertionSet.execute(block); + + return result; + } + + void considerBarrier(Edge base, Edge child) + { + if (verbose) + dataLog(" Considering adding barrier ", base, " => ", child, "\n"); + + // We don't need a store barrier if the child is guaranteed to not be a cell. + switch (mode) { + case PhaseMode::Fast: { + // Don't try too hard because it's too expensive to run AI. + if (child->hasConstant()) { + if (!child->asJSValue().isCell()) { + if (verbose) + dataLog(" Rejecting because of constant type.\n"); + return; + } + } else { + switch (child->result()) { + case NodeResultNumber: + case NodeResultDouble: + case NodeResultInt32: + case NodeResultInt52: + case NodeResultBoolean: + if (verbose) + dataLog(" Rejecting because of result type.\n"); + return; + default: + break; + } + } + break; + } + + case PhaseMode::Global: { + // Go into rage mode to eliminate any chance of a barrier with a non-cell child. We + // can afford to keep around AI in Global mode. + if (!m_interpreter->needsTypeCheck(child, ~SpecCell)) { + if (verbose) + dataLog(" Rejecting because of AI type.\n"); + return; + } + break; + } } + + // We don't need a store barrier if the base is at least as new as the child. For + // example this won't need a barrier: + // + // var o = {} + // var p = {} + // p.f = o + // + // This is stronger than the currentEpoch rule in considerBarrier(Edge), because it will + // also eliminate barriers in cases like this: + // + // var o = {} // o.epoch = 1, currentEpoch = 1 + // var p = {} // o.epoch = 1, p.epoch = 2, currentEpoch = 2 + // var q = {} // o.epoch = 1, p.epoch = 2, q.epoch = 3, currentEpoch = 3 + // p.f = o // p.epoch >= o.epoch + // + // This relationship works because if it holds then we are in one of the following + // scenarios. Note that we don't know *which* of these scenarios we are in, but it's + // one of them (though without loss of generality, you can replace "a GC happened" with + // "many GCs happened"). + // + // 1) There is no GC between the allocation/last-barrier of base, child and now. Then + // we definitely don't need a barrier. + // + // 2) There was a GC after child was allocated but before base was allocated. Then we + // don't need a barrier, because base is still a new object. + // + // 3) There was a GC after both child and base were allocated. Then they are both old. + // We don't need barriers on stores of old into old. Note that in this case it + // doesn't matter if there was also a GC between the allocation of child and base. + // + // Note that barriers will lift an object into the current epoch. This is sort of weird. + // It means that later if you store that object into some other object, and that other + // object was previously newer object, you'll think that you need a barrier. We could + // avoid this by tracking allocation epoch and barrier epoch separately. For now I think + // that this would be overkill. But this does mean that there are the following + // possibilities when this relationship holds: + // + // 4) Base is allocated first. A GC happens and base becomes old. Then we allocate + // child. (Note that alternatively the GC could happen during the allocation of + // child.) Then we run a barrier on base. Base will appear to be as new as child + // (same epoch). At this point, we don't need another barrier on base. + // + // 5) Base is allocated first. Then we allocate child. Then we run a GC. Then we run a + // barrier on base. Base will appear newer than child. We don't need a barrier + // because both objects are old. + // + // Something we watch out for here is that the null epoch is a catch-all for objects + // allocated before we did any epoch tracking. Two objects being in the null epoch + // means that we don't know their epoch relationship. + if (!!base->epoch() && base->epoch() >= child->epoch()) { + if (verbose) + dataLog(" Rejecting because of epoch ordering.\n"); + return; + } + + considerBarrier(base); + } + + void considerBarrier(Edge base) + { + if (verbose) + dataLog(" Considering adding barrier on ", base, "\n"); + + // We don't need a store barrier if the epoch of the base is identical to the current + // epoch. That means that we either just allocated the object and so it's guaranteed to + // be in newgen, or we just ran a barrier on it so it's guaranteed to be remembered + // already. + if (base->epoch() == m_currentEpoch) { + if (verbose) + dataLog(" Rejecting because it's in the current epoch.\n"); + return; + } + + if (verbose) + dataLog(" Inserting barrier.\n"); + insertBarrier(m_nodeIndex, base.node()); + } + + void insertBarrier(unsigned nodeIndex, Node* base) + { + // If we're in global mode, we should only insert the barriers once we have converged. + if (!reallyInsertBarriers()) + return; + + // FIXME: We could support StoreBarrier(UntypedUse:). That would be sort of cool. + // But right now we don't need it. + m_insertionSet.insertNode( + nodeIndex, SpecNone, StoreBarrier, m_node->origin, Edge(base, CellUse)); + + base->setEpoch(m_currentEpoch); + } + + bool reallyInsertBarriers() + { + return mode == PhaseMode::Fast || m_isConverged; + } + + InsertionSet m_insertionSet; + Epoch m_currentEpoch; + unsigned m_nodeIndex; + Node* m_node; + + // Things we only use in Global mode. + std::unique_ptr<InPlaceAbstractState> m_state; + std::unique_ptr<AbstractInterpreter<InPlaceAbstractState>> m_interpreter; + std::unique_ptr<BlockMap<HashSet<Node*>>> m_stateAtHead; + std::unique_ptr<BlockMap<HashSet<Node*>>> m_stateAtTail; + bool m_isConverged; +}; + +} // anonymous namespace + +bool performFastStoreBarrierInsertion(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Fast Store Barrier Insertion Phase"); + return runPhase<StoreBarrierInsertionPhase<PhaseMode::Fast>>(graph); +} + +bool performGlobalStoreBarrierInsertion(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Global Store Barrier Insertion Phase"); + return runPhase<StoreBarrierInsertionPhase<PhaseMode::Global>>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGStoreBarrierInsertionPhase.h b/dfg/DFGStoreBarrierInsertionPhase.h new file mode 100644 index 0000000..352759e --- /dev/null +++ b/dfg/DFGStoreBarrierInsertionPhase.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DFGStoreBarrierInsertionPhase_h +#define DFGStoreBarrierInsertionPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Inserts store barriers in a block-local manner without consulting the abstract interpreter. +// Uses a simple epoch-based analysis to avoid inserting redundant barriers. This phase requires +// that we are not in SSA. +bool performFastStoreBarrierInsertion(Graph&); + +// Inserts store barriers using a global analysis and consults the abstract interpreter. Uses a +// simple epoch-based analysis to avoid inserting redundant barriers, but only propagates "same +// epoch as current" property from one block to the next. This phase requires SSA. This phase +// also requires having valid AI and liveness. +bool performGlobalStoreBarrierInsertion(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGStoreBarrierInsertionPhase_h + diff --git a/dfg/DFGStrengthReductionPhase.cpp b/dfg/DFGStrengthReductionPhase.cpp index 1f837d3..03515d5 100644 --- a/dfg/DFGStrengthReductionPhase.cpp +++ b/dfg/DFGStrengthReductionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,8 @@ #if ENABLE(DFG_JIT) +#include "DFGAbstractHeap.h" +#include "DFGClobberize.h" #include "DFGGraph.h" #include "DFGInsertionSet.h" #include "DFGPhase.h" @@ -72,12 +74,9 @@ private: case BitOr: handleCommutativity(); - if (m_node->child2()->isConstant()) { - JSValue op2 = m_graph.valueOfJSConstant(m_node->child2().node()); - if (op2.isInt32() && !op2.asInt32()) { - convertToIdentityOverChild1(); - break; - } + if (m_node->child2()->isInt32Constant() && !m_node->child2()->asInt32()) { + convertToIdentityOverChild1(); + break; } break; @@ -89,39 +88,29 @@ private: case BitLShift: case BitRShift: case BitURShift: - if (m_node->child2()->isConstant()) { - JSValue op2 = m_graph.valueOfJSConstant(m_node->child2().node()); - if (op2.isInt32() && !(op2.asInt32() & 0x1f)) { - convertToIdentityOverChild1(); - break; - } + if (m_node->child2()->isInt32Constant() && !(m_node->child2()->asInt32() & 0x1f)) { + convertToIdentityOverChild1(); + break; } break; case UInt32ToNumber: if (m_node->child1()->op() == BitURShift - && m_node->child1()->child2()->isConstant()) { - JSValue shiftAmount = m_graph.valueOfJSConstant( - m_node->child1()->child2().node()); - if (shiftAmount.isInt32() && (shiftAmount.asInt32() & 0x1f) - && m_node->arithMode() != Arith::DoOverflow) { - m_node->convertToIdentity(); - m_changed = true; - break; - } + && m_node->child1()->child2()->isInt32Constant() + && (m_node->child1()->child2()->asInt32() & 0x1f) + && m_node->arithMode() != Arith::DoOverflow) { + m_node->convertToIdentity(); + m_changed = true; + break; } break; case ArithAdd: handleCommutativity(); - if (m_graph.isInt32Constant(m_node->child2().node())) { - int32_t value = m_graph.valueOfInt32Constant( - m_node->child2().node()); - if (!value) { - convertToIdentityOverChild1(); - break; - } + if (m_node->child2()->isInt32Constant() && !m_node->child2()->asInt32()) { + convertToIdentityOverChild1(); + break; } break; @@ -130,9 +119,9 @@ private: break; case ArithSub: - if (m_graph.isInt32Constant(m_node->child2().node()) + if (m_node->child2()->isInt32Constant() && m_node->isBinaryUseKind(Int32Use)) { - int32_t value = m_graph.valueOfInt32Constant(m_node->child2().node()); + int32_t value = m_node->child2()->asInt32(); if (-value != value) { m_node->setOp(ArithAdd); m_node->child2().setNode( @@ -143,34 +132,20 @@ private: } } break; - - case GetArrayLength: - if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) - foldTypedArrayPropertyToConstant(view, jsNumber(view->length())); - break; - - case GetTypedArrayByteOffset: - if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node())) - foldTypedArrayPropertyToConstant(view, jsNumber(view->byteOffset())); - break; - - case GetIndexedPropertyStorage: - if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) { - if (view->mode() != FastTypedArray) { - prepareToFoldTypedArray(view); - m_node->convertToConstantStoragePointer(view->vector()); + + case ArithPow: + if (m_node->child2()->isNumberConstant()) { + double yOperandValue = m_node->child2()->asNumber(); + if (yOperandValue == 1) { + convertToIdentityOverChild1(); + } else if (yOperandValue == 0.5) { + m_insertionSet.insertCheck(m_nodeIndex, m_node); + m_node->convertToArithSqrt(); m_changed = true; - break; - } else { - // FIXME: It would be awesome to be able to fold the property storage for - // these GC-allocated typed arrays. For now it doesn't matter because the - // most common use-cases for constant typed arrays involve large arrays with - // aliased buffer views. - // https://bugs.webkit.org/show_bug.cgi?id=125425 } } break; - + case ValueRep: case Int52Rep: case DoubleRep: { @@ -191,8 +166,7 @@ private: for (Node* node = m_node->child1().node(); ; node = node->child1().node()) { if (canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(m_node->result())) { - m_insertionSet.insertNode( - m_nodeIndex, SpecNone, Phantom, m_node->origin, m_node->child1()); + m_insertionSet.insertCheck(m_nodeIndex, m_node); if (hadInt32Check) { // FIXME: Consider adding Int52RepInt32Use or even DoubleRepInt32Use, // which would be super weird. The latter would only arise in some @@ -200,9 +174,8 @@ private: if (canonicalResultRepresentation(node->result()) != NodeResultJS) break; - m_insertionSet.insertNode( - m_nodeIndex, SpecNone, Phantom, m_node->origin, - Edge(node, Int32Use)); + m_insertionSet.insertCheck( + m_nodeIndex, m_node->origin, Edge(node, Int32Use)); } m_node->child1() = node->defaultEdge(); m_node->convertToIdentity(); @@ -229,6 +202,34 @@ private: break; } + case Flush: { + ASSERT(m_graph.m_form != SSA); + + Node* setLocal = nullptr; + VirtualRegister local = m_node->local(); + + for (unsigned i = m_nodeIndex; i--;) { + Node* node = m_block->at(i); + if (node->op() == SetLocal && node->local() == local) { + setLocal = node; + break; + } + if (accessesOverlap(m_graph, node, AbstractHeap(Stack, local))) + break; + } + + if (!setLocal) + break; + + // The Flush should become a PhantomLocal at this point. This means that we want the + // local's value during OSR, but we don't care if the value is stored to the stack. CPS + // rethreading can canonicalize PhantomLocals for us. + m_node->convertFlushToPhantomLocal(); + m_graph.dethread(); + m_changed = true; + break; + } + default: break; } @@ -236,8 +237,7 @@ private: void convertToIdentityOverChild(unsigned childIndex) { - m_insertionSet.insertNode( - m_nodeIndex, SpecNone, Phantom, m_node->origin, m_node->children); + m_insertionSet.insertCheck(m_nodeIndex, m_node); m_node->children.removeEdge(childIndex ^ 1); m_node->convertToIdentity(); m_changed = true; @@ -253,22 +253,6 @@ private: convertToIdentityOverChild(1); } - void foldTypedArrayPropertyToConstant(JSArrayBufferView* view, JSValue constant) - { - prepareToFoldTypedArray(view); - m_graph.convertToConstant(m_node, constant); - m_changed = true; - } - - void prepareToFoldTypedArray(JSArrayBufferView* view) - { - m_insertionSet.insertNode( - m_nodeIndex, SpecNone, TypedArrayWatchpoint, m_node->origin, - OpInfo(view)); - m_insertionSet.insertNode( - m_nodeIndex, SpecNone, Phantom, m_node->origin, m_node->children); - } - void handleCommutativity() { // If the right side is a constant then there is nothing left to do. diff --git a/dfg/DFGStructureAbstractValue.cpp b/dfg/DFGStructureAbstractValue.cpp new file mode 100644 index 0000000..87baa57 --- /dev/null +++ b/dfg/DFGStructureAbstractValue.cpp @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGStructureAbstractValue.h" + +#if ENABLE(DFG_JIT) + +#include "DFGGraph.h" + +namespace JSC { namespace DFG { + +// Comment out the empty SAMPLE() definition, and uncomment the one that uses SamplingRegion, if +// you want extremely fine-grained profiling in this code. +#define SAMPLE(name) +//#define SAMPLE(name) SamplingRegion samplingRegion(name) + +#if !ASSERT_DISABLED +void StructureAbstractValue::assertIsRegistered(Graph& graph) const +{ + SAMPLE("StructureAbstractValue assertIsRegistered"); + + if (isTop()) + return; + + for (unsigned i = size(); i--;) + graph.assertIsRegistered(at(i)); +} +#endif // !ASSERT_DISABLED + +void StructureAbstractValue::clobber() +{ + SAMPLE("StructureAbstractValue clobber"); + + // The premise of this approach to clobbering is that anytime we introduce + // a watchable structure into an abstract value, we watchpoint it. You can assert + // that this holds by calling assertIsWatched(). + + if (isTop()) + return; + + setClobbered(true); + + if (m_set.isThin()) { + if (!m_set.singleEntry()) + return; + if (!m_set.singleEntry()->dfgShouldWatch()) + makeTopWhenThin(); + return; + } + + StructureSet::OutOfLineList* list = m_set.list(); + for (unsigned i = list->m_length; i--;) { + if (!list->list()[i]->dfgShouldWatch()) { + makeTop(); + return; + } + } +} + +void StructureAbstractValue::observeTransition(Structure* from, Structure* to) +{ + SAMPLE("StructureAbstractValue observeTransition"); + + ASSERT(!from->dfgShouldWatch()); + + if (isTop()) + return; + + if (!m_set.contains(from)) + return; + + if (!m_set.add(to)) + return; + + if (m_set.size() > polymorphismLimit) + makeTop(); +} + +void StructureAbstractValue::observeTransitions(const TransitionVector& vector) +{ + SAMPLE("StructureAbstractValue observeTransitions"); + + if (isTop()) + return; + + StructureSet newStructures; + for (unsigned i = vector.size(); i--;) { + ASSERT(!vector[i].previous->dfgShouldWatch()); + + if (!m_set.contains(vector[i].previous)) + continue; + + newStructures.add(vector[i].next); + } + + if (!m_set.merge(newStructures)) + return; + + if (m_set.size() > polymorphismLimit) + makeTop(); +} + +bool StructureAbstractValue::add(Structure* structure) +{ + SAMPLE("StructureAbstractValue add"); + + if (isTop()) + return false; + + if (!m_set.add(structure)) + return false; + + if (m_set.size() > polymorphismLimit) + makeTop(); + + return true; +} + +bool StructureAbstractValue::merge(const StructureSet& other) +{ + SAMPLE("StructureAbstractValue merge set"); + + if (isTop()) + return false; + + return mergeNotTop(other); +} + +bool StructureAbstractValue::mergeSlow(const StructureAbstractValue& other) +{ + SAMPLE("StructureAbstractValue merge value slow"); + + // It isn't immediately obvious that the code below is doing the right thing, so let's go + // through it. + // + // This not clobbered, other not clobbered: Clearly, we don't want to make anything clobbered + // since we just have two sets and we are merging them. mergeNotTop() can handle this just + // fine. + // + // This clobbered, other clobbered: Clobbered means that we have a set of things, plus we + // temporarily have the set of all things but the latter will go away once we hit the next + // invalidation point. This allows us to merge two clobbered sets the natural way. For now + // the set will still be TOP (and so we keep the clobbered bit set), but we know that after + // invalidation, we will have the union of the this and other. + // + // This clobbered, other not clobbered: It's safe to merge in other for both before and after + // invalidation, so long as we leave the clobbered bit set. Before invalidation this has no + // effect since the set will still appear to have all things in it. The way to think about + // what invalidation would do is imagine if we had a set A that was clobbered and a set B + // that wasn't and we considered the following two cases. Note that we expect A to be the + // same at the end in both cases: + // + // A.merge(B) InvalidationPoint + // InvalidationPoint A.merge(B) + // + // The fact that we expect A to be the same in both cases means that we want to merge other + // into this but keep the clobbered bit. + // + // This not clobbered, other clobbered: This is just the converse of the previous case. We + // want to merge other into this and set the clobbered bit. + + bool changed = false; + + if (!isClobbered() && other.isClobbered()) { + setClobbered(true); + changed = true; + } + + changed |= mergeNotTop(other.m_set); + + return changed; +} + +bool StructureAbstractValue::mergeNotTop(const StructureSet& other) +{ + SAMPLE("StructureAbstractValue merge not top"); + + if (!m_set.merge(other)) + return false; + + if (m_set.size() > polymorphismLimit) + makeTop(); + + return true; +} + +void StructureAbstractValue::filter(const StructureSet& other) +{ + SAMPLE("StructureAbstractValue filter set"); + + if (isTop()) { + m_set = other; + return; + } + + if (isClobbered()) { + // We have two choices here: + // + // Do nothing: It's legal to keep our set intact, which would essentially mean that for + // now, our set would behave like TOP but after the next invalidation point it wold be + // a finite set again. This may be a good choice if 'other' is much bigger than our + // m_set. + // + // Replace m_set with other and clear the clobber bit: This is also legal, and means that + // we're no longer clobbered. This is usually better because it immediately gives us a + // smaller set. + // + // This scenario should come up rarely. We usually don't do anything to an abstract value + // after it is clobbered. But we apply some heuristics. + + if (other.size() > m_set.size() + clobberedSupremacyThreshold) + return; // Keep the clobbered set. + + m_set = other; + setClobbered(false); + return; + } + + m_set.filter(other); +} + +void StructureAbstractValue::filter(const StructureAbstractValue& other) +{ + SAMPLE("StructureAbstractValue filter value"); + + if (other.isTop()) + return; + + if (other.isClobbered()) { + if (isTop()) + return; + + if (!isClobbered()) { + // See justification in filter(const StructureSet&), above. An unclobbered set is + // almost always better. + if (m_set.size() > other.m_set.size() + clobberedSupremacyThreshold) + *this = other; // Keep the clobbered set. + return; + } + + m_set.filter(other.m_set); + return; + } + + filter(other.m_set); +} + +void StructureAbstractValue::filterSlow(SpeculatedType type) +{ + SAMPLE("StructureAbstractValue filter type slow"); + + if (!(type & SpecCell)) { + clear(); + return; + } + + ASSERT(!isTop()); + + m_set.genericFilter( + [&] (Structure* structure) { + return !!(speculationFromStructure(structure) & type); + }); +} + +bool StructureAbstractValue::contains(Structure* structure) const +{ + SAMPLE("StructureAbstractValue contains"); + + if (isTop() || isClobbered()) + return true; + + return m_set.contains(structure); +} + +bool StructureAbstractValue::isSubsetOf(const StructureSet& other) const +{ + SAMPLE("StructureAbstractValue isSubsetOf set"); + + if (isTop() || isClobbered()) + return false; + + return m_set.isSubsetOf(other); +} + +bool StructureAbstractValue::isSubsetOf(const StructureAbstractValue& other) const +{ + SAMPLE("StructureAbstractValue isSubsetOf value"); + + if (isTop()) + return false; + + if (other.isTop()) + return true; + + if (isClobbered() == other.isClobbered()) + return m_set.isSubsetOf(other.m_set); + + // Here it gets tricky. If in doubt, return false! + + if (isClobbered()) + return false; // A clobbered set is never a subset of an unclobbered set. + + // An unclobbered set is currently a subset of a clobbered set, but it may not be so after + // invalidation. + return m_set.isSubsetOf(other.m_set); +} + +bool StructureAbstractValue::isSupersetOf(const StructureSet& other) const +{ + SAMPLE("StructureAbstractValue isSupersetOf set"); + + if (isTop() || isClobbered()) + return true; + + return m_set.isSupersetOf(other); +} + +bool StructureAbstractValue::overlaps(const StructureSet& other) const +{ + SAMPLE("StructureAbstractValue overlaps set"); + + if (isTop() || isClobbered()) + return true; + + return m_set.overlaps(other); +} + +bool StructureAbstractValue::overlaps(const StructureAbstractValue& other) const +{ + SAMPLE("StructureAbstractValue overlaps value"); + + if (other.isTop() || other.isClobbered()) + return true; + + return overlaps(other.m_set); +} + +bool StructureAbstractValue::equalsSlow(const StructureAbstractValue& other) const +{ + SAMPLE("StructureAbstractValue equalsSlow"); + + ASSERT(m_set.m_pointer != other.m_set.m_pointer); + ASSERT(!isTop()); + ASSERT(!other.isTop()); + + return m_set == other.m_set + && isClobbered() == other.isClobbered(); +} + +void StructureAbstractValue::dumpInContext(PrintStream& out, DumpContext* context) const +{ + if (isClobbered()) + out.print("Clobbered:"); + + if (isTop()) + out.print("TOP"); + else + out.print(inContext(m_set, context)); +} + +void StructureAbstractValue::dump(PrintStream& out) const +{ + dumpInContext(out, 0); +} + +void StructureAbstractValue::validateReferences(const TrackedReferences& trackedReferences) const +{ + if (isTop()) + return; + m_set.validateReferences(trackedReferences); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGStructureAbstractValue.h b/dfg/DFGStructureAbstractValue.h index 10e476c..2b87cdc 100644 --- a/dfg/DFGStructureAbstractValue.h +++ b/dfg/DFGStructureAbstractValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,309 +28,224 @@ #if ENABLE(DFG_JIT) +#include "DFGTransition.h" #include "JSCell.h" #include "SpeculatedType.h" #include "DumpContext.h" #include "StructureSet.h" -namespace JSC { namespace DFG { +namespace JSC { + +class TrackedReferences; + +namespace DFG { class StructureAbstractValue { public: - StructureAbstractValue() - : m_structure(0) - { - } - + StructureAbstractValue() { } StructureAbstractValue(Structure* structure) - : m_structure(structure) + : m_set(StructureSet(structure)) { + setClobbered(false); } - - StructureAbstractValue(const StructureSet& set) + StructureAbstractValue(const StructureSet& other) + : m_set(other) { - switch (set.size()) { - case 0: - m_structure = 0; - break; - - case 1: - m_structure = set[0]; - break; - - default: - m_structure = topValue(); - break; - } + setClobbered(false); } - - void clear() + ALWAYS_INLINE StructureAbstractValue(const StructureAbstractValue& other) + : m_set(other.m_set) { - m_structure = 0; + setClobbered(other.isClobbered()); } - void makeTop() + ALWAYS_INLINE StructureAbstractValue& operator=(Structure* structure) { - m_structure = topValue(); + m_set = StructureSet(structure); + setClobbered(false); + return *this; } - - static StructureAbstractValue top() + ALWAYS_INLINE StructureAbstractValue& operator=(const StructureSet& other) { - StructureAbstractValue value; - value.makeTop(); - return value; + m_set = other; + setClobbered(false); + return *this; } - - void add(Structure* structure) + ALWAYS_INLINE StructureAbstractValue& operator=(const StructureAbstractValue& other) { - ASSERT(!contains(structure) && !isTop()); - if (m_structure) - makeTop(); - else - m_structure = structure; + m_set = other.m_set; + setClobbered(other.isClobbered()); + return *this; } - bool addAll(const StructureSet& other) + void clear() { - if (isTop() || !other.size()) - return false; - if (other.size() > 1) { - makeTop(); - return true; - } - if (!m_structure) { - m_structure = other[0]; - return true; - } - if (m_structure == other[0]) - return false; - makeTop(); - return true; + m_set.clear(); + setClobbered(false); } - bool addAll(const StructureAbstractValue& other) + void makeTop() { - if (!other.m_structure) - return false; - if (isTop()) - return false; - if (other.isTop()) { - makeTop(); - return true; - } - if (m_structure) { - if (m_structure == other.m_structure) - return false; - makeTop(); - return true; - } - m_structure = other.m_structure; - return true; + m_set.deleteListIfNecessary(); + m_set.m_pointer = topValue; } - bool contains(Structure* structure) const - { - if (isTop()) - return true; - if (m_structure == structure) - return true; - return false; - } +#if ASSERT_DISABLED + void assertIsRegistered(Graph&) const { } +#else + void assertIsRegistered(Graph&) const; +#endif - bool isSubsetOf(const StructureSet& other) const - { - if (isTop()) - return false; - if (!m_structure) - return true; - return other.contains(m_structure); - } + void clobber(); + void observeInvalidationPoint() { setClobbered(false); } - bool doesNotContainAnyOtherThan(Structure* structure) const - { - if (isTop()) - return false; - if (!m_structure) - return true; - return m_structure == structure; - } + void observeTransition(Structure* from, Structure* to); + void observeTransitions(const TransitionVector&); - bool isSupersetOf(const StructureSet& other) const + static StructureAbstractValue top() { - if (isTop()) - return true; - if (!other.size()) - return true; - if (other.size() > 1) - return false; - return m_structure == other[0]; + StructureAbstractValue result; + result.m_set.m_pointer = topValue; + return result; } - bool isSubsetOf(const StructureAbstractValue& other) const - { - if (other.isTop()) - return true; - if (isTop()) - return false; - if (m_structure) { - if (other.m_structure) - return m_structure == other.m_structure; - return false; - } - return true; - } + bool isClear() const { return m_set.isEmpty(); } + bool isTop() const { return m_set.m_pointer == topValue; } + bool isNeitherClearNorTop() const { return !isClear() && !isTop(); } - bool isSupersetOf(const StructureAbstractValue& other) const - { - return other.isSubsetOf(*this); - } + // A clobbered abstract value means that the set currently contains the m_set set of + // structures plus TOP, except that the "plus TOP" will go away at the next invalidation + // point. Note that it's tempting to think of this as "the set of structures in m_set plus + // the set of structures transition-reachable from m_set" - but this isn't really correct, + // since if we add an unwatchable structure after clobbering, the two definitions are not + // equivalent. If we do this, the new unwatchable structure will be added to m_set. + // Invalidation points do not try to "clip" the set of transition-reachable structures from + // m_set by looking at reachability as this would mean that the new set is TOP. Instead they + // literally assume that the set is just m_set rather than m_set plus TOP. + bool isClobbered() const { return m_set.getReservedFlag(); } - void filter(const StructureSet& other) + bool add(Structure* structure); + + bool merge(const StructureSet& other); + + ALWAYS_INLINE bool merge(const StructureAbstractValue& other) { - if (!m_structure) - return; + if (other.isClear()) + return false; - if (isTop()) { - switch (other.size()) { - case 0: - m_structure = 0; - return; - - case 1: - m_structure = other[0]; - return; - - default: - return; - } - } + if (isTop()) + return false; - if (other.contains(m_structure)) - return; + if (other.isTop()) { + makeTop(); + return true; + } - m_structure = 0; + return mergeSlow(other); } - void filter(const StructureAbstractValue& other) + void filter(const StructureSet& other); + void filter(const StructureAbstractValue& other); + + ALWAYS_INLINE void filter(SpeculatedType type) { - if (isTop()) { - m_structure = other.m_structure; + if (!(type & SpecCell)) { + clear(); return; } - if (m_structure == other.m_structure) - return; - if (other.isTop()) - return; - m_structure = 0; + if (isNeitherClearNorTop()) + filterSlow(type); } - void filter(SpeculatedType other) + ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const { - if (!(other & SpecCell)) { - clear(); - return; - } + if ((m_set.isThin() && other.m_set.isThin()) || isTop() || other.isTop()) + return m_set.m_pointer == other.m_set.m_pointer; - if (isClearOrTop()) - return; - - if (!(speculationFromStructure(m_structure) & other)) - m_structure = 0; + return equalsSlow(other); } - bool isClear() const + const StructureSet& set() const { - return !m_structure; + ASSERT(!isTop()); + return m_set; } - bool isTop() const { return m_structure == topValue(); } - - bool isClearOrTop() const { return m_structure <= topValue(); } - bool isNeitherClearNorTop() const { return !isClearOrTop(); } - size_t size() const { ASSERT(!isTop()); - return !!m_structure; + return m_set.size(); } Structure* at(size_t i) const { ASSERT(!isTop()); - ASSERT(m_structure); - ASSERT_UNUSED(i, !i); - return m_structure; + return m_set.at(i); } - Structure* operator[](size_t i) const - { - return at(i); - } + Structure* operator[](size_t i) const { return at(i); } - Structure* last() const + // In most cases, what you really want to do is verify whether the set is top or clobbered, and + // if not, enumerate the set of structures. Use this only in cases where the singleton case is + // meaningfully special, like for transitions. + Structure* onlyStructure() const { - return at(0); + if (isTop() || isClobbered()) + return nullptr; + return m_set.onlyStructure(); } - SpeculatedType speculationFromStructures() const - { - if (isTop()) - return SpecCell; - if (isClear()) - return SpecNone; - return speculationFromStructure(m_structure); - } + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; - bool isValidOffset(PropertyOffset offset) - { - if (isTop()) - return false; - if (isClear()) - return true; - return m_structure->isValidOffset(offset); - } + // The methods below are all conservative and err on the side of making 'this' appear bigger + // than it is. For example, contains() may return true if the set is clobbered or TOP. + // isSubsetOf() may return false in case of ambiguities. Therefore you should only perform + // optimizations as a consequence of the "this is smaller" return value - so false for + // contains(), true for isSubsetOf(), false for isSupersetOf(), and false for overlaps(). + + bool contains(Structure* structure) const; - bool hasSingleton() const - { - return isNeitherClearNorTop(); - } + bool isSubsetOf(const StructureSet& other) const; + bool isSubsetOf(const StructureAbstractValue& other) const; - Structure* singleton() const + bool isSupersetOf(const StructureSet& other) const; + bool isSupersetOf(const StructureAbstractValue& other) const { - ASSERT(isNeitherClearNorTop()); - return m_structure; + return other.isSubsetOf(*this); } - bool operator==(const StructureAbstractValue& other) const - { - return m_structure == other.m_structure; - } + bool overlaps(const StructureSet& other) const; + bool overlaps(const StructureAbstractValue& other) const; - void dumpInContext(PrintStream& out, DumpContext* context) const + void validateReferences(const TrackedReferences&) const; + +private: + static const uintptr_t clobberedFlag = StructureSet::reservedFlag; + static const uintptr_t topValue = StructureSet::reservedValue; + static const unsigned polymorphismLimit = 10; + static const unsigned clobberedSupremacyThreshold = 2; + + void filterSlow(SpeculatedType type); + bool mergeSlow(const StructureAbstractValue& other); + + bool equalsSlow(const StructureAbstractValue& other) const; + + void makeTopWhenThin() { - if (isTop()) { - out.print("TOP"); - return; - } - - out.print("["); - if (m_structure) - out.print(inContext(*m_structure, context)); - out.print("]"); + ASSERT(m_set.isThin()); + m_set.m_pointer = topValue; } - - void dump(PrintStream& out) const + + bool mergeNotTop(const StructureSet& other); + + void setClobbered(bool clobbered) { - dumpInContext(out, 0); + ASSERT(!isTop() || !clobbered); + m_set.setReservedFlag(clobbered); } - -private: - static Structure* topValue() { return reinterpret_cast<Structure*>(1); } - - // NB. This must have a trivial destructor. - // This can only remember one structure at a time. - Structure* m_structure; + StructureSet m_set; }; } } // namespace JSC::DFG diff --git a/dfg/DFGStructureClobberState.h b/dfg/DFGStructureClobberState.h new file mode 100644 index 0000000..ac4275a --- /dev/null +++ b/dfg/DFGStructureClobberState.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 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 DFGStructureClobberState_h +#define DFGStructureClobberState_h + +#if ENABLE(DFG_JIT) + +#include <wtf/PrintStream.h> + +namespace JSC { namespace DFG { + +enum StructureClobberState { + StructuresAreWatched, // Constants with watchable structures must have those structures. + StructuresAreClobbered // Constants with watchable structures could have any structure. +}; + +inline StructureClobberState merge(StructureClobberState a, StructureClobberState b) +{ + switch (a) { + case StructuresAreWatched: + return b; + case StructuresAreClobbered: + return StructuresAreClobbered; + } + RELEASE_ASSERT_NOT_REACHED(); + return StructuresAreClobbered; +} + +} } // namespace JSC::DFG + +namespace WTF { + +inline void printInternal(PrintStream& out, JSC::DFG::StructureClobberState state) +{ + switch (state) { + case JSC::DFG::StructuresAreWatched: + out.print("StructuresAreWatched"); + return; + case JSC::DFG::StructuresAreClobbered: + out.print("StructuresAreClobbered"); + return; + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + +#endif // DFGStructureClobberState_h diff --git a/dfg/DFGStructureRegistrationPhase.cpp b/dfg/DFGStructureRegistrationPhase.cpp new file mode 100644 index 0000000..875e0d3 --- /dev/null +++ b/dfg/DFGStructureRegistrationPhase.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGStructureRegistrationPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGBasicBlockInlines.h" +#include "DFGGraph.h" +#include "DFGPhase.h" +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +class StructureRegistrationPhase : public Phase { +public: + StructureRegistrationPhase(Graph& graph) + : Phase(graph, "structure registration") + { + } + + bool run() + { + // We need to set this before this phase finishes. This phase doesn't do anything + // conditioned on this field, except for assertIsRegistered() below. We intend for that + // method to behave as if the phase was already finished. So, we set this up here. + m_graph.m_structureRegistrationState = AllStructuresAreRegistered; + + // These are pretty dumb, but needed to placate subsequent assertions. We don't actually + // have to watch these because there is no way to transition away from it, but they are + // watchable and so we will assert if they aren't watched. + registerStructure(m_graph.m_vm.structureStructure.get()); + registerStructure(m_graph.m_vm.stringStructure.get()); + registerStructure(m_graph.m_vm.getterSetterStructure.get()); + + for (FrozenValue* value : m_graph.m_frozenValues) + m_graph.assertIsRegistered(value->structure()); + + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* block = m_graph.block(blockIndex); + if (!block) + continue; + + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + + switch (node->op()) { + case CheckStructure: + registerStructures(node->structureSet()); + break; + + case NewObject: + case ArrayifyToStructure: + case NewStringObject: + registerStructure(node->structure()); + break; + + case PutStructure: + case AllocatePropertyStorage: + case ReallocatePropertyStorage: + registerStructure(node->transition()->previous); + registerStructure(node->transition()->next); + break; + + case MultiGetByOffset: + for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) { + GetByIdVariant& variant = node->multiGetByOffsetData().variants[i]; + registerStructures(variant.structureSet()); + // Don't need to watch anything in the structure chain because that would + // have been decomposed into CheckStructure's. Don't need to watch the + // callLinkStatus because we wouldn't use MultiGetByOffset if any of the + // variants did that. + ASSERT(!variant.callLinkStatus()); + } + break; + + case MultiPutByOffset: + for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { + PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; + registerStructures(variant.oldStructure()); + if (variant.kind() == PutByIdVariant::Transition) + registerStructure(variant.newStructure()); + } + break; + + case NewArray: + case NewArrayBuffer: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); + break; + + case NewTypedArray: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure(node->typedArrayType())); + break; + + case ToString: + case CallStringConstructor: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()); + break; + + case CreateActivation: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->activationStructure()); + break; + + case CreateDirectArguments: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->directArgumentsStructure()); + break; + + case CreateScopedArguments: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()); + break; + + case NewRegexp: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->regExpStructure()); + break; + + case NewFunction: + registerStructure(m_graph.globalObjectFor(node->origin.semantic)->functionStructure()); + break; + + default: + break; + } + } + } + + return true; + } + +private: + void registerStructures(const StructureSet& set) + { + for (unsigned i = set.size(); i--;) + registerStructure(set[i]); + } + + void registerStructure(Structure* structure) + { + if (structure) + m_graph.registerStructure(structure); + } +}; + +bool performStructureRegistration(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Structure Registration Phase"); + return runPhase<StructureRegistrationPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGResurrectionForValidationPhase.h b/dfg/DFGStructureRegistrationPhase.h similarity index 59% rename from dfg/DFGResurrectionForValidationPhase.h rename to dfg/DFGStructureRegistrationPhase.h index 64f3b2b..bba7891 100644 --- a/dfg/DFGResurrectionForValidationPhase.h +++ b/dfg/DFGStructureRegistrationPhase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,28 +23,32 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DFGResurrectionForValidationPhase_h -#define DFGResurrectionForValidationPhase_h +#ifndef DFGStructureRegistrationPhase_h +#define DFGStructureRegistrationPhase_h #if ENABLE(DFG_JIT) -#include "DFGCommon.h" - namespace JSC { namespace DFG { class Graph; -// Places a Phantom after every value-producing node, thereby disabling DCE from killing it. -// This is useful for validating our OSR exit machinery by instituting the requirement that -// any live-in-bytecode variable should be OSR-available. Without this phase, it's impossible -// to make such an assertion because our DCE is more aggressive than the bytecode liveness -// analysis. +// Registers any structures we know about as weak references, and sets watchpoints on any +// such structures that we know of that are currently watchable. It's somewhat +// counterintuitive, but this ends up being the cleanest and most effective way of reducing +// structure checks on terminal structures: +// +// - We used to only set watchpoints on watchable structures if we knew that this would +// remove a structure check. Experiments show that switching from that, to blindly +// setting watchpoints on all watchable structures, was not a regression. +// +// - It makes abstract interpretation a whole lot easier. We just assume that watchable +// structures are unclobberable without having to do any other logic. -bool performResurrectionForValidation(Graph&); +bool performStructureRegistration(Graph&); } } // namespace JSC::DFG #endif // ENABLE(DFG_JIT) -#endif // DFGResurrectionForValidationPhase_h +#endif // DFGStructureRegistrationPhase_h diff --git a/dfg/DFGTierUpCheckInjectionPhase.cpp b/dfg/DFGTierUpCheckInjectionPhase.cpp index 09c22b8..5f509c4 100644 --- a/dfg/DFGTierUpCheckInjectionPhase.cpp +++ b/dfg/DFGTierUpCheckInjectionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,6 +60,13 @@ public: if (!Options::enableOSREntryToFTL()) level = FTL::CanCompile; + + // First we find all the loops that contain a LoopHint for which we cannot OSR enter. + // We use that information to decide if we need CheckTierUpAndOSREnter or CheckTierUpWithNestedTriggerAndOSREnter. + NaturalLoops& naturalLoops = m_graph.m_naturalLoops; + naturalLoops.computeIfNecessary(m_graph); + + HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter = findLoopsContainingLoopHintWithoutOSREnter(naturalLoops, level); InsertionSet insertionSet(m_graph); for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { @@ -71,41 +78,23 @@ public: Node* node = block->at(nodeIndex); if (node->op() != LoopHint) continue; - - // We only put OSR checks for the first LoopHint in the block. Note that - // more than one LoopHint could happen in cases where we did a lot of CFG - // simplification in the bytecode parser, but it should be very rare. - + NodeOrigin origin = node->origin; - - if (level != FTL::CanCompileAndOSREnter || origin.semantic.inlineCallFrame) { - insertionSet.insertNode( - nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin); - break; - } - - bool isAtTop = true; - for (unsigned subNodeIndex = nodeIndex; subNodeIndex--;) { - if (!block->at(subNodeIndex)->isSemanticallySkippable()) { - isAtTop = false; - break; - } - } - - if (!isAtTop) { - insertionSet.insertNode( - nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin); - break; - } - - insertionSet.insertNode( - nodeIndex + 1, SpecNone, CheckTierUpAndOSREnter, origin); + if (canOSREnterAtLoopHint(level, block, nodeIndex)) { + const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block); + if (loop && loopsContainingLoopHintWithoutOSREnter.contains(loop)) + insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpWithNestedTriggerAndOSREnter, origin); + else + insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpAndOSREnter, origin); + } else + insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin); break; } - if (block->last()->op() == Return) { + NodeAndIndex terminal = block->findTerminal(); + if (terminal.node->op() == Return) { insertionSet.insertNode( - block->size() - 1, SpecNone, CheckTierUpAtReturn, block->last()->origin); + terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin); } insertionSet.execute(block); @@ -118,6 +107,49 @@ public: return false; #endif // ENABLE(FTL_JIT) } + +private: +#if ENABLE(FTL_JIT) + bool canOSREnterAtLoopHint(FTL::CapabilityLevel level, const BasicBlock* block, unsigned nodeIndex) + { + Node* node = block->at(nodeIndex); + ASSERT(node->op() == LoopHint); + + NodeOrigin origin = node->origin; + if (level != FTL::CanCompileAndOSREnter || origin.semantic.inlineCallFrame) + return false; + + // We only put OSR checks for the first LoopHint in the block. Note that + // more than one LoopHint could happen in cases where we did a lot of CFG + // simplification in the bytecode parser, but it should be very rare. + for (unsigned subNodeIndex = nodeIndex; subNodeIndex--;) { + if (!block->at(subNodeIndex)->isSemanticallySkippable()) + return false; + } + return true; + } + + HashSet<const NaturalLoop*> findLoopsContainingLoopHintWithoutOSREnter(const NaturalLoops& naturalLoops, FTL::CapabilityLevel level) + { + HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (node->op() != LoopHint) + continue; + + if (!canOSREnterAtLoopHint(level, block, nodeIndex)) { + const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block); + while (loop) { + loopsContainingLoopHintWithoutOSREnter.add(loop); + loop = naturalLoops.innerMostOuterLoop(*loop); + } + } + } + } + return loopsContainingLoopHintWithoutOSREnter; + } +#endif }; bool performTierUpCheckInjection(Graph& graph) diff --git a/dfg/DFGToFTLDeferredCompilationCallback.cpp b/dfg/DFGToFTLDeferredCompilationCallback.cpp index d0162b7..dd8108a 100644 --- a/dfg/DFGToFTLDeferredCompilationCallback.cpp +++ b/dfg/DFGToFTLDeferredCompilationCallback.cpp @@ -43,10 +43,9 @@ ToFTLDeferredCompilationCallback::ToFTLDeferredCompilationCallback( ToFTLDeferredCompilationCallback::~ToFTLDeferredCompilationCallback() { } -PassRefPtr<ToFTLDeferredCompilationCallback> ToFTLDeferredCompilationCallback::create( - PassRefPtr<CodeBlock> dfgCodeBlock) +Ref<ToFTLDeferredCompilationCallback> ToFTLDeferredCompilationCallback::create(PassRefPtr<CodeBlock> dfgCodeBlock) { - return adoptRef(new ToFTLDeferredCompilationCallback(dfgCodeBlock)); + return adoptRef(*new ToFTLDeferredCompilationCallback(dfgCodeBlock)); } void ToFTLDeferredCompilationCallback::compilationDidBecomeReadyAsynchronously( diff --git a/dfg/DFGToFTLDeferredCompilationCallback.h b/dfg/DFGToFTLDeferredCompilationCallback.h index f1ac4a6..3e0ea02 100644 --- a/dfg/DFGToFTLDeferredCompilationCallback.h +++ b/dfg/DFGToFTLDeferredCompilationCallback.h @@ -45,8 +45,7 @@ protected: public: virtual ~ToFTLDeferredCompilationCallback(); - static PassRefPtr<ToFTLDeferredCompilationCallback> create( - PassRefPtr<CodeBlock> dfgCodeBlock); + static Ref<ToFTLDeferredCompilationCallback> create(PassRefPtr<CodeBlock> dfgCodeBlock); virtual void compilationDidBecomeReadyAsynchronously(CodeBlock*); virtual void compilationDidComplete(CodeBlock*, CompilationResult); diff --git a/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp b/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp index 47c4fbb..70cc825 100644 --- a/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp +++ b/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp @@ -45,11 +45,10 @@ ToFTLForOSREntryDeferredCompilationCallback::~ToFTLForOSREntryDeferredCompilatio { } -PassRefPtr<ToFTLForOSREntryDeferredCompilationCallback> -ToFTLForOSREntryDeferredCompilationCallback::create( +Ref<ToFTLForOSREntryDeferredCompilationCallback>ToFTLForOSREntryDeferredCompilationCallback::create( PassRefPtr<CodeBlock> dfgCodeBlock) { - return adoptRef(new ToFTLForOSREntryDeferredCompilationCallback(dfgCodeBlock)); + return adoptRef(*new ToFTLForOSREntryDeferredCompilationCallback(dfgCodeBlock)); } void ToFTLForOSREntryDeferredCompilationCallback::compilationDidBecomeReadyAsynchronously( diff --git a/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h b/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h index c53df91..c9dcf6d 100644 --- a/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h +++ b/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h @@ -45,8 +45,7 @@ protected: public: virtual ~ToFTLForOSREntryDeferredCompilationCallback(); - static PassRefPtr<ToFTLForOSREntryDeferredCompilationCallback> create( - PassRefPtr<CodeBlock> dfgCodeBlock); + static Ref<ToFTLForOSREntryDeferredCompilationCallback> create(PassRefPtr<CodeBlock> dfgCodeBlock); virtual void compilationDidBecomeReadyAsynchronously(CodeBlock*); virtual void compilationDidComplete(CodeBlock*, CompilationResult); diff --git a/dfg/DFGTransition.cpp b/dfg/DFGTransition.cpp new file mode 100644 index 0000000..80d9b99 --- /dev/null +++ b/dfg/DFGTransition.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 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 "DFGTransition.h" + +#if ENABLE(DFG_JIT) + +#include "JSCInlines.h" + +namespace JSC { namespace DFG { + +void Transition::dumpInContext(PrintStream& out, DumpContext* context) const +{ + out.print(pointerDumpInContext(previous, context), " -> ", pointerDumpInContext(next, context)); +} + +void Transition::dump(PrintStream& out) const +{ + dumpInContext(out, 0); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGTransition.h b/dfg/DFGTransition.h new file mode 100644 index 0000000..49a6544 --- /dev/null +++ b/dfg/DFGTransition.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 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 DFGTransition_h +#define DFGTransition_h + +#if ENABLE(DFG_JIT) + +#include <wtf/PrintStream.h> +#include <wtf/Vector.h> + +namespace JSC { + +class Structure; +struct DumpContext; + +namespace DFG { + +struct Transition { + Structure* previous; + Structure* next; + + Transition() + : previous(nullptr) + , next(nullptr) + { + } + + Transition(Structure* previous, Structure* next) + : previous(previous) + , next(next) + { + } + + void dumpInContext(PrintStream&, DumpContext*) const; + void dump(PrintStream&) const; +}; + +typedef Vector<Transition, 3> TransitionVector; + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGTransition_h + diff --git a/dfg/DFGTypeCheckHoistingPhase.cpp b/dfg/DFGTypeCheckHoistingPhase.cpp index ad509cf..3416edf 100644 --- a/dfg/DFGTypeCheckHoistingPhase.cpp +++ b/dfg/DFGTypeCheckHoistingPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -115,7 +115,6 @@ public: // from the node, before doing any appending. switch (node->op()) { case SetArgument: { - ASSERT(!blockIndex); // Insert a GetLocal and a CheckStructure immediately following this // SetArgument, if the variable was a candidate for structure hoisting. // If the basic block previously only had the SetArgument as its @@ -127,6 +126,9 @@ public: if (!iter->value.m_structure && !iter->value.m_arrayModeIsValid) break; + // Currently we should only be doing this hoisting for SetArguments at the prologue. + ASSERT(!blockIndex); + NodeOrigin origin = node->origin; Node* getLocal = insertionSet.insertNode( @@ -215,8 +217,7 @@ private: for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { Node* node = block->at(indexInBlock); switch (node->op()) { - case CheckStructure: - case StructureTransitionWatchpoint: { + case CheckStructure: { Node* child = node->child1().node(); if (child->op() != GetLocal) break; @@ -227,7 +228,9 @@ private: noticeStructureCheck(variable, node->structureSet()); break; } - + + case ArrayifyToStructure: + case Arrayify: case GetByOffset: case PutByOffset: case PutStructure: @@ -243,29 +246,12 @@ private: case GetIndexedPropertyStorage: case GetTypedArrayByteOffset: case Phantom: - case HardPhantom: case MovHint: case MultiGetByOffset: case MultiPutByOffset: // Don't count these uses. break; - case ArrayifyToStructure: - case Arrayify: - if (node->arrayMode().conversion() == Array::RageConvert) { - // Rage conversion changes structures. We should avoid tying to do - // any kind of hoisting when rage conversion is in play. - Node* child = node->child1().node(); - if (child->op() != GetLocal) - break; - VariableAccessData* variable = child->variableAccessData(); - variable->vote(VoteOther); - if (!shouldConsiderForHoisting<StructureTypeCheck>(variable)) - break; - noticeStructureCheck(variable, 0); - } - break; - case SetLocal: { // Find all uses of the source of the SetLocal. If any of them are a // kind of CheckStructure, then we should notice them to ensure that @@ -285,13 +271,6 @@ private: noticeStructureCheck(variable, subNode->structureSet()); break; } - case StructureTransitionWatchpoint: { - if (subNode->child1() != source) - break; - - noticeStructureCheck(variable, subNode->structure()); - break; - } default: break; } @@ -331,7 +310,6 @@ private: } case CheckStructure: - case StructureTransitionWatchpoint: case GetByOffset: case PutByOffset: case PutStructure: @@ -344,7 +322,6 @@ private: case GetArrayLength: case GetIndexedPropertyStorage: case Phantom: - case HardPhantom: case MovHint: case MultiGetByOffset: case MultiPutByOffset: @@ -386,13 +363,6 @@ private: noticeStructureCheckAccountingForArrayMode(variable, subNode->structureSet()); break; } - case StructureTransitionWatchpoint: { - if (subNode->child1() != source) - break; - - noticeStructureCheckAccountingForArrayMode(variable, subNode->structure()); - break; - } case CheckArray: { if (subNode->child1() != source) break; @@ -503,7 +473,7 @@ private: noticeStructureCheck(variable, 0); return; } - noticeStructureCheck(variable, set.singletonStructure()); + noticeStructureCheck(variable, set.onlyStructure()); } void noticeCheckArray(VariableAccessData* variable, ArrayMode arrayMode) diff --git a/dfg/DFGUnificationPhase.cpp b/dfg/DFGUnificationPhase.cpp index 4e43eeb..0722dd9 100644 --- a/dfg/DFGUnificationPhase.cpp +++ b/dfg/DFGUnificationPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -70,7 +70,6 @@ public: for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { VariableAccessData* data = &m_graph.m_variableAccessData[i]; data->find()->predict(data->nonUnifiedPrediction()); - data->find()->mergeIsCaptured(data->isCaptured()); data->find()->mergeStructureCheckHoistingFailed(data->structureCheckHoistingFailed()); data->find()->mergeCheckArrayHoistingFailed(data->checkArrayHoistingFailed()); data->find()->mergeShouldNeverUnbox(data->shouldNeverUnbox()); diff --git a/dfg/DFGUseKind.cpp b/dfg/DFGUseKind.cpp index 913a715..efa104f 100644 --- a/dfg/DFGUseKind.cpp +++ b/dfg/DFGUseKind.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,80 +39,87 @@ void printInternal(PrintStream& out, UseKind useKind) switch (useKind) { case UntypedUse: out.print("Untyped"); - break; + return; case Int32Use: out.print("Int32"); - break; + return; case KnownInt32Use: out.print("KnownInt32"); - break; + return; case Int52RepUse: out.print("Int52Rep"); - break; + return; case MachineIntUse: out.print("MachineInt"); - break; + return; case NumberUse: out.print("Number"); - break; + return; + case RealNumberUse: + out.print("RealNumber"); + return; case DoubleRepUse: out.print("DoubleRep"); - break; + return; case DoubleRepRealUse: out.print("DoubleRepReal"); - break; + return; case DoubleRepMachineIntUse: out.print("DoubleRepMachineInt"); - break; + return; case BooleanUse: out.print("Boolean"); - break; + return; case CellUse: out.print("Cell"); - break; + return; case KnownCellUse: out.print("KnownCell"); - break; + return; case ObjectUse: out.print("Object"); - break; + return; + case FunctionUse: + out.print("Function"); + return; case FinalObjectUse: out.print("FinalObject"); - break; + return; case ObjectOrOtherUse: out.print("ObjectOrOther"); - break; + return; case StringIdentUse: out.print("StringIdent"); - break; + return; case StringUse: out.print("String"); - break; + return; case KnownStringUse: out.print("KnownString"); - break; + return; case StringObjectUse: out.print("StringObject"); - break; + return; case StringOrStringObjectUse: out.print("StringOrStringObject"); - break; + return; case NotStringVarUse: out.print("NotStringVar"); - break; + return; case NotCellUse: out.print("NotCell"); - break; + return; case OtherUse: out.print("Other"); - break; + return; case MiscUse: out.print("Misc"); - break; - default: + return; + case LastUseKind: RELEASE_ASSERT_NOT_REACHED(); - break; + return; } + RELEASE_ASSERT_NOT_REACHED(); } } // namespace WTF diff --git a/dfg/DFGUseKind.h b/dfg/DFGUseKind.h index d6eeef7..ebf99da 100644 --- a/dfg/DFGUseKind.h +++ b/dfg/DFGUseKind.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,19 +35,23 @@ namespace JSC { namespace DFG { enum UseKind { - UntypedUse, + // The DFG has 3 representations of values used: + + // 1. The JSValue representation for a JSValue that must be stored in a GP + // register (or a GP register pair), and follows rules for boxing and unboxing + // that allow the JSValue to be stored as either fully boxed JSValues, or + // unboxed Int32, Booleans, Cells, etc. in 32-bit as appropriate. + UntypedUse, // UntypedUse must come first (value 0). Int32Use, KnownInt32Use, - Int52RepUse, MachineIntUse, NumberUse, - DoubleRepUse, - DoubleRepRealUse, - DoubleRepMachineIntUse, + RealNumberUse, BooleanUse, CellUse, KnownCellUse, ObjectUse, + FunctionUse, FinalObjectUse, ObjectOrOtherUse, StringIdentUse, @@ -59,6 +63,17 @@ enum UseKind { NotCellUse, OtherUse, MiscUse, + + // 2. The Double representation for an unboxed double value that must be stored + // in an FP register. + DoubleRepUse, + DoubleRepRealUse, + DoubleRepMachineIntUse, + + // 3. The Int52 representation for an unboxed integer value that must be stored + // in a GP register. + Int52RepUse, + LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements. }; @@ -76,6 +91,8 @@ inline SpeculatedType typeFilterFor(UseKind useKind) return SpecInt32 | SpecInt52AsDouble; case NumberUse: return SpecBytecodeNumber; + case RealNumberUse: + return SpecBytecodeRealNumber; case DoubleRepUse: return SpecFullDouble; case DoubleRepRealUse: @@ -89,6 +106,8 @@ inline SpeculatedType typeFilterFor(UseKind useKind) return SpecCell; case ObjectUse: return SpecObject; + case FunctionUse: + return SpecFunction; case FinalObjectUse: return SpecFinalObject; case ObjectOrOtherUse: @@ -142,6 +161,7 @@ inline bool isNumerical(UseKind kind) case Int32Use: case KnownInt32Use: case NumberUse: + case RealNumberUse: case Int52RepUse: case DoubleRepUse: case DoubleRepRealUse: @@ -171,6 +191,7 @@ inline bool isCell(UseKind kind) case CellUse: case KnownCellUse: case ObjectUse: + case FunctionUse: case FinalObjectUse: case StringIdentUse: case StringUse: @@ -196,6 +217,17 @@ inline bool usesStructure(UseKind kind) } } +// Returns true if we've already guaranteed the type +inline bool alreadyChecked(UseKind kind, SpeculatedType type) +{ + // If the check involves the structure then we need to know more than just the type to be sure + // that the check is done. + if (usesStructure(kind)) + return false; + + return !(type & ~typeFilterFor(kind)); +} + inline UseKind useKindForResult(NodeFlags result) { ASSERT(!(result & ~NodeResultMask)); diff --git a/dfg/DFGValidate.cpp b/dfg/DFGValidate.cpp index ecd4d87..6748f5f 100644 --- a/dfg/DFGValidate.cpp +++ b/dfg/DFGValidate.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,7 @@ #if ENABLE(DFG_JIT) #include "CodeBlockWithJITType.h" +#include "DFGMayExit.h" #include "JSCInlines.h" #include <wtf/Assertions.h> #include <wtf/BitVector.h> @@ -37,9 +38,10 @@ namespace JSC { namespace DFG { class Validate { public: - Validate(Graph& graph, GraphDumpMode graphDumpMode) + Validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase) : m_graph(graph) , m_graphDumpMode(graphDumpMode) + , m_graphDumpBeforePhase(graphDumpBeforePhase) { } @@ -48,7 +50,7 @@ public: startCrashing(); \ dataLogF("\n\n\nAt "); \ reportValidationContext context; \ - dataLogF(": validation %s (%s:%d) failed.\n", #assertion, __FILE__, __LINE__); \ + dataLogF(": validation failed: %s (%s:%d).\n", #assertion, __FILE__, __LINE__); \ dumpGraphIfAppropriate(); \ WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \ CRASH(); \ @@ -60,11 +62,11 @@ public: startCrashing(); \ dataLogF("\n\n\nAt "); \ reportValidationContext context; \ - dataLogF(": validation (%s = ", #left); \ + dataLogF(": validation failed: (%s = ", #left); \ dataLog(left); \ dataLogF(") == (%s = ", #right); \ dataLog(right); \ - dataLogF(") (%s:%d) failed.\n", __FILE__, __LINE__); \ + dataLogF(") (%s:%d).\n", __FILE__, __LINE__); \ dumpGraphIfAppropriate(); \ WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #left " == " #right); \ CRASH(); \ @@ -72,7 +74,7 @@ public: } while (0) #define notSet (static_cast<size_t>(-1)) - + void validate() { // NB. This code is not written for performance, since it is not intended to run @@ -116,8 +118,8 @@ public: continue; m_myRefCounts.find(edge.node())->value++; - - VALIDATE((node, edge), edge->hasDoubleResult() == (edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse)); + + validateEdgeWithDoubleResultIfNecessary(node, edge); VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse)); if (m_graph.m_form == SSA) { @@ -144,31 +146,6 @@ public: break; VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); break; - case Phantom: - switch (m_graph.m_form) { - case LoadStore: - if (j) { - VALIDATE((node, edge), edge->hasResult()); - break; - } - switch (edge->op()) { - case Phi: - case SetArgument: - case SetLocal: - break; - default: - VALIDATE((node, edge), edge->hasResult()); - break; - } - break; - case ThreadedCPS: - VALIDATE((node, edge), edge->hasResult()); - break; - case SSA: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - break; default: VALIDATE((node, edge), edge->hasResult()); break; @@ -185,25 +162,100 @@ public: Node* node = block->node(i); if (m_graph.m_refCountState == ExactRefCount) V_EQUAL((node), m_myRefCounts.get(node), node->adjustedRefCount()); - else - V_EQUAL((node), node->refCount(), 1); } - for (size_t i = 0 ; i < block->size() - 1; ++i) { + bool foundTerminal = false; + for (size_t i = 0 ; i < block->size(); ++i) { Node* node = block->at(i); - VALIDATE((node), !node->isTerminal()); + if (node->isTerminal()) { + foundTerminal = true; + for (size_t j = i + 1; j < block->size(); ++j) { + node = block->at(j); + VALIDATE((node), node->op() == Phantom || node->op() == PhantomLocal || node->op() == Flush || node->op() == Check); + m_graph.doToChildren( + node, + [&] (Edge edge) { + VALIDATE((node, edge), shouldNotHaveTypeCheck(edge.useKind())); + }); + } + break; + } } + VALIDATE((block), foundTerminal); for (size_t i = 0; i < block->size(); ++i) { Node* node = block->at(i); - if (node->hasStructure()) - VALIDATE((node), !!node->structure()); - + VALIDATE((node), node->origin.semantic.isSet() == node->origin.forExit.isSet()); + VALIDATE((node), !mayExit(m_graph, node) || node->origin.forExit.isSet()); + VALIDATE((node), !node->hasStructure() || !!node->structure()); + VALIDATE((node), !node->hasCellOperand() || node->cellOperand()->value().isCell()); + VALIDATE((node), !node->hasCellOperand() || !!node->cellOperand()->value()); + + if (!(node->flags() & NodeHasVarArgs)) { + if (!node->child2()) + VALIDATE((node), !node->child3()); + if (!node->child1()) + VALIDATE((node), !node->child2()); + } + switch (node->op()) { case Identity: VALIDATE((node), canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(node->child1()->result())); break; + case SetLocal: + case PutStack: + case Upsilon: + VALIDATE((node), !!node->child1()); + switch (node->child1().useKind()) { + case UntypedUse: + case CellUse: + case Int32Use: + case Int52RepUse: + case DoubleRepUse: + case BooleanUse: + break; + default: + VALIDATE((node), !"Bad use kind"); + break; + } + break; + case MakeRope: + case ValueAdd: + case ArithAdd: + case ArithSub: + case ArithMul: + case ArithIMul: + case ArithDiv: + case ArithMod: + case ArithMin: + case ArithMax: + case ArithPow: + case CompareLess: + case CompareLessEq: + case CompareGreater: + case CompareGreaterEq: + case CompareEq: + case CompareEqConstant: + case CompareStrictEq: + VALIDATE((node), !!node->child1()); + VALIDATE((node), !!node->child2()); + break; + case PutStructure: + VALIDATE((node), !node->transition()->previous->dfgShouldWatch()); + break; + case MultiPutByOffset: + for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { + const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; + if (variant.kind() != PutByIdVariant::Transition) + continue; + VALIDATE((node), !variant.oldStructureForTransition()->dfgShouldWatch()); + } + break; + case DoubleConstant: + case Int52Constant: + VALIDATE((node), node->isNumberConstant()); + break; default: break; } @@ -225,6 +277,7 @@ public: private: Graph& m_graph; GraphDumpMode m_graphDumpMode; + CString m_graphDumpBeforePhase; HashMap<Node*, unsigned> m_myRefCounts; HashSet<Node*> m_acceptableNodes; @@ -354,6 +407,7 @@ private: Node* node = block->at(i); ASSERT(nodesInThisBlock.contains(node)); VALIDATE((node), node->op() != Phi); + VALIDATE((node), node->origin.forExit.isSet()); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { Edge edge = m_graph.child(node, j); if (!edge) @@ -364,39 +418,63 @@ private: case GetLocal: case Flush: break; - case Phantom: - if (m_graph.m_form == LoadStore && !j) - break; - FALLTHROUGH; default: VALIDATE((node, edge), !phisInThisBlock.contains(edge.node())); break; } } + switch (node->op()) { + case Phi: + case Upsilon: + case CheckInBounds: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case GetMyArgumentByVal: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PutStack: + case KillStack: + case GetStack: + VALIDATE((node), !"unexpected node type in CPS"); + break; + case Phantom: + VALIDATE((node), m_graph.m_fixpointState != FixpointNotConverged); + break; + default: + break; + } + if (!node->shouldGenerate()) continue; switch (node->op()) { case GetLocal: - if (node->variableAccessData()->isCaptured()) - break; // Ignore GetLocal's that we know to be dead, but that the graph // doesn't yet know to be dead. if (!m_myRefCounts.get(node)) break; - if (m_graph.m_form == ThreadedCPS) + if (m_graph.m_form == ThreadedCPS) { VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet); + VALIDATE((node, block), !!node->child1()); + } getLocalPositions.operand(node->local()) = i; break; case SetLocal: - if (node->variableAccessData()->isCaptured()) - break; // Only record the first SetLocal. There may be multiple SetLocals // because of flushing. if (setLocalPositions.operand(node->local()) != notSet) break; setLocalPositions.operand(node->local()) = i; break; + case SetArgument: + // This acts like a reset. It's ok to have a second GetLocal for a local in the same + // block if we had a SetArgument for that local. + getLocalPositions.operand(node->local()) = notSet; + setLocalPositions.operand(node->local()) = notSet; + break; default: break; } @@ -426,19 +504,29 @@ private: if (!block) continue; + VALIDATE((block), block->phis.isEmpty()); + unsigned nodeIndex = 0; - for (; nodeIndex < block->size() && !block->at(nodeIndex)->origin.isSet(); nodeIndex++) { } + for (; nodeIndex < block->size() && !block->at(nodeIndex)->origin.forExit.isSet(); nodeIndex++) { } VALIDATE((block), nodeIndex < block->size()); for (; nodeIndex < block->size(); nodeIndex++) - VALIDATE((block->at(nodeIndex)), block->at(nodeIndex)->origin.isSet()); + VALIDATE((block->at(nodeIndex)), block->at(nodeIndex)->origin.forExit.isSet()); for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { Node* node = block->at(nodeIndex); switch (node->op()) { case Phi: - VALIDATE((node), !node->origin.isSet()); + VALIDATE((node), !node->origin.forExit.isSet()); + break; + + case GetLocal: + case SetLocal: + case GetLocalUnlinked: + case SetArgument: + case Phantom: + VALIDATE((node), !"bad node type for SSA"); break; default: @@ -449,7 +537,18 @@ private: } } } - + + void validateEdgeWithDoubleResultIfNecessary(Node* node, Edge edge) + { + if (!edge->hasDoubleResult()) + return; + + if (m_graph.m_planStage < PlanStage::AfterFixup) + return; + + VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse); + } + void checkOperand( BasicBlock* block, Operands<size_t>& getLocalPositions, Operands<size_t>& setLocalPositions, VirtualRegister operand) @@ -484,23 +583,23 @@ private: void reportValidationContext(VirtualRegister local, BasicBlock* block) { if (!block) { - dataLog("r", local, " in null Block "); + dataLog(local, " in null Block "); return; } - dataLog("r", local, " in Block ", *block); + dataLog(local, " in Block ", *block); } void reportValidationContext( VirtualRegister local, BasicBlock* sourceBlock, BasicBlock* destinationBlock) { - dataLog("r", local, " in Block ", *sourceBlock, " -> ", *destinationBlock); + dataLog(local, " in Block ", *sourceBlock, " -> ", *destinationBlock); } void reportValidationContext( VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode) { - dataLog(prevNode, " for r", local, " in Block ", *sourceBlock); + dataLog(prevNode, " for ", local, " in Block ", *sourceBlock); } void reportValidationContext(Node* node, BasicBlock* block) @@ -523,14 +622,19 @@ private: { if (m_graphDumpMode == DontDumpGraph) return; + dataLog("\n"); + if (!m_graphDumpBeforePhase.isNull()) { + dataLog("Before phase:\n"); + dataLog(m_graphDumpBeforePhase); + } dataLog("At time of failure:\n"); m_graph.dump(); } }; -void validate(Graph& graph, GraphDumpMode graphDumpMode) +void validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase) { - Validate validationObject(graph, graphDumpMode); + Validate validationObject(graph, graphDumpMode, graphDumpBeforePhase); validationObject.validate(); } diff --git a/dfg/DFGValidate.h b/dfg/DFGValidate.h index dd7b222..ff4d06b 100644 --- a/dfg/DFGValidate.h +++ b/dfg/DFGValidate.h @@ -35,7 +35,7 @@ namespace JSC { namespace DFG { enum GraphDumpMode { DontDumpGraph, DumpGraph }; -void validate(Graph&, GraphDumpMode = DumpGraph); +void validate(Graph&, GraphDumpMode = DumpGraph, CString graphDumpBeforePhase = CString()); } } // namespace JSC::DFG diff --git a/dfg/DFGValueSource.cpp b/dfg/DFGValueSource.cpp index 207a4d7..41d8b47 100644 --- a/dfg/DFGValueSource.cpp +++ b/dfg/DFGValueSource.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,25 +42,22 @@ void ValueSource::dump(PrintStream& out) const out.print("IsDead"); break; case ValueInJSStack: - out.print("JS:r", virtualRegister()); + out.print("JS:", virtualRegister()); break; case Int32InJSStack: - out.print("Int32:r", virtualRegister()); + out.print("Int32:", virtualRegister()); break; case Int52InJSStack: - out.print("Int52:r", virtualRegister()); + out.print("Int52:", virtualRegister()); break; case CellInJSStack: - out.print("Cell:r", virtualRegister()); + out.print("Cell:", virtualRegister()); break; case BooleanInJSStack: - out.print("Bool:r", virtualRegister()); + out.print("Bool:", virtualRegister()); break; case DoubleInJSStack: - out.print("Double:r", virtualRegister()); - break; - case ArgumentsSource: - out.print("Arguments"); + out.print("Double:", virtualRegister()); break; case HaveNode: out.print("Node(", m_value, ")"); diff --git a/dfg/DFGValueSource.h b/dfg/DFGValueSource.h index 33bb457..1b55797 100644 --- a/dfg/DFGValueSource.h +++ b/dfg/DFGValueSource.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,7 +45,6 @@ enum ValueSourceKind { CellInJSStack, BooleanInJSStack, DoubleInJSStack, - ArgumentsSource, SourceIsDead, HaveNode }; @@ -65,8 +64,6 @@ static inline ValueSourceKind dataFormatToValueSourceKind(DataFormat dataFormat) return CellInJSStack; case DataFormatDead: return SourceIsDead; - case DataFormatArguments: - return ArgumentsSource; default: RELEASE_ASSERT(dataFormat & DataFormatJS); return ValueInJSStack; @@ -88,8 +85,6 @@ static inline DataFormat valueSourceKindToDataFormat(ValueSourceKind kind) return DataFormatBoolean; case DoubleInJSStack: return DataFormatDouble; - case ArgumentsSource: - return DataFormatArguments; case SourceIsDead: return DataFormatDead; default: @@ -120,7 +115,7 @@ public: explicit ValueSource(ValueSourceKind valueSourceKind) : m_kind(valueSourceKind) { - ASSERT(kind() == ArgumentsSource || kind() == SourceIsDead || kind() == ArgumentsSource); + ASSERT(kind() == SourceIsDead); } explicit ValueSource(MinifiedID id) @@ -157,8 +152,6 @@ public: return ValueSource(CellInJSStack, where); case FlushedBoolean: return ValueSource(BooleanInJSStack, where); - case FlushedArguments: - return ValueSource(ArgumentsSource); } RELEASE_ASSERT_NOT_REACHED(); return ValueSource(); @@ -196,9 +189,6 @@ public: case SourceIsDead: return ValueRecovery::constant(jsUndefined()); - case ArgumentsSource: - return ValueRecovery::argumentsThatWereNotCreated(); - default: return ValueRecovery::displacedInJSStack(virtualRegister(), dataFormat()); } diff --git a/dfg/DFGValueStrength.cpp b/dfg/DFGValueStrength.cpp new file mode 100644 index 0000000..2c6e612 --- /dev/null +++ b/dfg/DFGValueStrength.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, 2015 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 "DFGValueStrength.h" + +#if ENABLE(DFG_JIT) + +namespace WTF { + +using namespace JSC::DFG; + +void printInternal(PrintStream& out, ValueStrength strength) +{ + switch (strength) { + case WeakValue: + out.print("Weak"); + return; + case StrongValue: + out.print("Strong"); + return; + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGValueStrength.h b/dfg/DFGValueStrength.h new file mode 100644 index 0000000..72cd71c --- /dev/null +++ b/dfg/DFGValueStrength.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014, 2015 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 DFGValueStrength_h +#define DFGValueStrength_h + +#if ENABLE(DFG_JIT) + +#include <wtf/PrintStream.h> + +namespace JSC { namespace DFG { + +enum ValueStrength { + // The value has been used for optimization and it arose through inference. We don't want the + // fact that we optimized the code to result in the GC keeping this value alive unnecessarily, + // so we'd rather kill the code and recompile than keep the object alive longer. + WeakValue, + + // The code will keep this value alive. This is true of constants that were present in the + // source. String constants tend to be strong. + StrongValue +}; + +inline ValueStrength merge(ValueStrength a, ValueStrength b) +{ + switch (a) { + case WeakValue: + return b; + case StrongValue: + return StrongValue; + } + RELEASE_ASSERT_NOT_REACHED(); + + return WeakValue; +} + +} } // namespace JSC::DFG + +namespace WTF { + +void printInternal(PrintStream&, JSC::DFG::ValueStrength); + +} // namespace WTF + +#endif // ENABLE(DFG_JIT) + +#endif // DFGValueStrength_h + diff --git a/dfg/DFGVarargsForwardingPhase.cpp b/dfg/DFGVarargsForwardingPhase.cpp new file mode 100644 index 0000000..9371de5 --- /dev/null +++ b/dfg/DFGVarargsForwardingPhase.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2015 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 "DFGVarargsForwardingPhase.h" + +#if ENABLE(DFG_JIT) + +#include "DFGArgumentsUtilities.h" +#include "DFGClobberize.h" +#include "DFGForAllKills.h" +#include "DFGGraph.h" +#include "DFGPhase.h" +#include "JSCInlines.h" +#include <wtf/ListDump.h> + +namespace JSC { namespace DFG { + +namespace { + +bool verbose = false; + +class VarargsForwardingPhase : public Phase { +public: + VarargsForwardingPhase(Graph& graph) + : Phase(graph, "varargs forwarding") + { + } + + bool run() + { + DFG_ASSERT(m_graph, nullptr, m_graph.m_form != SSA); + + if (verbose) { + dataLog("Graph before varargs forwarding:\n"); + m_graph.dump(); + } + + m_changed = false; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) + handleBlock(block); + return m_changed; + } + +private: + void handleBlock(BasicBlock* block) + { + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + switch (node->op()) { + case CreateDirectArguments: + case CreateClonedArguments: + handleCandidate(block, nodeIndex); + break; + default: + break; + } + } + } + + void handleCandidate(BasicBlock* block, unsigned candidateNodeIndex) + { + // We expect calls into this function to be rare. So, this is written in a simple O(n) manner. + + Node* candidate = block->at(candidateNodeIndex); + if (verbose) + dataLog("Handling candidate ", candidate, "\n"); + + // Find the index of the last node in this block to use the candidate, and look for escaping + // sites. + unsigned lastUserIndex = candidateNodeIndex; + Vector<VirtualRegister, 2> relevantLocals; // This is a set. We expect it to be a small set. + for (unsigned nodeIndex = candidateNodeIndex + 1; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + + switch (node->op()) { + case MovHint: + if (node->child1() != candidate) + break; + lastUserIndex = nodeIndex; + if (!relevantLocals.contains(node->unlinkedLocal())) + relevantLocals.append(node->unlinkedLocal()); + break; + + case Check: { + bool sawEscape = false; + m_graph.doToChildren( + node, + [&] (Edge edge) { + if (edge == candidate) + lastUserIndex = nodeIndex; + + if (edge.willNotHaveCheck()) + return; + + if (alreadyChecked(edge.useKind(), SpecObject)) + return; + + sawEscape = true; + }); + if (sawEscape) { + if (verbose) + dataLog(" Escape at ", node, "\n"); + return; + } + break; + } + + case LoadVarargs: + if (m_graph.uses(node, candidate)) + lastUserIndex = nodeIndex; + break; + + case CallVarargs: + case ConstructVarargs: + if (node->child1() == candidate || node->child3() == candidate) { + if (verbose) + dataLog(" Escape at ", node, "\n"); + return; + } + if (node->child2() == candidate) + lastUserIndex = nodeIndex; + break; + + case SetLocal: + if (node->child1() == candidate && node->variableAccessData()->isLoadedFrom()) { + if (verbose) + dataLog(" Escape at ", node, "\n"); + return; + } + break; + + default: + if (m_graph.uses(node, candidate)) { + if (verbose) + dataLog(" Escape at ", node, "\n"); + return; + } + } + + forAllKilledOperands( + m_graph, node, block->tryAt(nodeIndex + 1), + [&] (VirtualRegister reg) { + if (verbose) + dataLog(" Killing ", reg, " while we are interested in ", listDump(relevantLocals), "\n"); + for (unsigned i = 0; i < relevantLocals.size(); ++i) { + if (relevantLocals[i] == reg) { + relevantLocals[i--] = relevantLocals.last(); + relevantLocals.removeLast(); + lastUserIndex = nodeIndex; + } + } + }); + } + if (verbose) + dataLog("Selected lastUserIndex = ", lastUserIndex, ", ", block->at(lastUserIndex), "\n"); + + // We're still in business. Determine if between the candidate and the last user there is any + // effect that could interfere with sinking. + for (unsigned nodeIndex = candidateNodeIndex + 1; nodeIndex <= lastUserIndex; ++nodeIndex) { + Node* node = block->at(nodeIndex); + + // We have our own custom switch to detect some interferences that clobberize() wouldn't know + // about, and also some of the common ones, too. In particular, clobberize() doesn't know + // that Flush, MovHint, ZombieHint, and KillStack are bad because it's not worried about + // what gets read on OSR exit. + switch (node->op()) { + case MovHint: + case ZombieHint: + case KillStack: + if (argumentsInvolveStackSlot(candidate, node->unlinkedLocal())) { + if (verbose) + dataLog(" Interference at ", node, "\n"); + return; + } + break; + + case PutStack: + if (argumentsInvolveStackSlot(candidate, node->stackAccessData()->local)) { + if (verbose) + dataLog(" Interference at ", node, "\n"); + return; + } + break; + + case SetLocal: + case Flush: + if (argumentsInvolveStackSlot(candidate, node->local())) { + if (verbose) + dataLog(" Interference at ", node, "\n"); + return; + } + break; + + default: { + bool doesInterfere = false; + clobberize( + m_graph, node, NoOpClobberize(), + [&] (AbstractHeap heap) { + if (heap.kind() != Stack) { + ASSERT(!heap.overlaps(Stack)); + return; + } + ASSERT(!heap.payload().isTop()); + VirtualRegister reg(heap.payload().value32()); + if (argumentsInvolveStackSlot(candidate, reg)) + doesInterfere = true; + }, + NoOpClobberize()); + if (doesInterfere) { + if (verbose) + dataLog(" Interference at ", node, "\n"); + return; + } + } } + } + + // We can make this work. + if (verbose) + dataLog(" Will do forwarding!\n"); + m_changed = true; + + // Transform the program. + switch (candidate->op()) { + case CreateDirectArguments: + candidate->setOpAndDefaultFlags(PhantomDirectArguments); + break; + + case CreateClonedArguments: + candidate->setOpAndDefaultFlags(PhantomClonedArguments); + break; + + default: + DFG_CRASH(m_graph, candidate, "bad node type"); + break; + } + for (unsigned nodeIndex = candidateNodeIndex + 1; nodeIndex <= lastUserIndex; ++nodeIndex) { + Node* node = block->at(nodeIndex); + switch (node->op()) { + case Check: + case MovHint: + case PutHint: + // We don't need to change anything with these. + break; + + case LoadVarargs: + if (node->child1() != candidate) + break; + node->setOpAndDefaultFlags(ForwardVarargs); + break; + + case CallVarargs: + if (node->child2() != candidate) + break; + node->setOpAndDefaultFlags(CallForwardVarargs); + break; + + case ConstructVarargs: + if (node->child2() != candidate) + break; + node->setOpAndDefaultFlags(ConstructForwardVarargs); + break; + + case SetLocal: + // This is super odd. We don't have to do anything here, since in DFG IR, the phantom + // arguments nodes do produce a JSValue. Also, we know that if this SetLocal referenecs a + // candidate then the SetLocal - along with all of its references - will die off pretty + // soon, since it has no real users. DCE will surely kill it. If we make it to SSA, then + // SSA conversion will kill it. + break; + + default: + if (ASSERT_DISABLED) + break; + m_graph.doToChildren( + node, + [&] (Edge edge) { + DFG_ASSERT(m_graph, node, edge != candidate); + }); + break; + } + } + } + + bool m_changed; +}; + +} // anonymous namespace + +bool performVarargsForwarding(Graph& graph) +{ + SamplingRegion samplingRegion("DFG Varargs Forwarding Phase"); + return runPhase<VarargsForwardingPhase>(graph); +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/dfg/DFGVarargsForwardingPhase.h b/dfg/DFGVarargsForwardingPhase.h new file mode 100644 index 0000000..ece3747 --- /dev/null +++ b/dfg/DFGVarargsForwardingPhase.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 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 DFGVarargsForwardingPhase_h +#define DFGVarargsForwardingPhase_h + +#if ENABLE(DFG_JIT) + +namespace JSC { namespace DFG { + +class Graph; + +// Eliminates allocations of Arguments-class objects when they flow into CallVarargs, ConstructVarargs, +// or LoadVarargs. + +bool performVarargsForwarding(Graph&); + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGVarargsForwardingPhase_h + diff --git a/dfg/DFGVariableAccessData.cpp b/dfg/DFGVariableAccessData.cpp index 82784c8..bd1ba87 100644 --- a/dfg/DFGVariableAccessData.cpp +++ b/dfg/DFGVariableAccessData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,9 +35,7 @@ VariableAccessData::VariableAccessData() , m_prediction(SpecNone) , m_argumentAwarePrediction(SpecNone) , m_flags(0) - , m_isCaptured(false) , m_shouldNeverUnbox(false) - , m_isArgumentsAlias(false) , m_structureCheckHoistingFailed(false) , m_checkArrayHoistingFailed(false) , m_isProfitableToUnbox(false) @@ -47,14 +45,12 @@ VariableAccessData::VariableAccessData() clearVotes(); } -VariableAccessData::VariableAccessData(VirtualRegister local, bool isCaptured) +VariableAccessData::VariableAccessData(VirtualRegister local) : m_local(local) , m_prediction(SpecNone) , m_argumentAwarePrediction(SpecNone) , m_flags(0) - , m_isCaptured(isCaptured) - , m_shouldNeverUnbox(isCaptured) - , m_isArgumentsAlias(false) + , m_shouldNeverUnbox(false) , m_structureCheckHoistingFailed(false) , m_checkArrayHoistingFailed(false) , m_isProfitableToUnbox(false) @@ -64,12 +60,6 @@ VariableAccessData::VariableAccessData(VirtualRegister local, bool isCaptured) clearVotes(); } -bool VariableAccessData::mergeIsCaptured(bool isCaptured) -{ - return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox | isCaptured) - | checkAndSet(m_isCaptured, m_isCaptured | isCaptured); -} - bool VariableAccessData::mergeShouldNeverUnbox(bool shouldNeverUnbox) { bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox; @@ -198,9 +188,6 @@ FlushFormat VariableAccessData::flushFormat() { ASSERT(find() == this); - if (isArgumentsAlias()) - return FlushedArguments; - if (!shouldUnboxIfPossible()) return FlushedJSValue; diff --git a/dfg/DFGVariableAccessData.h b/dfg/DFGVariableAccessData.h index cfdd264..0f81756 100644 --- a/dfg/DFGVariableAccessData.h +++ b/dfg/DFGVariableAccessData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Apple Inc. All rights reserved. + * Copyright (C) 2011-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,7 +48,7 @@ enum DoubleBallot { VoteValue, VoteDouble }; class VariableAccessData : public UnionFind<VariableAccessData> { public: VariableAccessData(); - VariableAccessData(VirtualRegister local, bool isCaptured); + VariableAccessData(VirtualRegister local); VirtualRegister local() { @@ -62,16 +62,9 @@ public: return m_machineLocal; } - bool mergeIsCaptured(bool isCaptured); - - bool isCaptured() - { - return m_isCaptured; - } - bool mergeIsProfitableToUnbox(bool isProfitableToUnbox) { - return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox | isProfitableToUnbox); + return checkAndSet(m_isProfitableToUnbox, m_isProfitableToUnbox || isProfitableToUnbox); } bool isProfitableToUnbox() @@ -86,7 +79,6 @@ public: // mean that we have actually done so. bool shouldNeverUnbox() { - ASSERT(!(m_isCaptured && !m_shouldNeverUnbox)); return m_shouldNeverUnbox; } @@ -100,12 +92,12 @@ public: bool mergeStructureCheckHoistingFailed(bool failed) { - return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed | failed); + return checkAndSet(m_structureCheckHoistingFailed, m_structureCheckHoistingFailed || failed); } bool mergeCheckArrayHoistingFailed(bool failed) { - return checkAndSet(m_checkArrayHoistingFailed, m_checkArrayHoistingFailed | failed); + return checkAndSet(m_checkArrayHoistingFailed, m_checkArrayHoistingFailed || failed); } bool structureCheckHoistingFailed() @@ -118,19 +110,9 @@ public: return m_checkArrayHoistingFailed; } - bool mergeIsArgumentsAlias(bool isArgumentsAlias) - { - return checkAndSet(m_isArgumentsAlias, m_isArgumentsAlias | isArgumentsAlias); - } - - bool isArgumentsAlias() - { - return m_isArgumentsAlias; - } - bool mergeIsLoadedFrom(bool isLoadedFrom) { - return checkAndSet(m_isLoadedFrom, m_isLoadedFrom | isLoadedFrom); + return checkAndSet(m_isLoadedFrom, m_isLoadedFrom || isLoadedFrom); } void setIsLoadedFrom(bool isLoadedFrom) @@ -193,7 +175,6 @@ public: ASSERT(isRoot()); bool doubleState = m_doubleFormatState == UsingDoubleFormat; ASSERT(!(doubleState && shouldNeverUnbox())); - ASSERT(!(doubleState && isCaptured())); return doubleState && isProfitableToUnbox(); } @@ -233,9 +214,7 @@ private: SpeculatedType m_argumentAwarePrediction; NodeFlags m_flags; - bool m_isCaptured; bool m_shouldNeverUnbox; - bool m_isArgumentsAlias; bool m_structureCheckHoistingFailed; bool m_checkArrayHoistingFailed; bool m_isProfitableToUnbox; diff --git a/dfg/DFGVariableAccessDataDump.cpp b/dfg/DFGVariableAccessDataDump.cpp index 105964c..0062173 100644 --- a/dfg/DFGVariableAccessDataDump.cpp +++ b/dfg/DFGVariableAccessDataDump.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,9 +62,7 @@ void VariableAccessDataDump::dump(PrintStream& out) const index /= 26; } - if (m_data->isCaptured()) - out.print("*"); - else if (m_data->shouldNeverUnbox()) + if (m_data->shouldNeverUnbox()) out.print("!"); else if (!m_data->shouldUnboxIfPossible()) out.print("~"); diff --git a/dfg/DFGVariableAccessDataDump.h b/dfg/DFGVariableAccessDataDump.h index fd64e1a..fd53fcd 100644 --- a/dfg/DFGVariableAccessDataDump.h +++ b/dfg/DFGVariableAccessDataDump.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2015 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/dfg/DFGVariableEvent.cpp b/dfg/DFGVariableEvent.cpp index b71f4e7..28e437f 100644 --- a/dfg/DFGVariableEvent.cpp +++ b/dfg/DFGVariableEvent.cpp @@ -46,6 +46,9 @@ void VariableEvent::dump(PrintStream& out) const case BirthToSpill: dumpSpillInfo("BirthToSpill", out); break; + case Birth: + out.print("Birth(", id(), ")"); + break; case Fill: dumpFillInfo("Fill", out); break; @@ -56,11 +59,11 @@ void VariableEvent::dump(PrintStream& out) const out.print("Death(", id(), ")"); break; case MovHintEvent: - out.print("MovHint(", id(), ", r", bytecodeRegister(), ")"); + out.print("MovHint(", id(), ", ", bytecodeRegister(), ")"); break; case SetLocalEvent: out.print( - "SetLocal(machine:r", machineRegister(), " -> bytecode:r", bytecodeRegister(), + "SetLocal(machine:", machineRegister(), " -> bytecode:", bytecodeRegister(), ", ", dataFormatToString(dataFormat()), ")"); break; default: @@ -85,7 +88,7 @@ void VariableEvent::dumpFillInfo(const char* name, PrintStream& out) const void VariableEvent::dumpSpillInfo(const char* name, PrintStream& out) const { - out.print(name, "(", id(), ", r", spillRegister(), ", ", dataFormatToString(dataFormat()), ")"); + out.print(name, "(", id(), ", ", spillRegister(), ", ", dataFormatToString(dataFormat()), ")"); } } } // namespace JSC::DFG diff --git a/dfg/DFGVariableEvent.h b/dfg/DFGVariableEvent.h index 9e76e55..5fa4bb6 100644 --- a/dfg/DFGVariableEvent.h +++ b/dfg/DFGVariableEvent.h @@ -47,6 +47,7 @@ enum VariableEventKind { // that we start to care about this node. BirthToFill, BirthToSpill, + Birth, // Events related to how a node is represented. Fill, @@ -133,6 +134,14 @@ public: return event; } + static VariableEvent birth(MinifiedID id) + { + VariableEvent event; + event.m_which.id = id.bits(); + event.m_kind = Birth; + return event; + } + static VariableEvent spill(VariableEventKind kind, MinifiedID id, VirtualRegister virtualRegister, DataFormat format) { ASSERT(kind == BirthToSpill || kind == Spill); @@ -179,17 +188,17 @@ public: MinifiedID id() const { - ASSERT(m_kind == BirthToFill || m_kind == Fill - || m_kind == BirthToSpill || m_kind == Spill - || m_kind == Death || m_kind == MovHintEvent); + ASSERT( + m_kind == BirthToFill || m_kind == Fill || m_kind == BirthToSpill || m_kind == Spill + || m_kind == Death || m_kind == MovHintEvent || m_kind == Birth); return MinifiedID::fromBits(m_which.id); } DataFormat dataFormat() const { - ASSERT(m_kind == BirthToFill || m_kind == Fill - || m_kind == BirthToSpill || m_kind == Spill - || m_kind == SetLocalEvent); + ASSERT( + m_kind == BirthToFill || m_kind == Fill || m_kind == BirthToSpill || m_kind == Spill + || m_kind == SetLocalEvent); return static_cast<DataFormat>(m_dataFormat); } diff --git a/dfg/DFGVariableEventStream.cpp b/dfg/DFGVariableEventStream.cpp index c209ce4..e3f413c 100644 --- a/dfg/DFGVariableEventStream.cpp +++ b/dfg/DFGVariableEventStream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,11 +48,14 @@ namespace { struct MinifiedGenerationInfo { bool filled; // true -> in gpr/fpr/pair, false -> spilled + bool alive; VariableRepresentation u; DataFormat format; MinifiedGenerationInfo() - : format(DataFormatNone) + : filled(false) + , alive(false) + , format(DataFormatNone) { } @@ -62,13 +65,19 @@ struct MinifiedGenerationInfo { case BirthToFill: case Fill: filled = true; + alive = true; break; case BirthToSpill: case Spill: filled = false; + alive = true; break; + case Birth: + alive = true; + return; case Death: format = DataFormatNone; + alive = false; return; default: return; @@ -81,25 +90,23 @@ struct MinifiedGenerationInfo { } // namespace -bool VariableEventStream::tryToSetConstantRecovery(ValueRecovery& recovery, CodeBlock* codeBlock, MinifiedNode* node) const +bool VariableEventStream::tryToSetConstantRecovery(ValueRecovery& recovery, MinifiedNode* node) const { if (!node) return false; - if (node->hasConstantNumber()) { - recovery = ValueRecovery::constant( - codeBlock->constantRegister( - FirstConstantRegisterIndex + node->constantNumber()).get()); + if (node->hasConstant()) { + recovery = ValueRecovery::constant(node->constant()); return true; } - if (node->hasWeakConstant()) { - recovery = ValueRecovery::constant(node->weakConstant()); + if (node->op() == PhantomDirectArguments) { + recovery = ValueRecovery::directArgumentsThatWereNotCreated(node->id()); return true; } - if (node->op() == PhantomArguments) { - recovery = ValueRecovery::argumentsThatWereNotCreated(); + if (node->op() == PhantomClonedArguments) { + recovery = ValueRecovery::outOfBandArgumentsThatWereNotCreated(node->id()); return true; } @@ -148,7 +155,8 @@ void VariableEventStream::reconstruct( // nothing to do. break; case BirthToFill: - case BirthToSpill: { + case BirthToSpill: + case Birth: { MinifiedGenerationInfo info; info.update(event); generationInfos.add(event.id(), info); @@ -187,14 +195,14 @@ void VariableEventStream::reconstruct( ASSERT(source.kind() == HaveNode); MinifiedNode* node = graph.at(source.id()); - if (tryToSetConstantRecovery(valueRecoveries[i], codeBlock, node)) - continue; - MinifiedGenerationInfo info = generationInfos.get(source.id()); - if (info.format == DataFormatNone) { + if (!info.alive) { valueRecoveries[i] = ValueRecovery::constant(jsUndefined()); continue; } + + if (tryToSetConstantRecovery(valueRecoveries[i], node)) + continue; ASSERT(info.format != DataFormatNone); diff --git a/dfg/DFGVariableEventStream.h b/dfg/DFGVariableEventStream.h index 2bcf549..b0e4afa 100644 --- a/dfg/DFGVariableEventStream.h +++ b/dfg/DFGVariableEventStream.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,7 @@ #include "DFGMinifiedGraph.h" #include "DFGVariableEvent.h" #include "Operands.h" +#include "ValueRecovery.h" #include <wtf/Vector.h> namespace JSC { namespace DFG { @@ -48,7 +49,7 @@ public: unsigned index, Operands<ValueRecovery>&) const; private: - bool tryToSetConstantRecovery(ValueRecovery&, CodeBlock*, MinifiedNode*) const; + bool tryToSetConstantRecovery(ValueRecovery&, MinifiedNode*) const; void logEvent(const VariableEvent&); }; diff --git a/dfg/DFGVirtualRegisterAllocationPhase.cpp b/dfg/DFGVirtualRegisterAllocationPhase.cpp index 29310d3..e5e133d 100644 --- a/dfg/DFGVirtualRegisterAllocationPhase.cpp +++ b/dfg/DFGVirtualRegisterAllocationPhase.cpp @@ -45,6 +45,8 @@ public: bool run() { + DFG_ASSERT(m_graph, nullptr, m_graph.m_form == ThreadedCPS); + ScoreBoard scoreBoard(m_graph.m_nextMachineLocal); scoreBoard.assertClear(); for (size_t blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { @@ -53,6 +55,10 @@ public: continue; if (!block->isReachable) continue; + if (!ASSERT_DISABLED) { + // Force usage of highest-numbered virtual registers. + scoreBoard.sortFree(); + } for (size_t indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) { Node* node = block->at(indexInBlock); diff --git a/dfg/DFGWatchpointCollectionPhase.cpp b/dfg/DFGWatchpointCollectionPhase.cpp index 43e1b2d..f924e4a 100644 --- a/dfg/DFGWatchpointCollectionPhase.cpp +++ b/dfg/DFGWatchpointCollectionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,14 @@ #include "DFGPhase.h" #include "JSCInlines.h" +// FIXME: Remove this phase entirely by moving the addLazily() calls into either the backend or +// into the phase that performs the optimization. Moving the calls into the backend makes the most +// sense when the intermediate phases don't need to know that the watchpoint was set. Moving the +// calls earlier usually only makes sense if the node's only purpose was to convey the need for +// the watchpoint (like VarInjectionWatchpoint). But, it can also make sense if the fact that the +// watchpoint was set enables other optimizations. +// https://bugs.webkit.org/show_bug.cgi?id=144669 + namespace JSC { namespace DFG { class WatchpointCollectionPhase : public Phase { @@ -64,8 +72,6 @@ public: private: void handle() { - DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, handleEdge); - switch (m_node->op()) { case CompareEqConstant: case IsUndefined: @@ -81,31 +87,14 @@ private: case LogicalNot: case Branch: - if (m_node->child1().useKind() == ObjectOrOtherUse) + switch (m_node->child1().useKind()) { + case ObjectOrOtherUse: + case UntypedUse: handleMasqueradesAsUndefined(); - break; - - case GetByVal: - if (m_node->arrayMode().type() == Array::Double - && m_node->arrayMode().isSaneChain()) { - addLazily(globalObject()->arrayPrototype()->structure()->transitionWatchpointSet()); - addLazily(globalObject()->objectPrototype()->structure()->transitionWatchpointSet()); + break; + default: + break; } - - if (m_node->arrayMode().type() == Array::String) - handleStringGetByVal(); - - if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) - addLazily(view); - break; - - case PutByVal: - if (JSArrayBufferView* view = m_graph.tryGetFoldableViewForChild1(m_node)) - addLazily(view); - break; - - case StringCharAt: - handleStringGetByVal(); break; case NewArray: @@ -115,53 +104,10 @@ private: addLazily(globalObject()->havingABadTimeWatchpoint()); break; - case AllocationProfileWatchpoint: - addLazily(jsCast<JSFunction*>(m_node->function())->allocationProfileWatchpointSet()); - break; - - case StructureTransitionWatchpoint: - m_graph.watchpoints().addLazily( - m_node->origin.semantic, - m_node->child1()->op() == WeakJSConstant ? BadWeakConstantCacheWatchpoint : BadCacheWatchpoint, - m_node->structure()->transitionWatchpointSet()); - break; - - case VariableWatchpoint: - addLazily(m_node->variableWatchpointSet()); - break; - case VarInjectionWatchpoint: addLazily(globalObject()->varInjectionWatchpoint()); break; - case FunctionReentryWatchpoint: - addLazily(m_node->symbolTable()->m_functionEnteredOnce); - break; - - case TypedArrayWatchpoint: - addLazily(m_node->typedArray()); - break; - - default: - break; - } - } - - void handleEdge(Node*, Edge edge) - { - switch (edge.useKind()) { - case StringObjectUse: - case StringOrStringObjectUse: { - Structure* stringObjectStructure = globalObject()->stringObjectStructure(); - Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure(); - ASSERT(m_graph.watchpoints().isValidOrMixed(stringPrototypeStructure->transitionWatchpointSet())); - - m_graph.watchpoints().addLazily( - m_node->origin.semantic, NotStringObject, - stringPrototypeStructure->transitionWatchpointSet()); - break; - } - default: break; } @@ -173,16 +119,6 @@ private: addLazily(globalObject()->masqueradesAsUndefinedWatchpoint()); } - void handleStringGetByVal() - { - if (!m_node->arrayMode().isOutOfBounds()) - return; - if (!globalObject()->stringPrototypeChainIsSane()) - return; - addLazily(globalObject()->stringPrototype()->structure()->transitionWatchpointSet()); - addLazily(globalObject()->objectPrototype()->structure()->transitionWatchpointSet()); - } - void addLazily(WatchpointSet* set) { m_graph.watchpoints().addLazily(set); @@ -191,10 +127,6 @@ private: { m_graph.watchpoints().addLazily(set); } - void addLazily(JSArrayBufferView* view) - { - m_graph.watchpoints().addLazily(view); - } JSGlobalObject* globalObject() { diff --git a/dfg/DFGWorklist.cpp b/dfg/DFGWorklist.cpp index 4aa1428..4a8f572 100644 --- a/dfg/DFGWorklist.cpp +++ b/dfg/DFGWorklist.cpp @@ -68,9 +68,9 @@ void Worklist::finishCreation(unsigned numberOfThreads, int relativePriority) } } -PassRefPtr<Worklist> Worklist::create(CString worklistName, unsigned numberOfThreads, int relativePriority) +Ref<Worklist> Worklist::create(CString worklistName, unsigned numberOfThreads, int relativePriority) { - RefPtr<Worklist> result = adoptRef(new Worklist(worklistName)); + Ref<Worklist> result = adoptRef(*new Worklist(worklistName)); result->finishCreation(numberOfThreads, relativePriority); return result; } @@ -406,7 +406,7 @@ Worklist* ensureGlobalDFGWorklist() { static std::once_flag initializeGlobalWorklistOnceFlag; std::call_once(initializeGlobalWorklistOnceFlag, [] { - theGlobalDFGWorklist = Worklist::create("DFG Worklist", Options::numberOfDFGCompilerThreads(), Options::priorityDeltaOfDFGCompilerThreads()).leakRef(); + theGlobalDFGWorklist = &Worklist::create("DFG Worklist", Options::numberOfDFGCompilerThreads(), Options::priorityDeltaOfDFGCompilerThreads()).leakRef(); }); return theGlobalDFGWorklist; } @@ -422,7 +422,7 @@ Worklist* ensureGlobalFTLWorklist() { static std::once_flag initializeGlobalWorklistOnceFlag; std::call_once(initializeGlobalWorklistOnceFlag, [] { - theGlobalFTLWorklist = Worklist::create("FTL Worklist", Options::numberOfFTLCompilerThreads(), Options::priorityDeltaOfFTLCompilerThreads()).leakRef(); + theGlobalFTLWorklist = &Worklist::create("FTL Worklist", Options::numberOfFTLCompilerThreads(), Options::priorityDeltaOfFTLCompilerThreads()).leakRef(); }); return theGlobalFTLWorklist; } diff --git a/dfg/DFGWorklist.h b/dfg/DFGWorklist.h index 3d0b5d6..bd6e6fa 100644 --- a/dfg/DFGWorklist.h +++ b/dfg/DFGWorklist.h @@ -33,7 +33,6 @@ #include <wtf/Deque.h> #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> -#include <wtf/PassOwnPtr.h> #include <wtf/ThreadingPrimitives.h> namespace JSC { @@ -49,7 +48,7 @@ public: ~Worklist(); - static PassRefPtr<Worklist> create(CString worklistName, unsigned numberOfThreads, int relativePriority = 0); + static Ref<Worklist> create(CString worklistName, unsigned numberOfThreads, int relativePriority = 0); void enqueue(PassRefPtr<Plan>); diff --git a/disassembler/ARM64/A64DOpcode.cpp b/disassembler/ARM64/A64DOpcode.cpp index 415dbdb..52a92c6 100644 --- a/disassembler/ARM64/A64DOpcode.cpp +++ b/disassembler/ARM64/A64DOpcode.cpp @@ -23,7 +23,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define __STDC_FORMAT_MACROS #include "config.h" + +#if USE(ARM64_DISASSEMBLER) + #include "A64DOpcode.h" #include <stdarg.h> @@ -1194,3 +1198,5 @@ const char* A64DOpcodeUnconditionalBranchRegister::format() } } } // namespace JSC::ARM64Disassembler + +#endif // USE(ARM64_DISASSEMBLER) diff --git a/disassembler/ARM64/A64DOpcode.h b/disassembler/ARM64/A64DOpcode.h index 1c6ac43..5bb7db9 100644 --- a/disassembler/ARM64/A64DOpcode.h +++ b/disassembler/ARM64/A64DOpcode.h @@ -172,12 +172,12 @@ protected: void appendUnsignedImmediate64(uint64_t immediate) { - bufferPrintf("#0x%llx", immediate); + bufferPrintf("#0x%" PRIx64, immediate); } void appendPCRelativeOffset(uint32_t* pc, int32_t immediate) { - bufferPrintf("0x%llx", reinterpret_cast<uint64_t>(pc + immediate)); + bufferPrintf("0x%" PRIx64, reinterpret_cast<uint64_t>(pc + immediate)); } void appendShiftAmount(unsigned amount) diff --git a/disassembler/ARM64Disassembler.cpp b/disassembler/ARM64Disassembler.cpp index 7b86bf0..900b87e 100644 --- a/disassembler/ARM64Disassembler.cpp +++ b/disassembler/ARM64Disassembler.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define __STDC_FORMAT_MACROS #include "config.h" #include "Disassembler.h" diff --git a/disassembler/ARMv7/ARMv7DOpcode.cpp b/disassembler/ARMv7/ARMv7DOpcode.cpp index c11acf8..3175ccc 100644 --- a/disassembler/ARMv7/ARMv7DOpcode.cpp +++ b/disassembler/ARMv7/ARMv7DOpcode.cpp @@ -113,11 +113,16 @@ static Opcode16GroupInitializer opcode16BitGroupList[] = { }; static Opcode32GroupInitializer opcode32BitGroupList[] = { + OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeDataPopMultiple), + OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeDataPushMultiple), OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeDataProcessingShiftedReg), + OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVLDR), OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVSinglePrecision), OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVDoublePrecision), OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer), OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR), + OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCMP), + OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCVTBetweenFPAndInt), OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate), OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3), OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink), @@ -133,6 +138,8 @@ static Opcode32GroupInitializer opcode32BitGroupList[] = { OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeBranchOrBranchLink), OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadRegister), OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushPopSingle), // Should be before StoreSingle* + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPopMultiple), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushMultiple), OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleRegister), OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate12), OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate8), @@ -143,6 +150,9 @@ static Opcode32GroupInitializer opcode32BitGroupList[] = { OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegExtend), OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegParallel), OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegMisc), + OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeVLDR), + OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeVCMP), + OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeVCVTBetweenFPAndInt), }; bool ARMv7DOpcode::s_initialized = false; @@ -1444,6 +1454,46 @@ const char* ARMv7DOpcodeDataPushPopSingle::format() return m_formatBuffer; } +void ARMv7DOpcodeDataPushPopMultiple::appendRegisterList() +{ + unsigned registers = registerList(); + + appendCharacter('{'); + bool needSeparator = false; + + for (unsigned i = 0; i < 16; i++) { + if (registers & (1 << i)) { + if (needSeparator) + appendSeparator(); + appendRegisterName(i); + needSeparator = true; + } + } + appendCharacter('}'); +} + +const char* ARMv7DOpcodeDataPopMultiple::format() +{ + if (condition() != 0xe) + bufferPrintf(" pop%-4.4s", conditionName(condition())); + else + appendInstructionName("pop"); + appendRegisterList(); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeDataPushMultiple::format() +{ + if (condition() != 0xe) + bufferPrintf(" push%-3.3s", conditionName(condition())); + else + appendInstructionName("push"); + appendRegisterList(); + + return m_formatBuffer; +} + const char* ARMv7DOpcodeStoreSingleImmediate12::format() { appendInstructionName(opName()); @@ -1513,6 +1563,104 @@ const char* ARMv7DOpcodeStoreSingleRegister::format() return m_formatBuffer; } +const char* ARMv7DOpcodeVCMP::format() +{ + bufferPrintf(" vcmp"); + + if (eBit()) + appendCharacter('e'); // Raise exception on qNaN + + if (condition() != 0xe) + appendString(conditionName(condition())); + + appendCharacter('.'); + appendString(szBit() ? "f64" : "f32"); + appendCharacter(' '); + if (szBit()) { + appendFPRegisterName('d', (dBit() << 4) | vd()); + appendSeparator(); + appendFPRegisterName('d', (mBit() << 4) | vm()); + } else { + appendFPRegisterName('s', (vd() << 1) | dBit()); + appendSeparator(); + appendFPRegisterName('s', (vm() << 1) | mBit()); + } + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeVCVTBetweenFPAndInt::format() +{ + bufferPrintf(" vcvt"); + bool convertToInteger = op2() & 0x4; + + if (convertToInteger) { + if (!op()) + appendCharacter('r'); // Round using mode in FPSCR + if (condition() != 0xe) + appendString(conditionName(condition())); + appendCharacter('.'); + appendCharacter((op2() & 1) ? 's' : 'u'); + appendString("32.f"); + appendString(szBit() ? "64" : "32"); + appendCharacter(' '); + appendFPRegisterName('s', (vd() << 1) | dBit()); + appendSeparator(); + if (szBit()) + appendFPRegisterName('d', (mBit() << 4) | vm()); + else + appendFPRegisterName('s', (vm() << 1) | mBit()); + } else { + if (condition() != 0xe) + appendString(conditionName(condition())); + appendCharacter('.'); + appendString(szBit() ? "f64." : "f32."); + appendString(op() ? "s32" : "u32"); + appendCharacter(' '); + if (szBit()) + appendFPRegisterName('d', (dBit() << 4) | vd()); + else + appendFPRegisterName('s', (vd() << 1) | dBit()); + appendSeparator(); + appendFPRegisterName('s', (vm() << 1) | mBit()); + } + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeVLDR::format() +{ + if (condition() != 0xe) + bufferPrintf(" vldr%-3.3s", conditionName(condition())); + else + appendInstructionName("vldr"); + + appendFPRegisterName(doubleReg() ? 'd' : 's', vd()); + appendSeparator(); + + int immediate = immediate8() * 4; + + if (!uBit()) + immediate = -immediate; + + appendCharacter('['); + + if (rn() == RegPC) + appendPCRelativeOffset(immediate); + else { + appendRegisterName(rn()); + + if (immediate) { + appendSeparator(); + appendSignedImmediate(immediate); + } + } + + appendCharacter(']'); + + return m_formatBuffer; +} + const char* ARMv7DOpcodeVMOVDoublePrecision::format() { appendInstructionName("vmov"); diff --git a/disassembler/ARMv7/ARMv7DOpcode.h b/disassembler/ARMv7/ARMv7DOpcode.h index 4273c31..13e209d 100644 --- a/disassembler/ARMv7/ARMv7DOpcode.h +++ b/disassembler/ARMv7/ARMv7DOpcode.h @@ -1019,6 +1019,36 @@ protected: unsigned op() { return (m_opcode >> 20) & 0x1; } }; +class ARMv7DOpcodeDataPushPopMultiple : public ARMv7D32BitOpcode { +protected: + void appendRegisterList(); + + unsigned registerList() { return m_opcode & 0xffff; } + unsigned condition() { return m_opcode >> 28; } +}; + +class ARMv7DOpcodeDataPopMultiple : public ARMv7DOpcodeDataPushPopMultiple { +public: + static const uint32_t s_mask = 0x0fff0000; + static const uint32_t s_pattern = 0x08bd0000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataPopMultiple, thisObj); + +protected: + const char* format(); +}; + +class ARMv7DOpcodeDataPushMultiple : public ARMv7DOpcodeDataPushPopMultiple { +public: + static const uint32_t s_mask = 0xfe7f0000; + static const uint32_t s_pattern = 0xe82d0000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataPushMultiple, thisObj); + +protected: + const char* format(); +}; + class ARMv7DOpcodeDataStoreSingle : public ARMv7D32BitOpcode { protected: static const char* const s_opNames[4]; @@ -1094,6 +1124,63 @@ protected: unsigned immediate16() { return ((m_opcode >> 4) & 0xf000) | ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); } }; +class ARMv7DOpcodeVCMP : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0x0fbf0e50; + static const uint32_t s_pattern = 0x0eb40a40; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVCMP, thisObj); + +protected: + const char* format(); + + unsigned condition() { return m_opcode >> 28; } + unsigned dBit() { return (m_opcode >> 22) & 0x1; } + unsigned vd() { return (m_opcode >> 12) & 0xf; } + unsigned szBit() { return (m_opcode >> 8) & 0x1; } + unsigned eBit() { return (m_opcode >> 7) & 0x1; } + unsigned mBit() { return (m_opcode >> 5) & 0x1; } + unsigned vm() { return m_opcode & 0xf; } +}; + +class ARMv7DOpcodeVCVTBetweenFPAndInt : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0x0fb80e50; + static const uint32_t s_pattern = 0x0eb80a40; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVCVTBetweenFPAndInt, thisObj); + +protected: + const char* format(); + + unsigned condition() { return m_opcode >> 28; } + unsigned dBit() { return (m_opcode >> 22) & 0x1; } + unsigned op2() { return (m_opcode >> 16) & 0x7; } + unsigned vd() { return (m_opcode >> 12) & 0xf; } + unsigned szBit() { return (m_opcode >> 8) & 0x1; } + unsigned op() { return (m_opcode >> 7) & 0x1; } + unsigned mBit() { return (m_opcode >> 5) & 0x1; } + unsigned vm() { return m_opcode & 0xf; } +}; + +class ARMv7DOpcodeVLDR : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0x0f300e00; + static const uint32_t s_pattern = 0x0d100a00; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVLDR, thisObj); + +protected: + const char* format(); + + unsigned condition() { return m_opcode >> 28; } + unsigned uBit() { return (m_opcode >> 23) & 0x1; } + unsigned rn() { return (m_opcode >> 16) & 0xf; } + unsigned vd() { return ((m_opcode >> 18) & 0x10) | ((m_opcode >> 12) & 0xf); } + bool doubleReg() { return !!(m_opcode & 0x100); } + unsigned immediate8() { return m_opcode & 0xff; } +}; + class ARMv7DOpcodeVMOVDoublePrecision : public ARMv7D32BitOpcode { public: static const uint32_t s_mask = 0xffe00fd0; diff --git a/disassembler/Disassembler.cpp b/disassembler/Disassembler.cpp index 8bf3d15..8f35742 100644 --- a/disassembler/Disassembler.cpp +++ b/disassembler/Disassembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,11 @@ #include "MacroAssemblerCodeRef.h" #include <wtf/DataLog.h> +#include <wtf/Deque.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/StringPrintStream.h> +#include <wtf/Threading.h> +#include <wtf/ThreadingPrimitives.h> namespace JSC { @@ -39,5 +44,112 @@ void disassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* out.printf("%sdisassembly not available for range %p...%p\n", prefix, codePtr.executableAddress(), static_cast<char*>(codePtr.executableAddress()) + size); } +namespace { + +// This is really a struct, except that it should be a class because that's what the WTF_* macros +// expect. +class DisassemblyTask { + WTF_MAKE_NONCOPYABLE(DisassemblyTask); + WTF_MAKE_FAST_ALLOCATED; +public: + DisassemblyTask() + { + } + + ~DisassemblyTask() + { + if (header) + free(header); // free() because it would have been copied by strdup. + } + + char* header { nullptr }; + MacroAssemblerCodeRef codeRef; + size_t size { 0 }; + const char* prefix { nullptr }; + InstructionSubsetHint subsetHint { MacroAssemblerSubset }; +}; + +class AsynchronousDisassembler { +public: + AsynchronousDisassembler() + { + createThread("Asynchronous Disassembler", [&] () { run(); }); + } + + void enqueue(std::unique_ptr<DisassemblyTask> task) + { + MutexLocker locker(m_lock); + m_queue.append(WTF::move(task)); + m_condition.broadcast(); + } + + void waitUntilEmpty() + { + MutexLocker locker(m_lock); + while (!m_queue.isEmpty() || m_working) + m_condition.wait(m_lock); + } + +private: + NO_RETURN void run() + { + for (;;) { + std::unique_ptr<DisassemblyTask> task; + { + MutexLocker locker(m_lock); + m_working = false; + m_condition.broadcast(); + while (m_queue.isEmpty()) + m_condition.wait(m_lock); + task = m_queue.takeFirst(); + m_working = true; + } + + dataLog(task->header); + disassemble( + task->codeRef.code(), task->size, task->prefix, WTF::dataFile(), + task->subsetHint); + } + } + + Mutex m_lock; + ThreadCondition m_condition; + Deque<std::unique_ptr<DisassemblyTask>> m_queue; + bool m_working { false }; +}; + +bool hadAnyAsynchronousDisassembly = false; + +AsynchronousDisassembler& asynchronousDisassembler() +{ + static NeverDestroyed<AsynchronousDisassembler> disassembler; + hadAnyAsynchronousDisassembly = true; + return disassembler.get(); +} + +} // anonymous namespace + +void disassembleAsynchronously( + const CString& header, const MacroAssemblerCodeRef& codeRef, size_t size, const char* prefix, + InstructionSubsetHint subsetHint) +{ + std::unique_ptr<DisassemblyTask> task = std::make_unique<DisassemblyTask>(); + task->header = strdup(header.data()); // Yuck! We need this because CString does racy refcounting. + task->codeRef = codeRef; + task->size = size; + task->prefix = prefix; + task->subsetHint = subsetHint; + + asynchronousDisassembler().enqueue(WTF::move(task)); +} + +void waitForAsynchronousDisassembly() +{ + if (!hadAnyAsynchronousDisassembly) + return; + + asynchronousDisassembler().waitUntilEmpty(); +} + } // namespace JSC diff --git a/disassembler/Disassembler.h b/disassembler/Disassembler.h index d086c83..6eaf7b6 100644 --- a/disassembler/Disassembler.h +++ b/disassembler/Disassembler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,11 +26,14 @@ #ifndef Disassembler_h #define Disassembler_h +#include <functional> #include <wtf/PrintStream.h> +#include <wtf/text/CString.h> namespace JSC { class MacroAssemblerCodePtr; +class MacroAssemblerCodeRef; enum InstructionSubsetHint { MacroAssemblerSubset, LLVMSubset }; @@ -47,6 +50,14 @@ inline bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char*, // the range of machine code addresses. void disassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, PrintStream& out, InstructionSubsetHint = MacroAssemblerSubset); +// Asynchronous disassembly. This happens on another thread, and calls the provided +// callback when the disassembly is done. +void disassembleAsynchronously( + const CString& header, const MacroAssemblerCodeRef&, size_t, const char* prefix, + InstructionSubsetHint = MacroAssemblerSubset); + +JS_EXPORT_PRIVATE void waitForAsynchronousDisassembly(); + } // namespace JSC #endif // Disassembler_h diff --git a/features.json b/features.json new file mode 100644 index 0000000..e44b767 --- /dev/null +++ b/features.json @@ -0,0 +1,211 @@ +{ + "specification": [ + { + "name": "ES6", + "url": "http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts", + "keywords": ["es6", "es2015", "ecmascript"] + }, + { + "name": "ES7", + "url": "https://github.com/tc39/ecma262", + "keywords": ["es7", "ecmascript"] + } + ], + + "features": [ + { + "name": "ASM.js", + "status": { + "status": "Continuously improving", + "enabled-by-default": true + }, + "url": "http://asmjs.org", + "description": "ASM.js defines a subset of JavaScript that enforce stronger typing and has specific patterns of memory access. ASM.js is rarely hand-written, it is typically generated from other languages by compiler such as Emscripten.", + "comment": "There is no \"use asm\" mode in JavaScriptCore. Instead WebKit integrates ASM.js optimizations directly in the optimizer. As a result, it is possible to mix ASM-style typing with regular code and still get great performance and power efficiency." + }, + { + "name": "Array.prototype.copyWithin", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.copywithin", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=145107", + "specification": "ES6", + "contact": { + "name": "Yusuke Suzuki", + "email": "utatane.tea@gmail.com" + } + }, + { + "name": "Array.prototype.includes", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "https://github.com/tc39/Array.prototype.includes", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=142707", + "specification": "ES7" + }, + { + "name": "Classes", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "https://people.mozilla.org/~jorendorff/es6-draft.html#sec-class-definitions", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=142774", + "specification": "ES6", + "description": "The new class syntax of ES6 provides a new syntax to define and extend JavaScript objects. The class syntax is a new notation, objects still use prototypal inheritance." + }, + { + "name": "Map data structure", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-constructor", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=120333", + "description": "Map provides an <a href=\"https://en.wikipedia.org/wiki/Associative_array\">associative array data</a> structure that maps keys to values.", + "specification": "ES6" + }, + { + "name": "Number extensions (ES6)", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-number-objects", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=131707", + "specification": "ES6", + "description": "ES6 extend Number with the methods Number.isFinite(), Number.isInteger(), Number.isSafeInteger(), Number.isNaN() and the attributes Number.EPSILON, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER." + }, + { + "name": "Octal and binary literals", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "https://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-numeric-literals", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=142681", + "specification": "ES6", + "description": "New syntax for number literals. Numbers can be provided as binary (e.g. 0b001001) or octal (e.g. 0o24)." + }, + { + "name": "Promise Objects", + "status": { + "status": "Done", + "enabled-by-default": true, + "shipped": ["ios8-safari", "osx-safari-7.1"] + }, + "url": "https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=120260", + "specification": "ES6" + }, + { + "name": "Set data structure", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "https://people.mozilla.org/~jorendorff/es6-draft.html#sec-set-constructor", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=120549", + "description": "Set is a collection of unique objects.", + "specification": "ES6" + }, + { + "name": "Symbol Objects", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "https://people.mozilla.org/~jorendorff/es6-draft.html#sec-symbol-objects", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=140435", + "specification": "ES6", + "contact": { + "name": "Yusuke Suzuki", + "email": "utatane.tea@gmail.com" + } + }, + { + "name": "Tagged templates", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tagged-templates", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=143183", + "description": "The tagged-templates (like String.raw`Hello ${World}`) provides a way to modify the produced string from a given template-literals with a function.", + "specification": "ES6", + "contact": { + "name": "Yusuke Suzuki", + "email": "utatane.tea@gmail.com" + } + }, + { + "name": "Template literals", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literals", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=142691", + "description": "The template-literals (like `Hello ${World}`) provides string interpolation feature. Line terminators are also allowed in the template-literals.", + "specification": "ES6", + "contact": { + "name": "Yusuke Suzuki", + "email": "utatane.tea@gmail.com" + } + }, + { + "name": "WeakMap", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-weakmap-objects", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=120912", + "description": "WeakMap provides an <a href=\"https://en.wikipedia.org/wiki/Associative_array\">associative array data</a> structure that maps keys to values. WeakMap's keys must be objects.", + "specification": "ES6" + }, + { + "name": "WeakSet", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-weakset-objects", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet", + "webkit-url": "https://bugs.webkit.org/show_bug.cgi?id=142408", + "description": "WeakSet is a collection of unique objects. Keys stored in WeakSet are referenced weakly.", + "specification": "ES6", + "contact": { + "name": "Yusuke Suzuki", + "email": "utatane.tea@gmail.com" + } + }, + { + "name": "for...of loops", + "status": { + "status": "Done", + "enabled-by-default": true + }, + "url": "http://people.mozilla.org/~jorendorff/es6-draft.html#sec-for-in-and-for-of-statements", + "documentation-url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of", + "description": "The for...of loops iterate over the values provided by the iterator of the target object.", + "specification": "ES6", + "comment": "Older versions of WebKit only supported iterating JavaScript arrays." + } + ] +} diff --git a/ftl/FTLAbbreviatedTypes.h b/ftl/FTLAbbreviatedTypes.h index e824f87..2b93619 100644 --- a/ftl/FTLAbbreviatedTypes.h +++ b/ftl/FTLAbbreviatedTypes.h @@ -43,6 +43,7 @@ typedef LLVMModuleRef LModule; typedef LLVMRealPredicate LRealPredicate; typedef LLVMTypeRef LType; typedef LLVMValueRef LValue; +typedef LLVMMemoryBufferRef LMemoryBuffer; } } // namespace JSC::FTL diff --git a/ftl/FTLAbbreviations.h b/ftl/FTLAbbreviations.h index 78a7bf5..d3bff4c 100644 --- a/ftl/FTLAbbreviations.h +++ b/ftl/FTLAbbreviations.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -77,6 +77,9 @@ static inline LType structType(LContext context, LType element1, LType element2, return structType(context, elements, 2, packing); } +// FIXME: Make the Variadicity argument not be the last argument to functionType() so that this function +// can use C++11 variadic templates +// https://bugs.webkit.org/show_bug.cgi?id=141575 enum Variadicity { NotVariadic, Variadic }; static inline LType functionType(LType returnType, const LType* paramTypes, unsigned paramCount, Variadicity variadicity) { @@ -110,9 +113,21 @@ static inline LType functionType(LType returnType, LType param1, LType param2, L LType paramTypes[] = { param1, param2, param3, param4 }; return functionType(returnType, paramTypes, 4, variadicity); } +static inline LType functionType(LType returnType, LType param1, LType param2, LType param3, LType param4, LType param5, Variadicity variadicity = NotVariadic) +{ + LType paramTypes[] = { param1, param2, param3, param4, param5 }; + return functionType(returnType, paramTypes, 5, variadicity); +} +static inline LType functionType(LType returnType, LType param1, LType param2, LType param3, LType param4, LType param5, LType param6, Variadicity variadicity = NotVariadic) +{ + LType paramTypes[] = { param1, param2, param3, param4, param5, param6 }; + return functionType(returnType, paramTypes, 6, variadicity); +} static inline LType typeOf(LValue value) { return llvm->TypeOf(value); } +static inline LType getElementType(LType value) { return llvm->GetElementType(value); } + static inline unsigned mdKindID(LContext context, const char* string) { return llvm->GetMDKindIDInContext(context, string, std::strlen(string)); } static inline LValue mdString(LContext context, const char* string, unsigned length) { return llvm->MDStringInContext(context, string, length); } static inline LValue mdString(LContext context, const char* string) { return mdString(context, string, std::strlen(string)); } @@ -134,10 +149,31 @@ static inline LValue mdNode(LContext context, LValue arg1, LValue arg2, LValue a static inline void setMetadata(LValue instruction, unsigned kind, LValue metadata) { llvm->SetMetadata(instruction, kind, metadata); } +static inline LValue getFirstInstruction(LBasicBlock block) { return llvm->GetFirstInstruction(block); } +static inline LValue getNextInstruction(LValue instruction) { return llvm->GetNextInstruction(instruction); } + + static inline LValue addFunction(LModule module, const char* name, LType type) { return llvm->AddFunction(module, name, type); } -static inline void setLinkage(LValue global, LLinkage linkage) { llvm->SetLinkage(global, linkage); } +static inline LValue getNamedFunction(LModule module, const char* name) { return llvm->GetNamedFunction(module, name); } +static inline LValue getFirstFunction(LModule module) { return llvm->GetFirstFunction(module); } +static inline LValue getNextFunction(LValue function) { return llvm->GetNextFunction(function); } + static inline void setFunctionCallingConv(LValue function, LCallConv convention) { llvm->SetFunctionCallConv(function, convention); } static inline void addTargetDependentFunctionAttr(LValue function, const char* key, const char* value) { llvm->AddTargetDependentFunctionAttr(function, key, value); } +static inline void removeFunctionAttr(LValue function, LLVMAttribute pa) { llvm->RemoveFunctionAttr(function, pa); } + +static inline LLVMLinkage getLinkage(LValue global) { return llvm->GetLinkage(global); } +static inline void setLinkage(LValue global, LLVMLinkage linkage) { llvm->SetLinkage(global, linkage); } +static inline void setVisibility(LValue global, LLVMVisibility viz) { llvm->SetVisibility(global, viz); } +static inline LLVMBool isDeclaration(LValue global) { return llvm->IsDeclaration(global); } + +static inline LLVMBool linkModules(LModule dest, LModule str, LLVMLinkerMode mode, char** outMessage) { return llvm->LinkModules(dest, str, mode, outMessage); } + +static inline const char * getValueName(LValue global) { return llvm->GetValueName(global); } + +static inline LValue getNamedGlobal(LModule module, const char* name) { return llvm->GetNamedGlobal(module, name); } +static inline LValue getFirstGlobal(LModule module) { return llvm->GetFirstGlobal(module); } +static inline LValue getNextGlobal(LValue global) { return llvm->GetNextGlobal(global); } static inline LValue addExternFunction(LModule module, const char* name, LType type) { @@ -146,7 +182,29 @@ static inline LValue addExternFunction(LModule module, const char* name, LType t return result; } +static inline LLVMBool createMemoryBufferWithContentsOfFile(const char* path, LLVMMemoryBufferRef* outMemBuf, char** outMessage) +{ + return llvm->CreateMemoryBufferWithContentsOfFile(path, outMemBuf, outMessage); +} + + +static inline LLVMBool parseBitcodeInContext(LLVMContextRef contextRef, LLVMMemoryBufferRef memBuf, LModule *outModule, char **outMessage) +{ + return llvm->ParseBitcodeInContext(contextRef, memBuf, outModule, outMessage); +} + + +static inline void disposeMemoryBuffer(LLVMMemoryBufferRef memBuf){ llvm->DisposeMemoryBuffer(memBuf); } + + +static inline LModule moduleCreateWithNameInContext(const char* moduleID, LContext context){ return llvm->ModuleCreateWithNameInContext(moduleID, context); } +static inline void disposeModule(LModule m){ llvm->DisposeModule(m); } + +static inline void disposeMessage(char* outMsg) { llvm->DisposeMessage(outMsg); } + static inline LValue getParam(LValue function, unsigned index) { return llvm->GetParam(function, index); } + +static inline void getParamTypes(LType function, LType* dest) { return llvm->GetParamTypes(function, dest); } static inline LValue getUndef(LType type) { return llvm->GetUndef(type); } enum BitExtension { ZeroExtend, SignExtend }; @@ -156,6 +214,9 @@ static inline LValue constIntToPtr(LValue value, LType type) { return llvm->Cons static inline LValue constNull(LType type) { return llvm->ConstNull(type); } static inline LValue constBitCast(LValue value, LType type) { return llvm->ConstBitCast(value, type); } +static inline LBasicBlock getFirstBasicBlock(LValue function) { return llvm->GetFirstBasicBlock(function); } +static inline LBasicBlock getNextBasicBlock(LBasicBlock block) { return llvm->GetNextBasicBlock(block); } + static inline LBasicBlock appendBasicBlock(LContext context, LValue function, const char* name = "") { return llvm->AppendBasicBlockInContext(context, function, name); } static inline LBasicBlock insertBasicBlock(LContext context, LBasicBlock beforeBasicBlock, const char* name = "") { return llvm->InsertBasicBlockInContext(context, beforeBasicBlock, name); } @@ -250,41 +311,13 @@ static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1) { return buildCall(builder, function, &arg1, 1); } -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2) -{ - LValue args[] = { arg1, arg2 }; - return buildCall(builder, function, args, 2); -} -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2, LValue arg3) -{ - LValue args[] = { arg1, arg2, arg3 }; - return buildCall(builder, function, args, 3); -} -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4) +template<typename... Args> +LValue buildCall(LBuilder builder, LValue function, LValue arg1, Args... args) { - LValue args[] = { arg1, arg2, arg3, arg4 }; - return buildCall(builder, function, args, 4); -} -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5) -{ - LValue args[] = { arg1, arg2, arg3, arg4, arg5 }; - return buildCall(builder, function, args, 5); -} -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6) -{ - LValue args[] = { arg1, arg2, arg3, arg4, arg5, arg6 }; - return buildCall(builder, function, args, 6); -} -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6, LValue arg7) -{ - LValue args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }; - return buildCall(builder, function, args, 7); -} -static inline LValue buildCall(LBuilder builder, LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6, LValue arg7, LValue arg8) -{ - LValue args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }; - return buildCall(builder, function, args, 8); + LValue argsArray[] = { arg1, args... }; + return buildCall(builder, function, argsArray, sizeof(argsArray) / sizeof(LValue)); } + static inline void setInstructionCallingConvention(LValue instruction, LCallConv callingConvention) { llvm->SetInstructionCallConv(instruction, callingConvention); } static inline LValue buildExtractValue(LBuilder builder, LValue aggVal, unsigned index) { return llvm->BuildExtractValue(builder, aggVal, index, ""); } static inline LValue buildSelect(LBuilder builder, LValue condition, LValue taken, LValue notTaken) { return llvm->BuildSelect(builder, condition, taken, notTaken, ""); } diff --git a/ftl/FTLAbstractHeap.cpp b/ftl/FTLAbstractHeap.cpp index dfbbeb1..ce9fa0f 100644 --- a/ftl/FTLAbstractHeap.cpp +++ b/ftl/FTLAbstractHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,6 +53,20 @@ void AbstractHeap::decorateInstruction(LValue instruction, const AbstractHeapRep setMetadata(instruction, repository.m_tbaaKind, tbaaMetadata(repository)); } +void AbstractHeap::dump(PrintStream& out) const +{ + out.print(heapName()); + if (m_parent) + out.print("->", *m_parent); +} + +void AbstractField::dump(PrintStream& out) const +{ + out.print(heapName(), "(", m_offset, ")"); + if (parent()) + out.print("->", *parent()); +} + IndexedAbstractHeap::IndexedAbstractHeap(LContext context, AbstractHeap* parent, const char* heapName, ptrdiff_t offset, size_t elementSize) : m_heapForAnyIndex(parent, heapName) , m_heapNameLength(strlen(heapName)) @@ -102,7 +116,7 @@ const AbstractField& IndexedAbstractHeap::atSlow(ptrdiff_t index) ASSERT(static_cast<size_t>(index) >= m_smallIndices.size()); if (UNLIKELY(!m_largeIndices)) - m_largeIndices = adoptPtr(new MapType()); + m_largeIndices = std::make_unique<MapType>(); std::unique_ptr<AbstractField>& field = m_largeIndices->add(index, nullptr).iterator->value; if (!field) { @@ -176,6 +190,11 @@ void IndexedAbstractHeap::initialize(AbstractField& field, ptrdiff_t signedIndex RELEASE_ASSERT_NOT_REACHED(); } +void IndexedAbstractHeap::dump(PrintStream& out) const +{ + out.print("Indexed:", atAnyIndex()); +} + NumberedAbstractHeap::NumberedAbstractHeap(LContext context, AbstractHeap* heap, const char* heapName) : m_indexedHeap(context, heap, heapName, 0, 1) { @@ -185,6 +204,11 @@ NumberedAbstractHeap::~NumberedAbstractHeap() { } +void NumberedAbstractHeap::dump(PrintStream& out) const +{ + out.print("Numbered: ", atAnyNumber()); +} + AbsoluteAbstractHeap::AbsoluteAbstractHeap(LContext context, AbstractHeap* heap, const char* heapName) : m_indexedHeap(context, heap, heapName, 0, 1) { @@ -194,6 +218,11 @@ AbsoluteAbstractHeap::~AbsoluteAbstractHeap() { } +void AbsoluteAbstractHeap::dump(PrintStream& out) const +{ + out.print("Absolute:", atAnyAddress()); +} + } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) diff --git a/ftl/FTLAbstractHeap.h b/ftl/FTLAbstractHeap.h index c3e2907..a19ce38 100644 --- a/ftl/FTLAbstractHeap.h +++ b/ftl/FTLAbstractHeap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,7 +34,6 @@ #include <wtf/FastMalloc.h> #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> #include <wtf/Vector.h> #include <wtf/text/CString.h> @@ -72,6 +71,11 @@ public: m_parent = parent; m_heapName = heapName; } + + void changeParent(AbstractHeap* parent) + { + m_parent = parent; + } AbstractHeap* parent() const { @@ -95,6 +99,8 @@ public: void decorateInstruction(LValue instruction, const AbstractHeapRepository&) const; + void dump(PrintStream&) const; + private: friend class AbstractHeapRepository; @@ -131,6 +137,8 @@ public: return m_offset; } + void dump(PrintStream&) const; + private: ptrdiff_t m_offset; }; @@ -153,6 +161,8 @@ public: TypedPointer baseIndex(Output& out, LValue base, LValue index, JSValue indexAsConstant = JSValue(), ptrdiff_t offset = 0); + void dump(PrintStream&) const; + private: const AbstractField& returnInitialized(AbstractField& field, ptrdiff_t index) { @@ -178,7 +188,7 @@ private: }; typedef HashMap<ptrdiff_t, std::unique_ptr<AbstractField>, WTF::IntHash<ptrdiff_t>, WithoutZeroOrOneHashTraits> MapType; - OwnPtr<MapType> m_largeIndices; + std::unique_ptr<MapType> m_largeIndices; Vector<CString, 16> m_largeIndexNames; }; @@ -197,6 +207,8 @@ public: const AbstractHeap& at(unsigned number) { return m_indexedHeap.at(number); } const AbstractHeap& operator[](unsigned number) { return at(number); } + void dump(PrintStream&) const; + private: // We use the fact that the indexed heap already has a superset of the @@ -218,6 +230,8 @@ public: const AbstractHeap& operator[](void* address) { return at(address); } + void dump(PrintStream&) const; + private: // The trick here is that the indexed heap is "indexed" by a pointer-width // integer. Pointers are themselves pointer-width integers. So we can reuse diff --git a/ftl/FTLAbstractHeapRepository.cpp b/ftl/FTLAbstractHeapRepository.cpp index 2189cd9..e416fda 100644 --- a/ftl/FTLAbstractHeapRepository.cpp +++ b/ftl/FTLAbstractHeapRepository.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,9 +28,14 @@ #if ENABLE(FTL_JIT) +#include "DirectArguments.h" +#include "GetterSetter.h" +#include "JSEnvironmentRecord.h" +#include "JSPropertyNameEnumerator.h" #include "JSScope.h" -#include "JSVariableObject.h" #include "JSCInlines.h" +#include "ScopedArguments.h" +#include "ScopedArgumentsTable.h" namespace JSC { namespace FTL { @@ -59,6 +64,17 @@ AbstractHeapRepository::AbstractHeapRepository(LContext context) , m_context(context) , m_tbaaKind(mdKindID(m_context, "tbaa")) { + // Make sure that our explicit assumptions about the StructureIDBlob match reality. + RELEASE_ASSERT(!(JSCell_indexingType.offset() & (sizeof(int32_t) - 1))); + RELEASE_ASSERT(JSCell_indexingType.offset() + 1 == JSCell_typeInfoType.offset()); + RELEASE_ASSERT(JSCell_indexingType.offset() + 2 == JSCell_typeInfoFlags.offset()); + RELEASE_ASSERT(JSCell_indexingType.offset() + 3 == JSCell_gcData.offset()); + + JSCell_indexingType.changeParent(&JSCell_usefulBytes); + JSCell_typeInfoType.changeParent(&JSCell_usefulBytes); + JSCell_typeInfoFlags.changeParent(&JSCell_usefulBytes); + JSCell_gcData.changeParent(&JSCell_usefulBytes); + root.m_tbaaMetadata = mdNode(m_context, mdString(m_context, root.m_heapName)); RELEASE_ASSERT(m_tbaaKind); diff --git a/ftl/FTLAbstractHeapRepository.h b/ftl/FTLAbstractHeapRepository.h index d59ad6a..912754d 100644 --- a/ftl/FTLAbstractHeapRepository.h +++ b/ftl/FTLAbstractHeapRepository.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,10 +35,7 @@ namespace JSC { namespace FTL { #define FOR_EACH_ABSTRACT_HEAP(macro) \ - macro(length) \ - macro(structureTable) \ - macro(typedArrayProperties) \ - macro(WriteBarrierBuffer_bufferContents) + macro(typedArrayProperties) #define FOR_EACH_ABSTRACT_FIELD(macro) \ macro(ArrayBuffer_data, ArrayBuffer::offsetOfData()) \ @@ -46,25 +43,45 @@ namespace JSC { namespace FTL { macro(Butterfly_publicLength, Butterfly::offsetOfPublicLength()) \ macro(Butterfly_vectorLength, Butterfly::offsetOfVectorLength()) \ macro(CallFrame_callerFrame, CallFrame::callerFrameOffset()) \ + macro(DirectArguments_callee, DirectArguments::offsetOfCallee()) \ + macro(DirectArguments_length, DirectArguments::offsetOfLength()) \ + macro(DirectArguments_minCapacity, DirectArguments::offsetOfMinCapacity()) \ + macro(DirectArguments_overrides, DirectArguments::offsetOfOverrides()) \ + macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \ + macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \ macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \ macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \ macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \ macro(JSCell_structureID, JSCell::structureIDOffset()) \ + macro(JSCell_usefulBytes, JSCell::indexingTypeOffset()) \ macro(JSCell_typeInfoFlags, JSCell::typeInfoFlagsOffset()) \ macro(JSCell_typeInfoType, JSCell::typeInfoTypeOffset()) \ macro(JSCell_indexingType, JSCell::indexingTypeOffset()) \ macro(JSCell_gcData, JSCell::gcDataOffset()) \ macro(JSFunction_executable, JSFunction::offsetOfExecutable()) \ macro(JSFunction_scope, JSFunction::offsetOfScopeChain()) \ + macro(JSFunction_rareData, JSFunction::offsetOfRareData()) \ macro(JSObject_butterfly, JSObject::butterflyOffset()) \ + macro(JSPropertyNameEnumerator_cachedInlineCapacity, JSPropertyNameEnumerator::cachedInlineCapacityOffset()) \ + macro(JSPropertyNameEnumerator_cachedPropertyNamesVector, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()) \ + macro(JSPropertyNameEnumerator_cachedStructureID, JSPropertyNameEnumerator::cachedStructureIDOffset()) \ + macro(JSPropertyNameEnumerator_endGenericPropertyIndex, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()) \ + macro(JSPropertyNameEnumerator_endStructurePropertyIndex, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()) \ + macro(JSPropertyNameEnumerator_indexLength, JSPropertyNameEnumerator::indexedLengthOffset()) \ macro(JSScope_next, JSScope::offsetOfNext()) \ macro(JSString_flags, JSString::offsetOfFlags()) \ macro(JSString_length, JSString::offsetOfLength()) \ macro(JSString_value, JSString::offsetOfValue()) \ - macro(JSVariableObject_registers, JSVariableObject::offsetOfRegisters()) \ + macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \ macro(JSWrapperObject_internalValue, JSWrapperObject::internalValueOffset()) \ macro(MarkedAllocator_freeListHead, MarkedAllocator::offsetOfFreeListHead()) \ macro(MarkedBlock_markBits, MarkedBlock::offsetOfMarks()) \ + macro(ScopedArguments_overrodeThings, ScopedArguments::offsetOfOverrodeThings()) \ + macro(ScopedArguments_scope, ScopedArguments::offsetOfScope()) \ + macro(ScopedArguments_table, ScopedArguments::offsetOfTable()) \ + macro(ScopedArguments_totalLength, ScopedArguments::offsetOfTotalLength()) \ + macro(ScopedArgumentsTable_arguments, ScopedArgumentsTable::offsetOfArguments()) \ + macro(ScopedArgumentsTable_length, ScopedArgumentsTable::offsetOfLength()) \ macro(StringImpl_data, StringImpl::dataOffset()) \ macro(StringImpl_hashAndFlags, StringImpl::flagsOffset()) \ macro(Structure_classInfo, Structure::classInfoOffset()) \ @@ -73,14 +90,23 @@ namespace JSC { namespace FTL { macro(Structure_structureID, Structure::structureIDOffset()) #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \ + macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \ + macro(JSEnvironmentRecord_variables, JSEnvironmentRecord::offsetOfVariables(), sizeof(EncodedJSValue)) \ + macro(JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, 0, sizeof(WriteBarrier<JSString>)) \ macro(JSRopeString_fibers, JSRopeString::offsetOfFibers(), sizeof(WriteBarrier<JSString>)) \ + macro(MarkedSpace_Subspace_impreciseAllocators, OBJECT_OFFSETOF(MarkedSpace::Subspace, impreciseAllocators), sizeof(MarkedAllocator)) \ + macro(MarkedSpace_Subspace_preciseAllocators, OBJECT_OFFSETOF(MarkedSpace::Subspace, preciseAllocators), sizeof(MarkedAllocator)) \ + macro(ScopedArguments_overflowStorage, ScopedArguments::overflowStorageOffset(), sizeof(EncodedJSValue)) \ + macro(WriteBarrierBuffer_bufferContents, 0, sizeof(JSCell*)) \ macro(characters8, 0, sizeof(LChar)) \ macro(characters16, 0, sizeof(UChar)) \ macro(indexedInt32Properties, 0, sizeof(EncodedJSValue)) \ macro(indexedDoubleProperties, 0, sizeof(double)) \ macro(indexedContiguousProperties, 0, sizeof(EncodedJSValue)) \ macro(indexedArrayStorageProperties, 0, sizeof(EncodedJSValue)) \ + macro(scopedArgumentsTableArguments, 0, sizeof(int32_t)) \ macro(singleCharacterStrings, 0, sizeof(JSString*)) \ + macro(structureTable, 0, sizeof(Structure*)) \ macro(variables, 0, sizeof(Register)) #define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \ diff --git a/ftl/FTLCapabilities.cpp b/ftl/FTLCapabilities.cpp index 3c02547..1fe7987 100644 --- a/ftl/FTLCapabilities.cpp +++ b/ftl/FTLCapabilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,14 +44,14 @@ inline CapabilityLevel canCompile(Node* node) switch (node->op()) { case JSConstant: - case WeakJSConstant: - case GetMyArgumentsLength: case GetLocal: case SetLocal: + case PutStack: + case KillStack: + case GetStack: case MovHint: case ZombieHint: case Phantom: - case HardPhantom: case Flush: case PhantomLocal: case SetArgument: @@ -63,20 +63,23 @@ inline CapabilityLevel canCompile(Node* node) case BitLShift: case BitURShift: case CheckStructure: - case StructureTransitionWatchpoint: + case DoubleAsInt32: case ArrayifyToStructure: case PutStructure: - case PhantomPutStructure: case GetButterfly: case NewObject: case NewArray: case NewArrayBuffer: case GetByOffset: + case GetGetterSetterByOffset: + case GetGetter: + case GetSetter: case PutByOffset: case GetGlobalVar: case PutGlobalVar: case ValueAdd: case ArithAdd: + case ArithClz32: case ArithSub: case ArithMul: case ArithDiv: @@ -86,7 +89,10 @@ inline CapabilityLevel canCompile(Node* node) case ArithAbs: case ArithSin: case ArithCos: + case ArithPow: + case ArithRound: case ArithSqrt: + case ArithLog: case ArithFRound: case ArithNegate: case UInt32ToNumber: @@ -97,26 +103,36 @@ inline CapabilityLevel canCompile(Node* node) case Upsilon: case ExtractOSREntryLocal: case LoopHint: - case GetMyScope: case SkipScope: - case GetClosureRegisters: + case CreateActivation: + case NewFunction: case GetClosureVar: case PutClosureVar: + case CreateDirectArguments: + case CreateScopedArguments: + case CreateClonedArguments: + case GetFromArguments: + case PutToArguments: case InvalidationPoint: case StringCharAt: - case CheckFunction: + case CheckCell: + case CheckBadCell: + case CheckNotEmpty: case StringCharCodeAt: case AllocatePropertyStorage: case ReallocatePropertyStorage: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: case GetTypedArrayByteOffset: - case VariableWatchpoint: case NotifyWrite: case StoreBarrier: - case StoreBarrierWithNullCheck: case Call: case Construct: + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: + case LoadVarargs: + case NativeCall: + case NativeConstruct: case ValueToInt32: case Branch: case LogicalNot: @@ -124,12 +140,12 @@ inline CapabilityLevel canCompile(Node* node) case ConstantStoragePointer: case Check: case CountExecution: - case CheckExecutable: + case GetExecutable: case GetScope: - case AllocationProfileWatchpoint: - case CheckArgumentsNotCreated: case GetCallee: + case GetArgumentCount: case ToString: + case CallStringConstructor: case MakeRope: case NewArrayWithSize: case GetById: @@ -137,16 +153,15 @@ inline CapabilityLevel canCompile(Node* node) case MultiGetByOffset: case MultiPutByOffset: case ToPrimitive: - case PhantomArguments: case Throw: case ThrowReferenceError: case Unreachable: - case GetMyArgumentByVal: case IsUndefined: case IsBoolean: case IsNumber: case IsString: case IsObject: + case IsObjectOrNull: case IsFunction: case CheckHasInstance: case InstanceOf: @@ -156,6 +171,28 @@ inline CapabilityLevel canCompile(Node* node) case DoubleConstant: case Int52Constant: case BooleanToNumber: + case HasGenericProperty: + case HasStructureProperty: + case GetDirectPname: + case GetEnumerableLength: + case GetPropertyEnumerator: + case GetEnumeratorStructurePname: + case GetEnumeratorGenericPname: + case ToIndexString: + case BottomValue: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PutHint: + case CheckStructureImmediate: + case MaterializeNewObject: + case MaterializeCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case GetMyArgumentByVal: + case ForwardVarargs: + case Switch: + case TypeOf: // These are OK. break; case Identity: @@ -164,6 +201,10 @@ inline CapabilityLevel canCompile(Node* node) // case because it would prevent us from catching bugs where the FTL backend // pipeline failed to optimize out an Identity. break; + case In: + if (node->child2().useKind() == CellUse) + break; + return CannotCompile; case PutByIdDirect: case PutById: if (node->child1().useKind() == CellUse) @@ -180,6 +221,8 @@ inline CapabilityLevel canCompile(Node* node) case Array::Int32: case Array::Double: case Array::Contiguous: + case Array::DirectArguments: + case Array::ScopedArguments: break; default: if (isTypedView(node->arrayMode().typedArrayType())) @@ -193,6 +236,8 @@ inline CapabilityLevel canCompile(Node* node) case Array::Double: case Array::Contiguous: case Array::String: + case Array::DirectArguments: + case Array::ScopedArguments: break; default: if (isTypedView(node->arrayMode().typedArrayType())) @@ -200,6 +245,17 @@ inline CapabilityLevel canCompile(Node* node) return CannotCompile; } break; + case HasIndexedProperty: + switch (node->arrayMode().type()) { + case Array::ForceExit: + case Array::Int32: + case Array::Double: + case Array::Contiguous: + break; + default: + return CannotCompile; + } + break; case GetByVal: switch (node->arrayMode().type()) { case Array::ForceExit: @@ -208,6 +264,8 @@ inline CapabilityLevel canCompile(Node* node) case Array::Int32: case Array::Double: case Array::Contiguous: + case Array::DirectArguments: + case Array::ScopedArguments: break; default: if (isTypedView(node->arrayMode().typedArrayType())) @@ -271,6 +329,10 @@ inline CapabilityLevel canCompile(Node* node) break; if (node->isBinaryUseKind(StringIdentUse)) break; + if (node->isBinaryUseKind(ObjectUse, UntypedUse)) + break; + if (node->isBinaryUseKind(UntypedUse, ObjectUse)) + break; if (node->isBinaryUseKind(ObjectUse)) break; if (node->isBinaryUseKind(BooleanUse)) @@ -297,15 +359,6 @@ inline CapabilityLevel canCompile(Node* node) if (node->isBinaryUseKind(UntypedUse)) break; return CannotCompile; - case Switch: - switch (node->switchData()->kind) { - case SwitchImm: - case SwitchChar: - break; - default: - return CannotCompile; - } - break; default: // Don't know how to handle anything else. return CannotCompile; @@ -327,17 +380,6 @@ CapabilityLevel canCompile(Graph& graph) return CannotCompile; } - if (graph.m_codeBlock->needsActivation()) { - // Need this because although we also don't support - // CreateActivation/TearOffActivation, we might not see those nodes in case of - // OSR entry. - // FIXME: Support activations. - // https://bugs.webkit.org/show_bug.cgi?id=129576 - if (verboseCapabilities()) - dataLog("FTL rejecting ", *graph.m_codeBlock, " because it uses activations.\n"); - return CannotCompile; - } - CapabilityLevel result = CanCompileAndOSREnter; for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) { @@ -362,12 +404,14 @@ CapabilityLevel canCompile(Graph& graph) case KnownInt32Use: case Int52RepUse: case NumberUse: + case RealNumberUse: case DoubleRepUse: case DoubleRepRealUse: case BooleanUse: case CellUse: case KnownCellUse: case ObjectUse: + case FunctionUse: case ObjectOrOtherUse: case StringUse: case KnownStringUse: diff --git a/ftl/FTLCompile.cpp b/ftl/FTLCompile.cpp index feab9bd..c6fcca0 100644 --- a/ftl/FTLCompile.cpp +++ b/ftl/FTLCompile.cpp @@ -1,5 +1,7 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. + * Copyright (C) 2014 Samsung Electronics + * Copyright (C) 2014 University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -57,13 +59,23 @@ static uint8_t* mmAllocateCodeSection( RefPtr<ExecutableMemoryHandle> result = state.graph.m_vm.executableAllocator.allocate( - state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationMustSucceed); + state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationCanFail); + + if (!result) { + // Signal failure. This compilation will get tossed. + state.allocationFailed = true; + + // Fake an allocation, since LLVM cannot handle failures in the memory manager. + RefPtr<DataSection> fakeSection = adoptRef(new DataSection(size, jitAllocationGranule)); + state.jitCode->addDataSection(fakeSection); + return bitwise_cast<uint8_t*>(fakeSection->base()); + } // LLVM used to put __compact_unwind in a code section. We keep this here defensively, // for clients that use older LLVMs. - if (!strcmp(sectionName, "__compact_unwind")) { - state.compactUnwind = result->start(); - state.compactUnwindSize = result->sizeInBytes(); + if (!strcmp(sectionName, SECTION_NAME("compact_unwind"))) { + state.unwindDataSection = result->start(); + state.unwindDataSectionSize = result->sizeInBytes(); } state.jitCode->addHandle(result); @@ -80,21 +92,27 @@ static uint8_t* mmAllocateDataSection( UNUSED_PARAM(isReadOnly); // Allocate the GOT in the code section to make it reachable for all code. - if (!strcmp(sectionName, "__got")) + if (!strcmp(sectionName, SECTION_NAME("got"))) return mmAllocateCodeSection(opaqueState, size, alignment, sectionID, sectionName); State& state = *static_cast<State*>(opaqueState); RefPtr<DataSection> section = adoptRef(new DataSection(size, alignment)); - if (!strcmp(sectionName, "__llvm_stackmaps")) + if (!strcmp(sectionName, SECTION_NAME("llvm_stackmaps"))) state.stackmapsSection = section; else { state.jitCode->addDataSection(section); state.dataSectionNames.append(sectionName); - if (!strcmp(sectionName, "__compact_unwind")) { - state.compactUnwind = section->base(); - state.compactUnwindSize = size; +#if OS(DARWIN) + if (!strcmp(sectionName, SECTION_NAME("compact_unwind"))) { +#elif OS(LINUX) + if (!strcmp(sectionName, SECTION_NAME("eh_frame"))) { +#else +#error "Unrecognized OS" +#endif + state.unwindDataSection = section->base(); + state.unwindDataSectionSize = size; } } @@ -120,6 +138,66 @@ static void dumpDataSection(DataSection* section, const char* prefix) } } +static int offsetOfStackRegion(StackMaps::RecordMap& recordMap, uint32_t stackmapID) +{ + if (stackmapID == UINT_MAX) + return 0; + + StackMaps::RecordMap::iterator iter = recordMap.find(stackmapID); + RELEASE_ASSERT(iter != recordMap.end()); + RELEASE_ASSERT(iter->value.size() == 1); + RELEASE_ASSERT(iter->value[0].locations.size() == 1); + Location capturedLocation = + Location::forStackmaps(nullptr, iter->value[0].locations[0]); + RELEASE_ASSERT(capturedLocation.kind() == Location::Register); + RELEASE_ASSERT(capturedLocation.gpr() == GPRInfo::callFrameRegister); + RELEASE_ASSERT(!(capturedLocation.addend() % sizeof(Register))); + return capturedLocation.addend() / sizeof(Register); +} + +static void generateInlineIfPossibleOutOfLineIfNot(State& state, VM& vm, CodeBlock* codeBlock, CCallHelpers& code, char* startOfInlineCode, size_t sizeOfInlineCode, const char* codeDescription, const std::function<void(LinkBuffer&, CCallHelpers&, bool wasCompiledInline)>& callback) +{ + std::unique_ptr<LinkBuffer> codeLinkBuffer; + size_t actualCodeSize = code.m_assembler.buffer().codeSize(); + + if (actualCodeSize <= sizeOfInlineCode) { + LinkBuffer codeLinkBuffer(vm, code, startOfInlineCode, sizeOfInlineCode); + + // Fill the remainder of the inline space with nops to avoid confusing the disassembler. + MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + actualCodeSize, sizeOfInlineCode - actualCodeSize); + + callback(codeLinkBuffer, code, true); + + return; + } + + // If there isn't enough space in the provided inline code area, allocate out of line + // executable memory to link the provided code. Place a jump at the beginning of the + // inline area and jump to the out of line code. Similarly return by appending a jump + // to the provided code that goes to the instruction after the inline code. + // Fill the middle with nop's. + MacroAssembler::Jump returnToMainline = code.jump(); + + // Allocate out of line executable memory and link the provided code there. + codeLinkBuffer = std::make_unique<LinkBuffer>(vm, code, codeBlock, JITCompilationMustSucceed); + + // Plant a jmp in the inline buffer to the out of line code. + MacroAssembler callToOutOfLineCode; + MacroAssembler::Jump jumpToOutOfLine = callToOutOfLineCode.jump(); + LinkBuffer inlineBuffer(vm, callToOutOfLineCode, startOfInlineCode, sizeOfInlineCode); + inlineBuffer.link(jumpToOutOfLine, codeLinkBuffer->entrypoint()); + + // Fill the remainder of the inline space with nops to avoid confusing the disassembler. + MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + inlineBuffer.size(), sizeOfInlineCode - inlineBuffer.size()); + + // Link the end of the out of line code to right after the inline area. + codeLinkBuffer->link(returnToMainline, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(startOfInlineCode)).labelAtOffset(sizeOfInlineCode)); + + callback(*codeLinkBuffer.get(), code, false); + + state.finalizer->outOfLineCodeInfos.append(OutOfLineCodeInfo(WTF::move(codeLinkBuffer), codeDescription)); +} + template<typename DescriptorType> void generateICFastPath( State& state, CodeBlock* codeBlock, GeneratedFunction generatedFunction, @@ -146,26 +224,77 @@ void generateICFastPath( char* startOfIC = bitwise_cast<char*>(generatedFunction) + record.instructionOffset; + + generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "inline cache fast path", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) { + state.finalizer->sideCodeLinkBuffer->link(ic.m_slowPathDone[i], + CodeLocationLabel(startOfIC + sizeOfIC)); + + linkBuffer.link(generator.slowPathJump(), + state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin())); + + generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer); + }); + } +} + +static void generateCheckInICFastPath( + State& state, CodeBlock* codeBlock, GeneratedFunction generatedFunction, + StackMaps::RecordMap& recordMap, CheckInDescriptor& ic, size_t sizeOfIC) +{ + VM& vm = state.graph.m_vm; + + StackMaps::RecordMap::iterator iter = recordMap.find(ic.stackmapID()); + if (iter == recordMap.end()) { + // It was optimized out. + return; + } + + Vector<StackMaps::Record>& records = iter->value; + + RELEASE_ASSERT(records.size() == ic.m_generators.size()); + + for (unsigned i = records.size(); i--;) { + StackMaps::Record& record = records[i]; + auto generator = ic.m_generators[i]; + + StructureStubInfo& stubInfo = *generator.m_stub; + auto call = generator.m_slowCall; + auto slowPathBegin = generator.m_beginLabel; + + CCallHelpers fastPathJIT(&vm, codeBlock); - LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfIC); - // Note: we could handle the !isValid() case. We just don't appear to have a - // reason to do so, yet. - RELEASE_ASSERT(linkBuffer.isValid()); - - MacroAssembler::AssemblerType_T::fillNops( - startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size()); - - state.finalizer->sideCodeLinkBuffer->link( - ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC)); - - linkBuffer.link( - generator.slowPathJump(), - state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin())); - - generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer); + auto jump = fastPathJIT.patchableJump(); + auto done = fastPathJIT.label(); + + char* startOfIC = + bitwise_cast<char*>(generatedFunction) + record.instructionOffset; + + auto postLink = [&] (LinkBuffer& fastPath, CCallHelpers&, bool) { + LinkBuffer& slowPath = *state.finalizer->sideCodeLinkBuffer; + + state.finalizer->sideCodeLinkBuffer->link( + ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC)); + + CodeLocationLabel slowPathBeginLoc = slowPath.locationOf(slowPathBegin); + fastPath.link(jump, slowPathBeginLoc); + + CodeLocationCall callReturnLocation = slowPath.locationOf(call); + + stubInfo.patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr( + callReturnLocation, fastPath.locationOf(done)); + + stubInfo.patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr( + callReturnLocation, fastPath.locationOf(jump)); + stubInfo.callReturnLocation = callReturnLocation; + stubInfo.patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr( + callReturnLocation, slowPathBeginLoc); + }; + + generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "CheckIn inline cache", postLink); } } + static RegisterSet usedRegistersFor(const StackMaps::Record& record) { if (Options::assumeAllRegsInFTLICAreLive()) @@ -173,6 +302,32 @@ static RegisterSet usedRegistersFor(const StackMaps::Record& record) return RegisterSet(record.usedRegisterSet(), RegisterSet::calleeSaveRegisters()); } +template<typename CallType> +void adjustCallICsForStackmaps(Vector<CallType>& calls, StackMaps::RecordMap& recordMap) +{ + // Handling JS calls is weird: we need to ensure that we sort them by the PC in LLVM + // generated code. That implies first pruning the ones that LLVM didn't generate. + + Vector<CallType> oldCalls; + oldCalls.swap(calls); + + for (unsigned i = 0; i < oldCalls.size(); ++i) { + CallType& call = oldCalls[i]; + + StackMaps::RecordMap::iterator iter = recordMap.find(call.stackmapID()); + if (iter == recordMap.end()) + continue; + + for (unsigned j = 0; j < iter->value.size(); ++j) { + CallType copy = call; + copy.m_instructionOffset = iter->value[j].instructionOffset; + calls.append(copy); + } + } + + std::sort(calls.begin(), calls.end()); +} + static void fixFunctionBasedOnStackMaps( State& state, CodeBlock* codeBlock, JITCode* jitCode, GeneratedFunction generatedFunction, StackMaps::RecordMap& recordMap, bool didSeeUnwindInfo) @@ -181,24 +336,14 @@ static void fixFunctionBasedOnStackMaps( VM& vm = graph.m_vm; StackMaps stackmaps = jitCode->stackmaps; - StackMaps::RecordMap::iterator iter = recordMap.find(state.capturedStackmapID); - RELEASE_ASSERT(iter != recordMap.end()); - RELEASE_ASSERT(iter->value.size() == 1); - RELEASE_ASSERT(iter->value[0].locations.size() == 1); - Location capturedLocation = - Location::forStackmaps(&jitCode->stackmaps, iter->value[0].locations[0]); - RELEASE_ASSERT(capturedLocation.kind() == Location::Register); - RELEASE_ASSERT(capturedLocation.gpr() == GPRInfo::callFrameRegister); - RELEASE_ASSERT(!(capturedLocation.addend() % sizeof(Register))); - int32_t localsOffset = capturedLocation.addend() / sizeof(Register) + graph.m_nextMachineLocal; + int localsOffset = offsetOfStackRegion(recordMap, state.capturedStackmapID) + graph.m_nextMachineLocal; + int varargsSpillSlotsOffset = offsetOfStackRegion(recordMap, state.varargsSpillSlotsStackmapID); for (unsigned i = graph.m_inlineVariableData.size(); i--;) { InlineCallFrame* inlineCallFrame = graph.m_inlineVariableData[i].inlineCallFrame; - if (inlineCallFrame->argumentsRegister.isValid()) { - inlineCallFrame->argumentsRegister = VirtualRegister( - inlineCallFrame->argumentsRegister.offset() + localsOffset); - } + if (inlineCallFrame->argumentCountRegister.isValid()) + inlineCallFrame->argumentCountRegister += localsOffset; for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) { inlineCallFrame->arguments[argument] = @@ -209,13 +354,11 @@ static void fixFunctionBasedOnStackMaps( inlineCallFrame->calleeRecovery = inlineCallFrame->calleeRecovery.withLocalsOffset(localsOffset); } + + if (graph.hasDebuggerEnabled()) + codeBlock->setScopeRegister(codeBlock->scopeRegister() + localsOffset); } - if (codeBlock->usesArguments()) { - codeBlock->setArgumentsRegister( - VirtualRegister(codeBlock->argumentsRegister().offset() + localsOffset)); - } - MacroAssembler::Label stackOverflowException; { @@ -223,25 +366,27 @@ static void fixFunctionBasedOnStackMaps( // At this point it's perfectly fair to just blow away all state and restore the // JS JIT view of the universe. + checkJIT.move(MacroAssembler::TrustedImmPtr(&vm), GPRInfo::argumentGPR0); checkJIT.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); + MacroAssembler::Call callLookupExceptionHandler = checkJIT.call(); + checkJIT.jumpToExceptionHandler(); - MacroAssembler::Label exceptionContinueArg1Set = checkJIT.label(); - checkJIT.move(MacroAssembler::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister); - checkJIT.move(MacroAssembler::TrustedImm64(TagMask), GPRInfo::tagMaskRegister); - + stackOverflowException = checkJIT.label(); checkJIT.move(MacroAssembler::TrustedImmPtr(&vm), GPRInfo::argumentGPR0); - MacroAssembler::Call call = checkJIT.call(); + checkJIT.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); + MacroAssembler::Call callLookupExceptionHandlerFromCallerFrame = checkJIT.call(); checkJIT.jumpToExceptionHandler(); - stackOverflowException = checkJIT.label(); - checkJIT.emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::argumentGPR1); - checkJIT.jump(exceptionContinueArg1Set); + auto linkBuffer = std::make_unique<LinkBuffer>( + vm, checkJIT, codeBlock, JITCompilationCanFail); + if (linkBuffer->didFailToAllocate()) { + state.allocationFailed = true; + return; + } + linkBuffer->link(callLookupExceptionHandler, FunctionPtr(lookupExceptionHandler)); + linkBuffer->link(callLookupExceptionHandlerFromCallerFrame, FunctionPtr(lookupExceptionHandlerFromCallerFrame)); - OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer( - vm, checkJIT, codeBlock, JITCompilationMustSucceed)); - linkBuffer->link(call, FunctionPtr(lookupExceptionHandler)); - - state.finalizer->handleExceptionsLinkBuffer = linkBuffer.release(); + state.finalizer->handleExceptionsLinkBuffer = WTF::move(linkBuffer); } ExitThunkGenerator exitThunkGenerator(state); @@ -250,8 +395,12 @@ static void fixFunctionBasedOnStackMaps( RELEASE_ASSERT(state.finalizer->osrExit.size()); RELEASE_ASSERT(didSeeUnwindInfo); - OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer( - vm, exitThunkGenerator, codeBlock, JITCompilationMustSucceed)); + auto linkBuffer = std::make_unique<LinkBuffer>( + vm, exitThunkGenerator, codeBlock, JITCompilationCanFail); + if (linkBuffer->didFailToAllocate()) { + state.allocationFailed = true; + return; + } RELEASE_ASSERT(state.finalizer->osrExit.size() == state.jitCode->osrExit.size()); @@ -262,7 +411,7 @@ static void fixFunctionBasedOnStackMaps( if (verboseCompilationEnabled()) dataLog("Handling OSR stackmap #", exit.m_stackmapID, " for ", exit.m_codeOrigin, "\n"); - iter = recordMap.find(exit.m_stackmapID); + auto iter = recordMap.find(exit.m_stackmapID); if (iter == recordMap.end()) { // It was optimized out. continue; @@ -271,26 +420,26 @@ static void fixFunctionBasedOnStackMaps( info.m_thunkAddress = linkBuffer->locationOf(info.m_thunkLabel); exit.m_patchableCodeOffset = linkBuffer->offsetOf(info.m_thunkJump); - for (unsigned j = exit.m_values.size(); j--;) { - ExitValue value = exit.m_values[j]; - if (!value.isInJSStackSomehow()) - continue; - if (!value.virtualRegister().isLocal()) - continue; - exit.m_values[j] = value.withVirtualRegister( - VirtualRegister(value.virtualRegister().offset() + localsOffset)); - } + for (unsigned j = exit.m_values.size(); j--;) + exit.m_values[j] = exit.m_values[j].withLocalsOffset(localsOffset); + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) + materialization->accountForLocalsOffset(localsOffset); if (verboseCompilationEnabled()) { DumpContext context; dataLog(" Exit values: ", inContext(exit.m_values, &context), "\n"); + if (!exit.m_materializations.isEmpty()) { + dataLog(" Materializations: \n"); + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) + dataLog(" Materialize(", pointerDump(materialization), ")\n"); + } } } - state.finalizer->exitThunksLinkBuffer = linkBuffer.release(); + state.finalizer->exitThunksLinkBuffer = WTF::move(linkBuffer); } - if (!state.getByIds.isEmpty() || !state.putByIds.isEmpty()) { + if (!state.getByIds.isEmpty() || !state.putByIds.isEmpty() || !state.checkIns.isEmpty()) { CCallHelpers slowPathJIT(&vm, codeBlock); CCallHelpers::JumpList exceptionTarget; @@ -301,7 +450,7 @@ static void fixFunctionBasedOnStackMaps( if (verboseCompilationEnabled()) dataLog("Handling GetById stackmap #", getById.stackmapID(), "\n"); - iter = recordMap.find(getById.stackmapID()); + auto iter = recordMap.find(getById.stackmapID()); if (iter == recordMap.end()) { // It was optimized out. continue; @@ -320,13 +469,13 @@ static void fixFunctionBasedOnStackMaps( JSValueRegs(result), NeedToSpill); MacroAssembler::Label begin = slowPathJIT.label(); - + MacroAssembler::Call call = callOperation( state, usedRegisters, slowPathJIT, getById.codeOrigin(), &exceptionTarget, operationGetByIdOptimize, result, gen.stubInfo(), base, getById.uid()); - + gen.reportSlowPathCall(begin, call); - + getById.m_slowPathDone.append(slowPathJIT.jump()); getById.m_generators.append(gen); } @@ -338,7 +487,7 @@ static void fixFunctionBasedOnStackMaps( if (verboseCompilationEnabled()) dataLog("Handling PutById stackmap #", putById.stackmapID(), "\n"); - iter = recordMap.find(putById.stackmapID()); + auto iter = recordMap.find(putById.stackmapID()); if (iter == recordMap.end()) { // It was optimized out. continue; @@ -369,12 +518,51 @@ static void fixFunctionBasedOnStackMaps( putById.m_generators.append(gen); } } + + for (unsigned i = state.checkIns.size(); i--;) { + CheckInDescriptor& checkIn = state.checkIns[i]; + + if (verboseCompilationEnabled()) + dataLog("Handling checkIn stackmap #", checkIn.stackmapID(), "\n"); + + auto iter = recordMap.find(checkIn.stackmapID()); + if (iter == recordMap.end()) { + // It was optimized out. + continue; + } + + for (unsigned i = 0; i < iter->value.size(); ++i) { + StackMaps::Record& record = iter->value[i]; + RegisterSet usedRegisters = usedRegistersFor(record); + GPRReg result = record.locations[0].directGPR(); + GPRReg obj = record.locations[1].directGPR(); + StructureStubInfo* stubInfo = codeBlock->addStubInfo(); + stubInfo->codeOrigin = checkIn.codeOrigin(); + stubInfo->patch.baseGPR = static_cast<int8_t>(obj); + stubInfo->patch.valueGPR = static_cast<int8_t>(result); + stubInfo->patch.usedRegisters = usedRegisters; + stubInfo->patch.spillMode = NeedToSpill; + + MacroAssembler::Label begin = slowPathJIT.label(); + + MacroAssembler::Call slowCall = callOperation( + state, usedRegisters, slowPathJIT, checkIn.codeOrigin(), &exceptionTarget, + operationInOptimize, result, stubInfo, obj, checkIn.m_uid); + + checkIn.m_slowPathDone.append(slowPathJIT.jump()); + + checkIn.m_generators.append(CheckInGenerator(stubInfo, slowCall, begin)); + } + } exceptionTarget.link(&slowPathJIT); MacroAssembler::Jump exceptionJump = slowPathJIT.jump(); - state.finalizer->sideCodeLinkBuffer = adoptPtr( - new LinkBuffer(vm, slowPathJIT, codeBlock, JITCompilationMustSucceed)); + state.finalizer->sideCodeLinkBuffer = std::make_unique<LinkBuffer>(vm, slowPathJIT, codeBlock, JITCompilationCanFail); + if (state.finalizer->sideCodeLinkBuffer->didFailToAllocate()) { + state.allocationFailed = true; + return; + } state.finalizer->sideCodeLinkBuffer->link( exceptionJump, state.finalizer->handleExceptionsLinkBuffer->entrypoint()); @@ -388,51 +576,48 @@ static void fixFunctionBasedOnStackMaps( state, codeBlock, generatedFunction, recordMap, state.putByIds[i], sizeOfPutById()); } - } - - // Handling JS calls is weird: we need to ensure that we sort them by the PC in LLVM - // generated code. That implies first pruning the ones that LLVM didn't generate. - Vector<JSCall> oldCalls = state.jsCalls; - state.jsCalls.resize(0); - for (unsigned i = 0; i < oldCalls.size(); ++i) { - JSCall& call = oldCalls[i]; - - StackMaps::RecordMap::iterator iter = recordMap.find(call.stackmapID()); - if (iter == recordMap.end()) - continue; - for (unsigned j = 0; j < iter->value.size(); ++j) { - JSCall copy = call; - copy.m_instructionOffset = iter->value[j].instructionOffset; - state.jsCalls.append(copy); - } + for (unsigned i = state.checkIns.size(); i--;) { + generateCheckInICFastPath( + state, codeBlock, generatedFunction, recordMap, state.checkIns[i], + sizeOfIn()); + } } - std::sort(state.jsCalls.begin(), state.jsCalls.end()); + adjustCallICsForStackmaps(state.jsCalls, recordMap); for (unsigned i = state.jsCalls.size(); i--;) { JSCall& call = state.jsCalls[i]; CCallHelpers fastPathJIT(&vm, codeBlock); call.emit(fastPathJIT); - + char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset; + + generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfCall(), "JSCall inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) { + call.link(vm, linkBuffer); + }); + } + + adjustCallICsForStackmaps(state.jsCallVarargses, recordMap); + + for (unsigned i = state.jsCallVarargses.size(); i--;) { + JSCallVarargs& call = state.jsCallVarargses[i]; - LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfCall()); - if (!linkBuffer.isValid()) { - dataLog("Failed to insert inline cache for call because we thought the size would be ", sizeOfCall(), " but it ended up being ", fastPathJIT.m_assembler.codeSize(), " prior to compaction.\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - - MacroAssembler::AssemblerType_T::fillNops( - startOfIC + linkBuffer.size(), sizeOfCall() - linkBuffer.size()); - - call.link(vm, linkBuffer); + CCallHelpers fastPathJIT(&vm, codeBlock); + call.emit(fastPathJIT, varargsSpillSlotsOffset); + + char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset; + size_t sizeOfIC = sizeOfICFor(call.node()); + + generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "varargs call inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) { + call.link(vm, linkBuffer, state.finalizer->handleExceptionsLinkBuffer->entrypoint()); + }); } RepatchBuffer repatchBuffer(codeBlock); - iter = recordMap.find(state.handleStackOverflowExceptionStackmapID); + auto iter = recordMap.find(state.handleStackOverflowExceptionStackmapID); // It's sort of remotely possible that we won't have an in-band exception handling // path, for some kinds of functions. if (iter != recordMap.end()) { @@ -503,41 +688,73 @@ void compile(State& state, Safepoint::Result& safepointResult) options.NoFramePointerElim = true; if (Options::useLLVMSmallCodeModel()) options.CodeModel = LLVMCodeModelSmall; - options.EnableFastISel = Options::enableLLVMFastISel(); + options.EnableFastISel = enableLLVMFastISel; options.MCJMM = llvm->CreateSimpleMCJITMemoryManager( &state, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy); LLVMExecutionEngineRef engine; - if (isARM64()) + if (isARM64()) { +#if OS(DARWIN) llvm->SetTarget(state.module, "arm64-apple-ios"); - +#elif OS(LINUX) + llvm->SetTarget(state.module, "aarch64-linux-gnu"); +#else +#error "Unrecognized OS" +#endif + } + if (llvm->CreateMCJITCompilerForModule(&engine, state.module, &options, sizeof(options), &error)) { dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n"); CRASH(); } + + // At this point we no longer own the module. + LModule module = state.module; + state.module = nullptr; + + // The data layout also has to be set in the module. Get the data layout from the MCJIT and apply + // it to the module. + LLVMTargetMachineRef targetMachine = llvm->GetExecutionEngineTargetMachine(engine); + LLVMTargetDataRef targetData = llvm->GetExecutionEngineTargetData(engine); + char* stringRepOfTargetData = llvm->CopyStringRepOfTargetData(targetData); + llvm->SetDataLayout(module, stringRepOfTargetData); + free(stringRepOfTargetData); LLVMPassManagerRef functionPasses = 0; LLVMPassManagerRef modulePasses; - + if (Options::llvmSimpleOpt()) { modulePasses = llvm->CreatePassManager(); - llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses); + llvm->AddTargetData(targetData, modulePasses); + llvm->AddAnalysisPasses(targetMachine, modulePasses); llvm->AddPromoteMemoryToRegisterPass(modulePasses); + llvm->AddGlobalOptimizerPass(modulePasses); + llvm->AddFunctionInliningPass(modulePasses); + llvm->AddPruneEHPass(modulePasses); + llvm->AddGlobalDCEPass(modulePasses); llvm->AddConstantPropagationPass(modulePasses); + llvm->AddAggressiveDCEPass(modulePasses); llvm->AddInstructionCombiningPass(modulePasses); + // BEGIN - DO NOT CHANGE THE ORDER OF THE ALIAS ANALYSIS PASSES llvm->AddTypeBasedAliasAnalysisPass(modulePasses); llvm->AddBasicAliasAnalysisPass(modulePasses); + // END - DO NOT CHANGE THE ORDER OF THE ALIAS ANALYSIS PASSES llvm->AddGVNPass(modulePasses); llvm->AddCFGSimplificationPass(modulePasses); llvm->AddDeadStoreEliminationPass(modulePasses); - llvm->RunPassManager(modulePasses, state.module); + + if (enableLLVMFastISel) + llvm->AddLowerSwitchPass(modulePasses); + + llvm->RunPassManager(modulePasses, module); } else { LLVMPassManagerBuilderRef passBuilder = llvm->PassManagerBuilderCreate(); llvm->PassManagerBuilderSetOptLevel(passBuilder, Options::llvmOptimizationLevel()); + llvm->PassManagerBuilderUseInlinerWithThreshold(passBuilder, 275); llvm->PassManagerBuilderSetSizeLevel(passBuilder, Options::llvmSizeLevel()); - functionPasses = llvm->CreateFunctionPassManagerForModule(state.module); + functionPasses = llvm->CreateFunctionPassManagerForModule(module); modulePasses = llvm->CreatePassManager(); llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses); @@ -548,16 +765,16 @@ void compile(State& state, Safepoint::Result& safepointResult) llvm->PassManagerBuilderDispose(passBuilder); llvm->InitializeFunctionPassManager(functionPasses); - for (LValue function = llvm->GetFirstFunction(state.module); function; function = llvm->GetNextFunction(function)) + for (LValue function = llvm->GetFirstFunction(module); function; function = llvm->GetNextFunction(function)) llvm->RunFunctionPassManager(functionPasses, function); llvm->FinalizeFunctionPassManager(functionPasses); - llvm->RunPassManager(modulePasses, state.module); + llvm->RunPassManager(modulePasses, module); } if (shouldShowDisassembly() || verboseCompilationEnabled()) - state.dumpState("after optimization"); - + state.dumpState(module, "after optimization"); + // FIXME: Need to add support for the case where JIT memory allocation failed. // https://bugs.webkit.org/show_bug.cgi?id=113620 state.generatedFunction = reinterpret_cast<GeneratedFunction>(llvm->GetPointerToGlobal(engine, state.function)); @@ -566,10 +783,14 @@ void compile(State& state, Safepoint::Result& safepointResult) llvm->DisposePassManager(modulePasses); llvm->DisposeExecutionEngine(engine); } + if (safepointResult.didGetCancelled()) return; RELEASE_ASSERT(!state.graph.m_vm.heap.isCollecting()); + if (state.allocationFailed) + return; + if (shouldShowDisassembly()) { for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) { ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get(); @@ -593,7 +814,8 @@ void compile(State& state, Safepoint::Result& safepointResult) } bool didSeeUnwindInfo = state.jitCode->unwindInfo.parse( - state.compactUnwind, state.compactUnwindSize, state.generatedFunction); + state.unwindDataSection, state.unwindDataSectionSize, + state.generatedFunction); if (shouldShowDisassembly()) { dataLog("Unwind info for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ":\n"); if (didSeeUnwindInfo) @@ -624,26 +846,36 @@ void compile(State& state, Safepoint::Result& safepointResult) fixFunctionBasedOnStackMaps( state, state.graph.m_codeBlock, state.jitCode.get(), state.generatedFunction, recordMap, didSeeUnwindInfo); + if (state.allocationFailed) + return; - if (shouldShowDisassembly()) { + if (shouldShowDisassembly() || Options::asyncDisassembly()) { for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) { - if (state.codeSectionNames[i] != "__text") + if (state.codeSectionNames[i] != SECTION_NAME("text")) continue; ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get(); - dataLog( + + CString header = toCString( "Generated LLVM code after stackmap-based fix-up for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), " in ", state.graph.m_plan.mode, " #", i, ", ", state.codeSectionNames[i], ":\n"); + + if (Options::asyncDisassembly()) { + disassembleAsynchronously( + header, MacroAssemblerCodeRef(handle), handle->sizeInBytes(), " ", + LLVMSubset); + continue; + } + + dataLog(header); disassemble( MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(), " ", WTF::dataFile(), LLVMSubset); } } } - - state.module = 0; // We no longer own the module. } } } // namespace JSC::FTL diff --git a/ftl/FTLExitArgument.cpp b/ftl/FTLExitArgument.cpp index cbe0de7..381b3d3 100644 --- a/ftl/FTLExitArgument.cpp +++ b/ftl/FTLExitArgument.cpp @@ -32,7 +32,7 @@ namespace JSC { namespace FTL { void ExitArgument::dump(PrintStream& out) const { - out.print("arg", argument(), " as ", format()); + out.print("#", argument(), " as ", format()); } } } // namespace JSC::FTL diff --git a/ftl/FTLExitArgumentForOperand.cpp b/ftl/FTLExitArgumentForOperand.cpp index 775abe1..074e7a6 100644 --- a/ftl/FTLExitArgumentForOperand.cpp +++ b/ftl/FTLExitArgumentForOperand.cpp @@ -32,7 +32,7 @@ namespace JSC { namespace FTL { void ExitArgumentForOperand::dump(PrintStream& out) const { - out.print(m_exitArgument, " for r", m_operand); + out.print(m_exitArgument, " for ", m_operand); } } } // namespace JSC::FTL diff --git a/ftl/FTLExitPropertyValue.cpp b/ftl/FTLExitPropertyValue.cpp new file mode 100644 index 0000000..d57db74 --- /dev/null +++ b/ftl/FTLExitPropertyValue.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014, 2015 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 "FTLExitPropertyValue.h" + +#if ENABLE(FTL_JIT) + +namespace JSC { namespace FTL { + +ExitPropertyValue ExitPropertyValue::withLocalsOffset(int offset) const +{ + return ExitPropertyValue(m_location, m_value.withLocalsOffset(offset)); +} + +void ExitPropertyValue::dump(PrintStream& out) const +{ + out.print(m_location, " => ", m_value); +} + +void ExitPropertyValue::validateReferences(const TrackedReferences& trackedReferences) const +{ + m_value.validateReferences(trackedReferences); +} + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + diff --git a/ftl/FTLExitPropertyValue.h b/ftl/FTLExitPropertyValue.h new file mode 100644 index 0000000..76fd00c --- /dev/null +++ b/ftl/FTLExitPropertyValue.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014, 2015 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 FTLExitPropertyValue_h +#define FTLExitPropertyValue_h + +#if ENABLE(FTL_JIT) + +#include "DFGPromotedHeapLocation.h" +#include "FTLExitValue.h" + +namespace JSC { + +class TrackedReferences; + +namespace FTL { + +class ExitPropertyValue { +public: + ExitPropertyValue() + { + } + + ExitPropertyValue(DFG::PromotedLocationDescriptor location, const ExitValue& value) + : m_location(location) + , m_value(value) + { + ASSERT(!!location == !!value); + } + + bool operator!() const { return !m_location; } + + DFG::PromotedLocationDescriptor location() const { return m_location; } + const ExitValue& value() const { return m_value; } + + ExitPropertyValue withLocalsOffset(int offset) const; + + void dump(PrintStream& out) const; + + void validateReferences(const TrackedReferences&) const; + +private: + DFG::PromotedLocationDescriptor m_location; + ExitValue m_value; +}; + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + +#endif // FTLExitPropertyValue_h + diff --git a/ftl/FTLExitTimeObjectMaterialization.cpp b/ftl/FTLExitTimeObjectMaterialization.cpp new file mode 100644 index 0000000..858d1ba --- /dev/null +++ b/ftl/FTLExitTimeObjectMaterialization.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014, 2015 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 "FTLExitTimeObjectMaterialization.h" + +#if ENABLE(FTL_JIT) + +#include "DFGGraph.h" + +namespace JSC { namespace FTL { + +using namespace JSC::DFG; + +ExitTimeObjectMaterialization::ExitTimeObjectMaterialization(NodeType type, CodeOrigin codeOrigin) + : m_type(type) + , m_origin(codeOrigin) +{ +} + +ExitTimeObjectMaterialization::~ExitTimeObjectMaterialization() +{ +} + +void ExitTimeObjectMaterialization::add( + PromotedLocationDescriptor location, const ExitValue& value) +{ + m_properties.append(ExitPropertyValue(location, value)); +} + +ExitValue ExitTimeObjectMaterialization::get(PromotedLocationDescriptor location) const +{ + for (ExitPropertyValue value : m_properties) { + if (value.location() == location) + return value.value(); + } + return ExitValue(); +} + +void ExitTimeObjectMaterialization::accountForLocalsOffset(int offset) +{ + for (ExitPropertyValue& property : m_properties) + property = property.withLocalsOffset(offset); +} + +void ExitTimeObjectMaterialization::dump(PrintStream& out) const +{ + out.print(RawPointer(this), ":", Graph::opName(m_type), "(", listDump(m_properties), ")"); +} + +void ExitTimeObjectMaterialization::validateReferences(const TrackedReferences& trackedReferences) const +{ + for (ExitPropertyValue value : m_properties) + value.validateReferences(trackedReferences); +} + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + diff --git a/ftl/FTLExitTimeObjectMaterialization.h b/ftl/FTLExitTimeObjectMaterialization.h new file mode 100644 index 0000000..e2003c6 --- /dev/null +++ b/ftl/FTLExitTimeObjectMaterialization.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014, 2015 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 FTLExitTimeObjectMaterialization_h +#define FTLExitTimeObjectMaterialization_h + +#if ENABLE(FTL_JIT) + +#include "DFGNodeType.h" +#include "FTLExitPropertyValue.h" +#include "FTLExitValue.h" +#include <wtf/Noncopyable.h> + +namespace JSC { + +class TrackedReferences; + +namespace FTL { + +class ExitTimeObjectMaterialization { + WTF_MAKE_NONCOPYABLE(ExitTimeObjectMaterialization) +public: + ExitTimeObjectMaterialization(DFG::NodeType, CodeOrigin); + ~ExitTimeObjectMaterialization(); + + void add(DFG::PromotedLocationDescriptor, const ExitValue&); + + DFG::NodeType type() const { return m_type; } + CodeOrigin origin() const { return m_origin; } + + ExitValue get(DFG::PromotedLocationDescriptor) const; + const Vector<ExitPropertyValue>& properties() const { return m_properties; } + + void accountForLocalsOffset(int offset); + + void dump(PrintStream& out) const; + + void validateReferences(const TrackedReferences&) const; + +private: + DFG::NodeType m_type; + CodeOrigin m_origin; + Vector<ExitPropertyValue> m_properties; +}; + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + +#endif // FTLExitTimeObjectMaterialization_h + diff --git a/ftl/FTLExitValue.cpp b/ftl/FTLExitValue.cpp index 81df770..24a0f3c 100644 --- a/ftl/FTLExitValue.cpp +++ b/ftl/FTLExitValue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,10 +28,62 @@ #if ENABLE(FTL_JIT) +#include "FTLExitTimeObjectMaterialization.h" #include "JSCInlines.h" +#include "TrackedReferences.h" namespace JSC { namespace FTL { +ExitValue ExitValue::materializeNewObject(ExitTimeObjectMaterialization* data) +{ + ExitValue result; + result.m_kind = ExitValueMaterializeNewObject; + result.u.newObjectMaterializationData = data; + return result; +} + +ExitValue ExitValue::withLocalsOffset(int offset) const +{ + if (!isInJSStackSomehow()) + return *this; + if (!virtualRegister().isLocal()) + return *this; + return withVirtualRegister(virtualRegister() + offset); +} + +ValueFormat ExitValue::valueFormat() const +{ + switch (kind()) { + case InvalidExitValue: + RELEASE_ASSERT_NOT_REACHED(); + return InvalidValueFormat; + + case ExitValueDead: + case ExitValueConstant: + case ExitValueInJSStack: + case ExitValueMaterializeNewObject: + return ValueFormatJSValue; + + case ExitValueArgument: + return exitArgument().format(); + + case ExitValueInJSStackAsInt32: + return ValueFormatInt32; + + case ExitValueInJSStackAsInt52: + return ValueFormatInt52; + + case ExitValueInJSStackAsDouble: + return ValueFormatDouble; + + case ExitValueRecovery: + return recoveryFormat(); + } + + RELEASE_ASSERT_NOT_REACHED(); + return InvalidValueFormat; +} + void ExitValue::dumpInContext(PrintStream& out, DumpContext* context) const { switch (kind()) { @@ -48,23 +100,23 @@ void ExitValue::dumpInContext(PrintStream& out, DumpContext* context) const out.print("Constant(", inContext(constant(), context), ")"); return; case ExitValueInJSStack: - out.print("InJSStack:r", virtualRegister()); + out.print("InJSStack:", virtualRegister()); return; case ExitValueInJSStackAsInt32: - out.print("InJSStackAsInt32:r", virtualRegister()); + out.print("InJSStackAsInt32:", virtualRegister()); return; case ExitValueInJSStackAsInt52: - out.print("InJSStackAsInt52:r", virtualRegister()); + out.print("InJSStackAsInt52:", virtualRegister()); return; case ExitValueInJSStackAsDouble: - out.print("InJSStackAsDouble:r", virtualRegister()); - return; - case ExitValueArgumentsObjectThatWasNotCreated: - out.print("ArgumentsObjectThatWasNotCreated"); + out.print("InJSStackAsDouble:", virtualRegister()); return; case ExitValueRecovery: out.print("Recovery(", recoveryOpcode(), ", arg", leftRecoveryArgument(), ", arg", rightRecoveryArgument(), ", ", recoveryFormat(), ")"); return; + case ExitValueMaterializeNewObject: + out.print("Materialize(", WTF::RawPointer(objectMaterialization()), ")"); + return; } RELEASE_ASSERT_NOT_REACHED(); @@ -75,6 +127,12 @@ void ExitValue::dump(PrintStream& out) const dumpInContext(out, 0); } +void ExitValue::validateReferences(const TrackedReferences& trackedReferences) const +{ + if (isConstant()) + trackedReferences.check(constant()); +} + } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) diff --git a/ftl/FTLExitValue.h b/ftl/FTLExitValue.h index 043e1b7..13e6e09 100644 --- a/ftl/FTLExitValue.h +++ b/ftl/FTLExitValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,7 +34,11 @@ #include "VirtualRegister.h" #include <wtf/PrintStream.h> -namespace JSC { namespace FTL { +namespace JSC { + +class TrackedReferences; + +namespace FTL { // This is like ValueRecovery, but respects the way that the FTL does OSR // exit: the live non-constant non-flushed values are passed as arguments @@ -51,10 +55,12 @@ enum ExitValueKind { ExitValueInJSStackAsInt32, ExitValueInJSStackAsInt52, ExitValueInJSStackAsDouble, - ExitValueArgumentsObjectThatWasNotCreated, - ExitValueRecovery + ExitValueRecovery, + ExitValueMaterializeNewObject }; +class ExitTimeObjectMaterialization; + class ExitValue { public: ExitValue() @@ -119,13 +125,6 @@ public: return result; } - static ExitValue argumentsObjectThatWasNotCreated() - { - ExitValue result; - result.m_kind = ExitValueArgumentsObjectThatWasNotCreated; - return result; - } - static ExitValue recovery(RecoveryOpcode opcode, unsigned leftArgument, unsigned rightArgument, ValueFormat format) { ExitValue result; @@ -137,6 +136,8 @@ public: return result; } + static ExitValue materializeNewObject(ExitTimeObjectMaterialization*); + ExitValueKind kind() const { return m_kind; } bool isDead() const { return kind() == ExitValueDead; } @@ -154,8 +155,8 @@ public: } bool isConstant() const { return kind() == ExitValueConstant; } bool isArgument() const { return kind() == ExitValueArgument; } - bool isArgumentsObjectThatWasNotCreated() const { return kind() == ExitValueArgumentsObjectThatWasNotCreated; } bool isRecovery() const { return kind() == ExitValueRecovery; } + bool isObjectMaterialization() const { return kind() == ExitValueMaterializeNewObject; } ExitArgument exitArgument() const { @@ -199,7 +200,13 @@ public: return VirtualRegister(u.virtualRegister); } - ExitValue withVirtualRegister(VirtualRegister virtualRegister) + ExitTimeObjectMaterialization* objectMaterialization() const + { + ASSERT(isObjectMaterialization()); + return u.newObjectMaterializationData; + } + + ExitValue withVirtualRegister(VirtualRegister virtualRegister) const { ASSERT(isInJSStackSomehow()); ExitValue result; @@ -207,47 +214,20 @@ public: result.u.virtualRegister = virtualRegister.offset(); return result; } - + + ExitValue withLocalsOffset(int offset) const; + // If it's in the JSStack somehow, this will tell you what format it's in, in a manner // that is compatible with exitArgument().format(). If it's a constant or it's dead, it // will claim to be a JSValue. If it's an argument then it will tell you the argument's // format. - ValueFormat valueFormat() const - { - switch (kind()) { - case InvalidExitValue: - RELEASE_ASSERT_NOT_REACHED(); - return InvalidValueFormat; - - case ExitValueDead: - case ExitValueConstant: - case ExitValueInJSStack: - case ExitValueArgumentsObjectThatWasNotCreated: - return ValueFormatJSValue; - - case ExitValueArgument: - return exitArgument().format(); - - case ExitValueInJSStackAsInt32: - return ValueFormatInt32; - - case ExitValueInJSStackAsInt52: - return ValueFormatInt52; - - case ExitValueInJSStackAsDouble: - return ValueFormatDouble; - - case ExitValueRecovery: - return recoveryFormat(); - } - - RELEASE_ASSERT_NOT_REACHED(); - return InvalidValueFormat; - } + ValueFormat valueFormat() const; void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; + void validateReferences(const TrackedReferences&) const; + private: ExitValueKind m_kind; union { @@ -260,6 +240,7 @@ private: uint16_t opcode; uint16_t format; } recovery; + ExitTimeObjectMaterialization* newObjectMaterializationData; } u; }; diff --git a/ftl/FTLFail.cpp b/ftl/FTLFail.cpp index 1345c6f..ac2fc07 100644 --- a/ftl/FTLFail.cpp +++ b/ftl/FTLFail.cpp @@ -38,7 +38,7 @@ using namespace DFG; void fail(State& state) { - state.graph.m_plan.finalizer = adoptPtr(new FailedFinalizer(state.graph.m_plan)); + state.graph.m_plan.finalizer = std::make_unique<FailedFinalizer>(state.graph.m_plan); if (state.module) llvm->DisposeModule(state.module); diff --git a/ftl/FTLForOSREntryJITCode.cpp b/ftl/FTLForOSREntryJITCode.cpp index 708bedc..29f05e5 100644 --- a/ftl/FTLForOSREntryJITCode.cpp +++ b/ftl/FTLForOSREntryJITCode.cpp @@ -31,6 +31,8 @@ namespace JSC { namespace FTL { ForOSREntryJITCode::ForOSREntryJITCode() + : m_bytecodeIndex(UINT_MAX) + , m_entryFailureCount(0) { } diff --git a/ftl/FTLInlineCacheDescriptor.h b/ftl/FTLInlineCacheDescriptor.h index df0d711..6793e74 100644 --- a/ftl/FTLInlineCacheDescriptor.h +++ b/ftl/FTLInlineCacheDescriptor.h @@ -31,7 +31,7 @@ #include "CodeOrigin.h" #include "JITInlineCacheGenerator.h" #include "MacroAssembler.h" -#include <wtf/text/StringImpl.h> +#include <wtf/text/UniquedStringImpl.h> namespace JSC { namespace FTL { @@ -39,7 +39,7 @@ class InlineCacheDescriptor { public: InlineCacheDescriptor() { } - InlineCacheDescriptor(unsigned stackmapID, CodeOrigin codeOrigin, StringImpl* uid) + InlineCacheDescriptor(unsigned stackmapID, CodeOrigin codeOrigin, UniquedStringImpl* uid) : m_stackmapID(stackmapID) , m_codeOrigin(codeOrigin) , m_uid(uid) @@ -48,12 +48,12 @@ public: unsigned stackmapID() const { return m_stackmapID; } CodeOrigin codeOrigin() const { return m_codeOrigin; } - StringImpl* uid() const { return m_uid; } + UniquedStringImpl* uid() const { return m_uid; } private: unsigned m_stackmapID; CodeOrigin m_codeOrigin; - StringImpl* m_uid; + UniquedStringImpl* m_uid; public: Vector<MacroAssembler::Jump> m_slowPathDone; @@ -63,7 +63,7 @@ class GetByIdDescriptor : public InlineCacheDescriptor { public: GetByIdDescriptor() { } - GetByIdDescriptor(unsigned stackmapID, CodeOrigin codeOrigin, StringImpl* uid) + GetByIdDescriptor(unsigned stackmapID, CodeOrigin codeOrigin, UniquedStringImpl* uid) : InlineCacheDescriptor(stackmapID, codeOrigin, uid) { } @@ -76,7 +76,7 @@ public: PutByIdDescriptor() { } PutByIdDescriptor( - unsigned stackmapID, CodeOrigin codeOrigin, StringImpl* uid, + unsigned stackmapID, CodeOrigin codeOrigin, UniquedStringImpl* uid, ECMAMode ecmaMode, PutKind putKind) : InlineCacheDescriptor(stackmapID, codeOrigin, uid) , m_ecmaMode(ecmaMode) @@ -94,6 +94,35 @@ private: PutKind m_putKind; }; +struct CheckInGenerator { + StructureStubInfo* m_stub; + MacroAssembler::Call m_slowCall; + MacroAssembler::Label m_beginLabel; + + CheckInGenerator(StructureStubInfo* stub, MacroAssembler::Call slowCall, MacroAssembler::Label beginLabel) + : m_stub(stub) + , m_slowCall(slowCall) + , m_beginLabel(beginLabel) + { + } +}; + +class CheckInDescriptor : public InlineCacheDescriptor { +public: + CheckInDescriptor() { } + + CheckInDescriptor(unsigned stackmapID, CodeOrigin codeOrigin, const UniquedStringImpl* uid) + : InlineCacheDescriptor(stackmapID, codeOrigin, nullptr) + , m_uid(uid) + { + } + + + const UniquedStringImpl* m_uid; + Vector<CheckInGenerator> m_generators; +}; + + } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) diff --git a/ftl/FTLInlineCacheSize.cpp b/ftl/FTLInlineCacheSize.cpp index 6d44414..5cd6376 100644 --- a/ftl/FTLInlineCacheSize.cpp +++ b/ftl/FTLInlineCacheSize.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,11 +28,14 @@ #if ENABLE(FTL_JIT) +#include "DFGNode.h" #include "JITInlineCacheGenerator.h" #include "MacroAssembler.h" namespace JSC { namespace FTL { +using namespace DFG; + // The default sizes are x86-64-specific, and were found empirically. They have to cover the worst // possible combination of registers leading to the largest possible encoding of each instruction in // the IC. @@ -70,6 +73,68 @@ size_t sizeOfCall() #endif } +size_t sizeOfCallVarargs() +{ +#if CPU(ARM64) + return 332; +#else + return 275; +#endif +} + +size_t sizeOfCallForwardVarargs() +{ +#if CPU(ARM64) + return 312; +#else + return 262; +#endif +} + +size_t sizeOfConstructVarargs() +{ + return sizeOfCallVarargs(); // Should be the same size. +} + +size_t sizeOfConstructForwardVarargs() +{ + return sizeOfCallForwardVarargs(); // Should be the same size. +} + +size_t sizeOfIn() +{ +#if CPU(ARM64) + return 4; +#else + return 5; +#endif +} + +size_t sizeOfICFor(Node* node) +{ + switch (node->op()) { + case GetById: + return sizeOfGetById(); + case PutById: + return sizeOfPutById(); + case Call: + case Construct: + return sizeOfCall(); + case CallVarargs: + return sizeOfCallVarargs(); + case CallForwardVarargs: + return sizeOfCallForwardVarargs(); + case ConstructVarargs: + return sizeOfConstructVarargs(); + case ConstructForwardVarargs: + return sizeOfConstructForwardVarargs(); + case In: + return sizeOfIn(); + default: + return 0; + } +} + } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) diff --git a/ftl/FTLInlineCacheSize.h b/ftl/FTLInlineCacheSize.h index 7c7c189..82f3bbc 100644 --- a/ftl/FTLInlineCacheSize.h +++ b/ftl/FTLInlineCacheSize.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,11 +28,24 @@ #if ENABLE(FTL_JIT) -namespace JSC { namespace FTL { +namespace JSC { + +namespace DFG { +struct Node; +} + +namespace FTL { size_t sizeOfGetById(); size_t sizeOfPutById(); size_t sizeOfCall(); +size_t sizeOfCallVarargs(); +size_t sizeOfCallForwardVarargs(); +size_t sizeOfConstructVarargs(); +size_t sizeOfConstructForwardVarargs(); +size_t sizeOfIn(); + +size_t sizeOfICFor(DFG::Node*); } } // namespace JSC::FTL diff --git a/ftl/FTLIntrinsicRepository.h b/ftl/FTLIntrinsicRepository.h index 667e3fb..3e62d30 100644 --- a/ftl/FTLIntrinsicRepository.h +++ b/ftl/FTLIntrinsicRepository.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,12 +35,17 @@ namespace JSC { namespace FTL { #define FOR_EACH_FTL_INTRINSIC(macro) \ + macro(ceil64, "llvm.ceil.f64", functionType(doubleType, doubleType)) \ + macro(ctlz32, "llvm.ctlz.i32", functionType(int32, int32, boolean)) \ macro(addWithOverflow32, "llvm.sadd.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \ macro(addWithOverflow64, "llvm.sadd.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \ macro(doubleAbs, "llvm.fabs.f64", functionType(doubleType, doubleType)) \ macro(doubleSin, "llvm.sin.f64", functionType(doubleType, doubleType)) \ macro(doubleCos, "llvm.cos.f64", functionType(doubleType, doubleType)) \ + macro(doublePow, "llvm.pow.f64", functionType(doubleType, doubleType, doubleType)) \ + macro(doublePowi, "llvm.powi.f64", functionType(doubleType, doubleType, int32)) \ macro(doubleSqrt, "llvm.sqrt.f64", functionType(doubleType, doubleType)) \ + macro(doubleLog, "llvm.log.f64", functionType(doubleType, doubleType)) \ macro(frameAddress, "llvm.frameaddress", functionType(pointerType(int8), int32)) \ macro(mulWithOverflow32, "llvm.smul.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \ macro(mulWithOverflow64, "llvm.smul.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \ @@ -54,19 +59,33 @@ namespace JSC { namespace FTL { #define FOR_EACH_FUNCTION_TYPE(macro) \ macro(C_JITOperation_EC, functionType(intPtr, intPtr, intPtr)) \ + macro(C_JITOperation_ECZ, functionType(intPtr, intPtr, intPtr, int32)) \ + macro(C_JITOperation_ECZC, functionType(intPtr, intPtr, intPtr, int32, intPtr)) \ + macro(C_JITOperation_EGC, functionType(intPtr, intPtr, intPtr, intPtr)) \ macro(C_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \ macro(C_JITOperation_EJssJss, functionType(intPtr, intPtr, intPtr, intPtr)) \ macro(C_JITOperation_EJssJssJss, functionType(intPtr, intPtr, intPtr, intPtr, intPtr)) \ macro(C_JITOperation_ESt, functionType(intPtr, intPtr, intPtr)) \ + macro(C_JITOperation_EStJscSymtab, functionType(intPtr, intPtr, intPtr, intPtr, intPtr)) \ + macro(C_JITOperation_EStRZJsf, functionType(intPtr, intPtr, intPtr, intPtr, int32, intPtr)) \ + macro(C_JITOperation_EStRZJsfL, functionType(intPtr, intPtr, intPtr, intPtr, int32, intPtr, intPtr)) \ + macro(C_JITOperation_EStZ, functionType(intPtr, intPtr, intPtr, int32)) \ + macro(C_JITOperation_EStZZ, functionType(intPtr, intPtr, intPtr, int32, int32)) \ + macro(C_JITOperation_EZ, functionType(intPtr, intPtr, int32)) \ macro(D_JITOperation_D, functionType(doubleType, doubleType)) \ - macro(I_JITOperation_EJss, functionType(intPtr, intPtr, intPtr)) \ + macro(T_JITOperation_EJss, functionType(intPtr, intPtr, intPtr)) \ macro(J_JITOperation_E, functionType(int64, intPtr)) \ macro(J_JITOperation_EA, functionType(int64, intPtr, intPtr)) \ macro(J_JITOperation_EAZ, functionType(int64, intPtr, intPtr, int32)) \ + macro(J_JITOperation_ECJ, functionType(int64, intPtr, intPtr, int64)) \ + macro(J_JITOperation_ECZ, functionType(int64, intPtr, intPtr, int32)) \ macro(J_JITOperation_EDA, functionType(int64, intPtr, doubleType, intPtr)) \ macro(J_JITOperation_EJ, functionType(int64, intPtr, int64)) \ macro(J_JITOperation_EJA, functionType(int64, intPtr, int64, intPtr)) \ + macro(J_JITOperation_EJC, functionType(int64, intPtr, int64, intPtr)) \ + macro(J_JITOperation_EJI, functionType(int64, intPtr, int64, intPtr)) \ macro(J_JITOperation_EJJ, functionType(int64, intPtr, int64, int64)) \ + macro(J_JITOperation_EJscC, functionType(intPtr, intPtr, intPtr, intPtr)) \ macro(J_JITOperation_EJssZ, functionType(int64, intPtr, intPtr, int32)) \ macro(J_JITOperation_ESsiJI, functionType(int64, intPtr, intPtr, int64, intPtr)) \ macro(Jss_JITOperation_EZ, functionType(intPtr, intPtr, int32)) \ @@ -81,6 +100,7 @@ namespace JSC { namespace FTL { macro(P_JITOperation_EStZ, functionType(intPtr, intPtr, intPtr, int32)) \ macro(Q_JITOperation_D, functionType(int64, doubleType)) \ macro(Q_JITOperation_J, functionType(int64, int64)) \ + macro(S_JITOperation_EGC, functionType(intPtr, intPtr, intPtr, intPtr)) \ macro(S_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \ macro(S_JITOperation_EJJ, functionType(intPtr, intPtr, int64, int64)) \ macro(S_JITOperation_J, functionType(intPtr, int64)) \ @@ -90,9 +110,16 @@ namespace JSC { namespace FTL { macro(V_JITOperation_EOZJ, functionType(voidType, intPtr, intPtr, int32, int64)) \ macro(V_JITOperation_EC, functionType(voidType, intPtr, intPtr)) \ macro(V_JITOperation_ECb, functionType(voidType, intPtr, intPtr)) \ - macro(V_JITOperation_EVwsJ, functionType(voidType, intPtr, intPtr, int64)) \ - macro(Z_JITOperation_D, functionType(int32, doubleType)) - + macro(V_JITOperation_EWs, functionType(voidType, intPtr, intPtr)) \ + macro(V_JITOperation_EZJZZZ, functionType(voidType, intPtr, int32, int64, int32, int32, int32)) \ + macro(V_JITOperation_J, functionType(voidType, int64)) \ + macro(V_JITOperation_Z, functionType(voidType, int32)) \ + macro(Z_JITOperation_D, functionType(int32, doubleType)) \ + macro(Z_JITOperation_EC, functionType(int32, intPtr, intPtr)) \ + macro(Z_JITOperation_EGC, functionType(int32, intPtr, intPtr, intPtr)) \ + macro(Z_JITOperation_EJZ, functionType(int32, intPtr, int64, int32)) \ + macro(Z_JITOperation_ESJss, functionType(int32, intPtr, intPtr, int64)) \ + class IntrinsicRepository : public CommonValues { public: IntrinsicRepository(LContext); diff --git a/ftl/FTLJITCode.cpp b/ftl/FTLJITCode.cpp index c031609..6120f05 100644 --- a/ftl/FTLJITCode.cpp +++ b/ftl/FTLJITCode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -125,6 +125,14 @@ DFG::CommonData* JITCode::dfgCommon() return &common; } +void JITCode::validateReferences(const TrackedReferences& trackedReferences) +{ + common.validateReferences(trackedReferences); + + for (OSRExit& exit : osrExit) + exit.validateReferences(trackedReferences); +} + } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) diff --git a/ftl/FTLJITCode.h b/ftl/FTLJITCode.h index 9894d4c..6a4d152 100644 --- a/ftl/FTLJITCode.h +++ b/ftl/FTLJITCode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +37,21 @@ #include "LLVMAPI.h" #include <wtf/RefCountedArray.h> -namespace JSC { namespace FTL { +#if OS(DARWIN) +#define SECTION_NAME_PREFIX "__" +#elif OS(LINUX) +#define SECTION_NAME_PREFIX "." +#else +#error "Unsupported platform" +#endif + +#define SECTION_NAME(NAME) (SECTION_NAME_PREFIX NAME) + +namespace JSC { + +class TrackedReferences; + +namespace FTL { class JITCode : public JSC::JITCode { public: @@ -57,13 +71,15 @@ public: void initializeArityCheckEntrypoint(CodeRef); void initializeAddressForCall(CodePtr); + void validateReferences(const TrackedReferences&) override; + const Vector<RefPtr<ExecutableMemoryHandle>>& handles() const { return m_handles; } const Vector<RefPtr<DataSection>>& dataSections() const { return m_dataSections; } CodePtr exitThunks(); - JITCode* ftl(); - DFG::CommonData* dfgCommon(); + JITCode* ftl() override; + DFG::CommonData* dfgCommon() override; DFG::CommonData common; SegmentedVector<OSRExit, 8> osrExit; diff --git a/ftl/FTLJITFinalizer.cpp b/ftl/FTLJITFinalizer.cpp index 691cf77..3da4848 100644 --- a/ftl/FTLJITFinalizer.cpp +++ b/ftl/FTLJITFinalizer.cpp @@ -127,7 +127,13 @@ bool JITFinalizer::finalizeFunction() toCString(CodeBlockWithJITType(m_plan.codeBlock.get(), JITCode::FTLJIT)).data())) .executableMemory()); } - + + for (unsigned i = 0; i < outOfLineCodeInfos.size(); ++i) { + jitCode->addHandle(FINALIZE_DFG_CODE( + *outOfLineCodeInfos[i].m_linkBuffer, + ("FTL out of line code for %s", outOfLineCodeInfos[i].m_codeDescription)).executableMemory()); + } + jitCode->initializeArityCheckEntrypoint( FINALIZE_DFG_CODE( *entrypointLinkBuffer, diff --git a/ftl/FTLJITFinalizer.h b/ftl/FTLJITFinalizer.h index 97f1b96..a1e0d03 100644 --- a/ftl/FTLJITFinalizer.h +++ b/ftl/FTLJITFinalizer.h @@ -39,19 +39,32 @@ namespace JSC { namespace FTL { +class OutOfLineCodeInfo { +public: + OutOfLineCodeInfo(std::unique_ptr<LinkBuffer> linkBuffer, const char* codeDescription) + : m_linkBuffer(WTF::move(linkBuffer)) + , m_codeDescription(codeDescription) + { + } + + std::unique_ptr<LinkBuffer> m_linkBuffer; + const char* m_codeDescription; +}; + class JITFinalizer : public DFG::Finalizer { public: JITFinalizer(DFG::Plan&); virtual ~JITFinalizer(); - + size_t codeSize() override; bool finalize() override; bool finalizeFunction() override; - OwnPtr<LinkBuffer> exitThunksLinkBuffer; - OwnPtr<LinkBuffer> entrypointLinkBuffer; - OwnPtr<LinkBuffer> sideCodeLinkBuffer; - OwnPtr<LinkBuffer> handleExceptionsLinkBuffer; + std::unique_ptr<LinkBuffer> exitThunksLinkBuffer; + std::unique_ptr<LinkBuffer> entrypointLinkBuffer; + std::unique_ptr<LinkBuffer> sideCodeLinkBuffer; + std::unique_ptr<LinkBuffer> handleExceptionsLinkBuffer; + Vector<OutOfLineCodeInfo> outOfLineCodeInfos; Vector<SlowPathCall> slowPathCalls; // Calls inside the side code. Vector<OSRExitCompilationInfo> osrExit; GeneratedFunction function; diff --git a/ftl/FTLJSCall.cpp b/ftl/FTLJSCall.cpp index 76cd2dc..e6f6bda 100644 --- a/ftl/FTLJSCall.cpp +++ b/ftl/FTLJSCall.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,66 +33,22 @@ namespace JSC { namespace FTL { +using namespace DFG; + JSCall::JSCall() : m_stackmapID(UINT_MAX) - , m_node(nullptr) - , m_callLinkInfo(nullptr) , m_instructionOffset(UINT_MAX) { } -JSCall::JSCall(unsigned stackmapID, DFG::Node* node) - : m_stackmapID(stackmapID) - , m_node(node) - , m_callLinkInfo(nullptr) +JSCall::JSCall(unsigned stackmapID, Node* node) + : JSCallBase( + node->op() == Construct ? CallLinkInfo::Construct : CallLinkInfo::Call, + node->origin.semantic) + , m_stackmapID(stackmapID) , m_instructionOffset(0) { -} - -void JSCall::emit(CCallHelpers& jit) -{ - m_callLinkInfo = jit.codeBlock()->addCallLinkInfo(); - - CCallHelpers::Jump slowPath = jit.branchPtrWithPatch( - CCallHelpers::NotEqual, GPRInfo::regT0, m_targetToCheck, - CCallHelpers::TrustedImmPtr(0)); - - jit.loadPtr( - CCallHelpers::Address(GPRInfo::regT0, JSFunction::offsetOfScopeChain()), - GPRInfo::regT1); - jit.store64( - GPRInfo::regT1, - CCallHelpers::Address( - CCallHelpers::stackPointerRegister, - sizeof(Register) * (JSStack::ScopeChain - JSStack::CallerFrameAndPCSize))); - - m_fastCall = jit.nearCall(); - CCallHelpers::Jump done = jit.jump(); - - slowPath.link(&jit); - - jit.move(CCallHelpers::TrustedImmPtr(m_callLinkInfo), GPRInfo::regT2); - m_slowCall = jit.nearCall(); - - done.link(&jit); -} - -void JSCall::link(VM& vm, LinkBuffer& linkBuffer) -{ - ThunkGenerator generator = linkThunkGeneratorFor( - m_node->op() == DFG::Construct ? CodeForConstruct : CodeForCall, - MustPreserveRegisters); - - linkBuffer.link( - m_slowCall, FunctionPtr(vm.getCTIStub(generator).code().executableAddress())); - - m_callLinkInfo->isFTL = true; - m_callLinkInfo->callType = m_node->op() == DFG::Construct ? CallLinkInfo::Construct : CallLinkInfo::Call; - m_callLinkInfo->codeOrigin = m_node->origin.semantic; - m_callLinkInfo->callReturnLocation = linkBuffer.locationOfNearCall(m_slowCall); - m_callLinkInfo->hotPathBegin = linkBuffer.locationOf(m_targetToCheck); - m_callLinkInfo->hotPathOther = linkBuffer.locationOfNearCall(m_fastCall); - m_callLinkInfo->calleeGPR = GPRInfo::regT0; + ASSERT(node->op() == Call || node->op() == Construct); } } } // namespace JSC::FTL diff --git a/ftl/FTLJSCall.h b/ftl/FTLJSCall.h index bc2758d..2f5e64a 100644 --- a/ftl/FTLJSCall.h +++ b/ftl/FTLJSCall.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,28 +28,21 @@ #if ENABLE(FTL_JIT) -#include "CCallHelpers.h" -#include "CallLinkInfo.h" -#include "CodeOrigin.h" +#include "FTLJSCallBase.h" namespace JSC { -class LinkBuffer; - namespace DFG { struct Node; } namespace FTL { -class JSCall { +class JSCall : public JSCallBase { public: JSCall(); JSCall(unsigned stackmapID, DFG::Node*); - void emit(CCallHelpers&); - void link(VM&, LinkBuffer&); - unsigned stackmapID() const { return m_stackmapID; } bool operator<(const JSCall& other) const @@ -59,11 +52,6 @@ public: private: unsigned m_stackmapID; - DFG::Node* m_node; - CCallHelpers::DataLabelPtr m_targetToCheck; - CCallHelpers::Call m_fastCall; - CCallHelpers::Call m_slowCall; - CallLinkInfo* m_callLinkInfo; public: uint32_t m_instructionOffset; diff --git a/ftl/FTLJSCallBase.cpp b/ftl/FTLJSCallBase.cpp new file mode 100644 index 0000000..3279093 --- /dev/null +++ b/ftl/FTLJSCallBase.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 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 "FTLJSCallBase.h" + +#if ENABLE(FTL_JIT) + +#include "DFGNode.h" +#include "LinkBuffer.h" + +namespace JSC { namespace FTL { + +using namespace DFG; + +JSCallBase::JSCallBase() + : m_type(CallLinkInfo::None) + , m_callLinkInfo(nullptr) +{ +} + +JSCallBase::JSCallBase(CallLinkInfo::CallType type, CodeOrigin origin) + : m_type(type) + , m_origin(origin) + , m_callLinkInfo(nullptr) +{ +} + +void JSCallBase::emit(CCallHelpers& jit) +{ + m_callLinkInfo = jit.codeBlock()->addCallLinkInfo(); + + CCallHelpers::Jump slowPath = jit.branchPtrWithPatch( + CCallHelpers::NotEqual, GPRInfo::regT0, m_targetToCheck, + CCallHelpers::TrustedImmPtr(0)); + + m_fastCall = jit.nearCall(); + CCallHelpers::Jump done = jit.jump(); + + slowPath.link(&jit); + + jit.move(CCallHelpers::TrustedImmPtr(m_callLinkInfo), GPRInfo::regT2); + m_slowCall = jit.nearCall(); + + done.link(&jit); +} + +void JSCallBase::link(VM& vm, LinkBuffer& linkBuffer) +{ + ThunkGenerator generator = linkThunkGeneratorFor( + CallLinkInfo::specializationKindFor(m_type), MustPreserveRegisters); + + linkBuffer.link( + m_slowCall, FunctionPtr(vm.getCTIStub(generator).code().executableAddress())); + + m_callLinkInfo->setUpCallFromFTL(m_type, m_origin, linkBuffer.locationOfNearCall(m_slowCall), + linkBuffer.locationOf(m_targetToCheck), linkBuffer.locationOfNearCall(m_fastCall), + GPRInfo::regT0); +} + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + diff --git a/ftl/FTLJSCallBase.h b/ftl/FTLJSCallBase.h new file mode 100644 index 0000000..595ac69 --- /dev/null +++ b/ftl/FTLJSCallBase.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 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 FTLJSCallBase_h +#define FTLJSCallBase_h + +#if ENABLE(FTL_JIT) + +#include "CCallHelpers.h" +#include "CallLinkInfo.h" +#include "CodeOrigin.h" + +namespace JSC { + +class LinkBuffer; + +namespace DFG { +struct Node; +} + +namespace FTL { + +class JSCallBase { +public: + JSCallBase(); + JSCallBase(CallLinkInfo::CallType, CodeOrigin); + + void emit(CCallHelpers&); + void link(VM&, LinkBuffer&); + +private: + CallLinkInfo::CallType m_type; + CodeOrigin m_origin; + CCallHelpers::DataLabelPtr m_targetToCheck; + CCallHelpers::Call m_fastCall; + CCallHelpers::Call m_slowCall; + CallLinkInfo* m_callLinkInfo; +}; + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + +#endif // FTLJSCallBase_h + diff --git a/ftl/FTLJSCallVarargs.cpp b/ftl/FTLJSCallVarargs.cpp new file mode 100644 index 0000000..ac87a3c --- /dev/null +++ b/ftl/FTLJSCallVarargs.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2015 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 "FTLJSCallVarargs.h" + +#if ENABLE(FTL_JIT) + +#include "DFGNode.h" +#include "DFGOperations.h" +#include "JSCInlines.h" +#include "LinkBuffer.h" +#include "ScratchRegisterAllocator.h" +#include "SetupVarargsFrame.h" + +namespace JSC { namespace FTL { + +using namespace DFG; + +JSCallVarargs::JSCallVarargs() + : m_stackmapID(UINT_MAX) + , m_node(nullptr) + , m_instructionOffset(UINT_MAX) +{ +} + +JSCallVarargs::JSCallVarargs(unsigned stackmapID, Node* node) + : m_stackmapID(stackmapID) + , m_node(node) + , m_callBase( + (node->op() == ConstructVarargs || node->op() == ConstructForwardVarargs) + ? CallLinkInfo::ConstructVarargs : CallLinkInfo::CallVarargs, + node->origin.semantic) + , m_instructionOffset(0) +{ + ASSERT( + node->op() == CallVarargs || node->op() == CallForwardVarargs + || node->op() == ConstructVarargs || node->op() == ConstructForwardVarargs); +} + +unsigned JSCallVarargs::numSpillSlotsNeeded() +{ + return 4; +} + +void JSCallVarargs::emit(CCallHelpers& jit, int32_t spillSlotsOffset) +{ + // We are passed three pieces of information: + // - The callee. + // - The arguments object, if it's not a forwarding call. + // - The "this" value, if it's a constructor call. + + CallVarargsData* data = m_node->callVarargsData(); + + GPRReg calleeGPR = GPRInfo::argumentGPR0; + + GPRReg argumentsGPR = InvalidGPRReg; + GPRReg thisGPR = InvalidGPRReg; + + bool forwarding = false; + + switch (m_node->op()) { + case CallVarargs: + case ConstructVarargs: + argumentsGPR = GPRInfo::argumentGPR1; + thisGPR = GPRInfo::argumentGPR2; + break; + case CallForwardVarargs: + case ConstructForwardVarargs: + thisGPR = GPRInfo::argumentGPR1; + forwarding = true; + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + + const unsigned calleeSpillSlot = 0; + const unsigned argumentsSpillSlot = 1; + const unsigned thisSpillSlot = 2; + const unsigned stackPointerSpillSlot = 3; + + // Get some scratch registers. + RegisterSet usedRegisters; + usedRegisters.merge(RegisterSet::stackRegisters()); + usedRegisters.merge(RegisterSet::reservedHardwareRegisters()); + usedRegisters.merge(RegisterSet::calleeSaveRegisters()); + usedRegisters.set(calleeGPR); + if (argumentsGPR != InvalidGPRReg) + usedRegisters.set(argumentsGPR); + ASSERT(thisGPR); + usedRegisters.set(thisGPR); + ScratchRegisterAllocator allocator(usedRegisters); + GPRReg scratchGPR1 = allocator.allocateScratchGPR(); + GPRReg scratchGPR2 = allocator.allocateScratchGPR(); + GPRReg scratchGPR3 = allocator.allocateScratchGPR(); + + RELEASE_ASSERT(!allocator.numberOfReusedRegisters()); + + auto computeUsedStack = [&] (GPRReg targetGPR, unsigned extra) { + if (isARM64()) { + // Have to do this the weird way because $sp on ARM64 means zero when used in a subtraction. + jit.move(CCallHelpers::stackPointerRegister, targetGPR); + jit.negPtr(targetGPR); + jit.addPtr(GPRInfo::callFrameRegister, targetGPR); + } else { + jit.move(GPRInfo::callFrameRegister, targetGPR); + jit.subPtr(CCallHelpers::stackPointerRegister, targetGPR); + } + if (extra) + jit.subPtr(CCallHelpers::TrustedImm32(extra), targetGPR); + jit.urshiftPtr(CCallHelpers::Imm32(3), targetGPR); + }; + + auto callWithExceptionCheck = [&] (void* callee) { + jit.move(CCallHelpers::TrustedImmPtr(callee), GPRInfo::nonPreservedNonArgumentGPR); + jit.call(GPRInfo::nonPreservedNonArgumentGPR); + m_exceptions.append(jit.emitExceptionCheck(AssemblyHelpers::NormalExceptionCheck, AssemblyHelpers::FarJumpWidth)); + }; + + if (isARM64()) { + jit.move(CCallHelpers::stackPointerRegister, scratchGPR1); + jit.storePtr(scratchGPR1, CCallHelpers::addressFor(spillSlotsOffset + stackPointerSpillSlot)); + } else + jit.storePtr(CCallHelpers::stackPointerRegister, CCallHelpers::addressFor(spillSlotsOffset + stackPointerSpillSlot)); + + unsigned extraStack = sizeof(CallerFrameAndPC) + + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(void*)); + + if (forwarding) { + CCallHelpers::JumpList slowCase; + computeUsedStack(scratchGPR2, 0); + emitSetupVarargsFrameFastCase(jit, scratchGPR2, scratchGPR1, scratchGPR2, scratchGPR3, m_node->child2()->origin.semantic.inlineCallFrame, data->firstVarArgOffset, slowCase); + + CCallHelpers::Jump done = jit.jump(); + slowCase.link(&jit); + jit.subPtr(CCallHelpers::TrustedImm32(extraStack), CCallHelpers::stackPointerRegister); + jit.setupArgumentsExecState(); + callWithExceptionCheck(bitwise_cast<void*>(operationThrowStackOverflowForVarargs)); + jit.abortWithReason(DFGVarargsThrowingPathDidNotThrow); + + done.link(&jit); + jit.move(calleeGPR, GPRInfo::regT0); + } else { + // Gotta spill the callee, arguments, and this because we will need them later and we will have some + // calls that clobber them. + jit.store64(calleeGPR, CCallHelpers::addressFor(spillSlotsOffset + calleeSpillSlot)); + jit.store64(argumentsGPR, CCallHelpers::addressFor(spillSlotsOffset + argumentsSpillSlot)); + jit.store64(thisGPR, CCallHelpers::addressFor(spillSlotsOffset + thisSpillSlot)); + + computeUsedStack(scratchGPR1, 0); + jit.subPtr(CCallHelpers::TrustedImm32(extraStack), CCallHelpers::stackPointerRegister); + jit.setupArgumentsWithExecState(argumentsGPR, scratchGPR1, CCallHelpers::TrustedImm32(data->firstVarArgOffset)); + callWithExceptionCheck(bitwise_cast<void*>(operationSizeFrameForVarargs)); + + jit.move(GPRInfo::returnValueGPR, scratchGPR1); + computeUsedStack(scratchGPR2, extraStack); + jit.load64(CCallHelpers::addressFor(spillSlotsOffset + argumentsSpillSlot), argumentsGPR); + emitSetVarargsFrame(jit, scratchGPR1, false, scratchGPR2, scratchGPR2); + jit.addPtr(CCallHelpers::TrustedImm32(-extraStack), scratchGPR2, CCallHelpers::stackPointerRegister); + jit.setupArgumentsWithExecState(scratchGPR2, argumentsGPR, CCallHelpers::TrustedImm32(data->firstVarArgOffset), scratchGPR1); + callWithExceptionCheck(bitwise_cast<void*>(operationSetupVarargsFrame)); + + jit.move(GPRInfo::returnValueGPR, scratchGPR2); + + jit.load64(CCallHelpers::addressFor(spillSlotsOffset + thisSpillSlot), thisGPR); + jit.load64(CCallHelpers::addressFor(spillSlotsOffset + calleeSpillSlot), GPRInfo::regT0); + } + + jit.addPtr(CCallHelpers::TrustedImm32(sizeof(CallerFrameAndPC)), scratchGPR2, CCallHelpers::stackPointerRegister); + + jit.store64(thisGPR, CCallHelpers::calleeArgumentSlot(0)); + + // Henceforth we make the call. The base FTL call machinery expects the callee in regT0 and for the + // stack frame to already be set up, which it is. + jit.store64(GPRInfo::regT0, CCallHelpers::calleeFrameSlot(JSStack::Callee)); + + m_callBase.emit(jit); + + // Undo the damage we've done. + if (isARM64()) { + GPRReg scratchGPRAtReturn = CCallHelpers::selectScratchGPR(GPRInfo::returnValueGPR); + jit.loadPtr(CCallHelpers::addressFor(spillSlotsOffset + stackPointerSpillSlot), scratchGPRAtReturn); + jit.move(scratchGPRAtReturn, CCallHelpers::stackPointerRegister); + } else + jit.loadPtr(CCallHelpers::addressFor(spillSlotsOffset + stackPointerSpillSlot), CCallHelpers::stackPointerRegister); +} + +void JSCallVarargs::link(VM& vm, LinkBuffer& linkBuffer, CodeLocationLabel exceptionHandler) +{ + m_callBase.link(vm, linkBuffer); + linkBuffer.link(m_exceptions, exceptionHandler); +} + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + diff --git a/ftl/FTLJSCallVarargs.h b/ftl/FTLJSCallVarargs.h new file mode 100644 index 0000000..5128ff8 --- /dev/null +++ b/ftl/FTLJSCallVarargs.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 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 FTLJSCallVarargs_h +#define FTLJSCallVarargs_h + +#if ENABLE(FTL_JIT) + +#include "FTLJSCallBase.h" + +namespace JSC { + +class LinkBuffer; + +namespace DFG { +struct Node; +} + +namespace FTL { + +class JSCallVarargs { +public: + JSCallVarargs(); + JSCallVarargs(unsigned stackmapID, DFG::Node*); + + DFG::Node* node() const { return m_node; } + + static unsigned numSpillSlotsNeeded(); + + void emit(CCallHelpers&, int32_t spillSlotsOffset); + void link(VM&, LinkBuffer&, CodeLocationLabel exceptionHandler); + + unsigned stackmapID() const { return m_stackmapID; } + + bool operator<(const JSCallVarargs& other) const + { + return m_instructionOffset < other.m_instructionOffset; + } + +private: + unsigned m_stackmapID; + DFG::Node* m_node; + JSCallBase m_callBase; + CCallHelpers::JumpList m_exceptions; + +public: + uint32_t m_instructionOffset; +}; + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + +#endif // FTLJSCallVarargs_h + diff --git a/ftl/FTLLink.cpp b/ftl/FTLLink.cpp index d23cece..188afe5 100644 --- a/ftl/FTLLink.cpp +++ b/ftl/FTLLink.cpp @@ -63,11 +63,13 @@ void link(State& state) if (!graph.m_plan.inlineCallFrames->isEmpty()) state.jitCode->common.inlineCallFrames = graph.m_plan.inlineCallFrames; + graph.registerFrozenValues(); + // Create the entrypoint. Note that we use this entrypoint totally differently // depending on whether we're doing OSR entry or not. CCallHelpers jit(&vm, codeBlock); - OwnPtr<LinkBuffer> linkBuffer; + std::unique_ptr<LinkBuffer> linkBuffer; CCallHelpers::Address frame = CCallHelpers::Address( CCallHelpers::stackPointerRegister, -static_cast<int32_t>(AssemblyHelpers::prologueStackPointerDelta())); @@ -96,8 +98,6 @@ void link(State& state) for (size_t nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { Node* node = block->at(nodeIndex); - if (!node->willHaveCodeGenOrOSR() && !Options::showAllDFGNodes()) - continue; Profiler::OriginStack stack; @@ -126,13 +126,13 @@ void link(State& state) out.print(" Disassembly:\n"); for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) { - if (state.codeSectionNames[i] != "__text") + if (state.codeSectionNames[i] != SECTION_NAME("text")) continue; - ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get(); - disassemble( - MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(), - " ", out, LLVMSubset); + ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get(); + disassemble( + MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(), + " ", out, LLVMSubset); } compilation->addDescription(Profiler::OriginStack(), out.toCString()); out.reset(); @@ -169,15 +169,21 @@ void link(State& state) jit.emitFunctionEpilogue(); mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0)); jit.emitFunctionPrologue(); - jit.move(CCallHelpers::TrustedImmPtr(vm.arityCheckFailReturnThunks->returnPCsFor(vm, codeBlock->numParameters())), GPRInfo::regT7); + CodeLocationLabel* arityThunkLabels = + vm.arityCheckFailReturnThunks->returnPCsFor(vm, codeBlock->numParameters()); + jit.move(CCallHelpers::TrustedImmPtr(arityThunkLabels), GPRInfo::regT7); jit.loadPtr(CCallHelpers::BaseIndex(GPRInfo::regT7, GPRInfo::regT0, CCallHelpers::timesPtr()), GPRInfo::regT7); CCallHelpers::Call callArityFixup = jit.call(); jit.emitFunctionEpilogue(); mainPathJumps.append(jit.jump()); - linkBuffer = adoptPtr(new LinkBuffer(vm, jit, codeBlock, JITCompilationMustSucceed)); + linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail); + if (linkBuffer->didFailToAllocate()) { + state.allocationFailed = true; + return; + } linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck); - linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixup)).code().executableAddress())); + linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress())); linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction))); state.jitCode->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction))); @@ -193,7 +199,11 @@ void link(State& state) jit.emitFunctionEpilogue(); CCallHelpers::Jump mainPathJump = jit.jump(); - linkBuffer = adoptPtr(new LinkBuffer(vm, jit, codeBlock, JITCompilationMustSucceed)); + linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail); + if (linkBuffer->didFailToAllocate()) { + state.allocationFailed = true; + return; + } linkBuffer->link(mainPathJump, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction))); state.jitCode->initializeAddressForCall(linkBuffer->locationOf(start)); @@ -205,7 +215,7 @@ void link(State& state) break; } - state.finalizer->entrypointLinkBuffer = linkBuffer.release(); + state.finalizer->entrypointLinkBuffer = WTF::move(linkBuffer); state.finalizer->function = state.generatedFunction; state.finalizer->jitCode = state.jitCode; } diff --git a/ftl/FTLLowerDFGToLLVM.cpp b/ftl/FTLLowerDFGToLLVM.cpp index ecb1513..64b0abd 100644 --- a/ftl/FTLLowerDFGToLLVM.cpp +++ b/ftl/FTLLowerDFGToLLVM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 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,26 +31,59 @@ #include "CodeBlockWithJITType.h" #include "DFGAbstractInterpreterInlines.h" #include "DFGInPlaceAbstractState.h" +#include "DFGOSRAvailabilityAnalysisPhase.h" +#include "DFGOSRExitFuzz.h" +#include "DirectArguments.h" #include "FTLAbstractHeapRepository.h" #include "FTLAvailableRecovery.h" #include "FTLForOSREntryJITCode.h" #include "FTLFormattedValue.h" #include "FTLInlineCacheSize.h" #include "FTLLoweredNodeValue.h" +#include "FTLOperations.h" #include "FTLOutput.h" #include "FTLThunks.h" #include "FTLWeightedTarget.h" -#include "OperandsInlines.h" #include "JSCInlines.h" +#include "JSLexicalEnvironment.h" +#include "OperandsInlines.h" +#include "ScopedArguments.h" +#include "ScopedArgumentsTable.h" #include "VirtualRegister.h" #include <atomic> +#include <dlfcn.h> +#include <llvm/InitializeLLVM.h> +#include <unordered_set> #include <wtf/ProcessID.h> +#if ENABLE(FTL_NATIVE_CALL_INLINING) +#include "BundlePath.h" +#endif + namespace JSC { namespace FTL { using namespace DFG; -static std::atomic<int> compileCounter; +namespace { + +std::atomic<int> compileCounter; + +#if ASSERT_DISABLED +NO_RETURN_DUE_TO_CRASH static void ftlUnreachable() +{ + CRASH(); +} +#else +NO_RETURN_DUE_TO_CRASH static void ftlUnreachable( + CodeBlock* codeBlock, BlockIndex blockIndex, unsigned nodeIndex) +{ + dataLog("Crashing in thought-to-be-unreachable FTL-generated code for ", pointerDump(codeBlock), " at basic block #", blockIndex); + if (nodeIndex != UINT_MAX) + dataLog(", node @", nodeIndex); + dataLog(".\n"); + CRASH(); +} +#endif // Using this instead of typeCheck() helps to reduce the load on LLVM, by creating // significantly less dead code. @@ -68,21 +101,17 @@ public: LowerDFGToLLVM(State& state) : m_graph(state.graph) , m_ftlState(state) - , m_loweringSucceeded(true) , m_heaps(state.context) , m_out(state.context) - , m_availability(OperandsLike, state.graph.block(0)->variablesAtHead) , m_state(state.graph) , m_interpreter(state.graph, m_state) , m_stackmapIDs(0) + , m_tbaaKind(mdKindID(state.context, "tbaa")) + , m_tbaaStructKind(mdKindID(state.context, "tbaa.struct")) { } - - -#define LOWERING_FAILED(node, reason) \ - loweringFailed((node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, (reason)); - - bool lower() + + void lower() { CString name; if (verboseCompilationEnabled()) { @@ -95,7 +124,7 @@ public: m_graph.m_dominators.computeIfNecessary(m_graph); m_ftlState.module = - llvm->ModuleCreateWithNameInContext(name.data(), m_ftlState.context); + moduleCreateWithNameInContext(name.data(), m_ftlState.context); m_ftlState.function = addFunction( m_ftlState.module, name.data(), functionType(m_out.int64)); @@ -114,6 +143,8 @@ public: m_prologue = FTL_NEW_BLOCK(m_out, ("Prologue")); LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, ("Stack overflow")); m_handleExceptions = FTL_NEW_BLOCK(m_out, ("Handle Exceptions")); + + LBasicBlock checkArguments = FTL_NEW_BLOCK(m_out, ("Check arguments")); for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { m_highBlock = m_graph.block(blockIndex); @@ -124,19 +155,71 @@ public: m_out.appendTo(m_prologue, stackOverflow); createPhiVariables(); + + auto preOrder = m_graph.blocksInPreOrder(); + + int maxNumberOfArguments = -1; + for (BasicBlock* block : preOrder) { + for (unsigned nodeIndex = block->size(); nodeIndex--; ) { + Node* node = block->at(nodeIndex); + switch (node->op()) { + case NativeCall: + case NativeConstruct: { + int numArgs = node->numChildren(); + if (numArgs > maxNumberOfArguments) + maxNumberOfArguments = numArgs; + break; + } + default: + break; + } + } + } + + if (maxNumberOfArguments >= 0) { + m_execState = m_out.alloca(arrayType(m_out.int64, JSStack::CallFrameHeaderSize + maxNumberOfArguments)); + m_execStorage = m_out.ptrToInt(m_execState, m_out.intPtr); + } + LValue capturedAlloca = m_out.alloca(arrayType(m_out.int64, m_graph.m_nextMachineLocal)); + m_captured = m_out.add( m_out.ptrToInt(capturedAlloca, m_out.intPtr), m_out.constIntPtr(m_graph.m_nextMachineLocal * sizeof(Register))); - // We should not create any alloca's after this point, since they will cease to - // be mem2reg candidates. - m_ftlState.capturedStackmapID = m_stackmapIDs++; m_out.call( m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.capturedStackmapID), m_out.int32Zero, capturedAlloca); + // If we have any CallVarargs then we nee to have a spill slot for it. + bool hasVarargs = false; + for (BasicBlock* block : preOrder) { + for (Node* node : *block) { + switch (node->op()) { + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: + hasVarargs = true; + break; + default: + break; + } + } + } + if (hasVarargs) { + LValue varargsSpillSlots = m_out.alloca( + arrayType(m_out.int64, JSCallVarargs::numSpillSlotsNeeded())); + m_ftlState.varargsSpillSlotsStackmapID = m_stackmapIDs++; + m_out.call( + m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.varargsSpillSlotsStackmapID), + m_out.int32Zero, varargsSpillSlots); + } + + // We should not create any alloca's after this point, since they will cease to + // be mem2reg candidates. + m_callFrame = m_out.ptrToInt( m_out.call(m_out.frameAddressIntrinsic(), m_out.int32Zero), m_out.intPtr); m_tagTypeNumber = m_out.constInt64(TagTypeNumber); @@ -145,7 +228,7 @@ public: m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock)); m_out.branch( - didOverflowStack(), rarely(stackOverflow), usually(lowBlock(m_graph.block(0)))); + didOverflowStack(), rarely(stackOverflow), usually(checkArguments)); m_out.appendTo(stackOverflow, m_handleExceptions); m_out.call(m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock())); @@ -155,23 +238,60 @@ public: m_out.constInt32(MacroAssembler::maxJumpReplacementSize())); m_out.unreachable(); - m_out.appendTo(m_handleExceptions, lowBlock(m_graph.block(0))); + m_out.appendTo(m_handleExceptions, checkArguments); m_ftlState.handleExceptionStackmapID = m_stackmapIDs++; m_out.call( m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID), m_out.constInt32(MacroAssembler::maxJumpReplacementSize())); m_out.unreachable(); - if (!m_loweringSucceeded) - return m_loweringSucceeded; - - Vector<BasicBlock*> depthFirst; - m_graph.getBlocksInDepthFirstOrder(depthFirst); - for (unsigned i = 0; i < depthFirst.size(); ++i) { - compileBlock(depthFirst[i]); - if (!m_loweringSucceeded) - return m_loweringSucceeded; + m_out.appendTo(checkArguments, lowBlock(m_graph.block(0))); + availabilityMap().clear(); + availabilityMap().m_locals = Operands<Availability>(codeBlock()->numParameters(), 0); + for (unsigned i = codeBlock()->numParameters(); i--;) { + availabilityMap().m_locals.argument(i) = + Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i))); + } + m_codeOriginForExitTarget = CodeOrigin(0); + m_codeOriginForExitProfile = CodeOrigin(0); + m_node = nullptr; + for (unsigned i = codeBlock()->numParameters(); i--;) { + Node* node = m_graph.m_arguments[i]; + VirtualRegister operand = virtualRegisterForArgument(i); + + LValue jsValue = m_out.load64(addressFor(operand)); + + if (node) { + DFG_ASSERT(m_graph, node, operand == node->stackAccessData()->machineLocal); + + // This is a hack, but it's an effective one. It allows us to do CSE on the + // primordial load of arguments. This assumes that the GetLocal that got put in + // place of the original SetArgument doesn't have any effects before it. This + // should hold true. + m_loadedArgumentValues.add(node, jsValue); + } + + switch (m_graph.m_argumentFormats[i]) { + case FlushedInt32: + speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue)); + break; + case FlushedBoolean: + speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue)); + break; + case FlushedCell: + speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue)); + break; + case FlushedJSValue: + break; + default: + DFG_CRASH(m_graph, node, "Bad flush format for argument"); + break; + } } + m_out.jump(lowBlock(m_graph.block(0))); + + for (BasicBlock* block : preOrder) + compileBlock(block); if (Options::dumpLLVMIR()) dumpModule(m_ftlState.module); @@ -180,8 +300,6 @@ public: m_ftlState.dumpState("after lowering"); if (validationEnabled()) verifyModule(m_ftlState.module); - - return m_loweringSucceeded; } private: @@ -214,8 +332,8 @@ private: type = m_out.int64; break; default: - LOWERING_FAILED(node, "Bad Phi node result type"); - return; + DFG_CRASH(m_graph, node, "Bad Phi node result type"); + break; } m_phis.add(node, buildAlloca(m_out.m_builder, type)); } @@ -249,14 +367,16 @@ private: m_out.appendTo(lowBlock, m_nextLowBlock); if (Options::ftlCrashes()) - m_out.crashNonTerminal(); + m_out.trap(); if (!m_highBlock->cfaHasVisited) { - m_out.crash(); + if (verboseCompilationEnabled()) + dataLog("Bailing because CFA didn't reach.\n"); + crash(m_highBlock->index, UINT_MAX); return; } - initializeOSRExitStateForBlock(); + m_availabilityCalculator.beginBlock(m_highBlock); m_state.reset(); m_state.beginBasicBlock(m_highBlock); @@ -266,11 +386,34 @@ private: break; } } - + + void safelyInvalidateAfterTermination() + { + if (verboseCompilationEnabled()) + dataLog("Bailing.\n"); + crash(); + + // Invalidate dominated blocks. Under normal circumstances we would expect + // them to be invalidated already. But you can have the CFA become more + // precise over time because the structures of objects change on the main + // thread. Failing to do this would result in weird crashes due to a value + // being used but not defined. Race conditions FTW! + for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { + BasicBlock* target = m_graph.block(blockIndex); + if (!target) + continue; + if (m_graph.m_dominators.dominates(m_highBlock, target)) { + if (verboseCompilationEnabled()) + dataLog("Block ", *target, " will bail also.\n"); + target->cfaHasVisited = false; + } + } + } + bool compileNode(unsigned nodeIndex) { if (!m_state.isValid()) { - m_out.unreachable(); + safelyInvalidateAfterTermination(); return false; } @@ -283,7 +426,7 @@ private: m_availableRecoveries.resize(0); - bool shouldExecuteEffects = m_interpreter.startExecuting(m_node); + m_interpreter.startExecuting(); switch (m_node->op()) { case Upsilon: @@ -300,15 +443,12 @@ private: case Int52Constant: compileInt52Constant(); break; - case WeakJSConstant: - compileWeakJSConstant(); - break; - case PhantomArguments: - compilePhantomArguments(); - break; case DoubleRep: compileDoubleRep(); break; + case DoubleAsInt32: + compileDoubleAsInt32(); + break; case ValueRep: compileValueRep(); break; @@ -321,33 +461,17 @@ private: case BooleanToNumber: compileBooleanToNumber(); break; - case GetArgument: - compileGetArgument(); - break; case ExtractOSREntryLocal: compileExtractOSREntryLocal(); break; - case GetLocal: - compileGetLocal(); - break; - case SetLocal: - compileSetLocal(); - break; - case MovHint: - compileMovHint(); - break; - case GetMyArgumentsLength: - compileGetMyArgumentsLength(); - break; - case GetMyArgumentByVal: - compileGetMyArgumentByVal(); + case GetStack: + compileGetStack(); break; - case ZombieHint: - compileZombieHint(); + case PutStack: + compilePutStack(); break; - case Phantom: - case HardPhantom: - compilePhantom(); + case Check: + compileNoOp(); break; case ToThis: compileToThis(); @@ -359,6 +483,9 @@ private: case ArithSub: compileArithAddOrSub(); break; + case ArithClz32: + compileArithClz32(); + break; case ArithMul: compileArithMul(); break; @@ -381,9 +508,18 @@ private: case ArithCos: compileArithCos(); break; + case ArithPow: + compileArithPow(); + break; + case ArithRound: + compileArithRound(); + break; case ArithSqrt: compileArithSqrt(); break; + case ArithLog: + compileArithLog(); + break; case ArithFRound: compileArithFRound(); break; @@ -414,14 +550,17 @@ private: case CheckStructure: compileCheckStructure(); break; - case StructureTransitionWatchpoint: - compileStructureTransitionWatchpoint(); + case CheckCell: + compileCheckCell(); + break; + case CheckNotEmpty: + compileCheckNotEmpty(); break; - case CheckFunction: - compileCheckFunction(); + case CheckBadCell: + compileCheckBadCell(); break; - case CheckExecutable: - compileCheckExecutable(); + case GetExecutable: + compileGetExecutable(); break; case ArrayifyToStructure: compileArrayifyToStructure(); @@ -429,14 +568,14 @@ private: case PutStructure: compilePutStructure(); break; - case PhantomPutStructure: - compilePhantomPutStructure(); - break; case GetById: compileGetById(); break; - case PutByIdDirect: + case In: + compileIn(); + break; case PutById: + case PutByIdDirect: compilePutById(); break; case GetButterfly: @@ -460,6 +599,9 @@ private: case GetByVal: compileGetByVal(); break; + case GetMyArgumentByVal: + compileGetMyArgumentByVal(); + break; case PutByVal: case PutByValAlias: case PutByValDirect: @@ -471,6 +613,21 @@ private: case ArrayPop: compileArrayPop(); break; + case CreateActivation: + compileCreateActivation(); + break; + case NewFunction: + compileNewFunction(); + break; + case CreateDirectArguments: + compileCreateDirectArguments(); + break; + case CreateScopedArguments: + compileCreateScopedArguments(); + break; + case CreateClonedArguments: + compileCreateClonedArguments(); + break; case NewObject: compileNewObject(); break; @@ -493,7 +650,8 @@ private: compileReallocatePropertyStorage(); break; case ToString: - compileToString(); + case CallStringConstructor: + compileToStringOrCallStringConstructor(); break; case ToPrimitive: compileToPrimitive(); @@ -508,8 +666,15 @@ private: compileStringCharCodeAt(); break; case GetByOffset: + case GetGetterSetterByOffset: compileGetByOffset(); break; + case GetGetter: + compileGetGetter(); + break; + case GetSetter: + compileGetSetter(); + break; case MultiGetByOffset: compileMultiGetByOffset(); break; @@ -531,24 +696,27 @@ private: case GetCallee: compileGetCallee(); break; + case GetArgumentCount: + compileGetArgumentCount(); + break; case GetScope: compileGetScope(); break; - case GetMyScope: - compileGetMyScope(); - break; case SkipScope: compileSkipScope(); break; - case GetClosureRegisters: - compileGetClosureRegisters(); - break; case GetClosureVar: compileGetClosureVar(); break; case PutClosureVar: compilePutClosureVar(); break; + case GetFromArguments: + compileGetFromArguments(); + break; + case PutToArguments: + compilePutToArguments(); + break; case CompareEq: compileCompareEq(); break; @@ -577,6 +745,24 @@ private: case Construct: compileCallOrConstruct(); break; + case CallVarargs: + case CallForwardVarargs: + case ConstructVarargs: + case ConstructForwardVarargs: + compileCallOrConstructVarargs(); + break; + case LoadVarargs: + compileLoadVarargs(); + break; + case ForwardVarargs: + compileForwardVarargs(); + break; +#if ENABLE(FTL_NATIVE_CALL_INLINING) + case NativeCall: + case NativeConstruct: + compileNativeCallOrConstruct(); + break; +#endif case Jump: compileJump(); break; @@ -599,9 +785,6 @@ private: case InvalidationPoint: compileInvalidationPoint(); break; - case CheckArgumentsNotCreated: - compileCheckArgumentsNotCreated(); - break; case IsUndefined: compileIsUndefined(); break; @@ -617,9 +800,15 @@ private: case IsObject: compileIsObject(); break; + case IsObjectOrNull: + compileIsObjectOrNull(); + break; case IsFunction: compileIsFunction(); break; + case TypeOf: + compileTypeOf(); + break; case CheckHasInstance: compileCheckHasInstance(); break; @@ -632,27 +821,71 @@ private: case StoreBarrier: compileStoreBarrier(); break; - case StoreBarrierWithNullCheck: - compileStoreBarrierWithNullCheck(); + case HasIndexedProperty: + compileHasIndexedProperty(); + break; + case HasGenericProperty: + compileHasGenericProperty(); + break; + case HasStructureProperty: + compileHasStructureProperty(); + break; + case GetDirectPname: + compileGetDirectPname(); break; + case GetEnumerableLength: + compileGetEnumerableLength(); + break; + case GetPropertyEnumerator: + compileGetPropertyEnumerator(); + break; + case GetEnumeratorStructurePname: + compileGetEnumeratorStructurePname(); + break; + case GetEnumeratorGenericPname: + compileGetEnumeratorGenericPname(); + break; + case ToIndexString: + compileToIndexString(); + break; + case CheckStructureImmediate: + compileCheckStructureImmediate(); + break; + case MaterializeNewObject: + compileMaterializeNewObject(); + break; + case MaterializeCreateActivation: + compileMaterializeCreateActivation(); + break; + case PhantomLocal: - case SetArgument: case LoopHint: - case VariableWatchpoint: - case FunctionReentryWatchpoint: - case TypedArrayWatchpoint: - case AllocationProfileWatchpoint: + case MovHint: + case ZombieHint: + case PhantomNewObject: + case PhantomNewFunction: + case PhantomCreateActivation: + case PhantomDirectArguments: + case PhantomClonedArguments: + case PutHint: + case BottomValue: + case KillStack: break; default: - LOWERING_FAILED(m_node, "Unrecognized node in FTL backend"); + DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend"); break; } - if (!m_loweringSucceeded) + if (m_node->isTerminal()) + return false; + + if (!m_state.isValid()) { + safelyInvalidateAfterTermination(); return false; + } - if (shouldExecuteEffects) - m_interpreter.executeEffects(nodeIndex); + m_availabilityCalculator.executeNode(m_node); + m_interpreter.executeEffects(nodeIndex); return true; } @@ -681,7 +914,7 @@ private: m_out.set(lowJSValue(m_node->child1()), destination); break; default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -707,40 +940,134 @@ private: setJSValue(m_out.get(source)); break; default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } void compileDoubleConstant() { - setDouble(m_out.constDouble(m_graph.valueOfNumberConstant(m_node))); + setDouble(m_out.constDouble(m_node->asNumber())); } void compileInt52Constant() { - int64_t value = m_graph.valueOfJSConstant(m_node).asMachineInt(); + int64_t value = m_node->asMachineInt(); setInt52(m_out.constInt64(value << JSValue::int52ShiftAmount)); setStrictInt52(m_out.constInt64(value)); } - void compileWeakJSConstant() - { - setJSValue(weakPointer(m_node->weakConstant())); - } - - void compilePhantomArguments() - { - setJSValue(m_out.constInt64(JSValue::encode(JSValue()))); - } - void compileDoubleRep() { switch (m_node->child1().useKind()) { + case RealNumberUse: { + LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation); + + LValue doubleValue = unboxDouble(value); + + LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("DoubleRep RealNumberUse int case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("DoubleRep continuation")); + + ValueFromBlock fastResult = m_out.anchor(doubleValue); + m_out.branch( + m_out.doubleEqual(doubleValue, doubleValue), + usually(continuation), rarely(intCase)); + + LBasicBlock lastNext = m_out.appendTo(intCase, continuation); + + FTL_TYPE_CHECK( + jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber, + isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble)); + ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value))); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + + setDouble(m_out.phi(m_out.doubleType, fastResult, slowResult)); + return; + } + + case NotCellUse: case NumberUse: { + bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse; + LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation); - setDouble(jsValueToDouble(m_node->child1(), value)); + + LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case")); + LBasicBlock doubleTesting = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing double case")); + LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case")); + LBasicBlock nonDoubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing undefined case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation")); + + m_out.branch( + isNotInt32(value, provenType(m_node->child1())), + unsure(doubleTesting), unsure(intCase)); + + LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting); + + ValueFromBlock intToDouble = m_out.anchor( + m_out.intToDouble(unboxInt32(value))); + m_out.jump(continuation); + + m_out.appendTo(doubleTesting, doubleCase); + LValue valueIsNumber = isNumber(value, provenType(m_node->child1())); + m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase)); + + m_out.appendTo(doubleCase, nonDoubleCase); + ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value)); + m_out.jump(continuation); + + if (shouldConvertNonNumber) { + LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting undefined case")); + LBasicBlock testNullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing null case")); + LBasicBlock nullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting null case")); + LBasicBlock testBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing boolean true case")); + LBasicBlock convertBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean true case")); + LBasicBlock convertBooleanFalseCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean false case")); + + m_out.appendTo(nonDoubleCase, undefinedCase); + LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined)); + m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase)); + + m_out.appendTo(undefinedCase, testNullCase); + ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN)); + m_out.jump(continuation); + + m_out.appendTo(testNullCase, nullCase); + LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull)); + m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase)); + + m_out.appendTo(nullCase, testBooleanTrueCase); + ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0)); + m_out.jump(continuation); + + m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase); + LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue)); + m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase)); + + m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase); + ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1)); + m_out.jump(continuation); + + m_out.appendTo(convertBooleanFalseCase, continuation); + + LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse)); + FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse); + ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0)); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse)); + return; + } + m_out.appendTo(nonDoubleCase, continuation); + FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue); + m_out.unreachable(); + + m_out.appendTo(continuation, lastNext); + + setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble)); return; } @@ -750,10 +1077,16 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); } } - + + void compileDoubleAsInt32() + { + LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode())); + setInt32(integerValue); + } + void compileValueRep() { switch (m_node->child1().useKind()) { @@ -775,7 +1108,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); } } @@ -799,7 +1132,7 @@ private: return; default: - LOWERING_FAILED(m_node, "Bad use kind"); + RELEASE_ASSERT_NOT_REACHED(); } } @@ -838,7 +1171,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -854,11 +1187,18 @@ private: case UntypedUse: { LValue value = lowJSValue(m_node->child1()); + if (!m_interpreter.needsTypeCheck(m_node->child1(), SpecBoolInt32 | SpecBoolean)) { + setInt32(m_out.bitAnd(m_out.castToInt32(value), m_out.int32One)); + return; + } + LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("BooleanToNumber boolean case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("BooleanToNumber continuation")); ValueFromBlock notBooleanResult = m_out.anchor(value); - m_out.branch(isBoolean(value), unsure(booleanCase), unsure(continuation)); + m_out.branch( + isBoolean(value, provenType(m_node->child1())), + unsure(booleanCase), unsure(continuation)); LBasicBlock lastNext = m_out.appendTo(booleanCase, continuation); ValueFromBlock booleanResult = m_out.anchor(m_out.bitOr( @@ -871,41 +1211,11 @@ private: } default: - LOWERING_FAILED(m_node, "Bad flush format"); + RELEASE_ASSERT_NOT_REACHED(); return; } } - void compileGetArgument() - { - VariableAccessData* variable = m_node->variableAccessData(); - VirtualRegister operand = variable->machineLocal(); - RELEASE_ASSERT(operand.isArgument()); - - LValue jsValue = m_out.load64(addressFor(operand)); - - switch (useKindFor(variable->flushFormat())) { - case Int32Use: - speculate(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue)); - setInt32(unboxInt32(jsValue)); - break; - case CellUse: - speculate(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue)); - setJSValue(jsValue); - break; - case BooleanUse: - speculate(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue)); - setBoolean(unboxBoolean(jsValue)); - break; - case UntypedUse: - setJSValue(jsValue); - break; - default: - LOWERING_FAILED(m_node, "Bad use kind"); - break; - } - } - void compileExtractOSREntryLocal() { EncodedJSValue* buffer = static_cast<EncodedJSValue*>( @@ -913,53 +1223,58 @@ private: setJSValue(m_out.load64(m_out.absolute(buffer + m_node->unlinkedLocal().toLocal()))); } - void compileGetLocal() + void compileGetStack() { - // GetLocals arise only for captured variables. + // GetLocals arise only for captured variables and arguments. For arguments, we might have + // already loaded it. + if (LValue value = m_loadedArgumentValues.get(m_node)) { + setJSValue(value); + return; + } - VariableAccessData* variable = m_node->variableAccessData(); - AbstractValue& value = m_state.variables().operand(variable->local()); + StackAccessData* data = m_node->stackAccessData(); + AbstractValue& value = m_state.variables().operand(data->local); - RELEASE_ASSERT(variable->isCaptured()); + DFG_ASSERT(m_graph, m_node, isConcrete(data->format)); + DFG_ASSERT(m_graph, m_node, data->format != FlushedDouble); // This just happens to not arise for GetStacks, right now. It would be trivial to support. if (isInt32Speculation(value.m_type)) - setInt32(m_out.load32(payloadFor(variable->machineLocal()))); + setInt32(m_out.load32(payloadFor(data->machineLocal))); else - setJSValue(m_out.load64(addressFor(variable->machineLocal()))); + setJSValue(m_out.load64(addressFor(data->machineLocal))); } - void compileSetLocal() + void compilePutStack() { - VariableAccessData* variable = m_node->variableAccessData(); - switch (variable->flushFormat()) { - case FlushedJSValue: - case FlushedArguments: { + StackAccessData* data = m_node->stackAccessData(); + switch (data->format) { + case FlushedJSValue: { LValue value = lowJSValue(m_node->child1()); - m_out.store64(value, addressFor(variable->machineLocal())); + m_out.store64(value, addressFor(data->machineLocal)); break; } case FlushedDouble: { LValue value = lowDouble(m_node->child1()); - m_out.storeDouble(value, addressFor(variable->machineLocal())); + m_out.storeDouble(value, addressFor(data->machineLocal)); break; } case FlushedInt32: { LValue value = lowInt32(m_node->child1()); - m_out.store32(value, payloadFor(variable->machineLocal())); + m_out.store32(value, payloadFor(data->machineLocal)); break; } case FlushedInt52: { LValue value = lowInt52(m_node->child1()); - m_out.store64(value, addressFor(variable->machineLocal())); + m_out.store64(value, addressFor(data->machineLocal)); break; } case FlushedCell: { LValue value = lowCell(m_node->child1()); - m_out.store64(value, addressFor(variable->machineLocal())); + m_out.store64(value, addressFor(data->machineLocal)); break; } @@ -967,33 +1282,17 @@ private: speculateBoolean(m_node->child1()); m_out.store64( lowJSValue(m_node->child1(), ManualOperandSpeculation), - addressFor(variable->machineLocal())); + addressFor(data->machineLocal)); break; } default: - LOWERING_FAILED(m_node, "Bad flush format for argument"); - return; + DFG_CRASH(m_graph, m_node, "Bad flush format"); + break; } - - m_availability.operand(variable->local()) = Availability(variable->flushedAt()); - } - - void compileMovHint() - { - ASSERT(m_node->containsMovHint()); - ASSERT(m_node->op() != ZombieHint); - - VirtualRegister operand = m_node->unlinkedLocal(); - m_availability.operand(operand) = Availability(m_node->child1().node()); - } - - void compileZombieHint() - { - m_availability.operand(m_node->unlinkedLocal()) = Availability::unavailable(); } - void compilePhantom() + void compileNoOp() { DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, speculate); } @@ -1006,7 +1305,8 @@ private: LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("ToThis slow case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ToThis continuation")); - m_out.branch(isCell(value), usually(isCellCase), rarely(slowCase)); + m_out.branch( + isCell(value, provenType(m_node->child1())), usually(isCellCase), rarely(slowCase)); LBasicBlock lastNext = m_out.appendTo(isCellCase, slowCase); ValueFromBlock fastResult = m_out.anchor(value); @@ -1029,8 +1329,8 @@ private: void compileValueAdd() { J_JITOperation_EJJ operation; - if (!(m_state.forNode(m_node->child1()).m_type & SpecFullNumber) - && !(m_state.forNode(m_node->child2()).m_type & SpecFullNumber)) + if (!(provenType(m_node->child1()) & SpecFullNumber) + && !(provenType(m_node->child2()) & SpecFullNumber)) operation = operationValueAddNotNumber; else operation = operationValueAdd; @@ -1090,8 +1390,8 @@ private: } case Int52RepUse: { - if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52) - && !m_state.forNode(m_node->child2()).couldBeType(SpecInt52)) { + if (!abstractValue(m_node->child1()).couldBeType(SpecInt52) + && !abstractValue(m_node->child2()).couldBeType(SpecInt52)) { Int52Kind kind; LValue left = lowWhicheverInt52(m_node->child1(), kind); LValue right = lowInt52(m_node->child2(), kind); @@ -1148,10 +1448,17 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } + + void compileArithClz32() + { + LValue operand = lowInt32(m_node->child1()); + LValue isZeroUndef = m_out.booleanFalse; + setInt32(m_out.ctlz32(operand, isZeroUndef)); + } void compileArithMul() { @@ -1222,7 +1529,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -1325,7 +1632,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -1423,7 +1730,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -1474,7 +1781,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -1500,7 +1807,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -1509,23 +1816,119 @@ private: void compileArithCos() { setDouble(m_out.doubleCos(lowDouble(m_node->child1()))); } - void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); } - - void compileArithFRound() - { - LValue floatValue = m_out.fpCast(lowDouble(m_node->child1()), m_out.floatType); - setDouble(m_out.fpCast(floatValue, m_out.doubleType)); - } - - void compileArithNegate() + void compileArithPow() { - switch (m_node->child1().useKind()) { - case Int32Use: { - LValue value = lowInt32(m_node->child1()); - - LValue result; - if (!shouldCheckOverflow(m_node->arithMode())) - result = m_out.neg(value); + // FIXME: investigate llvm.powi to better understand its performance characteristics. + // It might be better to have the inline loop in DFG too. + if (m_node->child2().useKind() == Int32Use) + setDouble(m_out.doublePowi(lowDouble(m_node->child1()), lowInt32(m_node->child2()))); + else { + LValue base = lowDouble(m_node->child1()); + LValue exponent = lowDouble(m_node->child2()); + + LBasicBlock integerExponentIsSmallBlock = FTL_NEW_BLOCK(m_out, ("ArithPow test integer exponent is small.")); + LBasicBlock integerExponentPowBlock = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, (int)double).")); + LBasicBlock doubleExponentPowBlockEntry = FTL_NEW_BLOCK(m_out, ("ArithPow pow(double, double).")); + LBasicBlock nanExceptionExponentIsInfinity = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check exponent is infinity.")); + LBasicBlock nanExceptionBaseIsOne = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, check base is one.")); + LBasicBlock powBlock = FTL_NEW_BLOCK(m_out, ("ArithPow regular pow")); + LBasicBlock nanExceptionResultIsNaN = FTL_NEW_BLOCK(m_out, ("ArithPow NaN Exception, result is NaN.")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithPow continuation")); + + LValue integerExponent = m_out.fpToInt32(exponent); + LValue integerExponentConvertedToDouble = m_out.intToDouble(integerExponent); + LValue exponentIsInteger = m_out.doubleEqual(exponent, integerExponentConvertedToDouble); + m_out.branch(exponentIsInteger, unsure(integerExponentIsSmallBlock), unsure(doubleExponentPowBlockEntry)); + + LBasicBlock lastNext = m_out.appendTo(integerExponentIsSmallBlock, integerExponentPowBlock); + LValue integerExponentBelow1000 = m_out.below(integerExponent, m_out.constInt32(1000)); + m_out.branch(integerExponentBelow1000, usually(integerExponentPowBlock), rarely(doubleExponentPowBlockEntry)); + + m_out.appendTo(integerExponentPowBlock, doubleExponentPowBlockEntry); + ValueFromBlock powDoubleIntResult = m_out.anchor(m_out.doublePowi(base, integerExponent)); + m_out.jump(continuation); + + // If y is NaN, the result is NaN. + m_out.appendTo(doubleExponentPowBlockEntry, nanExceptionExponentIsInfinity); + LValue exponentIsNaN; + if (provenType(m_node->child2()) & SpecDoubleNaN) + exponentIsNaN = m_out.doubleNotEqualOrUnordered(exponent, exponent); + else + exponentIsNaN = m_out.booleanFalse; + m_out.branch(exponentIsNaN, rarely(nanExceptionResultIsNaN), usually(nanExceptionExponentIsInfinity)); + + // If abs(x) is 1 and y is +infinity, the result is NaN. + // If abs(x) is 1 and y is -infinity, the result is NaN. + m_out.appendTo(nanExceptionExponentIsInfinity, nanExceptionBaseIsOne); + LValue absoluteExponent = m_out.doubleAbs(exponent); + LValue absoluteExponentIsInfinity = m_out.doubleEqual(absoluteExponent, m_out.constDouble(std::numeric_limits<double>::infinity())); + m_out.branch(absoluteExponentIsInfinity, rarely(nanExceptionBaseIsOne), usually(powBlock)); + + m_out.appendTo(nanExceptionBaseIsOne, powBlock); + LValue absoluteBase = m_out.doubleAbs(base); + LValue absoluteBaseIsOne = m_out.doubleEqual(absoluteBase, m_out.constDouble(1)); + m_out.branch(absoluteBaseIsOne, unsure(nanExceptionResultIsNaN), unsure(powBlock)); + + m_out.appendTo(powBlock, nanExceptionResultIsNaN); + ValueFromBlock powResult = m_out.anchor(m_out.doublePow(base, exponent)); + m_out.jump(continuation); + + m_out.appendTo(nanExceptionResultIsNaN, continuation); + ValueFromBlock pureNan = m_out.anchor(m_out.constDouble(PNaN)); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan)); + } + } + + void compileArithRound() + { + LBasicBlock realPartIsMoreThanHalf = FTL_NEW_BLOCK(m_out, ("ArithRound should round down")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithRound continuation")); + + LValue value = lowDouble(m_node->child1()); + LValue integerValue = m_out.ceil64(value); + ValueFromBlock integerValueResult = m_out.anchor(integerValue); + + LValue realPart = m_out.doubleSub(integerValue, value); + + m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation)); + + LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation); + LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1)); + ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown); + m_out.jump(continuation); + m_out.appendTo(continuation, lastNext); + + LValue result = m_out.phi(m_out.doubleType, integerValueResult, integerValueRoundedDownResult); + + if (producesInteger(m_node->arithRoundingMode())) { + LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode())); + setInt32(integerValue); + } else + setDouble(result); + } + + void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); } + + void compileArithLog() { setDouble(m_out.doubleLog(lowDouble(m_node->child1()))); } + + void compileArithFRound() + { + LValue floatValue = m_out.fpCast(lowDouble(m_node->child1()), m_out.floatType); + setDouble(m_out.fpCast(floatValue, m_out.doubleType)); + } + + void compileArithNegate() + { + switch (m_node->child1().useKind()) { + case Int32Use: { + LValue value = lowInt32(m_node->child1()); + + LValue result; + if (!shouldCheckOverflow(m_node->arithMode())) + result = m_out.neg(value); else if (!shouldCheckNegativeZero(m_node->arithMode())) { // We don't have a negate-with-overflow intrinsic. Hopefully this // does the trick, though. @@ -1542,7 +1945,7 @@ private: } case Int52RepUse: { - if (!m_state.forNode(m_node->child1()).couldBeType(SpecInt52)) { + if (!abstractValue(m_node->child1()).couldBeType(SpecInt52)) { Int52Kind kind; LValue value = lowWhicheverInt52(m_node->child1(), kind); LValue result = m_out.neg(value); @@ -1567,7 +1970,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); break; } } @@ -1626,63 +2029,44 @@ private: LValue cell = lowCell(m_node->child1()); ExitKind exitKind; - if (m_node->child1()->op() == WeakJSConstant) - exitKind = BadWeakConstantCache; + if (m_node->child1()->hasConstant()) + exitKind = BadConstantCache; else exitKind = BadCache; LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID); - if (m_node->structureSet().size() == 1) { - speculate( - exitKind, jsValueValue(cell), 0, - m_out.notEqual(structureID, weakStructure(m_node->structureSet()[0]))); - return; - } - - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CheckStructure continuation")); - - LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); - for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) { - LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("CheckStructure nextStructure")); - m_out.branch( - m_out.equal(structureID, weakStructure(m_node->structureSet()[i])), - unsure(continuation), unsure(nextStructure)); - m_out.appendTo(nextStructure); - } - - speculate( - exitKind, jsValueValue(cell), 0, - m_out.notEqual(structureID, weakStructure(m_node->structureSet().last()))); - - m_out.jump(continuation); - m_out.appendTo(continuation, lastNext); + checkStructure( + structureID, jsValueValue(cell), exitKind, m_node->structureSet(), + [this] (Structure* structure) { + return weakStructureID(structure); + }); } - void compileStructureTransitionWatchpoint() - { - addWeakReference(m_node->structure()); - speculateCell(m_node->child1()); - } - - void compileCheckFunction() + void compileCheckCell() { LValue cell = lowCell(m_node->child1()); speculate( - BadFunction, jsValueValue(cell), m_node->child1().node(), - m_out.notEqual(cell, weakPointer(m_node->function()))); + BadCell, jsValueValue(cell), m_node->child1().node(), + m_out.notEqual(cell, weakPointer(m_node->cellOperand()->cell()))); } - void compileCheckExecutable() + void compileCheckBadCell() + { + terminate(BadCell); + } + + void compileCheckNotEmpty() + { + speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1()))); + } + + void compileGetExecutable() { LValue cell = lowCell(m_node->child1()); - - speculate( - BadExecutable, jsValueValue(cell), m_node->child1().node(), - m_out.notEqual( - m_out.loadPtr(cell, m_heaps.JSFunction_executable), - weakPointer(m_node->executable()))); + speculateFunction(m_node->child1(), cell); + setJSValue(m_out.loadPtr(cell, m_heaps.JSFunction_executable)); } void compileArrayifyToStructure() @@ -1696,7 +2080,7 @@ private: LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID); m_out.branch( - m_out.notEqual(structureID, weakStructure(m_node->structure())), + m_out.notEqual(structureID, weakStructureID(m_node->structure())), rarely(unexpectedStructure), usually(continuation)); LBasicBlock lastNext = m_out.appendTo(unexpectedStructure, continuation); @@ -1723,24 +2107,21 @@ private: vmCall(m_out.operation(operationEnsureDouble), m_callFrame, cell); break; case Array::Contiguous: - if (m_node->arrayMode().conversion() == Array::RageConvert) - vmCall(m_out.operation(operationRageEnsureContiguous), m_callFrame, cell); - else - vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell); + vmCall(m_out.operation(operationEnsureContiguous), m_callFrame, cell); break; case Array::ArrayStorage: case Array::SlowPutArrayStorage: vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell); break; default: - LOWERING_FAILED(m_node, "Bad array type"); - return; + DFG_CRASH(m_graph, m_node, "Bad array type"); + break; } structureID = m_out.load32(cell, m_heaps.JSCell_structureID); speculate( BadIndexingType, jsValueValue(cell), 0, - m_out.notEqual(structureID, weakStructure(m_node->structure()))); + m_out.notEqual(structureID, weakStructureID(m_node->structure()))); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); @@ -1750,23 +2131,18 @@ private: { m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node); - Structure* oldStructure = m_node->structureTransitionData().previousStructure; - Structure* newStructure = m_node->structureTransitionData().newStructure; + Structure* oldStructure = m_node->transition()->previous; + Structure* newStructure = m_node->transition()->next; ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType()); ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags()); ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type()); LValue cell = lowCell(m_node->child1()); m_out.store32( - weakStructure(newStructure), + weakStructureID(newStructure), cell, m_heaps.JSCell_structureID); } - void compilePhantomPutStructure() - { - m_ftlState.jitCode->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node); - } - void compileGetById() { // Pretty much the only reason why we don't also support GetByIdFlush is because: @@ -1788,7 +2164,8 @@ private: LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("GetById untyped not cell case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetById untyped continuation")); - m_out.branch(isCell(value), unsure(cellCase), unsure(notCellCase)); + m_out.branch( + isCell(value, provenType(m_node->child1())), unsure(cellCase), unsure(notCellCase)); LBasicBlock lastNext = m_out.appendTo(cellCase, notCellCase); ValueFromBlock cellResult = m_out.anchor(getById(value)); @@ -1796,8 +2173,8 @@ private: m_out.appendTo(notCellCase, continuation); ValueFromBlock notCellResult = m_out.anchor(vmCall( - m_out.operation(operationGetById), - m_callFrame, getUndef(m_out.intPtr), value, + m_out.operation(operationGetByIdGeneric), + m_callFrame, value, m_out.constIntPtr(m_graph.identifiers()[m_node->identifierNumber()]))); m_out.jump(continuation); @@ -1807,7 +2184,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); return; } } @@ -1819,12 +2196,12 @@ private: LValue base = lowCell(m_node->child1()); LValue value = lowJSValue(m_node->child2()); - StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()]; + auto uid = m_graph.identifiers()[m_node->identifierNumber()]; // Arguments: id, bytes, target, numArgs, args... unsigned stackmapID = m_stackmapIDs++; - if (Options::verboseCompilation()) + if (verboseCompilationEnabled()) dataLog(" Emitting PutById patchpoint with stackmap #", stackmapID, "\n"); LValue call = m_out.call( @@ -1884,7 +2261,7 @@ private: Edge edge = m_node->child1(); LValue cell = lowCell(edge); - if (m_node->arrayMode().alreadyChecked(m_graph, m_node, m_state.forNode(edge))) + if (m_node->arrayMode().alreadyChecked(m_graph, m_node, abstractValue(edge))) return; speculate( @@ -1900,9 +2277,9 @@ private: LBasicBlock wastefulCase = FTL_NEW_BLOCK(m_out, ("wasteful typed array")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("continuation branch")); - LValue baseAddress = m_out.addPtr(basePtr, JSArrayBufferView::offsetOfMode()); + LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode); m_out.branch( - m_out.notEqual(baseAddress , m_out.constIntPtr(WastefulTypedArray)), + m_out.notEqual(mode, m_out.constInt32(WastefulTypedArray)), unsure(simpleCase), unsure(wastefulCase)); // begin simple case @@ -1920,7 +2297,7 @@ private: LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer); LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data); - ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(dataPtr, vectorPtr)); + ValueFromBlock wastefulOut = m_out.anchor(m_out.sub(vectorPtr, dataPtr)); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); @@ -1929,56 +2306,6 @@ private: setInt32(m_out.castToInt32(m_out.phi(m_out.intPtr, simpleOut, wastefulOut))); } - void compileGetMyArgumentsLength() - { - checkArgumentsNotCreated(); - - RELEASE_ASSERT(!m_node->origin.semantic.inlineCallFrame); - setInt32(m_out.add(m_out.load32NonNegative(payloadFor(JSStack::ArgumentCount)), m_out.constInt32(-1))); - } - - void compileGetMyArgumentByVal() - { - checkArgumentsNotCreated(); - - CodeOrigin codeOrigin = m_node->origin.semantic; - - LValue zeroBasedIndex = lowInt32(m_node->child1()); - LValue oneBasedIndex = m_out.add(zeroBasedIndex, m_out.int32One); - - LValue limit; - if (codeOrigin.inlineCallFrame) - limit = m_out.constInt32(codeOrigin.inlineCallFrame->arguments.size()); - else - limit = m_out.load32(payloadFor(JSStack::ArgumentCount)); - - speculate(Uncountable, noValue(), 0, m_out.aboveOrEqual(oneBasedIndex, limit)); - - SymbolTable* symbolTable = m_graph.baselineCodeBlockFor(codeOrigin)->symbolTable(); - if (symbolTable->slowArguments()) { - // FIXME: FTL should support activations. - // https://bugs.webkit.org/show_bug.cgi?id=129576 - - LOWERING_FAILED(m_node, "Unimplemented"); - return; - } - - TypedPointer base; - if (codeOrigin.inlineCallFrame) { - VirtualRegister reg; - if (codeOrigin.inlineCallFrame->arguments.size() <= 1) - reg = virtualRegisterForLocal(0); // Doesn't matter what we do since we would have exited anyway. - else - reg = codeOrigin.inlineCallFrame->arguments[1].virtualRegister(); - base = addressFor(reg); - } else - base = addressFor(virtualRegisterForArgument(1)); - - LValue pointer = m_out.baseIndex( - base.value(), m_out.zeroExt(zeroBasedIndex, m_out.intPtr), ScaleEight); - setJSValue(m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer))); - } - void compileGetArrayLength() { switch (m_node->arrayMode().type()) { @@ -1995,6 +2322,24 @@ private: return; } + case Array::DirectArguments: { + LValue arguments = lowCell(m_node->child1()); + speculate( + ExoticObjectMode, noValue(), nullptr, + m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_overrides))); + setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length)); + return; + } + + case Array::ScopedArguments: { + LValue arguments = lowCell(m_node->child1()); + speculate( + ExoticObjectMode, noValue(), nullptr, + m_out.notZero8(m_out.load8(arguments, m_heaps.ScopedArguments_overrodeThings))); + setInt32(m_out.load32NonNegative(arguments, m_heaps.ScopedArguments_totalLength)); + return; + } + default: if (isTypedView(m_node->arrayMode().typedArrayType())) { setInt32( @@ -2002,7 +2347,7 @@ private: return; } - LOWERING_FAILED(m_node, "Bad array type"); + DFG_CRASH(m_graph, m_node, "Bad array type"); return; } } @@ -2027,7 +2372,14 @@ private: if (m_node->arrayMode().isInBounds()) { LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2())); - speculate(LoadFromHole, noValue(), 0, m_out.isZero64(result)); + LValue isHole = m_out.isZero64(result); + if (m_node->arrayMode().isSaneChain()) { + DFG_ASSERT( + m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous); + result = m_out.select( + isHole, m_out.constInt64(JSValue::encode(jsUndefined())), result); + } else + speculate(LoadFromHole, noValue(), 0, isHole); setJSValue(result); return; } @@ -2112,6 +2464,78 @@ private: return; } + case Array::DirectArguments: { + LValue base = lowCell(m_node->child1()); + LValue index = lowInt32(m_node->child2()); + + speculate( + ExoticObjectMode, noValue(), nullptr, + m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_overrides))); + speculate( + ExoticObjectMode, noValue(), nullptr, + m_out.aboveOrEqual( + index, + m_out.load32NonNegative(base, m_heaps.DirectArguments_length))); + + TypedPointer address = m_out.baseIndex( + m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index)); + setJSValue(m_out.load64(address)); + return; + } + + case Array::ScopedArguments: { + LValue base = lowCell(m_node->child1()); + LValue index = lowInt32(m_node->child2()); + + speculate( + ExoticObjectMode, noValue(), nullptr, + m_out.aboveOrEqual( + index, + m_out.load32NonNegative(base, m_heaps.ScopedArguments_totalLength))); + + LValue table = m_out.loadPtr(base, m_heaps.ScopedArguments_table); + LValue namedLength = m_out.load32(table, m_heaps.ScopedArgumentsTable_length); + + LBasicBlock namedCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments named case")); + LBasicBlock overflowCase = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments overflow case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetByVal ScopedArguments continuation")); + + m_out.branch( + m_out.aboveOrEqual(index, namedLength), unsure(overflowCase), unsure(namedCase)); + + LBasicBlock lastNext = m_out.appendTo(namedCase, overflowCase); + + LValue scope = m_out.loadPtr(base, m_heaps.ScopedArguments_scope); + LValue arguments = m_out.loadPtr(table, m_heaps.ScopedArgumentsTable_arguments); + + TypedPointer address = m_out.baseIndex( + m_heaps.scopedArgumentsTableArguments, arguments, m_out.zeroExtPtr(index)); + LValue scopeOffset = m_out.load32(address); + + speculate( + ExoticObjectMode, noValue(), nullptr, + m_out.equal(scopeOffset, m_out.constInt32(ScopeOffset::invalidOffset))); + + address = m_out.baseIndex( + m_heaps.JSEnvironmentRecord_variables, scope, m_out.zeroExtPtr(scopeOffset)); + ValueFromBlock namedResult = m_out.anchor(m_out.load64(address)); + m_out.jump(continuation); + + m_out.appendTo(overflowCase, continuation); + + address = m_out.baseIndex( + m_heaps.ScopedArguments_overflowStorage, base, + m_out.zeroExtPtr(m_out.sub(index, namedLength))); + LValue overflowValue = m_out.load64(address); + speculate(ExoticObjectMode, noValue(), nullptr, m_out.isZero64(overflowValue)); + ValueFromBlock overflowResult = m_out.anchor(overflowValue); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setJSValue(m_out.phi(m_out.int64, namedResult, overflowResult)); + return; + } + case Array::Generic: { setJSValue(vmCall( m_out.operation(operationGetByVal), m_callFrame, @@ -2136,7 +2560,7 @@ private: m_out.add( storage, m_out.shl( - m_out.zeroExt(index, m_out.intPtr), + m_out.zeroExtPtr(index), m_out.constIntPtr(logElementSize(type))))); if (isInt(type)) { @@ -2152,8 +2576,7 @@ private: result = m_out.load32(pointer); break; default: - LOWERING_FAILED(m_node, "Bad element size"); - return; + DFG_CRASH(m_graph, m_node, "Bad element size"); } if (elementSize(type) < 4) { @@ -2197,19 +2620,58 @@ private: result = m_out.loadDouble(pointer); break; default: - LOWERING_FAILED(m_node, "Bad typed array type"); - return; + DFG_CRASH(m_graph, m_node, "Bad typed array type"); } setDouble(result); return; } - LOWERING_FAILED(m_node, "Bad array type"); + DFG_CRASH(m_graph, m_node, "Bad array type"); return; } } } + void compileGetMyArgumentByVal() + { + InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame; + + LValue index = lowInt32(m_node->child2()); + + LValue limit; + if (inlineCallFrame && !inlineCallFrame->isVarargs()) + limit = m_out.constInt32(inlineCallFrame->arguments.size() - 1); + else { + VirtualRegister argumentCountRegister; + if (!inlineCallFrame) + argumentCountRegister = VirtualRegister(JSStack::ArgumentCount); + else + argumentCountRegister = inlineCallFrame->argumentCountRegister; + limit = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One); + } + + speculate(ExoticObjectMode, noValue(), 0, m_out.aboveOrEqual(index, limit)); + + TypedPointer base; + if (inlineCallFrame) { + if (inlineCallFrame->arguments.size() <= 1) { + // We should have already exited due to the bounds check, above. Just tell the + // compiler that anything dominated by this instruction is not reachable, so + // that we don't waste time generating such code. This will also plant some + // kind of crashing instruction so that if by some fluke the bounds check didn't + // work, we'll crash in an easy-to-see way. + didAlreadyTerminate(); + return; + } + base = addressFor(inlineCallFrame->arguments[1].virtualRegister()); + } else + base = addressFor(virtualRegisterForArgument(1)); + + LValue pointer = m_out.baseIndex( + base.value(), m_out.zeroExt(index, m_out.intPtr), ScaleEight); + setJSValue(m_out.load64(TypedPointer(m_heaps.variables.atAnyIndex(), pointer))); + } + void compilePutByVal() { Edge child1 = m_graph.varArgChild(m_node, 0); @@ -2265,8 +2727,7 @@ private: TypedPointer elementPointer = m_out.baseIndex( m_node->arrayMode().type() == Array::Int32 ? m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(child2).m_value); + storage, m_out.zeroExtPtr(index), provenValue(child2)); if (m_node->op() == PutByValAlias) { m_out.store64(value, elementPointer); @@ -2291,9 +2752,8 @@ private: m_out.doubleNotEqualOrUnordered(value, value)); TypedPointer elementPointer = m_out.baseIndex( - m_heaps.indexedDoubleProperties, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(child2).m_value); + m_heaps.indexedDoubleProperties, storage, m_out.zeroExtPtr(index), + provenValue(child2)); if (m_node->op() == PutByValAlias) { m_out.storeDouble(value, elementPointer); @@ -2311,8 +2771,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad array type"); - return; + DFG_CRASH(m_graph, m_node, "Bad array type"); } m_out.jump(continuation); @@ -2405,8 +2864,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); - return; + DFG_CRASH(m_graph, m_node, "Bad use kind"); } switch (elementSize(type)) { @@ -2423,8 +2881,7 @@ private: refType = m_out.ref32; break; default: - LOWERING_FAILED(m_node, "Bad element size"); - return; + DFG_CRASH(m_graph, m_node, "Bad element size"); } } else /* !isInt(type) */ { LValue value = lowDouble(child3); @@ -2438,8 +2895,7 @@ private: refType = m_out.refDouble; break; default: - LOWERING_FAILED(m_node, "Bad typed array type"); - return; + DFG_CRASH(m_graph, m_node, "Bad typed array type"); } } @@ -2463,8 +2919,8 @@ private: return; } - LOWERING_FAILED(m_node, "Bad array type"); - return; + DFG_CRASH(m_graph, m_node, "Bad array type"); + break; } } @@ -2510,9 +2966,7 @@ private: LBasicBlock lastNext = m_out.appendTo(fastPath, slowPath); m_out.store( - value, - m_out.baseIndex(heap, storage, m_out.zeroExt(prevLength, m_out.intPtr)), - refType); + value, m_out.baseIndex(heap, storage, m_out.zeroExtPtr(prevLength)), refType); LValue newLength = m_out.add(prevLength, m_out.int32One); m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength); @@ -2535,7 +2989,7 @@ private: } default: - LOWERING_FAILED(m_node, "Bad array type"); + DFG_CRASH(m_graph, m_node, "Bad array type"); return; } } @@ -2565,8 +3019,7 @@ private: LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase); LValue newLength = m_out.sub(prevLength, m_out.int32One); m_out.store32(newLength, storage, m_heaps.Butterfly_publicLength); - TypedPointer pointer = m_out.baseIndex( - heap, storage, m_out.zeroExt(newLength, m_out.intPtr)); + TypedPointer pointer = m_out.baseIndex(heap, storage, m_out.zeroExtPtr(newLength)); if (m_node->arrayMode().type() != Array::Double) { LValue result = m_out.load64(pointer); m_out.store64(m_out.int64Zero, pointer); @@ -2593,101 +3046,290 @@ private: } default: - LOWERING_FAILED(m_node, "Bad array type"); + DFG_CRASH(m_graph, m_node, "Bad array type"); return; } } - void compileNewObject() + void compileCreateActivation() { - Structure* structure = m_node->structure(); - size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); - MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); + LValue scope = lowCell(m_node->child1()); + SymbolTable* table = m_node->castOperand<SymbolTable*>(); + Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->activationStructure(); + + if (table->singletonScope()->isStillValid()) { + LValue callResult = vmCall( + m_out.operation(operationCreateActivationDirect), m_callFrame, weakPointer(structure), + scope, weakPointer(table)); + setJSValue(callResult); + return; + } - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewObject slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewObject continuation")); + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CreateActivation slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CreateActivation continuation")); LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - ValueFromBlock fastResult = m_out.anchor(allocateObject( - m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath)); + LValue fastObject = allocateObject<JSLexicalEnvironment>( + JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, slowPath); + + // We don't need memory barriers since we just fast-created the activation, so the + // activation must be young. + m_out.storePtr(scope, fastObject, m_heaps.JSScope_next); + m_out.storePtr(weakPointer(table), fastObject, m_heaps.JSSymbolTableObject_symbolTable); + for (unsigned i = 0; i < table->scopeSize(); ++i) { + m_out.store64( + m_out.constInt64(JSValue::encode(jsUndefined())), + fastObject, m_heaps.JSEnvironmentRecord_variables[i]); + } + + ValueFromBlock fastResult = m_out.anchor(fastObject); m_out.jump(continuation); m_out.appendTo(slowPath, continuation); - - ValueFromBlock slowResult = m_out.anchor(vmCall( - m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure))); + LValue callResult = vmCall( + m_out.operation(operationCreateActivationDirect), m_callFrame, weakPointer(structure), + scope, weakPointer(table)); + ValueFromBlock slowResult = m_out.anchor(callResult); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult)); } - void compileNewArray() + void compileNewFunction() { - // First speculate appropriately on all of the children. Do this unconditionally up here - // because some of the slow paths may otherwise forget to do it. It's sort of arguable - // that doing the speculations up here might be unprofitable for RA - so we can consider - // sinking this to below the allocation fast path if we find that this has a lot of - // register pressure. - for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) - speculate(m_graph.varArgChild(m_node, operandIndex)); + LValue scope = lowCell(m_node->child1()); + FunctionExecutable* executable = m_node->castOperand<FunctionExecutable*>(); + if (executable->singletonFunction()->isStillValid()) { + LValue callResult = vmCall( + m_out.operation(operationNewFunction), m_callFrame, scope, weakPointer(executable)); + setJSValue(callResult); + return; + } - JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); - Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation( - m_node->indexingType()); + Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->functionStructure(); - RELEASE_ASSERT(structure->indexingType() == m_node->indexingType()); + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewFunction slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewFunction continuation")); - if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) { - unsigned numElements = m_node->numChildren(); - - ArrayValues arrayValues = allocateJSArray(structure, numElements); - - for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) { - Edge edge = m_graph.varArgChild(m_node, operandIndex); - - switch (m_node->indexingType()) { - case ALL_BLANK_INDEXING_TYPES: - case ALL_UNDECIDED_INDEXING_TYPES: - CRASH(); - break; - - case ALL_DOUBLE_INDEXING_TYPES: - m_out.storeDouble( - lowDouble(edge), - arrayValues.butterfly, m_heaps.indexedDoubleProperties[operandIndex]); - break; - - case ALL_INT32_INDEXING_TYPES: - case ALL_CONTIGUOUS_INDEXING_TYPES: - m_out.store64( - lowJSValue(edge, ManualOperandSpeculation), - arrayValues.butterfly, - m_heaps.forIndexingType(m_node->indexingType())->at(operandIndex)); - break; - - default: - CRASH(); - } - } - - setJSValue(arrayValues.array); - return; - } + LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - if (!m_node->numChildren()) { - setJSValue(vmCall( - m_out.operation(operationNewEmptyArray), m_callFrame, - m_out.constIntPtr(structure))); - return; - } + LValue fastObject = allocateObject<JSFunction>( + structure, m_out.intPtrZero, slowPath); - size_t scratchSize = sizeof(EncodedJSValue) * m_node->numChildren(); - ASSERT(scratchSize); - ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize); - EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()); + // We don't need memory barriers since we just fast-created the function, so it + // must be young. + m_out.storePtr(scope, fastObject, m_heaps.JSFunction_scope); + m_out.storePtr(weakPointer(executable), fastObject, m_heaps.JSFunction_executable); + m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.JSFunction_rareData); + + ValueFromBlock fastResult = m_out.anchor(fastObject); + m_out.jump(continuation); + + m_out.appendTo(slowPath, continuation); + LValue callResult = vmCall( + m_out.operation(operationNewFunctionWithInvalidatedReallocationWatchpoint), + m_callFrame, scope, weakPointer(executable)); + ValueFromBlock slowResult = m_out.anchor(callResult); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult)); + } + + void compileCreateDirectArguments() + { + // FIXME: A more effective way of dealing with the argument count and callee is to have + // them be explicit arguments to this node. + // https://bugs.webkit.org/show_bug.cgi?id=142207 + + Structure* structure = + m_graph.globalObjectFor(m_node->origin.semantic)->directArgumentsStructure(); + + unsigned minCapacity = m_graph.baselineCodeBlockFor(m_node->origin.semantic)->numParameters() - 1; + + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments continuation")); + + LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); + + ArgumentsLength length = getArgumentsLength(); + + LValue fastObject; + if (length.isKnown) { + fastObject = allocateObject<DirectArguments>( + DirectArguments::allocationSize(std::max(length.known, minCapacity)), structure, + m_out.intPtrZero, slowPath); + } else { + LValue size = m_out.add( + m_out.shl(length.value, m_out.constInt32(3)), + m_out.constInt32(DirectArguments::storageOffset())); + + size = m_out.select( + m_out.aboveOrEqual(length.value, m_out.constInt32(minCapacity)), + size, m_out.constInt32(DirectArguments::allocationSize(minCapacity))); + + fastObject = allocateVariableSizedObject<DirectArguments>( + size, structure, m_out.intPtrZero, slowPath); + } + + m_out.store32(length.value, fastObject, m_heaps.DirectArguments_length); + m_out.store32(m_out.constInt32(minCapacity), fastObject, m_heaps.DirectArguments_minCapacity); + m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.DirectArguments_overrides); + + ValueFromBlock fastResult = m_out.anchor(fastObject); + m_out.jump(continuation); + + m_out.appendTo(slowPath, continuation); + LValue callResult = vmCall( + m_out.operation(operationCreateDirectArguments), m_callFrame, weakPointer(structure), + length.value, m_out.constInt32(minCapacity)); + ValueFromBlock slowResult = m_out.anchor(callResult); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + LValue result = m_out.phi(m_out.intPtr, fastResult, slowResult); + + m_out.storePtr(getCurrentCallee(), result, m_heaps.DirectArguments_callee); + + if (length.isKnown) { + VirtualRegister start = AssemblyHelpers::argumentsStart(m_node->origin.semantic); + for (unsigned i = 0; i < std::max(length.known, minCapacity); ++i) { + m_out.store64( + m_out.load64(addressFor(start + i)), + result, m_heaps.DirectArguments_storage[i]); + } + } else { + LValue stackBase = getArgumentsStart(); + + LBasicBlock loop = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments loop body")); + LBasicBlock end = FTL_NEW_BLOCK(m_out, ("CreateDirectArguments loop end")); + + ValueFromBlock originalLength; + if (minCapacity) { + LValue capacity = m_out.select( + m_out.aboveOrEqual(length.value, m_out.constInt32(minCapacity)), + length.value, + m_out.constInt32(minCapacity)); + originalLength = m_out.anchor(m_out.zeroExtPtr(capacity)); + m_out.jump(loop); + } else { + originalLength = m_out.anchor(m_out.zeroExtPtr(length.value)); + m_out.branch(m_out.isNull(originalLength.value()), unsure(end), unsure(loop)); + } + + lastNext = m_out.appendTo(loop, end); + LValue previousIndex = m_out.phi(m_out.intPtr, originalLength); + LValue index = m_out.sub(previousIndex, m_out.intPtrOne); + m_out.store64( + m_out.load64(m_out.baseIndex(m_heaps.variables, stackBase, index)), + m_out.baseIndex(m_heaps.DirectArguments_storage, result, index)); + ValueFromBlock nextIndex = m_out.anchor(index); + addIncoming(previousIndex, nextIndex); + m_out.branch(m_out.isNull(index), unsure(end), unsure(loop)); + + m_out.appendTo(end, lastNext); + } + + setJSValue(result); + } + + void compileCreateScopedArguments() + { + LValue scope = lowCell(m_node->child1()); + + LValue result = vmCall( + m_out.operation(operationCreateScopedArguments), m_callFrame, + weakPointer( + m_graph.globalObjectFor(m_node->origin.semantic)->scopedArgumentsStructure()), + getArgumentsStart(), getArgumentsLength().value, getCurrentCallee(), scope); + + setJSValue(result); + } + + void compileCreateClonedArguments() + { + LValue result = vmCall( + m_out.operation(operationCreateClonedArguments), m_callFrame, + weakPointer( + m_graph.globalObjectFor(m_node->origin.semantic)->outOfBandArgumentsStructure()), + getArgumentsStart(), getArgumentsLength().value, getCurrentCallee()); + + setJSValue(result); + } + + void compileNewObject() + { + setJSValue(allocateObject(m_node->structure())); + } + + void compileNewArray() + { + // First speculate appropriately on all of the children. Do this unconditionally up here + // because some of the slow paths may otherwise forget to do it. It's sort of arguable + // that doing the speculations up here might be unprofitable for RA - so we can consider + // sinking this to below the allocation fast path if we find that this has a lot of + // register pressure. + for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) + speculate(m_graph.varArgChild(m_node, operandIndex)); + + JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); + Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation( + m_node->indexingType()); + + DFG_ASSERT(m_graph, m_node, structure->indexingType() == m_node->indexingType()); + + if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) { + unsigned numElements = m_node->numChildren(); + + ArrayValues arrayValues = allocateJSArray(structure, numElements); + + for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) { + Edge edge = m_graph.varArgChild(m_node, operandIndex); + + switch (m_node->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_UNDECIDED_INDEXING_TYPES: + DFG_CRASH(m_graph, m_node, "Bad indexing type"); + break; + + case ALL_DOUBLE_INDEXING_TYPES: + m_out.storeDouble( + lowDouble(edge), + arrayValues.butterfly, m_heaps.indexedDoubleProperties[operandIndex]); + break; + + case ALL_INT32_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + m_out.store64( + lowJSValue(edge, ManualOperandSpeculation), + arrayValues.butterfly, + m_heaps.forIndexingType(m_node->indexingType())->at(operandIndex)); + break; + + default: + DFG_CRASH(m_graph, m_node, "Corrupt indexing type"); + break; + } + } + + setJSValue(arrayValues.array); + return; + } + + if (!m_node->numChildren()) { + setJSValue(vmCall( + m_out.operation(operationNewEmptyArray), m_callFrame, + m_out.constIntPtr(structure))); + return; + } + + size_t scratchSize = sizeof(EncodedJSValue) * m_node->numChildren(); + ASSERT(scratchSize); + ScratchBuffer* scratchBuffer = vm().scratchBufferForSize(scratchSize); + EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()); for (unsigned operandIndex = 0; operandIndex < m_node->numChildren(); ++operandIndex) { Edge edge = m_graph.varArgChild(m_node, operandIndex); @@ -2715,7 +3357,7 @@ private: Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation( m_node->indexingType()); - RELEASE_ASSERT(structure->indexingType() == m_node->indexingType()); + DFG_ASSERT(m_graph, m_node, structure->indexingType() == m_node->indexingType()); if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) { unsigned numElements = m_node->numConstants(); @@ -2768,7 +3410,7 @@ private: LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewArrayWithSize continuation")); m_out.branch( - m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)), + m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)), rarely(largeCase), usually(fastCase)); LBasicBlock lastNext = m_out.appendTo(fastCase, largeCase); @@ -2844,7 +3486,7 @@ private: } LValue structureValue = m_out.select( - m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_SPARSE_ARRAY_INDEX)), + m_out.aboveOrEqual(publicLength, m_out.constInt32(MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)), m_out.constIntPtr( globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage)), m_out.constIntPtr(structure)); @@ -2853,24 +3495,22 @@ private: void compileAllocatePropertyStorage() { - StructureTransitionData& data = m_node->structureTransitionData(); LValue object = lowCell(m_node->child1()); - - setStorage(allocatePropertyStorage(object, data.previousStructure)); + setStorage(allocatePropertyStorage(object, m_node->transition()->previous)); } void compileReallocatePropertyStorage() { - StructureTransitionData& data = m_node->structureTransitionData(); + Transition* transition = m_node->transition(); LValue object = lowCell(m_node->child1()); LValue oldStorage = lowStorage(m_node->child2()); setStorage( reallocatePropertyStorage( - object, oldStorage, data.previousStructure, data.newStructure)); + object, oldStorage, transition->previous, transition->next)); } - void compileToString() + void compileToStringOrCallStringConstructor() { switch (m_node->child1().useKind()) { case StringObjectUse: { @@ -2923,16 +3563,14 @@ private: if (m_node->child1().useKind() == CellUse) isCellPredicate = m_out.booleanTrue; else - isCellPredicate = this->isCell(value); + isCellPredicate = this->isCell(value, provenType(m_node->child1())); m_out.branch(isCellPredicate, unsure(isCell), unsure(notString)); LBasicBlock lastNext = m_out.appendTo(isCell, notString); ValueFromBlock simpleResult = m_out.anchor(value); LValue isStringPredicate; if (m_node->child1()->prediction() & SpecString) { - isStringPredicate = m_out.equal( - m_out.load32(value, m_heaps.JSCell_structureID), - m_out.constInt32(vm().stringStructure->id())); + isStringPredicate = isString(value, provenType(m_node->child1())); } else isStringPredicate = m_out.booleanFalse; m_out.branch(isStringPredicate, unsure(continuation), unsure(notString)); @@ -2940,9 +3578,9 @@ private: m_out.appendTo(notString, continuation); LValue operation; if (m_node->child1().useKind() == CellUse) - operation = m_out.operation(operationToStringOnCell); + operation = m_out.operation(m_node->op() == ToString ? operationToStringOnCell : operationCallStringConstructorOnCell); else - operation = m_out.operation(operationToString); + operation = m_out.operation(m_node->op() == ToString ? operationToString : operationCallStringConstructor); ValueFromBlock convertedResult = m_out.anchor(vmCall(operation, m_callFrame, value)); m_out.jump(continuation); @@ -2952,8 +3590,8 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); - return; + DFG_CRASH(m_graph, m_node, "Bad use kind"); + break; } } @@ -2968,11 +3606,14 @@ private: Vector<ValueFromBlock, 3> results; results.append(m_out.anchor(value)); - m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation)); + m_out.branch( + isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(continuation)); LBasicBlock lastNext = m_out.appendTo(isCellCase, isObjectCase); results.append(m_out.anchor(value)); - m_out.branch(isObject(value), unsure(isObjectCase), unsure(continuation)); + m_out.branch( + isObject(value, provenType(m_node->child1())), + unsure(isObjectCase), unsure(continuation)); m_out.appendTo(isObjectCase, continuation); results.append(m_out.anchor(vmCall( @@ -3003,7 +3644,7 @@ private: LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); MarkedAllocator& allocator = - vm().heap.allocatorForObjectWithImmortalStructureDestructor(sizeof(JSRopeString)); + vm().heap.allocatorForObjectWithDestructor(sizeof(JSRopeString)); LValue result = allocateCell( m_out.constIntPtr(&allocator), @@ -3044,8 +3685,7 @@ private: m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2])); break; default: - LOWERING_FAILED(m_node, "Bad number of children"); - return; + DFG_CRASH(m_graph, m_node, "Bad number of children"); break; } m_out.jump(continuation); @@ -3088,9 +3728,8 @@ private: ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt( m_out.load8(m_out.baseIndex( - m_heaps.characters8, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), + m_heaps.characters8, storage, m_out.zeroExtPtr(index), + provenValue(m_node->child2()))), m_out.int32)); m_out.jump(bitsContinuation); @@ -3098,9 +3737,8 @@ private: ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt( m_out.load16(m_out.baseIndex( - m_heaps.characters16, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), + m_heaps.characters16, storage, m_out.zeroExtPtr(index), + provenValue(m_node->child2()))), m_out.int32)); m_out.branch( m_out.aboveOrEqual(char16Bit.value(), m_out.constInt32(0x100)), @@ -3121,8 +3759,7 @@ private: LValue smallStrings = m_out.constIntPtr(vm().smallStrings.singleCharacterStrings()); results.append(m_out.anchor(m_out.loadPtr(m_out.baseIndex( - m_heaps.singleCharacterStrings, smallStrings, - m_out.zeroExt(character, m_out.intPtr))))); + m_heaps.singleCharacterStrings, smallStrings, m_out.zeroExtPtr(character))))); m_out.jump(continuation); m_out.appendTo(slowPath, continuation); @@ -3134,6 +3771,14 @@ private: JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); if (globalObject->stringPrototypeChainIsSane()) { + // FIXME: This could be captured using a Speculation mode that means + // "out-of-bounds loads return a trivial value", something like + // SaneChainOutOfBounds. + // https://bugs.webkit.org/show_bug.cgi?id=144668 + + m_graph.watchpoints().addLazily(globalObject->stringPrototype()->structure()->transitionWatchpointSet()); + m_graph.watchpoints().addLazily(globalObject->objectPrototype()->structure()->transitionWatchpointSet()); + LBasicBlock negativeIndex = FTL_NEW_BLOCK(m_out, ("GetByVal String negative index")); results.append(m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined())))); @@ -3181,9 +3826,8 @@ private: ValueFromBlock char8Bit = m_out.anchor(m_out.zeroExt( m_out.load8(m_out.baseIndex( - m_heaps.characters8, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), + m_heaps.characters8, storage, m_out.zeroExtPtr(index), + provenValue(m_node->child2()))), m_out.int32)); m_out.jump(continuation); @@ -3191,9 +3835,8 @@ private: ValueFromBlock char16Bit = m_out.anchor(m_out.zeroExt( m_out.load16(m_out.baseIndex( - m_heaps.characters16, - storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(m_node->child2()).m_value)), + m_heaps.characters16, storage, m_out.zeroExtPtr(index), + provenValue(m_node->child2()))), m_out.int32)); m_out.jump(continuation); @@ -3204,18 +3847,33 @@ private: void compileGetByOffset() { - StorageAccessData& data = - m_graph.m_storageAccessData[m_node->storageAccessDataIndex()]; + StorageAccessData& data = m_node->storageAccessData(); setJSValue(loadProperty( lowStorage(m_node->child1()), data.identifierNumber, data.offset)); } + void compileGetGetter() + { + setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.GetterSetter_getter)); + } + + void compileGetSetter() + { + setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.GetterSetter_setter)); + } + void compileMultiGetByOffset() { LValue base = lowCell(m_node->child1()); MultiGetByOffsetData& data = m_node->multiGetByOffsetData(); + + if (data.variants.isEmpty()) { + // Protect against creating a Phi function with zero inputs. LLVM doesn't like that. + terminate(BadCache); + return; + } Vector<LBasicBlock, 2> blocks(data.variants.size()); for (unsigned i = data.variants.size(); i--;) @@ -3224,11 +3882,13 @@ private: LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiGetByOffset continuation")); Vector<SwitchCase, 2> cases; + StructureSet baseSet; for (unsigned i = data.variants.size(); i--;) { GetByIdVariant variant = data.variants[i]; for (unsigned j = variant.structureSet().size(); j--;) { - cases.append(SwitchCase( - weakStructure(variant.structureSet()[j]), blocks[i], Weight(1))); + Structure* structure = variant.structureSet()[j]; + baseSet.add(structure); + cases.append(SwitchCase(weakStructureID(structure), blocks[i], Weight(1))); } } m_out.switchInstruction( @@ -3241,13 +3901,19 @@ private: m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit); GetByIdVariant variant = data.variants[i]; + baseSet.merge(variant.structureSet()); LValue result; - if (variant.specificValue()) - result = m_out.constInt64(JSValue::encode(variant.specificValue())); + JSValue constantResult; + if (variant.alternateBase()) { + constantResult = m_graph.tryGetConstantProperty( + variant.alternateBase(), variant.baseStructure(), variant.offset()); + } + if (constantResult) + result = m_out.constInt64(JSValue::encode(constantResult)); else { LValue propertyBase; - if (variant.chain()) - propertyBase = weakPointer(variant.chain()->terminalPrototype()); + if (variant.alternateBase()) + propertyBase = weakPointer(variant.alternateBase()); else propertyBase = base; if (!isInlineOffset(variant.offset())) @@ -3260,7 +3926,8 @@ private: } m_out.appendTo(exit, continuation); - terminate(BadCache); + if (!m_interpreter.forNode(m_node->child1()).m_structure.isSubsetOf(baseSet)) + speculate(BadCache, noValue(), nullptr, m_out.booleanTrue); m_out.unreachable(); m_out.appendTo(continuation, lastNext); @@ -3269,8 +3936,7 @@ private: void compilePutByOffset() { - StorageAccessData& data = - m_graph.m_storageAccessData[m_node->storageAccessDataIndex()]; + StorageAccessData& data = m_node->storageAccessData(); storeProperty( lowJSValue(m_node->child3()), @@ -3291,10 +3957,14 @@ private: LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset continuation")); Vector<SwitchCase, 2> cases; + StructureSet baseSet; for (unsigned i = data.variants.size(); i--;) { PutByIdVariant variant = data.variants[i]; - cases.append( - SwitchCase(weakStructure(variant.oldStructure()), blocks[i], Weight(1))); + for (unsigned j = variant.oldStructure().size(); j--;) { + Structure* structure = variant.oldStructure()[j]; + baseSet.add(structure); + cases.append(SwitchCase(weakStructureID(structure), blocks[i], Weight(1))); + } } m_out.switchInstruction( m_out.load32(base, m_heaps.JSCell_structureID), cases, exit, Weight(0)); @@ -3302,7 +3972,7 @@ private: LBasicBlock lastNext = m_out.m_nextBlock; for (unsigned i = data.variants.size(); i--;) { - m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit); + m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit); PutByIdVariant variant = data.variants[i]; @@ -3315,16 +3985,17 @@ private: } else { m_graph.m_plan.transitions.addLazily( codeBlock(), m_node->origin.semantic.codeOriginOwner(), - variant.oldStructure(), variant.newStructure()); + variant.oldStructureForTransition(), variant.newStructure()); storage = storageForTransition( - base, variant.offset(), variant.oldStructure(), variant.newStructure()); + base, variant.offset(), + variant.oldStructureForTransition(), variant.newStructure()); - ASSERT(variant.oldStructure()->indexingType() == variant.newStructure()->indexingType()); - ASSERT(variant.oldStructure()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags()); - ASSERT(variant.oldStructure()->typeInfo().type() == variant.newStructure()->typeInfo().type()); + ASSERT(variant.oldStructureForTransition()->indexingType() == variant.newStructure()->indexingType()); + ASSERT(variant.oldStructureForTransition()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags()); + ASSERT(variant.oldStructureForTransition()->typeInfo().type() == variant.newStructure()->typeInfo().type()); m_out.store32( - weakStructure(variant.newStructure()), base, m_heaps.JSCell_structureID); + weakStructureID(variant.newStructure()), base, m_heaps.JSCell_structureID); } storeProperty(value, storage, data.identifierNumber, variant.offset()); @@ -3332,7 +4003,8 @@ private: } m_out.appendTo(exit, continuation); - terminate(BadCache); + if (!m_interpreter.forNode(m_node->child1()).m_structure.isSubsetOf(baseSet)) + speculate(BadCache, noValue(), nullptr, m_out.booleanTrue); m_out.unreachable(); m_out.appendTo(continuation, lastNext); @@ -3340,40 +4012,30 @@ private: void compileGetGlobalVar() { - setJSValue(m_out.load64(m_out.absolute(m_node->registerPointer()))); + setJSValue(m_out.load64(m_out.absolute(m_node->variablePointer()))); } void compilePutGlobalVar() { m_out.store64( - lowJSValue(m_node->child1()), m_out.absolute(m_node->registerPointer())); + lowJSValue(m_node->child2()), m_out.absolute(m_node->variablePointer())); } void compileNotifyWrite() { - VariableWatchpointSet* set = m_node->variableWatchpointSet(); - - LValue value = lowJSValue(m_node->child1()); + WatchpointSet* set = m_node->watchpointSet(); LBasicBlock isNotInvalidated = FTL_NEW_BLOCK(m_out, ("NotifyWrite not invalidated case")); - LBasicBlock notifySlow = FTL_NEW_BLOCK(m_out, ("NotifyWrite notify slow case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NotifyWrite continuation")); LValue state = m_out.load8(m_out.absolute(set->addressOfState())); - m_out.branch( m_out.equal(state, m_out.constInt8(IsInvalidated)), usually(continuation), rarely(isNotInvalidated)); - LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, notifySlow); - - m_out.branch( - m_out.equal(value, m_out.load64(m_out.absolute(set->addressOfInferredValue()))), - unsure(continuation), unsure(notifySlow)); - - m_out.appendTo(notifySlow, continuation); + LBasicBlock lastNext = m_out.appendTo(isNotInvalidated, continuation); - vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set), value); + vmCall(m_out.operation(operationNotifyWrite), m_callFrame, m_out.constIntPtr(set)); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); @@ -3384,15 +4046,14 @@ private: setJSValue(m_out.loadPtr(addressFor(JSStack::Callee))); } - void compileGetScope() + void compileGetArgumentCount() { - setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope)); + setInt32(m_out.load32(payloadFor(JSStack::ArgumentCount))); } - void compileGetMyScope() + void compileGetScope() { - setJSValue(m_out.loadPtr(addressFor( - m_node->origin.semantic.stackOffset() + JSStack::ScopeChain))); + setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope)); } void compileSkipScope() @@ -3400,28 +4061,36 @@ private: setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next)); } - void compileGetClosureRegisters() + void compileGetClosureVar() { - if (WriteBarrierBase<Unknown>* registers = m_graph.tryGetRegisters(m_node->child1().node())) { - setStorage(m_out.constIntPtr(registers)); - return; - } - - setStorage(m_out.loadPtr( - lowCell(m_node->child1()), m_heaps.JSVariableObject_registers)); + setJSValue( + m_out.load64( + lowCell(m_node->child1()), + m_heaps.JSEnvironmentRecord_variables[m_node->scopeOffset().offset()])); } - void compileGetClosureVar() + void compilePutClosureVar() { - setJSValue(m_out.load64( - addressFor(lowStorage(m_node->child1()), m_node->varNumber()))); + m_out.store64( + lowJSValue(m_node->child2()), + lowCell(m_node->child1()), + m_heaps.JSEnvironmentRecord_variables[m_node->scopeOffset().offset()]); } - void compilePutClosureVar() + void compileGetFromArguments() + { + setJSValue( + m_out.load64( + lowCell(m_node->child1()), + m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()])); + } + + void compilePutToArguments() { m_out.store64( - lowJSValue(m_node->child3()), - addressFor(lowStorage(m_node->child2()), m_node->varNumber())); + lowJSValue(m_node->child2()), + lowCell(m_node->child1()), + m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()]); } void compileCompareEq() @@ -3450,13 +4119,13 @@ private: nonSpeculativeCompare(LLVMIntEQ, operationCompareEq); return; } - - LOWERING_FAILED(m_node, "Bad use kinds"); + + DFG_CRASH(m_graph, m_node, "Bad use kinds"); } void compileCompareEqConstant() { - ASSERT(m_graph.valueOfJSConstant(m_node->child2().node()).isNull()); + ASSERT(m_node->child2()->asJSValue().isNull()); setBoolean( equalNullOrUndefined( m_node->child1(), AllCellsAreFalse, EqualNullOrUndefined)); @@ -3489,7 +4158,23 @@ private: m_out.equal(lowStringIdent(m_node->child1()), lowStringIdent(m_node->child2()))); return; } + + if (m_node->isBinaryUseKind(ObjectUse, UntypedUse)) { + setBoolean( + m_out.equal( + lowNonNullObject(m_node->child1()), + lowJSValue(m_node->child2()))); + return; + } + if (m_node->isBinaryUseKind(UntypedUse, ObjectUse)) { + setBoolean( + m_out.equal( + lowNonNullObject(m_node->child2()), + lowJSValue(m_node->child1()))); + return; + } + if (m_node->isBinaryUseKind(ObjectUse)) { setBoolean( m_out.equal( @@ -3527,11 +4212,15 @@ private: LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar continuation")); ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse); - m_out.branch(isCell(rightValue), unsure(isCellCase), unsure(continuation)); + m_out.branch( + isCell(rightValue, provenType(rightEdge)), + unsure(isCellCase), unsure(continuation)); LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase); ValueFromBlock notStringResult = m_out.anchor(m_out.booleanFalse); - m_out.branch(isString(rightValue), unsure(isStringCase), unsure(continuation)); + m_out.branch( + isString(rightValue, provenType(rightEdge)), + unsure(isStringCase), unsure(continuation)); m_out.appendTo(isStringCase, continuation); LValue right = m_out.loadPtr(rightValue, m_heaps.JSString_value); @@ -3544,12 +4233,12 @@ private: return; } - LOWERING_FAILED(m_node, "Bad use kinds"); + DFG_CRASH(m_graph, m_node, "Bad use kinds"); } void compileCompareStrictEqConstant() { - JSValue constant = m_graph.valueOfJSConstant(m_node->child2().node()); + JSValue constant = m_node->child2()->asJSValue(); setBoolean( m_out.equal( @@ -3581,15 +4270,61 @@ private: { setBoolean(m_out.bitNot(boolify(m_node->child1()))); } - +#if ENABLE(FTL_NATIVE_CALL_INLINING) + void compileNativeCallOrConstruct() + { + int numPassedArgs = m_node->numChildren() - 1; + int numArgs = numPassedArgs; + + JSFunction* knownFunction = m_node->castOperand<JSFunction*>(); + NativeFunction function = knownFunction->nativeFunction(); + + Dl_info info; + if (!dladdr((void*)function, &info)) + ASSERT(false); // if we couldn't find the native function this doesn't bode well. + + LValue callee = getFunctionBySymbol(info.dli_sname); + + bool notInlinable; + if ((notInlinable = !callee)) + callee = m_out.operation(function); + + m_out.storePtr(m_callFrame, m_execStorage, m_heaps.CallFrame_callerFrame); + m_out.storePtr(constNull(m_out.intPtr), addressFor(m_execStorage, JSStack::CodeBlock)); + m_out.storePtr(weakPointer(knownFunction), addressFor(m_execStorage, JSStack::Callee)); + + m_out.store64(m_out.constInt64(numArgs), addressFor(m_execStorage, JSStack::ArgumentCount)); + + for (int i = 0; i < numPassedArgs; ++i) { + m_out.storePtr(lowJSValue(m_graph.varArgChild(m_node, 1 + i)), + addressFor(m_execStorage, JSStack::ThisArgument, i * sizeof(Register))); + } + + LValue calleeCallFrame = m_out.address(m_execState, m_heaps.CallFrame_callerFrame).value(); + m_out.storePtr(m_out.ptrToInt(calleeCallFrame, m_out.intPtr), m_out.absolute(&vm().topCallFrame)); + + LType typeCalleeArg; + getParamTypes(getElementType(typeOf(callee)), &typeCalleeArg); + + LValue argument = notInlinable + ? m_out.ptrToInt(calleeCallFrame, typeCalleeArg) + : m_out.bitCast(calleeCallFrame, typeCalleeArg); + LValue call = vmCall(callee, argument); + + if (verboseCompilationEnabled()) + dataLog("Native calling: ", info.dli_sname, "\n"); + + setJSValue(call); + } +#endif + void compileCallOrConstruct() { - int dummyThisArgument = m_node->op() == Call ? 0 : 1; int numPassedArgs = m_node->numChildren() - 1; - int numArgs = numPassedArgs + dummyThisArgument; - - LValue callee = lowJSValue(m_graph.varArgChild(m_node, 0)); - + int numArgs = numPassedArgs; + + LValue jsCallee = lowJSValue(m_graph.varArgChild(m_node, 0)); + unsigned stackmapID = m_stackmapIDs++; Vector<LValue> arguments; @@ -3597,13 +4332,10 @@ private: arguments.append(m_out.constInt32(sizeOfCall())); arguments.append(constNull(m_out.ref8)); arguments.append(m_out.constInt32(1 + JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + numArgs)); - arguments.append(callee); // callee -> %rax + arguments.append(jsCallee); // callee -> %rax arguments.append(getUndef(m_out.int64)); // code block - arguments.append(getUndef(m_out.int64)); // scope chain - arguments.append(callee); // callee -> stack + arguments.append(jsCallee); // callee -> stack arguments.append(m_out.constInt64(numArgs)); // argument count and zeros for the tag - if (dummyThisArgument) - arguments.append(getUndef(m_out.int64)); for (int i = 0; i < numPassedArgs; ++i) arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i))); @@ -3617,6 +4349,141 @@ private: setJSValue(call); } + void compileCallOrConstructVarargs() + { + LValue jsCallee = lowJSValue(m_node->child1()); + LValue thisArg = lowJSValue(m_node->child3()); + + LValue jsArguments = nullptr; + + switch (m_node->op()) { + case CallVarargs: + case ConstructVarargs: + jsArguments = lowJSValue(m_node->child2()); + break; + case CallForwardVarargs: + case ConstructForwardVarargs: + break; + default: + DFG_CRASH(m_graph, m_node, "bad node type"); + break; + } + + unsigned stackmapID = m_stackmapIDs++; + + Vector<LValue> arguments; + arguments.append(m_out.constInt64(stackmapID)); + arguments.append(m_out.constInt32(sizeOfICFor(m_node))); + arguments.append(constNull(m_out.ref8)); + arguments.append(m_out.constInt32(2 + !!jsArguments)); + arguments.append(jsCallee); + if (jsArguments) + arguments.append(jsArguments); + ASSERT(thisArg); + arguments.append(thisArg); + + callPreflight(); + + LValue call = m_out.call(m_out.patchpointInt64Intrinsic(), arguments); + setInstructionCallingConvention(call, LLVMCCallConv); + + m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, m_node)); + + setJSValue(call); + } + + void compileLoadVarargs() + { + LoadVarargsData* data = m_node->loadVarargsData(); + LValue jsArguments = lowJSValue(m_node->child1()); + + LValue length = vmCall( + m_out.operation(operationSizeOfVarargs), m_callFrame, jsArguments, + m_out.constInt32(data->offset)); + + // FIXME: There is a chance that we will call an effectful length property twice. This is safe + // from the standpoint of the VM's integrity, but it's subtly wrong from a spec compliance + // standpoint. The best solution would be one where we can exit *into* the op_call_varargs right + // past the sizing. + // https://bugs.webkit.org/show_bug.cgi?id=141448 + + LValue lengthIncludingThis = m_out.add(length, m_out.int32One); + speculate( + VarargsOverflow, noValue(), nullptr, + m_out.above(lengthIncludingThis, m_out.constInt32(data->limit))); + + m_out.store32(lengthIncludingThis, payloadFor(data->machineCount)); + + // FIXME: This computation is rather silly. If operationLaodVarargs just took a pointer instead + // of a VirtualRegister, we wouldn't have to do this. + // https://bugs.webkit.org/show_bug.cgi?id=141660 + LValue machineStart = m_out.lShr( + m_out.sub(addressFor(data->machineStart.offset()).value(), m_callFrame), + m_out.constIntPtr(3)); + + vmCall( + m_out.operation(operationLoadVarargs), m_callFrame, + m_out.castToInt32(machineStart), jsArguments, m_out.constInt32(data->offset), + length, m_out.constInt32(data->mandatoryMinimum)); + } + + void compileForwardVarargs() + { + LoadVarargsData* data = m_node->loadVarargsData(); + InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame; + + LValue length = getArgumentsLength(inlineCallFrame).value; + LValue lengthIncludingThis = m_out.add(length, m_out.constInt32(1 - data->offset)); + + speculate( + VarargsOverflow, noValue(), nullptr, + m_out.above(lengthIncludingThis, m_out.constInt32(data->limit))); + + m_out.store32(lengthIncludingThis, payloadFor(data->machineCount)); + + LValue sourceStart = getArgumentsStart(inlineCallFrame); + LValue targetStart = addressFor(data->machineStart).value(); + + LBasicBlock undefinedLoop = FTL_NEW_BLOCK(m_out, ("ForwardVarargs undefined loop body")); + LBasicBlock mainLoopEntry = FTL_NEW_BLOCK(m_out, ("ForwardVarargs main loop entry")); + LBasicBlock mainLoop = FTL_NEW_BLOCK(m_out, ("ForwardVarargs main loop body")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ForwardVarargs continuation")); + + LValue lengthAsPtr = m_out.zeroExtPtr(length); + ValueFromBlock loopBound = m_out.anchor(m_out.constIntPtr(data->mandatoryMinimum)); + m_out.branch( + m_out.above(loopBound.value(), lengthAsPtr), unsure(undefinedLoop), unsure(mainLoopEntry)); + + LBasicBlock lastNext = m_out.appendTo(undefinedLoop, mainLoopEntry); + LValue previousIndex = m_out.phi(m_out.intPtr, loopBound); + LValue currentIndex = m_out.sub(previousIndex, m_out.intPtrOne); + m_out.store64( + m_out.constInt64(JSValue::encode(jsUndefined())), + m_out.baseIndex(m_heaps.variables, targetStart, currentIndex)); + ValueFromBlock nextIndex = m_out.anchor(currentIndex); + addIncoming(previousIndex, nextIndex); + m_out.branch( + m_out.above(currentIndex, lengthAsPtr), unsure(undefinedLoop), unsure(mainLoopEntry)); + + m_out.appendTo(mainLoopEntry, mainLoop); + loopBound = m_out.anchor(lengthAsPtr); + m_out.branch(m_out.notNull(loopBound.value()), unsure(mainLoop), unsure(continuation)); + + m_out.appendTo(mainLoop, continuation); + previousIndex = m_out.phi(m_out.intPtr, loopBound); + currentIndex = m_out.sub(previousIndex, m_out.intPtrOne); + LValue value = m_out.load64( + m_out.baseIndex( + m_heaps.variables, sourceStart, + m_out.add(currentIndex, m_out.constIntPtr(data->offset)))); + m_out.store64(value, m_out.baseIndex(m_heaps.variables, targetStart, currentIndex)); + nextIndex = m_out.anchor(currentIndex); + addIncoming(previousIndex, nextIndex); + m_out.branch(m_out.isNull(currentIndex), unsure(continuation), unsure(mainLoop)); + + m_out.appendTo(continuation, lastNext); + } + void compileJump() { m_out.jump(lowBlock(m_node->targetBlock())); @@ -3666,7 +4533,7 @@ private: m_out.appendTo(isNotInt, isDouble); m_out.branch( - isCellOrMisc(boxedValue), + isCellOrMisc(boxedValue, provenType(m_node->child1())), usually(lowBlock(data->fallThrough.block)), rarely(isDouble)); m_out.appendTo(isDouble, innerLastNext); @@ -3680,8 +4547,8 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); - return; + DFG_CRASH(m_graph, m_node, "Bad use kind"); + break; } m_out.appendTo(switchOnInts, lastNext); @@ -3711,13 +4578,13 @@ private: LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar is string")); m_out.branch( - isNotCell(unboxedValue), + isNotCell(unboxedValue, provenType(m_node->child1())), unsure(lowBlock(data->fallThrough.block)), unsure(isCellCase)); LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase); LValue cellValue = unboxedValue; m_out.branch( - isNotString(cellValue), + isNotString(cellValue, provenType(m_node->child1())), unsure(lowBlock(data->fallThrough.block)), unsure(isStringCase)); m_out.appendTo(isStringCase, lastNext); @@ -3726,8 +4593,8 @@ private: } default: - LOWERING_FAILED(m_node, "Bad use kind"); - return; + DFG_CRASH(m_graph, m_node, "Bad use kind"); + break; } LBasicBlock lengthIs1 = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar length is 1")); @@ -3778,12 +4645,88 @@ private: return; } - case SwitchString: - LOWERING_FAILED(m_node, "Unimplemented"); - break; + case SwitchString: { + switch (m_node->child1().useKind()) { + case StringIdentUse: { + LValue stringImpl = lowStringIdent(m_node->child1()); + + Vector<SwitchCase> cases; + for (unsigned i = 0; i < data->cases.size(); ++i) { + LValue value = m_out.constIntPtr(data->cases[i].value.stringImpl()); + LBasicBlock block = lowBlock(data->cases[i].target.block); + Weight weight = Weight(data->cases[i].target.count); + cases.append(SwitchCase(value, block, weight)); + } + + m_out.switchInstruction( + stringImpl, cases, lowBlock(data->fallThrough.block), + Weight(data->fallThrough.count)); + return; + } + + case StringUse: { + switchString(data, lowString(m_node->child1())); + return; + } + + case UntypedUse: { + LValue value = lowJSValue(m_node->child1()); + + LBasicBlock isCellBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString Untyped cell case")); + LBasicBlock isStringBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString Untyped string case")); + + m_out.branch( + isCell(value, provenType(m_node->child1())), + unsure(isCellBlock), unsure(lowBlock(data->fallThrough.block))); + + LBasicBlock lastNext = m_out.appendTo(isCellBlock, isStringBlock); + + m_out.branch( + isString(value, provenType(m_node->child1())), + unsure(isStringBlock), unsure(lowBlock(data->fallThrough.block))); + + m_out.appendTo(isStringBlock, lastNext); + + switchString(data, value); + return; + } + + default: + DFG_CRASH(m_graph, m_node, "Bad use kind"); + return; + } + return; } + + case SwitchCell: { + LValue cell; + switch (m_node->child1().useKind()) { + case CellUse: { + cell = lowCell(m_node->child1()); + break; + } + + case UntypedUse: { + LValue value = lowJSValue(m_node->child1()); + LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("Switch/SwitchCell cell case")); + m_out.branch( + isCell(value, provenType(m_node->child1())), + unsure(cellCase), unsure(lowBlock(data->fallThrough.block))); + m_out.appendTo(cellCase); + cell = value; + break; + } + + default: + DFG_CRASH(m_graph, m_node, "Bad use kind"); + return; + } + + buildSwitch(m_node->switchData(), m_out.intPtr, cell); + return; + } } - LOWERING_FAILED(m_node, "Bad switch kind"); + DFG_CRASH(m_graph, m_node, "Bad switch kind"); } void compileReturn() @@ -3804,12 +4747,13 @@ private: void compileInvalidationPoint() { if (verboseCompilationEnabled()) - dataLog(" Invalidation point with availability: ", m_availability, "\n"); + dataLog(" Invalidation point with availability: ", availabilityMap(), "\n"); m_ftlState.jitCode->osrExit.append(OSRExit( UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(), m_codeOriginForExitTarget, m_codeOriginForExitProfile, - m_availability.numberOfArguments(), m_availability.numberOfLocals())); + availabilityMap().m_locals.numberOfArguments(), + availabilityMap().m_locals.numberOfLocals())); m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); OSRExit& exit = m_ftlState.jitCode->osrExit.last(); @@ -3823,15 +4767,6 @@ private: info.m_isInvalidationPoint = true; } - void compileCheckArgumentsNotCreated() - { - ASSERT(!isEmptySpeculation( - m_state.variables().operand( - m_graph.argumentsRegisterFor(m_node->origin.semantic)).m_type)); - - checkArgumentsNotCreated(); - } - void compileIsUndefined() { setBoolean(equalNullOrUndefined(m_node->child1(), AllCellsAreFalse, EqualUndefined)); @@ -3839,12 +4774,12 @@ private: void compileIsBoolean() { - setBoolean(isBoolean(lowJSValue(m_node->child1()))); + setBoolean(isBoolean(lowJSValue(m_node->child1()), provenType(m_node->child1()))); } void compileIsNumber() { - setBoolean(isNumber(lowJSValue(m_node->child1()))); + setBoolean(isNumber(lowJSValue(m_node->child1()), provenType(m_node->child1()))); } void compileIsString() @@ -3855,30 +4790,178 @@ private: LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsString continuation")); ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse); - m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation)); + m_out.branch( + isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(continuation)); LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation); - ValueFromBlock cellResult = m_out.anchor(isString(value)); + ValueFromBlock cellResult = m_out.anchor(isString(value, provenType(m_node->child1()))); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult)); } - + void compileIsObject() { - LValue pointerResult = vmCall( - m_out.operation(operationIsObject), m_callFrame, lowJSValue(m_node->child1())); - setBoolean(m_out.notNull(pointerResult)); + LValue value = lowJSValue(m_node->child1()); + + LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("IsObject cell case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsObject continuation")); + + ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse); + m_out.branch( + isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(continuation)); + + LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation); + ValueFromBlock cellResult = m_out.anchor(isObject(value, provenType(m_node->child1()))); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setBoolean(m_out.phi(m_out.boolean, notCellResult, cellResult)); + } + + void compileIsObjectOrNull() + { + JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); + + Edge child = m_node->child1(); + LValue value = lowJSValue(child); + + LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull cell case")); + LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull not function case")); + LBasicBlock objectCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull object case")); + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull slow path")); + LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull not cell case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsObjectOrNull continuation")); + + m_out.branch(isCell(value, provenType(child)), unsure(cellCase), unsure(notCellCase)); + + LBasicBlock lastNext = m_out.appendTo(cellCase, notFunctionCase); + ValueFromBlock isFunctionResult = m_out.anchor(m_out.booleanFalse); + m_out.branch( + isFunction(value, provenType(child)), + unsure(continuation), unsure(notFunctionCase)); + + m_out.appendTo(notFunctionCase, objectCase); + ValueFromBlock notObjectResult = m_out.anchor(m_out.booleanFalse); + m_out.branch( + isObject(value, provenType(child)), + unsure(objectCase), unsure(continuation)); + + m_out.appendTo(objectCase, slowPath); + ValueFromBlock objectResult = m_out.anchor(m_out.booleanTrue); + m_out.branch( + isExoticForTypeof(value, provenType(child)), + rarely(slowPath), usually(continuation)); + + m_out.appendTo(slowPath, notCellCase); + LValue slowResultValue = vmCall( + m_out.operation(operationObjectIsObject), m_callFrame, weakPointer(globalObject), + value); + ValueFromBlock slowResult = m_out.anchor(m_out.notNull(slowResultValue)); + m_out.jump(continuation); + + m_out.appendTo(notCellCase, continuation); + LValue notCellResultValue = m_out.equal(value, m_out.constInt64(JSValue::encode(jsNull()))); + ValueFromBlock notCellResult = m_out.anchor(notCellResultValue); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + LValue result = m_out.phi( + m_out.boolean, + isFunctionResult, notObjectResult, objectResult, slowResult, notCellResult); + setBoolean(result); } void compileIsFunction() { - LValue pointerResult = vmCall( - m_out.operation(operationIsFunction), lowJSValue(m_node->child1())); - setBoolean(m_out.notNull(pointerResult)); + JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); + + Edge child = m_node->child1(); + LValue value = lowJSValue(child); + + LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("IsFunction cell case")); + LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("IsFunction not function case")); + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("IsFunction slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("IsFunction continuation")); + + ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse); + m_out.branch( + isCell(value, provenType(child)), unsure(cellCase), unsure(continuation)); + + LBasicBlock lastNext = m_out.appendTo(cellCase, notFunctionCase); + ValueFromBlock functionResult = m_out.anchor(m_out.booleanTrue); + m_out.branch( + isFunction(value, provenType(child)), + unsure(continuation), unsure(notFunctionCase)); + + m_out.appendTo(notFunctionCase, slowPath); + ValueFromBlock objectResult = m_out.anchor(m_out.booleanFalse); + m_out.branch( + isExoticForTypeof(value, provenType(child)), + rarely(slowPath), usually(continuation)); + + m_out.appendTo(slowPath, continuation); + LValue slowResultValue = vmCall( + m_out.operation(operationObjectIsFunction), m_callFrame, weakPointer(globalObject), + value); + ValueFromBlock slowResult = m_out.anchor(m_out.notNull(slowResultValue)); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + LValue result = m_out.phi( + m_out.boolean, notCellResult, functionResult, objectResult, slowResult); + setBoolean(result); } + void compileTypeOf() + { + Edge child = m_node->child1(); + LValue value = lowJSValue(child); + + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("TypeOf continuation")); + LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); + + Vector<ValueFromBlock> results; + + buildTypeOf( + child, value, + [&] (TypeofType type) { + results.append(m_out.anchor(weakPointer(vm().smallStrings.typeString(type)))); + m_out.jump(continuation); + }); + + m_out.appendTo(continuation, lastNext); + setJSValue(m_out.phi(m_out.int64, results)); + } + + void compileIn() + { + Edge base = m_node->child2(); + LValue cell = lowCell(base); + speculateObject(base, cell); + if (JSString* string = m_node->child1()->dynamicCastConstant<JSString*>()) { + if (string->tryGetValueImpl() && string->tryGetValueImpl()->isAtomic()) { + + const auto str = static_cast<const AtomicStringImpl*>(string->tryGetValueImpl()); + unsigned stackmapID = m_stackmapIDs++; + + LValue call = m_out.call( + m_out.patchpointInt64Intrinsic(), + m_out.constInt64(stackmapID), m_out.constInt32(sizeOfIn()), + constNull(m_out.ref8), m_out.constInt32(1), cell); + + setInstructionCallingConvention(call, LLVMAnyRegCallConv); + + m_ftlState.checkIns.append(CheckInDescriptor(stackmapID, m_node->origin.semantic, str)); + setJSValue(call); + return; + } + } + + setJSValue(vmCall(m_out.operation(operationGenericIn), m_callFrame, cell, lowJSValue(m_node->child1()))); + } + void compileCheckHasInstance() { speculate( @@ -3906,7 +4989,7 @@ private: LValue condition; if (m_node->child1().useKind() == UntypedUse) - condition = isCell(cell); + condition = isCell(cell, provenType(m_node->child1())); else condition = m_out.booleanTrue; @@ -3915,7 +4998,7 @@ private: LBasicBlock lastNext = m_out.appendTo(isCellCase, loop); - speculate(BadType, noValue(), 0, isNotObject(prototype)); + speculate(BadType, noValue(), 0, isNotObject(prototype, provenType(m_node->child2()))); ValueFromBlock originalValue = m_out.anchor(cell); m_out.jump(loop); @@ -3950,20 +5033,547 @@ private: emitStoreBarrier(lowCell(m_node->child1())); } - void compileStoreBarrierWithNullCheck() + void compileHasIndexedProperty() { -#if ENABLE(GGC) - LBasicBlock isNotNull = FTL_NEW_BLOCK(m_out, ("Store barrier with null check value not null")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Store barrier continuation")); + switch (m_node->arrayMode().type()) { + case Array::Int32: + case Array::Contiguous: { + LValue base = lowCell(m_node->child1()); + LValue index = lowInt32(m_node->child2()); + LValue storage = lowStorage(m_node->child3()); + + IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ? + m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties; + + LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous check hole")); + LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous slow case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous continuation")); + + if (!m_node->arrayMode().isInBounds()) { + m_out.branch( + m_out.aboveOrEqual( + index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)), + rarely(slowCase), usually(checkHole)); + } else + m_out.jump(checkHole); + + LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase); + ValueFromBlock checkHoleResult = m_out.anchor( + m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_node->child2())))); + m_out.branch(checkHoleResult.value(), usually(continuation), rarely(slowCase)); + + m_out.appendTo(slowCase, continuation); + ValueFromBlock slowResult = m_out.anchor(m_out.equal( + m_out.constInt64(JSValue::encode(jsBoolean(true))), + vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index))); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult)); + return; + } + case Array::Double: { + LValue base = lowCell(m_node->child1()); + LValue index = lowInt32(m_node->child2()); + LValue storage = lowStorage(m_node->child3()); + + IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties; + + LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double check hole")); + LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double slow case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double continuation")); + + if (!m_node->arrayMode().isInBounds()) { + m_out.branch( + m_out.aboveOrEqual( + index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)), + rarely(slowCase), usually(checkHole)); + } else + m_out.jump(checkHole); + LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase); + LValue doubleValue = m_out.loadDouble(baseIndex(heap, storage, index, m_node->child2())); + ValueFromBlock checkHoleResult = m_out.anchor(m_out.doubleEqual(doubleValue, doubleValue)); + m_out.branch(checkHoleResult.value(), usually(continuation), rarely(slowCase)); + + m_out.appendTo(slowCase, continuation); + ValueFromBlock slowResult = m_out.anchor(m_out.equal( + m_out.constInt64(JSValue::encode(jsBoolean(true))), + vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index))); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult)); + return; + } + + default: + RELEASE_ASSERT_NOT_REACHED(); + return; + } + } + + void compileHasGenericProperty() + { LValue base = lowJSValue(m_node->child1()); - m_out.branch(m_out.isZero64(base), unsure(continuation), unsure(isNotNull)); - LBasicBlock lastNext = m_out.appendTo(isNotNull, continuation); - emitStoreBarrier(base); + LValue property = lowCell(m_node->child2()); + setJSValue(vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property)); + } + + void compileHasStructureProperty() + { + LValue base = lowJSValue(m_node->child1()); + LValue property = lowString(m_node->child2()); + LValue enumerator = lowCell(m_node->child3()); + + LBasicBlock correctStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty correct structure")); + LBasicBlock wrongStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty wrong structure")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasStructureProperty continuation")); + + m_out.branch(m_out.notEqual( + m_out.load32(base, m_heaps.JSCell_structureID), + m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)), + rarely(wrongStructure), usually(correctStructure)); + + LBasicBlock lastNext = m_out.appendTo(correctStructure, wrongStructure); + ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue); + m_out.jump(continuation); + + m_out.appendTo(wrongStructure, continuation); + ValueFromBlock wrongStructureResult = m_out.anchor( + m_out.equal( + m_out.constInt64(JSValue::encode(jsBoolean(true))), + vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property))); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setBoolean(m_out.phi(m_out.boolean, correctStructureResult, wrongStructureResult)); + } + + void compileGetDirectPname() + { + LValue base = lowCell(m_graph.varArgChild(m_node, 0)); + LValue property = lowCell(m_graph.varArgChild(m_node, 1)); + LValue index = lowInt32(m_graph.varArgChild(m_node, 2)); + LValue enumerator = lowCell(m_graph.varArgChild(m_node, 3)); + + LBasicBlock checkOffset = FTL_NEW_BLOCK(m_out, ("GetDirectPname check offset")); + LBasicBlock inlineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname inline load")); + LBasicBlock outOfLineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname out-of-line load")); + LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetDirectPname slow case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetDirectPname continuation")); + + m_out.branch(m_out.notEqual( + m_out.load32(base, m_heaps.JSCell_structureID), + m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)), + rarely(slowCase), usually(checkOffset)); + + LBasicBlock lastNext = m_out.appendTo(checkOffset, inlineLoad); + m_out.branch(m_out.aboveOrEqual(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity)), + unsure(outOfLineLoad), unsure(inlineLoad)); + + m_out.appendTo(inlineLoad, outOfLineLoad); + ValueFromBlock inlineResult = m_out.anchor( + m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), + base, m_out.zeroExt(index, m_out.int64), ScaleEight, JSObject::offsetOfInlineStorage()))); + m_out.jump(continuation); + + m_out.appendTo(outOfLineLoad, slowCase); + LValue storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly); + LValue realIndex = m_out.signExt( + m_out.neg(m_out.sub(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity))), + m_out.int64); + int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue); + ValueFromBlock outOfLineResult = m_out.anchor( + m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), storage, realIndex, ScaleEight, offsetOfFirstProperty))); + m_out.jump(continuation); + + m_out.appendTo(slowCase, continuation); + ValueFromBlock slowCaseResult = m_out.anchor( + vmCall(m_out.operation(operationGetByVal), m_callFrame, base, property)); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setJSValue(m_out.phi(m_out.int64, inlineResult, outOfLineResult, slowCaseResult)); + } + + void compileGetEnumerableLength() + { + LValue enumerator = lowCell(m_node->child1()); + setInt32(m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_indexLength)); + } + + void compileGetPropertyEnumerator() + { + LValue base = lowCell(m_node->child1()); + setJSValue(vmCall(m_out.operation(operationGetPropertyEnumerator), m_callFrame, base)); + } + + void compileGetEnumeratorStructurePname() + { + LValue enumerator = lowCell(m_node->child1()); + LValue index = lowInt32(m_node->child2()); + + LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname in bounds")); + LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname out of bounds")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname continuation")); + + m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endStructurePropertyIndex)), + usually(inBounds), rarely(outOfBounds)); + + LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds); + LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector); + ValueFromBlock inBoundsResult = m_out.anchor( + m_out.loadPtr(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, storage, m_out.zeroExtPtr(index)))); + m_out.jump(continuation); + + m_out.appendTo(outOfBounds, continuation); + ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull)); + m_out.jump(continuation); + m_out.appendTo(continuation, lastNext); + setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult)); + } + + void compileGetEnumeratorGenericPname() + { + LValue enumerator = lowCell(m_node->child1()); + LValue index = lowInt32(m_node->child2()); + + LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname in bounds")); + LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname out of bounds")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname continuation")); + + m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endGenericPropertyIndex)), + usually(inBounds), rarely(outOfBounds)); + + LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds); + LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector); + ValueFromBlock inBoundsResult = m_out.anchor( + m_out.loadPtr(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, storage, m_out.zeroExtPtr(index)))); + m_out.jump(continuation); + + m_out.appendTo(outOfBounds, continuation); + ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull)); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult)); + } + + void compileToIndexString() + { + LValue index = lowInt32(m_node->child1()); + setJSValue(vmCall(m_out.operation(operationToIndexString), m_callFrame, index)); + } + + void compileCheckStructureImmediate() + { + LValue structure = lowCell(m_node->child1()); + checkStructure( + structure, noValue(), BadCache, m_node->structureSet(), + [this] (Structure* structure) { + return weakStructure(structure); + }); + } + + void compileMaterializeNewObject() + { + ObjectMaterializationData& data = m_node->objectMaterializationData(); + + // Lower the values first, to avoid creating values inside a control flow diamond. + + Vector<LValue, 8> values; + for (unsigned i = 0; i < data.m_properties.size(); ++i) + values.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i))); + + StructureSet set; + m_interpreter.phiChildren()->forAllTransitiveIncomingValues( + m_graph.varArgChild(m_node, 0).node(), + [&] (Node* incoming) { + set.add(incoming->castConstant<Structure*>()); + }); + + Vector<LBasicBlock, 1> blocks(set.size()); + for (unsigned i = set.size(); i--;) + blocks[i] = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject case ", i)); + LBasicBlock dummyDefault = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject default case")); + LBasicBlock outerContinuation = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject continuation")); + + Vector<SwitchCase, 1> cases(set.size()); + for (unsigned i = set.size(); i--;) + cases[i] = SwitchCase(weakStructure(set[i]), blocks[i], Weight(1)); + m_out.switchInstruction( + lowCell(m_graph.varArgChild(m_node, 0)), cases, dummyDefault, Weight(0)); + + LBasicBlock outerLastNext = m_out.m_nextBlock; + + Vector<ValueFromBlock, 1> results; + + for (unsigned i = set.size(); i--;) { + m_out.appendTo(blocks[i], i + 1 < set.size() ? blocks[i + 1] : dummyDefault); + + Structure* structure = set[i]; + + LValue object; + LValue butterfly; + + if (structure->outOfLineCapacity()) { + size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); + MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); + + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject complex object allocation slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject complex object allocation continuation")); + + LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); + + LValue endOfStorage = allocateBasicStorageAndGetEnd( + m_out.constIntPtr(structure->outOfLineCapacity() * sizeof(JSValue)), + slowPath); + + LValue fastButterflyValue = m_out.add( + m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage); + + LValue fastObjectValue = allocateObject( + m_out.constIntPtr(allocator), structure, fastButterflyValue, slowPath); + + ValueFromBlock fastObject = m_out.anchor(fastObjectValue); + ValueFromBlock fastButterfly = m_out.anchor(fastButterflyValue); + m_out.jump(continuation); + + m_out.appendTo(slowPath, continuation); + + ValueFromBlock slowObject = m_out.anchor(vmCall( + m_out.operation(operationNewObjectWithButterfly), + m_callFrame, m_out.constIntPtr(structure))); + ValueFromBlock slowButterfly = m_out.anchor( + m_out.loadPtr(slowObject.value(), m_heaps.JSObject_butterfly)); + + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + + object = m_out.phi(m_out.intPtr, fastObject, slowObject); + butterfly = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); + } else { + // In the easy case where we can do a one-shot allocation, we simply allocate the + // object to directly have the desired structure. + object = allocateObject(structure); + butterfly = nullptr; // Don't have one, don't need one. + } + + for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) { + for (unsigned i = data.m_properties.size(); i--;) { + PhantomPropertyValue value = data.m_properties[i]; + if (m_graph.identifiers()[value.m_identifierNumber] != entry.key) + continue; + + LValue base = isInlineOffset(entry.offset) ? object : butterfly; + storeProperty(values[i], base, value.m_identifierNumber, entry.offset); + break; + } + } + + results.append(m_out.anchor(object)); + m_out.jump(outerContinuation); + } + + m_out.appendTo(dummyDefault, outerContinuation); + m_out.unreachable(); + + m_out.appendTo(outerContinuation, outerLastNext); + setJSValue(m_out.phi(m_out.intPtr, results)); + } + + void compileMaterializeCreateActivation() + { + ObjectMaterializationData& data = m_node->objectMaterializationData(); + + Vector<LValue, 8> values; + for (unsigned i = 0; i < data.m_properties.size(); ++i) + values.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i))); + + LValue scope = lowCell(m_graph.varArgChild(m_node, 0)); + SymbolTable* table = m_node->castOperand<SymbolTable*>(); + Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->activationStructure(); + + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MaterializeCreateActivation slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MaterializeCreateActivation continuation")); + + LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); + + LValue fastObject = allocateObject<JSLexicalEnvironment>( + JSLexicalEnvironment::allocationSize(table), structure, m_out.intPtrZero, slowPath); + + m_out.storePtr(scope, fastObject, m_heaps.JSScope_next); + m_out.storePtr(weakPointer(table), fastObject, m_heaps.JSSymbolTableObject_symbolTable); + + + ValueFromBlock fastResult = m_out.anchor(fastObject); + m_out.jump(continuation); + + m_out.appendTo(slowPath, continuation); + LValue callResult = vmCall( + m_out.operation(operationCreateActivationDirect), m_callFrame, weakPointer(structure), + scope, weakPointer(table)); + ValueFromBlock slowResult = m_out.anchor(callResult); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + LValue activation = m_out.phi(m_out.intPtr, fastResult, slowResult); + RELEASE_ASSERT(data.m_properties.size() == table->scopeSize()); + for (unsigned i = 0; i < data.m_properties.size(); ++i) { + m_out.store64(values[i], + activation, + m_heaps.JSEnvironmentRecord_variables[data.m_properties[i].m_identifierNumber]); + } + + if (validationEnabled()) { + // Validate to make sure every slot in the scope has one value. + ConcurrentJITLocker locker(table->m_lock); + for (auto iter = table->begin(locker), end = table->end(locker); iter != end; ++iter) { + bool found = false; + for (unsigned i = 0; i < data.m_properties.size(); ++i) { + if (iter->value.scopeOffset().offset() == data.m_properties[i].m_identifierNumber) { + found = true; + break; + } + } + ASSERT_UNUSED(found, found); + } + } + + setJSValue(activation); + } + +#if ENABLE(FTL_NATIVE_CALL_INLINING) + LValue getFunctionBySymbol(const CString symbol) + { + if (!m_ftlState.symbolTable.contains(symbol)) + return nullptr; + if (!getModuleByPathForSymbol(m_ftlState.symbolTable.get(symbol), symbol)) + return nullptr; + return getNamedFunction(m_ftlState.module, symbol.data()); + } + + bool getModuleByPathForSymbol(const CString path, const CString symbol) + { + if (m_ftlState.nativeLoadedLibraries.contains(path)) { + LValue function = getNamedFunction(m_ftlState.module, symbol.data()); + if (!isInlinableSize(function)) { + // We had no choice but to compile this function, but don't try to inline it ever again. + m_ftlState.symbolTable.remove(symbol); + return false; + } + return true; + } + + LMemoryBuffer memBuf; + + ASSERT(isX86() || isARM64()); + +#if PLATFORM(EFL) + const CString actualPath = toCString(bundlePath().data(), "/runtime/", path.data()); #else - speculate(m_node->child1()); + const CString actualPath = toCString(bundlePath().data(), + isX86() ? "/Resources/Runtime/x86_64/" : "/Resources/Runtime/arm64/", + path.data()); #endif + + char* outMsg; + + if (createMemoryBufferWithContentsOfFile(actualPath.data(), &memBuf, &outMsg)) { + if (Options::verboseFTLFailure()) + dataLog("Failed to load module at ", actualPath, "\n for symbol ", symbol, "\nERROR: ", outMsg, "\n"); + disposeMessage(outMsg); + return false; + } + + LModule module; + + if (parseBitcodeInContext(m_ftlState.context, memBuf, &module, &outMsg)) { + if (Options::verboseFTLFailure()) + dataLog("Failed to parse module at ", actualPath, "\n for symbol ", symbol, "\nERROR: ", outMsg, "\n"); + disposeMemoryBuffer(memBuf); + disposeMessage(outMsg); + return false; + } + + disposeMemoryBuffer(memBuf); + + if (LValue function = getNamedFunction(m_ftlState.module, symbol.data())) { + if (!isInlinableSize(function)) { + m_ftlState.symbolTable.remove(symbol); + disposeModule(module); + return false; + } + } + + Vector<CString> namedFunctions; + for (LValue function = getFirstFunction(module); function; function = getNextFunction(function)) { + CString functionName(getValueName(function)); + namedFunctions.append(functionName); + + for (LBasicBlock basicBlock = getFirstBasicBlock(function); basicBlock; basicBlock = getNextBasicBlock(basicBlock)) { + for (LValue instruction = getFirstInstruction(basicBlock); instruction; instruction = getNextInstruction(instruction)) { + setMetadata(instruction, m_tbaaKind, nullptr); + setMetadata(instruction, m_tbaaStructKind, nullptr); + } + } + } + + Vector<CString> namedGlobals; + for (LValue global = getFirstGlobal(module); global; global = getNextGlobal(global)) { + CString globalName(getValueName(global)); + namedGlobals.append(globalName); + } + + if (linkModules(m_ftlState.module, module, LLVMLinkerDestroySource, &outMsg)) { + if (Options::verboseFTLFailure()) + dataLog("Failed to link module at ", actualPath, "\n for symbol ", symbol, "\nERROR: ", outMsg, "\n"); + disposeMessage(outMsg); + return false; + } + + for (CString* symbol = namedFunctions.begin(); symbol != namedFunctions.end(); ++symbol) { + LValue function = getNamedFunction(m_ftlState.module, symbol->data()); + LLVMLinkage linkage = getLinkage(function); + if (linkage != LLVMInternalLinkage && linkage != LLVMPrivateLinkage) + setVisibility(function, LLVMHiddenVisibility); + if (!isDeclaration(function)) { + setLinkage(function, LLVMPrivateLinkage); + setLinkage(function, LLVMAvailableExternallyLinkage); + + if (ASSERT_DISABLED) + removeFunctionAttr(function, LLVMStackProtectAttribute); + } + } + + for (CString* symbol = namedGlobals.begin(); symbol != namedGlobals.end(); ++symbol) { + LValue global = getNamedGlobal(m_ftlState.module, symbol->data()); + LLVMLinkage linkage = getLinkage(global); + if (linkage != LLVMInternalLinkage && linkage != LLVMPrivateLinkage) + setVisibility(global, LLVMHiddenVisibility); + if (!isDeclaration(global)) + setLinkage(global, LLVMPrivateLinkage); + } + + m_ftlState.nativeLoadedLibraries.add(path); + return true; + } +#endif + + bool isInlinableSize(LValue function) + { + size_t instructionCount = 0; + size_t maxSize = Options::maximumLLVMInstructionCountForNativeInlining(); + for (LBasicBlock basicBlock = getFirstBasicBlock(function); basicBlock; basicBlock = getNextBasicBlock(basicBlock)) { + for (LValue instruction = getFirstInstruction(basicBlock); instruction; instruction = getNextInstruction(instruction)) { + if (++instructionCount >= maxSize) + return false; + } + } + return true; } LValue didOverflowStack() @@ -3988,6 +5598,8 @@ private: case PutById: case Call: case Construct: + case NativeCall: + case NativeConstruct: return m_out.below( m_callFrame, m_out.loadPtr( @@ -4002,6 +5614,98 @@ private: return m_out.booleanFalse; } + struct ArgumentsLength { + ArgumentsLength() + : isKnown(false) + , known(UINT_MAX) + , value(nullptr) + { + } + + bool isKnown; + unsigned known; + LValue value; + }; + ArgumentsLength getArgumentsLength(InlineCallFrame* inlineCallFrame) + { + ArgumentsLength length; + + if (inlineCallFrame && !inlineCallFrame->isVarargs()) { + length.known = inlineCallFrame->arguments.size() - 1; + length.isKnown = true; + length.value = m_out.constInt32(length.known); + } else { + length.known = UINT_MAX; + length.isKnown = false; + + VirtualRegister argumentCountRegister; + if (!inlineCallFrame) + argumentCountRegister = VirtualRegister(JSStack::ArgumentCount); + else + argumentCountRegister = inlineCallFrame->argumentCountRegister; + length.value = m_out.sub(m_out.load32(payloadFor(argumentCountRegister)), m_out.int32One); + } + + return length; + } + + ArgumentsLength getArgumentsLength() + { + return getArgumentsLength(m_node->origin.semantic.inlineCallFrame); + } + + LValue getCurrentCallee() + { + if (InlineCallFrame* frame = m_node->origin.semantic.inlineCallFrame) { + if (frame->isClosureCall) + return m_out.loadPtr(addressFor(frame->calleeRecovery.virtualRegister())); + return weakPointer(frame->calleeRecovery.constant().asCell()); + } + return m_out.loadPtr(addressFor(JSStack::Callee)); + } + + LValue getArgumentsStart(InlineCallFrame* inlineCallFrame) + { + VirtualRegister start = AssemblyHelpers::argumentsStart(inlineCallFrame); + return addressFor(start).value(); + } + + LValue getArgumentsStart() + { + return getArgumentsStart(m_node->origin.semantic.inlineCallFrame); + } + + template<typename Functor> + void checkStructure( + LValue structureDiscriminant, const FormattedValue& formattedValue, ExitKind exitKind, + const StructureSet& set, const Functor& weakStructureDiscriminant) + { + if (set.size() == 1) { + speculate( + exitKind, formattedValue, 0, + m_out.notEqual(structureDiscriminant, weakStructureDiscriminant(set[0]))); + return; + } + + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("checkStructure continuation")); + + LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); + for (unsigned i = 0; i < set.size() - 1; ++i) { + LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("checkStructure nextStructure")); + m_out.branch( + m_out.equal(structureDiscriminant, weakStructureDiscriminant(set[i])), + unsure(continuation), unsure(nextStructure)); + m_out.appendTo(nextStructure); + } + + speculate( + exitKind, formattedValue, 0, + m_out.notEqual(structureDiscriminant, weakStructureDiscriminant(set.last()))); + + m_out.jump(continuation); + m_out.appendTo(continuation, lastNext); + } + LValue numberOrNotCellToInt32(Edge edge, LValue value) { LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 int case")); @@ -4029,7 +5733,8 @@ private: m_out.jump(continuation); } else { m_out.appendTo(notIntCase, doubleCase); - m_out.branch(isCellOrMisc(value), unsure(notNumberCase), unsure(doubleCase)); + m_out.branch( + isCellOrMisc(value, provenType(edge)), unsure(notNumberCase), unsure(doubleCase)); m_out.appendTo(doubleCase, notNumberCase); results.append(m_out.anchor(doubleToInt32(unboxDouble(value)))); @@ -4093,97 +5798,87 @@ private: } LValue allocatePropertyStorage(LValue object, Structure* previousStructure) - { - if (previousStructure->couldHaveIndexingHeader()) { - return vmCall( - m_out.operation( - operationReallocateButterflyToHavePropertyStorageWithInitialCapacity), - m_callFrame, object); - } - - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage continuation")); - - LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - - LValue endOfStorage = allocateBasicStorageAndGetEnd( - m_out.constIntPtr(initialOutOfLineCapacity * sizeof(JSValue)), slowPath); - - ValueFromBlock fastButterfly = m_out.anchor( - m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); - - m_out.jump(continuation); - - m_out.appendTo(slowPath, continuation); - - ValueFromBlock slowButterfly = m_out.anchor(vmCall( - m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), m_callFrame)); - - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); + { + if (previousStructure->couldHaveIndexingHeader()) { + return vmCall( + m_out.operation( + operationReallocateButterflyToHavePropertyStorageWithInitialCapacity), + m_callFrame, object); + } - LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); + LValue result = allocatePropertyStorageWithSizeImpl(initialOutOfLineCapacity); m_out.storePtr(result, object, m_heaps.JSObject_butterfly); - return result; } LValue reallocatePropertyStorage( LValue object, LValue oldStorage, Structure* previous, Structure* next) { - size_t oldSize = previous->outOfLineCapacity() * sizeof(JSValue); + size_t oldSize = previous->outOfLineCapacity(); size_t newSize = oldSize * outOfLineGrowthFactor; - ASSERT_UNUSED(next, newSize == next->outOfLineCapacity() * sizeof(JSValue)); + ASSERT_UNUSED(next, newSize == next->outOfLineCapacity()); if (previous->couldHaveIndexingHeader()) { - LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue)); + LValue newAllocSize = m_out.constIntPtr(newSize); return vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize); } - LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage slow path")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage continuation")); + LValue result = allocatePropertyStorageWithSizeImpl(newSize); + + ptrdiff_t headerSize = -sizeof(IndexingHeader) - sizeof(void*); + ptrdiff_t endStorage = headerSize - static_cast<ptrdiff_t>(oldSize * sizeof(JSValue)); + + for (ptrdiff_t offset = headerSize; offset > endStorage; offset -= sizeof(void*)) { + LValue loaded = + m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset)); + m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset)); + } + + m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly)); + + return result; + } + + LValue allocatePropertyStorageWithSizeImpl(size_t sizeInValues) + { + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorageWithSizeImpl slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorageWithSizeImpl continuation")); + LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); - LValue endOfStorage = - allocateBasicStorageAndGetEnd(m_out.constIntPtr(newSize), slowPath); + LValue endOfStorage = allocateBasicStorageAndGetEnd( + m_out.constIntPtr(sizeInValues * sizeof(JSValue)), slowPath); - ValueFromBlock fastButterfly = m_out.anchor(m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); + ValueFromBlock fastButterfly = m_out.anchor( + m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); m_out.jump(continuation); m_out.appendTo(slowPath, continuation); - LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue)); - - LValue storageLocation = vmCall(m_out.operation(operationAllocatePropertyStorage), m_callFrame, newAllocSize); - - ValueFromBlock slowButterfly = m_out.anchor(storageLocation); + LValue slowButterflyValue; + if (sizeInValues == initialOutOfLineCapacity) { + slowButterflyValue = vmCall( + m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), + m_callFrame); + } else { + slowButterflyValue = vmCall( + m_out.operation(operationAllocatePropertyStorage), + m_callFrame, m_out.constIntPtr(sizeInValues)); + } + ValueFromBlock slowButterfly = m_out.anchor(slowButterflyValue); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); - LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); - - ptrdiff_t headerSize = -sizeof(JSValue) - sizeof(void *); - ptrdiff_t endStorage = headerSize - static_cast<ptrdiff_t>(oldSize); - - for (ptrdiff_t offset = headerSize; offset > endStorage; offset -= sizeof(void*)) { - LValue loaded = - m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset)); - m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset)); - } - - m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly)); - - return result; + return m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); } LValue getById(LValue base) { - StringImpl* uid = m_graph.identifiers()[m_node->identifierNumber()]; + auto uid = m_graph.identifiers()[m_node->identifierNumber()]; // Arguments: id, bytes, target, numArgs, args... unsigned stackmapID = m_stackmapIDs++; @@ -4202,11 +5897,10 @@ private: return call; } - TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge) + TypedPointer baseIndex(IndexedAbstractHeap& heap, LValue storage, LValue index, Edge edge, ptrdiff_t offset = 0) { return m_out.baseIndex( - heap, storage, m_out.zeroExt(index, m_out.intPtr), - m_state.forNode(edge).m_value); + heap, storage, m_out.zeroExtPtr(index), provenValue(edge), offset); } void compare( @@ -4240,7 +5934,7 @@ private: return; } - LOWERING_FAILED(m_node, "Bad use kinds"); + DFG_CRASH(m_graph, m_node, "Bad use kinds"); } void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild) @@ -4254,7 +5948,9 @@ private: LBasicBlock leftNotCellCase = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject left not cell case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareEqObjectOrOtherToObject continuation")); - m_out.branch(isCell(leftValue), unsure(leftCellCase), unsure(leftNotCellCase)); + m_out.branch( + isCell(leftValue, provenType(leftChild)), + unsure(leftCellCase), unsure(leftNotCellCase)); LBasicBlock lastNext = m_out.appendTo(leftCellCase, leftNotCellCase); speculateTruthyObject(leftChild, leftValue, SpecObject | (~SpecCell)); @@ -4278,10 +5974,7 @@ private: return; } - LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID); - FTL_TYPE_CHECK( - jsValueValue(cell), edge, filter, - m_out.equal(structureID, m_out.constInt32(vm().stringStructure->id()))); + FTL_TYPE_CHECK(jsValueValue(cell), edge, filter, isNotObject(cell)); speculate( BadType, jsValueValue(cell), edge.node(), m_out.testNonZero8( @@ -4318,7 +6011,7 @@ private: setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult)); } - LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath) + LValue allocateCell(LValue allocator, LBasicBlock slowPath) { LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success")); @@ -4333,12 +6026,21 @@ private: m_out.loadPtr(result, m_heaps.JSCell_freeListNext), allocator, m_heaps.MarkedAllocator_freeListHead); - m_out.store32(m_out.constInt32(structure->id()), result, m_heaps.JSCell_structureID); - m_out.store8(m_out.constInt8(structure->indexingType()), result, m_heaps.JSCell_indexingType); - m_out.store8(m_out.constInt8(structure->typeInfo().type()), result, m_heaps.JSCell_typeInfoType); - m_out.store8(m_out.constInt8(structure->typeInfo().inlineTypeFlags()), result, m_heaps.JSCell_typeInfoFlags); - m_out.store8(m_out.constInt8(JSCell::NotMarked), result, m_heaps.JSCell_gcData); - + return result; + } + + void storeStructure(LValue object, Structure* structure) + { + m_out.store32(m_out.constInt32(structure->id()), object, m_heaps.JSCell_structureID); + m_out.store32( + m_out.constInt32(structure->objectInitializationBlob()), + object, m_heaps.JSCell_usefulBytes); + } + + LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath) + { + LValue result = allocateCell(allocator, slowPath); + storeStructure(result, structure); return result; } @@ -4351,19 +6053,63 @@ private: } template<typename ClassType> - LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath) + LValue allocateObject( + size_t size, Structure* structure, LValue butterfly, LBasicBlock slowPath) { - MarkedAllocator* allocator; - size_t size = ClassType::allocationSize(0); - if (ClassType::needsDestruction && ClassType::hasImmortalStructure) - allocator = &vm().heap.allocatorForObjectWithImmortalStructureDestructor(size); - else if (ClassType::needsDestruction) - allocator = &vm().heap.allocatorForObjectWithNormalDestructor(size); - else - allocator = &vm().heap.allocatorForObjectWithoutDestructor(size); + MarkedAllocator* allocator = &vm().heap.allocatorForObjectOfType<ClassType>(size); return allocateObject(m_out.constIntPtr(allocator), structure, butterfly, slowPath); } + template<typename ClassType> + LValue allocateObject(Structure* structure, LValue butterfly, LBasicBlock slowPath) + { + return allocateObject<ClassType>( + ClassType::allocationSize(0), structure, butterfly, slowPath); + } + + template<typename ClassType> + LValue allocateVariableSizedObject( + LValue size, Structure* structure, LValue butterfly, LBasicBlock slowPath) + { + static_assert(!(MarkedSpace::preciseStep & (MarkedSpace::preciseStep - 1)), "MarkedSpace::preciseStep must be a power of two."); + static_assert(!(MarkedSpace::impreciseStep & (MarkedSpace::impreciseStep - 1)), "MarkedSpace::impreciseStep must be a power of two."); + + LValue subspace = m_out.constIntPtr(&vm().heap.subspaceForObjectOfType<ClassType>()); + + LBasicBlock smallCaseBlock = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject small case")); + LBasicBlock largeOrOversizeCaseBlock = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject large or oversize case")); + LBasicBlock largeCaseBlock = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject large case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocateVariableSizedObject continuation")); + + LValue uproundedSize = m_out.add(size, m_out.constInt32(MarkedSpace::preciseStep - 1)); + LValue isSmall = m_out.below(uproundedSize, m_out.constInt32(MarkedSpace::preciseCutoff)); + m_out.branch(isSmall, unsure(smallCaseBlock), unsure(largeOrOversizeCaseBlock)); + + LBasicBlock lastNext = m_out.appendTo(smallCaseBlock, largeOrOversizeCaseBlock); + TypedPointer address = m_out.baseIndex( + m_heaps.MarkedSpace_Subspace_preciseAllocators, subspace, + m_out.zeroExtPtr(m_out.lShr(uproundedSize, m_out.constInt32(getLSBSet(MarkedSpace::preciseStep))))); + ValueFromBlock smallAllocator = m_out.anchor(address.value()); + m_out.jump(continuation); + + m_out.appendTo(largeOrOversizeCaseBlock, largeCaseBlock); + m_out.branch( + m_out.below(uproundedSize, m_out.constInt32(MarkedSpace::impreciseCutoff)), + usually(largeCaseBlock), rarely(slowPath)); + + m_out.appendTo(largeCaseBlock, continuation); + address = m_out.baseIndex( + m_heaps.MarkedSpace_Subspace_impreciseAllocators, subspace, + m_out.zeroExtPtr(m_out.lShr(uproundedSize, m_out.constInt32(getLSBSet(MarkedSpace::impreciseStep))))); + ValueFromBlock largeAllocator = m_out.anchor(address.value()); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + LValue allocator = m_out.phi(m_out.intPtr, smallAllocator, largeAllocator); + + return allocateObject(allocator, structure, butterfly, slowPath); + } + // Returns a pointer to the end of the allocation. LValue allocateBasicStorageAndGetEnd(LValue size, LBasicBlock slowPath) { @@ -4385,6 +6131,31 @@ private: m_out.loadPtr(m_out.absolute(&allocator.m_currentPayloadEnd)), newRemaining); } + LValue allocateObject(Structure* structure) + { + size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); + MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); + + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocateObject slow path")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocateObject continuation")); + + LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); + + ValueFromBlock fastResult = m_out.anchor(allocateObject( + m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath)); + + m_out.jump(continuation); + + m_out.appendTo(slowPath, continuation); + + ValueFromBlock slowResult = m_out.anchor(vmCall( + m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure))); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + return m_out.phi(m_out.intPtr, fastResult, slowResult); + } + struct ArrayValues { ArrayValues() : array(0) @@ -4468,7 +6239,8 @@ private: LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode, LValue base) { - if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseEdge.node(), arrayMode)) + JSArrayBufferView* view = m_graph.tryGetFoldableView(provenValue(baseEdge), arrayMode); + if (view) return m_out.constInt32(view->length()); return m_out.load32NonNegative(base, m_heaps.JSArrayBufferView_length); } @@ -4482,9 +6254,9 @@ private: { switch (edge.useKind()) { case BooleanUse: - return lowBoolean(m_node->child1()); + return lowBoolean(edge); case Int32Use: - return m_out.notZero32(lowInt32(m_node->child1())); + return m_out.notZero32(lowInt32(edge)); case DoubleRepUse: return m_out.doubleNotEqual(lowDouble(edge), m_out.doubleZero); case ObjectOrOtherUse: @@ -4493,33 +6265,111 @@ private: edge, CellCaseSpeculatesObject, SpeculateNullOrUndefined, ManualOperandSpeculation)); case StringUse: { - LValue stringValue = lowString(m_node->child1()); + LValue stringValue = lowString(edge); LValue length = m_out.load32NonNegative(stringValue, m_heaps.JSString_length); return m_out.notEqual(length, m_out.int32Zero); } case UntypedUse: { - LValue value = lowJSValue(m_node->child1()); - - LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped slow case")); - LBasicBlock fastCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped fast case")); + LValue value = lowJSValue(edge); + + // Implements the following control flow structure: + // if (value is cell) { + // if (value is string) + // result = !!value->length + // else { + // do evil things for masquerades-as-undefined + // result = true + // } + // } else if (value is int32) { + // result = !!unboxInt32(value) + // } else if (value is number) { + // result = !!unboxDouble(value) + // } else { + // result = value == jsTrue + // } + + LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped cell case")); + LBasicBlock stringCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped string case")); + LBasicBlock notStringCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped not string case")); + LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped not cell case")); + LBasicBlock int32Case = FTL_NEW_BLOCK(m_out, ("Boolify untyped int32 case")); + LBasicBlock notInt32Case = FTL_NEW_BLOCK(m_out, ("Boolify untyped not int32 case")); + LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped double case")); + LBasicBlock notDoubleCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped not double case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Boolify untyped continuation")); - m_out.branch(isNotBoolean(value), rarely(slowCase), usually(fastCase)); + Vector<ValueFromBlock> results; - LBasicBlock lastNext = m_out.appendTo(fastCase, slowCase); - ValueFromBlock fastResult = m_out.anchor(unboxBoolean(value)); + m_out.branch(isCell(value, provenType(edge)), unsure(cellCase), unsure(notCellCase)); + + LBasicBlock lastNext = m_out.appendTo(cellCase, stringCase); + m_out.branch( + isString(value, provenType(edge) & SpecCell), + unsure(stringCase), unsure(notStringCase)); + + m_out.appendTo(stringCase, notStringCase); + LValue nonEmptyString = m_out.notZero32( + m_out.load32NonNegative(value, m_heaps.JSString_length)); + results.append(m_out.anchor(nonEmptyString)); m_out.jump(continuation); - m_out.appendTo(slowCase, continuation); - ValueFromBlock slowResult = m_out.anchor(m_out.notNull(vmCall( - m_out.operation(operationConvertJSValueToBoolean), m_callFrame, value))); + m_out.appendTo(notStringCase, notCellCase); + LValue isTruthyObject; + if (masqueradesAsUndefinedWatchpointIsStillValid()) + isTruthyObject = m_out.booleanTrue; + else { + LBasicBlock masqueradesCase = FTL_NEW_BLOCK(m_out, ("Boolify untyped masquerades case")); + + results.append(m_out.anchor(m_out.booleanTrue)); + + m_out.branch( + m_out.testIsZero8( + m_out.load8(value, m_heaps.JSCell_typeInfoFlags), + m_out.constInt8(MasqueradesAsUndefined)), + usually(continuation), rarely(masqueradesCase)); + + m_out.appendTo(masqueradesCase); + + isTruthyObject = m_out.notEqual( + m_out.constIntPtr(m_graph.globalObjectFor(m_node->origin.semantic)), + m_out.loadPtr(loadStructure(value), m_heaps.Structure_globalObject)); + } + results.append(m_out.anchor(isTruthyObject)); + m_out.jump(continuation); + + m_out.appendTo(notCellCase, int32Case); + m_out.branch( + isInt32(value, provenType(edge) & ~SpecCell), + unsure(int32Case), unsure(notInt32Case)); + + m_out.appendTo(int32Case, notInt32Case); + results.append(m_out.anchor(m_out.notZero32(unboxInt32(value)))); + m_out.jump(continuation); + + m_out.appendTo(notInt32Case, doubleCase); + m_out.branch( + isNumber(value, provenType(edge) & ~SpecCell), + unsure(doubleCase), unsure(notDoubleCase)); + + m_out.appendTo(doubleCase, notDoubleCase); + // Note that doubleNotEqual() really means not-equal-and-ordered. It will return false + // if value is NaN. + LValue doubleIsTruthy = m_out.doubleNotEqual( + unboxDouble(value), m_out.constDouble(0)); + results.append(m_out.anchor(doubleIsTruthy)); + m_out.jump(continuation); + + m_out.appendTo(notDoubleCase, continuation); + LValue miscIsTruthy = m_out.equal( + value, m_out.constInt64(JSValue::encode(jsBoolean(true)))); + results.append(m_out.anchor(miscIsTruthy)); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); - return m_out.phi(m_out.boolean, fastResult, slowResult); + return m_out.phi(m_out.boolean, results); } default: - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); return 0; } } @@ -4546,7 +6396,7 @@ private: LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined primitive case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("EqualNullOrUndefined continuation")); - m_out.branch(isNotCell(value), unsure(primitiveCase), unsure(cellCase)); + m_out.branch(isNotCell(value, provenType(edge)), unsure(primitiveCase), unsure(cellCase)); LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase); @@ -4557,10 +6407,7 @@ private: break; case CellCaseSpeculatesObject: FTL_TYPE_CHECK( - jsValueValue(value), edge, (~SpecCell) | SpecObject, - m_out.equal( - m_out.load32(value, m_heaps.JSCell_structureID), - m_out.constInt32(vm().stringStructure->id()))); + jsValueValue(value), edge, (~SpecCell) | SpecObject, isNotObject(value)); break; } @@ -4601,7 +6448,7 @@ private: primitiveResult = m_out.equal(value, m_out.constInt64(ValueUndefined)); break; case EqualNullOrUndefined: - primitiveResult = isOther(value); + primitiveResult = isOther(value, provenType(edge)); break; case SpeculateNullOrUndefined: FTL_TYPE_CHECK( @@ -4672,7 +6519,7 @@ private: Vector<SwitchCase> cases; for (unsigned i = 0; i < data->cases.size(); ++i) { cases.append(SwitchCase( - constInt(type, data->cases[i].value.switchLookupValue()), + constInt(type, data->cases[i].value.switchLookupValue(data->kind)), lowBlock(data->cases[i].target.block), Weight(data->cases[i].target.count))); } @@ -4681,6 +6528,434 @@ private: lowBlock(data->fallThrough.block), Weight(data->fallThrough.count)); } + void switchString(SwitchData* data, LValue string) + { + bool canDoBinarySwitch = true; + unsigned totalLength = 0; + + for (DFG::SwitchCase myCase : data->cases) { + StringImpl* string = myCase.value.stringImpl(); + if (!string->is8Bit()) { + canDoBinarySwitch = false; + break; + } + if (string->length() > Options::maximumBinaryStringSwitchCaseLength()) { + canDoBinarySwitch = false; + break; + } + totalLength += string->length(); + } + + if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) { + switchStringSlow(data, string); + return; + } + + LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value); + LValue length = m_out.load32(string, m_heaps.JSString_length); + + LBasicBlock hasImplBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString has impl case")); + LBasicBlock is8BitBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString is 8 bit case")); + LBasicBlock slowBlock = FTL_NEW_BLOCK(m_out, ("Switch/SwitchString slow case")); + + m_out.branch(m_out.isNull(stringImpl), unsure(slowBlock), unsure(hasImplBlock)); + + LBasicBlock lastNext = m_out.appendTo(hasImplBlock, is8BitBlock); + + m_out.branch( + m_out.testIsZero32( + m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), + m_out.constInt32(StringImpl::flagIs8Bit())), + unsure(slowBlock), unsure(is8BitBlock)); + + m_out.appendTo(is8BitBlock, slowBlock); + + LValue buffer = m_out.loadPtr(stringImpl, m_heaps.StringImpl_data); + + // FIXME: We should propagate branch weight data to the cases of this switch. + // https://bugs.webkit.org/show_bug.cgi?id=144368 + + Vector<StringSwitchCase> cases; + for (DFG::SwitchCase myCase : data->cases) + cases.append(StringSwitchCase(myCase.value.stringImpl(), lowBlock(myCase.target.block))); + std::sort(cases.begin(), cases.end()); + switchStringRecurse(data, buffer, length, cases, 0, 0, cases.size(), 0, false); + + m_out.appendTo(slowBlock, lastNext); + switchStringSlow(data, string); + } + + // The code for string switching is based closely on the same code in the DFG backend. While it + // would be nice to reduce the amount of similar-looking code, it seems like this is one of + // those algorithms where factoring out the common bits would result in more code than just + // duplicating. + + struct StringSwitchCase { + StringSwitchCase() { } + + StringSwitchCase(StringImpl* string, LBasicBlock target) + : string(string) + , target(target) + { + } + + bool operator<(const StringSwitchCase& other) const + { + return stringLessThan(*string, *other.string); + } + + StringImpl* string; + LBasicBlock target; + }; + + struct CharacterCase { + CharacterCase() + : character(0) + , begin(0) + , end(0) + { + } + + CharacterCase(LChar character, unsigned begin, unsigned end) + : character(character) + , begin(begin) + , end(end) + { + } + + bool operator<(const CharacterCase& other) const + { + return character < other.character; + } + + LChar character; + unsigned begin; + unsigned end; + }; + + void switchStringRecurse( + SwitchData* data, LValue buffer, LValue length, const Vector<StringSwitchCase>& cases, + unsigned numChecked, unsigned begin, unsigned end, unsigned alreadyCheckedLength, + unsigned checkedExactLength) + { + LBasicBlock fallThrough = lowBlock(data->fallThrough.block); + + if (begin == end) { + m_out.jump(fallThrough); + return; + } + + unsigned minLength = cases[begin].string->length(); + unsigned commonChars = minLength; + bool allLengthsEqual = true; + for (unsigned i = begin + 1; i < end; ++i) { + unsigned myCommonChars = numChecked; + unsigned limit = std::min(cases[begin].string->length(), cases[i].string->length()); + for (unsigned j = numChecked; j < limit; ++j) { + if (cases[begin].string->at(j) != cases[i].string->at(j)) + break; + myCommonChars++; + } + commonChars = std::min(commonChars, myCommonChars); + if (minLength != cases[i].string->length()) + allLengthsEqual = false; + minLength = std::min(minLength, cases[i].string->length()); + } + + if (checkedExactLength) { + DFG_ASSERT(m_graph, m_node, alreadyCheckedLength == minLength); + DFG_ASSERT(m_graph, m_node, allLengthsEqual); + } + + DFG_ASSERT(m_graph, m_node, minLength >= commonChars); + + if (!allLengthsEqual && alreadyCheckedLength < minLength) + m_out.check(m_out.below(length, m_out.constInt32(minLength)), unsure(fallThrough)); + if (allLengthsEqual && (alreadyCheckedLength < minLength || !checkedExactLength)) + m_out.check(m_out.notEqual(length, m_out.constInt32(minLength)), unsure(fallThrough)); + + for (unsigned i = numChecked; i < commonChars; ++i) { + m_out.check( + m_out.notEqual( + m_out.load8(buffer, m_heaps.characters8[i]), + m_out.constInt8(cases[begin].string->at(i))), + unsure(fallThrough)); + } + + if (minLength == commonChars) { + // This is the case where one of the cases is a prefix of all of the other cases. + // We've already checked that the input string is a prefix of all of the cases, + // so we just check length to jump to that case. + + DFG_ASSERT(m_graph, m_node, cases[begin].string->length() == commonChars); + for (unsigned i = begin + 1; i < end; ++i) + DFG_ASSERT(m_graph, m_node, cases[i].string->length() > commonChars); + + if (allLengthsEqual) { + DFG_ASSERT(m_graph, m_node, end == begin + 1); + m_out.jump(cases[begin].target); + return; + } + + m_out.check( + m_out.equal(length, m_out.constInt32(commonChars)), + unsure(cases[begin].target)); + + // We've checked if the length is >= minLength, and then we checked if the length is + // == commonChars. We get to this point if it is >= minLength but not == commonChars. + // Hence we know that it now must be > minLength, i.e. that it's >= minLength + 1. + switchStringRecurse( + data, buffer, length, cases, commonChars, begin + 1, end, minLength + 1, false); + return; + } + + // At this point we know that the string is longer than commonChars, and we've only verified + // commonChars. Use a binary switch on the next unchecked character, i.e. + // string[commonChars]. + + DFG_ASSERT(m_graph, m_node, end >= begin + 2); + + LValue uncheckedChar = m_out.load8(buffer, m_heaps.characters8[commonChars]); + + Vector<CharacterCase> characterCases; + CharacterCase currentCase(cases[begin].string->at(commonChars), begin, begin + 1); + for (unsigned i = begin + 1; i < end; ++i) { + LChar currentChar = cases[i].string->at(commonChars); + if (currentChar != currentCase.character) { + currentCase.end = i; + characterCases.append(currentCase); + currentCase = CharacterCase(currentChar, i, i + 1); + } else + currentCase.end = i + 1; + } + characterCases.append(currentCase); + + Vector<LBasicBlock> characterBlocks; + for (CharacterCase& myCase : characterCases) + characterBlocks.append(FTL_NEW_BLOCK(m_out, ("Switch/SwitchString case for ", myCase.character, " at index ", commonChars))); + + Vector<SwitchCase> switchCases; + for (unsigned i = 0; i < characterCases.size(); ++i) { + if (i) + DFG_ASSERT(m_graph, m_node, characterCases[i - 1].character < characterCases[i].character); + switchCases.append(SwitchCase( + m_out.constInt8(characterCases[i].character), characterBlocks[i], Weight())); + } + m_out.switchInstruction(uncheckedChar, switchCases, fallThrough, Weight()); + + LBasicBlock lastNext = m_out.m_nextBlock; + characterBlocks.append(lastNext); // Makes it convenient to set nextBlock. + for (unsigned i = 0; i < characterCases.size(); ++i) { + m_out.appendTo(characterBlocks[i], characterBlocks[i + 1]); + switchStringRecurse( + data, buffer, length, cases, commonChars + 1, + characterCases[i].begin, characterCases[i].end, minLength, allLengthsEqual); + } + + DFG_ASSERT(m_graph, m_node, m_out.m_nextBlock == lastNext); + } + + void switchStringSlow(SwitchData* data, LValue string) + { + // FIXME: We ought to be able to use computed gotos here. We would save the labels of the + // blocks we want to jump to, and then request their addresses after compilation completes. + // https://bugs.webkit.org/show_bug.cgi?id=144369 + + LValue branchOffset = vmCall( + m_out.operation(operationSwitchStringAndGetBranchOffset), + m_callFrame, m_out.constIntPtr(data->switchTableIndex), string); + + StringJumpTable& table = codeBlock()->stringSwitchJumpTable(data->switchTableIndex); + + Vector<SwitchCase> cases; + std::unordered_set<int32_t> alreadyHandled; // These may be negative, or zero, or probably other stuff, too. We don't want to mess with HashSet's corner cases and we don't really care about throughput here. + for (unsigned i = 0; i < data->cases.size(); ++i) { + // FIXME: The fact that we're using the bytecode's switch table means that the + // following DFG IR transformation would be invalid. + // + // Original code: + // switch (v) { + // case "foo": + // case "bar": + // things(); + // break; + // default: + // break; + // } + // + // New code: + // switch (v) { + // case "foo": + // instrumentFoo(); + // goto _things; + // case "bar": + // instrumentBar(); + // _things: + // things(); + // break; + // default: + // break; + // } + // + // Luckily, we don't currently do any such transformation. But it's kind of silly that + // this is an issue. + // https://bugs.webkit.org/show_bug.cgi?id=144635 + + DFG::SwitchCase myCase = data->cases[i]; + StringJumpTable::StringOffsetTable::iterator iter = + table.offsetTable.find(myCase.value.stringImpl()); + DFG_ASSERT(m_graph, m_node, iter != table.offsetTable.end()); + + if (!alreadyHandled.insert(iter->value.branchOffset).second) + continue; + + cases.append(SwitchCase( + m_out.constInt32(iter->value.branchOffset), + lowBlock(myCase.target.block), Weight(myCase.target.count))); + } + + m_out.switchInstruction( + branchOffset, cases, lowBlock(data->fallThrough.block), + Weight(data->fallThrough.count)); + } + + // Calls the functor at the point of code generation where we know what the result type is. + // You can emit whatever code you like at that point. Expects you to terminate the basic block. + // When buildTypeOf() returns, it will have terminated all basic blocks that it created. So, if + // you aren't using this as the terminator of a high-level block, you should create your own + // contination and set it as the nextBlock (m_out.insertNewBlocksBefore(continuation)) before + // calling this. For example: + // + // LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("My continuation")); + // LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); + // buildTypeOf( + // child, value, + // [&] (TypeofType type) { + // do things; + // m_out.jump(continuation); + // }); + // m_out.appendTo(continuation, lastNext); + template<typename Functor> + void buildTypeOf(Edge child, LValue value, const Functor& functor) + { + JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); + + // Implements the following branching structure: + // + // if (is cell) { + // if (is object) { + // if (is function) { + // return function; + // } else if (doesn't have call trap and doesn't masquerade as undefined) { + // return object + // } else { + // return slowPath(); + // } + // } else if (is string) { + // return string + // } else { + // return symbol + // } + // } else if (is number) { + // return number + // } else if (is null) { + // return object + // } else if (is boolean) { + // return boolean + // } else { + // return undefined + // } + + LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf cell case")); + LBasicBlock objectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf object case")); + LBasicBlock functionCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf function case")); + LBasicBlock notFunctionCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not function case")); + LBasicBlock reallyObjectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf really object case")); + LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("buildTypeOf slow path")); + LBasicBlock unreachable = FTL_NEW_BLOCK(m_out, ("buildTypeOf unreachable")); + LBasicBlock notObjectCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not object case")); + LBasicBlock stringCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf string case")); + LBasicBlock symbolCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf symbol case")); + LBasicBlock notCellCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not cell case")); + LBasicBlock numberCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf number case")); + LBasicBlock notNumberCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not number case")); + LBasicBlock notNullCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf not null case")); + LBasicBlock booleanCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf boolean case")); + LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("buildTypeOf undefined case")); + + m_out.branch(isCell(value, provenType(child)), unsure(cellCase), unsure(notCellCase)); + + LBasicBlock lastNext = m_out.appendTo(cellCase, objectCase); + m_out.branch(isObject(value, provenType(child)), unsure(objectCase), unsure(notObjectCase)); + + m_out.appendTo(objectCase, functionCase); + m_out.branch( + isFunction(value, provenType(child) & SpecObject), + unsure(functionCase), unsure(notFunctionCase)); + + m_out.appendTo(functionCase, notFunctionCase); + functor(TypeofType::Function); + + m_out.appendTo(notFunctionCase, reallyObjectCase); + m_out.branch( + isExoticForTypeof(value, provenType(child) & (SpecObject - SpecFunction)), + rarely(slowPath), usually(reallyObjectCase)); + + m_out.appendTo(reallyObjectCase, slowPath); + functor(TypeofType::Object); + + m_out.appendTo(slowPath, unreachable); + LValue result = vmCall( + m_out.operation(operationTypeOfObjectAsTypeofType), m_callFrame, + weakPointer(globalObject), value); + Vector<SwitchCase, 3> cases; + cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Undefined)), undefinedCase)); + cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Object)), reallyObjectCase)); + cases.append(SwitchCase(m_out.constInt32(static_cast<int32_t>(TypeofType::Function)), functionCase)); + m_out.switchInstruction(result, cases, unreachable, Weight()); + + m_out.appendTo(unreachable, notObjectCase); + m_out.unreachable(); + + m_out.appendTo(notObjectCase, stringCase); + m_out.branch( + isString(value, provenType(child) & (SpecCell - SpecObject)), + unsure(stringCase), unsure(symbolCase)); + + m_out.appendTo(stringCase, symbolCase); + functor(TypeofType::String); + + m_out.appendTo(symbolCase, notCellCase); + functor(TypeofType::Symbol); + + m_out.appendTo(notCellCase, numberCase); + m_out.branch( + isNumber(value, provenType(child) & ~SpecCell), + unsure(numberCase), unsure(notNumberCase)); + + m_out.appendTo(numberCase, notNumberCase); + functor(TypeofType::Number); + + m_out.appendTo(notNumberCase, notNullCase); + LValue isNull; + if (provenType(child) & SpecOther) + isNull = m_out.equal(value, m_out.constInt64(ValueNull)); + else + isNull = m_out.booleanFalse; + m_out.branch(isNull, unsure(reallyObjectCase), unsure(notNullCase)); + + m_out.appendTo(notNullCase, booleanCase); + m_out.branch( + isBoolean(value, provenType(child) & ~(SpecCell | SpecFullNumber)), + unsure(booleanCase), unsure(undefinedCase)); + + m_out.appendTo(booleanCase, undefinedCase); + functor(TypeofType::Boolean); + + m_out.appendTo(undefinedCase, lastNext); + functor(TypeofType::Undefined); + } + LValue doubleToInt32(LValue doubleValue, double low, double high, bool isSigned = true) { LBasicBlock greatEnough = FTL_NEW_BLOCK(m_out, ("doubleToInt32 greatEnough")); @@ -4745,19 +7020,6 @@ private: return m_out.phi(m_out.int32, fastResult, slowResult); } - void checkArgumentsNotCreated() - { - CodeOrigin codeOrigin = m_node->origin.semantic; - VirtualRegister argumentsRegister = m_graph.argumentsRegisterFor(codeOrigin); - if (isEmptySpeculation(m_state.variables().operand(argumentsRegister).m_type)) - return; - - VirtualRegister argsReg = m_graph.machineArgumentsRegisterFor(codeOrigin); - speculate( - ArgumentsEscaped, noValue(), 0, - m_out.notZero64(m_out.load64(addressFor(argsReg)))); - } - void speculate( ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) { @@ -4766,7 +7028,13 @@ private: void terminate(ExitKind kind) { - speculate(kind, noValue(), 0, m_out.booleanTrue); + speculate(kind, noValue(), nullptr, m_out.booleanTrue); + didAlreadyTerminate(); + } + + void didAlreadyTerminate() + { + m_state.setIsValid(false); } void typeCheck( @@ -4792,7 +7060,7 @@ private: ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use)); if (edge->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); + JSValue value = edge->asJSValue(); if (!value.isInt32()) { terminate(Uncountable); return m_out.int32Zero; @@ -4822,7 +7090,7 @@ private: return result; } - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecInt32)); + DFG_ASSERT(m_graph, m_node, !(provenType(edge) & SpecInt32)); terminate(Uncountable); return m_out.int32Zero; } @@ -4830,7 +7098,7 @@ private: enum Int52Kind { StrictInt52, Int52 }; LValue lowInt52(Edge edge, Int52Kind kind) { - RELEASE_ASSERT(edge.useKind() == Int52RepUse); + DFG_ASSERT(m_graph, m_node, edge.useKind() == Int52RepUse); LoweredNodeValue value; @@ -4856,7 +7124,7 @@ private: break; } - RELEASE_ASSERT(!m_state.forNode(edge).m_type); + DFG_ASSERT(m_graph, m_node, !provenType(edge)); terminate(Uncountable); return m_out.int64Zero; } @@ -4892,7 +7160,7 @@ private: case StrictInt52: return Int52; } - LOWERING_FAILED(m_node, "Bad use kind"); + DFG_CRASH(m_graph, m_node, "Bad use kind"); return Int52; } @@ -4904,10 +7172,10 @@ private: LValue lowCell(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind())); + DFG_ASSERT(m_graph, m_node, mode == ManualOperandSpeculation || DFG::isCell(edge.useKind())); if (edge->op() == JSConstant) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); + JSValue value = edge->asJSValue(); if (!value.isCell()) { terminate(Uncountable); return m_out.intPtrZero; @@ -4923,7 +7191,7 @@ private: return uncheckedValue; } - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecCell)); + DFG_ASSERT(m_graph, m_node, !(provenType(edge) & SpecCell)); terminate(Uncountable); return m_out.intPtrZero; } @@ -4970,7 +7238,7 @@ private: ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse); if (edge->hasConstant()) { - JSValue value = m_graph.valueOfJSConstant(edge.node()); + JSValue value = edge->asJSValue(); if (!value.isBoolean()) { terminate(Uncountable); return m_out.booleanFalse; @@ -4992,33 +7260,32 @@ private: return result; } - RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean)); + DFG_ASSERT(m_graph, m_node, !(provenType(edge) & SpecBoolean)); terminate(Uncountable); return m_out.booleanFalse; } LValue lowDouble(Edge edge) { - RELEASE_ASSERT(isDouble(edge.useKind())); + DFG_ASSERT(m_graph, m_node, isDouble(edge.useKind())); LoweredNodeValue value = m_doubleValues.get(edge.node()); if (isValid(value)) return value.value(); - - RELEASE_ASSERT(!m_state.forNode(edge).m_type); + DFG_ASSERT(m_graph, m_node, !provenType(edge)); terminate(Uncountable); return m_out.doubleZero; } LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) { - ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse); - RELEASE_ASSERT(!isDouble(edge.useKind())); - RELEASE_ASSERT(edge.useKind() != Int52RepUse); + DFG_ASSERT(m_graph, m_node, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse); + DFG_ASSERT(m_graph, m_node, !isDouble(edge.useKind())); + DFG_ASSERT(m_graph, m_node, edge.useKind() != Int52RepUse); if (edge->hasConstant()) - return m_out.constInt64(JSValue::encode(m_graph.valueOfJSConstant(edge.node()))); - + return m_out.constInt64(JSValue::encode(edge->asJSValue())); + LoweredNodeValue value = m_jsValueValues.get(edge.node()); if (isValid(value)) return value.value(); @@ -5037,7 +7304,7 @@ private: return result; } - LOWERING_FAILED(m_node, "Corrupt array class"); + DFG_CRASH(m_graph, m_node, "Value not defined"); return 0; } @@ -5104,8 +7371,16 @@ private: return m_out.aShr(value, m_out.constInt64(JSValue::int52ShiftAmount)); } - LValue isNotInt32(LValue jsValue) + LValue isInt32(LValue jsValue, SpeculatedType type = SpecFullTop) + { + if (LValue proven = isProvenValue(type, SpecInt32)) + return proven; + return m_out.aboveOrEqual(jsValue, m_tagTypeNumber); + } + LValue isNotInt32(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~SpecInt32)) + return proven; return m_out.below(jsValue, m_tagTypeNumber); } LValue unboxInt32(LValue jsValue) @@ -5117,12 +7392,16 @@ private: return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber); } - LValue isCellOrMisc(LValue jsValue) + LValue isCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, SpecCell | SpecMisc)) + return proven; return m_out.testIsZero64(jsValue, m_tagTypeNumber); } - LValue isNotCellOrMisc(LValue jsValue) + LValue isNotCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~(SpecCell | SpecMisc))) + return proven; return m_out.testNonZero64(jsValue, m_tagTypeNumber); } @@ -5134,39 +7413,6 @@ private: { return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber); } - LValue jsValueToDouble(Edge edge, LValue boxedValue) - { - LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case")); - LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case")); - LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation")); - - LValue isNotInt32; - if (!m_interpreter.needsTypeCheck(edge, SpecInt32)) - isNotInt32 = m_out.booleanFalse; - else if (!m_interpreter.needsTypeCheck(edge, ~SpecInt32)) - isNotInt32 = m_out.booleanTrue; - else - isNotInt32 = this->isNotInt32(boxedValue); - m_out.branch(isNotInt32, unsure(doubleCase), unsure(intCase)); - - LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase); - - ValueFromBlock intToDouble = m_out.anchor( - m_out.intToDouble(unboxInt32(boxedValue))); - m_out.jump(continuation); - - m_out.appendTo(doubleCase, continuation); - - FTL_TYPE_CHECK( - jsValueValue(boxedValue), edge, SpecBytecodeNumber, isCellOrMisc(boxedValue)); - - ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedValue)); - m_out.jump(continuation); - - m_out.appendTo(continuation, lastNext); - - return m_out.phi(m_out.doubleType, intToDouble, unboxedDouble); - } LValue jsValueToStrictInt52(Edge edge, LValue boxedValue) { @@ -5215,44 +7461,84 @@ private: return possibleResult; } - - LValue isNumber(LValue jsValue) + + LValue convertDoubleToInt32(LValue value, bool shouldCheckNegativeZero) + { + LValue integerValue = m_out.fpToInt32(value); + LValue integerValueConvertedToDouble = m_out.intToDouble(integerValue); + LValue valueNotConvertibleToInteger = m_out.doubleNotEqualOrUnordered(value, integerValueConvertedToDouble); + speculate(Overflow, FormattedValue(ValueFormatDouble, value), m_node, valueNotConvertibleToInteger); + + if (shouldCheckNegativeZero) { + LBasicBlock valueIsZero = FTL_NEW_BLOCK(m_out, ("ConvertDoubleToInt32 on zero")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ConvertDoubleToInt32 continuation")); + m_out.branch(m_out.isZero32(integerValue), unsure(valueIsZero), unsure(continuation)); + + LBasicBlock lastNext = m_out.appendTo(valueIsZero, continuation); + + LValue doubleBitcastToInt64 = m_out.bitCast(value, m_out.int64); + LValue signBitSet = m_out.lessThan(doubleBitcastToInt64, m_out.constInt64(0)); + + speculate(NegativeZero, FormattedValue(ValueFormatDouble, value), m_node, signBitSet); + m_out.jump(continuation); + m_out.appendTo(continuation, lastNext); + } + return integerValue; + } + + LValue isNumber(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, SpecFullNumber)) + return proven; return isNotCellOrMisc(jsValue); } - LValue isNotNumber(LValue jsValue) + LValue isNotNumber(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~SpecFullNumber)) + return proven; return isCellOrMisc(jsValue); } - LValue isNotCell(LValue jsValue) + LValue isNotCell(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~SpecCell)) + return proven; return m_out.testNonZero64(jsValue, m_tagMask); } - LValue isCell(LValue jsValue) + LValue isCell(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, SpecCell)) + return proven; return m_out.testIsZero64(jsValue, m_tagMask); } - LValue isNotMisc(LValue value) + LValue isNotMisc(LValue value, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~SpecMisc)) + return proven; return m_out.above(value, m_out.constInt64(TagBitTypeOther | TagBitBool | TagBitUndefined)); } - LValue isMisc(LValue value) + LValue isMisc(LValue value, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, SpecMisc)) + return proven; return m_out.bitNot(isNotMisc(value)); } - LValue isNotBoolean(LValue jsValue) + LValue isNotBoolean(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~SpecBoolean)) + return proven; return m_out.testNonZero64( m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)), m_out.constInt64(~1)); } - LValue isBoolean(LValue jsValue) + LValue isBoolean(LValue jsValue, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, SpecBoolean)) + return proven; return m_out.bitNot(isNotBoolean(jsValue)); } LValue unboxBoolean(LValue jsValue) @@ -5267,18 +7553,31 @@ private: value, m_out.constInt64(ValueTrue), m_out.constInt64(ValueFalse)); } - LValue isNotOther(LValue value) + LValue isNotOther(LValue value, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, ~SpecOther)) + return proven; return m_out.notEqual( m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)), m_out.constInt64(ValueNull)); } - LValue isOther(LValue value) + LValue isOther(LValue value, SpeculatedType type = SpecFullTop) { + if (LValue proven = isProvenValue(type, SpecOther)) + return proven; return m_out.equal( m_out.bitAnd(value, m_out.constInt64(~TagBitUndefined)), m_out.constInt64(ValueNull)); } + + LValue isProvenValue(SpeculatedType provenType, SpeculatedType wantedType) + { + if (!(provenType & ~wantedType)) + return m_out.booleanTrue; + if (!(provenType & wantedType)) + return m_out.booleanFalse; + return nullptr; + } void speculate(Edge edge) { @@ -5306,6 +7605,9 @@ private: case ObjectUse: speculateObject(edge); break; + case FunctionUse: + speculateFunction(edge); + break; case ObjectOrOtherUse: speculateObjectOrOther(edge); break; @@ -5327,8 +7629,11 @@ private: case NumberUse: speculateNumber(edge); break; + case RealNumberUse: + speculateRealNumber(edge); + break; case DoubleRepRealUse: - speculateDoubleReal(edge); + speculateDoubleRepReal(edge); break; case DoubleRepMachineIntUse: speculateDoubleRepMachineInt(edge); @@ -5349,8 +7654,7 @@ private: speculateMisc(edge); break; default: - LOWERING_FAILED(m_node, "Unsupported speculation use kind"); - return; + DFG_CRASH(m_graph, m_node, "Unsupported speculation use kind"); } } @@ -5377,28 +7681,40 @@ private: jsValueToStrictInt52(edge, lowJSValue(edge, ManualOperandSpeculation)); } - LValue isObject(LValue cell) + LValue isObject(LValue cell, SpeculatedType type = SpecFullTop) { - return m_out.notEqual( - m_out.load32(cell, m_heaps.JSCell_structureID), - m_out.constInt32(vm().stringStructure->id())); + if (LValue proven = isProvenValue(type & SpecCell, SpecObject)) + return proven; + return m_out.aboveOrEqual( + m_out.load8(cell, m_heaps.JSCell_typeInfoType), + m_out.constInt8(ObjectType)); } - - LValue isNotString(LValue cell) + + LValue isNotObject(LValue cell, SpeculatedType type = SpecFullTop) { - return isObject(cell); + if (LValue proven = isProvenValue(type & SpecCell, ~SpecObject)) + return proven; + return m_out.below( + m_out.load8(cell, m_heaps.JSCell_typeInfoType), + m_out.constInt8(ObjectType)); } - - LValue isString(LValue cell) + + LValue isNotString(LValue cell, SpeculatedType type = SpecFullTop) { - return m_out.equal( + if (LValue proven = isProvenValue(type & SpecCell, ~SpecString)) + return proven; + return m_out.notEqual( m_out.load32(cell, m_heaps.JSCell_structureID), m_out.constInt32(vm().stringStructure->id())); } - LValue isNotObject(LValue cell) + LValue isString(LValue cell, SpeculatedType type = SpecFullTop) { - return isString(cell); + if (LValue proven = isProvenValue(type & SpecCell, SpecString)) + return proven; + return m_out.equal( + m_out.load32(cell, m_heaps.JSCell_structureID), + m_out.constInt32(vm().stringStructure->id())); } LValue isArrayType(LValue cell, ArrayMode arrayMode) @@ -5411,7 +7727,7 @@ private: switch (arrayMode.arrayClass()) { case Array::OriginalArray: - LOWERING_FAILED(m_node, "Unexpected original array"); + DFG_CRASH(m_graph, m_node, "Unexpected original array"); return 0; case Array::Array: @@ -5431,10 +7747,19 @@ private: m_out.constInt8(arrayMode.shapeMask())); } - LOWERING_FAILED(m_node, "Corrupt array class"); - return 0; + DFG_CRASH(m_graph, m_node, "Corrupt array class"); } + case Array::DirectArguments: + return m_out.equal( + m_out.load8(cell, m_heaps.JSCell_typeInfoType), + m_out.constInt8(DirectArgumentsType)); + + case Array::ScopedArguments: + return m_out.equal( + m_out.load8(cell, m_heaps.JSCell_typeInfoType), + m_out.constInt8(ScopedArgumentsType)); + default: return m_out.equal( m_out.load8(cell, m_heaps.JSCell_typeInfoType), @@ -5442,6 +7767,28 @@ private: } } + LValue isFunction(LValue cell, SpeculatedType type = SpecFullTop) + { + if (LValue proven = isProvenValue(type & SpecCell, SpecFunction)) + return proven; + return isType(cell, JSFunctionType); + } + LValue isNotFunction(LValue cell, SpeculatedType type = SpecFullTop) + { + if (LValue proven = isProvenValue(type & SpecCell, ~SpecFunction)) + return proven; + return isNotType(cell, JSFunctionType); + } + + LValue isExoticForTypeof(LValue cell, SpeculatedType type = SpecFullTop) + { + if (!(type & SpecObjectOther)) + return m_out.booleanFalse; + return m_out.testNonZero8( + m_out.load8(cell, m_heaps.JSCell_typeInfoFlags), + m_out.constInt8(MasqueradesAsUndefined | TypeOfShouldCallGetCallData)); + } + LValue isType(LValue cell, JSType type) { return m_out.equal( @@ -5464,18 +7811,28 @@ private: speculateObject(edge, lowCell(edge)); } + void speculateFunction(Edge edge, LValue cell) + { + FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecFunction, isNotFunction(cell)); + } + + void speculateFunction(Edge edge) + { + speculateFunction(edge, lowCell(edge)); + } + void speculateObjectOrOther(Edge edge) { if (!m_interpreter.needsTypeCheck(edge)) return; - LValue value = lowJSValue(edge); + LValue value = lowJSValue(edge, ManualOperandSpeculation); LBasicBlock cellCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther cell case")); LBasicBlock primitiveCase = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther primitive case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateObjectOrOther continuation")); - m_out.branch(isNotCell(value), unsure(primitiveCase), unsure(cellCase)); + m_out.branch(isNotCell(value, provenType(edge)), unsure(primitiveCase), unsure(cellCase)); LBasicBlock lastNext = m_out.appendTo(cellCase, primitiveCase); @@ -5575,21 +7932,17 @@ private: Structure* stringObjectStructure = m_graph.globalObjectFor(m_node->origin.semantic)->stringObjectStructure(); - if (m_state.forNode(edge).m_currentKnownStructure.isSubsetOf(StructureSet(stringObjectStructure))) + if (abstractStructure(edge).isSubsetOf(StructureSet(stringObjectStructure))) return; speculate( NotStringObject, noValue(), 0, - m_out.notEqual(structureID, weakStructure(stringObjectStructure))); + m_out.notEqual(structureID, weakStructureID(stringObjectStructure))); } void speculateNonNullObject(Edge edge, LValue cell) { - FTL_TYPE_CHECK( - jsValueValue(cell), edge, SpecObject, - m_out.equal( - m_out.load32(cell, m_heaps.JSCell_structureID), - m_out.constInt32(vm().stringStructure->id()))); + FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell)); if (masqueradesAsUndefinedWatchpointIsStillValid()) return; @@ -5606,7 +7959,33 @@ private: FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBytecodeNumber, isNotNumber(value)); } - void speculateDoubleReal(Edge edge) + void speculateRealNumber(Edge edge) + { + // Do an early return here because lowDouble() can create a lot of control flow. + if (!m_interpreter.needsTypeCheck(edge)) + return; + + LValue value = lowJSValue(edge, ManualOperandSpeculation); + LValue doubleValue = unboxDouble(value); + + LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("speculateRealNumber int case")); + LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateRealNumber continuation")); + + m_out.branch( + m_out.doubleEqual(doubleValue, doubleValue), + usually(continuation), rarely(intCase)); + + LBasicBlock lastNext = m_out.appendTo(intCase, continuation); + + typeCheck( + jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber, + isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble)); + m_out.jump(continuation); + + m_out.appendTo(continuation, lastNext); + } + + void speculateDoubleRepReal(Edge edge) { // Do an early return here because lowDouble() can create a lot of control flow. if (!m_interpreter.needsTypeCheck(edge)) @@ -5642,10 +8021,10 @@ private: LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is string case")); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar continuation")); - m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation)); + m_out.branch(isCell(value, provenType(edge)), unsure(isCellCase), unsure(continuation)); LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase); - m_out.branch(isString(value), unsure(isStringCase), unsure(continuation)); + m_out.branch(isString(value, provenType(edge)), unsure(isStringCase), unsure(continuation)); m_out.appendTo(isStringCase, continuation); speculateStringIdent(edge, value, m_out.loadPtr(value, m_heaps.JSString_value)); @@ -5705,22 +8084,22 @@ private: // Append to the write barrier buffer. LBasicBlock lastNext = m_out.appendTo(isMarkedAndNotRemembered, bufferHasSpace); - LValue currentBufferIndex = m_out.load32(m_out.absolute(&vm().heap.writeBarrierBuffer().m_currentIndex)); - LValue bufferCapacity = m_out.load32(m_out.absolute(&vm().heap.writeBarrierBuffer().m_capacity)); + LValue currentBufferIndex = m_out.load32(m_out.absolute(vm().heap.writeBarrierBuffer().currentIndexAddress())); + LValue bufferCapacity = m_out.constInt32(vm().heap.writeBarrierBuffer().capacity()); m_out.branch( m_out.lessThan(currentBufferIndex, bufferCapacity), usually(bufferHasSpace), rarely(bufferIsFull)); // Buffer has space, store to it. m_out.appendTo(bufferHasSpace, bufferIsFull); - LValue writeBarrierBufferBase = m_out.loadPtr(m_out.absolute(&vm().heap.writeBarrierBuffer().m_buffer)); - m_out.storePtr(base, m_out.baseIndex(m_heaps.WriteBarrierBuffer_bufferContents, writeBarrierBufferBase, m_out.zeroExt(currentBufferIndex, m_out.intPtr), ScalePtr)); - m_out.store32(m_out.add(currentBufferIndex, m_out.constInt32(1)), m_out.absolute(&vm().heap.writeBarrierBuffer().m_currentIndex)); + LValue writeBarrierBufferBase = m_out.constIntPtr(vm().heap.writeBarrierBuffer().buffer()); + m_out.storePtr(base, m_out.baseIndex(m_heaps.WriteBarrierBuffer_bufferContents, writeBarrierBufferBase, m_out.zeroExtPtr(currentBufferIndex))); + m_out.store32(m_out.add(currentBufferIndex, m_out.constInt32(1)), m_out.absolute(vm().heap.writeBarrierBuffer().currentIndexAddress())); m_out.jump(continuation); // Buffer is out of space, flush it. m_out.appendTo(bufferIsFull, continuation); - vmCall(m_out.operation(operationFlushWriteBarrierBuffer), m_callFrame, base, NoExceptions); + vmCallNoExceptions(m_out.operation(operationFlushWriteBarrierBuffer), m_callFrame, base); m_out.jump(continuation); m_out.appendTo(continuation, lastNext); @@ -5729,44 +8108,23 @@ private: #endif } - enum ExceptionCheckMode { NoExceptions, CheckExceptions }; - - LValue vmCall(LValue function, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function, arg1); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, LValue arg2, ExceptionCheckMode mode = CheckExceptions) - { - callPreflight(); - LValue result = m_out.call(function, arg1, arg2); - callCheck(mode); - return result; - } - LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, ExceptionCheckMode mode = CheckExceptions) + template<typename... Args> + LValue vmCall(LValue function, Args... args) { callPreflight(); - LValue result = m_out.call(function, arg1, arg2, arg3); - callCheck(mode); + LValue result = m_out.call(function, args...); + callCheck(); return result; } - LValue vmCall(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, ExceptionCheckMode mode = CheckExceptions) + + template<typename... Args> + LValue vmCallNoExceptions(LValue function, Args... args) { callPreflight(); - LValue result = m_out.call(function, arg1, arg2, arg3, arg4); - callCheck(mode); + LValue result = m_out.call(function, args...); return result; } - + void callPreflight(CodeOrigin codeOrigin) { m_out.store32( @@ -5780,19 +8138,17 @@ private: callPreflight(m_node->origin.semantic); } - void callCheck(ExceptionCheckMode mode = CheckExceptions) + void callCheck() { - if (mode == NoExceptions) - return; - if (Options::enableExceptionFuzz()) m_out.call(m_out.operation(operationExceptionFuzz)); LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Exception check continuation")); + LValue exception = m_out.load64(m_out.absolute(vm().addressOfException())); + m_out.branch( - m_out.notZero64(m_out.load64(m_out.absolute(vm().addressOfException()))), - rarely(m_handleExceptions), usually(continuation)); + m_out.notZero64(exception), rarely(m_handleExceptions), usually(continuation)); m_out.appendTo(continuation); } @@ -5802,32 +8158,47 @@ private: return m_blocks.get(block); } - void initializeOSRExitStateForBlock() - { - m_availability = m_highBlock->ssa->availabilityAtHead; - } - void appendOSRExit( ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) { if (verboseCompilationEnabled()) { - dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", m_availability, "\n"); + dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", availabilityMap(), "\n"); if (!m_availableRecoveries.isEmpty()) dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n"); } + + if (doOSRExitFuzzing()) { + LValue numberOfFuzzChecks = m_out.add( + m_out.load32(m_out.absolute(&g_numberOfOSRExitFuzzChecks)), + m_out.int32One); + + m_out.store32(numberOfFuzzChecks, m_out.absolute(&g_numberOfOSRExitFuzzChecks)); + + if (unsigned atOrAfter = Options::fireOSRExitFuzzAtOrAfter()) { + failCondition = m_out.bitOr( + failCondition, + m_out.aboveOrEqual(numberOfFuzzChecks, m_out.constInt32(atOrAfter))); + } + if (unsigned at = Options::fireOSRExitFuzzAt()) { + failCondition = m_out.bitOr( + failCondition, + m_out.equal(numberOfFuzzChecks, m_out.constInt32(at))); + } + } ASSERT(m_ftlState.jitCode->osrExit.size() == m_ftlState.finalizer->osrExit.size()); m_ftlState.jitCode->osrExit.append(OSRExit( kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue), m_codeOriginForExitTarget, m_codeOriginForExitProfile, - m_availability.numberOfArguments(), m_availability.numberOfLocals())); + availabilityMap().m_locals.numberOfArguments(), + availabilityMap().m_locals.numberOfLocals())); m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); OSRExit& exit = m_ftlState.jitCode->osrExit.last(); - LBasicBlock lastNext = 0; - LBasicBlock continuation = 0; + LBasicBlock lastNext = nullptr; + LBasicBlock continuation = nullptr; LBasicBlock failCase = FTL_NEW_BLOCK(m_out, ("OSR exit failCase for ", m_node)); continuation = FTL_NEW_BLOCK(m_out, ("OSR exit continuation for ", m_node)); @@ -5861,62 +8232,56 @@ private: if (!!lowValue) arguments.append(lowValue.value()); + AvailabilityMap availabilityMap = this->availabilityMap(); + availabilityMap.pruneByLiveness(m_graph, codeOrigin); + + HashMap<Node*, ExitTimeObjectMaterialization*> map; + availabilityMap.forEachAvailability( + [&] (Availability availability) { + if (!availability.shouldUseNode()) + return; + + Node* node = availability.node(); + if (!node->isPhantomAllocation()) + return; + + auto result = map.add(node, nullptr); + if (result.isNewEntry) { + result.iterator->value = + exit.m_materializations.add(node->op(), node->origin.semantic); + } + }); + for (unsigned i = 0; i < exit.m_values.size(); ++i) { int operand = exit.m_values.operandForIndex(i); - bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin); - if (!isLive) { - exit.m_values[i] = ExitValue::dead(); - continue; - } - Availability availability = m_availability[i]; - FlushedAt flush = availability.flushedAt(); - switch (flush.format()) { - case DeadFlush: - case ConflictingFlush: - if (availability.hasNode()) { - addExitArgumentForNode(exit, arguments, i, availability.node()); - break; - } - - if (Options::validateFTLOSRExitLiveness()) { - dataLog("Expected r", operand, " to be available but it wasn't.\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - - // This means that the DFG's DCE proved that the value is dead in bytecode - // even though the bytecode liveness analysis thinks it's live. This is - // acceptable since the DFG's DCE is by design more aggressive while still - // being sound. - exit.m_values[i] = ExitValue::dead(); - break; - - case FlushedJSValue: - case FlushedCell: - case FlushedBoolean: - exit.m_values[i] = ExitValue::inJSStack(flush.virtualRegister()); - break; - - case FlushedInt32: - exit.m_values[i] = ExitValue::inJSStackAsInt32(flush.virtualRegister()); - break; - - case FlushedInt52: - exit.m_values[i] = ExitValue::inJSStackAsInt52(flush.virtualRegister()); - break; - - case FlushedDouble: - exit.m_values[i] = ExitValue::inJSStackAsDouble(flush.virtualRegister()); - break; - - case FlushedArguments: - exit.m_values[i] = ExitValue::argumentsObjectThatWasNotCreated(); - break; + Availability availability = availabilityMap.m_locals[i]; + + if (Options::validateFTLOSRExitLiveness()) { + DFG_ASSERT( + m_graph, m_node, + (!(availability.isDead() && m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin))) || m_graph.m_plan.mode == FTLForOSREntryMode); } + + exit.m_values[i] = exitValueForAvailability(arguments, map, availability); } - if (verboseCompilationEnabled()) + for (auto heapPair : availabilityMap.m_heap) { + Node* node = heapPair.key.base(); + ExitTimeObjectMaterialization* materialization = map.get(node); + materialization->add( + heapPair.key.descriptor(), + exitValueForAvailability(arguments, map, heapPair.value)); + } + + if (verboseCompilationEnabled()) { dataLog(" Exit values: ", exit.m_values, "\n"); + if (!exit.m_materializations.isEmpty()) { + dataLog(" Materializations: \n"); + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) + dataLog(" ", pointerDump(materialization), "\n"); + } + } } void callStackmap(OSRExit& exit, ExitArgumentList& arguments) @@ -5928,97 +8293,115 @@ private: m_out.call(m_out.stackmapIntrinsic(), arguments); } - void addExitArgumentForNode( - OSRExit& exit, ExitArgumentList& arguments, unsigned index, Node* node) + ExitValue exitValueForAvailability( + ExitArgumentList& arguments, const HashMap<Node*, ExitTimeObjectMaterialization*>& map, + Availability availability) + { + FlushedAt flush = availability.flushedAt(); + switch (flush.format()) { + case DeadFlush: + case ConflictingFlush: + if (availability.hasNode()) + return exitValueForNode(arguments, map, availability.node()); + + // This means that the value is dead. It could be dead in bytecode or it could have + // been killed by our DCE, which can sometimes kill things even if they were live in + // bytecode. + return ExitValue::dead(); + + case FlushedJSValue: + case FlushedCell: + case FlushedBoolean: + return ExitValue::inJSStack(flush.virtualRegister()); + + case FlushedInt32: + return ExitValue::inJSStackAsInt32(flush.virtualRegister()); + + case FlushedInt52: + return ExitValue::inJSStackAsInt52(flush.virtualRegister()); + + case FlushedDouble: + return ExitValue::inJSStackAsDouble(flush.virtualRegister()); + } + + DFG_CRASH(m_graph, m_node, "Invalid flush format"); + return ExitValue::dead(); + } + + ExitValue exitValueForNode( + ExitArgumentList& arguments, const HashMap<Node*, ExitTimeObjectMaterialization*>& map, + Node* node) { ASSERT(node->shouldGenerate()); ASSERT(node->hasResult()); - if (tryToSetConstantExitArgument(exit, index, node)) - return; + if (node) { + switch (node->op()) { + case BottomValue: + // This might arise in object materializations. I actually doubt that it would, + // but it seems worthwhile to be conservative. + return ExitValue::dead(); + + case JSConstant: + case Int52Constant: + case DoubleConstant: + return ExitValue::constant(node->asJSValue()); + + default: + if (node->isPhantomAllocation()) + return ExitValue::materializeNewObject(map.get(node)); + break; + } + } for (unsigned i = 0; i < m_availableRecoveries.size(); ++i) { AvailableRecovery recovery = m_availableRecoveries[i]; if (recovery.node() != node) continue; - exit.m_values[index] = ExitValue::recovery( + ExitValue result = ExitValue::recovery( recovery.opcode(), arguments.size(), arguments.size() + 1, recovery.format()); arguments.append(recovery.left()); arguments.append(recovery.right()); - return; + return result; } LoweredNodeValue value = m_int32Values.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatInt32, value.value()); - return; - } + if (isValid(value)) + return exitArgument(arguments, ValueFormatInt32, value.value()); value = m_int52Values.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatInt52, value.value()); - return; - } + if (isValid(value)) + return exitArgument(arguments, ValueFormatInt52, value.value()); value = m_strictInt52Values.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatStrictInt52, value.value()); - return; - } + if (isValid(value)) + return exitArgument(arguments, ValueFormatStrictInt52, value.value()); value = m_booleanValues.get(node); if (isValid(value)) { LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32); - addExitArgument(exit, arguments, index, ValueFormatBoolean, valueToPass); - return; + return exitArgument(arguments, ValueFormatBoolean, valueToPass); } value = m_jsValueValues.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatJSValue, value.value()); - return; - } + if (isValid(value)) + return exitArgument(arguments, ValueFormatJSValue, value.value()); value = m_doubleValues.get(node); - if (isValid(value)) { - addExitArgument(exit, arguments, index, ValueFormatDouble, value.value()); - return; - } + if (isValid(value)) + return exitArgument(arguments, ValueFormatDouble, value.value()); - startCrashing(); - dataLog("Cannot find value for node: ", node, " while compiling exit at ", exit.m_codeOrigin, " in node ", m_node, "\n"); - m_graph.dump(); - RELEASE_ASSERT_NOT_REACHED(); - } - - bool tryToSetConstantExitArgument(OSRExit& exit, unsigned index, Node* node) - { - if (!node) - return false; - - switch (node->op()) { - case JSConstant: - case Int52Constant: - case DoubleConstant: - case WeakJSConstant: - exit.m_values[index] = ExitValue::constant(m_graph.valueOfJSConstant(node)); - return true; - case PhantomArguments: - exit.m_values[index] = ExitValue::argumentsObjectThatWasNotCreated(); - return true; - default: - return false; - } + DFG_CRASH(m_graph, m_node, toCString("Cannot find value for node: ", node).data()); + return ExitValue::dead(); } - void addExitArgument( - OSRExit& exit, ExitArgumentList& arguments, unsigned index, ValueFormat format, - LValue value) + ExitValue exitArgument(ExitArgumentList& arguments, ValueFormat format, LValue value) { - exit.m_values[index] = ExitValue::exitArgument(ExitArgument(format, arguments.size())); + ExitValue result = ExitValue::exitArgument(ExitArgument(format, arguments.size())); arguments.append(value); + return result; } bool doesKill(Edge edge) @@ -6068,7 +8451,7 @@ private: return; } - LOWERING_FAILED(m_node, "Corrupt int52 kind"); + DFG_CRASH(m_graph, m_node, "Corrupt int52 kind"); } void setJSValue(Node* node, LValue value) { @@ -6139,9 +8522,9 @@ private: LValue tableIndex = m_out.load32(value, m_heaps.JSCell_structureID); LValue tableBase = m_out.loadPtr( m_out.absolute(vm().heap.structureIDTable().base())); - LValue pointerIntoTable = m_out.baseIndex( - tableBase, m_out.zeroExt(tableIndex, m_out.intPtr), ScaleEight); - return m_out.loadPtr(TypedPointer(m_heaps.structureTable, pointerIntoTable)); + TypedPointer address = m_out.baseIndex( + m_heaps.structureTable, tableBase, m_out.zeroExtPtr(tableIndex)); + return m_out.loadPtr(address); } LValue weakPointer(JSCell* pointer) @@ -6150,12 +8533,17 @@ private: return m_out.constIntPtr(pointer); } - LValue weakStructure(Structure* structure) + LValue weakStructureID(Structure* structure) { addWeakReference(structure); return m_out.constInt32(structure->id()); } + LValue weakStructure(Structure* structure) + { + return weakPointer(structure); + } + TypedPointer addressFor(LValue base, int operand, ptrdiff_t offset = 0) { return m_out.address(base, m_heaps.variables[operand], offset); @@ -6195,24 +8583,72 @@ private: return addressFor(operand, TagOffset); } - NO_RETURN_DUE_TO_ASSERT void loweringFailed(Node* node, const char* file, int line, const char* function, const char* assertion) + AbstractValue abstractValue(Node* node) { - if (!ASSERT_DISABLED) { - dataLog("FTL ASSERTION FAILED: ", assertion, "\n"); - dataLog(file, "(", line, ") : ", function, "\n"); - dataLog("While handling node ", node, "\n"); - RELEASE_ASSERT_NOT_REACHED(); - } - - m_loweringSucceeded = false; + return m_state.forNode(node); + } + AbstractValue abstractValue(Edge edge) + { + return abstractValue(edge.node()); + } + + SpeculatedType provenType(Node* node) + { + return abstractValue(node).m_type; + } + SpeculatedType provenType(Edge edge) + { + return provenType(edge.node()); + } + + JSValue provenValue(Node* node) + { + return abstractValue(node).m_value; + } + JSValue provenValue(Edge edge) + { + return provenValue(edge.node()); + } + + StructureAbstractValue abstractStructure(Node* node) + { + return abstractValue(node).m_structure; + } + StructureAbstractValue abstractStructure(Edge edge) + { + return abstractStructure(edge.node()); + } + + void crash() + { + crash(m_highBlock->index, m_node->index()); + } + void crash(BlockIndex blockIndex, unsigned nodeIndex) + { +#if ASSERT_DISABLED + m_out.call(m_out.operation(ftlUnreachable)); + UNUSED_PARAM(blockIndex); + UNUSED_PARAM(nodeIndex); +#else + m_out.call( + m_out.intToPtr( + m_out.constIntPtr(ftlUnreachable), + pointerType( + functionType( + m_out.voidType, m_out.intPtr, m_out.int32, m_out.int32))), + m_out.constIntPtr(codeBlock()), m_out.constInt32(blockIndex), + m_out.constInt32(nodeIndex)); +#endif + m_out.unreachable(); } + AvailabilityMap& availabilityMap() { return m_availabilityCalculator.m_availability; } + VM& vm() { return m_graph.m_vm; } CodeBlock* codeBlock() { return m_graph.m_codeBlock; } Graph& m_graph; State& m_ftlState; - bool m_loweringSucceeded; AbstractHeapRepository m_heaps; Output m_out; @@ -6220,6 +8656,8 @@ private: LBasicBlock m_handleExceptions; HashMap<BasicBlock*, LBasicBlock> m_blocks; + LValue m_execState; + LValue m_execStorage; LValue m_callFrame; LValue m_captured; LValue m_tagTypeNumber; @@ -6233,9 +8671,14 @@ private: HashMap<Node*, LoweredNodeValue> m_storageValues; HashMap<Node*, LoweredNodeValue> m_doubleValues; + // This is a bit of a hack. It prevents LLVM from having to do CSE on loading of arguments. + // It's nice to have these optimizations on our end because we can guarantee them a bit better. + // Probably also saves LLVM compile time. + HashMap<Node*, LValue> m_loadedArgumentValues; + HashMap<Node*, LValue> m_phis; - Operands<Availability> m_availability; + LocalOSRAvailabilityCalculator m_availabilityCalculator; Vector<AvailableRecovery, 3> m_availableRecoveries; @@ -6251,12 +8694,16 @@ private: Node* m_node; uint32_t m_stackmapIDs; + unsigned m_tbaaKind; + unsigned m_tbaaStructKind; }; -bool lowerDFGToLLVM(State& state) +} // anonymous namespace + +void lowerDFGToLLVM(State& state) { LowerDFGToLLVM lowering(state); - return lowering.lower(); + lowering.lower(); } } } // namespace JSC::FTL diff --git a/ftl/FTLLowerDFGToLLVM.h b/ftl/FTLLowerDFGToLLVM.h index 141b625..0e38d7b 100644 --- a/ftl/FTLLowerDFGToLLVM.h +++ b/ftl/FTLLowerDFGToLLVM.h @@ -33,7 +33,7 @@ namespace JSC { namespace FTL { -bool lowerDFGToLLVM(State&); +void lowerDFGToLLVM(State&); } } // namespace JSC::FTL diff --git a/ftl/FTLOSREntry.cpp b/ftl/FTLOSREntry.cpp index c31d77c..8e9d4f4 100644 --- a/ftl/FTLOSREntry.cpp +++ b/ftl/FTLOSREntry.cpp @@ -54,9 +54,12 @@ void* prepareOSREntry( bytecodeIndex, ".\n"); } + if (bytecodeIndex) + jsCast<ScriptExecutable*>(executable)->setDidTryToEnterInLoop(true); + if (bytecodeIndex != entryCode->bytecodeIndex()) { if (Options::verboseOSR()) - dataLog(" OSR failed because we don't have an entrypoint for bc#", bytecodeIndex, "; ours is for bc#", entryCode->bytecodeIndex()); + dataLog(" OSR failed because we don't have an entrypoint for bc#", bytecodeIndex, "; ours is for bc#", entryCode->bytecodeIndex(), "\n"); return 0; } diff --git a/ftl/FTLOSRExit.cpp b/ftl/FTLOSRExit.cpp index 6132ea1..3d96f39 100644 --- a/ftl/FTLOSRExit.cpp +++ b/ftl/FTLOSRExit.cpp @@ -61,6 +61,15 @@ CodeLocationJump OSRExit::codeLocationForRepatch(CodeBlock* ftlCodeBlock) const m_patchableCodeOffset); } +void OSRExit::validateReferences(const TrackedReferences& trackedReferences) +{ + for (unsigned i = m_values.size(); i--;) + m_values[i].validateReferences(trackedReferences); + + for (ExitTimeObjectMaterialization* materialization : m_materializations) + materialization->validateReferences(trackedReferences); +} + } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) diff --git a/ftl/FTLOSRExit.h b/ftl/FTLOSRExit.h index c623199..337c618 100644 --- a/ftl/FTLOSRExit.h +++ b/ftl/FTLOSRExit.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +33,7 @@ #include "DFGOSRExitBase.h" #include "FTLAbbreviations.h" #include "FTLExitArgumentList.h" +#include "FTLExitTimeObjectMaterialization.h" #include "FTLExitValue.h" #include "FTLFormattedValue.h" #include "MethodOfGettingAValueProfile.h" @@ -40,18 +41,20 @@ #include "ValueProfile.h" #include "VirtualRegister.h" -namespace JSC { namespace FTL { +namespace JSC { + +class TrackedReferences; + +namespace FTL { // Tracks one OSR exit site within the FTL JIT. OSR exit in FTL works by deconstructing // the crazy that is OSR down to simple SSA CFG primitives that any compiler backend -// (including of course LLVM) can grok and do meaningful things to. Except for -// watchpoint-based exits, which haven't yet been implemented (see webkit.org/b/113647), -// an exit is just a conditional branch in the emitted code where one destination is the -// continuation and the other is a basic block that performs a no-return tail-call to an -// exit thunk. This thunk takes as its arguments the live non-constant -// not-already-accounted-for bytecode state. To appreciate how this works consider the -// following JavaScript program, and its lowering down to LLVM IR including the relevant -// exits: +// (including of course LLVM) can grok and do meaningful things to. An exit is just a +// conditional branch in the emitted code where one destination is the continuation and +// the other is a basic block that performs a no-return tail-call to an exit thunk. +// This thunk takes as its arguments the live non-constant not-already-accounted-for +// bytecode state. To appreciate how this works consider the following JavaScript +// program, and its lowering down to LLVM IR including the relevant exits: // // function foo(o) { // var a = o.a; // predicted int @@ -65,10 +68,10 @@ namespace JSC { namespace FTL { // // BitOr(Check:Int32:@a, Int32:5) // -// Where @a is the node for the GetLocal node that gets the value of the 'a' variable. -// Conceptually, this node can be further broken down to the following (note that this -// particular lowering never actually happens - we skip this step and go straight to -// LLVM IR - but it's still useful to see this): +// Where @a is the node for the value of the 'a' variable. Conceptually, this node can +// be further broken down to the following (note that this particular lowering never +// actually happens - we skip this step and go straight to LLVM IR - but it's still +// useful to see this): // // exitIf(@a is not int32); // continuation; @@ -123,22 +126,12 @@ namespace JSC { namespace FTL { // arguments into argument position), the backend could choose to simply inform us // where it had placed the arguments and expect the callee (i.e. the exit thunk) to // figure it out from there. It could also tell us what we need to do to pop stack, -// although again, it doesn't have to; it could just emit that code normally. Though -// we don't support this yet, we could; the only thing that would change on our end -// is that we'd need feedback from the backend about the location of the arguments -// and a description of the things that need to be done to pop stack. This would -// involve switching the m_values array to use something more akin to ValueRecovery -// rather than the current ExitValue, albeit possibly with some hacks to better -// understand the kinds of places where the LLVM backend would put values. +// although again, it doesn't have to; it could just emit that code normally. We do +// all of these things through the patchpoint/stackmap LLVM intrinsics. // // - It could be extended to allow the backend to do its own exit hoisting, by using // intrinsics (or meta-data, or something) to inform the backend that it's safe to // make the predicate passed to 'exitIf()' more truthy. -// -// - It could be extended to support watchpoints (see webkit.org/b/113647) by making -// the predicate passed to 'exitIf()' be an intrinsic that the backend knows to be -// true at compile-time. The backend could then turn the conditional branch into a -// replaceable jump, much like the DFG does. struct OSRExit : public DFG::OSRExitBase { OSRExit( @@ -160,15 +153,18 @@ struct OSRExit : public DFG::OSRExitBase { unsigned m_patchableCodeOffset; Operands<ExitValue> m_values; + Bag<ExitTimeObjectMaterialization> m_materializations; uint32_t m_stackmapID; CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const; - bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock) + void considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock) { - return OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL); + OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL); } + + void validateReferences(const TrackedReferences&); }; } } // namespace JSC::FTL diff --git a/ftl/FTLOSRExitCompiler.cpp b/ftl/FTLOSRExitCompiler.cpp index 62e3b99..27788e7 100644 --- a/ftl/FTLOSRExitCompiler.cpp +++ b/ftl/FTLOSRExitCompiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +33,7 @@ #include "FTLExitArgumentForOperand.h" #include "FTLJITCode.h" #include "FTLOSRExit.h" +#include "FTLOperations.h" #include "FTLState.h" #include "FTLSaveRestore.h" #include "LinkBuffer.h" @@ -46,6 +47,83 @@ namespace JSC { namespace FTL { using namespace DFG; +static void compileRecovery( + CCallHelpers& jit, const ExitValue& value, StackMaps::Record* record, StackMaps& stackmaps, + char* registerScratch, + const HashMap<ExitTimeObjectMaterialization*, EncodedJSValue*>& materializationToPointer) +{ + switch (value.kind()) { + case ExitValueDead: + jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), GPRInfo::regT0); + break; + + case ExitValueConstant: + jit.move(MacroAssembler::TrustedImm64(JSValue::encode(value.constant())), GPRInfo::regT0); + break; + + case ExitValueArgument: + record->locations[value.exitArgument().argument()].restoreInto( + jit, stackmaps, registerScratch, GPRInfo::regT0); + break; + + case ExitValueInJSStack: + case ExitValueInJSStackAsInt32: + case ExitValueInJSStackAsInt52: + case ExitValueInJSStackAsDouble: + jit.load64(AssemblyHelpers::addressFor(value.virtualRegister()), GPRInfo::regT0); + break; + + case ExitValueRecovery: + record->locations[value.rightRecoveryArgument()].restoreInto( + jit, stackmaps, registerScratch, GPRInfo::regT1); + record->locations[value.leftRecoveryArgument()].restoreInto( + jit, stackmaps, registerScratch, GPRInfo::regT0); + switch (value.recoveryOpcode()) { + case AddRecovery: + switch (value.recoveryFormat()) { + case ValueFormatInt32: + jit.add32(GPRInfo::regT1, GPRInfo::regT0); + break; + case ValueFormatInt52: + jit.add64(GPRInfo::regT1, GPRInfo::regT0); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + break; + case SubRecovery: + switch (value.recoveryFormat()) { + case ValueFormatInt32: + jit.sub32(GPRInfo::regT1, GPRInfo::regT0); + break; + case ValueFormatInt52: + jit.sub64(GPRInfo::regT1, GPRInfo::regT0); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + break; + + case ExitValueMaterializeNewObject: + jit.loadPtr(materializationToPointer.get(value.objectMaterialization()), GPRInfo::regT0); + break; + + default: + RELEASE_ASSERT_NOT_REACHED(); + break; + } + + reboxAccordingToFormat( + value.valueFormat(), jit, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT2); +} + static void compileStub( unsigned exitID, JITCode* jitCode, OSRExit& exit, VM* vm, CodeBlock* codeBlock) { @@ -64,13 +142,39 @@ static void compileStub( CCallHelpers jit(vm, codeBlock); - // We need scratch space to save all registers and to build up the JSStack. - // Use a scratch buffer to transfer all values. - ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(sizeof(EncodedJSValue) * exit.m_values.size() + requiredScratchMemorySizeInBytes() + jitCode->unwindInfo.m_registers.size() * sizeof(uint64_t)); + // We need scratch space to save all registers, to build up the JS stack, to deal with unwind + // fixup, pointers to all of the objects we materialize, and the elements inside those objects + // that we materialize. + + // Figure out how much space we need for those object allocations. + unsigned numMaterializations = 0; + size_t maxMaterializationNumArguments = 0; + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) { + numMaterializations++; + + maxMaterializationNumArguments = std::max( + maxMaterializationNumArguments, + materialization->properties().size()); + } + + ScratchBuffer* scratchBuffer = vm->scratchBufferForSize( + sizeof(EncodedJSValue) * ( + exit.m_values.size() + numMaterializations + maxMaterializationNumArguments) + + requiredScratchMemorySizeInBytes() + + jitCode->unwindInfo.m_registers.size() * sizeof(uint64_t)); EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0; - char* registerScratch = bitwise_cast<char*>(scratch + exit.m_values.size()); + EncodedJSValue* materializationPointers = scratch + exit.m_values.size(); + EncodedJSValue* materializationArguments = materializationPointers + numMaterializations; + char* registerScratch = bitwise_cast<char*>(materializationArguments + maxMaterializationNumArguments); uint64_t* unwindScratch = bitwise_cast<uint64_t*>(registerScratch + requiredScratchMemorySizeInBytes()); + HashMap<ExitTimeObjectMaterialization*, EncodedJSValue*> materializationToPointer; + unsigned materializationCount = 0; + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) { + materializationToPointer.add( + materialization, materializationPointers + materializationCount++); + } + // Note that we come in here, the stack used to be as LLVM left it except that someone called pushToSave(). // We don't care about the value they saved. But, we do appreciate the fact that they did it, because we use // that slot for saveAllRegisters(). @@ -87,7 +191,7 @@ static void compileStub( Profiler::OSRExit* profilerExit = compilation->addOSRExit( exitID, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin), - exit.m_kind, isWatchpoint(exit.m_kind)); + exit.m_kind, exit.m_kind == UncountableInvalidation); jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress())); } @@ -120,83 +224,73 @@ static void compileStub( if (!!exit.m_valueProfile) jit.store64(GPRInfo::regT0, exit.m_valueProfile.getSpecFailBucket(0)); } - - // Save all state from wherever the exit data tells us it was, into the appropriate place in - // the scratch buffer. This doesn't rebox any values yet. - for (unsigned index = exit.m_values.size(); index--;) { - ExitValue value = exit.m_values[index]; + // Materialize all objects. Don't materialize an object until all of the objects it needs + // have been materialized. Curiously, this is the only place that we have an algorithm that prevents + // OSR exit from handling cyclic object materializations. Of course, object allocation sinking + // currently wouldn't recognize a cycle as being sinkable - but if it did then the only thing that + // would ahve to change is this fixpoint. Instead we would allocate the objects first and populate + // them with data later. + HashSet<ExitTimeObjectMaterialization*> toMaterialize; + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) + toMaterialize.add(materialization); + + while (!toMaterialize.isEmpty()) { + unsigned previousToMaterializeSize = toMaterialize.size(); - switch (value.kind()) { - case ExitValueDead: - jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), GPRInfo::regT0); - break; - - case ExitValueConstant: - jit.move(MacroAssembler::TrustedImm64(JSValue::encode(value.constant())), GPRInfo::regT0); - break; - - case ExitValueArgument: - record->locations[value.exitArgument().argument()].restoreInto( - jit, jitCode->stackmaps, registerScratch, GPRInfo::regT0); - break; - - case ExitValueInJSStack: - case ExitValueInJSStackAsInt32: - case ExitValueInJSStackAsInt52: - case ExitValueInJSStackAsDouble: - jit.load64(AssemblyHelpers::addressFor(value.virtualRegister()), GPRInfo::regT0); - break; - - case ExitValueArgumentsObjectThatWasNotCreated: - // We can't actually recover this yet, but we can make the stack look sane. This is - // a prerequisite to running the actual arguments recovery. - jit.move(MacroAssembler::TrustedImm64(JSValue::encode(JSValue())), GPRInfo::regT0); - break; - - case ExitValueRecovery: - record->locations[value.rightRecoveryArgument()].restoreInto( - jit, jitCode->stackmaps, registerScratch, GPRInfo::regT1); - record->locations[value.leftRecoveryArgument()].restoreInto( - jit, jitCode->stackmaps, registerScratch, GPRInfo::regT0); - switch (value.recoveryOpcode()) { - case AddRecovery: - switch (value.recoveryFormat()) { - case ValueFormatInt32: - jit.add32(GPRInfo::regT1, GPRInfo::regT0); - break; - case ValueFormatInt52: - jit.add64(GPRInfo::regT1, GPRInfo::regT0); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; - } - break; - case SubRecovery: - switch (value.recoveryFormat()) { - case ValueFormatInt32: - jit.sub32(GPRInfo::regT1, GPRInfo::regT0); - break; - case ValueFormatInt52: - jit.sub64(GPRInfo::regT1, GPRInfo::regT0); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); + Vector<ExitTimeObjectMaterialization*> worklist; + worklist.appendRange(toMaterialize.begin(), toMaterialize.end()); + for (ExitTimeObjectMaterialization* materialization : worklist) { + // Check if we can do anything about this right now. + bool allGood = true; + for (ExitPropertyValue value : materialization->properties()) { + if (!value.value().isObjectMaterialization()) + continue; + if (toMaterialize.contains(value.value().objectMaterialization())) { + // Gotta skip this one, since one of its fields points to a materialization + // that hasn't been materialized. + allGood = false; break; } - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; } - break; + if (!allGood) + continue; - default: - RELEASE_ASSERT_NOT_REACHED(); - break; + // All systems go for materializing the object. First we recover the values of all of + // its fields and then we call a function to actually allocate the beast. + for (unsigned propertyIndex = materialization->properties().size(); propertyIndex--;) { + const ExitValue& value = materialization->properties()[propertyIndex].value(); + compileRecovery( + jit, value, record, jitCode->stackmaps, registerScratch, + materializationToPointer); + jit.storePtr(GPRInfo::regT0, materializationArguments + propertyIndex); + } + + // This call assumes that we don't pass arguments on the stack. + jit.setupArgumentsWithExecState( + CCallHelpers::TrustedImmPtr(materialization), + CCallHelpers::TrustedImmPtr(materializationArguments)); + jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(operationMaterializeObjectInOSR)), GPRInfo::nonArgGPR0); + jit.call(GPRInfo::nonArgGPR0); + jit.storePtr(GPRInfo::returnValueGPR, materializationToPointer.get(materialization)); + + // Let everyone know that we're done. + toMaterialize.remove(materialization); } + // We expect progress! This ensures that we crash rather than looping infinitely if there + // is something broken about this fixpoint. Or, this could happen if we ever violate the + // "materializations form a DAG" rule. + RELEASE_ASSERT(toMaterialize.size() < previousToMaterializeSize); + } + + // Save all state from wherever the exit data tells us it was, into the appropriate place in + // the scratch buffer. This also does the reboxing. + + for (unsigned index = exit.m_values.size(); index--;) { + compileRecovery( + jit, exit.m_values[index], record, jitCode->stackmaps, registerScratch, + materializationToPointer); jit.store64(GPRInfo::regT0, scratch + index); } @@ -338,29 +432,17 @@ static void compileStub( arityReturnPCReady.link(&jit); - // Now get state out of the scratch buffer and place it back into the stack. This part does - // all reboxing. + // Now get state out of the scratch buffer and place it back into the stack. The values are + // already reboxed so we just move them. for (unsigned index = exit.m_values.size(); index--;) { int operand = exit.m_values.operandForIndex(index); - ExitValue value = exit.m_values[index]; jit.load64(scratch + index, GPRInfo::regT0); - reboxAccordingToFormat( - value.valueFormat(), jit, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT2); jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(static_cast<VirtualRegister>(operand))); } handleExitCounts(jit, exit); reifyInlinedCallFrames(jit, exit); - - ArgumentsRecoveryGenerator argumentsRecovery; - for (unsigned index = exit.m_values.size(); index--;) { - if (!exit.m_values[index].isArgumentsObjectThatWasNotCreated()) - continue; - int operand = exit.m_values.operandForIndex(index); - argumentsRecovery.generateFor(operand, exit.m_codeOrigin, jit); - } - adjustAndJumpToTarget(jit, exit); LinkBuffer patchBuffer(*vm, jit, codeBlock); @@ -395,6 +477,19 @@ extern "C" void* compileFTLOSRExit(ExecState* exec, unsigned exitID) JITCode* jitCode = codeBlock->jitCode()->ftl(); OSRExit& exit = jitCode->osrExit[exitID]; + if (shouldShowDisassembly() || Options::verboseOSR() || Options::verboseFTLOSRExit()) { + dataLog(" Owning block: ", pointerDump(codeBlock), "\n"); + dataLog(" Origin: ", exit.m_codeOrigin, "\n"); + if (exit.m_codeOriginForExitProfile != exit.m_codeOrigin) + dataLog(" Origin for exit profile: ", exit.m_codeOriginForExitProfile, "\n"); + dataLog(" Exit values: ", exit.m_values, "\n"); + if (!exit.m_materializations.isEmpty()) { + dataLog(" Materializations:\n"); + for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) + dataLog(" ", pointerDump(materialization), "\n"); + } + } + prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin); compileStub(exitID, jitCode, exit, vm, codeBlock); diff --git a/ftl/FTLOperations.cpp b/ftl/FTLOperations.cpp new file mode 100644 index 0000000..4e5c8b3 --- /dev/null +++ b/ftl/FTLOperations.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2014, 2015 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 "FTLOperations.h" + +#if ENABLE(FTL_JIT) + +#include "ClonedArguments.h" +#include "DirectArguments.h" +#include "JSCInlines.h" +#include "JSLexicalEnvironment.h" + +namespace JSC { namespace FTL { + +using namespace JSC::DFG; + +extern "C" JSCell* JIT_OPERATION operationNewObjectWithButterfly(ExecState* exec, Structure* structure) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + Butterfly* butterfly = Butterfly::create( + vm, nullptr, 0, structure->outOfLineCapacity(), false, IndexingHeader(), 0); + + return JSFinalObject::create(exec, structure, butterfly); +} + +extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR( + ExecState* exec, ExitTimeObjectMaterialization* materialization, EncodedJSValue* values) +{ + VM& vm = exec->vm(); + CodeBlock* codeBlock = exec->codeBlock(); + + // We cannot GC. We've got pointers in evil places. + DeferGCForAWhile deferGC(vm.heap); + + switch (materialization->type()) { + case PhantomNewObject: { + // First figure out what the structure is. + Structure* structure = nullptr; + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location() != PromotedLocationDescriptor(StructurePLoc)) + continue; + + structure = jsCast<Structure*>(JSValue::decode(values[i])); + break; + } + RELEASE_ASSERT(structure); + + // Let's create that object! + JSFinalObject* result = JSFinalObject::create(vm, structure); + + // Now figure out what the heck to populate the object with. Use getPropertiesConcurrently() + // because that happens to be lower-level and more convenient. It doesn't change the + // materialization of the property table. We want to have minimal visible effects on the + // system. Also, don't mind that this is O(n^2). It doesn't matter. We only get here from OSR + // exit. + for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) { + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location().kind() != NamedPropertyPLoc) + continue; + if (codeBlock->identifier(property.location().info()).impl() != entry.key) + continue; + + result->putDirect(vm, entry.offset, JSValue::decode(values[i])); + } + } + + return result; + } + + case PhantomNewFunction: { + // Figure out what the executable and activation are + FunctionExecutable* executable = nullptr; + JSScope* activation = nullptr; + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location() == PromotedLocationDescriptor(FunctionExecutablePLoc)) + executable = jsCast<FunctionExecutable*>(JSValue::decode(values[i])); + if (property.location() == PromotedLocationDescriptor(FunctionActivationPLoc)) + activation = jsCast<JSScope*>(JSValue::decode(values[i])); + } + RELEASE_ASSERT(executable && activation); + + JSFunction* result = JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation); + + return result; + } + + case PhantomCreateActivation: { + // Figure out where the scope is + JSScope* scope = nullptr; + SymbolTable* table = nullptr; + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location() == PromotedLocationDescriptor(ActivationScopePLoc)) + scope = jsCast<JSScope*>(JSValue::decode(values[i])); + else if (property.location() == PromotedLocationDescriptor(ActivationSymbolTablePLoc)) + table = jsCast<SymbolTable*>(JSValue::decode(values[i])); + } + RELEASE_ASSERT(scope); + RELEASE_ASSERT(table); + + CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock( + materialization->origin(), exec->codeBlock()); + Structure* structure = codeBlock->globalObject()->activationStructure(); + + JSLexicalEnvironment* result = JSLexicalEnvironment::create(vm, structure, scope, table); + + RELEASE_ASSERT(materialization->properties().size() - 2 == table->scopeSize()); + // Figure out what to populate the activation with + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location().kind() != ClosureVarPLoc) + continue; + + result->variableAt(ScopeOffset(property.location().info())).set(exec->vm(), result, JSValue::decode(values[i])); + } + + if (validationEnabled()) { + // Validate to make sure every slot in the scope has one value. + ConcurrentJITLocker locker(table->m_lock); + for (auto iter = table->begin(locker), end = table->end(locker); iter != end; ++iter) { + bool found = false; + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location().kind() != ClosureVarPLoc) + continue; + if (ScopeOffset(property.location().info()) == iter->value.scopeOffset()) { + found = true; + break; + } + } + ASSERT_UNUSED(found, found); + } + unsigned numberOfClosureVarPloc = 0; + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location().kind() == ClosureVarPLoc) + numberOfClosureVarPloc++; + } + ASSERT(numberOfClosureVarPloc == table->scopeSize()); + } + + return result; + } + + case PhantomDirectArguments: + case PhantomClonedArguments: { + if (!materialization->origin().inlineCallFrame) { + switch (materialization->type()) { + case PhantomDirectArguments: + return DirectArguments::createByCopying(exec); + case PhantomClonedArguments: + return ClonedArguments::createWithMachineFrame(exec, exec, ArgumentsMode::Cloned); + default: + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; + } + } + + // First figure out the argument count. If there isn't one then we represent the machine frame. + unsigned argumentCount = 0; + if (materialization->origin().inlineCallFrame->isVarargs()) { + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location() != PromotedLocationDescriptor(ArgumentCountPLoc)) + continue; + + argumentCount = JSValue::decode(values[i]).asUInt32(); + RELEASE_ASSERT(argumentCount); + break; + } + RELEASE_ASSERT(argumentCount); + } else + argumentCount = materialization->origin().inlineCallFrame->arguments.size(); + + JSFunction* callee = nullptr; + if (materialization->origin().inlineCallFrame->isClosureCall) { + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location() != PromotedLocationDescriptor(ArgumentsCalleePLoc)) + continue; + + callee = jsCast<JSFunction*>(JSValue::decode(values[i])); + break; + } + } else + callee = materialization->origin().inlineCallFrame->calleeConstant(); + RELEASE_ASSERT(callee); + + CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock( + materialization->origin(), exec->codeBlock()); + + // We have an inline frame and we have all of the data we need to recreate it. + switch (materialization->type()) { + case PhantomDirectArguments: { + unsigned length = argumentCount - 1; + unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1)); + DirectArguments* result = DirectArguments::create( + vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity); + result->callee().set(vm, result, callee); + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location().kind() != ArgumentPLoc) + continue; + + unsigned index = property.location().info(); + if (index >= capacity) + continue; + + // We don't want to use setIndexQuickly(), since that's only for the passed-in + // arguments but sometimes the number of named arguments is greater. For + // example: + // + // function foo(a, b, c) { ... } + // foo(); + // + // setIndexQuickly() would fail for indices 0, 1, 2 - but we need to recover + // those here. + result->argument(DirectArgumentsOffset(index)).set( + vm, result, JSValue::decode(values[i])); + } + return result; + } + case PhantomClonedArguments: { + unsigned length = argumentCount - 1; + ClonedArguments* result = ClonedArguments::createEmpty( + vm, codeBlock->globalObject()->outOfBandArgumentsStructure(), callee); + + for (unsigned i = materialization->properties().size(); i--;) { + const ExitPropertyValue& property = materialization->properties()[i]; + if (property.location().kind() != ArgumentPLoc) + continue; + + unsigned index = property.location().info(); + if (index >= length) + continue; + result->putDirectIndex(exec, index, JSValue::decode(values[i])); + } + + result->putDirect(vm, vm.propertyNames->length, jsNumber(length)); + return result; + } + default: + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; + } + } + + default: + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; + } +} + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + diff --git a/ftl/FTLOperations.h b/ftl/FTLOperations.h new file mode 100644 index 0000000..d15f18e --- /dev/null +++ b/ftl/FTLOperations.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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 FTLOperations_h +#define FTLOperations_h + +#if ENABLE(FTL_JIT) + +#include "DFGOperations.h" +#include "FTLExitTimeObjectMaterialization.h" + +namespace JSC { namespace FTL { + +extern "C" { + +JSCell* JIT_OPERATION operationNewObjectWithButterfly(ExecState*, Structure*) WTF_INTERNAL; + +JSCell* JIT_OPERATION operationMaterializeObjectInOSR( + ExecState*, ExitTimeObjectMaterialization*, EncodedJSValue*) WTF_INTERNAL; + +} // extern "C" + +} } // namespace JSC::DFG + +#endif // ENABLE(FTL_JIT) + +#endif // FTLOperations_h + diff --git a/ftl/FTLOutput.cpp b/ftl/FTLOutput.cpp index 986d374..30d5fbd 100644 --- a/ftl/FTLOutput.cpp +++ b/ftl/FTLOutput.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -138,9 +138,16 @@ void Output::branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBa constInt32(notTakenWeight.scaleToTotal(total)))); } -void Output::crashNonTerminal() +void Output::check(LValue condition, WeightedTarget taken, Weight notTakenWeight) { - call(intToPtr(constIntPtr(abort), pointerType(functionType(voidType)))); + LBasicBlock continuation = FTL_NEW_BLOCK(*this, ("Output::check continuation")); + branch(condition, taken, WeightedTarget(continuation, notTakenWeight)); + appendTo(continuation); +} + +void Output::check(LValue condition, WeightedTarget taken) +{ + check(condition, taken, taken.weight().inverse()); } } } // namespace JSC::FTL diff --git a/ftl/FTLOutput.h b/ftl/FTLOutput.h index f71b9c6..e2d973d 100644 --- a/ftl/FTLOutput.h +++ b/ftl/FTLOutput.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -133,12 +133,20 @@ public: LValue bitOr(LValue left, LValue right) { return buildOr(m_builder, left, right); } LValue bitXor(LValue left, LValue right) { return buildXor(m_builder, left, right); } LValue shl(LValue left, LValue right) { return buildShl(m_builder, left, right); } - LValue aShr(LValue left, LValue right) { return buildAShr(m_builder, left, right); } - LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); } + LValue aShr(LValue left, LValue right) { return buildAShr(m_builder, left, right); } // arithmetic = signed + LValue lShr(LValue left, LValue right) { return buildLShr(m_builder, left, right); } // logical = unsigned LValue bitNot(LValue value) { return buildNot(m_builder, value); } LValue insertElement(LValue vector, LValue element, LValue index) { return buildInsertElement(m_builder, vector, element, index); } - + + LValue ceil64(LValue operand) + { + return call(ceil64Intrinsic(), operand); + } + LValue ctlz32(LValue xOperand, LValue yOperand) + { + return call(ctlz32Intrinsic(), xOperand, yOperand); + } LValue addWithOverflow32(LValue left, LValue right) { return call(addWithOverflow32Intrinsic(), left, right); @@ -177,16 +185,32 @@ public: return call(doubleCosIntrinsic(), value); } + LValue doublePow(LValue xOperand, LValue yOperand) + { + return call(doublePowIntrinsic(), xOperand, yOperand); + } + + LValue doublePowi(LValue xOperand, LValue yOperand) + { + return call(doublePowiIntrinsic(), xOperand, yOperand); + } + LValue doubleSqrt(LValue value) { return call(doubleSqrtIntrinsic(), value); } + LValue doubleLog(LValue value) + { + return call(doubleLogIntrinsic(), value); + } + static bool hasSensibleDoubleToInt() { return isX86(); } LValue sensibleDoubleToInt(LValue); LValue signExt(LValue value, LType type) { return buildSExt(m_builder, value, type); } LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); } + LValue zeroExtPtr(LValue value) { return zeroExt(value, intPtr); } LValue fpToInt(LValue value, LType type) { return buildFPToSI(m_builder, value, type); } LValue fpToUInt(LValue value, LType type) { return buildFPToUI(m_builder, value, type); } LValue fpToInt32(LValue value) { return fpToInt(value, int32); } @@ -202,6 +226,8 @@ public: LValue ptrToInt(LValue value, LType type) { return buildPtrToInt(m_builder, value, type); } LValue bitCast(LValue value, LType type) { return buildBitCast(m_builder, value, type); } + // Hilariously, the #define machinery in the stdlib means that this method is actually called + // __builtin_alloca. So far this appears benign. :-| LValue alloca(LType type) { return buildAlloca(m_builder, type); } // Access the value of an alloca. Also used as a low-level implementation primitive for @@ -347,13 +373,8 @@ public: LValue call(LValue function, const VectorType& vector) { return buildCall(m_builder, function, vector); } LValue call(LValue function) { return buildCall(m_builder, function); } LValue call(LValue function, LValue arg1) { return buildCall(m_builder, function, arg1); } - LValue call(LValue function, LValue arg1, LValue arg2) { return buildCall(m_builder, function, arg1, arg2); } - LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3) { return buildCall(m_builder, function, arg1, arg2, arg3); } - LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4); } - LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5); } - LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5, arg6); } - LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6, LValue arg7) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - LValue call(LValue function, LValue arg1, LValue arg2, LValue arg3, LValue arg4, LValue arg5, LValue arg6, LValue arg7, LValue arg8) { return buildCall(m_builder, function, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } + template<typename... Args> + LValue call(LValue function, LValue arg1, Args... args) { return buildCall(m_builder, function, arg1, args...); } template<typename FunctionType> LValue operation(FunctionType function) @@ -367,6 +388,13 @@ public: { branch(condition, taken.target(), taken.weight(), notTaken.target(), notTaken.weight()); } + + // Branches to an already-created handler if true, "falls through" if false. Fall-through is + // simulated by creating a continuation for you. + void check(LValue condition, WeightedTarget taken, Weight notTakenWeight); + + // Same as check(), but uses Weight::inverse() to compute the notTakenWeight. + void check(LValue condition, WeightedTarget taken); template<typename VectorType> void switchInstruction(LValue value, const VectorType& cases, LBasicBlock fallThrough, Weight fallThroughWeight) @@ -401,14 +429,6 @@ public: call(trapIntrinsic()); } - void crashNonTerminal(); - - void crash() - { - crashNonTerminal(); - unreachable(); - } - ValueFromBlock anchor(LValue value) { return ValueFromBlock(value, m_block); diff --git a/ftl/FTLSlowPathCall.cpp b/ftl/FTLSlowPathCall.cpp index e48f862..ffbd474 100644 --- a/ftl/FTLSlowPathCall.cpp +++ b/ftl/FTLSlowPathCall.cpp @@ -173,11 +173,24 @@ void storeCodeOrigin(State& state, CCallHelpers& jit, CodeOrigin codeOrigin) CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount))); } +MacroAssembler::Call callOperation( + State& state, const RegisterSet& usedRegisters, CCallHelpers& jit, + CodeOrigin codeOrigin, MacroAssembler::JumpList* exceptionTarget, + J_JITOperation_ESsiCI operation, GPRReg result, StructureStubInfo* stubInfo, + GPRReg object, const UniquedStringImpl* uid) +{ + storeCodeOrigin(state, jit, codeOrigin); + CallContext context(state, usedRegisters, jit, 4, result); + jit.setupArgumentsWithExecState( + CCallHelpers::TrustedImmPtr(stubInfo), object, CCallHelpers::TrustedImmPtr(uid)); + return context.makeCall(bitwise_cast<void*>(operation), exceptionTarget); +} + MacroAssembler::Call callOperation( State& state, const RegisterSet& usedRegisters, CCallHelpers& jit, CodeOrigin codeOrigin, MacroAssembler::JumpList* exceptionTarget, J_JITOperation_ESsiJI operation, GPRReg result, StructureStubInfo* stubInfo, - GPRReg object, StringImpl* uid) + GPRReg object, UniquedStringImpl* uid) { storeCodeOrigin(state, jit, codeOrigin); CallContext context(state, usedRegisters, jit, 4, result); @@ -191,7 +204,7 @@ MacroAssembler::Call callOperation( State& state, const RegisterSet& usedRegisters, CCallHelpers& jit, CodeOrigin codeOrigin, MacroAssembler::JumpList* exceptionTarget, V_JITOperation_ESsiJJI operation, StructureStubInfo* stubInfo, GPRReg value, - GPRReg object, StringImpl* uid) + GPRReg object, UniquedStringImpl* uid) { storeCodeOrigin(state, jit, codeOrigin); CallContext context(state, usedRegisters, jit, 5, InvalidGPRReg); diff --git a/ftl/FTLSlowPathCall.h b/ftl/FTLSlowPathCall.h index 68e09e6..818ef64 100644 --- a/ftl/FTLSlowPathCall.h +++ b/ftl/FTLSlowPathCall.h @@ -57,14 +57,18 @@ private: void storeCodeOrigin(State&, CCallHelpers&, CodeOrigin); +MacroAssembler::Call callOperation( + State&, const RegisterSet&, CCallHelpers&, CodeOrigin, CCallHelpers::JumpList*, + J_JITOperation_ESsiCI, GPRReg, StructureStubInfo*, GPRReg, + const UniquedStringImpl* uid); MacroAssembler::Call callOperation( State&, const RegisterSet&, CCallHelpers&, CodeOrigin, CCallHelpers::JumpList*, J_JITOperation_ESsiJI, GPRReg result, StructureStubInfo*, GPRReg object, - StringImpl* uid); + UniquedStringImpl* uid); MacroAssembler::Call callOperation( State&, const RegisterSet&, CCallHelpers&, CodeOrigin, CCallHelpers::JumpList*, V_JITOperation_ESsiJJI, StructureStubInfo*, GPRReg value, GPRReg object, - StringImpl* uid); + UniquedStringImpl* uid); } } // namespace JSC::FTL diff --git a/ftl/FTLState.cpp b/ftl/FTLState.cpp index 32944d6..038e9b1 100644 --- a/ftl/FTLState.cpp +++ b/ftl/FTLState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,12 @@ #include "FTLForOSREntryJITCode.h" #include "FTLJITCode.h" #include "FTLJITFinalizer.h" +#include <llvm/InitializeLLVM.h> +#include <stdio.h> + +#if ENABLE(FTL_NATIVE_CALL_INLINING) +#include "InlineRuntimeSymbolTable.h" +#endif namespace JSC { namespace FTL { @@ -43,9 +49,21 @@ State::State(Graph& graph) , module(0) , function(0) , generatedFunction(0) - , compactUnwind(0) - , compactUnwindSize(0) + , handleStackOverflowExceptionStackmapID(UINT_MAX) + , handleExceptionStackmapID(UINT_MAX) + , capturedStackmapID(UINT_MAX) + , varargsSpillSlotsStackmapID(UINT_MAX) + , unwindDataSection(0) + , unwindDataSectionSize(0) { + +#if ENABLE(FTL_NATIVE_CALL_INLINING) +#define SYMBOL_TABLE_ADD(symbol, file) \ + symbolTable.fastAdd(symbol, file); + FOR_EACH_LIBRARY_SYMBOL(SYMBOL_TABLE_ADD) +#undef SYMBOL_TABLE_ADD +#endif + switch (graph.m_plan.mode) { case FTLMode: { jitCode = adoptRef(new JITCode()); @@ -62,9 +80,9 @@ State::State(Graph& graph) RELEASE_ASSERT_NOT_REACHED(); break; } - - finalizer = new JITFinalizer(graph.m_plan); - graph.m_plan.finalizer = adoptPtr(finalizer); + + graph.m_plan.finalizer = std::make_unique<JITFinalizer>(graph.m_plan); + finalizer = static_cast<JITFinalizer*>(graph.m_plan.finalizer.get()); } State::~State() @@ -73,6 +91,11 @@ State::~State() } void State::dumpState(const char* when) +{ + dumpState(module, when); +} + +void State::dumpState(LModule module, const char* when) { dataLog("LLVM IR for ", CodeBlockWithJITType(graph.m_codeBlock, FTL::JITCode::FTLJIT), " ", when, ":\n"); dumpModule(module); diff --git a/ftl/FTLState.h b/ftl/FTLState.h index 5219e29..8a0679b 100644 --- a/ftl/FTLState.h +++ b/ftl/FTLState.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,6 +36,7 @@ #include "FTLJITCode.h" #include "FTLJITFinalizer.h" #include "FTLJSCall.h" +#include "FTLJSCallVarargs.h" #include "FTLStackMaps.h" #include "FTLState.h" #include <wtf/Noncopyable.h> @@ -65,22 +66,33 @@ public: LContext context; LModule module; LValue function; + bool allocationFailed { false }; // Throw out the compilation once LLVM returns. RefPtr<JITCode> jitCode; GeneratedFunction generatedFunction; JITFinalizer* finalizer; unsigned handleStackOverflowExceptionStackmapID; unsigned handleExceptionStackmapID; unsigned capturedStackmapID; + unsigned varargsSpillSlotsStackmapID; SegmentedVector<GetByIdDescriptor> getByIds; SegmentedVector<PutByIdDescriptor> putByIds; + SegmentedVector<CheckInDescriptor> checkIns; Vector<JSCall> jsCalls; + Vector<JSCallVarargs> jsCallVarargses; Vector<CString> codeSectionNames; Vector<CString> dataSectionNames; - void* compactUnwind; - size_t compactUnwindSize; + void* unwindDataSection; + size_t unwindDataSectionSize; RefPtr<DataSection> stackmapsSection; void dumpState(const char* when); + void dumpState(LModule, const char* when); + + HashSet<CString> nativeLoadedLibraries; + +#if ENABLE(FTL_NATIVE_CALL_INLINING) + HashMap<CString, CString> symbolTable; +#endif }; } } // namespace JSC::FTL diff --git a/ftl/FTLSwitchCase.h b/ftl/FTLSwitchCase.h index 123a475..cd6bc07 100644 --- a/ftl/FTLSwitchCase.h +++ b/ftl/FTLSwitchCase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,13 @@ namespace JSC { namespace FTL { class SwitchCase { public: - SwitchCase(LValue value, LBasicBlock target, Weight weight) + SwitchCase() + : m_value(nullptr) + , m_target(nullptr) + { + } + + SwitchCase(LValue value, LBasicBlock target, Weight weight = Weight()) : m_value(value) , m_target(target) , m_weight(weight) diff --git a/ftl/FTLUnwindInfo.cpp b/ftl/FTLUnwindInfo.cpp index 98c1831..2867a72 100644 --- a/ftl/FTLUnwindInfo.cpp +++ b/ftl/FTLUnwindInfo.cpp @@ -1,5 +1,7 @@ /* * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 Samsung Electronics + * Copyright (C) 2014 University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,7 +22,73 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ============================================================================== + * + * University of Illinois/NCSA + * Open Source License + * + * Copyright (c) 2009-2014 by the contributors of LLVM/libc++abi project. + * + * All rights reserved. + * + * Developed by: + * + * LLVM Team + * + * University of Illinois at Urbana-Champaign + * + * http://llvm.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal with + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimers. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimers in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the names of the LLVM Team, University of Illinois at + * Urbana-Champaign, nor the names of its contributors may be used to + * endorse or promote products derived from this Software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE + * SOFTWARE. + * + * ============================================================================== + * + * Copyright (c) 2009-2014 by the contributors of LLVM/libc++abi project. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ #include "config.h" @@ -28,7 +96,9 @@ #if ENABLE(FTL_JIT) +#if OS(DARWIN) #include <mach-o/compact_unwind_encoding.h> +#endif #include <wtf/ListDump.h> namespace JSC { namespace FTL { @@ -36,8 +106,9 @@ namespace JSC { namespace FTL { UnwindInfo::UnwindInfo() { } UnwindInfo::~UnwindInfo() { } -namespace { +namespace { +#if OS(DARWIN) struct CompactUnwind { void* function; uint32_t size; @@ -45,17 +116,552 @@ struct CompactUnwind { void* personality; void* lsda; }; +#elif OS(LINUX) +// DWARF unwind instructions +enum { + DW_CFA_nop = 0x0, + DW_CFA_set_loc = 0x1, + DW_CFA_advance_loc1 = 0x2, + DW_CFA_advance_loc2 = 0x3, + DW_CFA_advance_loc4 = 0x4, + DW_CFA_offset_extended = 0x5, + DW_CFA_def_cfa = 0xC, + DW_CFA_def_cfa_register = 0xD, + DW_CFA_def_cfa_offset = 0xE, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + // high 2 bits are 0x1, lower 6 bits are delta + DW_CFA_advance_loc = 0x40, + // high 2 bits are 0x2, lower 6 bits are register + DW_CFA_offset = 0x80 +}; + +enum { + DW_CFA_operand_mask = 0x3F // low 6 bits mask for opcode-encoded operands in DW_CFA_advance_loc and DW_CFA_offset +}; + +// FSF exception handling Pointer-Encoding constants +enum { + DW_EH_PE_ptr = 0x00, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + DW_EH_PE_absptr = 0x00, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_indirect = 0x80 +}; + +enum { + DW_EH_PE_relative_mask = 0x70 +}; + +// 64-bit x86_64 registers +enum { + UNW_X86_64_rbx = 3, + UNW_X86_64_rbp = 6, + UNW_X86_64_r12 = 12, + UNW_X86_64_r13 = 13, + UNW_X86_64_r14 = 14, + UNW_X86_64_r15 = 15 +}; + +enum { + DW_X86_64_RET_addr = 16 +}; + +enum { + UNW_ARM64_x0 = 0, + UNW_ARM64_x1 = 1, + UNW_ARM64_x2 = 2, + UNW_ARM64_x3 = 3, + UNW_ARM64_x4 = 4, + UNW_ARM64_x5 = 5, + UNW_ARM64_x6 = 6, + UNW_ARM64_x7 = 7, + UNW_ARM64_x8 = 8, + UNW_ARM64_x9 = 9, + UNW_ARM64_x10 = 10, + UNW_ARM64_x11 = 11, + UNW_ARM64_x12 = 12, + UNW_ARM64_x13 = 13, + UNW_ARM64_x14 = 14, + UNW_ARM64_x15 = 15, + UNW_ARM64_x16 = 16, + UNW_ARM64_x17 = 17, + UNW_ARM64_x18 = 18, + UNW_ARM64_x19 = 19, + UNW_ARM64_x20 = 20, + UNW_ARM64_x21 = 21, + UNW_ARM64_x22 = 22, + UNW_ARM64_x23 = 23, + UNW_ARM64_x24 = 24, + UNW_ARM64_x25 = 25, + UNW_ARM64_x26 = 26, + UNW_ARM64_x27 = 27, + UNW_ARM64_x28 = 28, + UNW_ARM64_fp = 29, + UNW_ARM64_x30 = 30, + UNW_ARM64_sp = 31, + UNW_ARM64_v0 = 64, + UNW_ARM64_v1 = 65, + UNW_ARM64_v2 = 66, + UNW_ARM64_v3 = 67, + UNW_ARM64_v4 = 68, + UNW_ARM64_v5 = 69, + UNW_ARM64_v6 = 70, + UNW_ARM64_v7 = 71, + UNW_ARM64_v8 = 72, + UNW_ARM64_v9 = 73, + UNW_ARM64_v10 = 74, + UNW_ARM64_v11 = 75, + UNW_ARM64_v12 = 76, + UNW_ARM64_v13 = 77, + UNW_ARM64_v14 = 78, + UNW_ARM64_v15 = 79, + UNW_ARM64_v16 = 80, + UNW_ARM64_v17 = 81, + UNW_ARM64_v18 = 82, + UNW_ARM64_v19 = 83, + UNW_ARM64_v20 = 84, + UNW_ARM64_v21 = 85, + UNW_ARM64_v22 = 86, + UNW_ARM64_v23 = 87, + UNW_ARM64_v24 = 88, + UNW_ARM64_v25 = 89, + UNW_ARM64_v26 = 90, + UNW_ARM64_v27 = 91, + UNW_ARM64_v28 = 92, + UNW_ARM64_v29 = 93, + UNW_ARM64_v30 = 94, + UNW_ARM64_v31 = 95 +}; + +static uint8_t get8(uintptr_t addr) { return *((uint8_t*)addr); } +static uint16_t get16(uintptr_t addr) { return *((uint16_t*)addr); } +static uint32_t get32(uintptr_t addr) { return *((uint32_t*)addr); } +static uint64_t get64(uintptr_t addr) { return *((uint64_t*)addr); } + +static uintptr_t getP(uintptr_t addr) +{ + // FIXME: add support for 32 bit pointers on 32 bit architectures + return get64(addr); +} + +static uint64_t getULEB128(uintptr_t& addr, uintptr_t end) +{ + const uint8_t* p = (uint8_t*)addr; + const uint8_t* pend = (uint8_t*)end; + uint64_t result = 0; + int bit = 0; + do { + uint64_t b; + + RELEASE_ASSERT(p != pend); // truncated uleb128 expression + + b = *p & 0x7f; + + RELEASE_ASSERT(!(bit >= 64 || b << bit >> bit != b)); // malformed uleb128 expression + + result |= b << bit; + bit += 7; + } while (*p++ >= 0x80); + addr = (uintptr_t)p; + return result; +} + +static int64_t getSLEB128(uintptr_t& addr, uintptr_t end) +{ + const uint8_t* p = (uint8_t*)addr; + const uint8_t* pend = (uint8_t*)end; + + int64_t result = 0; + int bit = 0; + uint8_t byte; + do { + RELEASE_ASSERT(p != pend); // truncated sleb128 expression + + byte = *p++; + result |= ((byte & 0x7f) << bit); + bit += 7; + } while (byte & 0x80); + // sign extend negative numbers + if ((byte & 0x40)) + result |= (-1LL) << bit; + addr = (uintptr_t)p; + return result; +} + +static uintptr_t getEncodedP(uintptr_t& addr, uintptr_t end, uint8_t encoding) +{ + uintptr_t startAddr = addr; + const uint8_t* p = (uint8_t*)addr; + uintptr_t result; + + // first get value + switch (encoding & 0x0F) { + case DW_EH_PE_ptr: + result = getP(addr); + p += sizeof(uintptr_t); + addr = (uintptr_t)p; + break; + case DW_EH_PE_uleb128: + result = getULEB128(addr, end); + break; + case DW_EH_PE_udata2: + result = get16(addr); + p += 2; + addr = (uintptr_t)p; + break; + case DW_EH_PE_udata4: + result = get32(addr); + p += 4; + addr = (uintptr_t)p; + break; + case DW_EH_PE_udata8: + result = get64(addr); + p += 8; + addr = (uintptr_t)p; + break; + case DW_EH_PE_sleb128: + result = getSLEB128(addr, end); + break; + case DW_EH_PE_sdata2: + result = (int16_t)get16(addr); + p += 2; + addr = (uintptr_t)p; + break; + case DW_EH_PE_sdata4: + result = (int32_t)get32(addr); + p += 4; + addr = (uintptr_t)p; + break; + case DW_EH_PE_sdata8: + result = get64(addr); + p += 8; + addr = (uintptr_t)p; + break; + default: + RELEASE_ASSERT_NOT_REACHED(); // unknown pointer encoding + } + + // then add relative offset + switch (encoding & DW_EH_PE_relative_mask) { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + result += startAddr; + break; + default: + RELEASE_ASSERT_NOT_REACHED(); // unsupported or unknown pointer encoding + } + + if (encoding & DW_EH_PE_indirect) + result = getP(result); + + return result; +} + +// Information encoded in a CIE (Common Information Entry) +struct CIE_Info { + uintptr_t cieStart; + uintptr_t cieLength; + uintptr_t cieInstructions; + uint8_t pointerEncoding; + uint8_t lsdaEncoding; + uint8_t personalityEncoding; + uint8_t personalityOffsetInCIE; + uintptr_t personality; + int dataAlignFactor; + bool fdesHaveAugmentationData; +}; + +// Information about an FDE (Frame Description Entry) +struct FDE_Info { + uintptr_t fdeStart; + uintptr_t fdeLength; + uintptr_t fdeInstructions; + uintptr_t lsda; +}; + +// Information about a frame layout and registers saved determined +// by "running" the dwarf FDE "instructions" +#if CPU(ARM64) +enum { MaxRegisterNumber = 120 }; +#elif CPU(X86_64) +enum { MaxRegisterNumber = 17 }; +#else +#error "Unrecognized architecture" +#endif + +struct RegisterLocation { + bool saved; + int64_t offset; +}; +struct PrologInfo { + uint32_t cfaRegister; + int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset + RegisterLocation savedRegisters[MaxRegisterNumber]; // from where to restore registers +}; + +static void parseCIE(uintptr_t cie, CIE_Info* cieInfo) +{ + cieInfo->pointerEncoding = 0; + cieInfo->lsdaEncoding = 0; + cieInfo->personalityEncoding = 0; + cieInfo->personalityOffsetInCIE = 0; + cieInfo->personality = 0; + cieInfo->dataAlignFactor = 0; + cieInfo->fdesHaveAugmentationData = false; + cieInfo->cieStart = cie; + + uintptr_t p = cie; + uint64_t cieLength = get32(p); + p += 4; + uintptr_t cieContentEnd = p + cieLength; + if (cieLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cieLength = get64(p); + p += 8; + cieContentEnd = p + cieLength; + } + + RELEASE_ASSERT(cieLength); + + // CIE ID is always 0 + RELEASE_ASSERT(!get32(p)); // CIE ID is not zero + p += 4; + // Version is always 1 or 3 + uint8_t version = get8(p); + RELEASE_ASSERT((version == 1) || (version == 3)); // CIE version is not 1 or 3 + + ++p; + // save start of augmentation string and find end + uintptr_t strStart = p; + while (get8(p)) + ++p; + ++p; + // parse code aligment factor + getULEB128(p, cieContentEnd); + // parse data alignment factor + cieInfo->dataAlignFactor = getSLEB128(p, cieContentEnd); + // parse return address register + getULEB128(p, cieContentEnd); + // parse augmentation data based on augmentation string + if (get8(strStart) == 'z') { + // parse augmentation data length + getULEB128(p, cieContentEnd); + for (uintptr_t s = strStart; get8(s) != '\0'; ++s) { + switch (get8(s)) { + case 'z': + cieInfo->fdesHaveAugmentationData = true; + break; + case 'P': // FIXME: should assert on personality (just to keep in sync with the CU behaviour) + cieInfo->personalityEncoding = get8(p); + ++p; + cieInfo->personalityOffsetInCIE = p - cie; + cieInfo->personality = getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); + break; + case 'L': // FIXME: should assert on LSDA (just to keep in sync with the CU behaviour) + cieInfo->lsdaEncoding = get8(p); + ++p; + break; + case 'R': + cieInfo->pointerEncoding = get8(p); + ++p; + break; + default: + // ignore unknown letters + break; + } + } + } + cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; + cieInfo->cieInstructions = p; +} + +static void findFDE(uintptr_t pc, uintptr_t ehSectionStart, uint32_t sectionLength, FDE_Info* fdeInfo, CIE_Info* cieInfo) +{ + uintptr_t p = ehSectionStart; + const uintptr_t ehSectionEnd = p + sectionLength; + while (p < ehSectionEnd) { + uintptr_t currentCFI = p; + uint64_t cfiLength = get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = get64(p); + p += 8; + } + RELEASE_ASSERT(cfiLength); // end marker reached before finding FDE for pc + + uint32_t id = get32(p); + if (!id) { + // skip over CIEs + p += cfiLength; + } else { + // process FDE to see if it covers pc + uintptr_t nextCFI = p + cfiLength; + uint32_t ciePointer = get32(p); + uintptr_t cieStart = p - ciePointer; + // validate pointer to CIE is within section + RELEASE_ASSERT((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)); // malformed FDE. CIE is bad + + parseCIE(cieStart, cieInfo); + + p += 4; + // parse pc begin and range + uintptr_t pcStart = getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + uintptr_t pcRange = getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); + + // test if pc is within the function this FDE covers + // if pc is not in begin/range, skip this FDE + if ((pcStart <= pc) && (pc < pcStart+pcRange)) { + // parse rest of info + fdeInfo->lsda = 0; + // check for augmentation length + if (cieInfo->fdesHaveAugmentationData) { + uintptr_t augLen = getULEB128(p, nextCFI); + uintptr_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding) { + // peek at value (without indirection). Zero means no lsda + uintptr_t lsdaStart = p; + if (getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F)) { + // reset pointer and re-parse lsda address + p = lsdaStart; + fdeInfo->lsda = getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = currentCFI; + fdeInfo->fdeLength = nextCFI - currentCFI; + fdeInfo->fdeInstructions = p; + + return; // FDE found + } + + p = nextCFI; + } + } + + RELEASE_ASSERT_NOT_REACHED(); // no FDE found for pc +} + +static void executeDefCFARegister(uint64_t reg, PrologInfo* results) +{ + RELEASE_ASSERT(reg <= MaxRegisterNumber); // reg too big + results->cfaRegister = reg; +} + +static void executeDefCFAOffset(int64_t offset, PrologInfo* results) +{ + RELEASE_ASSERT(offset <= 0x80000000); // cfa has negative offset (dwarf might contain epilog) + results->cfaRegisterOffset = offset; +} + +static void executeOffset(uint64_t reg, int64_t offset, PrologInfo *results) +{ + if (reg > MaxRegisterNumber) + return; + + RELEASE_ASSERT(!results->savedRegisters[reg].saved); + results->savedRegisters[reg].saved = true; + results->savedRegisters[reg].offset = offset; +} + +static void parseInstructions(uintptr_t instructions, uintptr_t instructionsEnd, const CIE_Info& cieInfo, PrologInfo* results) +{ + uintptr_t p = instructions; + + // see Dwarf Spec, section 6.4.2 for details on unwind opcodes + while ((p < instructionsEnd)) { + uint64_t reg; + uint8_t opcode = get8(p); + uint8_t operand; + ++p; + switch (opcode) { + case DW_CFA_nop: + break; + case DW_CFA_set_loc: + getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); + break; + case DW_CFA_advance_loc1: + p += 1; + break; + case DW_CFA_advance_loc2: + p += 2; + break; + case DW_CFA_advance_loc4: + p += 4; + break; + case DW_CFA_def_cfa: + executeDefCFARegister(getULEB128(p, instructionsEnd), results); + executeDefCFAOffset(getULEB128(p, instructionsEnd), results); + break; + case DW_CFA_def_cfa_sf: + executeDefCFARegister(getULEB128(p, instructionsEnd), results); + executeDefCFAOffset(getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); + break; + case DW_CFA_def_cfa_register: + executeDefCFARegister(getULEB128(p, instructionsEnd), results); + break; + case DW_CFA_def_cfa_offset: + executeDefCFAOffset(getULEB128(p, instructionsEnd), results); + break; + case DW_CFA_def_cfa_offset_sf: + executeDefCFAOffset(getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); + break; + case DW_CFA_offset_extended: + reg = getULEB128(p, instructionsEnd); + executeOffset(reg, getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); + break; + case DW_CFA_offset_extended_sf: + reg = getULEB128(p, instructionsEnd); + executeOffset(reg, getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); + break; + default: + operand = opcode & DW_CFA_operand_mask; + switch (opcode & ~DW_CFA_operand_mask) { + case DW_CFA_offset: + executeOffset(operand, getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); + break; + case DW_CFA_advance_loc: + break; + default: + RELEASE_ASSERT_NOT_REACHED(); // unknown or unsupported CFA opcode + } + } + } +} + +static void parseFDEInstructions(const FDE_Info& fdeInfo, const CIE_Info& cieInfo, PrologInfo* results) +{ + // clear results + bzero(results, sizeof(PrologInfo)); + + // parse CIE then FDE instructions + parseInstructions(cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, cieInfo, results); + parseInstructions(fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, results); +} +#endif } // anonymous namespace bool UnwindInfo::parse(void* section, size_t size, GeneratedFunction generatedFunction) { m_registers.clear(); - - RELEASE_ASSERT(!!section == !!size); + RELEASE_ASSERT(!!section); if (!section) return false; - + +#if OS(DARWIN) RELEASE_ASSERT(size >= sizeof(CompactUnwind)); CompactUnwind* data = bitwise_cast<CompactUnwind*>(section); @@ -157,7 +763,260 @@ bool UnwindInfo::parse(void* section, size_t size, GeneratedFunction generatedFu #else #error "Unrecognized architecture" #endif - + +#elif OS(LINUX) + FDE_Info fdeInfo; + CIE_Info cieInfo; + PrologInfo prolog; + + findFDE((uintptr_t)generatedFunction, (uintptr_t)section, size, &fdeInfo, &cieInfo); + parseFDEInstructions(fdeInfo, cieInfo, &prolog); + +#if CPU(X86_64) + RELEASE_ASSERT(prolog.cfaRegister == UNW_X86_64_rbp); + RELEASE_ASSERT(prolog.cfaRegisterOffset == 16); + RELEASE_ASSERT(prolog.savedRegisters[UNW_X86_64_rbp].saved); + RELEASE_ASSERT(prolog.savedRegisters[UNW_X86_64_rbp].offset == -prolog.cfaRegisterOffset); + + for (int i = 0; i < MaxRegisterNumber; ++i) { + if (prolog.savedRegisters[i].saved) { + switch (i) { + case UNW_X86_64_rbx: + m_registers.append(RegisterAtOffset(X86Registers::ebx, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_X86_64_r12: + m_registers.append(RegisterAtOffset(X86Registers::r12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_X86_64_r13: + m_registers.append(RegisterAtOffset(X86Registers::r13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_X86_64_r14: + m_registers.append(RegisterAtOffset(X86Registers::r14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_X86_64_r15: + m_registers.append(RegisterAtOffset(X86Registers::r15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_X86_64_rbp: + m_registers.append(RegisterAtOffset(X86Registers::ebp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case DW_X86_64_RET_addr: + break; + default: + RELEASE_ASSERT_NOT_REACHED(); // non-standard register being saved in prolog + } + } + } +#elif CPU(ARM64) + RELEASE_ASSERT(prolog.cfaRegister == UNW_ARM64_fp); + RELEASE_ASSERT(prolog.cfaRegisterOffset == 16); + RELEASE_ASSERT(prolog.savedRegisters[UNW_ARM64_fp].saved); + RELEASE_ASSERT(prolog.savedRegisters[UNW_ARM64_fp].offset == -prolog.cfaRegisterOffset); + + for (int i = 0; i < MaxRegisterNumber; ++i) { + if (prolog.savedRegisters[i].saved) { + switch (i) { + case UNW_ARM64_x0: + m_registers.append(RegisterAtOffset(ARM64Registers::x0, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x1: + m_registers.append(RegisterAtOffset(ARM64Registers::x1, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x2: + m_registers.append(RegisterAtOffset(ARM64Registers::x2, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x3: + m_registers.append(RegisterAtOffset(ARM64Registers::x3, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x4: + m_registers.append(RegisterAtOffset(ARM64Registers::x4, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x5: + m_registers.append(RegisterAtOffset(ARM64Registers::x5, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x6: + m_registers.append(RegisterAtOffset(ARM64Registers::x6, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x7: + m_registers.append(RegisterAtOffset(ARM64Registers::x7, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x8: + m_registers.append(RegisterAtOffset(ARM64Registers::x8, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x9: + m_registers.append(RegisterAtOffset(ARM64Registers::x9, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x10: + m_registers.append(RegisterAtOffset(ARM64Registers::x10, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x11: + m_registers.append(RegisterAtOffset(ARM64Registers::x11, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x12: + m_registers.append(RegisterAtOffset(ARM64Registers::x12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x13: + m_registers.append(RegisterAtOffset(ARM64Registers::x13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x14: + m_registers.append(RegisterAtOffset(ARM64Registers::x14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x15: + m_registers.append(RegisterAtOffset(ARM64Registers::x15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x16: + m_registers.append(RegisterAtOffset(ARM64Registers::x16, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x17: + m_registers.append(RegisterAtOffset(ARM64Registers::x17, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x18: + m_registers.append(RegisterAtOffset(ARM64Registers::x18, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x19: + m_registers.append(RegisterAtOffset(ARM64Registers::x19, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x20: + m_registers.append(RegisterAtOffset(ARM64Registers::x20, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x21: + m_registers.append(RegisterAtOffset(ARM64Registers::x21, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x22: + m_registers.append(RegisterAtOffset(ARM64Registers::x22, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x23: + m_registers.append(RegisterAtOffset(ARM64Registers::x23, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x24: + m_registers.append(RegisterAtOffset(ARM64Registers::x24, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x25: + m_registers.append(RegisterAtOffset(ARM64Registers::x25, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x26: + m_registers.append(RegisterAtOffset(ARM64Registers::x26, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x27: + m_registers.append(RegisterAtOffset(ARM64Registers::x27, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x28: + m_registers.append(RegisterAtOffset(ARM64Registers::x28, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_fp: + m_registers.append(RegisterAtOffset(ARM64Registers::fp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_x30: + m_registers.append(RegisterAtOffset(ARM64Registers::x30, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_sp: + m_registers.append(RegisterAtOffset(ARM64Registers::sp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v0: + m_registers.append(RegisterAtOffset(ARM64Registers::q0, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v1: + m_registers.append(RegisterAtOffset(ARM64Registers::q1, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v2: + m_registers.append(RegisterAtOffset(ARM64Registers::q2, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v3: + m_registers.append(RegisterAtOffset(ARM64Registers::q3, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v4: + m_registers.append(RegisterAtOffset(ARM64Registers::q4, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v5: + m_registers.append(RegisterAtOffset(ARM64Registers::q5, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v6: + m_registers.append(RegisterAtOffset(ARM64Registers::q6, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v7: + m_registers.append(RegisterAtOffset(ARM64Registers::q7, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v8: + m_registers.append(RegisterAtOffset(ARM64Registers::q8, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v9: + m_registers.append(RegisterAtOffset(ARM64Registers::q9, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v10: + m_registers.append(RegisterAtOffset(ARM64Registers::q10, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v11: + m_registers.append(RegisterAtOffset(ARM64Registers::q11, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v12: + m_registers.append(RegisterAtOffset(ARM64Registers::q12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v13: + m_registers.append(RegisterAtOffset(ARM64Registers::q13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v14: + m_registers.append(RegisterAtOffset(ARM64Registers::q14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v15: + m_registers.append(RegisterAtOffset(ARM64Registers::q15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v16: + m_registers.append(RegisterAtOffset(ARM64Registers::q16, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v17: + m_registers.append(RegisterAtOffset(ARM64Registers::q17, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v18: + m_registers.append(RegisterAtOffset(ARM64Registers::q18, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v19: + m_registers.append(RegisterAtOffset(ARM64Registers::q19, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v20: + m_registers.append(RegisterAtOffset(ARM64Registers::q20, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v21: + m_registers.append(RegisterAtOffset(ARM64Registers::q21, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v22: + m_registers.append(RegisterAtOffset(ARM64Registers::q22, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v23: + m_registers.append(RegisterAtOffset(ARM64Registers::q23, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v24: + m_registers.append(RegisterAtOffset(ARM64Registers::q24, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v25: + m_registers.append(RegisterAtOffset(ARM64Registers::q25, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v26: + m_registers.append(RegisterAtOffset(ARM64Registers::q26, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v27: + m_registers.append(RegisterAtOffset(ARM64Registers::q27, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v28: + m_registers.append(RegisterAtOffset(ARM64Registers::q28, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v29: + m_registers.append(RegisterAtOffset(ARM64Registers::q29, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v30: + m_registers.append(RegisterAtOffset(ARM64Registers::q30, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + case UNW_ARM64_v31: + m_registers.append(RegisterAtOffset(ARM64Registers::q31, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); + break; + default: + RELEASE_ASSERT_NOT_REACHED(); // non-standard register being saved in prolog + } + } + } +#else +#error "Unrecognized architecture" +#endif + +#endif std::sort(m_registers.begin(), m_registers.end()); return true; } diff --git a/ftl/FTLUnwindInfo.h b/ftl/FTLUnwindInfo.h index a4e7abd..6d2bf63 100644 --- a/ftl/FTLUnwindInfo.h +++ b/ftl/FTLUnwindInfo.h @@ -1,5 +1,7 @@ /* * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 Samsung Electronics + * Copyright (C) 2014 University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/ftl/FTLWeight.h b/ftl/FTLWeight.h index 9b50681..34eb37c 100644 --- a/ftl/FTLWeight.h +++ b/ftl/FTLWeight.h @@ -62,6 +62,16 @@ public: return static_cast<unsigned>(result); } + // Inverse weight for a two-target branch. + Weight inverse() const + { + if (!isSet()) + return Weight(); + if (value()) + return Weight(0); + return Weight(1); + } + private: float m_value; }; diff --git a/generate-js-builtins b/generate-js-builtins index 613a207..446b497 100644 --- a/generate-js-builtins +++ b/generate-js-builtins @@ -22,6 +22,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import argparse import filecmp import fnmatch import os @@ -31,6 +32,12 @@ import sys import datetime import json +parser = argparse.ArgumentParser() +parser.add_argument('input_file', nargs='*', help='Input JS files which builtins generated from') +parser.add_argument('--input-directory', help='All JS files will be used as input from this directory.') +parser.add_argument('--output', help='path to output cpp or h file') +args = parser.parse_args() + copyrightText = """ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -59,7 +66,7 @@ generatorString = "/* Generated by %s do not hand edit. */\n" % os.path.basename functionHeadRegExp = re.compile(r"function\s+\w+\s*\(.*?\)", re.MULTILINE | re.S) functionNameRegExp = re.compile(r"function\s+(\w+)\s*\(", re.MULTILINE | re.S) -functionParameterFinder = re.compile(r"^function\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\)", re.MULTILINE | re.S) +functionParameterFinder = re.compile(r"^function\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\s*\)", re.MULTILINE | re.S) multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S) singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S) @@ -151,13 +158,14 @@ def mangleName(object, name): return mangledName builtins = [] +copyrights = [] +(output_base, _) = os.path.splitext(args.output) -baseName = sys.argv[-1] -builtin_definitions = sys.argv[1:-1] -(output_base, _) = os.path.splitext(sys.argv[-1]) +if args.input_directory: + for file in os.listdir(args.input_directory): + args.input_file.append(os.path.join(args.input_directory, file)) -copyrights = [] -for file in builtin_definitions: +for file in args.input_file: if fnmatch.fnmatch(file, '*.js'): (baseName, functions, objectCopyrights) = generateCode(file) copyrights.extend(objectCopyrights) @@ -264,24 +272,10 @@ for (codeReference, name, source) in codeReferences: builtinsImplementation.write("const int s_%sLength = %d;\n\n" % (codeReference, sourceLength + 1)) # + 1 for \n builtinsImplementation.write(""" -FunctionExecutable* createBuiltinExecutable(VM& vm, UnlinkedFunctionExecutable* unlinkedExecutable, const SourceCode& source) -{ - unsigned lineCount = unlinkedExecutable->lineCount(); - unsigned startColumn = 1; - unsigned sourceLength = unlinkedExecutable->sourceLength(); - bool endColumnIsOnStartLine = !lineCount; - unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); - unsigned startOffset = unlinkedExecutable->startOffset(); - unsigned startOffsetExcludingOpenBrace = startOffset + 1; - unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; - SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, 0, startColumn); - return FunctionExecutable::create(vm, bodySource, unlinkedExecutable, 0, lineCount, startColumn, endColumnExcludingBraces, false); -} - #define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ FunctionExecutable* codeName##Generator(VM& vm) \\ { \\ - return createBuiltinExecutable(vm, vm.builtinExecutables()->codeName##Executable(), vm.builtinExecutables()->codeName##Source()); \\ + return vm.builtinExecutables()->codeName##Executable()->link(vm, vm.builtinExecutables()->codeName##Source()); \\ } JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR) @@ -294,11 +288,15 @@ builtinsHeader.close() builtinsImplementation.close() if (not os.path.exists(output_base + ".h")) or (not filecmp.cmp(output_base + ".h.tmp", output_base + ".h", shallow=False)): + if (os.path.exists(output_base + ".h")): + os.remove(output_base + ".h") os.rename(output_base + ".h.tmp", output_base + ".h") else: os.remove(output_base + ".h.tmp") if (not os.path.exists(output_base + ".cpp")) or (not filecmp.cmp(output_base + ".cpp.tmp", output_base + ".cpp", shallow=False)): + if (os.path.exists(output_base + ".cpp")): + os.remove(output_base + ".cpp") os.rename(output_base + ".cpp.tmp", output_base + ".cpp") else: os.remove(output_base + ".cpp.tmp") diff --git a/heap/BlockAllocator.cpp b/heap/BlockAllocator.cpp deleted file mode 100644 index bf408f8..0000000 --- a/heap/BlockAllocator.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "BlockAllocator.h" - -#include "CopiedBlock.h" -#include "CopyWorkList.h" -#include "MarkedBlock.h" -#include "JSCInlines.h" -#include "WeakBlock.h" -#include <wtf/CurrentTime.h> - -namespace JSC { - -inline ThreadIdentifier createBlockFreeingThread(BlockAllocator* allocator) -{ - if (!GCActivityCallback::s_shouldCreateGCTimer) - return 0; // No block freeing thread. - ThreadIdentifier identifier = createThread(allocator->blockFreeingThreadStartFunc, allocator, "JavaScriptCore::BlockFree"); - RELEASE_ASSERT(identifier); - return identifier; -} - -BlockAllocator::BlockAllocator() - : m_superRegion() - , m_copiedRegionSet(CopiedBlock::blockSize) - , m_markedRegionSet(MarkedBlock::blockSize) - , m_fourKBBlockRegionSet(WeakBlock::blockSize) - , m_workListRegionSet(CopyWorkListSegment::blockSize) - , m_numberOfEmptyRegions(0) - , m_isCurrentlyAllocating(false) - , m_blockFreeingThreadShouldQuit(false) - , m_blockFreeingThread(createBlockFreeingThread(this)) -{ - m_regionLock.Init(); -} - -BlockAllocator::~BlockAllocator() -{ - releaseFreeRegions(); - { - std::lock_guard<std::mutex> lock(m_emptyRegionConditionMutex); - m_blockFreeingThreadShouldQuit = true; - m_emptyRegionCondition.notify_all(); - } - if (m_blockFreeingThread) - waitForThreadCompletion(m_blockFreeingThread); - ASSERT(allRegionSetsAreEmpty()); - ASSERT(m_emptyRegions.isEmpty()); -} - -bool BlockAllocator::allRegionSetsAreEmpty() const -{ - return m_copiedRegionSet.isEmpty() - && m_markedRegionSet.isEmpty() - && m_fourKBBlockRegionSet.isEmpty() - && m_workListRegionSet.isEmpty(); -} - -void BlockAllocator::releaseFreeRegions() -{ - while (true) { - Region* region; - { - SpinLockHolder locker(&m_regionLock); - if (!m_numberOfEmptyRegions) - region = 0; - else { - region = m_emptyRegions.removeHead(); - RELEASE_ASSERT(region); - m_numberOfEmptyRegions--; - } - } - - if (!region) - break; - - region->destroy(); - } -} - -void BlockAllocator::waitForDuration(std::chrono::milliseconds duration) -{ - std::unique_lock<std::mutex> lock(m_emptyRegionConditionMutex); - - // If this returns early, that's fine, so long as it doesn't do it too - // frequently. It would only be a bug if this function failed to return - // when it was asked to do so. - if (m_blockFreeingThreadShouldQuit) - return; - - m_emptyRegionCondition.wait_for(lock, duration); -} - -void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator) -{ - static_cast<BlockAllocator*>(blockAllocator)->blockFreeingThreadMain(); -} - -void BlockAllocator::blockFreeingThreadMain() -{ - size_t currentNumberOfEmptyRegions; - while (!m_blockFreeingThreadShouldQuit) { - // Generally wait for one second before scavenging free blocks. This - // may return early, particularly when we're being asked to quit. - waitForDuration(std::chrono::seconds(1)); - if (m_blockFreeingThreadShouldQuit) - break; - - if (m_isCurrentlyAllocating) { - m_isCurrentlyAllocating = false; - continue; - } - - // Sleep until there is actually work to do rather than waking up every second to check. - { - std::unique_lock<std::mutex> lock(m_emptyRegionConditionMutex); - SpinLockHolder regionLocker(&m_regionLock); - while (!m_numberOfEmptyRegions && !m_blockFreeingThreadShouldQuit) { - m_regionLock.Unlock(); - m_emptyRegionCondition.wait(lock); - m_regionLock.Lock(); - } - currentNumberOfEmptyRegions = m_numberOfEmptyRegions; - } - - size_t desiredNumberOfEmptyRegions = currentNumberOfEmptyRegions / 2; - - while (!m_blockFreeingThreadShouldQuit) { - Region* region; - { - SpinLockHolder locker(&m_regionLock); - if (m_numberOfEmptyRegions <= desiredNumberOfEmptyRegions) - region = 0; - else { - region = m_emptyRegions.removeHead(); - RELEASE_ASSERT(region); - m_numberOfEmptyRegions--; - } - } - - if (!region) - break; - - region->destroy(); - } - } -} - -} // namespace JSC diff --git a/heap/BlockAllocator.h b/heap/BlockAllocator.h deleted file mode 100644 index eb6867f..0000000 --- a/heap/BlockAllocator.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef BlockAllocator_h -#define BlockAllocator_h - -#include "GCActivityCallback.h" -#include "HeapBlock.h" -#include "Region.h" -#include <condition_variable> -#include <wtf/DoublyLinkedList.h> -#include <wtf/Forward.h> -#include <wtf/PageAllocationAligned.h> -#include <wtf/TCSpinLock.h> -#include <wtf/Threading.h> - -namespace JSC { - -class BlockAllocator; -class CodeBlock; -class CopiedBlock; -class CopyWorkListSegment; -template <typename T> class GCArraySegment; -class HandleBlock; -class JSCell; -class VM; -class MarkedBlock; -class WeakBlock; - -// Simple allocator to reduce VM cost by holding onto blocks of memory for -// short periods of time and then freeing them on a secondary thread. - -class BlockAllocator { -public: - BlockAllocator(); - ~BlockAllocator(); - - template <typename T> DeadBlock* allocate(); - DeadBlock* allocateCustomSize(size_t blockSize, size_t blockAlignment); - template <typename T> void deallocate(T*); - template <typename T> void deallocateCustomSize(T*); - - JS_EXPORT_PRIVATE void releaseFreeRegions(); - -private: - void waitForDuration(std::chrono::milliseconds); - - friend ThreadIdentifier createBlockFreeingThread(BlockAllocator*); - void blockFreeingThreadMain(); - static void blockFreeingThreadStartFunc(void* heap); - - struct RegionSet { - RegionSet(size_t blockSize) - : m_numberOfPartialRegions(0) - , m_blockSize(blockSize) - { - } - - bool isEmpty() const - { - return m_fullRegions.isEmpty() && m_partialRegions.isEmpty(); - } - - DoublyLinkedList<Region> m_fullRegions; - DoublyLinkedList<Region> m_partialRegions; - size_t m_numberOfPartialRegions; - size_t m_blockSize; - }; - - DeadBlock* tryAllocateFromRegion(RegionSet&, DoublyLinkedList<Region>&, size_t&); - - bool allRegionSetsAreEmpty() const; - - template <typename T> RegionSet& regionSetFor(); - - SuperRegion m_superRegion; - RegionSet m_copiedRegionSet; - RegionSet m_markedRegionSet; - // WeakBlocks and GCArraySegments use the same RegionSet since they're the same size. - RegionSet m_fourKBBlockRegionSet; - RegionSet m_workListRegionSet; - - DoublyLinkedList<Region> m_emptyRegions; - size_t m_numberOfEmptyRegions; - - bool m_isCurrentlyAllocating; - bool m_blockFreeingThreadShouldQuit; - SpinLock m_regionLock; - std::mutex m_emptyRegionConditionMutex; - std::condition_variable m_emptyRegionCondition; - ThreadIdentifier m_blockFreeingThread; -}; - -inline DeadBlock* BlockAllocator::tryAllocateFromRegion(RegionSet& set, DoublyLinkedList<Region>& regions, size_t& numberOfRegions) -{ - if (numberOfRegions) { - ASSERT(!regions.isEmpty()); - Region* region = regions.head(); - ASSERT(!region->isFull()); - - if (region->isEmpty()) { - ASSERT(region == m_emptyRegions.head()); - m_numberOfEmptyRegions--; - set.m_numberOfPartialRegions++; - region = m_emptyRegions.removeHead()->reset(set.m_blockSize); - set.m_partialRegions.push(region); - } - - DeadBlock* block = region->allocate(); - - if (region->isFull()) { - set.m_numberOfPartialRegions--; - set.m_fullRegions.push(set.m_partialRegions.removeHead()); - } - - return block; - } - return 0; -} - -template<typename T> -inline DeadBlock* BlockAllocator::allocate() -{ - RegionSet& set = regionSetFor<T>(); - DeadBlock* block; - m_isCurrentlyAllocating = true; - { - SpinLockHolder locker(&m_regionLock); - if ((block = tryAllocateFromRegion(set, set.m_partialRegions, set.m_numberOfPartialRegions))) - return block; - if ((block = tryAllocateFromRegion(set, m_emptyRegions, m_numberOfEmptyRegions))) - return block; - } - - Region* newRegion = Region::create(&m_superRegion, T::blockSize); - - SpinLockHolder locker(&m_regionLock); - m_emptyRegions.push(newRegion); - m_numberOfEmptyRegions++; - block = tryAllocateFromRegion(set, m_emptyRegions, m_numberOfEmptyRegions); - ASSERT(block); - return block; -} - -inline DeadBlock* BlockAllocator::allocateCustomSize(size_t blockSize, size_t blockAlignment) -{ - size_t realSize = WTF::roundUpToMultipleOf(blockAlignment, blockSize); - Region* newRegion = Region::createCustomSize(&m_superRegion, realSize, blockAlignment); - DeadBlock* block = newRegion->allocate(); - ASSERT(block); - return block; -} - -template<typename T> -inline void BlockAllocator::deallocate(T* block) -{ - RegionSet& set = regionSetFor<T>(); - bool shouldWakeBlockFreeingThread = false; - { - SpinLockHolder locker(&m_regionLock); - Region* region = block->region(); - ASSERT(!region->isEmpty()); - if (region->isFull()) - set.m_fullRegions.remove(region); - else { - set.m_partialRegions.remove(region); - set.m_numberOfPartialRegions--; - } - - region->deallocate(block); - - if (region->isEmpty()) { - m_emptyRegions.push(region); - shouldWakeBlockFreeingThread = !m_numberOfEmptyRegions; - m_numberOfEmptyRegions++; - } else { - set.m_partialRegions.push(region); - set.m_numberOfPartialRegions++; - } - } - - if (shouldWakeBlockFreeingThread) { - std::lock_guard<std::mutex> lock(m_emptyRegionConditionMutex); - m_emptyRegionCondition.notify_one(); - } - - if (!m_blockFreeingThread) - releaseFreeRegions(); -} - -template<typename T> -inline void BlockAllocator::deallocateCustomSize(T* block) -{ - Region* region = block->region(); - ASSERT(region->isCustomSize()); - region->deallocate(block); - region->destroy(); -} - -#define REGION_SET_FOR(blockType, set) \ - template <> \ - inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<blockType>() \ - { \ - return set; \ - } \ - template <> \ - inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor<HeapBlock<blockType>>() \ - { \ - return set; \ - } \ - -REGION_SET_FOR(MarkedBlock, m_markedRegionSet); -REGION_SET_FOR(CopiedBlock, m_copiedRegionSet); -REGION_SET_FOR(WeakBlock, m_fourKBBlockRegionSet); -REGION_SET_FOR(GCArraySegment<const JSCell*>, m_fourKBBlockRegionSet); -REGION_SET_FOR(GCArraySegment<CodeBlock*>, m_fourKBBlockRegionSet); -REGION_SET_FOR(CopyWorkListSegment, m_workListRegionSet); -REGION_SET_FOR(HandleBlock, m_fourKBBlockRegionSet); - -#undef REGION_SET_FOR - -template <typename T> -inline BlockAllocator::RegionSet& BlockAllocator::regionSetFor() -{ - RELEASE_ASSERT_NOT_REACHED(); - return *(RegionSet*)0; -} - -} // namespace JSC - -#endif // BlockAllocator_h diff --git a/heap/CodeBlockSet.cpp b/heap/CodeBlockSet.cpp index 2a818f0..9cfce4f 100644 --- a/heap/CodeBlockSet.cpp +++ b/heap/CodeBlockSet.cpp @@ -35,8 +35,7 @@ namespace JSC { static const bool verbose = false; -CodeBlockSet::CodeBlockSet(BlockAllocator& blockAllocator) - : m_currentlyExecuting(blockAllocator) +CodeBlockSet::CodeBlockSet() { } @@ -66,7 +65,7 @@ void CodeBlockSet::clearMarksForFullCollection() { for (CodeBlock* codeBlock : m_oldCodeBlocks) { codeBlock->m_mayBeExecuting = false; - codeBlock->m_visitAggregateHasBeenCalled = false; + codeBlock->m_visitAggregateHasBeenCalled.store(false, std::memory_order_relaxed); } // We promote after we clear marks on the old generation CodeBlocks because @@ -83,7 +82,7 @@ void CodeBlockSet::clearMarksForEdenCollection(const Vector<const JSCell*>& reme continue; executable->forEachCodeBlock([](CodeBlock* codeBlock) { codeBlock->m_mayBeExecuting = false; - codeBlock->m_visitAggregateHasBeenCalled = false; + codeBlock->m_visitAggregateHasBeenCalled.store(false, std::memory_order_relaxed); }); } } diff --git a/heap/CodeBlockSet.h b/heap/CodeBlockSet.h index e00cefe..6cab875 100644 --- a/heap/CodeBlockSet.h +++ b/heap/CodeBlockSet.h @@ -36,7 +36,6 @@ namespace JSC { -class BlockAllocator; class CodeBlock; class Heap; class JSCell; @@ -50,7 +49,7 @@ class CodeBlockSet { WTF_MAKE_NONCOPYABLE(CodeBlockSet); public: - CodeBlockSet(BlockAllocator&); + CodeBlockSet(); ~CodeBlockSet(); // Add a CodeBlock. This is only called by CodeBlock constructors. @@ -110,7 +109,7 @@ private: // and all, but that seemed like overkill. HashSet<CodeBlock*> m_oldCodeBlocks; HashSet<CodeBlock*> m_newCodeBlocks; - GCSegmentedArray<CodeBlock*> m_currentlyExecuting; + Vector<CodeBlock*> m_currentlyExecuting; }; } // namespace JSC diff --git a/heap/CopiedBlock.h b/heap/CopiedBlock.h index 4685e23..f636529 100644 --- a/heap/CopiedBlock.h +++ b/heap/CopiedBlock.h @@ -26,25 +26,25 @@ #ifndef CopiedBlock_h #define CopiedBlock_h -#include "BlockAllocator.h" #include "CopyWorkList.h" -#include "HeapBlock.h" #include "JSCJSValue.h" #include "Options.h" #include <wtf/Atomics.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> +#include <wtf/DoublyLinkedList.h> +#include <wtf/SpinLock.h> namespace JSC { class CopiedSpace; -class CopiedBlock : public HeapBlock<CopiedBlock> { +class CopiedBlock : public DoublyLinkedListNode<CopiedBlock> { + friend class WTF::DoublyLinkedListNode<CopiedBlock>; friend class CopiedSpace; friend class CopiedAllocator; public: - static CopiedBlock* create(DeadBlock*); - static CopiedBlock* createNoZeroFill(DeadBlock*); + static CopiedBlock* create(size_t = blockSize); + static CopiedBlock* createNoZeroFill(size_t = blockSize); + static void destroy(CopiedBlock*); void pin(); bool isPinned(); @@ -88,13 +88,18 @@ public: SpinLock& workListLock() { return m_workListLock; } private: - CopiedBlock(Region*); + CopiedBlock(size_t); void zeroFillWilderness(); // Can be called at any time to zero-fill to the end of the block. void checkConsistency(); + CopiedBlock* m_prev; + CopiedBlock* m_next; + + size_t m_capacity; + SpinLock m_workListLock; - OwnPtr<CopyWorkList> m_workList; + std::unique_ptr<CopyWorkList> m_workList; size_t m_remaining; bool m_isPinned : 1; @@ -105,15 +110,20 @@ private: #endif }; -inline CopiedBlock* CopiedBlock::createNoZeroFill(DeadBlock* block) +inline CopiedBlock* CopiedBlock::createNoZeroFill(size_t capacity) +{ + return new(NotNull, fastAlignedMalloc(CopiedBlock::blockSize, capacity)) CopiedBlock(capacity); +} + +inline void CopiedBlock::destroy(CopiedBlock* copiedBlock) { - Region* region = block->region(); - return new(NotNull, block) CopiedBlock(region); + copiedBlock->~CopiedBlock(); + fastAlignedFree(copiedBlock); } -inline CopiedBlock* CopiedBlock::create(DeadBlock* block) +inline CopiedBlock* CopiedBlock::create(size_t capacity) { - CopiedBlock* newBlock = createNoZeroFill(block); + CopiedBlock* newBlock = createNoZeroFill(capacity); newBlock->zeroFillWilderness(); return newBlock; } @@ -130,8 +140,9 @@ inline void CopiedBlock::zeroFillWilderness() #endif } -inline CopiedBlock::CopiedBlock(Region* region) - : HeapBlock<CopiedBlock>(region) +inline CopiedBlock::CopiedBlock(size_t capacity) + : DoublyLinkedListNode<CopiedBlock>() + , m_capacity(capacity) , m_remaining(payloadCapacity()) , m_isPinned(false) , m_isOld(false) @@ -140,7 +151,6 @@ inline CopiedBlock::CopiedBlock(Region* region) , m_liveObjects(0) #endif { - m_workListLock.Init(); ASSERT(is8ByteAligned(reinterpret_cast<void*>(m_remaining))); } @@ -154,7 +164,7 @@ inline void CopiedBlock::didSurviveGC() #endif m_isPinned = false; if (m_workList) - m_workList.clear(); + m_workList = nullptr; } inline void CopiedBlock::didEvacuateBytes(unsigned bytes) @@ -185,7 +195,7 @@ inline void CopiedBlock::pin() { m_isPinned = true; if (m_workList) - m_workList.clear(); + m_workList = nullptr; } inline bool CopiedBlock::isPinned() @@ -205,7 +215,7 @@ inline void CopiedBlock::didPromote() inline bool CopiedBlock::isOversize() { - return region()->isCustomSize(); + return m_capacity != blockSize; } inline unsigned CopiedBlock::liveBytes() @@ -216,12 +226,12 @@ inline unsigned CopiedBlock::liveBytes() inline char* CopiedBlock::payload() { - return reinterpret_cast<char*>(this) + ((sizeof(CopiedBlock) + 7) & ~7); + return reinterpret_cast<char*>(this) + WTF::roundUpToMultipleOf<sizeof(double)>(sizeof(CopiedBlock)); } inline char* CopiedBlock::payloadEnd() { - return reinterpret_cast<char*>(this) + region()->blockSize(); + return reinterpret_cast<char*>(this) + m_capacity; } inline size_t CopiedBlock::payloadCapacity() @@ -266,7 +276,7 @@ inline size_t CopiedBlock::size() inline size_t CopiedBlock::capacity() { - return region()->blockSize(); + return m_capacity; } inline bool CopiedBlock::hasWorkList() diff --git a/heap/CopiedBlockInlines.h b/heap/CopiedBlockInlines.h index 256f7a6..2db0cd1 100644 --- a/heap/CopiedBlockInlines.h +++ b/heap/CopiedBlockInlines.h @@ -51,7 +51,7 @@ inline void CopiedBlock::reportLiveBytes(SpinLockHolder&, JSCell* owner, CopyTok #endif m_liveBytes += bytes; checkConsistency(); - ASSERT(m_liveBytes <= CopiedBlock::blockSize); + ASSERT(m_liveBytes <= m_capacity); if (isPinned()) return; @@ -62,7 +62,7 @@ inline void CopiedBlock::reportLiveBytes(SpinLockHolder&, JSCell* owner, CopyTok } if (!m_workList) - m_workList = adoptPtr(new CopyWorkList(Heap::heap(owner)->blockAllocator())); + m_workList = std::make_unique<CopyWorkList>(); m_workList->append(CopyWorklistItem(owner, token)); } diff --git a/heap/CopiedSpace.cpp b/heap/CopiedSpace.cpp index cb1a656..9592eaa 100644 --- a/heap/CopiedSpace.cpp +++ b/heap/CopiedSpace.cpp @@ -38,29 +38,29 @@ CopiedSpace::CopiedSpace(Heap* heap) , m_inCopyingPhase(false) , m_shouldDoCopyPhase(false) , m_numberOfLoanedBlocks(0) + , m_bytesRemovedFromOldSpaceDueToReallocation(0) { - m_toSpaceLock.Init(); } CopiedSpace::~CopiedSpace() { while (!m_oldGen.toSpace->isEmpty()) - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.toSpace->removeHead())); + CopiedBlock::destroy(m_oldGen.toSpace->removeHead()); while (!m_oldGen.fromSpace->isEmpty()) - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.fromSpace->removeHead())); + CopiedBlock::destroy(m_oldGen.fromSpace->removeHead()); while (!m_oldGen.oversizeBlocks.isEmpty()) - m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_oldGen.oversizeBlocks.removeHead())); + CopiedBlock::destroy(m_oldGen.oversizeBlocks.removeHead()); while (!m_newGen.toSpace->isEmpty()) - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.toSpace->removeHead())); + CopiedBlock::destroy(m_newGen.toSpace->removeHead()); while (!m_newGen.fromSpace->isEmpty()) - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.fromSpace->removeHead())); + CopiedBlock::destroy(m_newGen.fromSpace->removeHead()); while (!m_newGen.oversizeBlocks.isEmpty()) - m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_newGen.oversizeBlocks.removeHead())); + CopiedBlock::destroy(m_newGen.oversizeBlocks.removeHead()); ASSERT(m_oldGen.toSpace->isEmpty()); ASSERT(m_oldGen.fromSpace->isEmpty()); @@ -99,7 +99,7 @@ CheckedBoolean CopiedSpace::tryAllocateOversize(size_t bytes, void** outPtr) { ASSERT(isOversize(bytes)); - CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocateCustomSize(sizeof(CopiedBlock) + bytes, CopiedBlock::blockSize)); + CopiedBlock* block = CopiedBlock::create(WTF::roundUpToMultipleOf<sizeof(double)>(sizeof(CopiedBlock) + bytes)); m_newGen.oversizeBlocks.push(block); m_newGen.blockFilter.add(reinterpret_cast<Bits>(block)); m_blockSet.add(block); @@ -110,7 +110,7 @@ CheckedBoolean CopiedSpace::tryAllocateOversize(size_t bytes, void** outPtr) *outPtr = allocator.forceAllocate(bytes); allocator.resetCurrentBlock(); - m_heap->didAllocate(block->region()->blockSize()); + m_heap->didAllocate(block->capacity()); return true; } @@ -156,12 +156,16 @@ CheckedBoolean CopiedSpace::tryReallocateOversize(void** ptr, size_t oldSize, si CopiedBlock* oldBlock = CopiedSpace::blockFor(oldPtr); if (oldBlock->isOversize()) { - if (oldBlock->isOld()) + // FIXME: Eagerly deallocating the old space block probably buys more confusion than + // value. + // https://bugs.webkit.org/show_bug.cgi?id=144750 + if (oldBlock->isOld()) { + m_bytesRemovedFromOldSpaceDueToReallocation += oldBlock->size(); m_oldGen.oversizeBlocks.remove(oldBlock); - else + } else m_newGen.oversizeBlocks.remove(oldBlock); m_blockSet.remove(oldBlock); - m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(oldBlock)); + CopiedBlock::destroy(oldBlock); } *ptr = newPtr; diff --git a/heap/CopiedSpace.h b/heap/CopiedSpace.h index c0a59a2..db1be18 100644 --- a/heap/CopiedSpace.h +++ b/heap/CopiedSpace.h @@ -27,7 +27,6 @@ #define CopiedSpace_h #include "CopiedAllocator.h" -#include "HeapBlock.h" #include "HeapOperation.h" #include "TinyBloomFilter.h" #include <wtf/Assertions.h> @@ -35,10 +34,9 @@ #include <wtf/DoublyLinkedList.h> #include <wtf/HashSet.h> #include <wtf/OSAllocator.h> -#include <wtf/PageAllocationAligned.h> #include <wtf/PageBlock.h> +#include <wtf/SpinLock.h> #include <wtf/StdLibExtras.h> -#include <wtf/TCSpinLock.h> #include <wtf/ThreadingPrimitives.h> namespace JSC { @@ -87,6 +85,13 @@ public: static CopiedBlock* blockFor(void*); Heap* heap() const { return m_heap; } + + size_t takeBytesRemovedFromOldSpaceDueToReallocation() + { + size_t result = 0; + std::swap(m_bytesRemovedFromOldSpaceDueToReallocation, result); + return result; + } private: static bool isOversize(size_t); @@ -136,6 +141,8 @@ private: Mutex m_loanedBlocksLock; ThreadCondition m_loanedBlocksCondition; size_t m_numberOfLoanedBlocks; + + size_t m_bytesRemovedFromOldSpaceDueToReallocation; static const size_t s_maxAllocationSize = CopiedBlock::blockSize / 2; static const size_t s_initialBlockNum = 16; diff --git a/heap/CopiedSpaceInlines.h b/heap/CopiedSpaceInlines.h index ec33f58..3faf342 100644 --- a/heap/CopiedSpaceInlines.h +++ b/heap/CopiedSpaceInlines.h @@ -29,7 +29,6 @@ #include "CopiedBlock.h" #include "CopiedSpace.h" #include "Heap.h" -#include "HeapBlock.h" #include "VM.h" #include <wtf/CheckedBoolean.h> @@ -106,12 +105,12 @@ inline void CopiedSpace::recycleEvacuatedBlock(CopiedBlock* block, HeapOperation else m_oldGen.fromSpace->remove(block); } - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); + CopiedBlock::destroy(block); } inline void CopiedSpace::recycleBorrowedBlock(CopiedBlock* block) { - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); + CopiedBlock::destroy(block); { MutexLocker locker(m_loanedBlocksLock); @@ -126,7 +125,7 @@ inline void CopiedSpace::recycleBorrowedBlock(CopiedBlock* block) inline CopiedBlock* CopiedSpace::allocateBlockForCopyingPhase() { ASSERT(m_inCopyingPhase); - CopiedBlock* block = CopiedBlock::createNoZeroFill(m_heap->blockAllocator().allocate<CopiedBlock>()); + CopiedBlock* block = CopiedBlock::createNoZeroFill(); { MutexLocker locker(m_loanedBlocksLock); @@ -143,7 +142,7 @@ inline void CopiedSpace::allocateBlock() m_allocator.resetCurrentBlock(); - CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocate<CopiedBlock>()); + CopiedBlock* block = CopiedBlock::create(); m_newGen.toSpace->push(block); m_newGen.blockFilter.add(reinterpret_cast<Bits>(block)); @@ -235,7 +234,7 @@ inline void CopiedSpace::startedCopying() } else { oversizeBlocks->remove(block); m_blockSet.remove(block); - m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(block)); + CopiedBlock::destroy(block); } block = next; } diff --git a/heap/CopyToken.h b/heap/CopyToken.h index bba5e91..5aceb5b 100644 --- a/heap/CopyToken.h +++ b/heap/CopyToken.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,8 +32,7 @@ enum CopyToken { ButterflyCopyToken, TypedArrayVectorCopyToken, MapBackingStoreCopyToken, - ArgumentsRegisterArrayCopyToken, - ArgumentsSlowArgumentDataCopyToken + DirectArgumentsOverridesCopyToken }; } // namespace JSC diff --git a/heap/CopyWorkList.h b/heap/CopyWorkList.h index 76f1c3d..8308667 100644 --- a/heap/CopyWorkList.h +++ b/heap/CopyWorkList.h @@ -27,6 +27,7 @@ #define CopyWorkList_h #include "CopyToken.h" +#include <wtf/DoublyLinkedList.h> #include <wtf/Vector.h> namespace JSC { @@ -57,11 +58,18 @@ private: uintptr_t m_value; }; -class CopyWorkListSegment : public HeapBlock<CopyWorkListSegment> { +class CopyWorkListSegment : public DoublyLinkedListNode<CopyWorkListSegment> { + friend class WTF::DoublyLinkedListNode<CopyWorkListSegment>; public: - static CopyWorkListSegment* create(DeadBlock* block) + static CopyWorkListSegment* create() { - return new (NotNull, block) CopyWorkListSegment(block->region()); + return new (NotNull, fastMalloc(blockSize)) CopyWorkListSegment(); + } + + static void destroy(CopyWorkListSegment* segment) + { + segment->~CopyWorkListSegment(); + fastFree(segment); } size_t size() { return m_size; } @@ -78,8 +86,8 @@ public: static const size_t blockSize = 512; private: - CopyWorkListSegment(Region* region) - : HeapBlock<CopyWorkListSegment>(region) + CopyWorkListSegment() + : DoublyLinkedListNode<CopyWorkListSegment>() , m_size(0) { } @@ -87,6 +95,8 @@ private: CopyWorklistItem* data() { return reinterpret_cast<CopyWorklistItem*>(this + 1); } char* endOfBlock() { return reinterpret_cast<char*>(this) + blockSize; } + CopyWorkListSegment* m_prev; + CopyWorkListSegment* m_next; size_t m_size; }; @@ -143,7 +153,7 @@ class CopyWorkList { public: typedef CopyWorkListIterator iterator; - CopyWorkList(BlockAllocator&); + CopyWorkList(); ~CopyWorkList(); void append(CopyWorklistItem); @@ -152,24 +162,22 @@ public: private: DoublyLinkedList<CopyWorkListSegment> m_segments; - BlockAllocator& m_blockAllocator; }; -inline CopyWorkList::CopyWorkList(BlockAllocator& blockAllocator) - : m_blockAllocator(blockAllocator) +inline CopyWorkList::CopyWorkList() { } inline CopyWorkList::~CopyWorkList() { while (!m_segments.isEmpty()) - m_blockAllocator.deallocate(CopyWorkListSegment::destroy(m_segments.removeHead())); + CopyWorkListSegment::destroy(m_segments.removeHead()); } inline void CopyWorkList::append(CopyWorklistItem item) { if (m_segments.isEmpty() || m_segments.tail()->isFull()) - m_segments.append(CopyWorkListSegment::create(m_blockAllocator.allocate<CopyWorkListSegment>())); + m_segments.append(CopyWorkListSegment::create()); ASSERT(!m_segments.tail()->isFull()); diff --git a/heap/CopyWriteBarrier.h b/heap/CopyWriteBarrier.h index eeef1d7..b014fcd 100644 --- a/heap/CopyWriteBarrier.h +++ b/heap/CopyWriteBarrier.h @@ -50,8 +50,7 @@ public: bool operator!() const { return !m_value; } - typedef T* (CopyWriteBarrier::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const { return m_value ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } + explicit operator bool() const { return m_value; } T* get() const { diff --git a/heap/DelayedReleaseScope.h b/heap/DelayedReleaseScope.h deleted file mode 100644 index 883c661..0000000 --- a/heap/DelayedReleaseScope.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DelayedReleaseScope_h -#define DelayedReleaseScope_h - -#include "Heap.h" -#include "JSLock.h" -#include "MarkedSpace.h" - -namespace JSC { - -#if USE(CF) - -class DelayedReleaseScope { -public: - DelayedReleaseScope(MarkedSpace& markedSpace) - : m_markedSpace(markedSpace) - { - ASSERT(!m_markedSpace.m_currentDelayedReleaseScope); - m_markedSpace.m_currentDelayedReleaseScope = this; - } - - ~DelayedReleaseScope() - { - ASSERT(m_markedSpace.m_currentDelayedReleaseScope == this); - m_markedSpace.m_currentDelayedReleaseScope = nullptr; - - HeapOperation operationInProgress = NoOperation; - std::swap(operationInProgress, m_markedSpace.m_heap->m_operationInProgress); - - { - JSLock::DropAllLocks dropAllLocks(*m_markedSpace.m_heap->vm()); - m_delayedReleaseObjects.clear(); - } - - std::swap(operationInProgress, m_markedSpace.m_heap->m_operationInProgress); - } - - template <typename T> - void releaseSoon(RetainPtr<T>&& object) - { - m_delayedReleaseObjects.append(WTF::move(object)); - } - - static bool isInEffectFor(MarkedSpace& markedSpace) - { - return markedSpace.m_currentDelayedReleaseScope; - } - -private: - MarkedSpace& m_markedSpace; - Vector<RetainPtr<CFTypeRef>> m_delayedReleaseObjects; -}; - -template <typename T> -inline void MarkedSpace::releaseSoon(RetainPtr<T>&& object) -{ - ASSERT(m_currentDelayedReleaseScope); - m_currentDelayedReleaseScope->releaseSoon(WTF::move(object)); -} - -#else // USE(CF) - -class DelayedReleaseScope { -public: - DelayedReleaseScope(MarkedSpace&) - { - } - - static bool isInEffectFor(MarkedSpace&) - { - return true; - } -}; - -#endif // USE(CF) - -} // namespace JSC - -#endif // DelayedReleaseScope_h diff --git a/heap/EdenGCActivityCallback.h b/heap/EdenGCActivityCallback.h index 28cfddb..214ab43 100644 --- a/heap/EdenGCActivityCallback.h +++ b/heap/EdenGCActivityCallback.h @@ -49,7 +49,7 @@ protected: virtual double deathRate() override; }; -inline PassRefPtr<GCActivityCallback> GCActivityCallback::createEdenTimer(Heap* heap) +inline RefPtr<GCActivityCallback> GCActivityCallback::createEdenTimer(Heap* heap) { return s_shouldCreateGCTimer ? adoptRef(new EdenGCActivityCallback(heap)) : nullptr; } diff --git a/heap/FullGCActivityCallback.cpp b/heap/FullGCActivityCallback.cpp index 76c678d..07ebbbd 100644 --- a/heap/FullGCActivityCallback.cpp +++ b/heap/FullGCActivityCallback.cpp @@ -43,18 +43,19 @@ FullGCActivityCallback::FullGCActivityCallback(Heap* heap) void FullGCActivityCallback::doCollection() { - Heap* heap = &m_vm->heap; + Heap& heap = m_vm->heap; + m_didSyncGCRecently = false; #if !PLATFORM(IOS) double startTime = WTF::monotonicallyIncreasingTime(); - if (heap->isPagedOut(startTime + pagingTimeOut)) { + if (heap.isPagedOut(startTime + pagingTimeOut)) { cancel(); - heap->increaseLastFullGCLength(pagingTimeOut); + heap.increaseLastFullGCLength(pagingTimeOut); return; } #endif - heap->collect(FullCollection); + heap.collect(FullCollection); } double FullGCActivityCallback::lastGCLength() diff --git a/heap/FullGCActivityCallback.h b/heap/FullGCActivityCallback.h index 88cebd9..e727592 100644 --- a/heap/FullGCActivityCallback.h +++ b/heap/FullGCActivityCallback.h @@ -36,6 +36,9 @@ public: virtual void doCollection() override; + bool didSyncGCRecently() const { return m_didSyncGCRecently; } + void setDidSyncGCRecently() { m_didSyncGCRecently = true; } + protected: #if USE(CF) FullGCActivityCallback(Heap* heap, CFRunLoopRef runLoop) @@ -47,9 +50,11 @@ protected: virtual double lastGCLength() override; virtual double gcTimeSlice(size_t bytes) override; virtual double deathRate() override; + + bool m_didSyncGCRecently { false }; }; -inline PassRefPtr<GCActivityCallback> GCActivityCallback::createFullTimer(Heap* heap) +inline RefPtr<FullGCActivityCallback> GCActivityCallback::createFullTimer(Heap* heap) { return s_shouldCreateGCTimer ? adoptRef(new FullGCActivityCallback(heap)) : nullptr; } diff --git a/heap/GCActivityCallback.h b/heap/GCActivityCallback.h index 8d802aa..73d0e89 100644 --- a/heap/GCActivityCallback.h +++ b/heap/GCActivityCallback.h @@ -30,8 +30,7 @@ #define GCActivityCallback_h #include "HeapTimer.h" -#include <wtf/OwnPtr.h> -#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> #if USE(CF) #include <CoreFoundation/CoreFoundation.h> @@ -39,13 +38,14 @@ namespace JSC { +class FullGCActivityCallback; class Heap; class JS_EXPORT_PRIVATE GCActivityCallback : public HeapTimer, public ThreadSafeRefCounted<GCActivityCallback> { WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<GCActivityCallback> createFullTimer(Heap*); - static PassRefPtr<GCActivityCallback> createEdenTimer(Heap*); + static RefPtr<FullGCActivityCallback> createFullTimer(Heap*); + static RefPtr<GCActivityCallback> createEdenTimer(Heap*); GCActivityCallback(Heap*); diff --git a/heap/GCLogging.cpp b/heap/GCLogging.cpp index 4c16a33..b8ed121 100644 --- a/heap/GCLogging.cpp +++ b/heap/GCLogging.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 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 @@ #include "HeapIterationScope.h" #include "JSCell.h" #include "JSCellInlines.h" +#include <wtf/PrintStream.h> namespace JSC { @@ -63,10 +64,11 @@ public: reviveCells(); } - void operator()(JSCell* cell) + IterationStatus operator()(JSCell* cell) { m_liveCells.append(cell); MarkedBlock::blockFor(cell)->clearMarked(cell); + return IterationStatus::Continue; } void log() @@ -112,3 +114,26 @@ void GCLogging::dumpObjectGraph(Heap* heap) } } // namespace JSC + +namespace WTF { + +void printInternal(PrintStream& out, JSC::GCLogging::Level level) +{ + switch (level) { + case JSC::GCLogging::Level::None: + out.print("None"); + return; + case JSC::GCLogging::Level::Basic: + out.print("Basic"); + return; + case JSC::GCLogging::Level::Verbose: + out.print("Verbose"); + return; + default: + out.print("Level=", level - JSC::GCLogging::Level::None); + return; + } +} + +} // namespace WTF + diff --git a/heap/GCLogging.h b/heap/GCLogging.h index 7773075..650d3fc 100644 --- a/heap/GCLogging.h +++ b/heap/GCLogging.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,4 +48,12 @@ typedef GCLogging::Level gcLogLevel; } // namespace JSC +namespace WTF { + +class PrintStream; + +void printInternal(PrintStream&, JSC::GCLogging::Level); + +} // namespace WTF + #endif // GCLogging_h diff --git a/heap/GCSegmentedArray.h b/heap/GCSegmentedArray.h index 8faf16b..8aeba10 100644 --- a/heap/GCSegmentedArray.h +++ b/heap/GCSegmentedArray.h @@ -26,26 +26,25 @@ #ifndef GCSegmentedArray_h #define GCSegmentedArray_h -#include "HeapBlock.h" +#include <wtf/DoublyLinkedList.h> #include <wtf/Vector.h> namespace JSC { -class BlockAllocator; -class DeadBlock; - template <typename T> -class GCArraySegment : public HeapBlock<GCArraySegment<T>> { +class GCArraySegment : public DoublyLinkedListNode<GCArraySegment<T>> { + friend class WTF::DoublyLinkedListNode<GCArraySegment<T>>; public: - GCArraySegment(Region* region) - : HeapBlock<GCArraySegment>(region) + GCArraySegment() + : DoublyLinkedListNode<GCArraySegment<T>>() #if !ASSERT_DISABLED , m_top(0) #endif { } - static GCArraySegment* create(DeadBlock*); + static GCArraySegment* create(); + static void destroy(GCArraySegment*); T* data() { @@ -54,6 +53,8 @@ public: static const size_t blockSize = 4 * KB; + GCArraySegment* m_prev; + GCArraySegment* m_next; #if !ASSERT_DISABLED size_t m_top; #endif @@ -66,7 +67,7 @@ class GCSegmentedArray { friend class GCSegmentedArrayIterator<T>; friend class GCSegmentedArrayIterator<const T>; public: - GCSegmentedArray(BlockAllocator&); + GCSegmentedArray(); ~GCSegmentedArray(); void append(T); @@ -101,7 +102,6 @@ protected: void validatePrevious(); DoublyLinkedList<GCArraySegment<T>> m_segments; - BlockAllocator& m_blockAllocator; JS_EXPORT_PRIVATE static const size_t s_segmentCapacity = CapacityFromSize<GCArraySegment<T>::blockSize>::value; size_t m_top; diff --git a/heap/GCSegmentedArrayInlines.h b/heap/GCSegmentedArrayInlines.h index e2eff4d..88e43cc 100644 --- a/heap/GCSegmentedArrayInlines.h +++ b/heap/GCSegmentedArrayInlines.h @@ -26,18 +26,16 @@ #ifndef GCSegmentedArrayInlines_h #define GCSegmentedArrayInlines_h -#include "BlockAllocator.h" #include "GCSegmentedArray.h" namespace JSC { template <typename T> -GCSegmentedArray<T>::GCSegmentedArray(BlockAllocator& blockAllocator) - : m_blockAllocator(blockAllocator) - , m_top(0) +GCSegmentedArray<T>::GCSegmentedArray() + : m_top(0) , m_numberOfSegments(0) { - m_segments.push(GCArraySegment<T>::create(m_blockAllocator.allocate<GCArraySegment<T>>())); + m_segments.push(GCArraySegment<T>::create()); m_numberOfSegments++; } @@ -46,7 +44,7 @@ GCSegmentedArray<T>::~GCSegmentedArray() { ASSERT(m_numberOfSegments == 1); ASSERT(m_segments.size() == 1); - m_blockAllocator.deallocate(GCArraySegment<T>::destroy(m_segments.removeHead())); + GCArraySegment<T>::destroy(m_segments.removeHead()); m_numberOfSegments--; ASSERT(!m_numberOfSegments); ASSERT(!m_segments.size()); @@ -61,7 +59,7 @@ void GCSegmentedArray<T>::clear() for (GCArraySegment<T>* current = m_segments.head(); current->next(); current = next) { next = current->next(); m_segments.remove(current); - m_blockAllocator.deallocate(GCArraySegment<T>::destroy(current)); + GCArraySegment<T>::destroy(current); } m_top = 0; m_numberOfSegments = 1; @@ -75,7 +73,7 @@ void GCSegmentedArray<T>::expand() { ASSERT(m_segments.head()->m_top == s_segmentCapacity); - GCArraySegment<T>* nextSegment = GCArraySegment<T>::create(m_blockAllocator.allocate<GCArraySegment<T>>()); + GCArraySegment<T>* nextSegment = GCArraySegment<T>::create(); m_numberOfSegments++; #if !ASSERT_DISABLED @@ -93,7 +91,7 @@ bool GCSegmentedArray<T>::refill() validatePrevious(); if (top()) return true; - m_blockAllocator.deallocate(GCArraySegment<T>::destroy(m_segments.removeHead())); + GCArraySegment<T>::destroy(m_segments.removeHead()); ASSERT(m_numberOfSegments > 1); m_numberOfSegments--; setTopForFullSegment(); @@ -127,9 +125,16 @@ void GCSegmentedArray<T>::fillVector(Vector<T>& vector) } template <typename T> -inline GCArraySegment<T>* GCArraySegment<T>::create(DeadBlock* block) +inline GCArraySegment<T>* GCArraySegment<T>::create() { - return new (NotNull, block) GCArraySegment<T>(block->region()); + return new (NotNull, fastMalloc(blockSize)) GCArraySegment<T>(); +} + +template <typename T> +inline void GCArraySegment<T>::destroy(GCArraySegment* segment) +{ + segment->~GCArraySegment(); + fastFree(segment); } template <typename T> diff --git a/heap/GCThread.cpp b/heap/GCThread.cpp index cf496a1..3a3dcea 100644 --- a/heap/GCThread.cpp +++ b/heap/GCThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,15 +32,14 @@ #include "JSCInlines.h" #include "SlotVisitor.h" #include <wtf/MainThread.h> -#include <wtf/PassOwnPtr.h> namespace JSC { -GCThread::GCThread(GCThreadSharedData& shared, SlotVisitor* slotVisitor, CopyVisitor* copyVisitor) +GCThread::GCThread(GCThreadSharedData& shared, std::unique_ptr<SlotVisitor> slotVisitor, std::unique_ptr<CopyVisitor> copyVisitor) : m_threadID(0) , m_shared(shared) - , m_slotVisitor(WTF::adoptPtr(slotVisitor)) - , m_copyVisitor(WTF::adoptPtr(copyVisitor)) + , m_slotVisitor(WTF::move(slotVisitor)) + , m_copyVisitor(WTF::move(copyVisitor)) { } @@ -116,6 +115,9 @@ void GCThread::gcThreadMain() // all of the blocks that the GCThreads borrowed have been returned. doneCopying() // returns our borrowed CopiedBlock, allowing the copying phase to finish. m_copyVisitor->doneCopying(); + + WTF::releaseFastMallocFreeMemoryForThisThread(); + break; case NoPhase: RELEASE_ASSERT_NOT_REACHED(); diff --git a/heap/GCThread.h b/heap/GCThread.h index 0d218f9..b727799 100644 --- a/heap/GCThread.h +++ b/heap/GCThread.h @@ -28,7 +28,6 @@ #include <GCThreadSharedData.h> #include <wtf/Deque.h> -#include <wtf/OwnPtr.h> #include <wtf/Threading.h> namespace JSC { @@ -39,7 +38,7 @@ class SlotVisitor; class GCThread { public: - GCThread(GCThreadSharedData&, SlotVisitor*, CopyVisitor*); + GCThread(GCThreadSharedData&, std::unique_ptr<SlotVisitor>, std::unique_ptr<CopyVisitor>); SlotVisitor* slotVisitor(); CopyVisitor* copyVisitor(); @@ -54,8 +53,8 @@ private: ThreadIdentifier m_threadID; GCThreadSharedData& m_shared; - OwnPtr<SlotVisitor> m_slotVisitor; - OwnPtr<CopyVisitor> m_copyVisitor; + std::unique_ptr<SlotVisitor> m_slotVisitor; + std::unique_ptr<CopyVisitor> m_copyVisitor; }; } // namespace JSC diff --git a/heap/GCThreadSharedData.cpp b/heap/GCThreadSharedData.cpp index 27e59e8..2286370 100644 --- a/heap/GCThreadSharedData.cpp +++ b/heap/GCThreadSharedData.cpp @@ -73,7 +73,7 @@ GCThreadSharedData::GCThreadSharedData(VM* vm) : m_vm(vm) , m_copiedSpace(&vm->heap.m_storageSpace) , m_shouldHashCons(false) - , m_sharedMarkStack(vm->heap.blockAllocator()) + , m_sharedMarkStack() , m_numberOfActiveParallelMarkers(0) , m_parallelMarkersShouldExit(false) , m_copyIndex(0) @@ -81,15 +81,12 @@ GCThreadSharedData::GCThreadSharedData(VM* vm) , m_gcThreadsShouldWait(false) , m_currentPhase(NoPhase) { - m_copyLock.Init(); #if ENABLE(PARALLEL_GC) // Grab the lock so the new GC threads can be properly initialized before they start running. std::unique_lock<std::mutex> lock(m_phaseMutex); for (unsigned i = 1; i < Options::numberOfGCMarkers(); ++i) { m_numberOfActiveGCThreads++; - SlotVisitor* slotVisitor = new SlotVisitor(*this); - CopyVisitor* copyVisitor = new CopyVisitor(*this); - GCThread* newThread = new GCThread(*this, slotVisitor, copyVisitor); + GCThread* newThread = new GCThread(*this, std::make_unique<SlotVisitor>(*this), std::make_unique<CopyVisitor>(*this)); ThreadIdentifier threadID = createThread(GCThread::gcThreadStartFunc, newThread, "JavaScriptCore::Marking"); newThread->initializeThreadID(threadID); m_gcThreads.append(newThread); diff --git a/heap/GCThreadSharedData.h b/heap/GCThreadSharedData.h index 32c06bd..d6c960a 100644 --- a/heap/GCThreadSharedData.h +++ b/heap/GCThreadSharedData.h @@ -33,15 +33,16 @@ #include "WeakReferenceHarvester.h" #include <condition_variable> #include <wtf/HashSet.h> -#include <wtf/TCSpinLock.h> +#include <wtf/SpinLock.h> #include <wtf/Vector.h> namespace JSC { -class GCThread; -class VM; +class CopiedBlock; class CopiedSpace; class CopyVisitor; +class GCThread; +class VM; enum GCPhase { NoPhase, diff --git a/heap/Handle.h b/heap/Handle.h index 28ac30c..c924e04 100644 --- a/heap/Handle.h +++ b/heap/Handle.h @@ -52,9 +52,7 @@ class HandleBase { public: bool operator!() const { return !m_slot || !*m_slot; } - // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef JSValue (HandleBase::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const { return (m_slot && *m_slot) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } + explicit operator bool() const { return m_slot && *m_slot; } HandleSlot slot() const { return m_slot; } diff --git a/heap/HandleBlock.h b/heap/HandleBlock.h index 962d37c..fb8c105 100644 --- a/heap/HandleBlock.h +++ b/heap/HandleBlock.h @@ -26,7 +26,7 @@ #ifndef HandleBlock_h #define HandleBlock_h -#include "HeapBlock.h" +#include <wtf/DoublyLinkedList.h> namespace JSC { @@ -34,9 +34,11 @@ class DeadBlock; class HandleSet; class HandleNode; -class HandleBlock : public HeapBlock<HandleBlock> { +class HandleBlock : public DoublyLinkedListNode<HandleBlock> { + friend class WTF::DoublyLinkedListNode<HandleBlock>; public: - static HandleBlock* create(DeadBlock*, HandleSet*); + static HandleBlock* create(HandleSet*); + static void destroy(HandleBlock*); static HandleBlock* blockFor(HandleNode*); static const size_t blockSize = 4 * KB; @@ -48,13 +50,15 @@ public: unsigned nodeCapacity(); private: - HandleBlock(Region*, HandleSet*); + HandleBlock(HandleSet*); char* payload(); char* payloadEnd(); static const size_t s_blockMask = ~(blockSize - 1); + HandleBlock* m_prev; + HandleBlock* m_next; HandleSet* m_handleSet; }; diff --git a/heap/HandleBlockInlines.h b/heap/HandleBlockInlines.h index 7c77193..9e29bff 100644 --- a/heap/HandleBlockInlines.h +++ b/heap/HandleBlockInlines.h @@ -26,26 +26,31 @@ #ifndef HandleBlockInlines_h #define HandleBlockInlines_h -#include "BlockAllocator.h" #include "HandleBlock.h" +#include <wtf/FastMalloc.h> namespace JSC { -inline HandleBlock* HandleBlock::create(DeadBlock* block, HandleSet* handleSet) +inline HandleBlock* HandleBlock::create(HandleSet* handleSet) { - Region* region = block->region(); - return new (NotNull, block) HandleBlock(region, handleSet); + return new (NotNull, fastAlignedMalloc(blockSize, blockSize)) HandleBlock(handleSet); } -inline HandleBlock::HandleBlock(Region* region, HandleSet* handleSet) - : HeapBlock<HandleBlock>(region) +inline void HandleBlock::destroy(HandleBlock* block) +{ + block->~HandleBlock(); + fastAlignedFree(block); +} + +inline HandleBlock::HandleBlock(HandleSet* handleSet) + : DoublyLinkedListNode<HandleBlock>() , m_handleSet(handleSet) { } inline char* HandleBlock::payloadEnd() { - return reinterpret_cast<char*>(this) + region()->blockSize(); + return reinterpret_cast<char*>(this) + blockSize; } inline char* HandleBlock::payload() diff --git a/heap/HandleSet.cpp b/heap/HandleSet.cpp index be667e8..dec8370 100644 --- a/heap/HandleSet.cpp +++ b/heap/HandleSet.cpp @@ -44,12 +44,12 @@ HandleSet::HandleSet(VM* vm) HandleSet::~HandleSet() { while (!m_blockList.isEmpty()) - m_vm->heap.blockAllocator().deallocate(HandleBlock::destroy(m_blockList.removeHead())); + HandleBlock::destroy(m_blockList.removeHead()); } void HandleSet::grow() { - HandleBlock* newBlock = HandleBlock::create(m_vm->heap.blockAllocator().allocate<HandleBlock>(), this); + HandleBlock* newBlock = HandleBlock::create(this); m_blockList.append(newBlock); for (int i = newBlock->nodeCapacity() - 1; i >= 0; --i) { diff --git a/heap/HandleStack.h b/heap/HandleStack.h index a7ce976..8df8684 100644 --- a/heap/HandleStack.h +++ b/heap/HandleStack.h @@ -53,7 +53,7 @@ public: void visit(HeapRootVisitor&); private: - void grow(); + JS_EXPORT_PRIVATE void grow(); void zapTo(Frame&); HandleSlot findFirstAfter(HandleSlot); diff --git a/heap/Heap.cpp b/heap/Heap.cpp index 447383b..b1f6625 100644 --- a/heap/Heap.cpp +++ b/heap/Heap.cpp @@ -27,7 +27,6 @@ #include "CopiedSpaceInlines.h" #include "CopyVisitorInlines.h" #include "DFGWorklist.h" -#include "DelayedReleaseScope.h" #include "EdenGCActivityCallback.h" #include "FullGCActivityCallback.h" #include "GCActivityCallback.h" @@ -35,6 +34,7 @@ #include "HeapIterationScope.h" #include "HeapRootVisitor.h" #include "HeapStatistics.h" +#include "HeapVerifier.h" #include "IncrementalSweeper.h" #include "Interpreter.h" #include "JSGlobalObject.h" @@ -44,6 +44,7 @@ #include "JSVirtualMachineInternal.h" #include "RecursiveAllocationScope.h" #include "Tracing.h" +#include "TypeProfilerLog.h" #include "UnlinkedCodeBlock.h" #include "VM.h" #include "WeakSetInlines.h" @@ -79,115 +80,125 @@ static type name arguments; struct GCTimer { GCTimer(const char* name) - : m_name(name) + : name(name) { } ~GCTimer() { - logData(m_allCollectionData, "(All)"); - logData(m_edenCollectionData, "(Eden)"); - logData(m_fullCollectionData, "(Full)"); + logData(allCollectionData, "(All)"); + logData(edenCollectionData, "(Eden)"); + logData(fullCollectionData, "(Full)"); } struct TimeRecord { TimeRecord() - : m_time(0) - , m_min(std::numeric_limits<double>::infinity()) - , m_max(0) - , m_count(0) + : time(0) + , min(std::numeric_limits<double>::infinity()) + , max(0) + , count(0) { } - double m_time; - double m_min; - double m_max; - size_t m_count; + double time; + double min; + double max; + size_t count; }; void logData(const TimeRecord& data, const char* extra) { - dataLogF("[%d] %s %s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf, count %lu)\n", + dataLogF("[%d] %s (Parent: %s) %s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf, count %lu)\n", getCurrentProcessID(), - m_name, extra, - data.m_time * 1000, - data.m_time * 1000 / data.m_count, - data.m_min * 1000, - data.m_max * 1000, - data.m_count); + name, + parent ? parent->name : "nullptr", + extra, + data.time * 1000, + data.time * 1000 / data.count, + data.min * 1000, + data.max * 1000, + data.count); } void updateData(TimeRecord& data, double duration) { - if (duration < data.m_min) - data.m_min = duration; - if (duration > data.m_max) - data.m_max = duration; - data.m_count++; - data.m_time += duration; + if (duration < data.min) + data.min = duration; + if (duration > data.max) + data.max = duration; + data.count++; + data.time += duration; } void didFinishPhase(HeapOperation collectionType, double duration) { - TimeRecord& data = collectionType == EdenCollection ? m_edenCollectionData : m_fullCollectionData; + TimeRecord& data = collectionType == EdenCollection ? edenCollectionData : fullCollectionData; updateData(data, duration); - updateData(m_allCollectionData, duration); + updateData(allCollectionData, duration); } - TimeRecord m_allCollectionData; - TimeRecord m_fullCollectionData; - TimeRecord m_edenCollectionData; - const char* m_name; + static GCTimer* s_currentGlobalTimer; + + TimeRecord allCollectionData; + TimeRecord fullCollectionData; + TimeRecord edenCollectionData; + const char* name; + GCTimer* parent { nullptr }; }; +GCTimer* GCTimer::s_currentGlobalTimer = nullptr; + struct GCTimerScope { - GCTimerScope(GCTimer* timer, HeapOperation collectionType) - : m_timer(timer) - , m_start(WTF::monotonicallyIncreasingTime()) - , m_collectionType(collectionType) + GCTimerScope(GCTimer& timer, HeapOperation collectionType) + : timer(timer) + , start(WTF::monotonicallyIncreasingTime()) + , collectionType(collectionType) { + timer.parent = GCTimer::s_currentGlobalTimer; + GCTimer::s_currentGlobalTimer = &timer; } ~GCTimerScope() { - double delta = WTF::monotonicallyIncreasingTime() - m_start; - m_timer->didFinishPhase(m_collectionType, delta); + double delta = WTF::monotonicallyIncreasingTime() - start; + timer.didFinishPhase(collectionType, delta); + GCTimer::s_currentGlobalTimer = timer.parent; } - GCTimer* m_timer; - double m_start; - HeapOperation m_collectionType; + GCTimer& timer; + double start; + HeapOperation collectionType; }; struct GCCounter { GCCounter(const char* name) - : m_name(name) - , m_count(0) - , m_total(0) - , m_min(10000000) - , m_max(0) + : name(name) + , count(0) + , total(0) + , min(10000000) + , max(0) { } - void count(size_t amount) + void add(size_t amount) { - m_count++; - m_total += amount; - if (amount < m_min) - m_min = amount; - if (amount > m_max) - m_max = amount; + count++; + total += amount; + if (amount < min) + min = amount; + if (amount > max) + max = amount; } ~GCCounter() { - dataLogF("[%d] %s: %zu values (avg. %zu, min. %zu, max. %zu)\n", getCurrentProcessID(), m_name, m_total, m_total / m_count, m_min, m_max); + dataLogF("[%d] %s: %zu values (avg. %zu, min. %zu, max. %zu)\n", getCurrentProcessID(), name, total, total / count, min, max); } - const char* m_name; - size_t m_count; - size_t m_total; - size_t m_min; - size_t m_max; + const char* name; + size_t count; + size_t total; + size_t min; + size_t max; }; -#define GCPHASE(name) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name##Timer, (#name)); GCTimerScope name##TimerScope(&name##Timer, m_operationInProgress) -#define GCCOUNTER(name, value) do { DEFINE_GC_LOGGING_GLOBAL(GCCounter, name##Counter, (#name)); name##Counter.count(value); } while (false) +#define GCPHASE(name) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name##Timer, (#name)); GCTimerScope name##TimerScope(name##Timer, m_operationInProgress) +#define GCCOUNTER(name, value) do { DEFINE_GC_LOGGING_GLOBAL(GCCounter, name##Counter, (#name)); name##Counter.add(value); } while (false) #else @@ -229,12 +240,17 @@ static inline bool isValidThreadState(VM* vm) } struct MarkObject : public MarkedBlock::VoidFunctor { - void operator()(JSCell* cell) + inline void visit(JSCell* cell) { if (cell->isZapped()) return; Heap::heap(cell)->setMarked(cell); } + IterationStatus operator()(JSCell* cell) + { + visit(cell); + return IterationStatus::Continue; + } }; struct Count : public MarkedBlock::CountFunctor { @@ -242,30 +258,36 @@ struct Count : public MarkedBlock::CountFunctor { }; struct CountIfGlobalObject : MarkedBlock::CountFunctor { - void operator()(JSCell* cell) { + inline void visit(JSCell* cell) + { if (!cell->isObject()) return; if (!asObject(cell)->isGlobalObject()) return; count(1); } + IterationStatus operator()(JSCell* cell) + { + visit(cell); + return IterationStatus::Continue; + } }; class RecordType { public: - typedef PassOwnPtr<TypeCountSet> ReturnType; + typedef std::unique_ptr<TypeCountSet> ReturnType; RecordType(); - void operator()(JSCell*); + IterationStatus operator()(JSCell*); ReturnType returnValue(); private: const char* typeName(JSCell*); - OwnPtr<TypeCountSet> m_typeCountSet; + std::unique_ptr<TypeCountSet> m_typeCountSet; }; inline RecordType::RecordType() - : m_typeCountSet(adoptPtr(new TypeCountSet)) + : m_typeCountSet(std::make_unique<TypeCountSet>()) { } @@ -277,21 +299,22 @@ inline const char* RecordType::typeName(JSCell* cell) return info->className; } -inline void RecordType::operator()(JSCell* cell) +inline IterationStatus RecordType::operator()(JSCell* cell) { m_typeCountSet->add(typeName(cell)); + return IterationStatus::Continue; } -inline PassOwnPtr<TypeCountSet> RecordType::returnValue() +inline std::unique_ptr<TypeCountSet> RecordType::returnValue() { - return m_typeCountSet.release(); + return WTF::move(m_typeCountSet); } } // anonymous namespace Heap::Heap(VM* vm, HeapType heapType) : m_heapType(heapType) - , m_ramSize(ramSize()) + , m_ramSize(Options::forceRAMSize() ? Options::forceRAMSize() : ramSize()) , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize)) , m_sizeAfterLastCollect(0) , m_sizeAfterLastFullCollect(0) @@ -306,16 +329,15 @@ Heap::Heap(VM* vm, HeapType heapType) , m_totalBytesVisited(0) , m_totalBytesCopied(0) , m_operationInProgress(NoOperation) - , m_blockAllocator() , m_objectSpace(this) , m_storageSpace(this) - , m_extraMemoryUsage(0) + , m_extraMemorySize(0) + , m_deprecatedExtraMemorySize(0) , m_machineThreads(this) , m_sharedData(vm) , m_slotVisitor(m_sharedData) , m_copyVisitor(m_sharedData) , m_handleSet(vm) - , m_codeBlocks(m_blockAllocator) , m_isSafeToCollect(false) , m_writeBarrierBuffer(256) , m_vm(vm) @@ -330,14 +352,25 @@ Heap::Heap(VM* vm, HeapType heapType) #else , m_edenActivityCallback(m_fullActivityCallback) #endif - , m_sweeper(IncrementalSweeper::create(this)) +#if USE(CF) + , m_sweeper(std::make_unique<IncrementalSweeper>(this, CFRunLoopGetCurrent())) +#else + , m_sweeper(std::make_unique<IncrementalSweeper>(this->vm())) +#endif , m_deferralDepth(0) +#if USE(CF) + , m_delayedReleaseRecursionCount(0) +#endif { m_storageSpace.init(); + if (Options::verifyHeap()) + m_verifier = std::make_unique<HeapVerifier>(this, Options::numberOfGCCyclesToRecordForVerification()); } Heap::~Heap() { + for (WeakBlock* block : m_logicallyEmptyWeakBlocks) + WeakBlock::destroy(block); } bool Heap::isPagedOut(double deadline) @@ -353,25 +386,51 @@ void Heap::lastChanceToFinalize() RELEASE_ASSERT(m_operationInProgress == NoOperation); m_objectSpace.lastChanceToFinalize(); + releaseDelayedReleasedObjects(); + + sweepAllLogicallyEmptyWeakBlocks(); } -void Heap::reportExtraMemoryCostSlowCase(size_t cost) +void Heap::releaseDelayedReleasedObjects() { - // Our frequency of garbage collection tries to balance memory use against speed - // by collecting based on the number of newly created values. However, for values - // that hold on to a great deal of memory that's not in the form of other JS values, - // that is not good enough - in some cases a lot of those objects can pile up and - // use crazy amounts of memory without a GC happening. So we track these extra - // memory costs. Only unusually large objects are noted, and we only keep track - // of this extra cost until the next GC. In garbage collected languages, most values - // are either very short lived temporaries, or have extremely long lifetimes. So - // if a large value survives one garbage collection, there is not much point to - // collecting more frequently as long as it stays alive. +#if USE(CF) + // We need to guard against the case that releasing an object can create more objects due to the + // release calling into JS. When those JS call(s) exit and all locks are being dropped we end up + // back here and could try to recursively release objects. We guard that with a recursive entry + // count. Only the initial call will release objects, recursive calls simple return and let the + // the initial call to the function take care of any objects created during release time. + // This also means that we need to loop until there are no objects in m_delayedReleaseObjects + // and use a temp Vector for the actual releasing. + if (!m_delayedReleaseRecursionCount++) { + while (!m_delayedReleaseObjects.isEmpty()) { + ASSERT(m_vm->currentThreadIsHoldingAPILock()); + + Vector<RetainPtr<CFTypeRef>> objectsToRelease = WTF::move(m_delayedReleaseObjects); + + { + // We need to drop locks before calling out to arbitrary code. + JSLock::DropAllLocks dropAllLocks(m_vm); + + objectsToRelease.clear(); + } + } + } + m_delayedReleaseRecursionCount--; +#endif +} - didAllocate(cost); +void Heap::reportExtraMemoryAllocatedSlowCase(size_t size) +{ + didAllocate(size); collectIfNecessaryOrDefer(); } +void Heap::deprecatedReportExtraMemorySlowCase(size_t size) +{ + m_deprecatedExtraMemorySize += size; + reportExtraMemoryAllocatedSlowCase(size); +} + void Heap::reportAbandonedObjectGraph() { // Our clients don't know exactly how much memory they @@ -424,17 +483,6 @@ void Heap::addReference(JSCell* cell, ArrayBuffer* buffer) } } -void Heap::pushTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempVector) -{ - m_tempSortingVectors.append(tempVector); -} - -void Heap::popTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempVector) -{ - ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last()); - m_tempSortingVectors.removeLast(); -} - void Heap::harvestWeakReferences() { m_slotVisitor.harvestWeakReferences(); @@ -475,7 +523,7 @@ void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots) } } -void Heap::markRoots(double gcStartTime) +void Heap::markRoots(double gcStartTime, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters) { SamplingRegion samplingRegion("Garbage Collection: Marking"); @@ -496,15 +544,11 @@ void Heap::markRoots(double gcStartTime) // We gather conservative roots before clearing mark bits because conservative // gathering uses the mark bits to determine whether a reference is valid. - void* dummy; - ALLOCATE_AND_GET_REGISTER_STATE(registers); ConservativeRoots conservativeRoots(&m_objectSpace.blocks(), &m_storageSpace); - gatherStackRoots(conservativeRoots, &dummy, registers); + gatherStackRoots(conservativeRoots, stackOrigin, stackTop, calleeSavedRegisters); gatherJSStackRoots(conservativeRoots); gatherScratchBufferRoots(conservativeRoots); - sanitizeStackForVM(m_vm); - clearLivenessData(); m_sharedData.didStartMarking(); @@ -518,7 +562,6 @@ void Heap::markRoots(double gcStartTime) visitSmallStrings(); visitConservativeRoots(conservativeRoots); visitProtectedObjects(heapRootVisitor); - visitTempSortVectors(heapRootVisitor); visitArgumentBuffers(heapRootVisitor); visitException(heapRootVisitor); visitStrongHandles(heapRootVisitor); @@ -539,6 +582,7 @@ void Heap::markRoots(double gcStartTime) void Heap::copyBackingStores() { + GCPHASE(CopyBackingStores); if (m_operationInProgress == EdenCollection) m_storageSpace.startedCopying<EdenCollection>(); else { @@ -559,11 +603,11 @@ void Heap::copyBackingStores() m_storageSpace.doneCopying(); } -void Heap::gatherStackRoots(ConservativeRoots& roots, void** dummy, MachineThreads::RegisterState& registers) +void Heap::gatherStackRoots(ConservativeRoots& roots, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters) { GCPHASE(GatherStackRoots); m_jitStubRoutines.clearMarks(); - m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, dummy, registers); + m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, stackOrigin, stackTop, calleeSavedRegisters); } void Heap::gatherJSStackRoots(ConservativeRoots& roots) @@ -603,11 +647,12 @@ void Heap::visitExternalRememberedSet() void Heap::visitSmallStrings() { GCPHASE(VisitSmallStrings); - m_vm->smallStrings.visitStrongReferences(m_slotVisitor); + if (!m_vm->smallStrings.needsToBeVisited(m_operationInProgress)) + return; + m_vm->smallStrings.visitStrongReferences(m_slotVisitor); if (Options::logGC() == GCLogging::Verbose) dataLog("Small strings:\n", m_slotVisitor); - m_slotVisitor.donateAndDrain(); } @@ -655,24 +700,6 @@ void Heap::visitProtectedObjects(HeapRootVisitor& heapRootVisitor) m_slotVisitor.donateAndDrain(); } -void Heap::visitTempSortVectors(HeapRootVisitor& heapRootVisitor) -{ - GCPHASE(VisitTempSortVectors); - typedef Vector<Vector<ValueStringPair, 0, UnsafeVectorOverflow>*> VectorOfValueStringVectors; - - for (auto* vector : m_tempSortingVectors) { - for (auto& valueStringPair : *vector) { - if (valueStringPair.first) - heapRootVisitor.visit(&valueStringPair.first); - } - } - - if (Options::logGC() == GCLogging::Verbose) - dataLog("Temp Sort Vectors:\n", m_slotVisitor); - - m_slotVisitor.donateAndDrain(); -} - void Heap::visitArgumentBuffers(HeapRootVisitor& visitor) { GCPHASE(MarkingArgumentBuffers); @@ -690,10 +717,11 @@ void Heap::visitArgumentBuffers(HeapRootVisitor& visitor) void Heap::visitException(HeapRootVisitor& visitor) { GCPHASE(MarkingException); - if (!m_vm->exception()) + if (!m_vm->exception() && !m_vm->lastException()) return; visitor.visit(m_vm->addressOfException()); + visitor.visit(m_vm->addressOfLastException()); if (Options::logGC() == GCLogging::Verbose) dataLog("Exceptions:\n", m_slotVisitor); @@ -771,10 +799,8 @@ void Heap::clearRememberedSet(Vector<const JSCell*>& rememberedSet) { #if ENABLE(GGC) GCPHASE(ClearRememberedSet); - for (auto* cell : rememberedSet) { - MarkedBlock::blockFor(cell)->clearRemembered(cell); + for (auto* cell : rememberedSet) const_cast<JSCell*>(cell)->setRemembered(false); - } #else UNUSED_PARAM(rememberedSet); #endif @@ -791,15 +817,18 @@ void Heap::updateObjectCounts(double gcStartTime) #endif dataLogF("\nNumber of live Objects after GC %lu, took %.6f secs\n", static_cast<unsigned long>(visitCount), WTF::monotonicallyIncreasingTime() - gcStartTime); } - - if (m_operationInProgress == EdenCollection) { - m_totalBytesVisited += m_slotVisitor.bytesVisited(); - m_totalBytesCopied += m_slotVisitor.bytesCopied(); - } else { - ASSERT(m_operationInProgress == FullCollection); - m_totalBytesVisited = m_slotVisitor.bytesVisited(); - m_totalBytesCopied = m_slotVisitor.bytesCopied(); - } + + size_t bytesRemovedFromOldSpaceDueToReallocation = + m_storageSpace.takeBytesRemovedFromOldSpaceDueToReallocation(); + + if (m_operationInProgress == FullCollection) { + m_totalBytesVisited = 0; + m_totalBytesCopied = 0; + } else + m_totalBytesCopied -= bytesRemovedFromOldSpaceDueToReallocation; + + m_totalBytesVisited += m_slotVisitor.bytesVisited(); + m_totalBytesCopied += m_slotVisitor.bytesCopied(); #if ENABLE(PARALLEL_GC) m_totalBytesVisited += m_sharedData.childBytesVisited(); m_totalBytesCopied += m_sharedData.childBytesCopied(); @@ -820,19 +849,19 @@ size_t Heap::objectCount() return m_objectSpace.objectCount(); } -size_t Heap::extraSize() +size_t Heap::extraMemorySize() { - return m_extraMemoryUsage + m_arrayBuffers.size(); + return m_extraMemorySize + m_deprecatedExtraMemorySize + m_arrayBuffers.size(); } size_t Heap::size() { - return m_objectSpace.size() + m_storageSpace.size() + extraSize(); + return m_objectSpace.size() + m_storageSpace.size() + extraMemorySize(); } size_t Heap::capacity() { - return m_objectSpace.capacity() + m_storageSpace.capacity() + extraSize(); + return m_objectSpace.capacity() + m_storageSpace.capacity() + extraMemorySize(); } size_t Heap::sizeAfterCollect() @@ -842,7 +871,7 @@ size_t Heap::sizeAfterCollect() // rather than all used (including dead) copied bytes, thus it's // always the case that m_totalBytesCopied <= m_storageSpace.size(). ASSERT(m_totalBytesCopied <= m_storageSpace.size()); - return m_totalBytesVisited + m_totalBytesCopied + extraSize(); + return m_totalBytesVisited + m_totalBytesCopied + extraMemorySize(); } size_t Heap::protectedGlobalObjectCount() @@ -861,12 +890,12 @@ size_t Heap::protectedObjectCount() return forEachProtectedCell<Count>(); } -PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts() +std::unique_ptr<TypeCountSet> Heap::protectedObjectTypeCounts() { return forEachProtectedCell<RecordType>(); } -PassOwnPtr<TypeCountSet> Heap::objectTypeCounts() +std::unique_ptr<TypeCountSet> Heap::objectTypeCounts() { HeapIterationScope iterationScope(*this); return m_objectSpace.forEachLiveCell<RecordType>(iterationScope); @@ -895,10 +924,10 @@ void Heap::deleteAllCompiledCode() } #endif // ENABLE(DFG_JIT) - for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) { + for (ExecutableBase* current : m_compiledCode) { if (!current->isFunctionExecutable()) continue; - static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling(); + static_cast<FunctionExecutable*>(current)->clearCode(); } ASSERT(m_operationInProgress == FullCollection || m_operationInProgress == NoOperation); @@ -908,26 +937,26 @@ void Heap::deleteAllCompiledCode() void Heap::deleteAllUnlinkedFunctionCode() { - for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) { + for (ExecutableBase* current : m_compiledCode) { if (!current->isFunctionExecutable()) continue; - static_cast<FunctionExecutable*>(current)->clearUnlinkedCodeForRecompilationIfNotCompiling(); + static_cast<FunctionExecutable*>(current)->clearUnlinkedCodeForRecompilation(); } } void Heap::clearUnmarkedExecutables() { GCPHASE(ClearUnmarkedExecutables); - ExecutableBase* next; - for (ExecutableBase* current = m_compiledCode.head(); current; current = next) { - next = current->next(); + for (unsigned i = m_compiledCode.size(); i--;) { + ExecutableBase* current = m_compiledCode[i]; if (isMarked(current)) continue; // We do this because executable memory is limited on some platforms and because // CodeBlock requires eager finalization. ExecutableBase::clearCodeVirtual(current); - m_compiledCode.remove(current); + std::swap(m_compiledCode[i], m_compiledCode.last()); + m_compiledCode.removeLast(); } } @@ -945,27 +974,39 @@ void Heap::addToRememberedSet(const JSCell* cell) ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread()); if (isRemembered(cell)) return; - MarkedBlock::blockFor(cell)->setRemembered(cell); const_cast<JSCell*>(cell)->setRemembered(true); m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell)); } -void Heap::collectAllGarbage() +void Heap::collectAndSweep(HeapOperation collectionType) { if (!m_isSafeToCollect) return; - collect(FullCollection); + collect(collectionType); SamplingRegion samplingRegion("Garbage Collection: Sweeping"); - DelayedReleaseScope delayedReleaseScope(m_objectSpace); + + DeferGCForAWhile deferGC(*this); m_objectSpace.sweep(); m_objectSpace.shrink(); + + sweepAllLogicallyEmptyWeakBlocks(); } static double minute = 60.0; -void Heap::collect(HeapOperation collectionType) +NEVER_INLINE void Heap::collect(HeapOperation collectionType) +{ + void* stackTop; + ALLOCATE_AND_GET_REGISTER_STATE(registers); + + collectImpl(collectionType, wtfThreadData().stack().origin(), &stackTop, registers); + + sanitizeStackForVM(m_vm); +} + +NEVER_INLINE void Heap::collectImpl(HeapOperation collectionType, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters) { #if ENABLE(ALLOCATION_LOGGING) dataLogF("JSC GC starting collection.\n"); @@ -979,6 +1020,11 @@ void Heap::collect(HeapOperation collectionType) SamplingRegion samplingRegion("Garbage Collection"); + if (vm()->typeProfiler()) { + DeferGCForAWhile awhile(*this); + vm()->typeProfilerLog()->processLogEntries(ASCIILiteral("GC")); + } + RELEASE_ASSERT(!m_deferralDepth); ASSERT(vm()->currentThreadIsHoldingAPILock()); RELEASE_ASSERT(vm()->atomicStringTable() == wtfThreadData().atomicStringTable()); @@ -991,17 +1037,33 @@ void Heap::collect(HeapOperation collectionType) GCPHASE(Collect); double gcStartTime = WTF::monotonicallyIncreasingTime(); + if (m_verifier) { + // Verify that live objects from the last GC cycle haven't been corrupted by + // mutators before we begin this new GC cycle. + m_verifier->verify(HeapVerifier::Phase::BeforeGC); + + m_verifier->initializeGCCycle(); + m_verifier->gatherLiveObjects(HeapVerifier::Phase::BeforeMarking); + } deleteOldCode(gcStartTime); flushOldStructureIDTables(); stopAllocation(); flushWriteBarrierBuffer(); - markRoots(gcStartTime); + markRoots(gcStartTime, stackOrigin, stackTop, calleeSavedRegisters); + if (m_verifier) { + m_verifier->gatherLiveObjects(HeapVerifier::Phase::AfterMarking); + m_verifier->verify(HeapVerifier::Phase::AfterMarking); + } JAVASCRIPTCORE_GC_MARKED(); + if (vm()->typeProfiler()) + vm()->typeProfiler()->invalidateTypeSetCache(); + reapWeakHandles(); + pruneStaleEntriesFromWeakGCMaps(); sweepArrayBuffers(); snapshotMarkedSpace(); @@ -1019,6 +1081,11 @@ void Heap::collect(HeapOperation collectionType) didFinishCollection(gcStartTime); resumeCompilerThreads(); + if (m_verifier) { + m_verifier->trimDeadObjects(); + m_verifier->verify(HeapVerifier::Phase::AfterGC); + } + if (Options::logGC()) { double after = currentTimeMS(); dataLog(after - before, " ms]\n"); @@ -1055,7 +1122,8 @@ void Heap::willStartCollection(HeapOperation collectionType) } if (m_operationInProgress == FullCollection) { m_sizeBeforeLastFullCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle; - m_extraMemoryUsage = 0; + m_extraMemorySize = 0; + m_deprecatedExtraMemorySize = 0; if (m_fullActivityCallback) m_fullActivityCallback->willCollect(); @@ -1110,6 +1178,15 @@ void Heap::reapWeakHandles() m_objectSpace.reapWeakSets(); } +void Heap::pruneStaleEntriesFromWeakGCMaps() +{ + GCPHASE(PruningStaleEntriesFromWeakGCMaps); + if (m_operationInProgress != FullCollection) + return; + for (auto& pruneCallback : m_weakGCMaps.values()) + pruneCallback(); +} + void Heap::sweepArrayBuffers() { GCPHASE(SweepingArrayBuffers); @@ -1132,12 +1209,17 @@ struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor { void Heap::snapshotMarkedSpace() { GCPHASE(SnapshotMarkedSpace); - if (m_operationInProgress != FullCollection) - return; - m_blockSnapshot.resize(m_objectSpace.blocks().set().size()); - MarkedBlockSnapshotFunctor functor(m_blockSnapshot); - m_objectSpace.forEachBlock(functor); + if (m_operationInProgress == EdenCollection) { + m_blockSnapshot.appendVector(m_objectSpace.blocksWithNewObjects()); + // Sort and deduplicate the block snapshot since we might be appending to an unfinished work list. + std::sort(m_blockSnapshot.begin(), m_blockSnapshot.end()); + m_blockSnapshot.shrink(std::unique(m_blockSnapshot.begin(), m_blockSnapshot.end()) - m_blockSnapshot.begin()); + } else { + m_blockSnapshot.resizeToFit(m_objectSpace.blocks().set().size()); + MarkedBlockSnapshotFunctor functor(m_blockSnapshot); + m_objectSpace.forEachBlock(functor); + } } void Heap::deleteSourceProviderCaches() @@ -1149,9 +1231,13 @@ void Heap::deleteSourceProviderCaches() void Heap::notifyIncrementalSweeper() { GCPHASE(NotifyIncrementalSweeper); - if (m_operationInProgress != FullCollection) - return; - m_sweeper->startSweeping(m_blockSnapshot); + + if (m_operationInProgress == FullCollection) { + if (!m_logicallyEmptyWeakBlocks.isEmpty()) + m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0; + } + + m_sweeper->startSweeping(); } void Heap::rememberCurrentlyExecutingCodeBlocks() @@ -1215,10 +1301,6 @@ void Heap::didFinishCollection(double gcStartTime) if (Options::recordGCPauseTimes()) HeapStatistics::recordGCPauseTime(gcStartTime, gcEndTime); - RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection); - - m_operationInProgress = NoOperation; - JAVASCRIPTCORE_GC_END(); if (Options::useZombieMode()) zombifyDeadObjects(); @@ -1231,6 +1313,10 @@ void Heap::didFinishCollection(double gcStartTime) if (Options::logGC() == GCLogging::Verbose) GCLogging::dumpObjectGraph(this); + + RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection); + m_operationInProgress = NoOperation; + JAVASCRIPTCORE_GC_END(); } void Heap::resumeCompilerThreads() @@ -1269,9 +1355,9 @@ GCActivityCallback* Heap::edenActivityCallback() return m_edenActivityCallback.get(); } -void Heap::setIncrementalSweeper(PassOwnPtr<IncrementalSweeper> sweeper) +void Heap::setIncrementalSweeper(std::unique_ptr<IncrementalSweeper> sweeper) { - m_sweeper = sweeper; + m_sweeper = WTF::move(sweeper); } IncrementalSweeper* Heap::sweeper() @@ -1323,9 +1409,26 @@ void Heap::addCompiledCode(ExecutableBase* executable) m_compiledCode.append(executable); } +void Heap::collectAllGarbageIfNotDoneRecently() +{ + if (!m_fullActivityCallback) { + collectAllGarbage(); + return; + } + + if (m_fullActivityCallback->didSyncGCRecently()) { + // A synchronous GC was already requested recently so we merely accelerate next collection. + reportAbandonedObjectGraph(); + return; + } + + m_fullActivityCallback->setDidSyncGCRecently(); + collectAllGarbage(); +} + class Zombify : public MarkedBlock::VoidFunctor { public: - void operator()(JSCell* cell) + inline void visit(JSCell* cell) { void** current = reinterpret_cast<void**>(cell); @@ -1338,6 +1441,11 @@ public: for (; current < limit; current++) *current = zombifiedBits; } + IterationStatus operator()(JSCell* cell) + { + visit(cell); + return IterationStatus::Continue; + } }; void Heap::zombifyDeadObjects() @@ -1345,7 +1453,6 @@ void Heap::zombifyDeadObjects() // Sweep now because destructors will crash once we're zombified. { SamplingRegion samplingRegion("Garbage Collection: Sweeping"); - DelayedReleaseScope delayedReleaseScope(m_objectSpace); m_objectSpace.zombifySweep(); } HeapIterationScope iterationScope(*this); @@ -1387,4 +1494,41 @@ bool Heap::shouldDoFullCollection(HeapOperation requestedCollectionType) const #endif } +void Heap::addLogicallyEmptyWeakBlock(WeakBlock* block) +{ + m_logicallyEmptyWeakBlocks.append(block); +} + +void Heap::sweepAllLogicallyEmptyWeakBlocks() +{ + if (m_logicallyEmptyWeakBlocks.isEmpty()) + return; + + m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0; + while (sweepNextLogicallyEmptyWeakBlock()) { } +} + +bool Heap::sweepNextLogicallyEmptyWeakBlock() +{ + if (m_indexOfNextLogicallyEmptyWeakBlockToSweep == WTF::notFound) + return false; + + WeakBlock* block = m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep]; + + block->sweep(); + if (block->isEmpty()) { + std::swap(m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep], m_logicallyEmptyWeakBlocks.last()); + m_logicallyEmptyWeakBlocks.removeLast(); + WeakBlock::destroy(block); + } else + m_indexOfNextLogicallyEmptyWeakBlockToSweep++; + + if (m_indexOfNextLogicallyEmptyWeakBlockToSweep >= m_logicallyEmptyWeakBlocks.size()) { + m_indexOfNextLogicallyEmptyWeakBlockToSweep = WTF::notFound; + return false; + } + + return true; +} + } // namespace JSC diff --git a/heap/Heap.h b/heap/Heap.h index 2f2e3e9..878fb5c 100644 --- a/heap/Heap.h +++ b/heap/Heap.h @@ -23,7 +23,6 @@ #define Heap_h #include "ArrayBuffer.h" -#include "BlockAllocator.h" #include "CodeBlockSet.h" #include "CopyVisitor.h" #include "GCIncomingRefCountedSet.h" @@ -57,6 +56,7 @@ class GCAwareJITStubRoutine; class GlobalCodeBlock; class Heap; class HeapRootVisitor; +class HeapVerifier; class IncrementalSweeper; class JITStubRoutine; class JSCell; @@ -75,7 +75,6 @@ class Worklist; static void* const zombifiedBits = reinterpret_cast<void*>(0xdeadbeef); -typedef std::pair<JSValue, WTF::String> ValueStringPair; typedef HashCountedSet<JSCell*> ProtectCountSet; typedef HashCountedSet<const char*> TypeCountSet; @@ -114,9 +113,11 @@ public: Heap(VM*, HeapType); ~Heap(); JS_EXPORT_PRIVATE void lastChanceToFinalize(); + void releaseDelayedReleasedObjects(); VM* vm() const { return m_vm; } MarkedSpace& objectSpace() { return m_objectSpace; } + CopiedSpace& storageSpace() { return m_storageSpace; } MachineThreads& machineThreads() { return m_machineThreads; } const SlotVisitor& slotVisitor() const { return m_slotVisitor; } @@ -128,17 +129,19 @@ public: JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool); JS_EXPORT_PRIVATE IncrementalSweeper* sweeper(); - JS_EXPORT_PRIVATE void setIncrementalSweeper(PassOwnPtr<IncrementalSweeper>); + JS_EXPORT_PRIVATE void setIncrementalSweeper(std::unique_ptr<IncrementalSweeper>); // true if collection is in progress bool isCollecting(); HeapOperation operationInProgress() { return m_operationInProgress; } // true if an allocation or collection is in progress bool isBusy(); - + MarkedSpace::Subspace& subspaceForObjectWithoutDestructor() { return m_objectSpace.subspaceForObjectsWithoutDestructor(); } + MarkedSpace::Subspace& subspaceForObjectDestructor() { return m_objectSpace.subspaceForObjectsWithDestructor(); } + template<typename ClassType> MarkedSpace::Subspace& subspaceForObjectOfType(); MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); } - MarkedAllocator& allocatorForObjectWithNormalDestructor(size_t bytes) { return m_objectSpace.normalDestructorAllocatorFor(bytes); } - MarkedAllocator& allocatorForObjectWithImmortalStructureDestructor(size_t bytes) { return m_objectSpace.immortalStructureDestructorAllocatorFor(bytes); } + MarkedAllocator& allocatorForObjectWithDestructor(size_t bytes) { return m_objectSpace.destructorAllocatorFor(bytes); } + template<typename ClassType> MarkedAllocator& allocatorForObjectOfType(size_t bytes); CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); } CheckedBoolean tryAllocateStorage(JSCell* intendedOwner, size_t, void**); CheckedBoolean tryReallocateStorage(JSCell* intendedOwner, void**, size_t, size_t); @@ -151,31 +154,38 @@ public: void notifyIsSafeToCollect() { m_isSafeToCollect = true; } bool isSafeToCollect() const { return m_isSafeToCollect; } - JS_EXPORT_PRIVATE void collectAllGarbage(); + JS_EXPORT_PRIVATE void collectAllGarbageIfNotDoneRecently(); + void collectAllGarbage() { collectAndSweep(FullCollection); } + JS_EXPORT_PRIVATE void collectAndSweep(HeapOperation collectionType = AnyCollection); bool shouldCollect(); JS_EXPORT_PRIVATE void collect(HeapOperation collectionType = AnyCollection); bool collectIfNecessaryOrDefer(); // Returns true if it did collect. - void reportExtraMemoryCost(size_t cost); + // Use this API to report non-GC memory referenced by GC objects. Be sure to + // call both of these functions: Calling only one may trigger catastropic + // memory growth. + void reportExtraMemoryAllocated(size_t); + void reportExtraMemoryVisited(JSCell*, size_t); + + // Use this API to report non-GC memory if you can't use the better API above. + void deprecatedReportExtraMemory(size_t); + JS_EXPORT_PRIVATE void reportAbandonedObjectGraph(); JS_EXPORT_PRIVATE void protect(JSValue); JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0. - size_t extraSize(); // extra memory usage outside of pages allocated by the heap + size_t extraMemorySize(); // Non-GC memory referenced by GC objects. JS_EXPORT_PRIVATE size_t size(); JS_EXPORT_PRIVATE size_t capacity(); JS_EXPORT_PRIVATE size_t objectCount(); JS_EXPORT_PRIVATE size_t globalObjectCount(); JS_EXPORT_PRIVATE size_t protectedObjectCount(); JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount(); - JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts(); - JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts(); + JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> protectedObjectTypeCounts(); + JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> objectTypeCounts(); void showStatistics(); - void pushTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>*); - void popTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>*); - HashSet<MarkedArgumentBuffer*>& markListSet(); template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&); @@ -212,7 +222,6 @@ public: bool isDeferred() const { return !!m_deferralDepth || Options::disableGC(); } - BlockAllocator& blockAllocator(); StructureIDTable& structureIDTable() { return m_structureIDTable; } #if USE(CF) @@ -223,15 +232,20 @@ public: static bool isZombified(JSCell* cell) { return *(void**)cell == zombifiedBits; } + void registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback); + void unregisterWeakGCMap(void* weakGCMap); + + void addLogicallyEmptyWeakBlock(WeakBlock*); + private: friend class CodeBlock; friend class CopiedBlock; friend class DeferGC; friend class DeferGCForAWhile; - friend class DelayedReleaseScope; friend class GCAwareJITStubRoutine; friend class GCLogging; friend class HandleSet; + friend class HeapVerifier; friend class JITStubRoutine; friend class LLIntOffsetsExtractor; friend class MarkedSpace; @@ -249,19 +263,21 @@ private: template<typename T> friend void* allocateCell(Heap&); template<typename T> friend void* allocateCell(Heap&, size_t); - void* allocateWithImmortalStructureDestructor(size_t); // For use with special objects whose Structures never die. - void* allocateWithNormalDestructor(size_t); // For use with objects that inherit directly or indirectly from JSDestructibleObject. + void* allocateWithDestructor(size_t); // For use with objects with destructors. void* allocateWithoutDestructor(size_t); // For use with objects without destructors. + template<typename ClassType> void* allocateObjectOfType(size_t); // Chooses one of the methods above based on type. - static const size_t minExtraCost = 256; - static const size_t maxExtraCost = 1024 * 1024; + static const size_t minExtraMemory = 256; class FinalizerOwner : public WeakHandleOwner { virtual void finalize(Handle<Unknown>, void* context) override; }; JS_EXPORT_PRIVATE bool isValidAllocation(size_t); - JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t); + JS_EXPORT_PRIVATE void reportExtraMemoryAllocatedSlowCase(size_t); + JS_EXPORT_PRIVATE void deprecatedReportExtraMemorySlowCase(size_t); + + void collectImpl(HeapOperation, void* stackOrigin, void* stackTop, MachineThreads::RegisterState&); void suspendCompilerThreads(); void willStartCollection(HeapOperation collectionType); @@ -270,8 +286,8 @@ private: void flushWriteBarrierBuffer(); void stopAllocation(); - void markRoots(double gcStartTime); - void gatherStackRoots(ConservativeRoots&, void** dummy, MachineThreads::RegisterState& registers); + void markRoots(double gcStartTime, void* stackOrigin, void* stackTop, MachineThreads::RegisterState&); + void gatherStackRoots(ConservativeRoots&, void* stackOrigin, void* stackTop, MachineThreads::RegisterState&); void gatherJSStackRoots(ConservativeRoots&); void gatherScratchBufferRoots(ConservativeRoots&); void clearLivenessData(); @@ -281,7 +297,6 @@ private: void visitCompilerWorklistWeakReferences(); void removeDeadCompilerWorklistEntries(); void visitProtectedObjects(HeapRootVisitor&); - void visitTempSortVectors(HeapRootVisitor&); void visitArgumentBuffers(HeapRootVisitor&); void visitException(HeapRootVisitor&); void visitStrongHandles(HeapRootVisitor&); @@ -294,6 +309,7 @@ private: void resetVisitors(); void reapWeakHandles(); + void pruneStaleEntriesFromWeakGCMaps(); void sweepArrayBuffers(); void snapshotMarkedSpace(); void deleteSourceProviderCaches(); @@ -311,6 +327,9 @@ private: void zombifyDeadObjects(); void markDeadObjects(); + void sweepAllLogicallyEmptyWeakBlocks(); + bool sweepNextLogicallyEmptyWeakBlock(); + bool shouldDoFullCollection(HeapOperation requestedCollectionType) const; size_t sizeAfterCollect(); @@ -338,18 +357,17 @@ private: size_t m_totalBytesCopied; HeapOperation m_operationInProgress; - BlockAllocator m_blockAllocator; StructureIDTable m_structureIDTable; MarkedSpace m_objectSpace; CopiedSpace m_storageSpace; GCIncomingRefCountedSet<ArrayBuffer> m_arrayBuffers; - size_t m_extraMemoryUsage; + size_t m_extraMemorySize; + size_t m_deprecatedExtraMemorySize; HashSet<const JSCell*> m_copyingRememberedSet; ProtectCountSet m_protectedValues; - Vector<Vector<ValueStringPair, 0, UnsafeVectorOverflow>*> m_tempSortingVectors; - OwnPtr<HashSet<MarkedArgumentBuffer*>> m_markListSet; + std::unique_ptr<HashSet<MarkedArgumentBuffer*>> m_markListSet; MachineThreads m_machineThreads; @@ -372,15 +390,26 @@ private: double m_lastEdenGCLength; double m_lastCodeDiscardTime; - DoublyLinkedList<ExecutableBase> m_compiledCode; + Vector<ExecutableBase*> m_compiledCode; + + Vector<WeakBlock*> m_logicallyEmptyWeakBlocks; + size_t m_indexOfNextLogicallyEmptyWeakBlockToSweep { WTF::notFound }; - RefPtr<GCActivityCallback> m_fullActivityCallback; + RefPtr<FullGCActivityCallback> m_fullActivityCallback; RefPtr<GCActivityCallback> m_edenActivityCallback; - OwnPtr<IncrementalSweeper> m_sweeper; + std::unique_ptr<IncrementalSweeper> m_sweeper; Vector<MarkedBlock*> m_blockSnapshot; unsigned m_deferralDepth; Vector<DFG::Worklist*> m_suspendedCompilerWorklists; + + std::unique_ptr<HeapVerifier> m_verifier; +#if USE(CF) + Vector<RetainPtr<CFTypeRef>> m_delayedReleaseObjects; + unsigned m_delayedReleaseRecursionCount; +#endif + + HashMap<void*, std::function<void()>> m_weakGCMaps; }; } // namespace JSC diff --git a/heap/HeapInlines.h b/heap/HeapInlines.h index 56fb3d7..c7e9735 100644 --- a/heap/HeapInlines.h +++ b/heap/HeapInlines.h @@ -29,6 +29,8 @@ #include "Heap.h" #include "JSCell.h" #include "Structure.h" +#include <type_traits> +#include <wtf/Assertions.h> namespace JSC { @@ -73,7 +75,6 @@ inline bool Heap::isRemembered(const void* ptr) const JSCell* cell = static_cast<const JSCell*>(ptr); ASSERT(cell); ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread()); - ASSERT(MarkedBlock::blockFor(cell)->isRemembered(cell) == cell->isRemembered()); return cell->isRemembered(); } @@ -152,10 +153,39 @@ inline void Heap::writeBarrier(const JSCell* from) #endif } -inline void Heap::reportExtraMemoryCost(size_t cost) +inline void Heap::reportExtraMemoryAllocated(size_t size) { - if (cost > minExtraCost) - reportExtraMemoryCostSlowCase(cost); + if (size > minExtraMemory) + reportExtraMemoryAllocatedSlowCase(size); +} + +inline void Heap::reportExtraMemoryVisited(JSCell* owner, size_t size) +{ +#if ENABLE(GGC) + // We don't want to double-count the extra memory that was reported in previous collections. + if (operationInProgress() == EdenCollection && Heap::isRemembered(owner)) + return; +#else + UNUSED_PARAM(owner); +#endif + + size_t* counter = &m_extraMemorySize; + +#if ENABLE(COMPARE_AND_SWAP) + for (;;) { + size_t oldSize = *counter; + if (WTF::weakCompareAndSwapSize(counter, oldSize, oldSize + size)) + return; + } +#else + (*counter) += size; +#endif +} + +inline void Heap::deprecatedReportExtraMemory(size_t size) +{ + if (size > minExtraMemory) + deprecatedReportExtraMemorySlowCase(size); } template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor) @@ -178,22 +208,13 @@ template<typename Functor> inline void Heap::forEachCodeBlock(Functor& functor) return m_codeBlocks.iterate<Functor>(functor); } -inline void* Heap::allocateWithNormalDestructor(size_t bytes) +inline void* Heap::allocateWithDestructor(size_t bytes) { #if ENABLE(ALLOCATION_LOGGING) dataLogF("JSC GC allocating %lu bytes with normal destructor.\n", bytes); #endif ASSERT(isValidAllocation(bytes)); - return m_objectSpace.allocateWithNormalDestructor(bytes); -} - -inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes) -{ -#if ENABLE(ALLOCATION_LOGGING) - dataLogF("JSC GC allocating %lu bytes with immortal structure destructor.\n", bytes); -#endif - ASSERT(isValidAllocation(bytes)); - return m_objectSpace.allocateWithImmortalStructureDestructor(bytes); + return m_objectSpace.allocateWithDestructor(bytes); } inline void* Heap::allocateWithoutDestructor(size_t bytes) @@ -205,6 +226,39 @@ inline void* Heap::allocateWithoutDestructor(size_t bytes) return m_objectSpace.allocateWithoutDestructor(bytes); } +template<typename ClassType> +void* Heap::allocateObjectOfType(size_t bytes) +{ + // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject. + ASSERT((!ClassType::needsDestruction || (ClassType::StructureFlags & StructureIsImmortal) || std::is_convertible<ClassType, JSDestructibleObject>::value)); + + if (ClassType::needsDestruction) + return allocateWithDestructor(bytes); + return allocateWithoutDestructor(bytes); +} + +template<typename ClassType> +MarkedSpace::Subspace& Heap::subspaceForObjectOfType() +{ + // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject. + ASSERT((!ClassType::needsDestruction || (ClassType::StructureFlags & StructureIsImmortal) || std::is_convertible<ClassType, JSDestructibleObject>::value)); + + if (ClassType::needsDestruction) + return subspaceForObjectDestructor(); + return subspaceForObjectWithoutDestructor(); +} + +template<typename ClassType> +MarkedAllocator& Heap::allocatorForObjectOfType(size_t bytes) +{ + // JSCell::classInfo() expects objects allocated with normal destructor to derive from JSDestructibleObject. + ASSERT((!ClassType::needsDestruction || (ClassType::StructureFlags & StructureIsImmortal) || std::is_convertible<ClassType, JSDestructibleObject>::value)); + + if (ClassType::needsDestruction) + return allocatorForObjectWithDestructor(bytes); + return allocatorForObjectWithoutDestructor(bytes); +} + inline CheckedBoolean Heap::tryAllocateStorage(JSCell* intendedOwner, size_t bytes, void** outPtr) { CheckedBoolean result = m_storageSpace.tryAllocate(bytes, outPtr); @@ -240,16 +294,11 @@ inline void Heap::ascribeOwner(JSCell* intendedOwner, void* storage) #endif } -inline BlockAllocator& Heap::blockAllocator() -{ - return m_blockAllocator; -} - #if USE(CF) template <typename T> inline void Heap::releaseSoon(RetainPtr<T>&& object) { - m_objectSpace.releaseSoon(WTF::move(object)); + m_delayedReleaseObjects.append(WTF::move(object)); } #endif @@ -286,9 +335,19 @@ inline void Heap::decrementDeferralDepthAndGCIfNeeded() inline HashSet<MarkedArgumentBuffer*>& Heap::markListSet() { if (!m_markListSet) - m_markListSet = adoptPtr(new HashSet<MarkedArgumentBuffer*>); + m_markListSet = std::make_unique<HashSet<MarkedArgumentBuffer*>>(); return *m_markListSet; } + +inline void Heap::registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback) +{ + m_weakGCMaps.add(weakGCMap, WTF::move(pruningCallback)); +} + +inline void Heap::unregisterWeakGCMap(void* weakGCMap) +{ + m_weakGCMaps.remove(weakGCMap); +} } // namespace JSC diff --git a/heap/HeapStatistics.cpp b/heap/HeapStatistics.cpp index f351f6a..bc5465f 100644 --- a/heap/HeapStatistics.cpp +++ b/heap/HeapStatistics.cpp @@ -28,8 +28,8 @@ #include "Heap.h" #include "HeapIterationScope.h" -#include "JSObject.h" #include "JSCInlines.h" +#include "JSObject.h" #include "Options.h" #include <stdlib.h> #if OS(UNIX) @@ -132,6 +132,7 @@ void HeapStatistics::logStatistics() void HeapStatistics::exitWithFailure() { + exit(-1); } void HeapStatistics::reportSuccess() @@ -166,7 +167,7 @@ class StorageStatistics : public MarkedBlock::VoidFunctor { public: StorageStatistics(); - void operator()(JSCell*); + IterationStatus operator()(JSCell*); size_t objectWithOutOfLineStorageCount(); size_t objectCount(); @@ -175,6 +176,8 @@ public: size_t storageCapacity(); private: + void visit(JSCell*); + size_t m_objectWithOutOfLineStorageCount; size_t m_objectCount; size_t m_storageSize; @@ -189,7 +192,7 @@ inline StorageStatistics::StorageStatistics() { } -inline void StorageStatistics::operator()(JSCell* cell) +inline void StorageStatistics::visit(JSCell* cell) { if (!cell->isObject()) return; @@ -208,6 +211,12 @@ inline void StorageStatistics::operator()(JSCell* cell) m_storageCapacity += object->structure()->totalStorageCapacity() * sizeof(WriteBarrierBase<Unknown>); } +inline IterationStatus StorageStatistics::operator()(JSCell* cell) +{ + visit(cell); + return IterationStatus::Continue; +} + inline size_t StorageStatistics::objectWithOutOfLineStorageCount() { return m_objectWithOutOfLineStorageCount; @@ -233,25 +242,26 @@ void HeapStatistics::showObjectStatistics(Heap* heap) 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_lastFullGCLength); + dataLogF("pause time: %lfs\n\n", heap->m_lastFullGCLength); StorageStatistics storageStatistics; { HeapIterationScope iterationScope(*heap); heap->m_objectSpace.forEachLiveCell(iterationScope, storageStatistics); } - 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())); - dataLogF("objects with out-of-line .property storage: %ld (%ld%%)\n", - static_cast<long>( - storageStatistics.objectWithOutOfLineStorageCount()), - static_cast<long>( - storageStatistics.objectWithOutOfLineStorageCount() * 100 - / storageStatistics.objectCount())); + long wastedPropertyStorageBytes = 0; + long wastedPropertyStoragePercent = 0; + long objectWithOutOfLineStorageCount = 0; + long objectsWithOutOfLineStoragePercent = 0; + if ((storageStatistics.storageCapacity() > 0) && (storageStatistics.objectCount() > 0)) { + wastedPropertyStorageBytes = static_cast<long>((storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB); + wastedPropertyStoragePercent = static_cast<long>( + (storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100 / storageStatistics.storageCapacity()); + objectWithOutOfLineStorageCount = static_cast<long>(storageStatistics.objectWithOutOfLineStorageCount()); + objectsWithOutOfLineStoragePercent = objectWithOutOfLineStorageCount * 100 / storageStatistics.objectCount(); + } + dataLogF("wasted .property storage: %ldkB (%ld%%)\n", wastedPropertyStorageBytes, wastedPropertyStoragePercent); + dataLogF("objects with out-of-line .property storage: %ld (%ld%%)\n", objectWithOutOfLineStorageCount, objectsWithOutOfLineStoragePercent); } } // namespace JSC diff --git a/heap/HeapTimer.cpp b/heap/HeapTimer.cpp index 9660d66..15e5484 100644 --- a/heap/HeapTimer.cpp +++ b/heap/HeapTimer.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "HeapTimer.h" +#include "GCActivityCallback.h" #include "IncrementalSweeper.h" #include "JSObject.h" #include "JSString.h" @@ -62,7 +63,7 @@ HeapTimer::HeapTimer(VM* vm, CFRunLoopRef runLoop) m_context.info = &vm->apiLock(); m_context.retain = retainAPILock; m_context.release = releaseAPILock; - m_timer = adoptCF(CFRunLoopTimerCreate(0, s_decade, s_decade, 0, 0, HeapTimer::timerDidFire, &m_context)); + m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, s_decade, s_decade, 0, 0, HeapTimer::timerDidFire, &m_context)); CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); } diff --git a/heap/HeapVerifier.cpp b/heap/HeapVerifier.cpp new file mode 100644 index 0000000..df92661 --- /dev/null +++ b/heap/HeapVerifier.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2014 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 "HeapVerifier.h" + +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" +#include "HeapIterationScope.h" +#include "JSCInlines.h" +#include "JSObject.h" + +namespace JSC { + +LiveObjectData* LiveObjectList::findObject(JSObject* obj) +{ + for (size_t i = 0; i < liveObjects.size(); i++) { + LiveObjectData& data = liveObjects[i]; + if (obj == data.obj) + return &data; + } + return nullptr; +} + +HeapVerifier::HeapVerifier(Heap* heap, unsigned numberOfGCCyclesToRecord) + : m_heap(heap) + , m_currentCycle(0) + , m_numberOfCycles(numberOfGCCyclesToRecord) +{ + RELEASE_ASSERT(m_numberOfCycles > 0); + m_cycles = std::make_unique<GCCycle[]>(m_numberOfCycles); +} + +const char* HeapVerifier::collectionTypeName(HeapOperation type) +{ + switch (type) { + case NoOperation: + return "NoOperation"; + case AnyCollection: + return "AnyCollection"; + case Allocation: + return "Allocation"; + case EdenCollection: + return "EdenCollection"; + case FullCollection: + return "FullCollection"; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; // Silencing a compiler warning. +} + +const char* HeapVerifier::phaseName(HeapVerifier::Phase phase) +{ + switch (phase) { + case Phase::BeforeGC: + return "BeforeGC"; + case Phase::BeforeMarking: + return "BeforeMarking"; + case Phase::AfterMarking: + return "AfterMarking"; + case Phase::AfterGC: + return "AfterGC"; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; // Silencing a compiler warning. +} + +static void getButterflyDetails(JSObject* obj, void*& butterflyBase, size_t& butterflyCapacityInBytes, CopiedBlock*& butterflyBlock) +{ + Structure* structure = obj->structure(); + Butterfly* butterfly = obj->butterfly(); + butterflyBase = butterfly->base(structure); + butterflyBlock = CopiedSpace::blockFor(butterflyBase); + + size_t propertyCapacity = structure->outOfLineCapacity(); + size_t preCapacity; + size_t indexingPayloadSizeInBytes; + bool hasIndexingHeader = obj->hasIndexingHeader(); + if (UNLIKELY(hasIndexingHeader)) { + preCapacity = butterfly->indexingHeader()->preCapacity(structure); + indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure); + } else { + preCapacity = 0; + indexingPayloadSizeInBytes = 0; + } + butterflyCapacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); +} + +void HeapVerifier::initializeGCCycle() +{ + Heap* heap = m_heap; + incrementCycle(); + currentCycle().collectionType = heap->operationInProgress(); +} + +struct GatherLiveObjFunctor : MarkedBlock::CountFunctor { + GatherLiveObjFunctor(LiveObjectList& list) + : m_list(list) + { + ASSERT(!list.liveObjects.size()); + } + + inline void visit(JSCell* cell) + { + if (!cell->isObject()) + return; + LiveObjectData data(asObject(cell)); + m_list.liveObjects.append(data); + } + + IterationStatus operator()(JSCell* cell) + { + visit(cell); + return IterationStatus::Continue; + } + + LiveObjectList& m_list; +}; + +void HeapVerifier::gatherLiveObjects(HeapVerifier::Phase phase) +{ + Heap* heap = m_heap; + LiveObjectList& list = *liveObjectListForGathering(phase); + + HeapIterationScope iterationScope(*heap); + list.reset(); + GatherLiveObjFunctor functor(list); + heap->m_objectSpace.forEachLiveCell(iterationScope, functor); +} + +LiveObjectList* HeapVerifier::liveObjectListForGathering(HeapVerifier::Phase phase) +{ + switch (phase) { + case Phase::BeforeMarking: + return ¤tCycle().before; + case Phase::AfterMarking: + return ¤tCycle().after; + case Phase::BeforeGC: + case Phase::AfterGC: + // We should not be gathering live objects during these phases. + break; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; // Silencing a compiler warning. +} + +static void trimDeadObjectsFromList(HashSet<JSObject*>& knownLiveSet, LiveObjectList& list) +{ + if (!list.hasLiveObjects) + return; + + size_t liveObjectsFound = 0; + for (size_t i = 0; i < list.liveObjects.size(); i++) { + LiveObjectData& objData = list.liveObjects[i]; + if (objData.isConfirmedDead) + continue; // Don't "resurrect" known dead objects. + if (!knownLiveSet.contains(objData.obj)) { + objData.isConfirmedDead = true; + continue; + } + liveObjectsFound++; + } + list.hasLiveObjects = !!liveObjectsFound; +} + +void HeapVerifier::trimDeadObjects() +{ + HashSet<JSObject*> knownLiveSet; + + LiveObjectList& after = currentCycle().after; + for (size_t i = 0; i < after.liveObjects.size(); i++) { + LiveObjectData& objData = after.liveObjects[i]; + knownLiveSet.add(objData.obj); + } + + trimDeadObjectsFromList(knownLiveSet, currentCycle().before); + + for (int i = -1; i > -m_numberOfCycles; i--) { + trimDeadObjectsFromList(knownLiveSet, cycleForIndex(i).before); + trimDeadObjectsFromList(knownLiveSet, cycleForIndex(i).after); + } +} + +bool HeapVerifier::verifyButterflyIsInStorageSpace(Phase phase, LiveObjectList& list) +{ + auto& liveObjects = list.liveObjects; + + CopiedSpace& storageSpace = m_heap->m_storageSpace; + bool listNamePrinted = false; + bool success = true; + for (size_t i = 0; i < liveObjects.size(); i++) { + LiveObjectData& objectData = liveObjects[i]; + if (objectData.isConfirmedDead) + continue; + + JSObject* obj = objectData.obj; + Butterfly* butterfly = obj->butterfly(); + if (butterfly) { + void* butterflyBase; + size_t butterflyCapacityInBytes; + CopiedBlock* butterflyBlock; + getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock); + + if (!storageSpace.contains(butterflyBlock)) { + if (!listNamePrinted) { + dataLogF("Verification @ phase %s FAILED in object list '%s' (size %zu)\n", + phaseName(phase), list.name, liveObjects.size()); + listNamePrinted = true; + } + + Structure* structure = obj->structure(); + const char* structureClassName = structure->classInfo()->className; + dataLogF(" butterfly %p (base %p size %zu block %p) NOT in StorageSpace | obj %p type '%s'\n", + butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, obj, structureClassName); + success = false; + } + } + } + return success; +} + +void HeapVerifier::verify(HeapVerifier::Phase phase) +{ + bool beforeVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().before); + bool afterVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().after); + RELEASE_ASSERT(beforeVerified && afterVerified); +} + +void HeapVerifier::reportObject(LiveObjectData& objData, int cycleIndex, HeapVerifier::GCCycle& cycle, LiveObjectList& list) +{ + JSObject* obj = objData.obj; + + if (objData.isConfirmedDead) { + dataLogF("FOUND dead obj %p in GC[%d] %s list '%s'\n", + obj, cycleIndex, cycle.collectionTypeName(), list.name); + return; + } + + Structure* structure = obj->structure(); + Butterfly* butterfly = obj->butterfly(); + void* butterflyBase; + size_t butterflyCapacityInBytes; + CopiedBlock* butterflyBlock; + getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock); + + dataLogF("FOUND obj %p type '%s' butterfly %p (base %p size %zu block %p) in GC[%d] %s list '%s'\n", + obj, structure->classInfo()->className, + butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, + cycleIndex, cycle.collectionTypeName(), list.name); +} + +void HeapVerifier::checkIfRecorded(JSObject* obj) +{ + bool found = false; + + for (int cycleIndex = 0; cycleIndex > -m_numberOfCycles; cycleIndex--) { + GCCycle& cycle = cycleForIndex(cycleIndex); + LiveObjectList& beforeList = cycle.before; + LiveObjectList& afterList = cycle.after; + + LiveObjectData* objData; + objData = beforeList.findObject(obj); + if (objData) { + reportObject(*objData, cycleIndex, cycle, beforeList); + found = true; + } + objData = afterList.findObject(obj); + if (objData) { + reportObject(*objData, cycleIndex, cycle, afterList); + found = true; + } + } + + if (!found) + dataLogF("obj %p NOT FOUND\n", obj); +} + +} // namespace JSC diff --git a/heap/HeapVerifier.h b/heap/HeapVerifier.h new file mode 100644 index 0000000..f6ec1d9 --- /dev/null +++ b/heap/HeapVerifier.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 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 HeapVerifier_h +#define HeapVerifier_h + +#include "Heap.h" +#include <wtf/Vector.h> + +namespace JSC { + +class JSObject; +class MarkedBlock; + +struct LiveObjectData { + LiveObjectData(JSObject* obj, bool isConfirmedDead = false) + : obj(obj) + , isConfirmedDead(isConfirmedDead) + { + } + + JSObject* obj; + bool isConfirmedDead; +}; + +struct LiveObjectList { + LiveObjectList(const char* name) + : name(name) + , hasLiveObjects(true) + { + } + + void reset() + { + liveObjects.clear(); + hasLiveObjects = true; // Presume to have live objects until the list is trimmed. + } + + LiveObjectData* findObject(JSObject*); + + const char* name; + Vector<LiveObjectData> liveObjects; + bool hasLiveObjects; +}; + +class HeapVerifier { +public: + enum class Phase { + BeforeGC, + BeforeMarking, + AfterMarking, + AfterGC + }; + + HeapVerifier(Heap*, unsigned numberOfGCCyclesToRecord); + + void initializeGCCycle(); + void gatherLiveObjects(Phase); + void trimDeadObjects(); + void verify(Phase); + + // Scans all previously recorded LiveObjectLists and checks if the specified + // object was in any of those lists. + JS_EXPORT_PRIVATE void checkIfRecorded(JSObject*); + + static const char* collectionTypeName(HeapOperation); + static const char* phaseName(Phase); + +private: + struct GCCycle { + GCCycle() + : before("Before Marking") + , after("After Marking") + { + } + + HeapOperation collectionType; + LiveObjectList before; + LiveObjectList after; + + const char* collectionTypeName() const + { + return HeapVerifier::collectionTypeName(collectionType); + } + }; + + void incrementCycle() { m_currentCycle = (m_currentCycle + 1) % m_numberOfCycles; } + GCCycle& currentCycle() { return m_cycles[m_currentCycle]; } + GCCycle& cycleForIndex(int cycleIndex) + { + ASSERT(cycleIndex <= 0 && cycleIndex > -m_numberOfCycles); + cycleIndex += m_currentCycle; + if (cycleIndex < 0) + cycleIndex += m_numberOfCycles; + ASSERT(cycleIndex < m_numberOfCycles); + return m_cycles[cycleIndex]; + } + + LiveObjectList* liveObjectListForGathering(Phase); + bool verifyButterflyIsInStorageSpace(Phase, LiveObjectList&); + + static void reportObject(LiveObjectData&, int cycleIndex, HeapVerifier::GCCycle&, LiveObjectList&); + + Heap* m_heap; + int m_currentCycle; + int m_numberOfCycles; + std::unique_ptr<GCCycle[]> m_cycles; +}; + +} // namespace JSC + +#endif // HeapVerifier diff --git a/heap/IncrementalSweeper.cpp b/heap/IncrementalSweeper.cpp index 76cec8f..e0783d6 100644 --- a/heap/IncrementalSweeper.cpp +++ b/heap/IncrementalSweeper.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "IncrementalSweeper.h" -#include "DelayedReleaseScope.h" #include "Heap.h" #include "JSObject.h" #include "JSString.h" @@ -46,16 +45,10 @@ static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal; IncrementalSweeper::IncrementalSweeper(Heap* heap, CFRunLoopRef runLoop) : HeapTimer(heap->vm(), runLoop) - , m_currentBlockToSweepIndex(0) , m_blocksToSweep(heap->m_blockSnapshot) { } -PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap* heap) -{ - return adoptPtr(new IncrementalSweeper(heap, CFRunLoopGetCurrent())); -} - void IncrementalSweeper::scheduleTimer() { CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + (sweepTimeSlice * sweepTimeMultiplier)); @@ -73,10 +66,7 @@ void IncrementalSweeper::doWork() void IncrementalSweeper::doSweep(double sweepBeginTime) { - DelayedReleaseScope scope(m_vm->heap.m_objectSpace); - while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) { - sweepNextBlock(); - + while (sweepNextBlock()) { double elapsedTime = WTF::monotonicallyIncreasingTime() - sweepBeginTime; if (elapsedTime < sweepTimeSlice) continue; @@ -89,30 +79,30 @@ void IncrementalSweeper::doSweep(double sweepBeginTime) cancelTimer(); } -void IncrementalSweeper::sweepNextBlock() +bool IncrementalSweeper::sweepNextBlock() { - while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) { - MarkedBlock* block = m_blocksToSweep[m_currentBlockToSweepIndex++]; + while (!m_blocksToSweep.isEmpty()) { + MarkedBlock* block = m_blocksToSweep.takeLast(); if (!block->needsSweeping()) continue; + DeferGCForAWhile deferGC(m_vm->heap); block->sweep(); m_vm->heap.objectSpace().freeOrShrinkBlock(block); - return; + return true; } + + return m_vm->heap.sweepNextLogicallyEmptyWeakBlock(); } -void IncrementalSweeper::startSweeping(Vector<MarkedBlock*>& blockSnapshot) +void IncrementalSweeper::startSweeping() { - m_blocksToSweep = blockSnapshot; - m_currentBlockToSweepIndex = 0; scheduleTimer(); } void IncrementalSweeper::willFinishSweeping() { - m_currentBlockToSweepIndex = 0; m_blocksToSweep.clear(); if (m_vm) cancelTimer(); @@ -129,12 +119,7 @@ void IncrementalSweeper::doWork() { } -PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap* heap) -{ - return adoptPtr(new IncrementalSweeper(heap->vm())); -} - -void IncrementalSweeper::startSweeping(Vector<MarkedBlock*>&) +void IncrementalSweeper::startSweeping() { } @@ -142,8 +127,9 @@ void IncrementalSweeper::willFinishSweeping() { } -void IncrementalSweeper::sweepNextBlock() +bool IncrementalSweeper::sweepNextBlock() { + return false; } #endif diff --git a/heap/IncrementalSweeper.h b/heap/IncrementalSweeper.h index 0ac145c..a86fd1c 100644 --- a/heap/IncrementalSweeper.h +++ b/heap/IncrementalSweeper.h @@ -27,7 +27,6 @@ #define IncrementalSweeper_h #include "HeapTimer.h" -#include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> namespace JSC { @@ -36,27 +35,26 @@ class Heap; class MarkedBlock; class IncrementalSweeper : public HeapTimer { + WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<IncrementalSweeper> create(Heap*); - void startSweeping(Vector<MarkedBlock*>&); - JS_EXPORT_PRIVATE virtual void doWork() override; - void sweepNextBlock(); - void willFinishSweeping(); - -protected: #if USE(CF) JS_EXPORT_PRIVATE IncrementalSweeper(Heap*, CFRunLoopRef); #else - IncrementalSweeper(VM*); + explicit IncrementalSweeper(VM*); #endif + void startSweeping(); + + JS_EXPORT_PRIVATE virtual void doWork() override; + bool sweepNextBlock(); + void willFinishSweeping(); + #if USE(CF) private: void doSweep(double startTime); void scheduleTimer(); void cancelTimer(); - unsigned m_currentBlockToSweepIndex; Vector<MarkedBlock*>& m_blocksToSweep; #endif }; diff --git a/heap/ListableHandler.h b/heap/ListableHandler.h index 16c3414..560a356 100644 --- a/heap/ListableHandler.h +++ b/heap/ListableHandler.h @@ -23,8 +23,8 @@ #include <stdint.h> #include <wtf/Locker.h> #include <wtf/Noncopyable.h> +#include <wtf/SpinLock.h> #include <wtf/ThreadingPrimitives.h> -#include <wtf/TCSpinLock.h> namespace JSC { @@ -61,7 +61,6 @@ private: List() : m_first(0) { - m_lock.Init(); } void addThreadSafe(T* handler) diff --git a/heap/MachineStackMarker.cpp b/heap/MachineStackMarker.cpp index c354e77..4ae16a9 100644 --- a/heap/MachineStackMarker.cpp +++ b/heap/MachineStackMarker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003-2009, 2015 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Acision BV. All rights reserved. * @@ -69,22 +69,10 @@ using namespace WTF; namespace JSC { -static inline void swapIfBackwards(void*& begin, void*& end) -{ -#if OS(WINCE) - if (begin <= end) - return; - std::swap(begin, end); -#else -UNUSED_PARAM(begin); -UNUSED_PARAM(end); -#endif -} - #if OS(DARWIN) typedef mach_port_t PlatformThread; #elif OS(WINDOWS) -typedef HANDLE PlatformThread; +typedef DWORD PlatformThread; #elif USE(PTHREADS) typedef pthread_t PlatformThread; static const int SigThreadSuspendResume = SIGUSR2; @@ -100,9 +88,78 @@ static void pthreadSignalHandlerSuspendResume(int) #endif #endif +class ActiveMachineThreadsManager; +static ActiveMachineThreadsManager& activeMachineThreadsManager(); + +class ActiveMachineThreadsManager { + WTF_MAKE_NONCOPYABLE(ActiveMachineThreadsManager); +public: + + class Locker { + public: + Locker(ActiveMachineThreadsManager& manager) + : m_locker(manager.m_lock) + { + } + + private: + MutexLocker m_locker; + }; + + void add(MachineThreads* machineThreads) + { + MutexLocker managerLock(m_lock); + m_set.add(machineThreads); + } + + void remove(MachineThreads* machineThreads) + { + MutexLocker managerLock(m_lock); + auto recordedMachineThreads = m_set.take(machineThreads); + RELEASE_ASSERT(recordedMachineThreads = machineThreads); + } + + bool contains(MachineThreads* machineThreads) + { + return m_set.contains(machineThreads); + } + +private: + typedef HashSet<MachineThreads*> MachineThreadsSet; + + ActiveMachineThreadsManager() { } + + Mutex m_lock; + MachineThreadsSet m_set; + + friend ActiveMachineThreadsManager& activeMachineThreadsManager(); +}; + +static ActiveMachineThreadsManager& activeMachineThreadsManager() +{ + static std::once_flag initializeManagerOnceFlag; + static ActiveMachineThreadsManager* manager = nullptr; + + std::call_once(initializeManagerOnceFlag, [] { + manager = new ActiveMachineThreadsManager(); + }); + return *manager; +} + +static inline PlatformThread getCurrentPlatformThread() +{ +#if OS(DARWIN) + return pthread_mach_thread_np(pthread_self()); +#elif OS(WINDOWS) + return GetCurrentThreadId(); +#elif USE(PTHREADS) + return pthread_self(); +#endif +} + class MachineThreads::Thread { WTF_MAKE_FAST_ALLOCATED; -public: + Thread(const PlatformThread& platThread, void* base) : platformThread(platThread) , stackBase(base) @@ -119,12 +176,74 @@ public: sigemptyset(&mask); sigaddset(&mask, SigThreadSuspendResume); pthread_sigmask(SIG_UNBLOCK, &mask, 0); +#elif OS(WINDOWS) + ASSERT(platformThread == GetCurrentThreadId()); + bool isSuccessful = + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &platformThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); + RELEASE_ASSERT(isSuccessful); +#endif + } + +public: + ~Thread() + { +#if OS(WINDOWS) + CloseHandle(platformThreadHandle); #endif } + static Thread* createForCurrentThread() + { + return new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); + } + + struct Registers { + inline void* stackPointer() const; + +#if OS(DARWIN) +#if CPU(X86) + typedef i386_thread_state_t PlatformRegisters; +#elif CPU(X86_64) + typedef x86_thread_state64_t PlatformRegisters; +#elif CPU(PPC) + typedef ppc_thread_state_t PlatformRegisters; +#elif CPU(PPC64) + typedef ppc_thread_state64_t PlatformRegisters; +#elif CPU(ARM) + typedef arm_thread_state_t PlatformRegisters; +#elif CPU(ARM64) + typedef arm_thread_state64_t PlatformRegisters; +#else +#error Unknown Architecture +#endif + +#elif OS(WINDOWS) + typedef CONTEXT PlatformRegisters; +#elif USE(PTHREADS) + typedef pthread_attr_t PlatformRegisters; +#else +#error Need a thread register struct for this platform +#endif + + PlatformRegisters regs; + }; + + inline bool operator==(const PlatformThread& other) const; + inline bool operator!=(const PlatformThread& other) const { return !(*this == other); } + + inline bool suspend(); + inline void resume(); + size_t getRegisters(Registers&); + void freeRegisters(Registers&); + std::pair<void*, size_t> captureStack(void* stackTop); + Thread* next; PlatformThread platformThread; void* stackBase; +#if OS(WINDOWS) + HANDLE platformThreadHandle; +#endif }; MachineThreads::MachineThreads(Heap* heap) @@ -135,12 +254,14 @@ MachineThreads::MachineThreads(Heap* heap) #endif { UNUSED_PARAM(heap); + threadSpecificKeyCreate(&m_threadSpecific, removeThread); + activeMachineThreadsManager().add(this); } MachineThreads::~MachineThreads() { - if (m_threadSpecific) - threadSpecificKeyDelete(m_threadSpecific); + activeMachineThreadsManager().remove(this); + threadSpecificKeyDelete(m_threadSpecific); MutexLocker registeredThreadsLock(m_registeredThreadsMutex); for (Thread* t = m_registeredThreads; t;) { @@ -150,45 +271,28 @@ MachineThreads::~MachineThreads() } } -static inline PlatformThread getCurrentPlatformThread() -{ -#if OS(DARWIN) - return pthread_mach_thread_np(pthread_self()); -#elif OS(WINDOWS) - return GetCurrentThread(); -#elif USE(PTHREADS) - return pthread_self(); -#endif -} - -static inline bool equalThread(const PlatformThread& first, const PlatformThread& second) +inline bool MachineThreads::Thread::operator==(const PlatformThread& other) const { #if OS(DARWIN) || OS(WINDOWS) - return first == second; + return platformThread == other; #elif USE(PTHREADS) - return !!pthread_equal(first, second); + return !!pthread_equal(platformThread, other); #else #error Need a way to compare threads on this platform #endif } -void MachineThreads::makeUsableFromMultipleThreads() -{ - if (m_threadSpecific) - return; - - threadSpecificKeyCreate(&m_threadSpecific, removeThread); -} - void MachineThreads::addCurrentThread() { ASSERT(!m_heap->vm()->hasExclusiveThread() || m_heap->vm()->exclusiveThread() == std::this_thread::get_id()); - if (!m_threadSpecific || threadSpecificGet(m_threadSpecific)) + if (threadSpecificGet(m_threadSpecific)) { + ASSERT(threadSpecificGet(m_threadSpecific) == this); return; + } threadSpecificSet(m_threadSpecific, this); - Thread* thread = new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin()); + Thread* thread = Thread::createForCurrentThread(); MutexLocker lock(m_registeredThreadsMutex); @@ -198,55 +302,56 @@ void MachineThreads::addCurrentThread() void MachineThreads::removeThread(void* p) { - if (p) - static_cast<MachineThreads*>(p)->removeCurrentThread(); + auto& manager = activeMachineThreadsManager(); + ActiveMachineThreadsManager::Locker lock(manager); + auto machineThreads = static_cast<MachineThreads*>(p); + if (manager.contains(machineThreads)) { + // There's a chance that the MachineThreads registry that this thread + // was registered with was already destructed, and another one happened + // to be instantiated at the same address. Hence, this thread may or + // may not be found in this MachineThreads registry. We only need to + // do a removal if this thread is found in it. + machineThreads->removeThreadIfFound(getCurrentPlatformThread()); + } } -void MachineThreads::removeCurrentThread() +template<typename PlatformThread> +void MachineThreads::removeThreadIfFound(PlatformThread platformThread) { - PlatformThread currentPlatformThread = getCurrentPlatformThread(); - MutexLocker lock(m_registeredThreadsMutex); - - if (equalThread(currentPlatformThread, m_registeredThreads->platformThread)) { - Thread* t = m_registeredThreads; + Thread* t = m_registeredThreads; + if (*t == platformThread) { m_registeredThreads = m_registeredThreads->next; delete t; } else { Thread* last = m_registeredThreads; - Thread* t; for (t = m_registeredThreads->next; t; t = t->next) { - if (equalThread(t->platformThread, currentPlatformThread)) { + if (*t == platformThread) { last->next = t->next; break; } last = t; } - ASSERT(t); // If t is NULL, we never found ourselves in the list. delete t; } } - -void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers) + +void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters) { - void* registersBegin = ®isters; - void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(®isters + 1))); - swapIfBackwards(registersBegin, registersEnd); + void* registersBegin = &calleeSavedRegisters; + void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(&calleeSavedRegisters + 1))); conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks); - void* stackBegin = stackCurrent; - void* stackEnd = wtfThreadData().stack().origin(); - swapIfBackwards(stackBegin, stackEnd); - conservativeRoots.add(stackBegin, stackEnd, jitStubRoutines, codeBlocks); + conservativeRoots.add(stackTop, stackOrigin, jitStubRoutines, codeBlocks); } -static inline bool suspendThread(const PlatformThread& platformThread) +inline bool MachineThreads::Thread::suspend() { #if OS(DARWIN) kern_return_t result = thread_suspend(platformThread); return result == KERN_SUCCESS; #elif OS(WINDOWS) - bool threadIsSuspended = (SuspendThread(platformThread) != (DWORD)-1); + bool threadIsSuspended = (SuspendThread(platformThreadHandle) != (DWORD)-1); ASSERT(threadIsSuspended); return threadIsSuspended; #elif USE(PTHREADS) @@ -257,12 +362,12 @@ static inline bool suspendThread(const PlatformThread& platformThread) #endif } -static inline void resumeThread(const PlatformThread& platformThread) +inline void MachineThreads::Thread::resume() { #if OS(DARWIN) thread_resume(platformThread); #elif OS(WINDOWS) - ResumeThread(platformThread); + ResumeThread(platformThreadHandle); #elif USE(PTHREADS) pthread_kill(platformThread, SigThreadSuspendResume); #else @@ -270,38 +375,10 @@ static inline void resumeThread(const PlatformThread& platformThread) #endif } -typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit - -#if OS(DARWIN) - -#if CPU(X86) -typedef i386_thread_state_t PlatformThreadRegisters; -#elif CPU(X86_64) -typedef x86_thread_state64_t PlatformThreadRegisters; -#elif CPU(PPC) -typedef ppc_thread_state_t PlatformThreadRegisters; -#elif CPU(PPC64) -typedef ppc_thread_state64_t PlatformThreadRegisters; -#elif CPU(ARM) -typedef arm_thread_state_t PlatformThreadRegisters; -#elif CPU(ARM64) -typedef arm_thread_state64_t PlatformThreadRegisters; -#else -#error Unknown Architecture -#endif - -#elif OS(WINDOWS) -typedef CONTEXT PlatformThreadRegisters; -#elif USE(PTHREADS) -typedef pthread_attr_t PlatformThreadRegisters; -#else -#error Need a thread register struct for this platform -#endif - -static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) +size_t MachineThreads::Thread::getRegisters(MachineThreads::Thread::Registers& registers) { + Thread::Registers::PlatformRegisters& regs = registers.regs; #if OS(DARWIN) - #if CPU(X86) unsigned user_count = sizeof(regs)/sizeof(int); thread_state_flavor_t flavor = i386_THREAD_STATE; @@ -330,12 +407,12 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result); CRASH(); } - return user_count * sizeof(usword_t); + return user_count * sizeof(uintptr_t); // end OS(DARWIN) #elif OS(WINDOWS) regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; - GetThreadContext(platformThread, ®s); + GetThreadContext(platformThreadHandle, ®s); return sizeof(CONTEXT); #elif USE(PTHREADS) pthread_attr_init(®s); @@ -354,7 +431,7 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P #endif } -static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) +inline void* MachineThreads::Thread::Registers::stackPointer() const { #if OS(DARWIN) @@ -422,8 +499,9 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) #endif } -static void freePlatformThreadRegisters(PlatformThreadRegisters& regs) +void MachineThreads::Thread::freeRegisters(MachineThreads::Thread::Registers& registers) { + Thread::Registers::PlatformRegisters& regs = registers.regs; #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) pthread_attr_destroy(®s); #else @@ -431,106 +509,164 @@ static void freePlatformThreadRegisters(PlatformThreadRegisters& regs) #endif } -void MachineThreads::gatherFromOtherThread(ConservativeRoots& conservativeRoots, Thread* thread, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks) +std::pair<void*, size_t> MachineThreads::Thread::captureStack(void* stackTop) { - PlatformThreadRegisters regs; - size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); + void* begin = stackBase; + void* end = reinterpret_cast<void*>( + WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop))); + if (begin > end) + std::swap(begin, end); + return std::make_pair(begin, static_cast<char*>(end) - static_cast<char*>(begin)); +} - conservativeRoots.add(static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize), jitStubRoutines, codeBlocks); +static void copyMemory(void* dst, const void* src, size_t size) +{ + size_t dstAsSize = reinterpret_cast<size_t>(dst); + size_t srcAsSize = reinterpret_cast<size_t>(src); + RELEASE_ASSERT(dstAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(dstAsSize)); + RELEASE_ASSERT(srcAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(srcAsSize)); + RELEASE_ASSERT(size == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(size)); + + intptr_t* dstPtr = reinterpret_cast<intptr_t*>(dst); + const intptr_t* srcPtr = reinterpret_cast<const intptr_t*>(src); + size /= sizeof(intptr_t); + while (size--) + *dstPtr++ = *srcPtr++; +} + + + +// This function must not call malloc(), free(), or any other function that might +// acquire a lock. Since 'thread' is suspended, trying to acquire a lock +// will deadlock if 'thread' holds that lock. +// This function, specifically the memory copying, was causing problems with Address Sanitizer in +// apps. Since we cannot blacklist the system memcpy we must use our own naive implementation, +// copyMemory, for ASan to work on either instrumented or non-instrumented builds. This is not a +// significant performance loss as tryCopyOtherThreadStack is only called as part of an O(heapsize) +// operation. As the heap is generally much larger than the stack the performance hit is minimal. +// See: https://bugs.webkit.org/show_bug.cgi?id=146297 +void MachineThreads::tryCopyOtherThreadStack(Thread* thread, void* buffer, size_t capacity, size_t* size) +{ + Thread::Registers registers; + size_t registersSize = thread->getRegisters(registers); + std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer()); - void* stackPointer = otherThreadStackPointer(regs); - void* stackBase = thread->stackBase; - swapIfBackwards(stackPointer, stackBase); - stackPointer = reinterpret_cast<void*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackPointer))); - conservativeRoots.add(stackPointer, stackBase, jitStubRoutines, codeBlocks); + bool canCopy = *size + registersSize + stack.second <= capacity; - freePlatformThreadRegisters(regs); -} + if (canCopy) + copyMemory(static_cast<char*>(buffer) + *size, ®isters, registersSize); + *size += registersSize; -void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers) -{ - gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackCurrent, registers); + if (canCopy) + copyMemory(static_cast<char*>(buffer) + *size, stack.first, stack.second); + *size += stack.second; - if (m_threadSpecific) { - PlatformThread currentPlatformThread = getCurrentPlatformThread(); + thread->freeRegisters(registers); +} - MutexLocker lock(m_registeredThreadsMutex); +bool MachineThreads::tryCopyOtherThreadStacks(MutexLocker&, void* buffer, size_t capacity, size_t* size) +{ + // Prevent two VMs from suspending each other's threads at the same time, + // which can cause deadlock: <rdar://problem/20300842>. + static StaticSpinLock mutex; + std::lock_guard<StaticSpinLock> lock(mutex); - Thread* threadsToBeDeleted = nullptr; + *size = 0; -#ifndef NDEBUG - // Forbid malloc during the gather phase. The gather phase suspends - // threads, so a malloc during gather would risk a deadlock with a - // thread that had been suspended while holding the malloc lock. - fastMallocForbid(); -#endif - int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet. - int index = 1; - Thread* previousThread = nullptr; - for (Thread* thread = m_registeredThreads; thread; index++) { - if (!equalThread(thread->platformThread, currentPlatformThread)) { - bool success = suspendThread(thread->platformThread); + PlatformThread currentPlatformThread = getCurrentPlatformThread(); + int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet. + int index = 1; + Thread* threadsToBeDeleted = nullptr; + + Thread* previousThread = nullptr; + for (Thread* thread = m_registeredThreads; thread; index++) { + if (*thread != currentPlatformThread) { + bool success = thread->suspend(); #if OS(DARWIN) - if (!success) { - if (!numberOfThreads) { - for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next) - numberOfThreads++; - } - - // Re-do the suspension to get the actual failure result for logging. - kern_return_t error = thread_suspend(thread->platformThread); - ASSERT(error != KERN_SUCCESS); - - WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, - "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.", - error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread)); - - // Put the invalid thread on the threadsToBeDeleted list. - // We can't just delete it here because we have suspended other - // threads, and they may still be holding the C heap lock which - // we need for deleting the invalid thread. Hence, we need to - // defer the deletion till after we have resumed all threads. - Thread* nextThread = thread->next; - thread->next = threadsToBeDeleted; - threadsToBeDeleted = thread; - - if (previousThread) - previousThread->next = nextThread; - else - m_registeredThreads = nextThread; - thread = nextThread; - continue; + if (!success) { + if (!numberOfThreads) { + for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next) + numberOfThreads++; } + + // Re-do the suspension to get the actual failure result for logging. + kern_return_t error = thread_suspend(thread->platformThread); + ASSERT(error != KERN_SUCCESS); + + WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, + "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.", + error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread)); + + // Put the invalid thread on the threadsToBeDeleted list. + // We can't just delete it here because we have suspended other + // threads, and they may still be holding the C heap lock which + // we need for deleting the invalid thread. Hence, we need to + // defer the deletion till after we have resumed all threads. + Thread* nextThread = thread->next; + thread->next = threadsToBeDeleted; + threadsToBeDeleted = thread; + + if (previousThread) + previousThread->next = nextThread; + else + m_registeredThreads = nextThread; + thread = nextThread; + continue; + } #else - UNUSED_PARAM(numberOfThreads); - ASSERT_UNUSED(success, success); + UNUSED_PARAM(numberOfThreads); + UNUSED_PARAM(previousThread); + ASSERT_UNUSED(success, success); #endif - } - previousThread = thread; - thread = thread->next; } + previousThread = thread; + thread = thread->next; + } - // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, - // and since this is a shared heap, they are real locks. - for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { - if (!equalThread(thread->platformThread, currentPlatformThread)) - gatherFromOtherThread(conservativeRoots, thread, jitStubRoutines, codeBlocks); - } + for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { + if (*thread != currentPlatformThread) + tryCopyOtherThreadStack(thread, buffer, capacity, size); + } - for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { - if (!equalThread(thread->platformThread, currentPlatformThread)) - resumeThread(thread->platformThread); - } + for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { + if (*thread != currentPlatformThread) + thread->resume(); + } -#ifndef NDEBUG - fastMallocAllow(); -#endif - for (Thread* thread = threadsToBeDeleted; thread; ) { - Thread* nextThread = thread->next; - delete thread; - thread = nextThread; - } + for (Thread* thread = threadsToBeDeleted; thread; ) { + Thread* nextThread = thread->next; + delete thread; + thread = nextThread; } + + return *size <= capacity; +} + +static void growBuffer(size_t size, void** buffer, size_t* capacity) +{ + if (*buffer) + fastFree(*buffer); + + *capacity = WTF::roundUpToMultipleOf(WTF::pageSize(), size * 2); + *buffer = fastMalloc(*capacity); +} + +void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters) +{ + gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackOrigin, stackTop, calleeSavedRegisters); + + size_t size; + size_t capacity = 0; + void* buffer = nullptr; + MutexLocker lock(m_registeredThreadsMutex); + while (!tryCopyOtherThreadStacks(lock, buffer, capacity, &size)) + growBuffer(size, &buffer, &capacity); + + if (!buffer) + return; + + conservativeRoots.add(buffer, static_cast<char*>(buffer) + size, jitStubRoutines, codeBlocks); + fastFree(buffer); } } // namespace JSC diff --git a/heap/MachineStackMarker.h b/heap/MachineStackMarker.h index 22b1d22..9b6b732 100644 --- a/heap/MachineStackMarker.h +++ b/heap/MachineStackMarker.h @@ -42,20 +42,22 @@ namespace JSC { MachineThreads(Heap*); ~MachineThreads(); - void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackCurrent, RegisterState& registers); + void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters); - JS_EXPORT_PRIVATE void makeUsableFromMultipleThreads(); JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads. private: - void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackCurrent, RegisterState& registers); - class Thread; + void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters); + + void tryCopyOtherThreadStack(Thread*, void*, size_t capacity, size_t*); + bool tryCopyOtherThreadStacks(MutexLocker&, void*, size_t capacity, size_t*); + static void removeThread(void*); - void removeCurrentThread(); - void gatherFromOtherThread(ConservativeRoots&, Thread*, JITStubRoutineSet&, CodeBlockSet&); + template<typename PlatformThread> + void removeThreadIfFound(PlatformThread); Mutex m_registeredThreadsMutex; Thread* m_registeredThreads; diff --git a/heap/MarkStack.cpp b/heap/MarkStack.cpp index 66201f4..da6ef94 100644 --- a/heap/MarkStack.cpp +++ b/heap/MarkStack.cpp @@ -30,8 +30,8 @@ namespace JSC { -MarkStackArray::MarkStackArray(BlockAllocator& blockAllocator) - : GCSegmentedArray<const JSCell*>(blockAllocator) +MarkStackArray::MarkStackArray() + : GCSegmentedArray<const JSCell*>() { } diff --git a/heap/MarkStack.h b/heap/MarkStack.h index 17a6019..04f19c6 100644 --- a/heap/MarkStack.h +++ b/heap/MarkStack.h @@ -34,7 +34,7 @@ class JSCell; class MarkStackArray : public GCSegmentedArray<const JSCell*> { public: - MarkStackArray(BlockAllocator&); + MarkStackArray(); void donateSomeCellsTo(MarkStackArray& other); void stealSomeCellsFrom(MarkStackArray& other, size_t idleThreadCount); diff --git a/heap/MarkedAllocator.cpp b/heap/MarkedAllocator.cpp index b8f01fd..2dbf8ae 100644 --- a/heap/MarkedAllocator.cpp +++ b/heap/MarkedAllocator.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "MarkedAllocator.h" -#include "DelayedReleaseScope.h" #include "GCActivityCallback.h" #include "Heap.h" #include "IncrementalSweeper.h" @@ -62,46 +61,40 @@ bool MarkedAllocator::isPagedOut(double deadline) inline void* MarkedAllocator::tryAllocateHelper(size_t bytes) { - // We need a while loop to check the free list because the DelayedReleaseScope - // could cause arbitrary code to execute and exhaust the free list that we - // thought had elements in it. - while (!m_freeList.head) { - DelayedReleaseScope delayedReleaseScope(*m_markedSpace); - if (m_currentBlock) { - ASSERT(m_currentBlock == m_nextBlockToSweep); - m_currentBlock->didConsumeFreeList(); - m_nextBlockToSweep = m_currentBlock->next(); - } + if (m_currentBlock) { + ASSERT(m_currentBlock == m_nextBlockToSweep); + m_currentBlock->didConsumeFreeList(); + m_nextBlockToSweep = m_currentBlock->next(); + } - MarkedBlock* next; - for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) { - next = block->next(); - - MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList); - - double utilization = ((double)MarkedBlock::blockSize - (double)freeList.bytes) / (double)MarkedBlock::blockSize; - if (utilization >= Options::minMarkedBlockUtilization()) { - ASSERT(freeList.bytes || !freeList.head); - m_blockList.remove(block); - m_retiredBlocks.push(block); - block->didRetireBlock(freeList); - continue; - } - - if (bytes > block->cellSize()) { - block->stopAllocating(freeList); - continue; - } - - m_currentBlock = block; - m_freeList = freeList; - break; - } + MarkedBlock* next; + for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) { + next = block->next(); + + MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList); - if (!m_freeList.head) { - m_currentBlock = 0; - return 0; + double utilization = ((double)MarkedBlock::blockSize - (double)freeList.bytes) / (double)MarkedBlock::blockSize; + if (utilization >= Options::minMarkedBlockUtilization()) { + ASSERT(freeList.bytes || !freeList.head); + m_blockList.remove(block); + m_retiredBlocks.push(block); + block->didRetireBlock(freeList); + continue; } + + if (bytes > block->cellSize()) { + block->stopAllocating(freeList); + continue; + } + + m_currentBlock = block; + m_freeList = freeList; + break; + } + + if (!m_freeList.head) { + m_currentBlock = 0; + return 0; } ASSERT(m_freeList.head); @@ -128,17 +121,6 @@ inline void* MarkedAllocator::tryAllocate(size_t bytes) m_heap->m_operationInProgress = Allocation; void* result = tryAllocateHelper(bytes); - // Due to the DelayedReleaseScope in tryAllocateHelper, some other thread might have - // created a new block after we thought we didn't find any free cells. - while (!result && m_currentBlock) { - // A new block was added by another thread so try popping the free list. - result = tryPopFreeList(bytes); - if (result) - break; - // The free list was empty, so call tryAllocateHelper to do the normal sweeping stuff. - result = tryAllocateHelper(bytes); - } - m_heap->m_operationInProgress = NoOperation; ASSERT(result || !m_currentBlock); return result; @@ -198,9 +180,7 @@ MarkedBlock* MarkedAllocator::allocateBlock(size_t bytes) size_t cellSize = m_cellSize ? m_cellSize : WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(bytes); - if (blockSize == MarkedBlock::blockSize) - return MarkedBlock::create(m_heap->blockAllocator().allocate<MarkedBlock>(), this, cellSize, m_destructorType); - return MarkedBlock::create(m_heap->blockAllocator().allocateCustomSize(blockSize, MarkedBlock::blockSize), this, cellSize, m_destructorType); + return MarkedBlock::create(this, blockSize, cellSize, m_needsDestruction); } void MarkedAllocator::addBlock(MarkedBlock* block) diff --git a/heap/MarkedAllocator.h b/heap/MarkedAllocator.h index b497f8f..161af48 100644 --- a/heap/MarkedAllocator.h +++ b/heap/MarkedAllocator.h @@ -26,7 +26,7 @@ public: void stopAllocating(); void resumeAllocating(); size_t cellSize() { return m_cellSize; } - MarkedBlock::DestructorType destructorType() { return m_destructorType; } + bool needsDestruction() { return m_needsDestruction; } void* allocate(size_t); Heap* heap() { return m_heap; } MarkedBlock* takeLastActiveBlock() @@ -40,7 +40,7 @@ public: void addBlock(MarkedBlock*); void removeBlock(MarkedBlock*); - void init(Heap*, MarkedSpace*, size_t cellSize, MarkedBlock::DestructorType); + void init(Heap*, MarkedSpace*, size_t cellSize, bool needsDestruction); bool isPagedOut(double deadline); @@ -59,7 +59,7 @@ private: DoublyLinkedList<MarkedBlock> m_blockList; DoublyLinkedList<MarkedBlock> m_retiredBlocks; size_t m_cellSize; - MarkedBlock::DestructorType m_destructorType; + bool m_needsDestruction { false }; Heap* m_heap; MarkedSpace* m_markedSpace; }; @@ -74,18 +74,17 @@ inline MarkedAllocator::MarkedAllocator() , m_lastActiveBlock(0) , m_nextBlockToSweep(0) , m_cellSize(0) - , m_destructorType(MarkedBlock::None) , m_heap(0) , m_markedSpace(0) { } -inline void MarkedAllocator::init(Heap* heap, MarkedSpace* markedSpace, size_t cellSize, MarkedBlock::DestructorType destructorType) +inline void MarkedAllocator::init(Heap* heap, MarkedSpace* markedSpace, size_t cellSize, bool needsDestruction) { m_heap = heap; m_markedSpace = markedSpace; m_cellSize = cellSize; - m_destructorType = destructorType; + m_needsDestruction = needsDestruction; } inline void* MarkedAllocator::allocate(size_t bytes) diff --git a/heap/MarkedBlock.cpp b/heap/MarkedBlock.cpp index f4d39fc..b9c3f9f 100644 --- a/heap/MarkedBlock.cpp +++ b/heap/MarkedBlock.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "MarkedBlock.h" -#include "DelayedReleaseScope.h" #include "IncrementalSweeper.h" #include "JSCell.h" #include "JSDestructibleObject.h" @@ -34,46 +33,53 @@ namespace JSC { -MarkedBlock* MarkedBlock::create(DeadBlock* block, MarkedAllocator* allocator, size_t cellSize, DestructorType destructorType) +MarkedBlock* MarkedBlock::create(MarkedAllocator* allocator, size_t capacity, size_t cellSize, bool needsDestruction) { - ASSERT(reinterpret_cast<size_t>(block) == (reinterpret_cast<size_t>(block) & blockMask)); - Region* region = block->region(); - return new (NotNull, block) MarkedBlock(region, allocator, cellSize, destructorType); + return new (NotNull, fastAlignedMalloc(blockSize, capacity)) MarkedBlock(allocator, capacity, cellSize, needsDestruction); } -MarkedBlock::MarkedBlock(Region* region, MarkedAllocator* allocator, size_t cellSize, DestructorType destructorType) - : HeapBlock<MarkedBlock>(region) +void MarkedBlock::destroy(MarkedBlock* block) +{ + block->~MarkedBlock(); + fastAlignedFree(block); +} + +MarkedBlock::MarkedBlock(MarkedAllocator* allocator, size_t capacity, size_t cellSize, bool needsDestruction) + : DoublyLinkedListNode<MarkedBlock>() , m_atomsPerCell((cellSize + atomSize - 1) / atomSize) - , m_endAtom((allocator->cellSize() ? atomsPerBlock : region->blockSize() / atomSize) - m_atomsPerCell + 1) - , m_destructorType(destructorType) + , m_endAtom((allocator->cellSize() ? atomsPerBlock - m_atomsPerCell : firstAtom()) + 1) + , m_capacity(capacity) + , m_needsDestruction(needsDestruction) , m_allocator(allocator) , m_state(New) // All cells start out unmarked. - , m_weakSet(allocator->heap()->vm()) + , m_weakSet(allocator->heap()->vm(), *this) { ASSERT(allocator); HEAP_LOG_BLOCK_STATE_TRANSITION(this); } -template<MarkedBlock::DestructorType dtorType> inline void MarkedBlock::callDestructor(JSCell* cell) { // A previous eager sweep may already have run cell's destructor. if (cell->isZapped()) return; - if (dtorType == MarkedBlock::Normal) - jsCast<JSDestructibleObject*>(cell)->classInfo()->methodTable.destroy(cell); - else + ASSERT(cell->structureID()); + if (cell->inlineTypeFlags() & StructureIsImmortal) cell->structure(*vm())->classInfo()->methodTable.destroy(cell); + else + jsCast<JSDestructibleObject*>(cell)->classInfo()->methodTable.destroy(cell); cell->zap(); } -template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode, MarkedBlock::DestructorType dtorType> +template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode, bool callDestructors> MarkedBlock::FreeList MarkedBlock::specializedSweep() { ASSERT(blockState != Allocated && blockState != FreeListed); - ASSERT(!(dtorType == MarkedBlock::None && sweepMode == SweepOnly)); + ASSERT(!(!callDestructors && sweepMode == SweepOnly)); + SamplingRegion samplingRegion((!callDestructors && blockState != New) ? "Calling destructors" : "sweeping"); + // This produces a free list that is ordered in reverse through the block. // This is fine, since the allocation code makes no assumptions about the // order of the free list. @@ -85,8 +91,8 @@ MarkedBlock::FreeList MarkedBlock::specializedSweep() JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]); - if (dtorType != MarkedBlock::None && blockState != New) - callDestructor<dtorType>(cell); + if (callDestructors && blockState != New) + callDestructor(cell); if (sweepMode == SweepToFreeList) { FreeCell* freeCell = reinterpret_cast<FreeCell*>(cell); @@ -99,7 +105,7 @@ MarkedBlock::FreeList MarkedBlock::specializedSweep() // We only want to discard the newlyAllocated bits if we're creating a FreeList, // otherwise we would lose information on what's currently alive. if (sweepMode == SweepToFreeList && m_newlyAllocated) - m_newlyAllocated.clear(); + m_newlyAllocated = nullptr; m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Marked); return FreeList(head, count * cellSize()); @@ -107,28 +113,25 @@ MarkedBlock::FreeList MarkedBlock::specializedSweep() MarkedBlock::FreeList MarkedBlock::sweep(SweepMode sweepMode) { - ASSERT(DelayedReleaseScope::isInEffectFor(heap()->m_objectSpace)); HEAP_LOG_BLOCK_STATE_TRANSITION(this); m_weakSet.sweep(); - if (sweepMode == SweepOnly && m_destructorType == MarkedBlock::None) + if (sweepMode == SweepOnly && !m_needsDestruction) return FreeList(); - if (m_destructorType == MarkedBlock::ImmortalStructure) - return sweepHelper<MarkedBlock::ImmortalStructure>(sweepMode); - if (m_destructorType == MarkedBlock::Normal) - return sweepHelper<MarkedBlock::Normal>(sweepMode); - return sweepHelper<MarkedBlock::None>(sweepMode); + if (m_needsDestruction) + return sweepHelper<true>(sweepMode); + return sweepHelper<false>(sweepMode); } -template<MarkedBlock::DestructorType dtorType> +template<bool callDestructors> MarkedBlock::FreeList MarkedBlock::sweepHelper(SweepMode sweepMode) { switch (m_state) { case New: ASSERT(sweepMode == SweepToFreeList); - return specializedSweep<New, SweepToFreeList, dtorType>(); + return specializedSweep<New, SweepToFreeList, callDestructors>(); case FreeListed: // Happens when a block transitions to fully allocated. ASSERT(sweepMode == SweepToFreeList); @@ -139,8 +142,8 @@ MarkedBlock::FreeList MarkedBlock::sweepHelper(SweepMode sweepMode) return FreeList(); case Marked: return sweepMode == SweepToFreeList - ? specializedSweep<Marked, SweepToFreeList, dtorType>() - : specializedSweep<Marked, SweepOnly, dtorType>(); + ? specializedSweep<Marked, SweepToFreeList, callDestructors>() + : specializedSweep<Marked, SweepOnly, callDestructors>(); } RELEASE_ASSERT_NOT_REACHED(); @@ -154,10 +157,11 @@ public: { } - void operator()(JSCell* cell) + IterationStatus operator()(JSCell* cell) { ASSERT(MarkedBlock::blockFor(cell) == m_block); m_block->setNewlyAllocated(cell); + return IterationStatus::Continue; } private: @@ -187,7 +191,7 @@ void MarkedBlock::stopAllocating(const FreeList& freeList) // way to tell what's live vs dead. ASSERT(!m_newlyAllocated); - m_newlyAllocated = adoptPtr(new WTF::Bitmap<atomsPerBlock>()); + m_newlyAllocated = std::make_unique<WTF::Bitmap<atomsPerBlock>>(); SetNewlyAllocatedFunctor functor(this); forEachCell(functor); @@ -214,11 +218,6 @@ void MarkedBlock::clearMarks() #endif } -void MarkedBlock::clearRememberedSet() -{ - m_rememberedSet.clearAll(); -} - template <HeapOperation collectionType> void MarkedBlock::clearMarksWithCollectionType() { @@ -228,9 +227,6 @@ void MarkedBlock::clearMarksWithCollectionType() ASSERT(m_state != New && m_state != FreeListed); if (collectionType == FullCollection) { m_marks.clearAll(); -#if ENABLE(GGC) - m_rememberedSet.clearAll(); -#endif // This will become true at the end of the mark phase. We set it now to // avoid an extra pass to do so later. m_state = Marked; diff --git a/heap/MarkedBlock.h b/heap/MarkedBlock.h index f2626b7..839099d 100644 --- a/heap/MarkedBlock.h +++ b/heap/MarkedBlock.h @@ -22,16 +22,13 @@ #ifndef MarkedBlock_h #define MarkedBlock_h -#include "BlockAllocator.h" -#include "HeapBlock.h" - #include "HeapOperation.h" +#include "IterationStatus.h" #include "WeakSet.h" #include <wtf/Bitmap.h> #include <wtf/DataLog.h> #include <wtf/DoublyLinkedList.h> #include <wtf/HashFunctions.h> -#include <wtf/PageAllocationAligned.h> #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> @@ -69,13 +66,14 @@ namespace JSC { // size is equal to the difference between the cell size and the object // size. - class MarkedBlock : public HeapBlock<MarkedBlock> { + class MarkedBlock : public DoublyLinkedListNode<MarkedBlock> { + friend class WTF::DoublyLinkedListNode<MarkedBlock>; friend class LLIntOffsetsExtractor; friend struct VerifyMarkedOrRetired; public: static const size_t atomSize = 16; // bytes static const size_t atomShiftAmount = 4; // log_2(atomSize) FIXME: Change atomSize to 16. - static const size_t blockSize = 64 * KB; + static const size_t blockSize = 16 * KB; static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two. static const size_t atomsPerBlock = blockSize / atomSize; @@ -112,8 +110,8 @@ namespace JSC { ReturnType m_count; }; - enum DestructorType { None, ImmortalStructure, Normal }; - static MarkedBlock* create(DeadBlock*, MarkedAllocator*, size_t cellSize, DestructorType); + static MarkedBlock* create(MarkedAllocator*, size_t capacity, size_t cellSize, bool needsDestruction); + static void destroy(MarkedBlock*); static bool isAtomAligned(const void*); static MarkedBlock* blockFor(const void*); @@ -147,7 +145,6 @@ namespace JSC { // and was successfully cleared and false otherwise. bool clearNewlyAllocated(); void clearMarks(); - void clearRememberedSet(); template <HeapOperation collectionType> void clearMarksWithCollectionType(); @@ -155,7 +152,7 @@ namespace JSC { bool isEmpty(); size_t cellSize(); - DestructorType destructorType(); + bool needsDestruction() const; size_t size(); size_t capacity(); @@ -164,6 +161,7 @@ namespace JSC { bool testAndSetMarked(const void*); bool isLive(const JSCell*); bool isLiveCell(const void*); + bool isMarkedOrNewlyAllocated(const JSCell*); void setMarked(const void*); void clearMarked(const void*); @@ -176,13 +174,14 @@ namespace JSC { void setNewlyAllocated(const void*); void clearNewlyAllocated(const void*); + bool isAllocated() const; bool needsSweeping(); void didRetireBlock(const FreeList&); void willRemoveBlock(); - template <typename Functor> void forEachCell(Functor&); - template <typename Functor> void forEachLiveCell(Functor&); - template <typename Functor> void forEachDeadCell(Functor&); + template <typename Functor> IterationStatus forEachCell(Functor&); + template <typename Functor> IterationStatus forEachLiveCell(Functor&); + template <typename Functor> IterationStatus forEachDeadCell(Functor&); static ptrdiff_t offsetOfMarks() { return OBJECT_OFFSETOF(MarkedBlock, m_marks); } @@ -190,28 +189,30 @@ namespace JSC { static const size_t atomAlignmentMask = atomSize - 1; // atomSize must be a power of two. enum BlockState { New, FreeListed, Allocated, Marked, Retired }; - template<DestructorType> FreeList sweepHelper(SweepMode = SweepOnly); + template<bool callDestructors> FreeList sweepHelper(SweepMode = SweepOnly); typedef char Atom[atomSize]; - MarkedBlock(Region*, MarkedAllocator*, size_t cellSize, DestructorType); + MarkedBlock(MarkedAllocator*, size_t capacity, size_t cellSize, bool needsDestruction); Atom* atoms(); size_t atomNumber(const void*); - template<DestructorType> void callDestructor(JSCell*); - template<BlockState, SweepMode, DestructorType> FreeList specializedSweep(); + void callDestructor(JSCell*); + template<BlockState, SweepMode, bool callDestructors> FreeList specializedSweep(); + MarkedBlock* m_prev; + MarkedBlock* m_next; + size_t m_atomsPerCell; size_t m_endAtom; // This is a fuzzy end. Always test for < m_endAtom. #if ENABLE(PARALLEL_GC) WTF::Bitmap<atomsPerBlock, WTF::BitmapAtomic, uint8_t> m_marks; - WTF::Bitmap<atomsPerBlock, WTF::BitmapAtomic, uint8_t> m_rememberedSet; #else WTF::Bitmap<atomsPerBlock, WTF::BitmapNotAtomic, uint8_t> m_marks; - WTF::Bitmap<atomsPerBlock, WTF::BitmapNotAtomic, uint8_t> m_rememberedSet; #endif - OwnPtr<WTF::Bitmap<atomsPerBlock>> m_newlyAllocated; + std::unique_ptr<WTF::Bitmap<atomsPerBlock>> m_newlyAllocated; - DestructorType m_destructorType; + size_t m_capacity; + bool m_needsDestruction; MarkedAllocator* m_allocator; BlockState m_state; WeakSet m_weakSet; @@ -321,9 +322,9 @@ namespace JSC { return m_atomsPerCell * atomSize; } - inline MarkedBlock::DestructorType MarkedBlock::destructorType() + inline bool MarkedBlock::needsDestruction() const { - return m_destructorType; + return m_needsDestruction; } inline size_t MarkedBlock::size() @@ -333,7 +334,7 @@ namespace JSC { inline size_t MarkedBlock::capacity() { - return region()->blockSize(); + return m_capacity; } inline size_t MarkedBlock::atomNumber(const void* p) @@ -341,26 +342,6 @@ namespace JSC { return (reinterpret_cast<Bits>(p) - reinterpret_cast<Bits>(this)) / atomSize; } - inline void MarkedBlock::setRemembered(const void* p) - { - m_rememberedSet.set(atomNumber(p)); - } - - inline void MarkedBlock::clearRemembered(const void* p) - { - m_rememberedSet.clear(atomNumber(p)); - } - - inline void MarkedBlock::atomicClearRemembered(const void* p) - { - m_rememberedSet.concurrentTestAndClear(atomNumber(p)); - } - - inline bool MarkedBlock::isRemembered(const void* p) - { - return m_rememberedSet.get(atomNumber(p)); - } - inline bool MarkedBlock::isMarked(const void* p) { return m_marks.get(atomNumber(p)); @@ -400,12 +381,18 @@ namespace JSC { inline bool MarkedBlock::clearNewlyAllocated() { if (m_newlyAllocated) { - m_newlyAllocated.clear(); + m_newlyAllocated = nullptr; return true; } return false; } + inline bool MarkedBlock::isMarkedOrNewlyAllocated(const JSCell* cell) + { + ASSERT(m_state == Retired || m_state == Marked); + return m_marks.get(atomNumber(cell)) || (m_newlyAllocated && isNewlyAllocated(cell)); + } + inline bool MarkedBlock::isLive(const JSCell* cell) { switch (m_state) { @@ -414,7 +401,7 @@ namespace JSC { case Retired: case Marked: - return m_marks.get(atomNumber(cell)) || (m_newlyAllocated && isNewlyAllocated(cell)); + return isMarkedOrNewlyAllocated(cell); case New: case FreeListed: @@ -441,34 +428,40 @@ namespace JSC { return isLive(static_cast<const JSCell*>(p)); } - template <typename Functor> inline void MarkedBlock::forEachCell(Functor& functor) + template <typename Functor> inline IterationStatus MarkedBlock::forEachCell(Functor& functor) { for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) { JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]); - functor(cell); + if (functor(cell) == IterationStatus::Done) + return IterationStatus::Done; } + return IterationStatus::Continue; } - template <typename Functor> inline void MarkedBlock::forEachLiveCell(Functor& functor) + template <typename Functor> inline IterationStatus MarkedBlock::forEachLiveCell(Functor& functor) { for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) { JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]); if (!isLive(cell)) continue; - functor(cell); + if (functor(cell) == IterationStatus::Done) + return IterationStatus::Done; } + return IterationStatus::Continue; } - template <typename Functor> inline void MarkedBlock::forEachDeadCell(Functor& functor) + template <typename Functor> inline IterationStatus MarkedBlock::forEachDeadCell(Functor& functor) { for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) { JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]); if (isLive(cell)) continue; - functor(cell); + if (functor(cell) == IterationStatus::Done) + return IterationStatus::Done; } + return IterationStatus::Continue; } inline bool MarkedBlock::needsSweeping() @@ -476,6 +469,11 @@ namespace JSC { return m_state == Marked; } + inline bool MarkedBlock::isAllocated() const + { + return m_state == Allocated; + } + } // namespace JSC namespace WTF { diff --git a/heap/MarkedBlockSet.h b/heap/MarkedBlockSet.h index 022a173..9cf1908 100644 --- a/heap/MarkedBlockSet.h +++ b/heap/MarkedBlockSet.h @@ -57,7 +57,7 @@ inline void MarkedBlockSet::add(MarkedBlock* block) inline void MarkedBlockSet::remove(MarkedBlock* block) { - int oldCapacity = m_set.capacity(); + unsigned oldCapacity = m_set.capacity(); m_set.remove(block); if (m_set.capacity() != oldCapacity) // Indicates we've removed a lot of blocks. recomputeFilter(); diff --git a/heap/MarkedSpace.cpp b/heap/MarkedSpace.cpp index 8a8fbf6..4f30890 100644 --- a/heap/MarkedSpace.cpp +++ b/heap/MarkedSpace.cpp @@ -21,7 +21,6 @@ #include "config.h" #include "MarkedSpace.h" -#include "DelayedReleaseScope.h" #include "IncrementalSweeper.h" #include "JSGlobalObject.h" #include "JSLock.h" @@ -82,23 +81,19 @@ MarkedSpace::MarkedSpace(Heap* heap) : m_heap(heap) , m_capacity(0) , m_isIterating(false) - , m_currentDelayedReleaseScope(nullptr) { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { - allocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::None); - normalDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::Normal); - immortalStructureDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::ImmortalStructure); + allocatorFor(cellSize).init(heap, this, cellSize, false); + destructorAllocatorFor(cellSize).init(heap, this, cellSize, true); } for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) { - allocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::None); - normalDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::Normal); - immortalStructureDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::ImmortalStructure); + allocatorFor(cellSize).init(heap, this, cellSize, false); + destructorAllocatorFor(cellSize).init(heap, this, cellSize, true); } - m_normalSpace.largeAllocator.init(heap, this, 0, MarkedBlock::None); - m_normalDestructorSpace.largeAllocator.init(heap, this, 0, MarkedBlock::Normal); - m_immortalStructureDestructorSpace.largeAllocator.init(heap, this, 0, MarkedBlock::ImmortalStructure); + m_normalSpace.largeAllocator.init(heap, this, 0, false); + m_destructorSpace.largeAllocator.init(heap, this, 0, true); } MarkedSpace::~MarkedSpace() @@ -114,15 +109,12 @@ struct LastChanceToFinalize { void MarkedSpace::lastChanceToFinalize() { - DelayedReleaseScope delayedReleaseScope(*this); stopAllocating(); forEachAllocator<LastChanceToFinalize>(); } void MarkedSpace::sweep() { - if (Options::logGC()) - dataLog("Eagerly sweeping..."); m_heap->sweeper()->willFinishSweeping(); forEachBlock<Sweep>(); } @@ -139,19 +131,16 @@ void MarkedSpace::resetAllocators() { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { allocatorFor(cellSize).reset(); - normalDestructorAllocatorFor(cellSize).reset(); - immortalStructureDestructorAllocatorFor(cellSize).reset(); + destructorAllocatorFor(cellSize).reset(); } for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) { allocatorFor(cellSize).reset(); - normalDestructorAllocatorFor(cellSize).reset(); - immortalStructureDestructorAllocatorFor(cellSize).reset(); + destructorAllocatorFor(cellSize).reset(); } m_normalSpace.largeAllocator.reset(); - m_normalDestructorSpace.largeAllocator.reset(); - m_immortalStructureDestructorSpace.largeAllocator.reset(); + m_destructorSpace.largeAllocator.reset(); #if ENABLE(GGC) m_blocksWithNewObjects.clear(); @@ -189,19 +178,16 @@ void MarkedSpace::forEachAllocator(Functor& functor) { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { functor(allocatorFor(cellSize)); - functor(normalDestructorAllocatorFor(cellSize)); - functor(immortalStructureDestructorAllocatorFor(cellSize)); + functor(destructorAllocatorFor(cellSize)); } for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) { functor(allocatorFor(cellSize)); - functor(normalDestructorAllocatorFor(cellSize)); - functor(immortalStructureDestructorAllocatorFor(cellSize)); + functor(destructorAllocatorFor(cellSize)); } functor(m_normalSpace.largeAllocator); - functor(m_normalDestructorSpace.largeAllocator); - functor(m_immortalStructureDestructorSpace.largeAllocator); + functor(m_destructorSpace.largeAllocator); } struct StopAllocatingFunctor { @@ -228,21 +214,18 @@ bool MarkedSpace::isPagedOut(double deadline) { for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { if (allocatorFor(cellSize).isPagedOut(deadline) - || normalDestructorAllocatorFor(cellSize).isPagedOut(deadline) - || immortalStructureDestructorAllocatorFor(cellSize).isPagedOut(deadline)) + || destructorAllocatorFor(cellSize).isPagedOut(deadline)) return true; } for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) { if (allocatorFor(cellSize).isPagedOut(deadline) - || normalDestructorAllocatorFor(cellSize).isPagedOut(deadline) - || immortalStructureDestructorAllocatorFor(cellSize).isPagedOut(deadline)) + || destructorAllocatorFor(cellSize).isPagedOut(deadline)) return true; } if (m_normalSpace.largeAllocator.isPagedOut(deadline) - || m_normalDestructorSpace.largeAllocator.isPagedOut(deadline) - || m_immortalStructureDestructorSpace.largeAllocator.isPagedOut(deadline)) + || m_destructorSpace.largeAllocator.isPagedOut(deadline)) return true; return false; @@ -253,11 +236,7 @@ void MarkedSpace::freeBlock(MarkedBlock* block) block->allocator()->removeBlock(block); m_capacity -= block->capacity(); m_blocks.remove(block); - if (block->capacity() == MarkedBlock::blockSize) { - m_heap->blockAllocator().deallocate(MarkedBlock::destroy(block)); - return; - } - m_heap->blockAllocator().deallocateCustomSize(MarkedBlock::destroy(block)); + MarkedBlock::destroy(block); } void MarkedSpace::freeOrShrinkBlock(MarkedBlock* block) @@ -301,14 +280,12 @@ void MarkedSpace::clearNewlyAllocated() { for (size_t i = 0; i < preciseCount; ++i) { clearNewlyAllocatedInBlock(m_normalSpace.preciseAllocators[i].takeLastActiveBlock()); - clearNewlyAllocatedInBlock(m_normalDestructorSpace.preciseAllocators[i].takeLastActiveBlock()); - clearNewlyAllocatedInBlock(m_immortalStructureDestructorSpace.preciseAllocators[i].takeLastActiveBlock()); + clearNewlyAllocatedInBlock(m_destructorSpace.preciseAllocators[i].takeLastActiveBlock()); } for (size_t i = 0; i < impreciseCount; ++i) { clearNewlyAllocatedInBlock(m_normalSpace.impreciseAllocators[i].takeLastActiveBlock()); - clearNewlyAllocatedInBlock(m_normalDestructorSpace.impreciseAllocators[i].takeLastActiveBlock()); - clearNewlyAllocatedInBlock(m_immortalStructureDestructorSpace.impreciseAllocators[i].takeLastActiveBlock()); + clearNewlyAllocatedInBlock(m_destructorSpace.impreciseAllocators[i].takeLastActiveBlock()); } // We have to iterate all of the blocks in the large allocators because they are @@ -316,8 +293,7 @@ void MarkedSpace::clearNewlyAllocated() // which creates the m_newlyAllocated bitmap. ClearNewlyAllocated functor; m_normalSpace.largeAllocator.forEachBlock(functor); - m_normalDestructorSpace.largeAllocator.forEachBlock(functor); - m_immortalStructureDestructorSpace.largeAllocator.forEachBlock(functor); + m_destructorSpace.largeAllocator.forEachBlock(functor); #ifndef NDEBUG VerifyNewlyAllocated verifyFunctor; @@ -364,7 +340,6 @@ void MarkedSpace::willStartIterating() void MarkedSpace::didFinishIterating() { ASSERT(isIterating()); - DelayedReleaseScope scope(*this); resumeAllocating(); m_isIterating = false; } diff --git a/heap/MarkedSpace.h b/heap/MarkedSpace.h index 253d2f1..bb388dd 100644 --- a/heap/MarkedSpace.h +++ b/heap/MarkedSpace.h @@ -27,16 +27,15 @@ #include "MarkedBlock.h" #include "MarkedBlockSet.h" #include <array> -#include <wtf/PageAllocationAligned.h> #include <wtf/Bitmap.h> #include <wtf/DoublyLinkedList.h> #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> +#include <wtf/RetainPtr.h> #include <wtf/Vector.h> namespace JSC { -class DelayedReleaseScope; class Heap; class HeapIterationScope; class JSCell; @@ -52,13 +51,6 @@ struct ClearMarks : MarkedBlock::VoidFunctor { } }; -struct ClearRememberedSet : MarkedBlock::VoidFunctor { - void operator()(MarkedBlock* block) - { - block->clearRememberedSet(); - } -}; - struct Sweep : MarkedBlock::VoidFunctor { void operator()(MarkedBlock* block) { block->sweep(); } }; @@ -82,18 +74,35 @@ struct Size : MarkedBlock::CountFunctor { class MarkedSpace { WTF_MAKE_NONCOPYABLE(MarkedSpace); public: + // [ 32... 128 ] + static const size_t preciseStep = MarkedBlock::atomSize; + static const size_t preciseCutoff = 128; + static const size_t preciseCount = preciseCutoff / preciseStep; + + // [ 1024... blockSize ] + static const size_t impreciseStep = 2 * preciseCutoff; + static const size_t impreciseCutoff = MarkedBlock::blockSize / 2; + static const size_t impreciseCount = impreciseCutoff / impreciseStep; + + struct Subspace { + std::array<MarkedAllocator, preciseCount> preciseAllocators; + std::array<MarkedAllocator, impreciseCount> impreciseAllocators; + MarkedAllocator largeAllocator; + }; + MarkedSpace(Heap*); ~MarkedSpace(); void lastChanceToFinalize(); MarkedAllocator& firstAllocator(); MarkedAllocator& allocatorFor(size_t); - MarkedAllocator& immortalStructureDestructorAllocatorFor(size_t); - MarkedAllocator& normalDestructorAllocatorFor(size_t); - void* allocateWithNormalDestructor(size_t); - void* allocateWithImmortalStructureDestructor(size_t); + MarkedAllocator& destructorAllocatorFor(size_t); + void* allocateWithDestructor(size_t); void* allocateWithoutDestructor(size_t); - + + Subspace& subspaceForObjectsWithDestructor() { return m_destructorSpace; } + Subspace& subspaceForObjectsWithoutDestructor() { return m_normalSpace; } + void resetAllocators(); void visitWeakSets(HeapRootVisitor&); @@ -126,7 +135,6 @@ public: void didAllocateInBlock(MarkedBlock*); void clearMarks(); - void clearRememberedSet(); void clearNewlyAllocated(); void sweep(); void zombifySweep(); @@ -140,31 +148,16 @@ public: template<typename T> void releaseSoon(RetainPtr<T>&&); #endif + const Vector<MarkedBlock*>& blocksWithNewObjects() const { return m_blocksWithNewObjects; } + private: - friend class DelayedReleaseScope; friend class LLIntOffsetsExtractor; + friend class JIT; template<typename Functor> void forEachAllocator(Functor&); template<typename Functor> void forEachAllocator(); - // [ 32... 128 ] - static const size_t preciseStep = MarkedBlock::atomSize; - static const size_t preciseCutoff = 128; - static const size_t preciseCount = preciseCutoff / preciseStep; - - // [ 1024... blockSize ] - static const size_t impreciseStep = 2 * preciseCutoff; - static const size_t impreciseCutoff = MarkedBlock::blockSize / 2; - static const size_t impreciseCount = impreciseCutoff / impreciseStep; - - struct Subspace { - std::array<MarkedAllocator, preciseCount> preciseAllocators; - std::array<MarkedAllocator, impreciseCount> impreciseAllocators; - MarkedAllocator largeAllocator; - }; - - Subspace m_normalDestructorSpace; - Subspace m_immortalStructureDestructorSpace; + Subspace m_destructorSpace; Subspace m_normalSpace; Heap* m_heap; @@ -172,16 +165,16 @@ private: bool m_isIterating; MarkedBlockSet m_blocks; Vector<MarkedBlock*> m_blocksWithNewObjects; - - DelayedReleaseScope* m_currentDelayedReleaseScope; }; template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachLiveCell(HeapIterationScope&, Functor& functor) { ASSERT(isIterating()); BlockIterator end = m_blocks.set().end(); - for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) - (*it)->forEachLiveCell(functor); + for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) { + if ((*it)->forEachLiveCell(functor) == IterationStatus::Done) + break; + } return functor.returnValue(); } @@ -195,8 +188,10 @@ template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forE { ASSERT(isIterating()); BlockIterator end = m_blocks.set().end(); - for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) - (*it)->forEachDeadCell(functor); + for (BlockIterator it = m_blocks.set().begin(); it != end; ++it) { + if ((*it)->forEachDeadCell(functor) == IterationStatus::Done) + break; + } return functor.returnValue(); } @@ -216,24 +211,14 @@ inline MarkedAllocator& MarkedSpace::allocatorFor(size_t bytes) return m_normalSpace.largeAllocator; } -inline MarkedAllocator& MarkedSpace::immortalStructureDestructorAllocatorFor(size_t bytes) +inline MarkedAllocator& MarkedSpace::destructorAllocatorFor(size_t bytes) { ASSERT(bytes); if (bytes <= preciseCutoff) - return m_immortalStructureDestructorSpace.preciseAllocators[(bytes - 1) / preciseStep]; + return m_destructorSpace.preciseAllocators[(bytes - 1) / preciseStep]; if (bytes <= impreciseCutoff) - return m_immortalStructureDestructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; - return m_immortalStructureDestructorSpace.largeAllocator; -} - -inline MarkedAllocator& MarkedSpace::normalDestructorAllocatorFor(size_t bytes) -{ - ASSERT(bytes); - if (bytes <= preciseCutoff) - return m_normalDestructorSpace.preciseAllocators[(bytes - 1) / preciseStep]; - if (bytes <= impreciseCutoff) - return m_normalDestructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; - return m_normalDestructorSpace.largeAllocator; + return m_destructorSpace.impreciseAllocators[(bytes - 1) / impreciseStep]; + return m_destructorSpace.largeAllocator; } inline void* MarkedSpace::allocateWithoutDestructor(size_t bytes) @@ -241,14 +226,9 @@ inline void* MarkedSpace::allocateWithoutDestructor(size_t bytes) return allocatorFor(bytes).allocate(bytes); } -inline void* MarkedSpace::allocateWithImmortalStructureDestructor(size_t bytes) -{ - return immortalStructureDestructorAllocatorFor(bytes).allocate(bytes); -} - -inline void* MarkedSpace::allocateWithNormalDestructor(size_t bytes) +inline void* MarkedSpace::allocateWithDestructor(size_t bytes) { - return normalDestructorAllocatorFor(bytes).allocate(bytes); + return destructorAllocatorFor(bytes).allocate(bytes); } template <typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachBlock(Functor& functor) @@ -260,16 +240,10 @@ template <typename Functor> inline typename Functor::ReturnType MarkedSpace::for m_normalSpace.largeAllocator.forEachBlock(functor); for (size_t i = 0; i < preciseCount; ++i) - m_normalDestructorSpace.preciseAllocators[i].forEachBlock(functor); - for (size_t i = 0; i < impreciseCount; ++i) - m_normalDestructorSpace.impreciseAllocators[i].forEachBlock(functor); - m_normalDestructorSpace.largeAllocator.forEachBlock(functor); - - for (size_t i = 0; i < preciseCount; ++i) - m_immortalStructureDestructorSpace.preciseAllocators[i].forEachBlock(functor); + m_destructorSpace.preciseAllocators[i].forEachBlock(functor); for (size_t i = 0; i < impreciseCount; ++i) - m_immortalStructureDestructorSpace.impreciseAllocators[i].forEachBlock(functor); - m_immortalStructureDestructorSpace.largeAllocator.forEachBlock(functor); + m_destructorSpace.impreciseAllocators[i].forEachBlock(functor); + m_destructorSpace.largeAllocator.forEachBlock(functor); return functor.returnValue(); } @@ -295,11 +269,6 @@ inline void MarkedSpace::didAllocateInBlock(MarkedBlock* block) #endif } -inline void MarkedSpace::clearRememberedSet() -{ - forEachBlock<ClearRememberedSet>(); -} - inline size_t MarkedSpace::objectCount() { return forEachBlock<MarkCount>(); diff --git a/heap/Region.h b/heap/Region.h deleted file mode 100644 index 3255f56..0000000 --- a/heap/Region.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef JSC_Region_h -#define JSC_Region_h - -#include "HeapBlock.h" -#include "SuperRegion.h" -#include <wtf/DoublyLinkedList.h> -#include <wtf/MetaAllocatorHandle.h> -#include <wtf/PageAllocationAligned.h> - -#define HEAP_MEMORY_ID reinterpret_cast<void*>(static_cast<intptr_t>(-3)) - -#define ENABLE_SUPER_REGION 0 - -#ifndef ENABLE_SUPER_REGION -#if USE(JSVALUE64) && !CPU(ARM64) -#define ENABLE_SUPER_REGION 1 -#else -#define ENABLE_SUPER_REGION 0 -#endif -#endif - -namespace JSC { - -class DeadBlock : public HeapBlock<DeadBlock> { -public: - DeadBlock(Region*); -}; - -inline DeadBlock::DeadBlock(Region* region) - : HeapBlock<DeadBlock>(region) -{ -} - -class Region : public DoublyLinkedListNode<Region> { - WTF_MAKE_FAST_ALLOCATED; - - friend class WTF::DoublyLinkedListNode<Region>; - friend class BlockAllocator; -public: - ~Region(); - static Region* create(SuperRegion*, size_t blockSize); - static Region* createCustomSize(SuperRegion*, size_t blockSize, size_t blockAlignment); - Region* reset(size_t blockSize); - void destroy(); - - size_t blockSize() const { return m_blockSize; } - bool isFull() const { return m_blocksInUse == m_totalBlocks; } - bool isEmpty() const { return !m_blocksInUse; } - bool isCustomSize() const { return m_isCustomSize; } - - DeadBlock* allocate(); - void deallocate(void*); - - static const size_t s_regionSize = 64 * KB; - static const size_t s_regionMask = ~(s_regionSize - 1); - -protected: - Region(size_t blockSize, size_t totalBlocks, bool isExcess); - void initializeBlockList(); - - bool m_isExcess; - -private: - void* base(); - size_t size(); - - size_t m_totalBlocks; - size_t m_blocksInUse; - size_t m_blockSize; - bool m_isCustomSize; - Region* m_prev; - Region* m_next; - DoublyLinkedList<DeadBlock> m_deadBlocks; -}; - - -class NormalRegion : public Region { - friend class Region; -private: - NormalRegion(PassRefPtr<WTF::MetaAllocatorHandle>, size_t blockSize, size_t totalBlocks); - - static NormalRegion* tryCreate(SuperRegion*, size_t blockSize); - static NormalRegion* tryCreateCustomSize(SuperRegion*, size_t blockSize, size_t blockAlignment); - - void* base() { return m_allocation->start(); } - size_t size() { return m_allocation->sizeInBytes(); } - - NormalRegion* reset(size_t blockSize); - - RefPtr<WTF::MetaAllocatorHandle> m_allocation; -}; - -class ExcessRegion : public Region { - friend class Region; -private: - ExcessRegion(PageAllocationAligned&, size_t blockSize, size_t totalBlocks); - - ~ExcessRegion(); - - static ExcessRegion* create(size_t blockSize); - static ExcessRegion* createCustomSize(size_t blockSize, size_t blockAlignment); - - void* base() { return m_allocation.base(); } - size_t size() { return m_allocation.size(); } - - ExcessRegion* reset(size_t blockSize); - - PageAllocationAligned m_allocation; -}; - -inline NormalRegion::NormalRegion(PassRefPtr<WTF::MetaAllocatorHandle> allocation, size_t blockSize, size_t totalBlocks) - : Region(blockSize, totalBlocks, false) - , m_allocation(allocation) -{ - initializeBlockList(); -} - -inline NormalRegion* NormalRegion::tryCreate(SuperRegion* superRegion, size_t blockSize) -{ - RefPtr<WTF::MetaAllocatorHandle> allocation = superRegion->allocate(s_regionSize, HEAP_MEMORY_ID); - if (!allocation) - return 0; - return new NormalRegion(allocation, blockSize, s_regionSize / blockSize); -} - -inline NormalRegion* NormalRegion::tryCreateCustomSize(SuperRegion* superRegion, size_t blockSize, size_t blockAlignment) -{ - ASSERT_UNUSED(blockAlignment, blockAlignment <= s_regionSize); - RefPtr<WTF::MetaAllocatorHandle> allocation = superRegion->allocate(blockSize, HEAP_MEMORY_ID); - if (!allocation) - return 0; - return new NormalRegion(allocation, blockSize, 1); -} - -inline NormalRegion* NormalRegion::reset(size_t blockSize) -{ - ASSERT(!m_isExcess); - RefPtr<WTF::MetaAllocatorHandle> allocation = m_allocation.release(); - return new (NotNull, this) NormalRegion(allocation.release(), blockSize, s_regionSize / blockSize); -} - -inline ExcessRegion::ExcessRegion(PageAllocationAligned& allocation, size_t blockSize, size_t totalBlocks) - : Region(blockSize, totalBlocks, true) - , m_allocation(allocation) -{ - initializeBlockList(); -} - -inline ExcessRegion::~ExcessRegion() -{ - m_allocation.deallocate(); -} - -inline ExcessRegion* ExcessRegion::create(size_t blockSize) -{ - PageAllocationAligned allocation = PageAllocationAligned::allocate(s_regionSize, s_regionSize, OSAllocator::JSGCHeapPages); - ASSERT(static_cast<bool>(allocation)); - return new ExcessRegion(allocation, blockSize, s_regionSize / blockSize); -} - -inline ExcessRegion* ExcessRegion::createCustomSize(size_t blockSize, size_t blockAlignment) -{ - PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockAlignment, OSAllocator::JSGCHeapPages); - ASSERT(static_cast<bool>(allocation)); - return new ExcessRegion(allocation, blockSize, 1); -} - -inline ExcessRegion* ExcessRegion::reset(size_t blockSize) -{ - ASSERT(m_isExcess); - PageAllocationAligned allocation = m_allocation; - return new (NotNull, this) ExcessRegion(allocation, blockSize, s_regionSize / blockSize); -} - -inline Region::Region(size_t blockSize, size_t totalBlocks, bool isExcess) - : DoublyLinkedListNode<Region>() - , m_isExcess(isExcess) - , m_totalBlocks(totalBlocks) - , m_blocksInUse(0) - , m_blockSize(blockSize) - , m_isCustomSize(false) - , m_prev(0) - , m_next(0) -{ -} - -inline void Region::initializeBlockList() -{ - char* start = static_cast<char*>(base()); - char* current = start; - for (size_t i = 0; i < m_totalBlocks; i++) { - ASSERT(current < start + size()); - m_deadBlocks.append(new (NotNull, current) DeadBlock(this)); - current += m_blockSize; - } -} - -inline Region* Region::create(SuperRegion* superRegion, size_t blockSize) -{ -#if ENABLE(SUPER_REGION) - ASSERT(blockSize <= s_regionSize); - ASSERT(!(s_regionSize % blockSize)); - Region* region = NormalRegion::tryCreate(superRegion, blockSize); - if (LIKELY(!!region)) - return region; -#else - UNUSED_PARAM(superRegion); -#endif - return ExcessRegion::create(blockSize); -} - -inline Region* Region::createCustomSize(SuperRegion* superRegion, size_t blockSize, size_t blockAlignment) -{ -#if ENABLE(SUPER_REGION) - Region* region = NormalRegion::tryCreateCustomSize(superRegion, blockSize, blockAlignment); - if (UNLIKELY(!region)) - region = ExcessRegion::createCustomSize(blockSize, blockAlignment); -#else - UNUSED_PARAM(superRegion); - Region* region = ExcessRegion::createCustomSize(blockSize, blockAlignment); -#endif - region->m_isCustomSize = true; - return region; -} - -inline Region::~Region() -{ - ASSERT(isEmpty()); -} - -inline void Region::destroy() -{ -#if ENABLE(SUPER_REGION) - if (UNLIKELY(m_isExcess)) - delete static_cast<ExcessRegion*>(this); - else - delete static_cast<NormalRegion*>(this); -#else - delete static_cast<ExcessRegion*>(this); -#endif -} - -inline Region* Region::reset(size_t blockSize) -{ -#if ENABLE(SUPER_REGION) - ASSERT(isEmpty()); - if (UNLIKELY(m_isExcess)) - return static_cast<ExcessRegion*>(this)->reset(blockSize); - return static_cast<NormalRegion*>(this)->reset(blockSize); -#else - return static_cast<ExcessRegion*>(this)->reset(blockSize); -#endif -} - -inline DeadBlock* Region::allocate() -{ - ASSERT(!isFull()); - m_blocksInUse++; - return m_deadBlocks.removeHead(); -} - -inline void Region::deallocate(void* base) -{ - ASSERT(base); - ASSERT(m_blocksInUse); - ASSERT(base >= this->base() && base < static_cast<char*>(this->base()) + size()); - DeadBlock* block = new (NotNull, base) DeadBlock(this); - m_deadBlocks.push(block); - m_blocksInUse--; -} - -inline void* Region::base() -{ -#if ENABLE(SUPER_REGION) - if (UNLIKELY(m_isExcess)) - return static_cast<ExcessRegion*>(this)->ExcessRegion::base(); - return static_cast<NormalRegion*>(this)->NormalRegion::base(); -#else - return static_cast<ExcessRegion*>(this)->ExcessRegion::base(); -#endif -} - -inline size_t Region::size() -{ -#if ENABLE(SUPER_REGION) - if (UNLIKELY(m_isExcess)) - return static_cast<ExcessRegion*>(this)->ExcessRegion::size(); - return static_cast<NormalRegion*>(this)->NormalRegion::size(); -#else - return static_cast<ExcessRegion*>(this)->ExcessRegion::size(); -#endif -} - -} // namespace JSC - -#endif // JSC_Region_h diff --git a/heap/SlotVisitor.cpp b/heap/SlotVisitor.cpp index d45c381..4de4966 100644 --- a/heap/SlotVisitor.cpp +++ b/heap/SlotVisitor.cpp @@ -17,7 +17,7 @@ namespace JSC { SlotVisitor::SlotVisitor(GCThreadSharedData& shared) - : m_stack(shared.m_vm->heap.blockAllocator()) + : m_stack() , m_bytesVisited(0) , m_bytesCopied(0) , m_visitCount(0) diff --git a/heap/SlotVisitor.h b/heap/SlotVisitor.h index 25e32ea..5152be2 100644 --- a/heap/SlotVisitor.h +++ b/heap/SlotVisitor.h @@ -105,7 +105,7 @@ public: void copyLater(JSCell*, CopyToken, void*, size_t); - void reportExtraMemoryUsage(JSCell* owner, size_t); + void reportExtraMemoryVisited(JSCell* owner, size_t); void addWeakReferenceHarvester(WeakReferenceHarvester*); void addUnconditionalFinalizer(UnconditionalFinalizer*); diff --git a/heap/SlotVisitorInlines.h b/heap/SlotVisitorInlines.h index f3355a5..1d688f8 100644 --- a/heap/SlotVisitorInlines.h +++ b/heap/SlotVisitorInlines.h @@ -239,8 +239,13 @@ inline void SlotVisitor::copyLater(JSCell* owner, CopyToken token, void* ptr, si ASSERT(bytes); CopiedBlock* block = CopiedSpace::blockFor(ptr); if (block->isOversize()) { + ASSERT(bytes <= block->size()); + // FIXME: We should be able to shrink the allocation if bytes went below the block size. + // For now, we just make sure that our accounting of how much memory we are actually using + // is correct. + // https://bugs.webkit.org/show_bug.cgi?id=144749 + bytes = block->size(); m_shared.m_copiedSpace->pin(block); - return; } ASSERT(heap()->m_storageSpace.contains(block)); @@ -252,27 +257,9 @@ inline void SlotVisitor::copyLater(JSCell* owner, CopyToken token, void* ptr, si } } -inline void SlotVisitor::reportExtraMemoryUsage(JSCell* owner, size_t size) +inline void SlotVisitor::reportExtraMemoryVisited(JSCell* owner, size_t size) { -#if ENABLE(GGC) - // We don't want to double-count the extra memory that was reported in previous collections. - if (heap()->operationInProgress() == EdenCollection && Heap::isRemembered(owner)) - return; -#else - UNUSED_PARAM(owner); -#endif - - size_t* counter = &m_shared.m_vm->heap.m_extraMemoryUsage; - -#if ENABLE(COMPARE_AND_SWAP) - for (;;) { - size_t oldSize = *counter; - if (WTF::weakCompareAndSwapSize(counter, oldSize, oldSize + size)) - return; - } -#else - (*counter) += size; -#endif + heap()->reportExtraMemoryVisited(owner, size); } inline Heap* SlotVisitor::heap() const diff --git a/heap/Strong.h b/heap/Strong.h index 27ab5d3..5c0f832 100644 --- a/heap/Strong.h +++ b/heap/Strong.h @@ -84,9 +84,7 @@ public: bool operator!() const { return !slot() || !*slot(); } - // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef JSValue (HandleBase::*UnspecifiedBoolType); - operator UnspecifiedBoolType*() const { return !!*this ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; } + explicit operator bool() const { return !!*this; } void swap(Strong& other) { diff --git a/heap/SuperRegion.cpp b/heap/SuperRegion.cpp deleted file mode 100644 index 157fe2e..0000000 --- a/heap/SuperRegion.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "SuperRegion.h" - -#include "JSCInlines.h" -#include "Region.h" - -namespace JSC { - -const uint64_t SuperRegion::s_fixedHeapMemoryPoolSize = 4 * 1024 * static_cast<uint64_t>(MB); - -SuperRegion::SuperRegion() - : MetaAllocator(Region::s_regionSize, Region::s_regionSize) - , m_reservationBase(0) -{ -#if ENABLE(SUPER_REGION) - // Over-allocate so that we can make sure that we're aligned to the size of Regions. - m_reservation = PageReservation::reserve(s_fixedHeapMemoryPoolSize + Region::s_regionSize, OSAllocator::JSGCHeapPages); - m_reservationBase = getAlignedBase(m_reservation); - addFreshFreeSpace(m_reservationBase, s_fixedHeapMemoryPoolSize); -#else - UNUSED_PARAM(m_reservation); - UNUSED_PARAM(m_reservationBase); -#endif -} - -SuperRegion::~SuperRegion() -{ -#if ENABLE(SUPER_REGION) - m_reservation.deallocate(); -#endif -} - -void* SuperRegion::getAlignedBase(PageReservation& reservation) -{ - for (char* current = static_cast<char*>(reservation.base()); current < static_cast<char*>(reservation.base()) + Region::s_regionSize; current += pageSize()) { - if (!(reinterpret_cast<size_t>(current) & ~Region::s_regionMask)) - return current; - } - ASSERT_NOT_REACHED(); - return 0; -} - -void* SuperRegion::allocateNewSpace(size_t&) -{ - return 0; -} - -void SuperRegion::notifyNeedPage(void* page) -{ - m_reservation.commit(page, Region::s_regionSize); -} - -void SuperRegion::notifyPageIsFree(void* page) -{ - m_reservation.decommit(page, Region::s_regionSize); -} - -} // namespace JSC diff --git a/heap/WeakBlock.cpp b/heap/WeakBlock.cpp index 54127ca..7c7d86c 100644 --- a/heap/WeakBlock.cpp +++ b/heap/WeakBlock.cpp @@ -34,14 +34,20 @@ namespace JSC { -WeakBlock* WeakBlock::create(DeadBlock* block) +WeakBlock* WeakBlock::create(MarkedBlock& markedBlock) { - Region* region = block->region(); - return new (NotNull, block) WeakBlock(region); + return new (NotNull, fastMalloc(blockSize)) WeakBlock(markedBlock); } -WeakBlock::WeakBlock(Region* region) - : HeapBlock<WeakBlock>(region) +void WeakBlock::destroy(WeakBlock* block) +{ + block->~WeakBlock(); + fastFree(block); +} + +WeakBlock::WeakBlock(MarkedBlock& markedBlock) + : DoublyLinkedListNode<WeakBlock>() + , m_markedBlock(&markedBlock) { for (size_t i = 0; i < weakImplCount(); ++i) { WeakImpl* weakImpl = &weakImpls()[i]; @@ -76,8 +82,11 @@ void WeakBlock::sweep() finalize(weakImpl); if (weakImpl->state() == WeakImpl::Deallocated) addToFreeList(&sweepResult.freeList, weakImpl); - else + else { sweepResult.blockIsFree = false; + if (weakImpl->state() == WeakImpl::Live) + sweepResult.blockIsLogicallyEmpty = false; + } } m_sweepResult = sweepResult; @@ -90,6 +99,12 @@ void WeakBlock::visit(HeapRootVisitor& heapRootVisitor) if (isEmpty()) return; + // If this WeakBlock doesn't belong to a MarkedBlock, we won't even be here. + ASSERT(m_markedBlock); + + if (m_markedBlock->isAllocated()) + return; + SlotVisitor& visitor = heapRootVisitor.visitor(); for (size_t i = 0; i < weakImplCount(); ++i) { @@ -98,7 +113,7 @@ void WeakBlock::visit(HeapRootVisitor& heapRootVisitor) continue; const JSValue& jsValue = weakImpl->jsValue(); - if (Heap::isLive(jsValue.asCell())) + if (m_markedBlock->isMarkedOrNewlyAllocated(jsValue.asCell())) continue; WeakHandleOwner* weakHandleOwner = weakImpl->weakHandleOwner(); @@ -118,12 +133,18 @@ void WeakBlock::reap() if (isEmpty()) return; + // If this WeakBlock doesn't belong to a MarkedBlock, we won't even be here. + ASSERT(m_markedBlock); + + if (m_markedBlock->isAllocated()) + return; + for (size_t i = 0; i < weakImplCount(); ++i) { WeakImpl* weakImpl = &weakImpls()[i]; if (weakImpl->state() > WeakImpl::Dead) continue; - if (Heap::isLive(weakImpl->jsValue().asCell())) { + if (m_markedBlock->isMarkedOrNewlyAllocated(weakImpl->jsValue().asCell())) { ASSERT(weakImpl->state() == WeakImpl::Live); continue; } diff --git a/heap/WeakBlock.h b/heap/WeakBlock.h index b6b631e..b829e9d 100644 --- a/heap/WeakBlock.h +++ b/heap/WeakBlock.h @@ -26,7 +26,7 @@ #ifndef WeakBlock_h #define WeakBlock_h -#include "HeapBlock.h" +#include <wtf/DoublyLinkedList.h> #include "WeakHandleOwner.h" #include "WeakImpl.h" #include <wtf/DoublyLinkedList.h> @@ -34,33 +34,35 @@ namespace JSC { -class DeadBlock; class HeapRootVisitor; class JSValue; +class MarkedBlock; class WeakHandleOwner; -class WeakBlock : public HeapBlock<WeakBlock> { +class WeakBlock : public DoublyLinkedListNode<WeakBlock> { public: friend class WTF::DoublyLinkedListNode<WeakBlock>; - static const size_t blockSize = 4 * KB; // 5% of MarkedBlock size + static const size_t blockSize = 1 * KB; // 1/16 of MarkedBlock size struct FreeCell { FreeCell* next; }; struct SweepResult { - SweepResult(); bool isNull() const; - bool blockIsFree; - FreeCell* freeList; + bool blockIsFree { true }; + bool blockIsLogicallyEmpty { true }; + FreeCell* freeList { nullptr }; }; - static WeakBlock* create(DeadBlock*); + static WeakBlock* create(MarkedBlock&); + static void destroy(WeakBlock*); static WeakImpl* asWeakImpl(FreeCell*); bool isEmpty(); + bool isLogicallyEmptyButNotFree() const; void sweep(); SweepResult takeSweepResult(); @@ -69,27 +71,24 @@ public: void reap(); void lastChanceToFinalize(); + void disconnectMarkedBlock() { m_markedBlock = nullptr; } private: static FreeCell* asFreeCell(WeakImpl*); - WeakBlock(Region*); + explicit WeakBlock(MarkedBlock&); WeakImpl* firstWeakImpl(); void finalize(WeakImpl*); WeakImpl* weakImpls(); size_t weakImplCount(); void addToFreeList(FreeCell**, WeakImpl*); + MarkedBlock* m_markedBlock; + WeakBlock* m_prev; + WeakBlock* m_next; SweepResult m_sweepResult; }; -inline WeakBlock::SweepResult::SweepResult() - : blockIsFree(true) - , freeList(0) -{ - ASSERT(isNull()); -} - inline bool WeakBlock::SweepResult::isNull() const { return blockIsFree && !freeList; // This state is impossible, so we can use it to mean null. @@ -138,6 +137,11 @@ inline bool WeakBlock::isEmpty() return !m_sweepResult.isNull() && m_sweepResult.blockIsFree; } +inline bool WeakBlock::isLogicallyEmptyButNotFree() const +{ + return !m_sweepResult.isNull() && !m_sweepResult.blockIsFree && m_sweepResult.blockIsLogicallyEmpty; +} + } // namespace JSC #endif // WeakBlock_h diff --git a/heap/WeakSet.cpp b/heap/WeakSet.cpp index 556c851..1eed8c3 100644 --- a/heap/WeakSet.cpp +++ b/heap/WeakSet.cpp @@ -37,15 +37,26 @@ WeakSet::~WeakSet() WeakBlock* next = 0; for (WeakBlock* block = m_blocks.head(); block; block = next) { next = block->next(); - heap()->blockAllocator().deallocate(WeakBlock::destroy(block)); + WeakBlock::destroy(block); } m_blocks.clear(); } void WeakSet::sweep() { - for (WeakBlock* block = m_blocks.head(); block; block = block->next()) + for (WeakBlock* block = m_blocks.head(); block;) { + WeakBlock* nextBlock = block->next(); block->sweep(); + if (block->isLogicallyEmptyButNotFree()) { + // If this WeakBlock is logically empty, but still has Weaks pointing into it, + // we can't destroy it just yet. Detach it from the WeakSet and hand ownership + // to the Heap so we don't pin down the entire 64kB MarkedBlock. + m_blocks.remove(block); + heap()->addLogicallyEmptyWeakBlock(block); + block->disconnectMarkedBlock(); + } + block = nextBlock; + } resetAllocator(); } @@ -74,7 +85,7 @@ WeakBlock::FreeCell* WeakSet::tryFindAllocator() WeakBlock::FreeCell* WeakSet::addAllocator() { - WeakBlock* block = WeakBlock::create(heap()->blockAllocator().allocate<WeakBlock>()); + WeakBlock* block = WeakBlock::create(m_markedBlock); heap()->didAllocate(WeakBlock::blockSize); m_blocks.append(block); WeakBlock::SweepResult sweepResult = block->takeSweepResult(); @@ -85,7 +96,7 @@ WeakBlock::FreeCell* WeakSet::addAllocator() void WeakSet::removeAllocator(WeakBlock* block) { m_blocks.remove(block); - heap()->blockAllocator().deallocate(WeakBlock::destroy(block)); + WeakBlock::destroy(block); } } // namespace JSC diff --git a/heap/WeakSet.h b/heap/WeakSet.h index a5ddcaf..dbde510 100644 --- a/heap/WeakSet.h +++ b/heap/WeakSet.h @@ -31,6 +31,7 @@ namespace JSC { class Heap; +class MarkedBlock; class WeakImpl; class WeakSet { @@ -40,7 +41,7 @@ public: static WeakImpl* allocate(JSValue, WeakHandleOwner* = 0, void* context = 0); static void deallocate(WeakImpl*); - WeakSet(VM*); + WeakSet(VM*, MarkedBlock&); ~WeakSet(); void lastChanceToFinalize(); @@ -65,12 +66,14 @@ private: WeakBlock* m_nextAllocator; DoublyLinkedList<WeakBlock> m_blocks; VM* m_vm; + MarkedBlock& m_markedBlock; }; -inline WeakSet::WeakSet(VM* vm) +inline WeakSet::WeakSet(VM* vm, MarkedBlock& markedBlock) : m_allocator(0) , m_nextAllocator(0) , m_vm(vm) + , m_markedBlock(markedBlock) { } diff --git a/heap/WriteBarrierBuffer.cpp b/heap/WriteBarrierBuffer.cpp index 93afa73..10b7430 100644 --- a/heap/WriteBarrierBuffer.cpp +++ b/heap/WriteBarrierBuffer.cpp @@ -44,7 +44,6 @@ WriteBarrierBuffer::WriteBarrierBuffer(unsigned capacity) WriteBarrierBuffer::~WriteBarrierBuffer() { fastFree(m_buffer); - m_buffer = 0; } void WriteBarrierBuffer::flush(Heap& heap) diff --git a/heap/WriteBarrierBuffer.h b/heap/WriteBarrierBuffer.h index 9126bdb..7359083 100644 --- a/heap/WriteBarrierBuffer.h +++ b/heap/WriteBarrierBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,10 +33,7 @@ namespace JSC { class Heap; class JSCell; -namespace FTL { class LowerDFGToLLVM; } - class WriteBarrierBuffer { - friend class FTL::LowerDFGToLLVM; public: WriteBarrierBuffer(unsigned capacity); ~WriteBarrierBuffer(); @@ -45,25 +42,25 @@ public: void flush(Heap&); void reset(); - static ptrdiff_t currentIndexOffset() + unsigned* currentIndexAddress() { - return OBJECT_OFFSETOF(WriteBarrierBuffer, m_currentIndex); + return &m_currentIndex; } - static ptrdiff_t capacityOffset() + unsigned capacity() const { - return OBJECT_OFFSETOF(WriteBarrierBuffer, m_capacity); + return m_capacity; } - static ptrdiff_t bufferOffset() + JSCell** buffer() { - return OBJECT_OFFSETOF(WriteBarrierBuffer, m_buffer); + return m_buffer; } private: unsigned m_currentIndex; - unsigned m_capacity; - JSCell** m_buffer; + const unsigned m_capacity; + JSCell** const m_buffer; }; } // namespace JSC diff --git a/inspector/ConsoleMessage.cpp b/inspector/ConsoleMessage.cpp index 40790bf..9ac0dde 100644 --- a/inspector/ConsoleMessage.cpp +++ b/inspector/ConsoleMessage.cpp @@ -31,8 +31,6 @@ #include "config.h" #include "ConsoleMessage.h" -#if ENABLE(INSPECTOR) - #include "IdentifiersFactory.h" #include "InjectedScript.h" #include "InjectedScriptManager.h" @@ -131,60 +129,63 @@ void ConsoleMessage::autogenerateMetadata(JSC::ExecState* state) } } -static Inspector::TypeBuilder::Console::ConsoleMessage::Source::Enum messageSourceValue(MessageSource source) +static Inspector::Protocol::Console::ConsoleMessage::Source messageSourceValue(MessageSource source) { switch (source) { - case MessageSource::XML: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::XML; - case MessageSource::JS: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Javascript; - case MessageSource::Network: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Network; - case MessageSource::ConsoleAPI: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::ConsoleAPI; - case MessageSource::Storage: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Storage; - case MessageSource::AppCache: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Appcache; - case MessageSource::Rendering: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Rendering; - case MessageSource::CSS: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::CSS; - case MessageSource::Security: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Security; - case MessageSource::Other: return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Other; + case MessageSource::XML: return Inspector::Protocol::Console::ConsoleMessage::Source::XML; + case MessageSource::JS: return Inspector::Protocol::Console::ConsoleMessage::Source::Javascript; + case MessageSource::Network: return Inspector::Protocol::Console::ConsoleMessage::Source::Network; + case MessageSource::ConsoleAPI: return Inspector::Protocol::Console::ConsoleMessage::Source::ConsoleAPI; + case MessageSource::Storage: return Inspector::Protocol::Console::ConsoleMessage::Source::Storage; + case MessageSource::AppCache: return Inspector::Protocol::Console::ConsoleMessage::Source::Appcache; + case MessageSource::Rendering: return Inspector::Protocol::Console::ConsoleMessage::Source::Rendering; + case MessageSource::CSS: return Inspector::Protocol::Console::ConsoleMessage::Source::CSS; + case MessageSource::Security: return Inspector::Protocol::Console::ConsoleMessage::Source::Security; + case MessageSource::ContentBlocker: return Inspector::Protocol::Console::ConsoleMessage::Source::ContentBlocker; + case MessageSource::Other: return Inspector::Protocol::Console::ConsoleMessage::Source::Other; } - return Inspector::TypeBuilder::Console::ConsoleMessage::Source::Other; + return Inspector::Protocol::Console::ConsoleMessage::Source::Other; } -static Inspector::TypeBuilder::Console::ConsoleMessage::Type::Enum messageTypeValue(MessageType type) +static Inspector::Protocol::Console::ConsoleMessage::Type messageTypeValue(MessageType type) { switch (type) { - case MessageType::Log: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Log; - case MessageType::Clear: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Clear; - case MessageType::Dir: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Dir; - case MessageType::DirXML: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::DirXML; - case MessageType::Table: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Table; - case MessageType::Trace: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Trace; - case MessageType::StartGroup: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::StartGroup; - case MessageType::StartGroupCollapsed: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::StartGroupCollapsed; - case MessageType::EndGroup: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::EndGroup; - case MessageType::Assert: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Assert; - case MessageType::Timing: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Timing; - case MessageType::Profile: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Profile; - case MessageType::ProfileEnd: return Inspector::TypeBuilder::Console::ConsoleMessage::Type::ProfileEnd; + case MessageType::Log: return Inspector::Protocol::Console::ConsoleMessage::Type::Log; + case MessageType::Clear: return Inspector::Protocol::Console::ConsoleMessage::Type::Clear; + case MessageType::Dir: return Inspector::Protocol::Console::ConsoleMessage::Type::Dir; + case MessageType::DirXML: return Inspector::Protocol::Console::ConsoleMessage::Type::DirXML; + case MessageType::Table: return Inspector::Protocol::Console::ConsoleMessage::Type::Table; + case MessageType::Trace: return Inspector::Protocol::Console::ConsoleMessage::Type::Trace; + case MessageType::StartGroup: return Inspector::Protocol::Console::ConsoleMessage::Type::StartGroup; + case MessageType::StartGroupCollapsed: return Inspector::Protocol::Console::ConsoleMessage::Type::StartGroupCollapsed; + case MessageType::EndGroup: return Inspector::Protocol::Console::ConsoleMessage::Type::EndGroup; + case MessageType::Assert: return Inspector::Protocol::Console::ConsoleMessage::Type::Assert; + case MessageType::Timing: return Inspector::Protocol::Console::ConsoleMessage::Type::Timing; + case MessageType::Profile: return Inspector::Protocol::Console::ConsoleMessage::Type::Profile; + case MessageType::ProfileEnd: return Inspector::Protocol::Console::ConsoleMessage::Type::ProfileEnd; } - return Inspector::TypeBuilder::Console::ConsoleMessage::Type::Log; + return Inspector::Protocol::Console::ConsoleMessage::Type::Log; } -static Inspector::TypeBuilder::Console::ConsoleMessage::Level::Enum messageLevelValue(MessageLevel level) +static Inspector::Protocol::Console::ConsoleMessage::Level messageLevelValue(MessageLevel level) { switch (level) { - case MessageLevel::Log: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Log; - case MessageLevel::Warning: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Warning; - case MessageLevel::Error: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Error; - case MessageLevel::Debug: return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Debug; + case MessageLevel::Log: return Inspector::Protocol::Console::ConsoleMessage::Level::Log; + case MessageLevel::Info: return Inspector::Protocol::Console::ConsoleMessage::Level::Info; + case MessageLevel::Warning: return Inspector::Protocol::Console::ConsoleMessage::Level::Warning; + case MessageLevel::Error: return Inspector::Protocol::Console::ConsoleMessage::Level::Error; + case MessageLevel::Debug: return Inspector::Protocol::Console::ConsoleMessage::Level::Debug; } - return Inspector::TypeBuilder::Console::ConsoleMessage::Level::Log; + return Inspector::Protocol::Console::ConsoleMessage::Level::Log; } -void ConsoleMessage::addToFrontend(InspectorConsoleFrontendDispatcher* consoleFrontendDispatcher, Inspector::InjectedScriptManager* injectedScriptManager, bool generatePreview) +void ConsoleMessage::addToFrontend(ConsoleFrontendDispatcher* consoleFrontendDispatcher, InjectedScriptManager* injectedScriptManager, bool generatePreview) { - RefPtr<Inspector::TypeBuilder::Console::ConsoleMessage> jsonObj = Inspector::TypeBuilder::Console::ConsoleMessage::create() + Ref<Inspector::Protocol::Console::ConsoleMessage> jsonObj = Inspector::Protocol::Console::ConsoleMessage::create() .setSource(messageSourceValue(m_source)) .setLevel(messageLevelValue(m_level)) - .setText(m_message); + .setText(m_message) + .release(); // FIXME: only send out type for ConsoleAPI source messages. jsonObj->setType(messageTypeValue(m_type)); @@ -199,37 +200,39 @@ void ConsoleMessage::addToFrontend(InspectorConsoleFrontendDispatcher* consoleFr if (m_arguments && m_arguments->argumentCount()) { InjectedScript injectedScript = injectedScriptManager->injectedScriptFor(m_arguments->globalState()); if (!injectedScript.hasNoValue()) { - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::RemoteObject>> jsonArgs = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::RemoteObject>::create(); + Ref<Inspector::Protocol::Array<Inspector::Protocol::Runtime::RemoteObject>> jsonArgs = Inspector::Protocol::Array<Inspector::Protocol::Runtime::RemoteObject>::create(); if (m_type == MessageType::Table && generatePreview && m_arguments->argumentCount()) { Deprecated::ScriptValue table = m_arguments->argumentAt(0); Deprecated::ScriptValue columns = m_arguments->argumentCount() > 1 ? m_arguments->argumentAt(1) : Deprecated::ScriptValue(); - RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns); + RefPtr<Inspector::Protocol::Runtime::RemoteObject> inspectorValue = injectedScript.wrapTable(table, columns); if (!inspectorValue) { ASSERT_NOT_REACHED(); return; } - jsonArgs->addItem(inspectorValue); + jsonArgs->addItem(inspectorValue.copyRef()); + if (m_arguments->argumentCount() > 1) + jsonArgs->addItem(injectedScript.wrapObject(columns, ASCIILiteral("console"), true)); } else { for (unsigned i = 0; i < m_arguments->argumentCount(); ++i) { - RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), "console", generatePreview); + RefPtr<Inspector::Protocol::Runtime::RemoteObject> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), ASCIILiteral("console"), generatePreview); if (!inspectorValue) { ASSERT_NOT_REACHED(); return; } - jsonArgs->addItem(inspectorValue); + jsonArgs->addItem(inspectorValue.copyRef()); } } - jsonObj->setParameters(jsonArgs); + jsonObj->setParameters(WTF::move(jsonArgs)); } } if (m_callStack) jsonObj->setStackTrace(m_callStack->buildInspectorArray()); - consoleFrontendDispatcher->messageAdded(jsonObj); + consoleFrontendDispatcher->messageAdded(WTF::move(jsonObj)); } -void ConsoleMessage::updateRepeatCountInConsole(InspectorConsoleFrontendDispatcher* consoleFrontendDispatcher) +void ConsoleMessage::updateRepeatCountInConsole(ConsoleFrontendDispatcher* consoleFrontendDispatcher) { consoleFrontendDispatcher->messageRepeatCountUpdated(m_repeatCount); } @@ -270,7 +273,7 @@ void ConsoleMessage::clear() m_message = ASCIILiteral("<message collected>"); if (m_arguments) - m_arguments.clear(); + m_arguments = nullptr; } JSC::ExecState* ConsoleMessage::scriptState() const @@ -290,5 +293,3 @@ unsigned ConsoleMessage::argumentCount() const } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/ConsoleMessage.h b/inspector/ConsoleMessage.h index 2e6c44c..a73e286 100644 --- a/inspector/ConsoleMessage.h +++ b/inspector/ConsoleMessage.h @@ -31,10 +31,8 @@ #ifndef ConsoleMessage_h #define ConsoleMessage_h -#if ENABLE(INSPECTOR) - #include "ConsoleTypes.h" -#include "InspectorJSFrontendDispatchers.h" +#include "InspectorFrontendDispatchers.h" #include <wtf/Forward.h> namespace JSC { @@ -57,13 +55,16 @@ public: ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptArguments>, JSC::ExecState*, unsigned long requestIdentifier = 0); ~ConsoleMessage(); - void addToFrontend(InspectorConsoleFrontendDispatcher*, InjectedScriptManager*, bool generatePreview); - void updateRepeatCountInConsole(InspectorConsoleFrontendDispatcher*); + void addToFrontend(ConsoleFrontendDispatcher*, InjectedScriptManager*, bool generatePreview); + void updateRepeatCountInConsole(ConsoleFrontendDispatcher*); MessageSource source() const { return m_source; } const String& message() const { return m_message; } MessageType type() const { return m_type; } JSC::ExecState* scriptState() const; + const String& url() const { return m_url; } + unsigned line() const { return m_line; } + unsigned column() const { return m_column; } void incrementCount() { ++m_repeatCount; } @@ -92,5 +93,3 @@ private: } // namespace Inspector #endif // ConsoleMessage_h - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/ContentSearchUtilities.cpp b/inspector/ContentSearchUtilities.cpp index bcd691b..ed32a15 100644 --- a/inspector/ContentSearchUtilities.cpp +++ b/inspector/ContentSearchUtilities.cpp @@ -29,9 +29,6 @@ #include "config.h" #include "ContentSearchUtilities.h" -#if ENABLE(INSPECTOR) - -#include "InspectorJSTypeBuilders.h" #include "InspectorValues.h" #include "RegularExpression.h" #include "Yarr.h" @@ -121,9 +118,9 @@ std::unique_ptr<Vector<size_t>> lineEndings(const String& text) return result; } -static PassRefPtr<Inspector::TypeBuilder::GenericTypes::SearchMatch> buildObjectForSearchMatch(size_t lineNumber, const String& lineContent) +static Ref<Inspector::Protocol::GenericTypes::SearchMatch> buildObjectForSearchMatch(size_t lineNumber, const String& lineContent) { - return Inspector::TypeBuilder::GenericTypes::SearchMatch::create() + return Inspector::Protocol::GenericTypes::SearchMatch::create() .setLineNumber(lineNumber) .setLineContent(lineContent) .release(); @@ -154,15 +151,17 @@ int countRegularExpressionMatches(const JSC::Yarr::RegularExpression& regex, con return result; } -PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>> searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex) +Ref<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>> searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex) { - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>> result = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>::create(); + Ref<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>> result = Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>::create(); JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(query, caseSensitive, isRegex); Vector<std::pair<size_t, String>> matches = getRegularExpressionMatchesByLines(regex, text); - for (const auto& match : matches) - result->addItem(buildObjectForSearchMatch(match.first, match.second)); + for (const auto& match : matches) { + Ref<Inspector::Protocol::GenericTypes::SearchMatch> matchObject = buildObjectForSearchMatch(match.first, match.second); + result->addItem(WTF::move(matchObject)); + } return result; } @@ -181,11 +180,12 @@ static String stylesheetCommentPattern(const String& name) static String findMagicComment(const String& content, const String& patternString) { + ASSERT(!content.isNull()); const char* error = nullptr; JSC::Yarr::YarrPattern pattern(patternString, false, true, &error); ASSERT(!error); BumpPointerAllocator regexAllocator; - OwnPtr<JSC::Yarr::BytecodePattern> bytecodePattern = JSC::Yarr::byteCompile(pattern, ®exAllocator); + auto bytecodePattern = JSC::Yarr::byteCompile(pattern, ®exAllocator); ASSERT(bytecodePattern); ASSERT(pattern.m_numSubpatterns == 1); @@ -216,5 +216,3 @@ String findStylesheetSourceMapURL(const String& content) } // namespace ContentSearchUtilities } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/ContentSearchUtilities.h b/inspector/ContentSearchUtilities.h index 2bc2d3c..542065f 100644 --- a/inspector/ContentSearchUtilities.h +++ b/inspector/ContentSearchUtilities.h @@ -29,9 +29,7 @@ #ifndef ContentSearchUtilities_h #define ContentSearchUtilities_h -#if ENABLE(INSPECTOR) - -#include "InspectorJSTypeBuilders.h" +#include "InspectorProtocolObjects.h" #include <wtf/Vector.h> #include <wtf/text/TextPosition.h> #include <wtf/text/WTFString.h> @@ -46,7 +44,7 @@ namespace ContentSearchUtilities { JS_EXPORT_PRIVATE JSC::Yarr::RegularExpression createSearchRegex(const String& query, bool caseSensitive, bool isRegex); JS_EXPORT_PRIVATE int countRegularExpressionMatches(const JSC::Yarr::RegularExpression&, const String&); -JS_EXPORT_PRIVATE PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>> searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex); +JS_EXPORT_PRIVATE Ref<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>> searchInTextByLines(const String& text, const String& query, const bool caseSensitive, const bool isRegex); JS_EXPORT_PRIVATE TextPosition textPositionFromOffset(size_t offset, const Vector<size_t>& lineEndings); JS_EXPORT_PRIVATE std::unique_ptr<Vector<size_t>> lineEndings(const String&); @@ -58,6 +56,4 @@ JS_EXPORT_PRIVATE String findStylesheetSourceMapURL(const String& content); } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(ContentSearchUtilities_h) diff --git a/inspector/IdentifiersFactory.cpp b/inspector/IdentifiersFactory.cpp index 321b5ee..7e145be 100644 --- a/inspector/IdentifiersFactory.cpp +++ b/inspector/IdentifiersFactory.cpp @@ -27,8 +27,6 @@ #include "config.h" #include "IdentifiersFactory.h" -#if ENABLE(INSPECTOR) - #include <wtf/text/StringBuilder.h> namespace Inspector { @@ -62,4 +60,3 @@ String IdentifiersFactory::addProcessIdPrefixTo(const String& id) } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/IdentifiersFactory.h b/inspector/IdentifiersFactory.h index 0d5611d..d81c79a 100644 --- a/inspector/IdentifiersFactory.h +++ b/inspector/IdentifiersFactory.h @@ -26,8 +26,6 @@ #ifndef IdentifiersFactory_h #define IdentifiersFactory_h -#if ENABLE(INSPECTOR) - #include <wtf/text/WTFString.h> namespace Inspector { @@ -47,5 +45,3 @@ private: } // namespace Inspector #endif // !defined(IdentifiersFactory_h) - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InjectedScript.cpp b/inspector/InjectedScript.cpp index 1a2b930..492060e 100644 --- a/inspector/InjectedScript.cpp +++ b/inspector/InjectedScript.cpp @@ -32,15 +32,13 @@ #include "config.h" #include "InjectedScript.h" -#if ENABLE(INSPECTOR) - #include "InspectorValues.h" #include "JSCInlines.h" #include "ScriptFunctionCall.h" #include "ScriptObject.h" #include <wtf/text/WTFString.h> -using Inspector::TypeBuilder::Array; +using Inspector::Protocol::Array; namespace Inspector { @@ -58,7 +56,7 @@ InjectedScript::~InjectedScript() { } -void InjectedScript::evaluate(ErrorString* errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>* result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) +void InjectedScript::evaluate(ErrorString& errorString, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("evaluate"), inspectorEnvironment()->functionCallHandler()); function.appendArgument(expression); @@ -66,10 +64,11 @@ void InjectedScript::evaluate(ErrorString* errorString, const String& expression function.appendArgument(includeCommandLineAPI); function.appendArgument(returnByValue); function.appendArgument(generatePreview); - makeEvalCall(errorString, function, result, wasThrown); + function.appendArgument(saveResult); + makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); } -void InjectedScript::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>* result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) +void InjectedScript::callFunctionOn(ErrorString& errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("callFunctionOn"), inspectorEnvironment()->functionCallHandler()); function.appendArgument(objectId); @@ -80,7 +79,7 @@ void InjectedScript::callFunctionOn(ErrorString* errorString, const String& obje makeEvalCall(errorString, function, result, wasThrown); } -void InjectedScript::evaluateOnCallFrame(ErrorString* errorString, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>* result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) +void InjectedScript::evaluateOnCallFrame(ErrorString& errorString, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>* result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("evaluateOnCallFrame"), inspectorEnvironment()->functionCallHandler()); function.appendArgument(callFrames); @@ -90,60 +89,112 @@ void InjectedScript::evaluateOnCallFrame(ErrorString* errorString, const Depreca function.appendArgument(includeCommandLineAPI); function.appendArgument(returnByValue); function.appendArgument(generatePreview); - makeEvalCall(errorString, function, result, wasThrown); + function.appendArgument(saveResult); + makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); } -void InjectedScript::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<Inspector::TypeBuilder::Debugger::FunctionDetails>* result) +void InjectedScript::getFunctionDetails(ErrorString& errorString, const String& functionId, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>* result) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getFunctionDetails"), inspectorEnvironment()->functionCallHandler()); function.appendArgument(functionId); RefPtr<InspectorValue> resultValue; makeCall(function, &resultValue); - if (!resultValue || resultValue->type() != InspectorValue::TypeObject) { + if (!resultValue || resultValue->type() != InspectorValue::Type::Object) { if (!resultValue->asString(errorString)) - *errorString = ASCIILiteral("Internal error"); + errorString = ASCIILiteral("Internal error"); return; } - *result = Inspector::TypeBuilder::Debugger::FunctionDetails::runtimeCast(resultValue); + *result = BindingTraits<Inspector::Protocol::Debugger::FunctionDetails>::runtimeCast(WTF::move(resultValue)); } -void InjectedScript::getProperties(ErrorString* errorString, const String& objectId, bool ownProperties, bool ownAndGetterProperties, RefPtr<Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>* properties) +void InjectedScript::getProperties(ErrorString& errorString, const String& objectId, bool ownProperties, bool generatePreview, RefPtr<Array<Inspector::Protocol::Runtime::PropertyDescriptor>>* properties) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getProperties"), inspectorEnvironment()->functionCallHandler()); function.appendArgument(objectId); function.appendArgument(ownProperties); - function.appendArgument(ownAndGetterProperties); + function.appendArgument(generatePreview); + + RefPtr<InspectorValue> result; + makeCall(function, &result); + if (!result || result->type() != InspectorValue::Type::Array) { + errorString = ASCIILiteral("Internal error"); + return; + } + + *properties = BindingTraits<Array<Inspector::Protocol::Runtime::PropertyDescriptor>>::runtimeCast(WTF::move(result)); +} + +void InjectedScript::getDisplayableProperties(ErrorString& errorString, const String& objectId, bool generatePreview, RefPtr<Array<Inspector::Protocol::Runtime::PropertyDescriptor>>* properties) +{ + Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getDisplayableProperties"), inspectorEnvironment()->functionCallHandler()); + function.appendArgument(objectId); + function.appendArgument(generatePreview); RefPtr<InspectorValue> result; makeCall(function, &result); - if (!result || result->type() != InspectorValue::TypeArray) { - *errorString = ASCIILiteral("Internal error"); + if (!result || result->type() != InspectorValue::Type::Array) { + errorString = ASCIILiteral("Internal error"); return; } - *properties = Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>::runtimeCast(result); + *properties = BindingTraits<Array<Inspector::Protocol::Runtime::PropertyDescriptor>>::runtimeCast(WTF::move(result)); } -void InjectedScript::getInternalProperties(ErrorString* errorString, const String& objectId, RefPtr<Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>* properties) +void InjectedScript::getInternalProperties(ErrorString& errorString, const String& objectId, bool generatePreview, RefPtr<Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>* properties) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getInternalProperties"), inspectorEnvironment()->functionCallHandler()); function.appendArgument(objectId); + function.appendArgument(generatePreview); RefPtr<InspectorValue> result; makeCall(function, &result); - if (!result || result->type() != InspectorValue::TypeArray) { - *errorString = ASCIILiteral("Internal error"); + if (!result || result->type() != InspectorValue::Type::Array) { + errorString = ASCIILiteral("Internal error"); return; } - RefPtr<Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>> array = Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>::runtimeCast(result); - if (array->length() > 0) - *properties = array; + auto array = BindingTraits<Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>::runtimeCast(WTF::move(result)); + *properties = array->length() > 0 ? array : nullptr; } -PassRefPtr<Array<Inspector::TypeBuilder::Debugger::CallFrame>> InjectedScript::wrapCallFrames(const Deprecated::ScriptValue& callFrames) +void InjectedScript::getCollectionEntries(ErrorString& errorString, const String& objectId, const String& objectGroup, int startIndex, int numberToFetch, RefPtr<Protocol::Array<Protocol::Runtime::CollectionEntry>>* entries) +{ + Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getCollectionEntries"), inspectorEnvironment()->functionCallHandler()); + function.appendArgument(objectId); + function.appendArgument(objectGroup); + function.appendArgument(startIndex); + function.appendArgument(numberToFetch); + + RefPtr<InspectorValue> result; + makeCall(function, &result); + if (!result || result->type() != InspectorValue::Type::Array) { + errorString = ASCIILiteral("Internal error"); + return; + } + + *entries = BindingTraits<Array<Protocol::Runtime::CollectionEntry>>::runtimeCast(WTF::move(result)); +} + +void InjectedScript::saveResult(ErrorString& errorString, const String& callArgumentJSON, Inspector::Protocol::OptOutput<int>* savedResultIndex) +{ + Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("saveResult"), inspectorEnvironment()->functionCallHandler()); + function.appendArgument(callArgumentJSON); + + RefPtr<InspectorValue> result; + makeCall(function, &result); + if (!result || result->type() != InspectorValue::Type::Integer) { + errorString = ASCIILiteral("Internal error"); + return; + } + + int savedResultIndexInt = 0; + if (result->asInteger(savedResultIndexInt) && savedResultIndexInt > 0) + *savedResultIndex = savedResultIndexInt; +} + +Ref<Array<Inspector::Protocol::Debugger::CallFrame>> InjectedScript::wrapCallFrames(const Deprecated::ScriptValue& callFrames) { ASSERT(!hasNoValue()); Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("wrapCallFrames"), inspectorEnvironment()->functionCallHandler()); @@ -153,13 +204,13 @@ PassRefPtr<Array<Inspector::TypeBuilder::Debugger::CallFrame>> InjectedScript::w Deprecated::ScriptValue callFramesValue = callFunctionWithEvalEnabled(function, hadException); ASSERT(!hadException); RefPtr<InspectorValue> result = callFramesValue.toInspectorValue(scriptState()); - if (result->type() == InspectorValue::TypeArray) - return Array<Inspector::TypeBuilder::Debugger::CallFrame>::runtimeCast(result); + if (result->type() == InspectorValue::Type::Array) + return BindingTraits<Array<Inspector::Protocol::Debugger::CallFrame>>::runtimeCast(WTF::move(result)).releaseNonNull(); - return Array<Inspector::TypeBuilder::Debugger::CallFrame>::create(); + return Array<Inspector::Protocol::Debugger::CallFrame>::create(); } -PassRefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapObject(const Deprecated::ScriptValue& value, const String& groupName, bool generatePreview) const +RefPtr<Inspector::Protocol::Runtime::RemoteObject> InjectedScript::wrapObject(const Deprecated::ScriptValue& value, const String& groupName, bool generatePreview) const { ASSERT(!hasNoValue()); Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), ASCIILiteral("wrapObject"), inspectorEnvironment()->functionCallHandler()); @@ -173,11 +224,14 @@ PassRefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapOb if (hadException) return nullptr; - RefPtr<InspectorObject> rawResult = r.toInspectorValue(scriptState())->asObject(); - return Inspector::TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult); + RefPtr<InspectorObject> resultObject; + bool castSucceeded = r.toInspectorValue(scriptState())->asObject(resultObject); + ASSERT_UNUSED(castSucceeded, castSucceeded); + + return BindingTraits<Inspector::Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); } -PassRefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapTable(const Deprecated::ScriptValue& table, const Deprecated::ScriptValue& columns) const +RefPtr<Inspector::Protocol::Runtime::RemoteObject> InjectedScript::wrapTable(const Deprecated::ScriptValue& table, const Deprecated::ScriptValue& columns) const { ASSERT(!hasNoValue()); Deprecated::ScriptFunctionCall wrapFunction(injectedScriptObject(), ASCIILiteral("wrapTable"), inspectorEnvironment()->functionCallHandler()); @@ -193,8 +247,28 @@ PassRefPtr<Inspector::TypeBuilder::Runtime::RemoteObject> InjectedScript::wrapTa if (hadException) return nullptr; - RefPtr<InspectorObject> rawResult = r.toInspectorValue(scriptState())->asObject(); - return Inspector::TypeBuilder::Runtime::RemoteObject::runtimeCast(rawResult); + RefPtr<InspectorObject> resultObject; + bool castSucceeded = r.toInspectorValue(scriptState())->asObject(resultObject); + ASSERT_UNUSED(castSucceeded, castSucceeded); + + return BindingTraits<Inspector::Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); +} + +void InjectedScript::setExceptionValue(const Deprecated::ScriptValue& value) +{ + ASSERT(!hasNoValue()); + Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("setExceptionValue"), inspectorEnvironment()->functionCallHandler()); + function.appendArgument(value); + RefPtr<InspectorValue> result; + makeCall(function, &result); +} + +void InjectedScript::clearExceptionValue() +{ + ASSERT(!hasNoValue()); + Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("clearExceptionValue"), inspectorEnvironment()->functionCallHandler()); + RefPtr<InspectorValue> result; + makeCall(function, &result); } Deprecated::ScriptValue InjectedScript::findObjectById(const String& objectId) const @@ -240,4 +314,3 @@ void InjectedScript::releaseObjectGroup(const String& objectGroup) } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InjectedScript.h b/inspector/InjectedScript.h index fce17fc..bd43f72 100644 --- a/inspector/InjectedScript.h +++ b/inspector/InjectedScript.h @@ -32,13 +32,9 @@ #ifndef InjectedScript_h #define InjectedScript_h -#if ENABLE(INSPECTOR) - #include "InjectedScriptBase.h" -#include "InspectorJSTypeBuilders.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> -#include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> namespace Deprecated { @@ -56,16 +52,22 @@ public: InjectedScript(Deprecated::ScriptObject, InspectorEnvironment*); virtual ~InjectedScript(); - void evaluate(ErrorString*, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown); - void callFunctionOn(ErrorString*, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown); - void evaluateOnCallFrame(ErrorString*, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown); - void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>* result); - void getProperties(ErrorString*, const String& objectId, bool ownProperties, bool ownAndGetterProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor>>* result); - void getInternalProperties(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor>>* result); + void evaluate(ErrorString&, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex); + void callFunctionOn(ErrorString&, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown); + void evaluateOnCallFrame(ErrorString&, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex); + void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>* result); + void getProperties(ErrorString&, const String& objectId, bool ownProperties, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::PropertyDescriptor>>* result); + void getDisplayableProperties(ErrorString&, const String& objectId, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::PropertyDescriptor>>* result); + void getInternalProperties(ErrorString&, const String& objectId, bool generatePreview, RefPtr<Protocol::Array<Protocol::Runtime::InternalPropertyDescriptor>>* result); + void getCollectionEntries(ErrorString&, const String& objectId, const String& objectGroup, int startIndex, int numberToFetch, RefPtr<Protocol::Array<Protocol::Runtime::CollectionEntry>>* entries); + void saveResult(ErrorString&, const String& callArgumentJSON, Inspector::Protocol::OptOutput<int>* savedResultIndex); + + Ref<Protocol::Array<Protocol::Debugger::CallFrame>> wrapCallFrames(const Deprecated::ScriptValue&); + RefPtr<Protocol::Runtime::RemoteObject> wrapObject(const Deprecated::ScriptValue&, const String& groupName, bool generatePreview = false) const; + RefPtr<Protocol::Runtime::RemoteObject> wrapTable(const Deprecated::ScriptValue& table, const Deprecated::ScriptValue& columns) const; - PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame>> wrapCallFrames(const Deprecated::ScriptValue&); - PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapObject(const Deprecated::ScriptValue&, const String& groupName, bool generatePreview = false) const; - PassRefPtr<TypeBuilder::Runtime::RemoteObject> wrapTable(const Deprecated::ScriptValue& table, const Deprecated::ScriptValue& columns) const; + void setExceptionValue(const Deprecated::ScriptValue&); + void clearExceptionValue(); Deprecated::ScriptValue findObjectById(const String& objectId) const; void inspectObject(Deprecated::ScriptValue); @@ -78,6 +80,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // InjectedScript_h diff --git a/inspector/InjectedScriptBase.cpp b/inspector/InjectedScriptBase.cpp index d9561e1..2dd5643 100644 --- a/inspector/InjectedScriptBase.cpp +++ b/inspector/InjectedScriptBase.cpp @@ -32,8 +32,7 @@ #include "config.h" #include "InjectedScriptBase.h" -#if ENABLE(INSPECTOR) - +#include "DebuggerEvalEnabler.h" #include "InspectorValues.h" #include "JSCInlines.h" #include "JSGlobalObject.h" @@ -81,18 +80,12 @@ Deprecated::ScriptValue InjectedScriptBase::callFunctionWithEvalEnabled(Deprecat m_environment->willCallInjectedScriptFunction(m_injectedScriptObject.scriptState(), name(), 1); JSC::ExecState* scriptState = m_injectedScriptObject.scriptState(); - bool evalIsDisabled = false; - if (scriptState) { - evalIsDisabled = !scriptState->lexicalGlobalObject()->evalEnabled(); - // Temporarily enable allow evals for inspector. - if (evalIsDisabled) - scriptState->lexicalGlobalObject()->setEvalEnabled(true); - } - - Deprecated::ScriptValue resultValue = function.call(hadException); + Deprecated::ScriptValue resultValue; - if (evalIsDisabled) - scriptState->lexicalGlobalObject()->setEvalEnabled(false); + { + JSC::DebuggerEvalEnabler evalEnabler(scriptState); + resultValue = function.call(hadException); + } if (m_environment) m_environment->didCallInjectedScriptFunction(m_injectedScriptObject.scriptState()); @@ -119,38 +112,48 @@ void InjectedScriptBase::makeCall(Deprecated::ScriptFunctionCall& function, RefP *result = InspectorString::create("Exception while making a call."); } -void InjectedScriptBase::makeEvalCall(ErrorString* errorString, Deprecated::ScriptFunctionCall& function, RefPtr<TypeBuilder::Runtime::RemoteObject>* objectResult, TypeBuilder::OptOutput<bool>* wasThrown) +void InjectedScriptBase::makeEvalCall(ErrorString& errorString, Deprecated::ScriptFunctionCall& function, RefPtr<Protocol::Runtime::RemoteObject>* objectResult, Protocol::OptOutput<bool>* wasThrown, Protocol::OptOutput<int>* savedResultIndex) { RefPtr<InspectorValue> result; makeCall(function, &result); if (!result) { - *errorString = ASCIILiteral("Internal error: result value is empty"); + errorString = ASCIILiteral("Internal error: result value is empty"); return; } - if (result->type() == InspectorValue::TypeString) { + if (result->type() == InspectorValue::Type::String) { result->asString(errorString); - ASSERT(errorString->length()); + ASSERT(errorString.length()); return; } - RefPtr<InspectorObject> resultPair = result->asObject(); - if (!resultPair) { - *errorString = ASCIILiteral("Internal error: result is not an Object"); + RefPtr<InspectorObject> resultTuple; + if (!result->asObject(resultTuple)) { + errorString = ASCIILiteral("Internal error: result is not an Object"); return; } - RefPtr<InspectorObject> resultObj = resultPair->getObject(ASCIILiteral("result")); - bool wasThrownVal = false; - if (!resultObj || !resultPair->getBoolean(ASCIILiteral("wasThrown"), &wasThrownVal)) { - *errorString = ASCIILiteral("Internal error: result is not a pair of value and wasThrown flag"); + RefPtr<InspectorObject> resultObject; + if (!resultTuple->getObject(ASCIILiteral("result"), resultObject)) { + errorString = ASCIILiteral("Internal error: result is not a pair of value and wasThrown flag"); return; } - *objectResult = TypeBuilder::Runtime::RemoteObject::runtimeCast(resultObj); - *wasThrown = wasThrownVal; + bool wasThrownValue = false; + if (!resultTuple->getBoolean(ASCIILiteral("wasThrown"), wasThrownValue)) { + errorString = ASCIILiteral("Internal error: result is not a pair of value and wasThrown flag"); + return; + } + + *objectResult = BindingTraits<Protocol::Runtime::RemoteObject>::runtimeCast(resultObject); + *wasThrown = wasThrownValue; + + if (savedResultIndex) { + int savedIndex = 0; + if (resultTuple->getInteger(ASCIILiteral("savedResultIndex"), savedIndex)) + *savedResultIndex = savedIndex; + } } } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InjectedScriptBase.h b/inspector/InjectedScriptBase.h index 034e0c2..06c3f56 100644 --- a/inspector/InjectedScriptBase.h +++ b/inspector/InjectedScriptBase.h @@ -32,10 +32,8 @@ #ifndef InjectedScriptBase_h #define InjectedScriptBase_h -#if ENABLE(INSPECTOR) - #include "InspectorEnvironment.h" -#include "InspectorJSTypeBuilders.h" +#include "InspectorProtocolObjects.h" #include "bindings/ScriptObject.h" #include <wtf/Forward.h> #include <wtf/RefPtr.h> @@ -68,7 +66,7 @@ protected: const Deprecated::ScriptObject& injectedScriptObject() const; Deprecated::ScriptValue callFunctionWithEvalEnabled(Deprecated::ScriptFunctionCall&, bool& hadException) const; void makeCall(Deprecated::ScriptFunctionCall&, RefPtr<InspectorValue>* result); - void makeEvalCall(ErrorString*, Deprecated::ScriptFunctionCall&, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown); + void makeEvalCall(ErrorString&, Deprecated::ScriptFunctionCall&, RefPtr<Protocol::Runtime::RemoteObject>* result, Protocol::OptOutput<bool>* wasThrown, Protocol::OptOutput<int>* savedResult = nullptr); private: String m_name; @@ -78,6 +76,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // InjectedScriptBase_h diff --git a/inspector/InjectedScriptHost.cpp b/inspector/InjectedScriptHost.cpp index db917f8..6351472 100644 --- a/inspector/InjectedScriptHost.cpp +++ b/inspector/InjectedScriptHost.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "InjectedScriptHost.h" -#if ENABLE(INSPECTOR) - #include "JSInjectedScriptHost.h" using namespace JSC; @@ -79,5 +77,3 @@ void InjectedScriptHost::clearAllWrappers() } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InjectedScriptHost.h b/inspector/InjectedScriptHost.h index db93f86..ae530a2 100644 --- a/inspector/InjectedScriptHost.h +++ b/inspector/InjectedScriptHost.h @@ -26,8 +26,6 @@ #ifndef InjectedScriptHost_h #define InjectedScriptHost_h -#if ENABLE(INSPECTOR) - #include "JSCJSValueInlines.h" #include "Strong.h" #include "StrongInlines.h" @@ -38,10 +36,10 @@ namespace Inspector { class JS_EXPORT_PRIVATE InjectedScriptHost : public RefCounted<InjectedScriptHost> { public: - static PassRefPtr<InjectedScriptHost> create() { return adoptRef(new InjectedScriptHost); } + static Ref<InjectedScriptHost> create() { return adoptRef(*new InjectedScriptHost); } virtual ~InjectedScriptHost(); - virtual JSC::JSValue type(JSC::ExecState*, JSC::JSValue) { return JSC::jsUndefined(); } + virtual JSC::JSValue subtype(JSC::ExecState*, JSC::JSValue) { return JSC::jsUndefined(); } virtual bool isHTMLAllCollection(JSC::JSValue) { return false; } JSC::JSValue jsWrapper(JSC::ExecState*, JSC::JSGlobalObject*); @@ -54,6 +52,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(InjectedScriptHost_h) diff --git a/inspector/InjectedScriptManager.cpp b/inspector/InjectedScriptManager.cpp index ef0d9a3..1bac2ec 100644 --- a/inspector/InjectedScriptManager.cpp +++ b/inspector/InjectedScriptManager.cpp @@ -31,8 +31,6 @@ #include "config.h" #include "InjectedScriptManager.h" -#if ENABLE(INSPECTOR) - #include "Completion.h" #include "InjectedScriptHost.h" #include "InjectedScriptSource.h" @@ -94,15 +92,19 @@ int InjectedScriptManager::injectedScriptIdFor(ExecState* scriptState) InjectedScript InjectedScriptManager::injectedScriptForObjectId(const String& objectId) { - RefPtr<InspectorValue> parsedObjectId = InspectorValue::parseJSON(objectId); - if (parsedObjectId && parsedObjectId->type() == InspectorValue::TypeObject) { - long injectedScriptId = 0; - bool success = parsedObjectId->asObject()->getNumber(ASCIILiteral("injectedScriptId"), &injectedScriptId); - if (success) - return m_idToInjectedScript.get(injectedScriptId); - } + RefPtr<InspectorValue> parsedObjectId; + if (!InspectorValue::parseJSON(objectId, parsedObjectId)) + return InjectedScript(); - return InjectedScript(); + RefPtr<InspectorObject> resultObject; + if (!parsedObjectId->asObject(resultObject)) + return InjectedScript(); + + long injectedScriptId = 0; + if (!resultObject->getInteger(ASCIILiteral("injectedScriptId"), injectedScriptId)) + return InjectedScript(); + + return m_idToInjectedScript.get(injectedScriptId); } void InjectedScriptManager::discardInjectedScripts() @@ -114,13 +116,19 @@ void InjectedScriptManager::discardInjectedScripts() void InjectedScriptManager::releaseObjectGroup(const String& objectGroup) { - for (auto it = m_idToInjectedScript.begin(); it != m_idToInjectedScript.end(); ++it) - it->value.releaseObjectGroup(objectGroup); + for (auto& injectedScript : m_idToInjectedScript.values()) + injectedScript.releaseObjectGroup(objectGroup); +} + +void InjectedScriptManager::clearExceptionValue() +{ + for (auto& injectedScript : m_idToInjectedScript.values()) + injectedScript.clearExceptionValue(); } String InjectedScriptManager::injectedScriptSource() { - return String(reinterpret_cast<const char*>(InjectedScriptSource_js), sizeof(InjectedScriptSource_js)); + return StringImpl::createWithoutCopying(InjectedScriptSource_js, sizeof(InjectedScriptSource_js)); } Deprecated::ScriptObject InjectedScriptManager::createInjectedScript(const String& source, ExecState* scriptState, int id) @@ -131,9 +139,9 @@ Deprecated::ScriptObject InjectedScriptManager::createInjectedScript(const Strin JSGlobalObject* globalObject = scriptState->lexicalGlobalObject(); JSValue globalThisValue = scriptState->globalThisValue(); - JSValue evaluationException; + NakedPtr<Exception> evaluationException; InspectorEvaluateHandler evaluateHandler = m_environment.evaluateHandler(); - JSValue functionValue = evaluateHandler(scriptState, sourceCode, globalThisValue, &evaluationException); + JSValue functionValue = evaluateHandler(scriptState, sourceCode, globalThisValue, evaluationException); if (evaluationException) return Deprecated::ScriptObject(); @@ -148,6 +156,7 @@ Deprecated::ScriptObject InjectedScriptManager::createInjectedScript(const Strin args.append(jsNumber(id)); JSValue result = JSC::call(scriptState, functionValue, callType, callData, globalThisValue, args); + scriptState->clearException(); if (result.isObject()) return Deprecated::ScriptObject(scriptState, result.getObject()); @@ -181,4 +190,3 @@ void InjectedScriptManager::didCreateInjectedScript(InjectedScript) } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InjectedScriptManager.h b/inspector/InjectedScriptManager.h index 33a6084..cb6c9b3 100644 --- a/inspector/InjectedScriptManager.h +++ b/inspector/InjectedScriptManager.h @@ -30,8 +30,6 @@ #ifndef InjectedScriptManager_h #define InjectedScriptManager_h -#if ENABLE(INSPECTOR) - #include "InjectedScript.h" #include "InjectedScriptHost.h" #include "InspectorEnvironment.h" @@ -66,6 +64,7 @@ public: InjectedScript injectedScriptForObjectId(const String& objectId); void discardInjectedScripts(); void releaseObjectGroup(const String& objectGroup); + void clearExceptionValue(); protected: virtual void didCreateInjectedScript(InjectedScript); @@ -84,6 +83,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(InjectedScriptManager_h) diff --git a/inspector/InjectedScriptModule.cpp b/inspector/InjectedScriptModule.cpp index a3cfb32..5ba27e0 100644 --- a/inspector/InjectedScriptModule.cpp +++ b/inspector/InjectedScriptModule.cpp @@ -32,8 +32,6 @@ #include "config.h" #include "InjectedScriptModule.h" -#if ENABLE(INSPECTOR) - #include "InjectedScript.h" #include "InjectedScriptManager.h" #include "ScriptFunctionCall.h" @@ -88,5 +86,3 @@ void InjectedScriptModule::ensureInjected(InjectedScriptManager* injectedScriptM } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InjectedScriptModule.h b/inspector/InjectedScriptModule.h index a170e79..e8881b9 100644 --- a/inspector/InjectedScriptModule.h +++ b/inspector/InjectedScriptModule.h @@ -35,8 +35,6 @@ #include "InjectedScriptBase.h" #include <wtf/text/WTFString.h> -#if ENABLE(INSPECTOR) - namespace JSC { class JSValue; } @@ -64,6 +62,4 @@ protected: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // InjectedScriptModule_h diff --git a/inspector/InjectedScriptSource.js b/inspector/InjectedScriptSource.js index a7a1e5c..e576139 100644 --- a/inspector/InjectedScriptSource.js +++ b/inspector/InjectedScriptSource.js @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2014-2015 Apple Inc. All rights reserved. + * Copyright (C) 2013 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,19 +29,36 @@ //# sourceURL=__WebInspectorInjectedScript__ -/** - * @param {InjectedScriptHost} InjectedScriptHost - * @param {GlobalObject} inspectedGlobalObject - * @param {number} injectedScriptId - */ (function (InjectedScriptHost, inspectedGlobalObject, injectedScriptId) { // Protect against Object overwritten by the user code. var Object = {}.constructor; -/** - * @constructor - */ +function toString(obj) +{ + return String(obj); +} + +function toStringDescription(obj) +{ + if (obj === 0 && 1 / obj < 0) + return "-0"; + + return toString(obj); +} + +function isUInt32(obj) +{ + if (typeof obj === "number") + return obj >>> 0 === obj && (obj > 0 || 1 / obj > 0); + return "" + (obj >>> 0) === obj; +} + +function isSymbol(obj) +{ + return typeof obj === "symbol"; +} + var InjectedScript = function() { this._lastBoundObjectId = 1; @@ -48,37 +66,30 @@ var InjectedScript = function() this._idToObjectGroupName = {}; this._objectGroups = {}; this._modules = {}; + this._nextSavedResultIndex = 1; + this._savedResults = []; } -/** - * @type {Object.<string, boolean>} - * @const - */ InjectedScript.primitiveTypes = { undefined: true, boolean: true, number: true, - string: true + string: true, +} + +InjectedScript.CollectionMode = { + OwnProperties: 1 << 0, // own properties. + NativeGetterProperties: 1 << 1, // native getter properties in the prototype chain. + AllProperties: 1 << 2, // all properties in the prototype chain. } InjectedScript.prototype = { - /** - * @param {*} object - * @return {boolean} - */ isPrimitiveValue: function(object) { // FIXME(33716): typeof document.all is always 'undefined'. return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllCollection(object); }, - /** - * @param {*} object - * @param {string} groupName - * @param {boolean} canAccessInspectedGlobalObject - * @param {boolean} generatePreview - * @return {!RuntimeAgent.RemoteObject} - */ wrapObject: function(object, groupName, canAccessInspectedGlobalObject, generatePreview) { if (canAccessInspectedGlobalObject) @@ -86,10 +97,16 @@ InjectedScript.prototype = { return this._fallbackWrapper(object); }, - /** - * @param {*} object - * @return {!RuntimeAgent.RemoteObject} - */ + setExceptionValue: function(value) + { + this._exceptionValue = value; + }, + + clearExceptionValue: function() + { + delete this._exceptionValue; + }, + _fallbackWrapper: function(object) { var result = {}; @@ -97,50 +114,38 @@ InjectedScript.prototype = { if (this.isPrimitiveValue(object)) result.value = object; else - result.description = this._toString(object); - return /** @type {!RuntimeAgent.RemoteObject} */ (result); + result.description = toString(object); + return result; }, - /** - * @param {boolean} canAccessInspectedGlobalObject - * @param {Object} table - * @param {Array.<string>|string|boolean} columns - * @return {!RuntimeAgent.RemoteObject} - */ wrapTable: function(canAccessInspectedGlobalObject, table, columns) { if (!canAccessInspectedGlobalObject) return this._fallbackWrapper(table); + + // FIXME: Currently columns are ignored. Instead, the frontend filters all + // properties based on the provided column names and in the provided order. + // Should we filter here too? + var columnNames = null; if (typeof columns === "string") columns = [columns]; - if (InjectedScriptHost.type(columns) == "array") { + + if (InjectedScriptHost.subtype(columns) === "array") { columnNames = []; for (var i = 0; i < columns.length; ++i) - columnNames.push(String(columns[i])); + columnNames.push(toString(columns[i])); } + return this._wrapObject(table, "console", false, true, columnNames); }, - /** - * @param {*} object - */ inspectObject: function(object) { if (this._commandLineAPIImpl) this._commandLineAPIImpl.inspect(object); }, - /** - * This method cannot throw. - * @param {*} object - * @param {string=} objectGroupName - * @param {boolean=} forceValueType - * @param {boolean=} generatePreview - * @param {?Array.<string>=} columnNames - * @return {!RuntimeAgent.RemoteObject} - * @suppress {checkTypes} - */ _wrapObject: function(object, objectGroupName, forceValueType, generatePreview, columnNames) { try { @@ -155,11 +160,6 @@ InjectedScript.prototype = { } }, - /** - * @param {*} object - * @param {string=} objectGroupName - * @return {string} - */ _bind: function(object, objectGroupName) { var id = this._lastBoundObjectId++; @@ -177,33 +177,29 @@ InjectedScript.prototype = { return objectId; }, - /** - * @param {string} objectId - * @return {Object} - */ _parseObjectId: function(objectId) { return InjectedScriptHost.evaluate("(" + objectId + ")"); }, - /** - * @param {string} objectGroupName - */ releaseObjectGroup: function(objectGroupName) { + if (objectGroupName === "console") { + delete this._lastResult; + this._nextSavedResultIndex = 1; + this._savedResults = []; + } + var group = this._objectGroups[objectGroupName]; if (!group) return; + for (var i = 0; i < group.length; i++) this._releaseObject(group[i]); + delete this._objectGroups[objectGroupName]; }, - /** - * @param {string} methodName - * @param {string} args - * @return {*} - */ dispatch: function(methodName, args) { var argsArray = InjectedScriptHost.evaluate("(" + args + ")"); @@ -216,7 +212,7 @@ InjectedScript.prototype = { return result; }, - getProperties: function(objectId, ownProperties, ownAndGetterProperties) + _getProperties: function(objectId, collectionMode, generatePreview) { var parsedObjectId = this._parseObjectId(objectId); var object = this._objectForId(parsedObjectId); @@ -225,7 +221,10 @@ InjectedScript.prototype = { if (!this._isDefined(object)) return false; - var descriptors = this._propertyDescriptors(object, ownProperties, ownAndGetterProperties); + if (isSymbol(object)) + return false; + + var descriptors = this._propertyDescriptors(object, collectionMode); // Go over properties, wrap object values. for (var i = 0; i < descriptors.length; ++i) { @@ -235,46 +234,90 @@ InjectedScript.prototype = { if ("set" in descriptor) descriptor.set = this._wrapObject(descriptor.set, objectGroupName); if ("value" in descriptor) - descriptor.value = this._wrapObject(descriptor.value, objectGroupName); + descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview); if (!("configurable" in descriptor)) descriptor.configurable = false; if (!("enumerable" in descriptor)) descriptor.enumerable = false; + if ("symbol" in descriptor) + descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName); } return descriptors; }, - /** - * @param {string} objectId - * @return {Array.<Object>|boolean} - */ - getInternalProperties: function(objectId, ownProperties) + getProperties: function(objectId, ownProperties, generatePreview) + { + var collectionMode = ownProperties ? InjectedScript.CollectionMode.OwnProperties : InjectedScript.CollectionMode.AllProperties; + return this._getProperties(objectId, collectionMode, generatePreview); + }, + + getDisplayableProperties: function(objectId, generatePreview) + { + var collectionMode = InjectedScript.CollectionMode.OwnProperties | InjectedScript.CollectionMode.NativeGetterProperties; + return this._getProperties(objectId, collectionMode, generatePreview); + }, + + getInternalProperties: function(objectId, generatePreview) { var parsedObjectId = this._parseObjectId(objectId); var object = this._objectForId(parsedObjectId); var objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; + if (!this._isDefined(object)) return false; - var descriptors = []; - var internalProperties = InjectedScriptHost.getInternalProperties(object); - if (internalProperties) { - for (var i = 0; i < internalProperties.length; i++) { - var property = internalProperties[i]; - var descriptor = { - name: property.name, - value: this._wrapObject(property.value, objectGroupName) - }; - descriptors.push(descriptor); - } + + if (isSymbol(object)) + return false; + + var descriptors = this._internalPropertyDescriptors(object); + if (!descriptors) + return []; + + // Go over properties, wrap object values. + for (var i = 0; i < descriptors.length; ++i) { + var descriptor = descriptors[i]; + if ("value" in descriptor) + descriptor.value = this._wrapObject(descriptor.value, objectGroupName, false, generatePreview); } + return descriptors; }, - /** - * @param {string} functionId - * @return {!DebuggerAgent.FunctionDetails|string} - */ + getCollectionEntries: function(objectId, objectGroupName, startIndex, numberToFetch) + { + var parsedObjectId = this._parseObjectId(objectId); + var object = this._objectForId(parsedObjectId); + var objectGroupName = objectGroupName || this._idToObjectGroupName[parsedObjectId.id]; + + if (!this._isDefined(object)) + return; + + if (typeof object !== "object") + return; + + var entries = this._entries(object, InjectedScriptHost.subtype(object), startIndex, numberToFetch); + return entries.map(function(entry) { + entry.value = injectedScript._wrapObject(entry.value, objectGroupName, false, true); + if ("key" in entry) + entry.key = injectedScript._wrapObject(entry.key, objectGroupName, false, true); + return entry; + }); + }, + + saveResult: function(callArgumentJSON) + { + this._savedResultIndex = 0; + + try { + var callArgument = InjectedScriptHost.evaluate("(" + callArgumentJSON + ")"); + var value = this._resolveCallArgument(callArgument); + this._saveResult(value); + } catch (e) {} + + return this._savedResultIndex; + }, + getFunctionDetails: function(functionId) { var parsedFunctionId = this._parseObjectId(functionId); @@ -296,44 +339,24 @@ InjectedScript.prototype = { return details; }, - /** - * @param {string} objectId - */ releaseObject: function(objectId) { var parsedObjectId = this._parseObjectId(objectId); this._releaseObject(parsedObjectId.id); }, - /** - * @param {string} id - */ _releaseObject: function(id) { delete this._idToWrappedObject[id]; delete this._idToObjectGroupName[id]; }, - /** - * @param {string} expression - * @param {string} objectGroup - * @param {boolean} injectCommandLineAPI - * @param {boolean} returnByValue - * @param {boolean} generatePreview - * @return {*} - */ - evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview) + evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult) { - return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview); + return this._evaluateAndWrap(InjectedScriptHost.evaluate, InjectedScriptHost, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, saveResult); }, - /** - * @param {string} objectId - * @param {string} expression - * @param {boolean} returnByValue - * @return {Object|string} - */ - callFunctionOn: function(objectId, expression, args, returnByValue) + callFunctionOn: function(objectId, expression, args, returnByValue, generatePreview) { var parsedObjectId = this._parseObjectId(objectId); var object = this._objectForId(parsedObjectId); @@ -342,15 +365,13 @@ InjectedScript.prototype = { if (args) { var resolvedArgs = []; - args = InjectedScriptHost.evaluate(args); - for (var i = 0; i < args.length; ++i) { - var resolvedCallArgument; + var callArgs = InjectedScriptHost.evaluate(args); + for (var i = 0; i < callArgs.length; ++i) { try { - resolvedCallArgument = this._resolveCallArgument(args[i]); + resolvedArgs[i] = this._resolveCallArgument(callArgs[i]); } catch (e) { return String(e); } - resolvedArgs.push(resolvedCallArgument) } } @@ -360,21 +381,21 @@ InjectedScript.prototype = { if (typeof func !== "function") return "Given expression does not evaluate to a function"; - return { wasThrown: false, - result: this._wrapObject(func.apply(object, resolvedArgs), objectGroup, returnByValue) }; + return { + wasThrown: false, + result: this._wrapObject(func.apply(object, resolvedArgs), objectGroup, returnByValue, generatePreview) + }; } catch (e) { return this._createThrownValue(e, objectGroup); } }, - /** - * Resolves a value from CallArgument description. - * @param {RuntimeAgent.CallArgument} callArgumentJson - * @return {*} resolved value - * @throws {string} error message - */ - _resolveCallArgument: function(callArgumentJson) { - var objectId = callArgumentJson.objectId; + _resolveCallArgument: function(callArgumentJSON) + { + if ("value" in callArgumentJSON) + return callArgumentJSON.value; + + var objectId = callArgumentJSON.objectId; if (objectId) { var parsedArgId = this._parseObjectId(objectId); if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScriptId) @@ -385,57 +406,43 @@ InjectedScript.prototype = { throw "Could not find object with given id"; return resolvedArg; - } else if ("value" in callArgumentJson) - return callArgumentJson.value; - else - return undefined; + } + + return undefined; }, - /** - * @param {Function} evalFunction - * @param {Object} object - * @param {string} objectGroup - * @param {boolean} isEvalOnCallFrame - * @param {boolean} injectCommandLineAPI - * @param {boolean} returnByValue - * @param {boolean} generatePreview - * @return {*} - */ - _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview) + _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, saveResult) { try { - return { wasThrown: false, - result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI), objectGroup, returnByValue, generatePreview) }; + this._savedResultIndex = 0; + + var returnObject = { + wasThrown: false, + result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult), objectGroup, returnByValue, generatePreview) + }; + + if (saveResult && this._savedResultIndex) + returnObject.savedResultIndex = this._savedResultIndex; + + return returnObject; } catch (e) { return this._createThrownValue(e, objectGroup); } }, - /** - * @param {*} value - * @param {string} objectGroup - * @return {Object} - */ _createThrownValue: function(value, objectGroup) { var remoteObject = this._wrapObject(value, objectGroup); try { - remoteObject.description = this._toString(value); + remoteObject.description = toStringDescription(value); } catch (e) {} - return { wasThrown: true, - result: remoteObject }; + return { + wasThrown: true, + result: remoteObject + }; }, - /** - * @param {Function} evalFunction - * @param {Object} object - * @param {string} objectGroup - * @param {string} expression - * @param {boolean} isEvalOnCallFrame - * @param {boolean} injectCommandLineAPI - * @return {*} - */ - _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI) + _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, saveResult) { var commandLineAPI = null; if (injectCommandLineAPI) { @@ -480,8 +487,8 @@ InjectedScript.prototype = { var expressionFunction = evalFunction.call(object, boundExpressionFunctionString); var result = expressionFunction.apply(null, parameters); - if (objectGroup === "console") - this._lastResult = result; + if (objectGroup === "console" && saveResult) + this._saveResult(result); return result; } @@ -500,8 +507,8 @@ InjectedScript.prototype = { var result = evalFunction.call(inspectedGlobalObject, expression); - if (objectGroup === "console") - this._lastResult = result; + if (objectGroup === "console" && saveResult) + this._saveResult(result); return result; } finally { @@ -514,10 +521,6 @@ InjectedScript.prototype = { } }, - /** - * @param {Object} callFrame - * @return {Array.<InjectedScript.CallFrameProxy>|boolean} - */ wrapCallFrames: function(callFrame) { if (!callFrame) @@ -532,29 +535,14 @@ InjectedScript.prototype = { return result; }, - /** - * @param {Object} topCallFrame - * @param {string} callFrameId - * @param {string} expression - * @param {string} objectGroup - * @param {boolean} injectCommandLineAPI - * @param {boolean} returnByValue - * @param {boolean} generatePreview - * @return {*} - */ - evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview) + evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, saveResult) { var callFrame = this._callFrameForId(topCallFrame, callFrameId); if (!callFrame) return "Could not find call frame with given id"; - return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview); + return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview, saveResult); }, - /** - * @param {Object} topCallFrame - * @param {string} callFrameId - * @return {Object} - */ _callFrameForId: function(topCallFrame, callFrameId) { var parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")"); @@ -565,118 +553,129 @@ InjectedScript.prototype = { return callFrame; }, - /** - * @param {Object} objectId - * @return {Object} - */ _objectForId: function(objectId) { return this._idToWrappedObject[objectId.id]; }, - /** - * @param {string} objectId - * @return {Object} - */ findObjectById: function(objectId) { var parsedObjectId = this._parseObjectId(objectId); return this._objectForId(parsedObjectId); }, - /** - * @param {string} name - * @return {Object} - */ module: function(name) { return this._modules[name]; }, - /** - * @param {string} name - * @param {string} source - * @return {Object} - */ injectModule: function(name, source, host) { delete this._modules[name]; + var moduleFunction = InjectedScriptHost.evaluate("(" + source + ")"); if (typeof moduleFunction !== "function") { if (inspectedGlobalObject.console) inspectedGlobalObject.console.error("Web Inspector error: A function was expected for module %s evaluation", name); return null; } + var module = moduleFunction.call(inspectedGlobalObject, InjectedScriptHost, inspectedGlobalObject, injectedScriptId, this, host); this._modules[name] = module; return module; }, - _propertyDescriptors: function(object, ownProperties, ownAndGetterProperties) + _internalPropertyDescriptors: function(object, completeDescriptor) { - // Modes: - // - ownProperties - only own properties and __proto__ - // - ownAndGetterProperties - own properties, __proto__, and getters in the prototype chain - // - neither - get all properties in the prototype chain, exclude __proto__ + var internalProperties = InjectedScriptHost.getInternalProperties(object); + if (!internalProperties) + return null; + + var descriptors = []; + for (var i = 0; i < internalProperties.length; i++) { + var property = internalProperties[i]; + var descriptor = {name: property.name, value: property.value}; + if (completeDescriptor) { + descriptor.writable = false; + descriptor.configurable = false; + descriptor.enumerable = false; + descriptor.isOwn = true; + } + descriptors.push(descriptor); + } + return descriptors; + }, + _propertyDescriptors: function(object, collectionMode) + { var descriptors = []; - var nameProcessed = {}; - nameProcessed["__proto__"] = null; + var nameProcessed = new Set; - function createFakeValueDescriptor(name, descriptor, isOwnProperty) + function createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, possibleNativeBindingGetter) { try { - return {name: name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false}; + var descriptor = {name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false}; + if (possibleNativeBindingGetter) + descriptor.nativeGetter = true; + if (isOwnProperty) + descriptor.isOwn = true; + if (symbol) + descriptor.symbol = symbol; + return descriptor; } catch (e) { - var errorDescriptor = {name: name, value: e, wasThrown: true}; + var errorDescriptor = {name, value: e, wasThrown: true}; if (isOwnProperty) errorDescriptor.isOwn = true; + if (symbol) + errorDescriptor.symbol = symbol; return errorDescriptor; } } function processDescriptor(descriptor, isOwnProperty, possibleNativeBindingGetter) { - // Own properties only. - if (ownProperties) { - if (isOwnProperty) - descriptors.push(descriptor); + // All properties. + if (collectionMode & InjectedScript.CollectionMode.AllProperties) { + descriptors.push(descriptor); return; } - // Own and getter properties. - if (ownAndGetterProperties) { - if (isOwnProperty) { - // Own property, include the descriptor as is. - descriptors.push(descriptor); - } else if (descriptor.hasOwnProperty("get") && descriptor.get) { - // Getter property in the prototype chain. Create a fake value descriptor. - descriptors.push(createFakeValueDescriptor(descriptor.name, descriptor, isOwnProperty)); - } else if (possibleNativeBindingGetter) { + // Own properties. + if (collectionMode & InjectedScript.CollectionMode.OwnProperties && isOwnProperty) { + descriptors.push(descriptor); + return; + } + + // Native Getter properties. + if (collectionMode & InjectedScript.CollectionMode.NativeGetterProperties) { + // FIXME: <https://webkit.org/b/140575> Web Inspector: Native Bindings Descriptors are Incomplete + // if (descriptor.hasOwnProperty("get") && descriptor.get && isNativeFunction(descriptor.get)) { ... } + + if (possibleNativeBindingGetter) { // Possible getter property in the prototype chain. descriptors.push(descriptor); + return; } - return; } - - // All properties. - descriptors.push(descriptor); } - function processPropertyNames(o, names, isOwnProperty) + function processProperties(o, properties, isOwnProperty) { - for (var i = 0; i < names.length; ++i) { - var name = names[i]; - if (nameProcessed[name] || name === "__proto__") + for (var i = 0; i < properties.length; ++i) { + var property = properties[i]; + if (nameProcessed.has(property) || property === "__proto__") continue; - nameProcessed[name] = true; + nameProcessed.add(property); + + var name = toString(property); + var symbol = isSymbol(property) ? property : null; - var descriptor = Object.getOwnPropertyDescriptor(o, name); + var descriptor = Object.getOwnPropertyDescriptor(o, property); if (!descriptor) { // FIXME: Bad descriptor. Can we get here? // Fall back to very restrictive settings. - var fakeDescriptor = createFakeValueDescriptor(name, {writable: false, configurable: false, enumerable: false}, isOwnProperty); + var fakeDescriptor = createFakeValueDescriptor(name, symbol, {writable: false, configurable: false, enumerable: false}, isOwnProperty); processDescriptor(fakeDescriptor, isOwnProperty); continue; } @@ -685,7 +684,7 @@ InjectedScript.prototype = { // FIXME: <https://webkit.org/b/140575> Web Inspector: Native Bindings Descriptors are Incomplete // Developers may create such a descriptors, so we should be resilient: // var x = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p") - var fakeDescriptor = createFakeValueDescriptor(name, descriptor, isOwnProperty); + var fakeDescriptor = createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, true); processDescriptor(fakeDescriptor, isOwnProperty, true); continue; } @@ -693,19 +692,45 @@ InjectedScript.prototype = { descriptor.name = name; if (isOwnProperty) descriptor.isOwn = true; + if (symbol) + descriptor.symbol = symbol; processDescriptor(descriptor, isOwnProperty); } } - // Iterate prototype chain. + function arrayIndexPropertyNames(o, length) + { + var array = new Array(length); + for (var i = 0; i < length; ++i) { + if (i in o) + array.push("" + i); + } + return array; + } + + // FIXME: <https://webkit.org/b/143589> Web Inspector: Better handling for large collections in Object Trees + // For array types with a large length we attempt to skip getOwnPropertyNames and instead just sublist of indexes. + var isArrayTypeWithLargeLength = false; + try { + isArrayTypeWithLargeLength = injectedScript._subtype(object) === "array" && isFinite(object.length) && object.length > 100; + } catch(e) {} + for (var o = object; this._isDefined(o); o = o.__proto__) { var isOwnProperty = o === object; - processPropertyNames(o, Object.getOwnPropertyNames(o), isOwnProperty); - if (ownProperties) + + if (isArrayTypeWithLargeLength && isOwnProperty) + processProperties(o, arrayIndexPropertyNames(o, 100), isOwnProperty); + else { + processProperties(o, Object.getOwnPropertyNames(o), isOwnProperty); + if (Object.getOwnPropertySymbols) + processProperties(o, Object.getOwnPropertySymbols(o), isOwnProperty); + } + + if (collectionMode === InjectedScript.CollectionMode.OwnProperties) break; } - - // Include __proto__ at the end. + + // Always include __proto__ at the end. try { if (object.__proto__) descriptors.push({name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true}); @@ -714,41 +739,29 @@ InjectedScript.prototype = { return descriptors; }, - /** - * @param {*} object - * @return {boolean} - */ _isDefined: function(object) { return !!object || this._isHTMLAllCollection(object); }, - /** - * @param {*} object - * @return {boolean} - */ _isHTMLAllCollection: function(object) { // document.all is reported as undefined, but we still want to process it. return (typeof object === "undefined") && InjectedScriptHost.isHTMLAllCollection(object); }, - /** - * @param {Object=} obj - * @return {string?} - */ _subtype: function(obj) { if (obj === null) return "null"; - if (this.isPrimitiveValue(obj)) + if (this.isPrimitiveValue(obj) || isSymbol(obj)) return null; if (this._isHTMLAllCollection(obj)) return "array"; - var preciseType = InjectedScriptHost.type(obj); + var preciseType = InjectedScriptHost.subtype(obj); if (preciseType) return preciseType; @@ -756,321 +769,621 @@ InjectedScript.prototype = { try { if (typeof obj.splice === "function" && isFinite(obj.length)) return "array"; - if (Object.prototype.toString.call(obj) === "[object Arguments]" && isFinite(obj.length)) // arguments. - return "array"; } catch (e) { } - // If owning frame has navigated to somewhere else window properties will be undefined. return null; }, - /** - * @param {*} obj - * @return {string?} - */ + _nodeDescription: function(node) + { + var isXMLDocument = node.ownerDocument && !!node.ownerDocument.xmlVersion; + var description = isXMLDocument ? node.nodeName : node.nodeName.toLowerCase(); + + switch (node.nodeType) { + case 1: // Node.ELEMENT_NODE + if (node.id) + description += "#" + node.id; + if (node.hasAttribute("class")) { + // Using .getAttribute() is a workaround for SVG*Element.className returning SVGAnimatedString, + // which doesn't have any useful String methods. See <https://webkit.org/b/145363/>. + description += "." + node.getAttribute("class").trim().replace(/\s+/g, "."); + } + return description; + + default: + return description; + } + }, + + _classPreview: function(classConstructorValue) + { + return "class " + classConstructorValue.name; + }, + + _nodePreview: function(node) + { + var isXMLDocument = node.ownerDocument && !!node.ownerDocument.xmlVersion; + var nodeName = isXMLDocument ? node.nodeName : node.nodeName.toLowerCase(); + + switch (node.nodeType) { + case 1: // Node.ELEMENT_NODE + if (node.id) + return "<" + nodeName + " id=\"" + node.id + "\">"; + if (node.className) + return "<" + nodeName + " class=\"" + node.className + "\">"; + if (nodeName === "input" && node.type) + return "<" + nodeName + " type=\"" + node.type + "\">"; + return "<" + nodeName + ">"; + + case 3: // Node.TEXT_NODE + return nodeName + " \"" + node.nodeValue + "\""; + + case 8: // Node.COMMENT_NODE + return "<!--" + node.nodeValue + "-->"; + + case 10: // Node.DOCUMENT_TYPE_NODE + return "<!DOCTYPE " + nodeName + ">"; + + default: + return nodeName; + } + }, + _describe: function(obj) { if (this.isPrimitiveValue(obj)) return null; - obj = /** @type {Object} */ (obj); + if (isSymbol(obj)) + return toString(obj); - // Type is object, get subtype. var subtype = this._subtype(obj); if (subtype === "regexp") - return this._toString(obj); + return toString(obj); if (subtype === "date") - return this._toString(obj); - - if (subtype === "node") { - var description = obj.nodeName.toLowerCase(); - switch (obj.nodeType) { - case 1 /* Node.ELEMENT_NODE */: - description += obj.id ? "#" + obj.id : ""; - var className = obj.className; - description += className ? "." + className : ""; - break; - case 10 /*Node.DOCUMENT_TYPE_NODE */: - description = "<!DOCTYPE " + description + ">"; - break; - } - return description; - } + return toString(obj); + + if (subtype === "error") + return toString(obj); + + if (subtype === "node") + return this._nodeDescription(obj); var className = InjectedScriptHost.internalConstructorName(obj); - if (subtype === "array") { - if (typeof obj.length === "number") - className += "[" + obj.length + "]"; + if (subtype === "array") return className; - } // NodeList in JSC is a function, check for array prior to this. if (typeof obj === "function") - return this._toString(obj); + return toString(obj); + // If Object, try for a better name from the constructor. if (className === "Object") { - // In Chromium DOM wrapper prototypes will have Object as their constructor name, - // get the real DOM wrapper name from the constructor property. var constructorName = obj.constructor && obj.constructor.name; if (constructorName) return constructorName; } + return className; }, - /** - * @param {*} obj - * @return {string} - */ - _toString: function(obj) + _getSetEntries: function(object, skip, numberToFetch) + { + var entries = []; + + for (var value of object) { + if (skip > 0) { + skip--; + continue; + } + + entries.push({value}); + + if (numberToFetch && entries.length === numberToFetch) + break; + } + + return entries; + }, + + _getMapEntries: function(object, skip, numberToFetch) { - // We don't use String(obj) because inspectedGlobalObject.String is undefined if owning frame navigated to another page. - return "" + obj; + var entries = []; + + for (var [key, value] of object) { + if (skip > 0) { + skip--; + continue; + } + + entries.push({key, value}); + + if (numberToFetch && entries.length === numberToFetch) + break; + } + + return entries; + }, + + _getWeakMapEntries: function(object, numberToFetch) + { + return InjectedScriptHost.weakMapEntries(object, numberToFetch); + }, + + _getWeakSetEntries: function(object, numberToFetch) + { + return InjectedScriptHost.weakSetEntries(object, numberToFetch); + }, + + _getIteratorEntries: function(object, numberToFetch) + { + return InjectedScriptHost.iteratorEntries(object, numberToFetch); + }, + + _entries: function(object, subtype, startIndex, numberToFetch) + { + if (subtype === "set") + return this._getSetEntries(object, startIndex, numberToFetch); + if (subtype === "map") + return this._getMapEntries(object, startIndex, numberToFetch); + if (subtype === "weakmap") + return this._getWeakMapEntries(object, numberToFetch); + if (subtype === "weakset") + return this._getWeakSetEntries(object, numberToFetch); + if (subtype === "iterator") + return this._getIteratorEntries(object, numberToFetch); + + throw "unexpected type"; + }, + + _saveResult: function(result) + { + this._lastResult = result; + + if (result === undefined || result === null) + return; + + var existingIndex = this._savedResults.indexOf(result); + if (existingIndex !== -1) { + this._savedResultIndex = existingIndex; + return; + } + + this._savedResultIndex = this._nextSavedResultIndex; + this._savedResults[this._nextSavedResultIndex++] = result; + + // $n is limited from $1-$99. $0 is special. + if (this._nextSavedResultIndex >= 100) + this._nextSavedResultIndex = 1; + }, + + _savedResult: function(index) + { + return this._savedResults[index]; } } -/** - * @type {InjectedScript} - * @const - */ -var injectedScript = new InjectedScript(); - -/** - * @constructor - * @param {*} object - * @param {string=} objectGroupName - * @param {boolean=} forceValueType - * @param {boolean=} generatePreview - * @param {?Array.<string>=} columnNames - */ +var injectedScript = new InjectedScript; + + InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, generatePreview, columnNames) { this.type = typeof object; + + if (this.type === "undefined" && injectedScript._isHTMLAllCollection(object)) + this.type = "object"; + if (injectedScript.isPrimitiveValue(object) || object === null || forceValueType) { // We don't send undefined values over JSON. - if (typeof object !== "undefined") + if (this.type !== "undefined") this.value = object; - // Null object is object with 'null' subtype' + // Null object is object with 'null' subtype. if (object === null) this.subtype = "null"; // Provide user-friendly number values. - if (typeof object === "number") - this.description = object + ""; + if (this.type === "number") + this.description = toStringDescription(object); return; } - object = /** @type {Object} */ (object); - this.objectId = injectedScript._bind(object, objectGroupName); + var subtype = injectedScript._subtype(object); if (subtype) this.subtype = subtype; + this.className = InjectedScriptHost.internalConstructorName(object); this.description = injectedScript._describe(object); - if (generatePreview && (this.type === "object" || injectedScript._isHTMLAllCollection(object))) + if (subtype === "array") + this.size = typeof object.length === "number" ? object.length : 0; + else if (subtype === "set" || subtype === "map") + this.size = object.size; + else if (subtype === "weakmap") + this.size = InjectedScriptHost.weakMapSize(object); + else if (subtype === "weakset") + this.size = InjectedScriptHost.weakSetSize(object); + else if (subtype === "class") { + this.classPrototype = injectedScript._wrapObject(object.prototype, objectGroupName); + this.className = object.name; + } + + if (generatePreview && this.type === "object") this.preview = this._generatePreview(object, undefined, columnNames); } InjectedScript.RemoteObject.prototype = { - /** - * @param {Object} object - * @param {Array.<string>=} firstLevelKeys - * @param {?Array.<string>=} secondLevelKeys - * @return {Object} preview - */ + _emptyPreview: function() + { + var preview = { + type: this.type, + description: this.description || toString(this.value), + lossless: true, + }; + + if (this.subtype) { + preview.subtype = this.subtype; + if (this.subtype !== "null") { + preview.overflow = false; + preview.properties = []; + } + } + + if ("size" in this) + preview.size = this.size; + + return preview; + }, + + _createObjectPreviewForValue: function(value) + { + var remoteObject = new InjectedScript.RemoteObject(value, undefined, false, true, undefined); + if (remoteObject.objectId) + injectedScript.releaseObject(remoteObject.objectId); + if (remoteObject.classPrototype && remoteObject.classPrototype.objectId) + injectedScript.releaseObject(remoteObject.classPrototype.objectId); + + return remoteObject.preview || remoteObject._emptyPreview(); + }, + _generatePreview: function(object, firstLevelKeys, secondLevelKeys) { - var preview = {}; - preview.lossless = true; - preview.overflow = false; - preview.properties = []; + var preview = this._emptyPreview(); + + // Primitives just have a value. + if (this.type !== "object") + return; var isTableRowsRequest = secondLevelKeys === null || secondLevelKeys; var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0; var propertiesThreshold = { properties: isTableRowsRequest ? 1000 : Math.max(5, firstLevelKeysCount), - indexes: isTableRowsRequest ? 1000 : Math.max(100, firstLevelKeysCount) + indexes: isTableRowsRequest ? 1000 : Math.max(10, firstLevelKeysCount) }; - for (var o = object; injectedScript._isDefined(o); o = o.__proto__) - this._generateProtoPreview(o, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys); + + try { + // Maps, Sets, and Iterators have entries. + if (this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap" || this.subtype === "weakset" || this.subtype === "iterator") + this._appendEntryPreviews(object, preview); + + preview.properties = []; + + // Internal Properties. + var internalPropertyDescriptors = injectedScript._internalPropertyDescriptors(object, true); + if (internalPropertyDescriptors) { + this._appendPropertyPreviews(preview, internalPropertyDescriptors, true, propertiesThreshold, firstLevelKeys, secondLevelKeys); + if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) + return preview; + } + + if (preview.entries) + return preview; + + // Properties. + var descriptors = injectedScript._propertyDescriptors(object, InjectedScript.CollectionMode.AllProperties); + this._appendPropertyPreviews(preview, descriptors, false, propertiesThreshold, firstLevelKeys, secondLevelKeys); + if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) + return preview; + } catch (e) { + preview.lossless = false; + } + return preview; }, - /** - * @param {Object} object - * @param {Object} preview - * @param {Object} propertiesThreshold - * @param {Array.<string>=} firstLevelKeys - * @param {Array.<string>=} secondLevelKeys - */ - _generateProtoPreview: function(object, preview, propertiesThreshold, firstLevelKeys, secondLevelKeys) + _appendPropertyPreviews: function(preview, descriptors, internal, propertiesThreshold, firstLevelKeys, secondLevelKeys) { - var propertyNames = firstLevelKeys ? firstLevelKeys : Object.keys(/** @type {!Object} */(object)); - try { - for (var i = 0; i < propertyNames.length; ++i) { - if (!propertiesThreshold.properties || !propertiesThreshold.indexes) { - preview.overflow = true; + for (var descriptor of descriptors) { + // Seen enough. + if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) + break; + + // Error in descriptor. + if (descriptor.wasThrown) { + preview.lossless = false; + continue; + } + + // Do not show "__proto__" in preview. + var name = descriptor.name; + if (name === "__proto__") + continue; + + // For arrays, only allow indexes. + if (this.subtype === "array" && !isUInt32(name)) + continue; + + // Do not show non-enumerable non-own properties. Special case to allow array indexes that may be on the prototype. + if (!descriptor.enumerable && !descriptor.isOwn && this.subtype !== "array") + continue; + + // If we have a filter, only show properties in the filter. + // FIXME: Currently these filters do nothing on the backend. + if (firstLevelKeys && !firstLevelKeys.includes(name)) + continue; + + // Getter/setter. + if (!("value" in descriptor)) { + preview.lossless = false; + this._appendPropertyPreview(preview, internal, {name, type: "accessor"}, propertiesThreshold); + continue; + } + + // Null value. + var value = descriptor.value; + if (value === null) { + this._appendPropertyPreview(preview, internal, {name, type: "object", subtype: "null", value: "null"}, propertiesThreshold); + continue; + } + + // Ignore non-enumerable functions. + var type = typeof value; + if (!descriptor.enumerable && type === "function") + continue; + + // Fix type of document.all. + if (type === "undefined" && injectedScript._isHTMLAllCollection(value)) + type = "object"; + + // Primitive. + const maxLength = 100; + if (InjectedScript.primitiveTypes[type]) { + if (type === "string" && value.length > maxLength) { + value = this._abbreviateString(value, maxLength, true); preview.lossless = false; - break; } - var name = propertyNames[i]; - if (this.subtype === "array" && name === "length") - continue; + this._appendPropertyPreview(preview, internal, {name, type, value: toStringDescription(value)}, propertiesThreshold); + continue; + } - var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */(object), name); - if (!("value" in descriptor) || !descriptor.enumerable) { + // Symbol. + if (isSymbol(value)) { + var symbolString = toString(value); + if (symbolString.length > maxLength) { + symbolString = this._abbreviateString(symbolString, maxLength, true); preview.lossless = false; - continue; } + this._appendPropertyPreview(preview, internal, {name, type, value: symbolString}, propertiesThreshold); + return; + } - var value = descriptor.value; - if (value === null) { - this._appendPropertyPreview(preview, { name: name, type: "object", value: "null" }, propertiesThreshold); - continue; + // Object. + var property = {name, type}; + var subtype = injectedScript._subtype(value); + if (subtype) + property.subtype = subtype; + + // Second level. + if ((secondLevelKeys === null || secondLevelKeys) || this._isPreviewableObject(value)) { + // FIXME: If we want secondLevelKeys filter to continue we would need some refactoring. + var subPreview = this._createObjectPreviewForValue(value); + property.valuePreview = subPreview; + if (!subPreview.lossless) + preview.lossless = false; + if (subPreview.overflow) + preview.overflow = true; + } else { + var description = ""; + if (type !== "function" || subtype === "class") { + var fullDescription; + if (subtype === "class") + fullDescription = "class " + value.name; + else if (subtype === "node") + fullDescription = injectedScript._nodePreview(value); + else + fullDescription = injectedScript._describe(value); + description = this._abbreviateString(fullDescription, maxLength, subtype === "regexp"); } + property.value = description; + preview.lossless = false; + } - const maxLength = 100; - var type = typeof value; - - if (InjectedScript.primitiveTypes[type]) { - if (type === "string") { - if (value.length > maxLength) { - value = this._abbreviateString(value, maxLength, true); - preview.lossless = false; - } - value = value.replace(/\n/g, "\u21B5"); - } - this._appendPropertyPreview(preview, { name: name, type: type, value: value + "" }, propertiesThreshold); - continue; - } + this._appendPropertyPreview(preview, internal, property, propertiesThreshold); + } + }, - if (secondLevelKeys === null || secondLevelKeys) { - var subPreview = this._generatePreview(value, secondLevelKeys || undefined); - var property = { name: name, type: type, valuePreview: subPreview }; - this._appendPropertyPreview(preview, property, propertiesThreshold); - if (!subPreview.lossless) - preview.lossless = false; - if (subPreview.overflow) - preview.overflow = true; - continue; - } + _appendPropertyPreview: function(preview, internal, property, propertiesThreshold) + { + if (toString(property.name >>> 0) === property.name) + propertiesThreshold.indexes--; + else + propertiesThreshold.properties--; - preview.lossless = false; + if (propertiesThreshold.indexes < 0 || propertiesThreshold.properties < 0) { + preview.overflow = true; + preview.lossless = false; + return; + } - var subtype = injectedScript._subtype(value); - var description = ""; - if (type !== "function") - description = this._abbreviateString(/** @type {string} */ (injectedScript._describe(value)), maxLength, subtype === "regexp"); + if (internal) + property.internal = true; - var property = { name: name, type: type, value: description }; - if (subtype) - property.subtype = subtype; - this._appendPropertyPreview(preview, property, propertiesThreshold); - } - } catch (e) { + preview.properties.push(property); + }, + + _appendEntryPreviews: function(object, preview) + { + // Fetch 6, but only return 5, so we can tell if we overflowed. + var entries = injectedScript._entries(object, this.subtype, 0, 6); + if (!entries) + return; + + if (entries.length > 5) { + entries.pop(); + preview.overflow = true; + preview.lossless = false; } + + preview.entries = entries.map(function(entry) { + entry.value = this._createObjectPreviewForValue(entry.value); + if ("key" in entry) + entry.key = this._createObjectPreviewForValue(entry.key); + return entry; + }, this); }, - /** - * @param {Object} preview - * @param {Object} property - * @param {Object} propertiesThreshold - */ - _appendPropertyPreview: function(preview, property, propertiesThreshold) + _isPreviewableObject: function(object) { - if (isNaN(property.name)) - propertiesThreshold.properties--; - else - propertiesThreshold.indexes--; - preview.properties.push(property); + return this._isPreviewableObjectInternal(object, new Set, 1); + }, + + _isPreviewableObjectInternal: function(object, knownObjects, depth) + { + // Deep object. + if (depth > 3) + return false; + + // Primitive. + if (injectedScript.isPrimitiveValue(object) || isSymbol(object)) + return true; + + // Null. + if (object === null) + return true; + + // Cyclic objects. + if (knownObjects.has(object)) + return false; + + ++depth; + knownObjects.add(object); + + // Arrays are simple if they have 5 or less simple objects. + var subtype = injectedScript._subtype(object); + if (subtype === "array") { + var length = object.length; + if (length > 5) + return false; + for (var i = 0; i < length; ++i) { + if (!this._isPreviewableObjectInternal(object[i], knownObjects, depth)) + return false; + } + return true; + } + + // Not a basic object. + if (object.__proto__ && object.__proto__.__proto__) + return false; + + // Objects are simple if they have 3 or less simple properties. + var ownPropertyNames = Object.getOwnPropertyNames(object); + if (ownPropertyNames.length > 3) + return false; + for (var propertyName of ownPropertyNames) { + if (!this._isPreviewableObjectInternal(object[propertyName], knownObjects, depth)) + return false; + } + + return true; }, - /** - * @param {string} string - * @param {number} maxLength - * @param {boolean=} middle - * @returns - */ _abbreviateString: function(string, maxLength, middle) { if (string.length <= maxLength) return string; + if (middle) { var leftHalf = maxLength >> 1; var rightHalf = maxLength - leftHalf - 1; return string.substr(0, leftHalf) + "\u2026" + string.substr(string.length - rightHalf, rightHalf); } + return string.substr(0, maxLength) + "\u2026"; } } -/** - * @constructor - * @param {number} ordinal - * @param {Object} callFrame - */ + InjectedScript.CallFrameProxy = function(ordinal, callFrame) { this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + injectedScriptId + "}"; this.functionName = (callFrame.type === "function" ? callFrame.functionName : ""); - this.location = { scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column }; + this.location = {scriptId: String(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column}; this.scopeChain = this._wrapScopeChain(callFrame); this.this = injectedScript._wrapObject(callFrame.thisObject, "backtrace"); } InjectedScript.CallFrameProxy.prototype = { - /** - * @param {Object} callFrame - * @return {!Array.<DebuggerAgent.Scope>} - */ _wrapScopeChain: function(callFrame) { var scopeChain = callFrame.scopeChain; var scopeChainProxy = []; - for (var i = 0; i < scopeChain.length; i++) { - var scope = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace"); - scopeChainProxy.push(scope); - } + for (var i = 0; i < scopeChain.length; i++) + scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace"); return scopeChainProxy; } } -/** - * @param {number} scopeTypeCode - * @param {*} scopeObject - * @param {string} groupId - * @return {!DebuggerAgent.Scope} - */ -InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId) { - const GLOBAL_SCOPE = 0; - const LOCAL_SCOPE = 1; - const WITH_SCOPE = 2; - const CLOSURE_SCOPE = 3; - const CATCH_SCOPE = 4; - - /** @type {!Object.<number, string>} */ - var scopeTypeNames = {}; - scopeTypeNames[GLOBAL_SCOPE] = "global"; - scopeTypeNames[LOCAL_SCOPE] = "local"; - scopeTypeNames[WITH_SCOPE] = "with"; - scopeTypeNames[CLOSURE_SCOPE] = "closure"; - scopeTypeNames[CATCH_SCOPE] = "catch"; +InjectedScript.CallFrameProxy._scopeTypeNames = { + 0: "global", // GLOBAL_SCOPE + 1: "local", // LOCAL_SCOPE + 2: "with", // WITH_SCOPE + 3: "closure", // CLOSURE_SCOPE + 4: "catch", // CATCH_SCOPE + 5: "functionName", // FUNCTION_NAME_SCOPE +} +InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId) +{ return { object: injectedScript._wrapObject(scopeObject, groupId), - type: /** @type {DebuggerAgent.ScopeType} */ (scopeTypeNames[scopeTypeCode]) + type: InjectedScript.CallFrameProxy._scopeTypeNames[scopeTypeCode] }; } + +function slice(array, index) +{ + var result = []; + for (var i = index || 0; i < array.length; ++i) + result.push(array[i]); + return result; +} + +function bind(func, thisObject, var_args) +{ + var args = slice(arguments, 2); + return function(var_args) { + return func.apply(thisObject, args.concat(slice(arguments))); + } +} + function BasicCommandLineAPI() { this.$_ = injectedScript._lastResult; + this.$exception = injectedScript._exceptionValue; + + // $1-$99 + for (var i = 1; i <= injectedScript._savedResults.length; ++i) { + var member = "$" + i; + if (member in inspectedGlobalObject) + continue; + this.__defineGetter__("$" + i, bind(injectedScript._savedResult, injectedScript, i)); + } } return injectedScript; diff --git a/inspector/InspectorAgentBase.h b/inspector/InspectorAgentBase.h index f6b6c55..63404cf 100644 --- a/inspector/InspectorAgentBase.h +++ b/inspector/InspectorAgentBase.h @@ -31,10 +31,10 @@ namespace Inspector { -class InspectorBackendDispatcher; -class InspectorFrontendChannel; +class BackendDispatcher; +class FrontendChannel; -enum class InspectorDisconnectReason { +enum class DisconnectReason { InspectedTargetDestroyed, InspectorDestroyed }; @@ -43,8 +43,10 @@ class InspectorAgentBase { public: virtual ~InspectorAgentBase() { } - virtual void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*) = 0; - virtual void willDestroyFrontendAndBackend(InspectorDisconnectReason reason) = 0; + String domainName() const { return m_name; } + + virtual void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher*) = 0; + virtual void willDestroyFrontendAndBackend(DisconnectReason) = 0; virtual void discardAgent() { } protected: @@ -55,7 +57,7 @@ protected: String m_name; }; - + } // namespace Inspector #endif // !defined(InspectorAgentBase_h) diff --git a/inspector/InspectorAgentRegistry.cpp b/inspector/InspectorAgentRegistry.cpp index 4124cfe..bcc0988 100644 --- a/inspector/InspectorAgentRegistry.cpp +++ b/inspector/InspectorAgentRegistry.cpp @@ -27,34 +27,41 @@ #include "config.h" #include "InspectorAgentRegistry.h" -#if ENABLE(INSPECTOR) - #include "InspectorAgentBase.h" namespace Inspector { -InspectorAgentRegistry::InspectorAgentRegistry() +AgentRegistry::AgentRegistry() { } -void InspectorAgentRegistry::append(std::unique_ptr<InspectorAgentBase> agent) +void AgentRegistry::append(std::unique_ptr<InspectorAgentBase> agent) { m_agents.append(WTF::move(agent)); } -void InspectorAgentRegistry::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +void AgentRegistry::appendExtraAgent(std::unique_ptr<InspectorAgentBase> agent) +{ + m_extraDomains.append(agent->domainName()); + + append(WTF::move(agent)); +} +#endif + +void AgentRegistry::didCreateFrontendAndBackend(FrontendChannel* frontendChannel, BackendDispatcher* backendDispatcher) { for (size_t i = 0; i < m_agents.size(); i++) m_agents[i]->didCreateFrontendAndBackend(frontendChannel, backendDispatcher); } -void InspectorAgentRegistry::willDestroyFrontendAndBackend(InspectorDisconnectReason reason) +void AgentRegistry::willDestroyFrontendAndBackend(DisconnectReason reason) { for (size_t i = 0; i < m_agents.size(); i++) m_agents[i]->willDestroyFrontendAndBackend(reason); } -void InspectorAgentRegistry::discardAgents() +void AgentRegistry::discardAgents() { for (size_t i = 0; i < m_agents.size(); i++) m_agents[i]->discardAgent(); @@ -62,4 +69,3 @@ void InspectorAgentRegistry::discardAgents() } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/InspectorAgentRegistry.h b/inspector/InspectorAgentRegistry.h index 17d65e7..962f006 100644 --- a/inspector/InspectorAgentRegistry.h +++ b/inspector/InspectorAgentRegistry.h @@ -28,31 +28,41 @@ #define InspectorAgentRegistry_h #include <wtf/Vector.h> +#include <wtf/text/WTFString.h> namespace Inspector { +class BackendDispatcher; +class FrontendChannel; class InspectorAgentBase; -class InspectorBackendDispatcher; -class InspectorFrontendChannel; -enum class InspectorDisconnectReason; -class JS_EXPORT_PRIVATE InspectorAgentRegistry { +enum class DisconnectReason; + +class JS_EXPORT_PRIVATE AgentRegistry { public: - InspectorAgentRegistry(); + AgentRegistry(); void append(std::unique_ptr<InspectorAgentBase>); - void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*); - void willDestroyFrontendAndBackend(InspectorDisconnectReason reason); + void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher*); + void willDestroyFrontendAndBackend(DisconnectReason); void discardAgents(); +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + void appendExtraAgent(std::unique_ptr<InspectorAgentBase>); + Vector<String> extraDomains() const { return m_extraDomains; } +#endif + private: // These are declared here to avoid MSVC from trying to create default iplementations which would // involve generating a copy constructor and copy assignment operator for the Vector of std::unique_ptrs. - InspectorAgentRegistry(const InspectorAgentRegistry&) = delete; - InspectorAgentRegistry& operator=(const InspectorAgentRegistry&) = delete; + AgentRegistry(const AgentRegistry&) = delete; + AgentRegistry& operator=(const AgentRegistry&) = delete; Vector<std::unique_ptr<InspectorAgentBase>> m_agents; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + Vector<String> m_extraDomains; +#endif }; } // namespace Inspector diff --git a/inspector/InspectorBackendDispatcher.cpp b/inspector/InspectorBackendDispatcher.cpp index 30a66f7..f88cfbd 100644 --- a/inspector/InspectorBackendDispatcher.cpp +++ b/inspector/InspectorBackendDispatcher.cpp @@ -27,8 +27,6 @@ #include "config.h" #include "InspectorBackendDispatcher.h" -#if ENABLE(INSPECTOR) - #include "InspectorFrontendChannel.h" #include "InspectorValues.h" #include <wtf/text/CString.h> @@ -36,80 +34,80 @@ namespace Inspector { -InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtr<InspectorBackendDispatcher> backendDispatcher, int id) - : m_backendDispatcher(backendDispatcher) +BackendDispatcher::CallbackBase::CallbackBase(Ref<BackendDispatcher>&& backendDispatcher, int id) + : m_backendDispatcher(WTF::move(backendDispatcher)) , m_id(id) , m_alreadySent(false) { } -bool InspectorBackendDispatcher::CallbackBase::isActive() const +bool BackendDispatcher::CallbackBase::isActive() const { return !m_alreadySent && m_backendDispatcher->isActive(); } -void InspectorBackendDispatcher::CallbackBase::sendFailure(const ErrorString& error) +void BackendDispatcher::CallbackBase::sendFailure(const ErrorString& error) { ASSERT(error.length()); sendIfActive(nullptr, error); } -void InspectorBackendDispatcher::CallbackBase::sendIfActive(PassRefPtr<InspectorObject> partialMessage, const ErrorString& invocationError) +void BackendDispatcher::CallbackBase::sendIfActive(RefPtr<InspectorObject>&& partialMessage, const ErrorString& invocationError) { if (m_alreadySent) return; - m_backendDispatcher->sendResponse(m_id, partialMessage, invocationError); + m_backendDispatcher->sendResponse(m_id, WTF::move(partialMessage), invocationError); m_alreadySent = true; } -PassRefPtr<InspectorBackendDispatcher> InspectorBackendDispatcher::create(InspectorFrontendChannel* inspectorFrontendChannel) +Ref<BackendDispatcher> BackendDispatcher::create(FrontendChannel* frontendChannel) { - return adoptRef(new InspectorBackendDispatcher(inspectorFrontendChannel)); + return adoptRef(*new BackendDispatcher(frontendChannel)); } -void InspectorBackendDispatcher::registerDispatcherForDomain(const String& domain, InspectorSupplementalBackendDispatcher* dispatcher) +void BackendDispatcher::registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher* dispatcher) { auto result = m_dispatchers.add(domain, dispatcher); ASSERT_UNUSED(result, result.isNewEntry); } -void InspectorBackendDispatcher::dispatch(const String& message) +void BackendDispatcher::dispatch(const String& message) { - Ref<InspectorBackendDispatcher> protect(*this); + Ref<BackendDispatcher> protect(*this); - RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message); - if (!parsedMessage) { + RefPtr<InspectorValue> parsedMessage; + if (!InspectorValue::parseJSON(message, parsedMessage)) { reportProtocolError(nullptr, ParseError, ASCIILiteral("Message must be in JSON format")); return; } - RefPtr<InspectorObject> messageObject = parsedMessage->asObject(); - if (!messageObject) { + RefPtr<InspectorObject> messageObject; + if (!parsedMessage->asObject(messageObject)) { reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("Message must be a JSONified object")); return; } - RefPtr<InspectorValue> callIdValue = messageObject->get("id"); - if (!callIdValue) { + RefPtr<InspectorValue> callIdValue; + if (!messageObject->getValue(ASCIILiteral("id"), callIdValue)) { reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("'id' property was not found")); return; } long callId = 0; - if (!callIdValue->asNumber(&callId)) { - reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("The type of 'id' property must be number")); + if (!callIdValue->asInteger(callId)) { + reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("The type of 'id' property must be integer")); return; } - RefPtr<InspectorValue> methodValue = messageObject->get("method"); - if (!methodValue) { + RefPtr<InspectorValue> methodValue; + if (!messageObject->getValue(ASCIILiteral("method"), methodValue)) { reportProtocolError(&callId, InvalidRequest, ASCIILiteral("'method' property wasn't found")); return; } String method; - if (!methodValue->asString(&method)) { + if (!methodValue->asString(method)) { reportProtocolError(&callId, InvalidRequest, ASCIILiteral("The type of 'method' property must be string")); return; } @@ -121,19 +119,19 @@ void InspectorBackendDispatcher::dispatch(const String& message) } String domain = method.substring(0, position); - InspectorSupplementalBackendDispatcher* domainDispatcher = m_dispatchers.get(domain); + SupplementalBackendDispatcher* domainDispatcher = m_dispatchers.get(domain); if (!domainDispatcher) { reportProtocolError(&callId, MethodNotFound, "'" + domain + "' domain was not found"); return; } String domainMethod = method.substring(position + 1); - domainDispatcher->dispatch(callId, domainMethod, messageObject.release()); + domainDispatcher->dispatch(callId, domainMethod, messageObject.releaseNonNull()); } -void InspectorBackendDispatcher::sendResponse(long callId, PassRefPtr<InspectorObject> result, const ErrorString& invocationError) +void BackendDispatcher::sendResponse(long callId, RefPtr<InspectorObject>&& result, const ErrorString& invocationError) { - if (!m_inspectorFrontendChannel) + if (!m_frontendChannel) return; if (invocationError.length()) { @@ -141,18 +139,18 @@ void InspectorBackendDispatcher::sendResponse(long callId, PassRefPtr<InspectorO return; } - RefPtr<InspectorObject> responseMessage = InspectorObject::create(); + Ref<InspectorObject> responseMessage = InspectorObject::create(); responseMessage->setObject(ASCIILiteral("result"), result); - responseMessage->setNumber(ASCIILiteral("id"), callId); - m_inspectorFrontendChannel->sendMessageToFrontend(responseMessage->toJSONString()); + responseMessage->setInteger(ASCIILiteral("id"), callId); + m_frontendChannel->sendMessageToFrontend(responseMessage->toJSONString()); } -void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage) const +void BackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage) const { reportProtocolError(callId, errorCode, errorMessage, nullptr); } -void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const +void BackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage, RefPtr<Inspector::Protocol::Array<String>>&& data) const { static const int errorCodes[] = { -32700, // ParseError @@ -163,102 +161,105 @@ void InspectorBackendDispatcher::reportProtocolError(const long* const callId, C -32000, // ServerError }; - ASSERT(errorCode >= 0); - ASSERT((unsigned)errorCode < WTF_ARRAY_LENGTH(errorCodes)); - ASSERT(errorCodes[errorCode]); + ASSERT_ARG(errorCode, errorCode >= 0); + ASSERT_ARG(errorCode, (unsigned)errorCode < WTF_ARRAY_LENGTH(errorCodes)); + ASSERT_ARG(errorCode, errorCodes[errorCode]); - if (!m_inspectorFrontendChannel) + if (!m_frontendChannel) return; - RefPtr<InspectorObject> error = InspectorObject::create(); - error->setNumber(ASCIILiteral("code"), errorCodes[errorCode]); + Ref<InspectorObject> error = InspectorObject::create(); + error->setInteger(ASCIILiteral("code"), errorCodes[errorCode]); error->setString(ASCIILiteral("message"), errorMessage); if (data) - error->setArray(ASCIILiteral("data"), data); + error->setArray(ASCIILiteral("data"), WTF::move(data)); - RefPtr<InspectorObject> message = InspectorObject::create(); - message->setObject(ASCIILiteral("error"), error.release()); + Ref<InspectorObject> message = InspectorObject::create(); + message->setObject(ASCIILiteral("error"), WTF::move(error)); if (callId) - message->setNumber(ASCIILiteral("id"), *callId); + message->setInteger(ASCIILiteral("id"), *callId); else message->setValue(ASCIILiteral("id"), InspectorValue::null()); - m_inspectorFrontendChannel->sendMessageToFrontend(message->toJSONString()); + m_frontendChannel->sendMessageToFrontend(message->toJSONString()); } template<typename ReturnValueType, typename ValueType, typename DefaultValueType> -static ReturnValueType getPropertyValue(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors, DefaultValueType defaultValue, bool (*asMethod)(InspectorValue*, ValueType*), const char* typeName) +static ReturnValueType getPropertyValue(InspectorObject* object, const String& name, bool* out_optionalValueFound, Inspector::Protocol::Array<String>& protocolErrors, DefaultValueType defaultValue, bool (*asMethod)(InspectorValue&, ValueType&), const char* typeName) { - ASSERT(protocolErrors); - - ValueType value = defaultValue; - if (valueFound) - *valueFound = false; + ValueType result = defaultValue; + // out_optionalValueFound signals to the caller whether an optional property was found. + // if out_optionalValueFound == nullptr, then this is a required property. + if (out_optionalValueFound) + *out_optionalValueFound = false; if (!object) { - if (!valueFound) - protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type '%s'.", name.utf8().data(), typeName)); - return value; + if (!out_optionalValueFound) + protocolErrors.addItem(String::format("'params' object must contain required parameter '%s' with type '%s'.", name.utf8().data(), typeName)); + return result; } - InspectorObject::const_iterator end = object->end(); - InspectorObject::const_iterator valueIterator = object->find(name); - if (valueIterator == end) { - if (!valueFound) - protocolErrors->pushString(String::format("Parameter '%s' with type '%s' was not found.", name.utf8().data(), typeName)); - return value; + auto findResult = object->find(name); + if (findResult == object->end()) { + if (!out_optionalValueFound) + protocolErrors.addItem(String::format("Parameter '%s' with type '%s' was not found.", name.utf8().data(), typeName)); + return result; } - if (!asMethod(valueIterator->value.get(), &value)) { - protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be '%s'.", name.utf8().data(), typeName)); - return value; + if (!asMethod(*findResult->value, result)) { + protocolErrors.addItem(String::format("Parameter '%s' has wrong type. It must be '%s'.", name.utf8().data(), typeName)); + return result; } - if (valueFound) - *valueFound = true; + if (out_optionalValueFound) + *out_optionalValueFound = true; - return value; + return result; } struct AsMethodBridges { - static bool asInt(InspectorValue* value, int* output) { return value->asNumber(output); } - static bool asDouble(InspectorValue* value, double* output) { return value->asNumber(output); } - static bool asString(InspectorValue* value, String* output) { return value->asString(output); } - static bool asBoolean(InspectorValue* value, bool* output) { return value->asBoolean(output); } - static bool asObject(InspectorValue* value, RefPtr<InspectorObject>* output) { return value->asObject(output); } - static bool asArray(InspectorValue* value, RefPtr<InspectorArray>* output) { return value->asArray(output); } + static bool asInteger(InspectorValue& value, int& output) { return value.asInteger(output); } + static bool asDouble(InspectorValue& value, double& output) { return value.asDouble(output); } + static bool asString(InspectorValue& value, String& output) { return value.asString(output); } + static bool asBoolean(InspectorValue& value, bool& output) { return value.asBoolean(output); } + static bool asObject(InspectorValue& value, RefPtr<InspectorObject>& output) { return value.asObject(output); } + static bool asArray(InspectorValue& value, RefPtr<InspectorArray>& output) { return value.asArray(output); } + static bool asValue(InspectorValue& value, RefPtr<InspectorValue>& output) { return value.asValue(output); } }; -int InspectorBackendDispatcher::getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors) +int BackendDispatcher::getInteger(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) { - return getPropertyValue<int, int, int>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asInt, "Number"); + return getPropertyValue<int, int, int>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asInteger, "Integer"); } -double InspectorBackendDispatcher::getDouble(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors) +double BackendDispatcher::getDouble(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) { return getPropertyValue<double, double, double>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asDouble, "Number"); } -String InspectorBackendDispatcher::getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors) +String BackendDispatcher::getString(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) { return getPropertyValue<String, String, String>(object, name, valueFound, protocolErrors, "", AsMethodBridges::asString, "String"); } -bool InspectorBackendDispatcher::getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors) +bool BackendDispatcher::getBoolean(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) { return getPropertyValue<bool, bool, bool>(object, name, valueFound, protocolErrors, false, AsMethodBridges::asBoolean, "Boolean"); } -PassRefPtr<InspectorObject> InspectorBackendDispatcher::getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors) +RefPtr<InspectorObject> BackendDispatcher::getObject(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) { - return getPropertyValue<PassRefPtr<InspectorObject>, RefPtr<InspectorObject>, InspectorObject*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asObject, "Object"); + return getPropertyValue<RefPtr<InspectorObject>, RefPtr<InspectorObject>, InspectorObject*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asObject, "Object"); } -PassRefPtr<InspectorArray> InspectorBackendDispatcher::getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors) +RefPtr<InspectorArray> BackendDispatcher::getArray(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) { - return getPropertyValue<PassRefPtr<InspectorArray>, RefPtr<InspectorArray>, InspectorArray*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asArray, "Array"); + return getPropertyValue<RefPtr<InspectorArray>, RefPtr<InspectorArray>, InspectorArray*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asArray, "Array"); } -} // namespace Inspector +RefPtr<InspectorValue> BackendDispatcher::getValue(InspectorObject* object, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors) +{ + return getPropertyValue<RefPtr<InspectorValue>, RefPtr<InspectorValue>, InspectorValue*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asValue, "Value"); +} -#endif // ENABLE(INSPECTOR) +} // namespace Inspector diff --git a/inspector/InspectorBackendDispatcher.h b/inspector/InspectorBackendDispatcher.h index 0a55a1c..b303700 100644 --- a/inspector/InspectorBackendDispatcher.h +++ b/inspector/InspectorBackendDispatcher.h @@ -27,49 +27,50 @@ #ifndef InspectorBackendDispatcher_h #define InspectorBackendDispatcher_h -#include "InspectorValues.h" -#include <wtf/PassRefPtr.h> +#include "InspectorProtocolTypes.h" #include <wtf/RefCounted.h> #include <wtf/text/WTFString.h> namespace Inspector { -class InspectorBackendDispatcher; -class InspectorFrontendChannel; +class BackendDispatcher; +class FrontendChannel; + typedef String ErrorString; -class InspectorSupplementalBackendDispatcher : public RefCounted<InspectorSupplementalBackendDispatcher> { +class SupplementalBackendDispatcher : public RefCounted<SupplementalBackendDispatcher> { public: - InspectorSupplementalBackendDispatcher(InspectorBackendDispatcher* backendDispatcher) : m_backendDispatcher(backendDispatcher) { } - virtual ~InspectorSupplementalBackendDispatcher() { } - virtual void dispatch(long callId, const String& method, PassRefPtr<InspectorObject> message) = 0; + SupplementalBackendDispatcher(BackendDispatcher& backendDispatcher) + : m_backendDispatcher(backendDispatcher) { } + virtual ~SupplementalBackendDispatcher() { } + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) = 0; protected: - RefPtr<InspectorBackendDispatcher> m_backendDispatcher; + Ref<BackendDispatcher> m_backendDispatcher; }; -class JS_EXPORT_PRIVATE InspectorBackendDispatcher : public RefCounted<InspectorBackendDispatcher> { +class JS_EXPORT_PRIVATE BackendDispatcher : public RefCounted<BackendDispatcher> { public: - static PassRefPtr<InspectorBackendDispatcher> create(InspectorFrontendChannel*); + static Ref<BackendDispatcher> create(FrontendChannel*); class JS_EXPORT_PRIVATE CallbackBase : public RefCounted<CallbackBase> { public: - CallbackBase(PassRefPtr<InspectorBackendDispatcher>, int id); + CallbackBase(Ref<BackendDispatcher>&&, int id); bool isActive() const; void sendFailure(const ErrorString&); void disable() { m_alreadySent = true; } protected: - void sendIfActive(PassRefPtr<InspectorObject> partialMessage, const ErrorString& invocationError); + void sendIfActive(RefPtr<InspectorObject>&& partialMessage, const ErrorString& invocationError); private: - RefPtr<InspectorBackendDispatcher> m_backendDispatcher; + Ref<BackendDispatcher> m_backendDispatcher; int m_id; bool m_alreadySent; }; - void clearFrontend() { m_inspectorFrontendChannel = nullptr; } - bool isActive() const { return !!m_inspectorFrontendChannel; } + void clearFrontend() { m_frontendChannel = nullptr; } + bool isActive() const { return !!m_frontendChannel; } enum CommonErrorCode { ParseError = 0, @@ -80,24 +81,26 @@ public: ServerError }; - void registerDispatcherForDomain(const String& domain, InspectorSupplementalBackendDispatcher*); + void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); void dispatch(const String& message); - void sendResponse(long callId, PassRefPtr<InspectorObject> result, const ErrorString& invocationError); + void sendResponse(long callId, RefPtr<InspectorObject>&& result, const ErrorString& invocationError); void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage) const; - void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const; + void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorMessage, RefPtr<Inspector::Protocol::Array<String>>&& data) const; - static int getInt(InspectorObject*, const String& name, bool* valueFound, InspectorArray* protocolErrors); - static double getDouble(InspectorObject*, const String& name, bool* valueFound, InspectorArray* protocolErrors); - static String getString(InspectorObject*, const String& name, bool* valueFound, InspectorArray* protocolErrors); - static bool getBoolean(InspectorObject*, const String& name, bool* valueFound, InspectorArray* protocolErrors); - static PassRefPtr<InspectorObject> getObject(InspectorObject*, const String& name, bool* valueFound, InspectorArray* protocolErrors); - static PassRefPtr<InspectorArray> getArray(InspectorObject*, const String& name, bool* valueFound, InspectorArray* protocolErrors); + static int getInteger(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); + static double getDouble(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); + static String getString(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); + static bool getBoolean(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); + static RefPtr<InspectorValue> getValue(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); + static RefPtr<InspectorObject> getObject(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); + static RefPtr<InspectorArray> getArray(InspectorObject*, const String& name, bool* valueFound, Inspector::Protocol::Array<String>& protocolErrors); private: - InspectorBackendDispatcher(InspectorFrontendChannel* inspectorFrontendChannel) : m_inspectorFrontendChannel(inspectorFrontendChannel) { } + BackendDispatcher(FrontendChannel* FrontendChannel) + : m_frontendChannel(FrontendChannel) { } - InspectorFrontendChannel* m_inspectorFrontendChannel; - HashMap<String, InspectorSupplementalBackendDispatcher*> m_dispatchers; + FrontendChannel* m_frontendChannel; + HashMap<String, SupplementalBackendDispatcher*> m_dispatchers; }; } // namespace Inspector diff --git a/inspector/InspectorEnvironment.h b/inspector/InspectorEnvironment.h index 588d7a1..cb48771 100644 --- a/inspector/InspectorEnvironment.h +++ b/inspector/InspectorEnvironment.h @@ -28,14 +28,19 @@ #include "CallData.h" +namespace WTF { +class Stopwatch; +} + namespace JSC { +class Exception; class SourceCode; } namespace Inspector { -typedef JSC::JSValue (*InspectorFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, JSC::JSValue* exception); -typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception); +typedef JSC::JSValue (*InspectorFunctionCallHandler)(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException); +typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException); class InspectorEnvironment { public: @@ -46,6 +51,8 @@ public: virtual InspectorEvaluateHandler evaluateHandler() const = 0; virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String& scriptName, int scriptLine) = 0; virtual void didCallInjectedScriptFunction(JSC::ExecState*) = 0; + virtual void frontendInitialized() = 0; + virtual Ref<WTF::Stopwatch> executionStopwatch() = 0; }; } // namespace Inspector diff --git a/inspector/InspectorFrontendChannel.h b/inspector/InspectorFrontendChannel.h index fa0a8ea..a2bf6f3 100644 --- a/inspector/InspectorFrontendChannel.h +++ b/inspector/InspectorFrontendChannel.h @@ -30,9 +30,9 @@ namespace Inspector { -class InspectorFrontendChannel { +class FrontendChannel { public: - virtual ~InspectorFrontendChannel() { } + virtual ~FrontendChannel() { } virtual bool sendMessageToFrontend(const String& message) = 0; }; diff --git a/inspector/InspectorProtocolTypes.h b/inspector/InspectorProtocolTypes.h new file mode 100644 index 0000000..6f06296 --- /dev/null +++ b/inspector/InspectorProtocolTypes.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2011 The Chromium Authors. 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 InspectorProtocolTypes_h +#define InspectorProtocolTypes_h + +#include "InspectorValues.h" +#include <wtf/Assertions.h> + +namespace Inspector { + +namespace Protocol { + +template<typename T> struct BindingTraits; + +template<typename T> +class OptOutput { +public: + OptOutput() : m_assigned(false) { } + + void operator=(T value) + { + m_value = value; + m_assigned = true; + } + + bool isAssigned() const { return m_assigned; } + + T getValue() + { + ASSERT(isAssigned()); + return m_value; + } + +private: + T m_value; + bool m_assigned; + + WTF_MAKE_NONCOPYABLE(OptOutput); +}; + +template<typename T> +class Array : public InspectorArrayBase { +private: + Array() { } + + InspectorArray& openAccessors() + { + COMPILE_ASSERT(sizeof(InspectorArray) == sizeof(Array<T>), cannot_cast); + return *static_cast<InspectorArray*>(static_cast<InspectorArrayBase*>(this)); + } + +public: + void addItem(Ref<T>&& value) + { + openAccessors().pushValue(&value.get()); + } + + void addItem(RefPtr<T>&& value) + { + openAccessors().pushValue(WTF::move(value)); + } + + void addItem(const String& value) + { + openAccessors().pushString(value); + } + + void addItem(int value) + { + openAccessors().pushInteger(value); + } + + static Ref<Array<T>> create() + { + return adoptRef(*new Array<T>()); + } +}; + +// Helper methods for Protocol and other Inspector types are provided by +// specializations of BindingTraits<T>. Some are generated for protocol types. + +template<typename T> +struct BindingTraits { + typedef T BindingType; + + static void push(InspectorArray&, BindingType&); + static InspectorValue::Type typeTag(); + static RefPtr<T> runtimeCast(RefPtr<InspectorObject>&&); +#if !ASSERT_DISABLED + static void assertValueHasExpectedType(InspectorValue*); +#endif // !ASSERT_DISABLED +}; + +template<InspectorValue::Type TYPE> +struct PrimitiveBindingTraits { +#if !ASSERT_DISABLED + static void assertValueHasExpectedType(InspectorValue* value) + { + ASSERT_ARG(value, value && value->type() == TYPE); + } +#endif // !ASSERT_DISABLED +}; + +template<typename T> +struct BindingTraits<Protocol::Array<T>> { + static RefPtr<Array<T>> runtimeCast(RefPtr<InspectorValue>&& value) + { + ASSERT_ARG(value, value); + RefPtr<InspectorArray> array; + bool castSucceeded = value->asArray(array); + ASSERT_UNUSED(castSucceeded, castSucceeded); +#if !ASSERT_DISABLED + assertValueHasExpectedType(array.get()); +#endif // !ASSERT_DISABLED + COMPILE_ASSERT(sizeof(Array<T>) == sizeof(InspectorArray), type_cast_problem); + return static_cast<Array<T>*>(static_cast<InspectorArrayBase*>(array.get())); + } + +#if !ASSERT_DISABLED + static void assertValueHasExpectedType(InspectorValue* value) + { + ASSERT_ARG(value, value); + RefPtr<InspectorArray> array; + bool castSucceeded = value->asArray(array); + ASSERT_UNUSED(castSucceeded, castSucceeded); + for (unsigned i = 0; i < array->length(); i++) + BindingTraits<T>::assertValueHasExpectedType(array->get(i).get()); + } +#endif // !ASSERT_DISABLED +}; + +template<> +struct BindingTraits<InspectorValue> { +#if !ASSERT_DISABLED + static void assertValueHasExpectedType(InspectorValue*) + { + } +#endif // !ASSERT_DISABLED +}; + +template<> struct BindingTraits<InspectorArray> : public PrimitiveBindingTraits<InspectorValue::Type::Array> { }; +template<> struct BindingTraits<InspectorObject> : public PrimitiveBindingTraits<InspectorValue::Type::Object> { }; +template<> struct BindingTraits<String> : public PrimitiveBindingTraits<InspectorValue::Type::String> { }; +template<> struct BindingTraits<bool> : public PrimitiveBindingTraits<InspectorValue::Type::Boolean> { }; +template<> struct BindingTraits<double> : public PrimitiveBindingTraits<InspectorValue::Type::Double> { }; +template<> struct BindingTraits<int> : public PrimitiveBindingTraits<InspectorValue::Type::Integer> { }; + +} // namespace Protocol + +using Protocol::BindingTraits; + +} // namespace Inspector + +#endif // !defined(InspectorProtocolTypes_h) diff --git a/inspector/InspectorTypeBuilder.h b/inspector/InspectorTypeBuilder.h deleted file mode 100644 index 8ea76ec..0000000 --- a/inspector/InspectorTypeBuilder.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All Rights Reserved. - * Copyright (C) 2011 The Chromium Authors. 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 InspectorTypeBuilder_h -#define InspectorTypeBuilder_h - -#if ENABLE(INSPECTOR) - -#include "InspectorValues.h" -#include <wtf/Assertions.h> -#include <wtf/PassRefPtr.h> - -namespace Inspector { - -namespace TypeBuilder { - -template<typename T> -class OptOutput { -public: - OptOutput() : m_assigned(false) { } - - void operator=(T value) - { - m_value = value; - m_assigned = true; - } - - bool isAssigned() const { return m_assigned; } - - T getValue() - { - ASSERT(isAssigned()); - return m_value; - } - -private: - T m_value; - bool m_assigned; - - WTF_MAKE_NONCOPYABLE(OptOutput); -}; - - -// A small transient wrapper around int type, that can be used as a funciton parameter type -// cleverly disallowing C++ implicit casts from float or double. -class ExactlyInt { -public: - template<typename T> - ExactlyInt(T t) : m_value(cast_to_int<T>(t)) { } - ExactlyInt() { } - - operator int() { return m_value; } - -private: - int m_value; - - template<typename T> - static int cast_to_int(T) { return T::default_case_cast_is_not_supported(); } -}; - -template<> -inline int ExactlyInt::cast_to_int<int>(int i) { return i; } - -template<> -inline int ExactlyInt::cast_to_int<unsigned int>(unsigned int i) { return i; } - -#if !ASSERT_DISABLED -class RuntimeCastHelper { -public: - template<InspectorValue::Type TYPE> - static void assertType(InspectorValue* value) - { - ASSERT(value->type() == TYPE); - } - - static void assertAny(InspectorValue*) - { - } - - static void assertInt(InspectorValue* value) - { - double v; - bool castRes = value->asNumber(&v); - ASSERT_UNUSED(castRes, castRes); - ASSERT(static_cast<double>(static_cast<int>(v)) == v); - } -}; -#endif - - -// This class provides "Traits" type for the input type T. It is programmed using C++ template specialization -// technique. By default it simply takes "ItemTraits" type from T, but it doesn't work with the base types. -template<typename T> -struct ArrayItemHelper { - typedef typename T::ItemTraits Traits; -}; - -template<typename T> -class Array : public InspectorArrayBase { -private: - Array() { } - - InspectorArray* openAccessors() - { - COMPILE_ASSERT(sizeof(InspectorArray) == sizeof(Array<T>), cannot_cast); - return static_cast<InspectorArray*>(static_cast<InspectorArrayBase*>(this)); - } - -public: - void addItem(PassRefPtr<T> value) - { - ArrayItemHelper<T>::Traits::pushRefPtr(this->openAccessors(), value); - } - - void addItem(T value) - { - ArrayItemHelper<T>::Traits::pushRaw(this->openAccessors(), value); - } - - static PassRefPtr<Array<T>> create() - { - return adoptRef(new Array<T>()); - } - - static PassRefPtr<Array<T>> runtimeCast(PassRefPtr<InspectorValue> value) - { - RefPtr<InspectorArray> array; - bool castRes = value->asArray(&array); - ASSERT_UNUSED(castRes, castRes); -#if !ASSERT_DISABLED - assertCorrectValue(array.get()); -#endif // !ASSERT_DISABLED - COMPILE_ASSERT(sizeof(Array<T>) == sizeof(InspectorArray), type_cast_problem); - return static_cast<Array<T>*>(static_cast<InspectorArrayBase*>(array.get())); - } - -#if !ASSERT_DISABLED - static void assertCorrectValue(InspectorValue* value) - { - RefPtr<InspectorArray> array; - bool castRes = value->asArray(&array); - ASSERT_UNUSED(castRes, castRes); - for (unsigned i = 0; i < array->length(); i++) - ArrayItemHelper<T>::Traits::template assertCorrectValue<T>(array->get(i).get()); - } -#endif // !ASSERT_DISABLED -}; - -struct StructItemTraits { - static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value) - { - array->pushValue(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - T::assertCorrectValue(value); - } -#endif // !ASSERT_DISABLED -}; - -template<> -struct ArrayItemHelper<String> { - struct Traits { - static void pushRaw(InspectorArray* array, const String& value) - { - array->pushString(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertType<InspectorValue::TypeString>(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<> -struct ArrayItemHelper<int> { - struct Traits { - static void pushRaw(InspectorArray* array, int value) - { - array->pushInt(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertInt(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<> -struct ArrayItemHelper<double> { - struct Traits { - static void pushRaw(InspectorArray* array, double value) - { - array->pushNumber(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertType<InspectorValue::TypeNumber>(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<> -struct ArrayItemHelper<bool> { - struct Traits { - static void pushRaw(InspectorArray* array, bool value) - { - array->pushBoolean(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertType<InspectorValue::TypeBoolean>(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<> -struct ArrayItemHelper<InspectorValue> { - struct Traits { - static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value) - { - array->pushValue(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertAny(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<> -struct ArrayItemHelper<InspectorObject> { - struct Traits { - static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorValue> value) - { - array->pushValue(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertType<InspectorValue::TypeObject>(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<> -struct ArrayItemHelper<InspectorArray> { - struct Traits { - static void pushRefPtr(InspectorArray* array, PassRefPtr<InspectorArray> value) - { - array->pushArray(value); - } - -#if !ASSERT_DISABLED - template<typename T> - static void assertCorrectValue(InspectorValue* value) - { - RuntimeCastHelper::assertType<InspectorValue::TypeArray>(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -template<typename T> -struct ArrayItemHelper<TypeBuilder::Array<T>> { - struct Traits { - static void pushRefPtr(InspectorArray* array, PassRefPtr<TypeBuilder::Array<T>> value) - { - array->pushValue(value); - } - -#if !ASSERT_DISABLED - template<typename S> - static void assertCorrectValue(InspectorValue* value) - { - S::assertCorrectValue(value); - } -#endif // !ASSERT_DISABLED - }; -}; - -} // namespace TypeBuilder - -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) - -#endif // !defined(InspectorTypeBuilder_h) diff --git a/inspector/InspectorValues.cpp b/inspector/InspectorValues.cpp index 192fb6c..5896ad6 100644 --- a/inspector/InspectorValues.cpp +++ b/inspector/InspectorValues.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -63,8 +64,10 @@ const char* const falseString = "false"; bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token) { while (start < end && *token != '\0' && *start++ == *token++) { } + if (*token != '\0') return false; + *tokenEnd = start; return true; } @@ -73,16 +76,20 @@ bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool { if (start == end) return false; + bool haveLeadingZero = '0' == *start; int length = 0; while (start < end && '0' <= *start && *start <= '9') { ++start; ++length; } + if (!length) return false; + if (!canHaveLeadingZeros && length > 1 && haveLeadingZero) return false; + *tokenEnd = start; return true; } @@ -93,12 +100,14 @@ bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenE // According to RFC4627, a valid number is: [minus] int [frac] [exp] if (start == end) return false; + UChar c = *start; if ('-' == c) ++start; if (!readInt(start, end, &start, false)) return false; + if (start == end) { *tokenEnd = start; return true; @@ -140,11 +149,13 @@ bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, { if (end - start < digits) return false; + for (int i = 0; i < digits; ++i) { UChar c = *start++; if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))) return false; } + *tokenEnd = start; return true; } @@ -183,6 +194,7 @@ bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenE return true; } } + return false; } @@ -246,6 +258,7 @@ Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart, return STRING; break; } + return INVALID_TOKEN; } @@ -257,16 +270,17 @@ inline int hexToInt(UChar c) return c - 'A' + 10; if ('a' <= c && c <= 'f') return c - 'a' + 10; + ASSERT_NOT_REACHED(); return 0; } -bool decodeString(const UChar* start, const UChar* end, StringBuilder* output) +bool decodeString(const UChar* start, const UChar* end, StringBuilder& output) { while (start < end) { UChar c = *start++; if ('\\' != c) { - output->append(c); + output.append(c); continue; } c = *start++; @@ -308,28 +322,32 @@ bool decodeString(const UChar* start, const UChar* end, StringBuilder* output) default: return false; } - output->append(c); + output.append(c); } + return true; } -bool decodeString(const UChar* start, const UChar* end, String* output) +bool decodeString(const UChar* start, const UChar* end, String& output) { if (start == end) { - *output = ""; + output = emptyString(); return true; } + if (start > end) return false; + StringBuilder buffer; buffer.reserveCapacity(end - start); - if (!decodeString(start, end, &buffer)) + if (!decodeString(start, end, buffer)) return false; - *output = buffer.toString(); + + output = buffer.toString(); return true; } -PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth) +RefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth) { if (depth > stackLimit) return nullptr; @@ -360,21 +378,21 @@ PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, cons } case STRING: { String value; - bool ok = decodeString(tokenStart + 1, tokenEnd - 1, &value); + bool ok = decodeString(tokenStart + 1, tokenEnd - 1, value); if (!ok) return nullptr; result = InspectorString::create(value); break; } case ARRAY_BEGIN: { - RefPtr<InspectorArray> array = InspectorArray::create(); + Ref<InspectorArray> array = InspectorArray::create(); start = tokenEnd; token = parseToken(start, end, &tokenStart, &tokenEnd); while (token != ARRAY_END) { RefPtr<InspectorValue> arrayNode = buildValue(start, end, &tokenEnd, depth + 1); if (!arrayNode) return nullptr; - array->pushValue(arrayNode); + array->pushValue(WTF::move(arrayNode)); // After a list value, we expect a comma or the end of the list. start = tokenEnd; @@ -391,18 +409,18 @@ PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, cons } if (token != ARRAY_END) return nullptr; - result = array.release(); + result = WTF::move(array); break; } case OBJECT_BEGIN: { - RefPtr<InspectorObject> object = InspectorObject::create(); + Ref<InspectorObject> object = InspectorObject::create(); start = tokenEnd; token = parseToken(start, end, &tokenStart, &tokenEnd); while (token != OBJECT_END) { if (token != STRING) return nullptr; String key; - if (!decodeString(tokenStart + 1, tokenEnd - 1, &key)) + if (!decodeString(tokenStart + 1, tokenEnd - 1, key)) return nullptr; start = tokenEnd; @@ -414,7 +432,7 @@ PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, cons RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, depth + 1); if (!value) return nullptr; - object->setValue(key, value); + object->setValue(key, WTF::move(value)); start = tokenEnd; // After a key/value pair, we expect a comma or the end of the @@ -432,7 +450,7 @@ PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, cons } if (token != OBJECT_END) return nullptr; - result = object.release(); + result = WTF::move(object); break; } @@ -444,25 +462,25 @@ PassRefPtr<InspectorValue> buildValue(const UChar* start, const UChar* end, cons return result.release(); } -inline bool escapeChar(UChar c, StringBuilder* dst) +inline bool escapeChar(UChar c, StringBuilder& dst) { switch (c) { - case '\b': dst->append("\\b", 2); break; - case '\f': dst->append("\\f", 2); break; - case '\n': dst->append("\\n", 2); break; - case '\r': dst->append("\\r", 2); break; - case '\t': dst->append("\\t", 2); break; - case '\\': dst->append("\\\\", 2); break; - case '"': dst->append("\\\"", 2); break; + case '\b': dst.appendLiteral("\\b"); break; + case '\f': dst.appendLiteral("\\f"); break; + case '\n': dst.appendLiteral("\\n"); break; + case '\r': dst.appendLiteral("\\r"); break; + case '\t': dst.appendLiteral("\\t"); break; + case '\\': dst.appendLiteral("\\\\"); break; + case '"': dst.appendLiteral("\\\""); break; default: return false; } return true; } -inline void doubleQuoteString(const String& str, StringBuilder* dst) +inline void doubleQuoteString(const String& str, StringBuilder& dst) { - dst->append('"'); + dst.append('"'); for (unsigned i = 0; i < str.length(); ++i) { UChar c = str[i]; if (!escapeChar(c, dst)) { @@ -470,203 +488,206 @@ inline void doubleQuoteString(const String& str, StringBuilder* dst) // 1. Escaping <, > to prevent script execution. // 2. Technically, we could also pass through c > 126 as UTF8, but this // is also optional. It would also be a pain to implement here. - dst->append(String::format("\\u%04X", c)); + dst.append(String::format("\\u%04X", c)); } else - dst->append(c); + dst.append(c); } } - dst->append('"'); + dst.append('"'); } } // anonymous namespace -bool InspectorValue::asBoolean(bool*) const +bool InspectorValue::asBoolean(bool&) const { return false; } -bool InspectorValue::asNumber(double*) const +bool InspectorValue::asDouble(double&) const { return false; } -bool InspectorValue::asNumber(float*) const +bool InspectorValue::asDouble(float&) const { return false; } -bool InspectorValue::asNumber(int*) const +bool InspectorValue::asInteger(int&) const { return false; } -bool InspectorValue::asNumber(unsigned*) const +bool InspectorValue::asInteger(unsigned&) const { return false; } -bool InspectorValue::asNumber(long*) const +bool InspectorValue::asInteger(long&) const { return false; } -bool InspectorValue::asNumber(long long*) const +bool InspectorValue::asInteger(long long&) const { return false; } -bool InspectorValue::asNumber(unsigned long*) const +bool InspectorValue::asInteger(unsigned long&) const { return false; } -bool InspectorValue::asNumber(unsigned long long*) const +bool InspectorValue::asInteger(unsigned long long&) const { return false; } -bool InspectorValue::asString(String*) const +bool InspectorValue::asString(String&) const { return false; } -bool InspectorValue::asValue(RefPtr<InspectorValue>* output) +bool InspectorValue::asValue(RefPtr<InspectorValue>& output) { - *output = this; + output = this; return true; } -bool InspectorValue::asObject(RefPtr<InspectorObject>*) +bool InspectorValue::asObject(RefPtr<InspectorObject>&) { return false; } -bool InspectorValue::asArray(RefPtr<InspectorArray>*) +bool InspectorValue::asArray(RefPtr<InspectorArray>&) { return false; } -PassRefPtr<InspectorObject> InspectorValue::asObject() -{ - return nullptr; -} - -PassRefPtr<InspectorArray> InspectorValue::asArray() -{ - return nullptr; -} - -PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json) +bool InspectorValue::parseJSON(const String& jsonInput, RefPtr<InspectorValue>& output) { // FIXME: This whole file should just use StringView instead of UChar/length and avoid upconverting. - auto characters = StringView(json).upconvertedCharacters(); + auto characters = StringView(jsonInput).upconvertedCharacters(); const UChar* start = characters; - const UChar* end = start + json.length(); + const UChar* end = start + jsonInput.length(); const UChar* tokenEnd; - RefPtr<InspectorValue> value = buildValue(start, end, &tokenEnd, 0); - if (!value || tokenEnd != end) - return nullptr; - return value.release(); + RefPtr<InspectorValue> result = buildValue(start, end, &tokenEnd, 0); + if (!result || tokenEnd != end) + return false; + + output = result.release(); + return true; } String InspectorValue::toJSONString() const { StringBuilder result; result.reserveCapacity(512); - writeJSON(&result); + writeJSON(result); return result.toString(); } -void InspectorValue::writeJSON(StringBuilder* output) const +void InspectorValue::writeJSON(StringBuilder& output) const { - ASSERT(m_type == TypeNull); - output->append(nullString, 4); + ASSERT(m_type == Type::Null); + + output.appendLiteral("null"); } -bool InspectorBasicValue::asBoolean(bool* output) const +bool InspectorBasicValue::asBoolean(bool& output) const { - if (type() != TypeBoolean) + if (type() != Type::Boolean) return false; - *output = m_boolValue; + + output = m_booleanValue; return true; } -bool InspectorBasicValue::asNumber(double* output) const +bool InspectorBasicValue::asDouble(double& output) const { - if (type() != TypeNumber) + if (type() != Type::Double) return false; - *output = m_doubleValue; + + output = m_doubleValue; return true; } -bool InspectorBasicValue::asNumber(float* output) const +bool InspectorBasicValue::asDouble(float& output) const { - if (type() != TypeNumber) + if (type() != Type::Double) return false; - *output = static_cast<float>(m_doubleValue); + + output = static_cast<float>(m_doubleValue); return true; } -bool InspectorBasicValue::asNumber(int* output) const +bool InspectorBasicValue::asInteger(int& output) const { - if (type() != TypeNumber) + if (type() != Type::Integer && type() != Type::Double) return false; - *output = static_cast<int>(m_doubleValue); + + output = static_cast<int>(m_doubleValue); return true; } -bool InspectorBasicValue::asNumber(unsigned* output) const +bool InspectorBasicValue::asInteger(unsigned& output) const { - if (type() != TypeNumber) + if (type() != Type::Integer && type() != Type::Double) return false; - *output = static_cast<unsigned>(m_doubleValue); + + output = static_cast<unsigned>(m_doubleValue); return true; } -bool InspectorBasicValue::asNumber(long* output) const +bool InspectorBasicValue::asInteger(long& output) const { - if (type() != TypeNumber) + if (type() != Type::Integer && type() != Type::Double) return false; - *output = static_cast<long>(m_doubleValue); + + output = static_cast<long>(m_doubleValue); return true; } -bool InspectorBasicValue::asNumber(long long* output) const +bool InspectorBasicValue::asInteger(long long& output) const { - if (type() != TypeNumber) + if (type() != Type::Integer && type() != Type::Double) return false; - *output = static_cast<long long>(m_doubleValue); + + output = static_cast<long long>(m_doubleValue); return true; } -bool InspectorBasicValue::asNumber(unsigned long* output) const +bool InspectorBasicValue::asInteger(unsigned long& output) const { - if (type() != TypeNumber) + if (type() != Type::Integer && type() != Type::Double) return false; - *output = static_cast<unsigned long>(m_doubleValue); + + output = static_cast<unsigned long>(m_doubleValue); return true; } -bool InspectorBasicValue::asNumber(unsigned long long* output) const +bool InspectorBasicValue::asInteger(unsigned long long& output) const { - if (type() != TypeNumber) + if (type() != Type::Integer && type() != Type::Double) return false; - *output = static_cast<unsigned long long>(m_doubleValue); + + output = static_cast<unsigned long long>(m_doubleValue); return true; } -void InspectorBasicValue::writeJSON(StringBuilder* output) const +void InspectorBasicValue::writeJSON(StringBuilder& output) const { - ASSERT(type() == TypeBoolean || type() == TypeNumber); - if (type() == TypeBoolean) { - if (m_boolValue) - output->append(trueString, 4); + ASSERT(type() == Type::Boolean || type() == Type::Double || type() == Type::Integer); + + if (type() == Type::Boolean) { + if (m_booleanValue) + output.appendLiteral("true"); else - output->append(falseString, 5); - } else if (type() == TypeNumber) { + output.appendLiteral("false"); + } else if (type() == Type::Double || type() == Type::Integer) { NumberToLStringBuffer buffer; if (!std::isfinite(m_doubleValue)) { - output->append(nullString, 4); + output.appendLiteral("null"); return; } DecimalNumber decimal = m_doubleValue; @@ -675,25 +696,25 @@ void InspectorBasicValue::writeJSON(StringBuilder* output) const // Not enough room for decimal. Use exponential format. if (decimal.bufferLengthForStringExponential() > WTF::NumberToStringBufferLength) { // Fallback for an abnormal case if it's too little even for exponential. - output->append("NaN", 3); + output.appendLiteral("NaN"); return; } length = decimal.toStringExponential(buffer, WTF::NumberToStringBufferLength); } else length = decimal.toStringDecimal(buffer, WTF::NumberToStringBufferLength); - output->append(buffer, length); + output.append(buffer, length); } } -bool InspectorString::asString(String* output) const +bool InspectorString::asString(String& output) const { - *output = m_stringValue; + output = m_stringValue; return true; } -void InspectorString::writeJSON(StringBuilder* output) const +void InspectorString::writeJSON(StringBuilder& output) const { - ASSERT(type() == TypeString); + ASSERT(type() == Type::String); doubleQuoteString(m_stringValue, output); } @@ -701,92 +722,90 @@ InspectorObjectBase::~InspectorObjectBase() { } -bool InspectorObjectBase::asObject(RefPtr<InspectorObject>* output) +bool InspectorObjectBase::asObject(RefPtr<InspectorObject>& output) { COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast); - *output = static_cast<InspectorObject*>(this); - return true; -} -PassRefPtr<InspectorObject> InspectorObjectBase::asObject() -{ - return openAccessors(); + output = static_cast<InspectorObject*>(this); + return true; } InspectorObject* InspectorObjectBase::openAccessors() { COMPILE_ASSERT(sizeof(InspectorObject) == sizeof(InspectorObjectBase), cannot_cast); + return static_cast<InspectorObject*>(this); } -bool InspectorObjectBase::getBoolean(const String& name, bool* output) const +bool InspectorObjectBase::getBoolean(const String& name, bool& output) const { - RefPtr<InspectorValue> value = get(name); - if (!value) + RefPtr<InspectorValue> value; + if (!getValue(name, value)) return false; + return value->asBoolean(output); } -bool InspectorObjectBase::getString(const String& name, String* output) const +bool InspectorObjectBase::getString(const String& name, String& output) const { - RefPtr<InspectorValue> value = get(name); - if (!value) + RefPtr<InspectorValue> value; + if (!getValue(name, value)) return false; + return value->asString(output); } -PassRefPtr<InspectorObject> InspectorObjectBase::getObject(const String& name) const +bool InspectorObjectBase::getObject(const String& name, RefPtr<InspectorObject>& output) const { - PassRefPtr<InspectorValue> value = get(name); - if (!value) - return nullptr; - return value->asObject(); + RefPtr<InspectorValue> value; + if (!getValue(name, value)) + return false; + + return value->asObject(output); } -PassRefPtr<InspectorArray> InspectorObjectBase::getArray(const String& name) const +bool InspectorObjectBase::getArray(const String& name, RefPtr<InspectorArray>& output) const { - PassRefPtr<InspectorValue> value = get(name); - if (!value) - return nullptr; - return value->asArray(); + RefPtr<InspectorValue> value; + if (!getValue(name, value)) + return false; + + return value->asArray(output); } -PassRefPtr<InspectorValue> InspectorObjectBase::get(const String& name) const +bool InspectorObjectBase::getValue(const String& name, RefPtr<InspectorValue>& output) const { - Dictionary::const_iterator it = m_data.find(name); - if (it == m_data.end()) - return nullptr; - return it->value; + Dictionary::const_iterator findResult = m_data.find(name); + if (findResult == m_data.end()) + return false; + + output = findResult->value; + return true; } void InspectorObjectBase::remove(const String& name) { m_data.remove(name); - for (size_t i = 0; i < m_order.size(); ++i) { - if (m_order[i] == name) { - m_order.remove(i); - break; - } - } + m_order.removeFirst(name); } -void InspectorObjectBase::writeJSON(StringBuilder* output) const +void InspectorObjectBase::writeJSON(StringBuilder& output) const { - output->append('{'); + output.append('{'); for (size_t i = 0; i < m_order.size(); ++i) { - Dictionary::const_iterator it = m_data.find(m_order[i]); - ASSERT(it != m_data.end()); + auto findResult = m_data.find(m_order[i]); + ASSERT(findResult != m_data.end()); if (i) - output->append(','); - doubleQuoteString(it->key, output); - output->append(':'); - it->value->writeJSON(output); + output.append(','); + doubleQuoteString(findResult->key, output); + output.append(':'); + findResult->value->writeJSON(output); } - output->append('}'); + output.append('}'); } InspectorObjectBase::InspectorObjectBase() - : InspectorValue(TypeObject) + : InspectorValue(Type::Object) , m_data() , m_order() { @@ -796,80 +815,74 @@ InspectorArrayBase::~InspectorArrayBase() { } -bool InspectorArrayBase::asArray(RefPtr<InspectorArray>* output) +bool InspectorArrayBase::asArray(RefPtr<InspectorArray>& output) { COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast); - *output = static_cast<InspectorArray*>(this); + output = static_cast<InspectorArray*>(this); return true; } -PassRefPtr<InspectorArray> InspectorArrayBase::asArray() -{ - COMPILE_ASSERT(sizeof(InspectorArrayBase) == sizeof(InspectorArray), cannot_cast); - return static_cast<InspectorArray*>(this); -} - -void InspectorArrayBase::writeJSON(StringBuilder* output) const +void InspectorArrayBase::writeJSON(StringBuilder& output) const { - output->append('['); + output.append('['); for (Vector<RefPtr<InspectorValue>>::const_iterator it = m_data.begin(); it != m_data.end(); ++it) { if (it != m_data.begin()) - output->append(','); + output.append(','); (*it)->writeJSON(output); } - output->append(']'); + output.append(']'); } InspectorArrayBase::InspectorArrayBase() - : InspectorValue(TypeArray) + : InspectorValue(Type::Array) , m_data() { } -PassRefPtr<InspectorValue> InspectorArrayBase::get(size_t index) +RefPtr<InspectorValue> InspectorArrayBase::get(size_t index) const { ASSERT_WITH_SECURITY_IMPLICATION(index < m_data.size()); return m_data[index]; } -PassRefPtr<InspectorObject> InspectorObject::create() +Ref<InspectorObject> InspectorObject::create() { - return adoptRef(new InspectorObject); + return adoptRef(*new InspectorObject); } -PassRefPtr<InspectorArray> InspectorArray::create() +Ref<InspectorArray> InspectorArray::create() { - return adoptRef(new InspectorArray); + return adoptRef(*new InspectorArray); } -PassRefPtr<InspectorValue> InspectorValue::null() +Ref<InspectorValue> InspectorValue::null() { - return adoptRef(new InspectorValue); + return adoptRef(*new InspectorValue); } -PassRefPtr<InspectorString> InspectorString::create(const String& value) +Ref<InspectorString> InspectorString::create(const String& value) { - return adoptRef(new InspectorString(value)); + return adoptRef(*new InspectorString(value)); } -PassRefPtr<InspectorString> InspectorString::create(const char* value) +Ref<InspectorString> InspectorString::create(const char* value) { - return adoptRef(new InspectorString(value)); + return adoptRef(*new InspectorString(value)); } -PassRefPtr<InspectorBasicValue> InspectorBasicValue::create(bool value) +Ref<InspectorBasicValue> InspectorBasicValue::create(bool value) { - return adoptRef(new InspectorBasicValue(value)); + return adoptRef(*new InspectorBasicValue(value)); } -PassRefPtr<InspectorBasicValue> InspectorBasicValue::create(int value) +Ref<InspectorBasicValue> InspectorBasicValue::create(int value) { - return adoptRef(new InspectorBasicValue(value)); + return adoptRef(*new InspectorBasicValue(value)); } -PassRefPtr<InspectorBasicValue> InspectorBasicValue::create(double value) +Ref<InspectorBasicValue> InspectorBasicValue::create(double value) { - return adoptRef(new InspectorBasicValue(value)); + return adoptRef(*new InspectorBasicValue(value)); } } // namespace Inspector diff --git a/inspector/InspectorValues.h b/inspector/InspectorValues.h index 3b86166..db05036 100644 --- a/inspector/InspectorValues.h +++ b/inspector/InspectorValues.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,7 +32,7 @@ #ifndef InspectorValues_h #define InspectorValues_h -#include <wtf/Forward.h> +#include <wtf/Assertions.h> #include <wtf/HashMap.h> #include <wtf/RefCounted.h> #include <wtf/Vector.h> @@ -41,50 +42,52 @@ namespace Inspector { class InspectorArray; +class InspectorArrayBase; class InspectorObject; +class InspectorObjectBase; class JS_EXPORT_PRIVATE InspectorValue : public RefCounted<InspectorValue> { public: static const int maxDepth = 1000; - InspectorValue() : m_type(TypeNull) { } + InspectorValue() + : m_type(Type::Null) { } virtual ~InspectorValue() { } - static PassRefPtr<InspectorValue> null(); + static Ref<InspectorValue> null(); - typedef enum { - TypeNull = 0, - TypeBoolean, - TypeNumber, - TypeString, - TypeObject, - TypeArray - } Type; + enum class Type { + Null = 0, + Boolean, + Double, + Integer, + String, + Object, + Array + }; Type type() const { return m_type; } - bool isNull() const { return m_type == TypeNull; } - - virtual bool asBoolean(bool* output) const; - virtual bool asNumber(double* output) const; - virtual bool asNumber(float* output) const; - virtual bool asNumber(int* output) const; - virtual bool asNumber(unsigned* output) const; - virtual bool asNumber(long* output) const; - virtual bool asNumber(long long* output) const; - virtual bool asNumber(unsigned long* output) const; - virtual bool asNumber(unsigned long long* output) const; - virtual bool asString(String* output) const; - virtual bool asValue(RefPtr<InspectorValue>* output); - virtual bool asObject(RefPtr<InspectorObject>* output); - virtual bool asArray(RefPtr<InspectorArray>* output); - virtual PassRefPtr<InspectorObject> asObject(); - virtual PassRefPtr<InspectorArray> asArray(); - - static PassRefPtr<InspectorValue> parseJSON(const String& json); + bool isNull() const { return m_type == Type::Null; } + + virtual bool asBoolean(bool&) const; + virtual bool asInteger(int&) const; + virtual bool asInteger(unsigned&) const; + virtual bool asInteger(long&) const; + virtual bool asInteger(long long&) const; + virtual bool asInteger(unsigned long&) const; + virtual bool asInteger(unsigned long long&) const; + virtual bool asDouble(double&) const; + virtual bool asDouble(float&) const; + virtual bool asString(String&) const; + virtual bool asValue(RefPtr<InspectorValue>&); + virtual bool asObject(RefPtr<InspectorObject>&); + virtual bool asArray(RefPtr<InspectorArray>&); + + static bool parseJSON(const String& jsonInput, RefPtr<InspectorValue>& output); String toJSONString() const; - virtual void writeJSON(StringBuilder* output) const; + virtual void writeJSON(StringBuilder& output) const; protected: explicit InspectorValue(Type type) : m_type(type) { } @@ -96,45 +99,60 @@ private: class JS_EXPORT_PRIVATE InspectorBasicValue : public InspectorValue { public: - static PassRefPtr<InspectorBasicValue> create(bool); - static PassRefPtr<InspectorBasicValue> create(int); - static PassRefPtr<InspectorBasicValue> create(double); + static Ref<InspectorBasicValue> create(bool); + static Ref<InspectorBasicValue> create(int); + static Ref<InspectorBasicValue> create(double); - virtual bool asBoolean(bool* output) const override; - virtual bool asNumber(double* output) const override; - virtual bool asNumber(float* output) const override; - virtual bool asNumber(int* output) const override; - virtual bool asNumber(unsigned* output) const override; - virtual bool asNumber(long* output) const override; - virtual bool asNumber(long long* output) const override; - virtual bool asNumber(unsigned long* output) const override; - virtual bool asNumber(unsigned long long* output) const override; + virtual bool asBoolean(bool&) const override; + // Numbers from the frontend are always parsed as doubles, so we allow + // clients to convert to integral values with this function. + virtual bool asInteger(int&) const override; + virtual bool asInteger(unsigned&) const override; + virtual bool asInteger(long&) const override; + virtual bool asInteger(long long&) const override; + virtual bool asInteger(unsigned long&) const override; + virtual bool asInteger(unsigned long long&) const override; + virtual bool asDouble(double&) const override; + virtual bool asDouble(float&) const override; - virtual void writeJSON(StringBuilder* output) const override; + virtual void writeJSON(StringBuilder& output) const override; private: - explicit InspectorBasicValue(bool value) : InspectorValue(TypeBoolean), m_boolValue(value) { } - explicit InspectorBasicValue(int value) : InspectorValue(TypeNumber), m_doubleValue((double)value) { } - explicit InspectorBasicValue(double value) : InspectorValue(TypeNumber), m_doubleValue(value) { } + explicit InspectorBasicValue(bool value) + : InspectorValue(Type::Boolean) + , m_booleanValue(value) { } + + explicit InspectorBasicValue(int value) + : InspectorValue(Type::Integer) + , m_doubleValue(static_cast<double>(value)) { } + + explicit InspectorBasicValue(double value) + : InspectorValue(Type::Double) + , m_doubleValue(value) { } union { - bool m_boolValue; + bool m_booleanValue; double m_doubleValue; }; }; class JS_EXPORT_PRIVATE InspectorString : public InspectorValue { public: - static PassRefPtr<InspectorString> create(const String&); - static PassRefPtr<InspectorString> create(const char*); + static Ref<InspectorString> create(const String&); + static Ref<InspectorString> create(const char*); - virtual bool asString(String* output) const override; + virtual bool asString(String& output) const override; - virtual void writeJSON(StringBuilder* output) const override; + virtual void writeJSON(StringBuilder& output) const override; private: - explicit InspectorString(const String& value) : InspectorValue(TypeString), m_stringValue(value) { } - explicit InspectorString(const char* value) : InspectorValue(TypeString), m_stringValue(value) { } + explicit InspectorString(const String& value) + : InspectorValue(Type::String) + , m_stringValue(value) { } + + explicit InspectorString(const char* value) + : InspectorValue(Type::String) + , m_stringValue(value) { } String m_stringValue; }; @@ -147,39 +165,52 @@ public: typedef Dictionary::iterator iterator; typedef Dictionary::const_iterator const_iterator; - virtual PassRefPtr<InspectorObject> asObject() override; InspectorObject* openAccessors(); protected: virtual ~InspectorObjectBase(); - virtual bool asObject(RefPtr<InspectorObject>* output) override; + virtual bool asObject(RefPtr<InspectorObject>& output) override; + // FIXME: use templates to reduce the amount of duplicated set*() methods. void setBoolean(const String& name, bool); - void setNumber(const String& name, double); + void setInteger(const String& name, int); + void setDouble(const String& name, double); void setString(const String& name, const String&); - void setValue(const String& name, PassRefPtr<InspectorValue>); - void setObject(const String& name, PassRefPtr<InspectorObject>); - void setArray(const String& name, PassRefPtr<InspectorArray>); + void setValue(const String& name, RefPtr<InspectorValue>&&); + void setObject(const String& name, RefPtr<InspectorObjectBase>&&); + void setArray(const String& name, RefPtr<InspectorArrayBase>&&); iterator find(const String& name); const_iterator find(const String& name) const; - bool getBoolean(const String& name, bool* output) const; - template<class T> bool getNumber(const String& name, T* output) const + + // FIXME: use templates to reduce the amount of duplicated get*() methods. + bool getBoolean(const String& name, bool& output) const; + template<class T> bool getDouble(const String& name, T& output) const + { + RefPtr<InspectorValue> value; + if (!getValue(name, value)) + return false; + + return value->asDouble(output); + } + template<class T> bool getInteger(const String& name, T& output) const { - RefPtr<InspectorValue> value = get(name); - if (!value) + RefPtr<InspectorValue> value; + if (!getValue(name, value)) return false; - return value->asNumber(output); + + return value->asInteger(output); } - bool getString(const String& name, String* output) const; - PassRefPtr<InspectorObject> getObject(const String& name) const; - PassRefPtr<InspectorArray> getArray(const String& name) const; - PassRefPtr<InspectorValue> get(const String& name) const; + + bool getString(const String& name, String& output) const; + bool getObject(const String& name, RefPtr<InspectorObject>&) const; + bool getArray(const String& name, RefPtr<InspectorArray>&) const; + bool getValue(const String& name, RefPtr<InspectorValue>&) const; void remove(const String& name); - virtual void writeJSON(StringBuilder* output) const override; + virtual void writeJSON(StringBuilder& output) const override; iterator begin() { return m_data.begin(); } iterator end() { return m_data.end(); } @@ -198,12 +229,13 @@ private: class InspectorObject : public InspectorObjectBase { public: - static JS_EXPORT_PRIVATE PassRefPtr<InspectorObject> create(); + static JS_EXPORT_PRIVATE Ref<InspectorObject> create(); using InspectorObjectBase::asObject; using InspectorObjectBase::setBoolean; - using InspectorObjectBase::setNumber; + using InspectorObjectBase::setInteger; + using InspectorObjectBase::setDouble; using InspectorObjectBase::setString; using InspectorObjectBase::setValue; using InspectorObjectBase::setObject; @@ -211,11 +243,12 @@ public: using InspectorObjectBase::find; using InspectorObjectBase::getBoolean; - using InspectorObjectBase::getNumber; + using InspectorObjectBase::getInteger; + using InspectorObjectBase::getDouble; using InspectorObjectBase::getString; using InspectorObjectBase::getObject; using InspectorObjectBase::getArray; - using InspectorObjectBase::get; + using InspectorObjectBase::getValue; using InspectorObjectBase::remove; @@ -231,26 +264,24 @@ public: typedef Vector<RefPtr<InspectorValue>>::iterator iterator; typedef Vector<RefPtr<InspectorValue>>::const_iterator const_iterator; - virtual PassRefPtr<InspectorArray> asArray() override; - - unsigned length() const { return m_data.size(); } + unsigned length() const { return static_cast<unsigned>(m_data.size()); } protected: virtual ~InspectorArrayBase(); - virtual bool asArray(RefPtr<InspectorArray>* output) override; + virtual bool asArray(RefPtr<InspectorArray>&) override; void pushBoolean(bool); - void pushInt(int); - void pushNumber(double); + void pushInteger(int); + void pushDouble(double); void pushString(const String&); - void pushValue(PassRefPtr<InspectorValue>); - void pushObject(PassRefPtr<InspectorObject>); - void pushArray(PassRefPtr<InspectorArray>); + void pushValue(RefPtr<InspectorValue>&&); + void pushObject(RefPtr<InspectorObjectBase>&&); + void pushArray(RefPtr<InspectorArrayBase>&&); - PassRefPtr<InspectorValue> get(size_t index); + RefPtr<InspectorValue> get(size_t index) const; - virtual void writeJSON(StringBuilder* output) const override; + virtual void writeJSON(StringBuilder& output) const override; iterator begin() { return m_data.begin(); } iterator end() { return m_data.end(); } @@ -266,13 +297,13 @@ private: class InspectorArray : public InspectorArrayBase { public: - static JS_EXPORT_PRIVATE PassRefPtr<InspectorArray> create(); + static JS_EXPORT_PRIVATE Ref<InspectorArray> create(); using InspectorArrayBase::asArray; using InspectorArrayBase::pushBoolean; - using InspectorArrayBase::pushInt; - using InspectorArrayBase::pushNumber; + using InspectorArrayBase::pushInteger; + using InspectorArrayBase::pushDouble; using InspectorArrayBase::pushString; using InspectorArrayBase::pushValue; using InspectorArrayBase::pushObject; @@ -300,7 +331,12 @@ inline void InspectorObjectBase::setBoolean(const String& name, bool value) setValue(name, InspectorBasicValue::create(value)); } -inline void InspectorObjectBase::setNumber(const String& name, double value) +inline void InspectorObjectBase::setInteger(const String& name, int value) +{ + setValue(name, InspectorBasicValue::create(value)); +} + +inline void InspectorObjectBase::setDouble(const String& name, double value) { setValue(name, InspectorBasicValue::create(value)); } @@ -310,24 +346,24 @@ inline void InspectorObjectBase::setString(const String& name, const String& val setValue(name, InspectorString::create(value)); } -inline void InspectorObjectBase::setValue(const String& name, PassRefPtr<InspectorValue> value) +inline void InspectorObjectBase::setValue(const String& name, RefPtr<InspectorValue>&& value) { ASSERT(value); - if (m_data.set(name, value).isNewEntry) + if (m_data.set(name, WTF::move(value)).isNewEntry) m_order.append(name); } -inline void InspectorObjectBase::setObject(const String& name, PassRefPtr<InspectorObject> value) +inline void InspectorObjectBase::setObject(const String& name, RefPtr<InspectorObjectBase>&& value) { ASSERT(value); - if (m_data.set(name, value).isNewEntry) + if (m_data.set(name, WTF::move(value)).isNewEntry) m_order.append(name); } -inline void InspectorObjectBase::setArray(const String& name, PassRefPtr<InspectorArray> value) +inline void InspectorObjectBase::setArray(const String& name, RefPtr<InspectorArrayBase>&& value) { ASSERT(value); - if (m_data.set(name, value).isNewEntry) + if (m_data.set(name, WTF::move(value)).isNewEntry) m_order.append(name); } @@ -336,12 +372,12 @@ inline void InspectorArrayBase::pushBoolean(bool value) m_data.append(InspectorBasicValue::create(value)); } -inline void InspectorArrayBase::pushInt(int value) +inline void InspectorArrayBase::pushInteger(int value) { m_data.append(InspectorBasicValue::create(value)); } -inline void InspectorArrayBase::pushNumber(double value) +inline void InspectorArrayBase::pushDouble(double value) { m_data.append(InspectorBasicValue::create(value)); } @@ -351,22 +387,22 @@ inline void InspectorArrayBase::pushString(const String& value) m_data.append(InspectorString::create(value)); } -inline void InspectorArrayBase::pushValue(PassRefPtr<InspectorValue> value) +inline void InspectorArrayBase::pushValue(RefPtr<InspectorValue>&& value) { ASSERT(value); - m_data.append(value); + m_data.append(WTF::move(value)); } -inline void InspectorArrayBase::pushObject(PassRefPtr<InspectorObject> value) +inline void InspectorArrayBase::pushObject(RefPtr<InspectorObjectBase>&& value) { ASSERT(value); - m_data.append(value); + m_data.append(WTF::move(value)); } -inline void InspectorArrayBase::pushArray(PassRefPtr<InspectorArray> value) +inline void InspectorArrayBase::pushArray(RefPtr<InspectorArrayBase>&& value) { ASSERT(value); - m_data.append(value); + m_data.append(WTF::move(value)); } } // namespace Inspector diff --git a/inspector/JSConsoleClient.cpp b/inspector/JSConsoleClient.cpp deleted file mode 100644 index 019dba0..0000000 --- a/inspector/JSConsoleClient.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2014 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 "JSConsoleClient.h" - -#if ENABLE(INSPECTOR) - -#include "InspectorConsoleAgent.h" -#include "InspectorProfilerAgent.h" -#include "ScriptArguments.h" -#include "ScriptCallStack.h" -#include "ScriptCallStackFactory.h" - -#if USE(CF) -#include <CoreFoundation/CoreFoundation.h> -#endif - -using namespace JSC; - -namespace Inspector { - -static bool sLogToSystemConsole = false; - -bool JSConsoleClient::logToSystemConsole() -{ - return sLogToSystemConsole; -} - -void JSConsoleClient::setLogToSystemConsole(bool shouldLog) -{ - sLogToSystemConsole = shouldLog; -} - -void JSConsoleClient::initializeLogToSystemConsole() -{ -#if !LOG_DISABLED - sLogToSystemConsole = true; -#elif USE(CF) - Boolean keyExistsAndHasValidFormat = false; - Boolean preference = CFPreferencesGetAppBooleanValue(CFSTR("JavaScriptCoreOutputConsoleMessagesToSystemConsole"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat); - if (keyExistsAndHasValidFormat) - sLogToSystemConsole = preference; -#endif -} - -JSConsoleClient::JSConsoleClient(InspectorConsoleAgent* consoleAgent, InspectorProfilerAgent* profilerAgent) - : ConsoleClient() - , m_consoleAgent(consoleAgent) - , m_profilerAgent(profilerAgent) -{ - static std::once_flag initializeLogging; - std::call_once(initializeLogging, []{ - JSConsoleClient::initializeLogToSystemConsole(); - }); -} - -void JSConsoleClient::messageWithTypeAndLevel(MessageType type, MessageLevel level, JSC::ExecState* exec, PassRefPtr<ScriptArguments> prpArguments) -{ - RefPtr<ScriptArguments> arguments = prpArguments; - - if (JSConsoleClient::logToSystemConsole()) - ConsoleClient::printConsoleMessageWithArguments(MessageSource::ConsoleAPI, type, level, exec, arguments); - - String message; - arguments->getFirstArgumentAsString(message); - m_consoleAgent->addMessageToConsole(MessageSource::ConsoleAPI, type, level, message, exec, arguments.release()); -} - -void JSConsoleClient::count(ExecState* exec, PassRefPtr<ScriptArguments> arguments) -{ - m_consoleAgent->count(exec, arguments); -} - -void JSConsoleClient::profile(JSC::ExecState* exec, const String& title) -{ - if (!m_profilerAgent->enabled()) - return; - - String resolvedTitle = m_profilerAgent->startProfiling(title); - - RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(exec, 1)); - m_consoleAgent->addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Profile, MessageLevel::Debug, resolvedTitle, callStack); -} - -void JSConsoleClient::profileEnd(JSC::ExecState* exec, const String& title) -{ - if (!m_profilerAgent->enabled()) - return; - - RefPtr<JSC::Profile> profile = m_profilerAgent->stopProfiling(title); - if (!profile) - return; - - RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(exec, 1)); - String message = makeString(profile->title(), '#', String::number(profile->uid())); - m_consoleAgent->addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Profile, MessageLevel::Debug, message, callStack); -} - -void JSConsoleClient::time(ExecState*, const String& title) -{ - m_consoleAgent->startTiming(title); -} - -void JSConsoleClient::timeEnd(ExecState* exec, const String& title) -{ - RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(exec, 1)); - m_consoleAgent->stopTiming(title, callStack.release()); -} - -void JSConsoleClient::timeStamp(ExecState*, PassRefPtr<ScriptArguments>) -{ - // FIXME: JSContext inspection needs a timeline. - warnUnimplemented(ASCIILiteral("console.timeStamp")); -} - -void JSConsoleClient::warnUnimplemented(const String& method) -{ - String message = method + " is currently ignored in JavaScript context inspection."; - m_consoleAgent->addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Warning, message, nullptr, nullptr); -} - -} // namespace Inspector - -#endif diff --git a/inspector/JSGlobalObjectConsoleClient.cpp b/inspector/JSGlobalObjectConsoleClient.cpp new file mode 100644 index 0000000..75b805f --- /dev/null +++ b/inspector/JSGlobalObjectConsoleClient.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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 "JSGlobalObjectConsoleClient.h" + +#include "ConsoleMessage.h" +#include "InspectorConsoleAgent.h" +#include "ScriptArguments.h" +#include "ScriptCallStack.h" +#include "ScriptCallStackFactory.h" + +using namespace JSC; + +namespace Inspector { + +#if !LOG_DISABLED +static bool sLogToSystemConsole = true; +#else +static bool sLogToSystemConsole = false; +#endif + +bool JSGlobalObjectConsoleClient::logToSystemConsole() +{ + return sLogToSystemConsole; +} + +void JSGlobalObjectConsoleClient::setLogToSystemConsole(bool shouldLog) +{ + sLogToSystemConsole = shouldLog; +} + +JSGlobalObjectConsoleClient::JSGlobalObjectConsoleClient(InspectorConsoleAgent* consoleAgent) + : ConsoleClient() + , m_consoleAgent(consoleAgent) +{ +} + +void JSGlobalObjectConsoleClient::messageWithTypeAndLevel(MessageType type, MessageLevel level, JSC::ExecState* exec, RefPtr<ScriptArguments>&& arguments) +{ + if (JSGlobalObjectConsoleClient::logToSystemConsole()) + ConsoleClient::printConsoleMessageWithArguments(MessageSource::ConsoleAPI, type, level, exec, arguments.copyRef()); + + String message; + arguments->getFirstArgumentAsString(message); + m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, type, level, message, WTF::move(arguments), exec)); +} + +void JSGlobalObjectConsoleClient::count(ExecState* exec, RefPtr<ScriptArguments>&& arguments) +{ + m_consoleAgent->count(exec, arguments); +} + +void JSGlobalObjectConsoleClient::profile(JSC::ExecState*, const String&) +{ + // FIXME: support |console.profile| for JSContexts. <https://webkit.org/b/136466> +} + +void JSGlobalObjectConsoleClient::profileEnd(JSC::ExecState*, const String&) +{ + // FIXME: support |console.profile| for JSContexts. <https://webkit.org/b/136466> +} + +void JSGlobalObjectConsoleClient::time(ExecState*, const String& title) +{ + m_consoleAgent->startTiming(title); +} + +void JSGlobalObjectConsoleClient::timeEnd(ExecState* exec, const String& title) +{ + RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(exec, 1)); + m_consoleAgent->stopTiming(title, WTF::move(callStack)); +} + +void JSGlobalObjectConsoleClient::timeStamp(ExecState*, RefPtr<ScriptArguments>&&) +{ + // FIXME: JSContext inspection needs a timeline. + warnUnimplemented(ASCIILiteral("console.timeStamp")); +} + +void JSGlobalObjectConsoleClient::warnUnimplemented(const String& method) +{ + String message = method + " is currently ignored in JavaScript context inspection."; + m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Warning, message, nullptr, nullptr)); +} + +} // namespace Inspector diff --git a/inspector/JSConsoleClient.h b/inspector/JSGlobalObjectConsoleClient.h similarity index 76% rename from inspector/JSConsoleClient.h rename to inspector/JSGlobalObjectConsoleClient.h index 74132c6..12e1e41 100644 --- a/inspector/JSConsoleClient.h +++ b/inspector/JSGlobalObjectConsoleClient.h @@ -23,43 +23,40 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSConsoleClient_h -#define JSConsoleClient_h +#ifndef JSGlobalObjectConsoleClient_h +#define JSGlobalObjectConsoleClient_h #include "ConsoleClient.h" namespace Inspector { class InspectorConsoleAgent; -class InspectorProfilerAgent; -class JSConsoleClient final : public JSC::ConsoleClient { +class JSGlobalObjectConsoleClient final : public JSC::ConsoleClient { WTF_MAKE_FAST_ALLOCATED; public: - explicit JSConsoleClient(InspectorConsoleAgent*, InspectorProfilerAgent*); - virtual ~JSConsoleClient() { } + explicit JSGlobalObjectConsoleClient(InspectorConsoleAgent*); + virtual ~JSGlobalObjectConsoleClient() { } static bool logToSystemConsole(); static void setLogToSystemConsole(bool); - static void initializeLogToSystemConsole(); protected: - virtual void messageWithTypeAndLevel(MessageType, MessageLevel, JSC::ExecState*, PassRefPtr<ScriptArguments>) override; - virtual void count(JSC::ExecState*, PassRefPtr<ScriptArguments>) override; + virtual void messageWithTypeAndLevel(MessageType, MessageLevel, JSC::ExecState*, RefPtr<ScriptArguments>&&) override; + virtual void count(JSC::ExecState*, RefPtr<ScriptArguments>&&) override; virtual void profile(JSC::ExecState*, const String& title) override; virtual void profileEnd(JSC::ExecState*, const String& title) override; virtual void time(JSC::ExecState*, const String& title) override; virtual void timeEnd(JSC::ExecState*, const String& title) override; - virtual void timeStamp(JSC::ExecState*, PassRefPtr<ScriptArguments>) override; + virtual void timeStamp(JSC::ExecState*, RefPtr<ScriptArguments>&&) override; private: void warnUnimplemented(const String& method); - void internalAddMessage(MessageType, MessageLevel, JSC::ExecState*, PassRefPtr<ScriptArguments>); + void internalAddMessage(MessageType, MessageLevel, JSC::ExecState*, RefPtr<ScriptArguments>&&); InspectorConsoleAgent* m_consoleAgent; - InspectorProfilerAgent* m_profilerAgent; }; } -#endif // !defined(JSConsoleClient_h) +#endif // !defined(JSGlobalObjectConsoleClient_h) diff --git a/inspector/JSGlobalObjectInspectorController.cpp b/inspector/JSGlobalObjectInspectorController.cpp index ebdd180..11d86ed 100644 --- a/inspector/JSGlobalObjectInspectorController.cpp +++ b/inspector/JSGlobalObjectInspectorController.cpp @@ -26,27 +26,30 @@ #include "config.h" #include "JSGlobalObjectInspectorController.h" -#if ENABLE(INSPECTOR) - #include "Completion.h" +#include "ConsoleMessage.h" #include "ErrorHandlingScope.h" +#include "Exception.h" #include "InjectedScriptHost.h" #include "InjectedScriptManager.h" #include "InspectorAgent.h" #include "InspectorBackendDispatcher.h" #include "InspectorFrontendChannel.h" -#include "JSConsoleClient.h" #include "JSGlobalObject.h" #include "JSGlobalObjectConsoleAgent.h" +#include "JSGlobalObjectConsoleClient.h" #include "JSGlobalObjectDebuggerAgent.h" -#include "JSGlobalObjectProfilerAgent.h" #include "JSGlobalObjectRuntimeAgent.h" #include "ScriptArguments.h" #include "ScriptCallStack.h" #include "ScriptCallStackFactory.h" +#include <wtf/Stopwatch.h> + #include <cxxabi.h> +#if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK)) #include <dlfcn.h> #include <execinfo.h> +#endif #if ENABLE(REMOTE_INSPECTOR) #include "JSGlobalObjectDebuggable.h" @@ -60,24 +63,32 @@ namespace Inspector { JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObject& globalObject) : m_globalObject(globalObject) , m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create())) - , m_inspectorFrontendChannel(nullptr) + , m_frontendChannel(nullptr) + , m_executionStopwatch(Stopwatch::create()) , m_includeNativeCallStackWithExceptions(true) + , m_isAutomaticInspection(false) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_augmentingClient(nullptr) +#endif { + auto inspectorAgent = std::make_unique<InspectorAgent>(*this); auto runtimeAgent = std::make_unique<JSGlobalObjectRuntimeAgent>(m_injectedScriptManager.get(), m_globalObject); auto consoleAgent = std::make_unique<JSGlobalObjectConsoleAgent>(m_injectedScriptManager.get()); auto debuggerAgent = std::make_unique<JSGlobalObjectDebuggerAgent>(m_injectedScriptManager.get(), m_globalObject, consoleAgent.get()); - auto profilerAgent = std::make_unique<JSGlobalObjectProfilerAgent>(m_globalObject); + m_inspectorAgent = inspectorAgent.get(); + m_debuggerAgent = debuggerAgent.get(); m_consoleAgent = consoleAgent.get(); - m_consoleClient = std::make_unique<JSConsoleClient>(m_consoleAgent, profilerAgent.get()); + m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent); runtimeAgent->setScriptDebugServer(&debuggerAgent->scriptDebugServer()); - profilerAgent->setScriptDebugServer(&debuggerAgent->scriptDebugServer()); - m_agents.append(std::make_unique<InspectorAgent>()); + m_agents.append(WTF::move(inspectorAgent)); m_agents.append(WTF::move(runtimeAgent)); m_agents.append(WTF::move(consoleAgent)); m_agents.append(WTF::move(debuggerAgent)); + + m_executionStopwatch->start(); } JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController() @@ -87,42 +98,69 @@ JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController() void JSGlobalObjectInspectorController::globalObjectDestroyed() { - disconnectFrontend(InspectorDisconnectReason::InspectedTargetDestroyed); + disconnectFrontend(DisconnectReason::InspectedTargetDestroyed); m_injectedScriptManager->disconnect(); } -void JSGlobalObjectInspectorController::connectFrontend(InspectorFrontendChannel* frontendChannel) +void JSGlobalObjectInspectorController::connectFrontend(FrontendChannel* frontendChannel, bool isAutomaticInspection) { - ASSERT(!m_inspectorFrontendChannel); - ASSERT(!m_inspectorBackendDispatcher); + ASSERT(!m_frontendChannel); + ASSERT(!m_backendDispatcher); - m_inspectorFrontendChannel = frontendChannel; - m_inspectorBackendDispatcher = InspectorBackendDispatcher::create(frontendChannel); + m_isAutomaticInspection = isAutomaticInspection; - m_agents.didCreateFrontendAndBackend(frontendChannel, m_inspectorBackendDispatcher.get()); + m_frontendChannel = frontendChannel; + m_backendDispatcher = BackendDispatcher::create(frontendChannel); + + m_agents.didCreateFrontendAndBackend(frontendChannel, m_backendDispatcher.get()); + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + m_inspectorAgent->activateExtraDomains(m_agents.extraDomains()); + + if (m_augmentingClient) + m_augmentingClient->inspectorConnected(); +#endif } -void JSGlobalObjectInspectorController::disconnectFrontend(InspectorDisconnectReason reason) +void JSGlobalObjectInspectorController::disconnectFrontend(DisconnectReason reason) { - if (!m_inspectorFrontendChannel) + if (!m_frontendChannel) return; m_agents.willDestroyFrontendAndBackend(reason); - m_inspectorBackendDispatcher->clearFrontend(); - m_inspectorBackendDispatcher.clear(); - m_inspectorFrontendChannel = nullptr; + m_backendDispatcher->clearFrontend(); + m_backendDispatcher = nullptr; + m_frontendChannel = nullptr; + + m_isAutomaticInspection = false; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_augmentingClient) + m_augmentingClient->inspectorDisconnected(); +#endif } void JSGlobalObjectInspectorController::dispatchMessageFromFrontend(const String& message) { - if (m_inspectorBackendDispatcher) - m_inspectorBackendDispatcher->dispatch(message); + if (m_backendDispatcher) + m_backendDispatcher->dispatch(message); +} + +void JSGlobalObjectInspectorController::pause() +{ + if (!m_frontendChannel) + return; + + ErrorString dummyError; + m_debuggerAgent->enable(dummyError); + m_debuggerAgent->pause(dummyError); } void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* callStack) { +#if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK)) static const int framesToShow = 31; static const int framesToSkip = 3; // WTFGetBacktrace, appendAPIBacktrace, reportAPIException. @@ -146,9 +184,12 @@ void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* call callStack->append(ScriptCallFrame(ASCIILiteral("?"), ASCIILiteral("[native code]"), 0, 0)); free(cxaDemangled); } +#else + UNUSED_PARAM(callStack); +#endif } -void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, JSValue exception) +void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, Exception* exception) { if (isTerminatedExecutionException(exception)) return; @@ -161,10 +202,10 @@ void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, JSVa // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not evaluate JavaScript handling exceptions // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception. - String errorMessage = exception.toString(exec)->value(exec); + String errorMessage = exception->value().toString(exec)->value(exec); exec->clearException(); - if (JSConsoleClient::logToSystemConsole()) { + if (JSGlobalObjectConsoleClient::logToSystemConsole()) { if (callStack->size()) { const ScriptCallFrame& callFrame = callStack->at(0); ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber()); @@ -172,7 +213,7 @@ void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, JSVa ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, String(), 0, 0); } - m_consoleAgent->addMessageToConsole(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack); + m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack)); } ConsoleClient* JSGlobalObjectInspectorController::consoleClient() const @@ -183,7 +224,7 @@ ConsoleClient* JSGlobalObjectInspectorController::consoleClient() const bool JSGlobalObjectInspectorController::developerExtrasEnabled() const { #if ENABLE(REMOTE_INSPECTOR) - if (!RemoteInspector::shared().enabled()) + if (!RemoteInspector::singleton().enabled()) return false; if (!m_globalObject.inspectorDebuggable().remoteDebuggingAllowed()) @@ -203,6 +244,33 @@ InspectorEvaluateHandler JSGlobalObjectInspectorController::evaluateHandler() co return JSC::evaluate; } +void JSGlobalObjectInspectorController::frontendInitialized() +{ +#if ENABLE(REMOTE_INSPECTOR) + if (m_isAutomaticInspection) + m_globalObject.inspectorDebuggable().unpauseForInitializedInspector(); +#endif +} + +Ref<Stopwatch> JSGlobalObjectInspectorController::executionStopwatch() +{ + return m_executionStopwatch.copyRef(); +} + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +void JSGlobalObjectInspectorController::appendExtraAgent(std::unique_ptr<InspectorAgentBase> agent) +{ + String domainName = agent->domainName(); + + if (m_frontendChannel) + agent->didCreateFrontendAndBackend(m_frontendChannel, m_backendDispatcher.get()); + + m_agents.appendExtraAgent(WTF::move(agent)); + + if (m_frontendChannel) + m_inspectorAgent->activateExtraDomain(domainName); +} +#endif + } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/JSGlobalObjectInspectorController.h b/inspector/JSGlobalObjectInspectorController.h index 61ab1c1..6e3f94e 100644 --- a/inspector/JSGlobalObjectInspectorController.h +++ b/inspector/JSGlobalObjectInspectorController.h @@ -26,16 +26,24 @@ #ifndef JSGlobalObjectInspectorController_h #define JSGlobalObjectInspectorController_h -#if ENABLE(INSPECTOR) - #include "InspectorAgentRegistry.h" #include "InspectorEnvironment.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> #include <wtf/text/WTFString.h> +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "AugmentableInspectorController.h" +#endif + +namespace WTF { +class Stopwatch; +} + + namespace JSC { class ConsoleClient; +class Exception; class ExecState; class JSGlobalObject; class JSValue; @@ -43,23 +51,29 @@ class JSValue; namespace Inspector { +class BackendDispatcher; +class FrontendChannel; class InjectedScriptManager; +class InspectorAgent; class InspectorConsoleAgent; -class InspectorBackendDispatcher; -class InspectorConsoleAgent; -class InspectorFrontendChannel; -class JSConsoleClient; +class InspectorDebuggerAgent; +class JSGlobalObjectConsoleClient; class ScriptCallStack; -class JSGlobalObjectInspectorController final : public InspectorEnvironment { +class JSGlobalObjectInspectorController final + : public InspectorEnvironment +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , public AugmentableInspectorController +#endif +{ WTF_MAKE_NONCOPYABLE(JSGlobalObjectInspectorController); WTF_MAKE_FAST_ALLOCATED; public: JSGlobalObjectInspectorController(JSC::JSGlobalObject&); ~JSGlobalObjectInspectorController(); - void connectFrontend(InspectorFrontendChannel*); - void disconnectFrontend(InspectorDisconnectReason reason); + void connectFrontend(FrontendChannel*, bool isAutomaticInspection); + void disconnectFrontend(DisconnectReason); void dispatchMessageFromFrontend(const String&); void globalObjectDestroyed(); @@ -67,7 +81,8 @@ public: bool includesNativeCallStackWhenReportingExceptions() const { return m_includeNativeCallStackWithExceptions; } void setIncludesNativeCallStackWhenReportingExceptions(bool includesNativeCallStack) { m_includeNativeCallStackWithExceptions = includesNativeCallStack; } - void reportAPIException(JSC::ExecState*, JSC::JSValue exception); + void pause(); + void reportAPIException(JSC::ExecState*, JSC::Exception*); JSC::ConsoleClient* consoleClient() const; @@ -77,22 +92,38 @@ public: virtual InspectorEvaluateHandler evaluateHandler() const override; virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String&, int) override { } virtual void didCallInjectedScriptFunction(JSC::ExecState*) override { } + virtual void frontendInitialized() override; + virtual Ref<WTF::Stopwatch> executionStopwatch() override; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const override { return m_augmentingClient; } + virtual void setAugmentableInspectorControllerClient(AugmentableInspectorControllerClient* client) override { m_augmentingClient = client; } + + virtual FrontendChannel* frontendChannel() const override { return m_frontendChannel; } + virtual void appendExtraAgent(std::unique_ptr<InspectorAgentBase>) override; +#endif private: void appendAPIBacktrace(ScriptCallStack* callStack); JSC::JSGlobalObject& m_globalObject; std::unique_ptr<InjectedScriptManager> m_injectedScriptManager; - std::unique_ptr<JSConsoleClient> m_consoleClient; + std::unique_ptr<JSGlobalObjectConsoleClient> m_consoleClient; + InspectorAgent* m_inspectorAgent; InspectorConsoleAgent* m_consoleAgent; - InspectorAgentRegistry m_agents; - InspectorFrontendChannel* m_inspectorFrontendChannel; - RefPtr<InspectorBackendDispatcher> m_inspectorBackendDispatcher; + InspectorDebuggerAgent* m_debuggerAgent; + AgentRegistry m_agents; + FrontendChannel* m_frontendChannel; + RefPtr<BackendDispatcher> m_backendDispatcher; + Ref<WTF::Stopwatch> m_executionStopwatch; bool m_includeNativeCallStackWithExceptions; + bool m_isAutomaticInspection; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + AugmentableInspectorControllerClient* m_augmentingClient; +#endif }; } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSGlobalObjectInspectorController_h) diff --git a/inspector/JSGlobalObjectScriptDebugServer.cpp b/inspector/JSGlobalObjectScriptDebugServer.cpp index ff061ed..0e968f7 100644 --- a/inspector/JSGlobalObjectScriptDebugServer.cpp +++ b/inspector/JSGlobalObjectScriptDebugServer.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "JSGlobalObjectScriptDebugServer.h" -#if ENABLE(INSPECTOR) - #include "EventLoop.h" #include "JSCInlines.h" #include "JSLock.h" @@ -89,4 +87,3 @@ void JSGlobalObjectScriptDebugServer::runEventLoopWhilePaused() } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/JSGlobalObjectScriptDebugServer.h b/inspector/JSGlobalObjectScriptDebugServer.h index d309e59..901b673 100644 --- a/inspector/JSGlobalObjectScriptDebugServer.h +++ b/inspector/JSGlobalObjectScriptDebugServer.h @@ -26,8 +26,6 @@ #ifndef JSGlobalObjectScriptDebugServer_h #define JSGlobalObjectScriptDebugServer_h -#if ENABLE(INSPECTOR) - #include "ScriptDebugServer.h" #include <wtf/Forward.h> @@ -47,7 +45,7 @@ public: virtual void recompileAllJSFunctions() override; private: - virtual ListenerSet* getListenersForGlobalObject(JSC::JSGlobalObject*) override { return &m_listeners; } + virtual ListenerSet& getListeners() override { return m_listeners; } virtual void didPause(JSC::JSGlobalObject*) override { } virtual void didContinue(JSC::JSGlobalObject*) override { } virtual void runEventLoopWhilePaused() override; @@ -56,7 +54,7 @@ private: // NOTE: Currently all exceptions are reported at the API boundary through reportAPIException. // Until a time comes where an exception can be caused outside of the API (e.g. setTimeout // or some other async operation in a pure JSContext) we can ignore exceptions reported here. - virtual void reportException(JSC::ExecState*, JSC::JSValue) const override { } + virtual void reportException(JSC::ExecState*, JSC::Exception*) const override { } ListenerSet m_listeners; JSC::JSGlobalObject& m_globalObject; @@ -64,6 +62,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // JSGlobalObjectScriptDebugServer_h diff --git a/inspector/JSInjectedScriptHost.cpp b/inspector/JSInjectedScriptHost.cpp index 0e9555f..a17ba98 100644 --- a/inspector/JSInjectedScriptHost.cpp +++ b/inspector/JSInjectedScriptHost.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,26 +26,41 @@ #include "config.h" #include "JSInjectedScriptHost.h" -#if ENABLE(INSPECTOR) - #include "DateInstance.h" +#include "DirectArguments.h" #include "Error.h" #include "InjectedScriptHost.h" +#include "IteratorOperations.h" #include "JSArray.h" +#include "JSArrayIterator.h" +#include "JSBoundFunction.h" +#include "JSCInlines.h" #include "JSFunction.h" #include "JSInjectedScriptHostPrototype.h" +#include "JSMap.h" +#include "JSMapIterator.h" +#include "JSSet.h" +#include "JSSetIterator.h" +#include "JSStringIterator.h" #include "JSTypedArrays.h" +#include "JSWeakMap.h" +#include "JSWeakSet.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" #include "RegExpObject.h" +#include "ScopedArguments.h" #include "SourceCode.h" #include "TypedArrayInlines.h" +#include "WeakMapData.h" + +#if ENABLE(PROMISES) +#include "JSPromise.h" +#endif using namespace JSC; namespace Inspector { -const ClassInfo JSInjectedScriptHost::s_info = { "InjectedScriptHost", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSInjectedScriptHost) }; +const ClassInfo JSInjectedScriptHost::s_info = { "InjectedScriptHost", &Base::s_info, 0, CREATE_METHOD_TABLE(JSInjectedScriptHost) }; JSInjectedScriptHost::JSInjectedScriptHost(VM& vm, Structure* structure, PassRefPtr<InjectedScriptHost> impl) : JSDestructibleObject(vm, structure) @@ -72,10 +87,8 @@ void JSInjectedScriptHost::destroy(JSC::JSCell* cell) void JSInjectedScriptHost::releaseImpl() { - if (m_impl) { - m_impl->deref(); - m_impl = nullptr; - } + if (auto impl = std::exchange(m_impl, nullptr)) + impl->deref(); } JSInjectedScriptHost::~JSInjectedScriptHost() @@ -94,9 +107,8 @@ JSValue JSInjectedScriptHost::internalConstructorName(ExecState* exec) if (exec->argumentCount() < 1) return jsUndefined(); - JSObject* thisObject = jsCast<JSObject*>(exec->uncheckedArgument(0).toThis(exec, NotStrictMode)); - String result = thisObject->methodTable()->className(thisObject); - return jsString(exec, result); + JSObject* object = jsCast<JSObject*>(exec->uncheckedArgument(0).toThis(exec, NotStrictMode)); + return jsString(exec, JSObject::calculatedClassName(object)); } JSValue JSInjectedScriptHost::isHTMLAllCollection(ExecState* exec) @@ -108,7 +120,7 @@ JSValue JSInjectedScriptHost::isHTMLAllCollection(ExecState* exec) return jsBoolean(impl().isHTMLAllCollection(value)); } -JSValue JSInjectedScriptHost::type(ExecState* exec) +JSValue JSInjectedScriptHost::subtype(ExecState* exec) { if (exec->argumentCount() < 1) return jsUndefined(); @@ -120,13 +132,45 @@ JSValue JSInjectedScriptHost::type(ExecState* exec) return exec->vm().smallStrings.booleanString(); if (value.isNumber()) return exec->vm().smallStrings.numberString(); + if (value.isSymbol()) + return exec->vm().smallStrings.symbolString(); + + JSObject* object = asObject(value); + if (object) { + if (object->isErrorInstance()) + return jsNontrivialString(exec, ASCIILiteral("error")); + + // Consider class constructor functions class objects. + JSFunction* function = jsDynamicCast<JSFunction*>(value); + if (function && function->isClassConstructorFunction()) + return jsNontrivialString(exec, ASCIILiteral("class")); + } if (value.inherits(JSArray::info())) return jsNontrivialString(exec, ASCIILiteral("array")); + if (value.inherits(DirectArguments::info()) || value.inherits(ScopedArguments::info())) + return jsNontrivialString(exec, ASCIILiteral("array")); + if (value.inherits(DateInstance::info())) return jsNontrivialString(exec, ASCIILiteral("date")); if (value.inherits(RegExpObject::info())) return jsNontrivialString(exec, ASCIILiteral("regexp")); + + if (value.inherits(JSMap::info())) + return jsNontrivialString(exec, ASCIILiteral("map")); + if (value.inherits(JSSet::info())) + return jsNontrivialString(exec, ASCIILiteral("set")); + if (value.inherits(JSWeakMap::info())) + return jsNontrivialString(exec, ASCIILiteral("weakmap")); + if (value.inherits(JSWeakSet::info())) + return jsNontrivialString(exec, ASCIILiteral("weakset")); + + if (value.inherits(JSArrayIterator::info()) + || value.inherits(JSMapIterator::info()) + || value.inherits(JSSetIterator::info()) + || value.inherits(JSStringIterator::info())) + return jsNontrivialString(exec, ASCIILiteral("iterator")); + if (value.inherits(JSInt8Array::info()) || value.inherits(JSInt16Array::info()) || value.inherits(JSInt32Array::info())) return jsNontrivialString(exec, ASCIILiteral("array")); if (value.inherits(JSUint8Array::info()) || value.inherits(JSUint16Array::info()) || value.inherits(JSUint32Array::info())) @@ -134,7 +178,7 @@ JSValue JSInjectedScriptHost::type(ExecState* exec) if (value.inherits(JSFloat32Array::info()) || value.inherits(JSFloat64Array::info())) return jsNontrivialString(exec, ASCIILiteral("array")); - return impl().type(exec, value); + return impl().subtype(exec, value); } JSValue JSInjectedScriptHost::functionDetails(ExecState* exec) @@ -146,30 +190,37 @@ JSValue JSInjectedScriptHost::functionDetails(ExecState* exec) if (!value.asCell()->inherits(JSFunction::info())) return jsUndefined(); + // FIXME: This should provide better details for JSBoundFunctions. + JSFunction* function = jsCast<JSFunction*>(value); const SourceCode* sourceCode = function->sourceCode(); if (!sourceCode) return jsUndefined(); + // In the inspector protocol all positions are 0-based while in SourceCode they are 1-based int lineNumber = sourceCode->firstLine(); if (lineNumber) - lineNumber -= 1; // In the inspector protocol all positions are 0-based while in SourceCode they are 1-based + lineNumber -= 1; + int columnNumber = sourceCode->startColumn(); + if (columnNumber) + columnNumber -= 1; String scriptID = String::number(sourceCode->provider()->asID()); JSObject* location = constructEmptyObject(exec); - location->putDirect(exec->vm(), Identifier(exec, "lineNumber"), jsNumber(lineNumber)); - location->putDirect(exec->vm(), Identifier(exec, "scriptId"), jsString(exec, scriptID)); + location->putDirect(exec->vm(), Identifier::fromString(exec, "scriptId"), jsString(exec, scriptID)); + location->putDirect(exec->vm(), Identifier::fromString(exec, "lineNumber"), jsNumber(lineNumber)); + location->putDirect(exec->vm(), Identifier::fromString(exec, "columnNumber"), jsNumber(columnNumber)); JSObject* result = constructEmptyObject(exec); - result->putDirect(exec->vm(), Identifier(exec, "location"), location); + result->putDirect(exec->vm(), Identifier::fromString(exec, "location"), location); String name = function->name(exec); if (!name.isEmpty()) - result->putDirect(exec->vm(), Identifier(exec, "name"), jsString(exec, name)); + result->putDirect(exec->vm(), Identifier::fromString(exec, "name"), jsString(exec, name)); String displayName = function->displayName(exec); if (!displayName.isEmpty()) - result->putDirect(exec->vm(), Identifier(exec, "displayName"), jsString(exec, displayName)); + result->putDirect(exec->vm(), Identifier::fromString(exec, "displayName"), jsString(exec, displayName)); // FIXME: provide function scope data in "scopesRaw" property when JSC supports it. // <https://webkit.org/b/87192> [JSC] expose function (closure) inner context to debugger @@ -177,12 +228,256 @@ JSValue JSInjectedScriptHost::functionDetails(ExecState* exec) return result; } -JSValue JSInjectedScriptHost::getInternalProperties(ExecState*) +static JSObject* constructInternalProperty(ExecState* exec, const String& name, JSValue value) { - // FIXME: <https://webkit.org/b/94533> [JSC] expose object inner properties to debugger + JSObject* result = constructEmptyObject(exec); + result->putDirect(exec->vm(), Identifier::fromString(exec, "name"), jsString(exec, name)); + result->putDirect(exec->vm(), Identifier::fromString(exec, "value"), value); + return result; +} + +JSValue JSInjectedScriptHost::getInternalProperties(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue value = exec->uncheckedArgument(0); + +#if ENABLE(PROMISES) + if (JSPromise* promise = jsDynamicCast<JSPromise*>(value)) { + unsigned index = 0; + JSArray* array = constructEmptyArray(exec, nullptr); + switch (promise->status(exec->vm())) { + case JSPromise::Status::Pending: + array->putDirectIndex(exec, index++, constructInternalProperty(exec, ASCIILiteral("status"), jsNontrivialString(exec, ASCIILiteral("pending")))); + break; + case JSPromise::Status::Fulfilled: + array->putDirectIndex(exec, index++, constructInternalProperty(exec, ASCIILiteral("status"), jsNontrivialString(exec, ASCIILiteral("resolved")))); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, ASCIILiteral("result"), promise->result(exec->vm()))); + break; + case JSPromise::Status::Rejected: + array->putDirectIndex(exec, index++, constructInternalProperty(exec, ASCIILiteral("status"), jsNontrivialString(exec, ASCIILiteral("rejected")))); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, ASCIILiteral("result"), promise->result(exec->vm()))); + break; + } + // FIXME: <https://webkit.org/b/141664> Web Inspector: ES6: Improved Support for Promises - Promise Reactions + return array; + } +#endif + + if (JSBoundFunction* boundFunction = jsDynamicCast<JSBoundFunction*>(value)) { + unsigned index = 0; + JSArray* array = constructEmptyArray(exec, nullptr, 3); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "targetFunction", boundFunction->targetFunction())); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "boundThis", boundFunction->boundThis())); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "boundArgs", boundFunction->boundArgs())); + return array; + } + + if (JSArrayIterator* arrayIterator = jsDynamicCast<JSArrayIterator*>(value)) { + String kind; + switch (arrayIterator->kind(exec)) { + case ArrayIterateKey: + kind = ASCIILiteral("key"); + break; + case ArrayIterateValue: + kind = ASCIILiteral("value"); + break; + case ArrayIterateKeyValue: + kind = ASCIILiteral("key+value"); + break; + } + unsigned index = 0; + JSArray* array = constructEmptyArray(exec, nullptr, 2); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "array", arrayIterator->iteratedValue(exec))); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "kind", jsNontrivialString(exec, kind))); + return array; + } + + if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value)) { + String kind; + switch (mapIterator->kind()) { + case MapIterateKey: + kind = ASCIILiteral("key"); + break; + case MapIterateValue: + kind = ASCIILiteral("value"); + break; + case MapIterateKeyValue: + kind = ASCIILiteral("key+value"); + break; + } + unsigned index = 0; + JSArray* array = constructEmptyArray(exec, nullptr, 2); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "map", mapIterator->iteratedValue())); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "kind", jsNontrivialString(exec, kind))); + return array; + } + + if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value)) { + String kind; + switch (setIterator->kind()) { + case SetIterateKey: + kind = ASCIILiteral("key"); + break; + case SetIterateValue: + kind = ASCIILiteral("value"); + break; + case SetIterateKeyValue: + kind = ASCIILiteral("key+value"); + break; + } + unsigned index = 0; + JSArray* array = constructEmptyArray(exec, nullptr, 2); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "set", setIterator->iteratedValue())); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "kind", jsNontrivialString(exec, kind))); + return array; + } + + if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value)) { + unsigned index = 0; + JSArray* array = constructEmptyArray(exec, nullptr, 1); + array->putDirectIndex(exec, index++, constructInternalProperty(exec, "string", stringIterator->iteratedValue(exec))); + return array; + } + return jsUndefined(); } +JSValue JSInjectedScriptHost::weakMapSize(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue value = exec->uncheckedArgument(0); + JSWeakMap* weakMap = jsDynamicCast<JSWeakMap*>(value); + if (!weakMap) + return jsUndefined(); + + return jsNumber(weakMap->weakMapData()->size()); +} + +JSValue JSInjectedScriptHost::weakMapEntries(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue value = exec->uncheckedArgument(0); + JSWeakMap* weakMap = jsDynamicCast<JSWeakMap*>(value); + if (!weakMap) + return jsUndefined(); + + unsigned fetched = 0; + unsigned numberToFetch = 100; + + JSValue numberToFetchArg = exec->argument(1); + double fetchDouble = numberToFetchArg.toInteger(exec); + if (fetchDouble >= 0) + numberToFetch = static_cast<unsigned>(fetchDouble); + + JSArray* array = constructEmptyArray(exec, nullptr); + for (auto it = weakMap->weakMapData()->begin(); it != weakMap->weakMapData()->end(); ++it) { + JSObject* entry = constructEmptyObject(exec); + entry->putDirect(exec->vm(), Identifier::fromString(exec, "key"), it->key); + entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), it->value.get()); + array->putDirectIndex(exec, fetched++, entry); + if (numberToFetch && fetched >= numberToFetch) + break; + } + + return array; +} + +JSValue JSInjectedScriptHost::weakSetSize(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue value = exec->uncheckedArgument(0); + JSWeakSet* weakSet = jsDynamicCast<JSWeakSet*>(value); + if (!weakSet) + return jsUndefined(); + + return jsNumber(weakSet->weakMapData()->size()); +} + +JSValue JSInjectedScriptHost::weakSetEntries(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue value = exec->uncheckedArgument(0); + JSWeakSet* weakSet = jsDynamicCast<JSWeakSet*>(value); + if (!weakSet) + return jsUndefined(); + + unsigned fetched = 0; + unsigned numberToFetch = 100; + + JSValue numberToFetchArg = exec->argument(1); + double fetchDouble = numberToFetchArg.toInteger(exec); + if (fetchDouble >= 0) + numberToFetch = static_cast<unsigned>(fetchDouble); + + JSArray* array = constructEmptyArray(exec, nullptr); + for (auto it = weakSet->weakMapData()->begin(); it != weakSet->weakMapData()->end(); ++it) { + JSObject* entry = constructEmptyObject(exec); + entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), it->key); + array->putDirectIndex(exec, fetched++, entry); + if (numberToFetch && fetched >= numberToFetch) + break; + } + + return array; +} + +JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return jsUndefined(); + + JSValue iterator; + JSValue value = exec->uncheckedArgument(0); + if (JSArrayIterator* arrayIterator = jsDynamicCast<JSArrayIterator*>(value)) + iterator = arrayIterator->clone(exec); + else if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value)) + iterator = mapIterator->clone(exec); + else if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value)) + iterator = setIterator->clone(exec); + else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value)) + iterator = stringIterator->clone(exec); + else + return jsUndefined(); + + unsigned numberToFetch = 5; + JSValue numberToFetchArg = exec->argument(1); + double fetchDouble = numberToFetchArg.toInteger(exec); + if (fetchDouble >= 0) + numberToFetch = static_cast<unsigned>(fetchDouble); + + JSArray* array = constructEmptyArray(exec, nullptr); + + for (unsigned i = 0; i < numberToFetch; ++i) { + JSValue next = iteratorStep(exec, iterator); + if (exec->hadException()) + break; + if (next.isFalse()) + break; + + JSValue nextValue = iteratorValue(exec, next); + if (exec->hadException()) + break; + + JSObject* entry = constructEmptyObject(exec); + entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), nextValue); + array->putDirectIndex(exec, i, entry); + } + + iteratorClose(exec, iterator); + + return array; +} + JSValue toJS(ExecState* exec, JSGlobalObject* globalObject, InjectedScriptHost* impl) { if (!impl) @@ -201,5 +496,3 @@ JSInjectedScriptHost* toJSInjectedScriptHost(JSValue value) } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/JSInjectedScriptHost.h b/inspector/JSInjectedScriptHost.h index dc23568..8689151 100644 --- a/inspector/JSInjectedScriptHost.h +++ b/inspector/JSInjectedScriptHost.h @@ -26,10 +26,12 @@ #ifndef JSInjectedScriptHost_h #define JSInjectedScriptHost_h -#if ENABLE(INSPECTOR) - #include "JSDestructibleObject.h" +namespace JSC { +class WeakMapData; +} + namespace Inspector { class InjectedScriptHost; @@ -37,6 +39,7 @@ class InjectedScriptHost; class JSInjectedScriptHost : public JSC::JSDestructibleObject { public: typedef JSC::JSDestructibleObject Base; + static const unsigned StructureFlags = Base::StructureFlags; DECLARE_INFO; @@ -64,13 +67,16 @@ public: // Functions. JSC::JSValue internalConstructorName(JSC::ExecState*); JSC::JSValue isHTMLAllCollection(JSC::ExecState*); - JSC::JSValue type(JSC::ExecState*); + JSC::JSValue subtype(JSC::ExecState*); JSC::JSValue functionDetails(JSC::ExecState*); JSC::JSValue getInternalProperties(JSC::ExecState*); + JSC::JSValue weakMapSize(JSC::ExecState*); + JSC::JSValue weakMapEntries(JSC::ExecState*); + JSC::JSValue weakSetSize(JSC::ExecState*); + JSC::JSValue weakSetEntries(JSC::ExecState*); + JSC::JSValue iteratorEntries(JSC::ExecState*); protected: - static const unsigned StructureFlags = Base::StructureFlags; - void finishCreation(JSC::VM&); private: @@ -85,6 +91,4 @@ JSInjectedScriptHost* toJSInjectedScriptHost(JSC::JSValue); } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSInjectedScriptHost_h) diff --git a/inspector/JSInjectedScriptHostPrototype.cpp b/inspector/JSInjectedScriptHostPrototype.cpp index b07970a..b86a2e0 100644 --- a/inspector/JSInjectedScriptHostPrototype.cpp +++ b/inspector/JSInjectedScriptHostPrototype.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,8 +26,6 @@ #include "config.h" #include "JSInjectedScriptHostPrototype.h" -#if ENABLE(INSPECTOR) - #include "Error.h" #include "GetterSetter.h" #include "Identifier.h" @@ -40,15 +38,20 @@ using namespace JSC; namespace Inspector { -static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionType(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionSubtype(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionFunctionDetails(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionGetInternalProperties(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionInternalConstructorName(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapSize(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapEntries(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetSize(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetEntries(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntries(ExecState*); static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeAttributeEvaluate(ExecState*); -const ClassInfo JSInjectedScriptHostPrototype::s_info = { "InjectedScriptHost", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSInjectedScriptHostPrototype) }; +const ClassInfo JSInjectedScriptHostPrototype::s_info = { "InjectedScriptHost", &Base::s_info, 0, CREATE_METHOD_TABLE(JSInjectedScriptHostPrototype) }; void JSInjectedScriptHostPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { @@ -56,16 +59,21 @@ void JSInjectedScriptHostPrototype::finishCreation(VM& vm, JSGlobalObject* globa ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); - JSC_NATIVE_FUNCTION("type", jsInjectedScriptHostPrototypeFunctionType, DontEnum, 1); + JSC_NATIVE_FUNCTION("subtype", jsInjectedScriptHostPrototypeFunctionSubtype, DontEnum, 1); JSC_NATIVE_FUNCTION("functionDetails", jsInjectedScriptHostPrototypeFunctionFunctionDetails, DontEnum, 1); JSC_NATIVE_FUNCTION("getInternalProperties", jsInjectedScriptHostPrototypeFunctionGetInternalProperties, DontEnum, 1); JSC_NATIVE_FUNCTION("internalConstructorName", jsInjectedScriptHostPrototypeFunctionInternalConstructorName, DontEnum, 1); JSC_NATIVE_FUNCTION("isHTMLAllCollection", jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection, DontEnum, 1); - - Identifier evaluateIdentifier(&vm, "evaluate"); - GetterSetter* accessor = GetterSetter::create(vm); + JSC_NATIVE_FUNCTION("weakMapSize", jsInjectedScriptHostPrototypeFunctionWeakMapSize, DontEnum, 1); + JSC_NATIVE_FUNCTION("weakMapEntries", jsInjectedScriptHostPrototypeFunctionWeakMapEntries, DontEnum, 1); + JSC_NATIVE_FUNCTION("weakSetSize", jsInjectedScriptHostPrototypeFunctionWeakSetSize, DontEnum, 1); + JSC_NATIVE_FUNCTION("weakSetEntries", jsInjectedScriptHostPrototypeFunctionWeakSetEntries, DontEnum, 1); + JSC_NATIVE_FUNCTION("iteratorEntries", jsInjectedScriptHostPrototypeFunctionIteratorEntries, DontEnum, 1); + + Identifier evaluateIdentifier = Identifier::fromString(&vm, "evaluate"); + GetterSetter* accessor = GetterSetter::create(vm, globalObject); JSFunction* function = JSFunction::create(vm, globalObject, 0, evaluateIdentifier.string(), jsInjectedScriptHostPrototypeAttributeEvaluate); - accessor->setGetter(vm, function); + accessor->setGetter(vm, globalObject, function); putDirectNonIndexAccessor(vm, evaluateIdentifier, accessor, DontEnum | Accessor); } @@ -102,7 +110,62 @@ EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIsHTMLAllColle return JSValue::encode(castedThis->isHTMLAllCollection(exec)); } -EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionType(ExecState* exec) +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapSize(ExecState* exec) +{ + JSValue thisValue = exec->thisValue(); + JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue); + if (!castedThis) + return throwVMTypeError(exec); + + ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); + return JSValue::encode(castedThis->weakMapSize(exec)); +} + +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapEntries(ExecState* exec) +{ + JSValue thisValue = exec->thisValue(); + JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue); + if (!castedThis) + return throwVMTypeError(exec); + + ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); + return JSValue::encode(castedThis->weakMapEntries(exec)); +} + +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetSize(ExecState* exec) +{ + JSValue thisValue = exec->thisValue(); + JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue); + if (!castedThis) + return throwVMTypeError(exec); + + ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); + return JSValue::encode(castedThis->weakSetSize(exec)); +} + +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetEntries(ExecState* exec) +{ + JSValue thisValue = exec->thisValue(); + JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue); + if (!castedThis) + return throwVMTypeError(exec); + + ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); + return JSValue::encode(castedThis->weakSetEntries(exec)); +} + +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntries(ExecState* exec) +{ + JSValue thisValue = exec->thisValue(); + JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue); + if (!castedThis) + return throwVMTypeError(exec); + + ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); + return JSValue::encode(castedThis->iteratorEntries(exec)); +} + +EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionSubtype(ExecState* exec) { JSValue thisValue = exec->thisValue(); JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue); @@ -110,7 +173,7 @@ EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionType(ExecState return throwVMTypeError(exec); ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info()); - return JSValue::encode(castedThis->type(exec)); + return JSValue::encode(castedThis->subtype(exec)); } EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionFunctionDetails(ExecState* exec) @@ -137,4 +200,3 @@ EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionGetInternalPro } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/JSInjectedScriptHostPrototype.h b/inspector/JSInjectedScriptHostPrototype.h index 9d0b7b6..aa4963e 100644 --- a/inspector/JSInjectedScriptHostPrototype.h +++ b/inspector/JSInjectedScriptHostPrototype.h @@ -26,8 +26,6 @@ #ifndef JSInjectedScriptHostPrototype_h #define JSInjectedScriptHostPrototype_h -#if ENABLE(INSPECTOR) - #include "JSObject.h" namespace Inspector { @@ -35,6 +33,7 @@ namespace Inspector { class JSInjectedScriptHostPrototype : public JSC::JSNonFinalObject { public: typedef JSC::JSNonFinalObject Base; + static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot; DECLARE_INFO; @@ -50,9 +49,6 @@ public: return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); } -protected: - static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | Base::StructureFlags; - private: JSInjectedScriptHostPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(vm, structure) @@ -63,6 +59,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSInjectedScriptHostPrototype_h) diff --git a/inspector/JSJavaScriptCallFrame.cpp b/inspector/JSJavaScriptCallFrame.cpp index 08fd618..cb1f9d1 100644 --- a/inspector/JSJavaScriptCallFrame.cpp +++ b/inspector/JSJavaScriptCallFrame.cpp @@ -26,8 +26,7 @@ #include "config.h" #include "JSJavaScriptCallFrame.h" -#if ENABLE(INSPECTOR) - +#include "DebuggerScope.h" #include "Error.h" #include "JSCJSValue.h" #include "JSCellInlines.h" @@ -38,7 +37,7 @@ using namespace JSC; namespace Inspector { -const ClassInfo JSJavaScriptCallFrame::s_info = { "JavaScriptCallFrame", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSJavaScriptCallFrame) }; +const ClassInfo JSJavaScriptCallFrame::s_info = { "JavaScriptCallFrame", &Base::s_info, 0, CREATE_METHOD_TABLE(JSJavaScriptCallFrame) }; JSJavaScriptCallFrame::JSJavaScriptCallFrame(VM& vm, Structure* structure, PassRefPtr<JavaScriptCallFrame> impl) : JSDestructibleObject(vm, structure) @@ -65,10 +64,8 @@ void JSJavaScriptCallFrame::destroy(JSC::JSCell* cell) void JSJavaScriptCallFrame::releaseImpl() { - if (m_impl) { - m_impl->deref(); - m_impl = nullptr; - } + if (auto impl = std::exchange(m_impl, nullptr)) + impl->deref(); } JSJavaScriptCallFrame::~JSJavaScriptCallFrame() @@ -78,7 +75,7 @@ JSJavaScriptCallFrame::~JSJavaScriptCallFrame() JSValue JSJavaScriptCallFrame::evaluate(ExecState* exec) { - JSValue exception; + NakedPtr<Exception> exception; JSValue result = impl().evaluate(exec->argument(0).toString(exec)->value(exec), exception); if (exception) exec->vm().throwException(exec, exception); @@ -95,29 +92,33 @@ JSValue JSJavaScriptCallFrame::scopeType(ExecState* exec) return jsUndefined(); int index = exec->argument(0).asInt32(); - JSScope* scopeChain = impl().scopeChain(); - ScopeChainIterator end = scopeChain->end(); - - // FIXME: We should be identifying and returning CATCH_SCOPE appropriately. + DebuggerScope* scopeChain = impl().scopeChain(); + DebuggerScope::iterator end = scopeChain->end(); bool foundLocalScope = false; - for (ScopeChainIterator iter = scopeChain->begin(); iter != end; ++iter) { - JSObject* scope = iter.get(); - if (scope->isActivationObject()) { - if (!foundLocalScope) { - // First activation object is local scope, each successive activation object is closure. - if (!index) - return jsNumber(JSJavaScriptCallFrame::LOCAL_SCOPE); - foundLocalScope = true; - } else if (!index) - return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE); + for (DebuggerScope::iterator iter = scopeChain->begin(); iter != end; ++iter) { + DebuggerScope* scope = iter.get(); + + if (!foundLocalScope && scope->isFunctionOrEvalScope()) { + // First function scope is the local scope, each successive one is a closure. + if (!index) + return jsNumber(JSJavaScriptCallFrame::LOCAL_SCOPE); + foundLocalScope = true; } if (!index) { - // Last in the chain is global scope. - if (++iter == end) + if (scope->isCatchScope()) + return jsNumber(JSJavaScriptCallFrame::CATCH_SCOPE); + if (scope->isFunctionNameScope()) + return jsNumber(JSJavaScriptCallFrame::FUNCTION_NAME_SCOPE); + if (scope->isWithScope()) + return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE); + if (scope->isGlobalScope()) { + ASSERT(++iter == end); return jsNumber(JSJavaScriptCallFrame::GLOBAL_SCOPE); - return jsNumber(JSJavaScriptCallFrame::WITH_SCOPE); + } + ASSERT(scope->isFunctionOrEvalScope()); + return jsNumber(JSJavaScriptCallFrame::CLOSURE_SCOPE); } --index; @@ -157,9 +158,9 @@ JSValue JSJavaScriptCallFrame::scopeChain(ExecState* exec) const if (!impl().scopeChain()) return jsNull(); - JSScope* scopeChain = impl().scopeChain(); - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); + DebuggerScope* scopeChain = impl().scopeChain(); + DebuggerScope::iterator iter = scopeChain->begin(); + DebuggerScope::iterator end = scopeChain->end(); // We must always have something in the scope chain. ASSERT(iter != end); @@ -210,4 +211,3 @@ JSJavaScriptCallFrame* toJSJavaScriptCallFrame(JSValue value) } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/JSJavaScriptCallFrame.h b/inspector/JSJavaScriptCallFrame.h index dbbb93f..b77c06e 100644 --- a/inspector/JSJavaScriptCallFrame.h +++ b/inspector/JSJavaScriptCallFrame.h @@ -26,8 +26,6 @@ #ifndef JSJavaScriptCallFrame_h #define JSJavaScriptCallFrame_h -#if ENABLE(INSPECTOR) - #include "JSDestructibleObject.h" #include "JavaScriptCallFrame.h" @@ -36,6 +34,7 @@ namespace Inspector { class JSJavaScriptCallFrame : public JSC::JSDestructibleObject { public: typedef JSC::JSDestructibleObject Base; + static const unsigned StructureFlags = Base::StructureFlags; DECLARE_INFO; @@ -77,10 +76,9 @@ public: static const unsigned short WITH_SCOPE = 2; static const unsigned short CLOSURE_SCOPE = 3; static const unsigned short CATCH_SCOPE = 4; + static const unsigned short FUNCTION_NAME_SCOPE = 5; protected: - static const unsigned StructureFlags = Base::StructureFlags; - void finishCreation(JSC::VM&); private: @@ -95,6 +93,4 @@ JSJavaScriptCallFrame* toJSJavaScriptCallFrame(JSC::JSValue); } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSJavaScriptCallFrame_h) diff --git a/inspector/JSJavaScriptCallFramePrototype.cpp b/inspector/JSJavaScriptCallFramePrototype.cpp index f7fc21e..4828386 100644 --- a/inspector/JSJavaScriptCallFramePrototype.cpp +++ b/inspector/JSJavaScriptCallFramePrototype.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "JSJavaScriptCallFramePrototype.h" -#if ENABLE(INSPECTOR) - #include "Error.h" #include "GetterSetter.h" #include "Identifier.h" @@ -59,15 +57,16 @@ static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantLOCAL_SCOPE(Exe static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantWITH_SCOPE(ExecState*); static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantCLOSURE_SCOPE(ExecState*); static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantCATCH_SCOPE(ExecState*); +static EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantFUNCTION_NAME_SCOPE(ExecState*); -const ClassInfo JSJavaScriptCallFramePrototype::s_info = { "JavaScriptCallFrame", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSJavaScriptCallFramePrototype) }; +const ClassInfo JSJavaScriptCallFramePrototype::s_info = { "JavaScriptCallFrame", &Base::s_info, 0, CREATE_METHOD_TABLE(JSJavaScriptCallFramePrototype) }; #define JSC_NATIVE_NON_INDEX_ACCESSOR(jsName, cppName, attributes) \ { \ - Identifier identifier(&vm, jsName); \ - GetterSetter* accessor = GetterSetter::create(vm); \ + Identifier identifier = Identifier::fromString(&vm, jsName); \ + GetterSetter* accessor = GetterSetter::create(vm, globalObject); \ JSFunction* function = JSFunction::create(vm, globalObject, 0, identifier.string(), cppName); \ - accessor->setGetter(vm, function); \ + accessor->setGetter(vm, globalObject, function); \ putDirectNonIndexAccessor(vm, identifier, accessor, (attributes)); \ } @@ -94,6 +93,7 @@ void JSJavaScriptCallFramePrototype::finishCreation(VM& vm, JSGlobalObject* glob JSC_NATIVE_NON_INDEX_ACCESSOR("WITH_SCOPE", jsJavaScriptCallFrameConstantWITH_SCOPE, DontEnum | Accessor); JSC_NATIVE_NON_INDEX_ACCESSOR("CLOSURE_SCOPE", jsJavaScriptCallFrameConstantCLOSURE_SCOPE, DontEnum | Accessor); JSC_NATIVE_NON_INDEX_ACCESSOR("CATCH_SCOPE", jsJavaScriptCallFrameConstantCATCH_SCOPE, DontEnum | Accessor); + JSC_NATIVE_NON_INDEX_ACCESSOR("FUNCTION_NAME_SCOPE", jsJavaScriptCallFrameConstantFUNCTION_NAME_SCOPE, DontEnum | Accessor); } EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFramePrototypeFunctionEvaluate(ExecState* exec) @@ -231,6 +231,9 @@ EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantCATCH_SCOPE(ExecState* return JSValue::encode(jsNumber(JSJavaScriptCallFrame::CATCH_SCOPE)); } -} // namespace Inspector +EncodedJSValue JSC_HOST_CALL jsJavaScriptCallFrameConstantFUNCTION_NAME_SCOPE(ExecState*) +{ + return JSValue::encode(jsNumber(JSJavaScriptCallFrame::FUNCTION_NAME_SCOPE)); +} -#endif // ENABLE(INSPECTOR) +} // namespace Inspector diff --git a/inspector/JSJavaScriptCallFramePrototype.h b/inspector/JSJavaScriptCallFramePrototype.h index b868c53..0811c24 100644 --- a/inspector/JSJavaScriptCallFramePrototype.h +++ b/inspector/JSJavaScriptCallFramePrototype.h @@ -26,8 +26,6 @@ #ifndef JSJavaScriptCallFramePrototype_h #define JSJavaScriptCallFramePrototype_h -#if ENABLE(INSPECTOR) - #include "JSObject.h" namespace Inspector { @@ -35,6 +33,7 @@ namespace Inspector { class JSJavaScriptCallFramePrototype : public JSC::JSNonFinalObject { public: typedef JSC::JSNonFinalObject Base; + static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot; DECLARE_INFO; @@ -50,9 +49,6 @@ public: return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); } -protected: - static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | Base::StructureFlags; - private: JSJavaScriptCallFramePrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(vm, structure) @@ -63,6 +59,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSJavaScriptCallFramePrototype_h) diff --git a/inspector/JavaScriptCallFrame.cpp b/inspector/JavaScriptCallFrame.cpp index f735a8a..d5f73d5 100644 --- a/inspector/JavaScriptCallFrame.cpp +++ b/inspector/JavaScriptCallFrame.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "JavaScriptCallFrame.h" -#if ENABLE(INSPECTOR) - using namespace JSC; namespace Inspector { @@ -52,4 +50,3 @@ JavaScriptCallFrame* JavaScriptCallFrame::caller() } // namespace Inspector -#endif // ENABLE(INSPECTOR) diff --git a/inspector/JavaScriptCallFrame.h b/inspector/JavaScriptCallFrame.h index b584067..c7d037b 100644 --- a/inspector/JavaScriptCallFrame.h +++ b/inspector/JavaScriptCallFrame.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2013-2014 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,8 +26,6 @@ #ifndef JavaScriptCallFrame_h #define JavaScriptCallFrame_h -#if ENABLE(INSPECTOR) - #include "JSCJSValueInlines.h" #include "debugger/DebuggerCallFrame.h" #include "interpreter/CallFrame.h" @@ -40,9 +38,9 @@ namespace Inspector { class JavaScriptCallFrame : public RefCounted<JavaScriptCallFrame> { public: - static PassRefPtr<JavaScriptCallFrame> create(PassRefPtr<JSC::DebuggerCallFrame> debuggerCallFrame) + static Ref<JavaScriptCallFrame> create(PassRefPtr<JSC::DebuggerCallFrame> debuggerCallFrame) { - return adoptRef(new JavaScriptCallFrame(debuggerCallFrame)); + return adoptRef(*new JavaScriptCallFrame(debuggerCallFrame)); } JavaScriptCallFrame* caller(); @@ -53,11 +51,11 @@ public: String functionName() const { return m_debuggerCallFrame->functionName(); } JSC::DebuggerCallFrame::Type type() const { return m_debuggerCallFrame->type(); } - JSC::JSScope* scopeChain() const { return m_debuggerCallFrame->scope(); } + JSC::DebuggerScope* scopeChain() const { return m_debuggerCallFrame->scope(); } JSC::JSGlobalObject* vmEntryGlobalObject() const { return m_debuggerCallFrame->vmEntryGlobalObject(); } JSC::JSValue thisValue() const { return m_debuggerCallFrame->thisValue(); } - JSC::JSValue evaluate(const String& script, JSC::JSValue& exception) const { return m_debuggerCallFrame->evaluate(script, exception); } + JSC::JSValue evaluate(const String& script, NakedPtr<JSC::Exception>& exception) const { return m_debuggerCallFrame->evaluate(script, exception); } private: JavaScriptCallFrame(PassRefPtr<JSC::DebuggerCallFrame>); @@ -68,6 +66,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // JavaScriptCallFrame_h diff --git a/inspector/ScriptArguments.cpp b/inspector/ScriptArguments.cpp index 4100a3f..51d1fe6 100644 --- a/inspector/ScriptArguments.cpp +++ b/inspector/ScriptArguments.cpp @@ -37,9 +37,9 @@ namespace Inspector { -PassRefPtr<ScriptArguments> ScriptArguments::create(JSC::ExecState* scriptState, Vector<Deprecated::ScriptValue>& arguments) +Ref<ScriptArguments> ScriptArguments::create(JSC::ExecState* scriptState, Vector<Deprecated::ScriptValue>& arguments) { - return adoptRef(new ScriptArguments(scriptState, arguments)); + return adoptRef(*new ScriptArguments(scriptState, arguments)); } ScriptArguments::ScriptArguments(JSC::ExecState* execState, Vector<Deprecated::ScriptValue>& arguments) diff --git a/inspector/ScriptArguments.h b/inspector/ScriptArguments.h index 5337e01..7200ab4 100644 --- a/inspector/ScriptArguments.h +++ b/inspector/ScriptArguments.h @@ -51,7 +51,7 @@ namespace Inspector { class JS_EXPORT_PRIVATE ScriptArguments : public RefCounted<ScriptArguments> { public: - static PassRefPtr<ScriptArguments> create(JSC::ExecState*, Vector<Deprecated::ScriptValue>& arguments); + static Ref<ScriptArguments> create(JSC::ExecState*, Vector<Deprecated::ScriptValue>& arguments); ~ScriptArguments(); const Deprecated::ScriptValue& argumentAt(size_t) const; diff --git a/inspector/ScriptCallFrame.cpp b/inspector/ScriptCallFrame.cpp index c7a822e..96a06ff 100644 --- a/inspector/ScriptCallFrame.cpp +++ b/inspector/ScriptCallFrame.cpp @@ -33,7 +33,6 @@ #include "ScriptCallFrame.h" #include "InspectorValues.h" -#include <wtf/PassRefPtr.h> namespace Inspector { @@ -57,16 +56,14 @@ bool ScriptCallFrame::isEqual(const ScriptCallFrame& o) const && m_column == o.m_column; } -#if ENABLE(INSPECTOR) -PassRefPtr<Inspector::TypeBuilder::Console::CallFrame> ScriptCallFrame::buildInspectorObject() const +Ref<Inspector::Protocol::Console::CallFrame> ScriptCallFrame::buildInspectorObject() const { - return Inspector::TypeBuilder::Console::CallFrame::create() + return Inspector::Protocol::Console::CallFrame::create() .setFunctionName(m_functionName) .setUrl(m_scriptName) .setLineNumber(m_lineNumber) .setColumnNumber(m_column) .release(); } -#endif } // namespace Inspector diff --git a/inspector/ScriptCallFrame.h b/inspector/ScriptCallFrame.h index 00524dc..99ac489 100644 --- a/inspector/ScriptCallFrame.h +++ b/inspector/ScriptCallFrame.h @@ -34,10 +34,7 @@ #include <wtf/Forward.h> #include <wtf/text/WTFString.h> - -#if ENABLE(INSPECTOR) -#include "InspectorJSTypeBuilders.h" -#endif +#include "InspectorProtocolObjects.h" namespace Inspector { @@ -53,9 +50,7 @@ public: bool isEqual(const ScriptCallFrame&) const; -#if ENABLE(INSPECTOR) - PassRefPtr<Inspector::TypeBuilder::Console::CallFrame> buildInspectorObject() const; -#endif + Ref<Inspector::Protocol::Console::CallFrame> buildInspectorObject() const; private: String m_functionName; diff --git a/inspector/ScriptCallStack.cpp b/inspector/ScriptCallStack.cpp index 9b3cca1..49b0719 100644 --- a/inspector/ScriptCallStack.cpp +++ b/inspector/ScriptCallStack.cpp @@ -36,14 +36,14 @@ namespace Inspector { -PassRefPtr<ScriptCallStack> ScriptCallStack::create() +Ref<ScriptCallStack> ScriptCallStack::create() { - return adoptRef(new ScriptCallStack); + return adoptRef(*new ScriptCallStack); } -PassRefPtr<ScriptCallStack> ScriptCallStack::create(Vector<ScriptCallFrame>& frames) +Ref<ScriptCallStack> ScriptCallStack::create(Vector<ScriptCallFrame>& frames) { - return adoptRef(new ScriptCallStack(frames)); + return adoptRef(*new ScriptCallStack(frames)); } ScriptCallStack::ScriptCallStack() @@ -106,14 +106,12 @@ bool ScriptCallStack::isEqual(ScriptCallStack* o) const return true; } -#if ENABLE(INSPECTOR) -PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Console::CallFrame>> ScriptCallStack::buildInspectorArray() const +Ref<Inspector::Protocol::Console::StackTrace> ScriptCallStack::buildInspectorArray() const { - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Console::CallFrame>> frames = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Console::CallFrame>::create(); + auto frames = Inspector::Protocol::Console::StackTrace::create(); for (size_t i = 0; i < m_frames.size(); i++) frames->addItem(m_frames.at(i).buildInspectorObject()); - return frames; + return WTF::move(frames); } -#endif } // namespace Inspector diff --git a/inspector/ScriptCallStack.h b/inspector/ScriptCallStack.h index 9c2a534..d2cbb65 100644 --- a/inspector/ScriptCallStack.h +++ b/inspector/ScriptCallStack.h @@ -32,23 +32,20 @@ #ifndef ScriptCallStack_h #define ScriptCallStack_h +#include "InspectorProtocolObjects.h" #include "ScriptCallFrame.h" #include <wtf/Forward.h> #include <wtf/RefCounted.h> #include <wtf/Vector.h> -#if ENABLE(INSPECTOR) -#include "InspectorJSTypeBuilders.h" -#endif - namespace Inspector { class JS_EXPORT_PRIVATE ScriptCallStack : public RefCounted<ScriptCallStack> { public: static const size_t maxCallStackSizeToCapture = 200; - static PassRefPtr<ScriptCallStack> create(); - static PassRefPtr<ScriptCallStack> create(Vector<ScriptCallFrame>&); + static Ref<ScriptCallStack> create(); + static Ref<ScriptCallStack> create(Vector<ScriptCallFrame>&); ~ScriptCallStack(); @@ -61,9 +58,7 @@ public: bool isEqual(ScriptCallStack*) const; -#if ENABLE(INSPECTOR) - PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Console::CallFrame>> buildInspectorArray() const; -#endif + Ref<Inspector::Protocol::Console::StackTrace> buildInspectorArray() const; private: ScriptCallStack(); diff --git a/inspector/ScriptCallStackFactory.cpp b/inspector/ScriptCallStackFactory.cpp index 2f06279..f33d405 100644 --- a/inspector/ScriptCallStackFactory.cpp +++ b/inspector/ScriptCallStackFactory.cpp @@ -34,6 +34,7 @@ #include "ScriptCallStackFactory.h" #include "CallFrame.h" +#include "Exception.h" #include "JSCJSValue.h" #include "JSCInlines.h" #include "ScriptArguments.h" @@ -83,7 +84,7 @@ private: size_t m_remainingCapacityForFrameCapture; }; -PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize) +Ref<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize) { if (!exec) return ScriptCallStack::create(); @@ -97,7 +98,7 @@ PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t m return ScriptCallStack::create(frames); } -PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState* exec, size_t maxStackSize) +Ref<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState* exec, size_t maxStackSize) { if (!exec) return ScriptCallStack::create(); @@ -119,19 +120,19 @@ PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState* exec static void extractSourceInformationFromException(JSC::ExecState* exec, JSObject* exceptionObject, int* lineNumber, int* columnNumber, String* sourceURL) { // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not need to evaluate JavaScript handling exceptions - JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line")); + JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier::fromString(exec, "line")); *lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0; - JSValue columnValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "column")); + JSValue columnValue = exceptionObject->getDirect(exec->vm(), Identifier::fromString(exec, "column")); *columnNumber = columnValue && columnValue.isNumber() ? int(columnValue.toNumber(exec)) : 0; - JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL")); - *sourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : String("undefined"); + JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier::fromString(exec, "sourceURL")); + *sourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined"); exec->clearException(); } -PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::JSValue& exception, size_t maxStackSize) +Ref<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::Exception* exception, size_t maxStackSize) { Vector<ScriptCallFrame> frames; - RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack(); + RefCountedArray<StackFrame> stackTrace = exception->stack(); for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) { unsigned line; unsigned column; @@ -141,8 +142,8 @@ PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* e } // Fallback to getting at least the line and sourceURL from the exception object if it has values and the exceptionStack doesn't. - JSObject* exceptionObject = exception.toObject(exec); - if (exception.isObject()) { + if (exception->value().isObject()) { + JSObject* exceptionObject = exception->value().toObject(exec); int lineNumber; int columnNumber; String exceptionSourceURL; @@ -161,7 +162,7 @@ PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* e return ScriptCallStack::create(frames); } -PassRefPtr<ScriptArguments> createScriptArguments(JSC::ExecState* exec, unsigned skipArgumentCount) +Ref<ScriptArguments> createScriptArguments(JSC::ExecState* exec, unsigned skipArgumentCount) { Vector<Deprecated::ScriptValue> arguments; size_t argumentCount = exec->argumentCount(); diff --git a/inspector/ScriptCallStackFactory.h b/inspector/ScriptCallStackFactory.h index 07c1586..b0c0dc0 100644 --- a/inspector/ScriptCallStackFactory.h +++ b/inspector/ScriptCallStackFactory.h @@ -35,6 +35,7 @@ #include <wtf/Forward.h> namespace JSC { +class Exception; class ExecState; class JSValue; } @@ -45,10 +46,10 @@ class ScriptArguments; class ScriptCallStack; // FIXME: The subtle differences between these should be eliminated. -JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState*, size_t maxStackSize); -JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState*, size_t maxStackSize); -JS_EXPORT_PRIVATE PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState*, JSC::JSValue& exception, size_t maxStackSize); -JS_EXPORT_PRIVATE PassRefPtr<ScriptArguments> createScriptArguments(JSC::ExecState*, unsigned skipArgumentCount); +JS_EXPORT_PRIVATE Ref<ScriptCallStack> createScriptCallStack(JSC::ExecState*, size_t maxStackSize); +JS_EXPORT_PRIVATE Ref<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState*, size_t maxStackSize); +JS_EXPORT_PRIVATE Ref<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState*, JSC::Exception*, size_t maxStackSize); +JS_EXPORT_PRIVATE Ref<ScriptArguments> createScriptArguments(JSC::ExecState*, unsigned skipArgumentCount); } // namespace Inspector diff --git a/inspector/ScriptDebugListener.h b/inspector/ScriptDebugListener.h index 3bdbcd8..dfd9e0a 100644 --- a/inspector/ScriptDebugListener.h +++ b/inspector/ScriptDebugListener.h @@ -75,7 +75,7 @@ public: virtual void breakpointActionLog(JSC::ExecState*, const String&) = 0; virtual void breakpointActionSound(int breakpointActionIdentifier) = 0; - virtual void breakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&, int hitCount, const Deprecated::ScriptValue& result) = 0; + virtual void breakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, const Deprecated::ScriptValue& result) = 0; }; } // namespace Inspector diff --git a/inspector/ScriptDebugServer.cpp b/inspector/ScriptDebugServer.cpp index d279893..74602c5 100644 --- a/inspector/ScriptDebugServer.cpp +++ b/inspector/ScriptDebugServer.cpp @@ -31,9 +31,9 @@ #include "config.h" #include "ScriptDebugServer.h" -#if ENABLE(INSPECTOR) - #include "DebuggerCallFrame.h" +#include "DebuggerScope.h" +#include "Exception.h" #include "JSJavaScriptCallFrame.h" #include "JSLock.h" #include "JavaScriptCallFrame.h" @@ -49,8 +49,6 @@ namespace Inspector { ScriptDebugServer::ScriptDebugServer(bool isInWorkerThread) : Debugger(isInWorkerThread) - , m_doneProcessingDebuggerEvents(true) - , m_callingListeners(false) { } @@ -96,7 +94,7 @@ bool ScriptDebugServer::evaluateBreakpointAction(const ScriptBreakpointAction& b break; } case ScriptBreakpointActionTypeEvaluate: { - JSValue exception; + NakedPtr<Exception> exception; debuggerCallFrame->evaluate(breakpointAction.data, exception); if (exception) reportException(debuggerCallFrame->exec(), exception); @@ -106,13 +104,13 @@ bool ScriptDebugServer::evaluateBreakpointAction(const ScriptBreakpointAction& b dispatchBreakpointActionSound(debuggerCallFrame->exec(), breakpointAction.identifier); break; case ScriptBreakpointActionTypeProbe: { - JSValue exception; + NakedPtr<Exception> exception; JSValue result = debuggerCallFrame->evaluate(breakpointAction.data, exception); if (exception) reportException(debuggerCallFrame->exec(), exception); JSC::ExecState* state = debuggerCallFrame->scope()->globalObject()->globalExec(); - Deprecated::ScriptValue wrappedResult = Deprecated::ScriptValue(state->vm(), exception ? exception : result); + Deprecated::ScriptValue wrappedResult = Deprecated::ScriptValue(state->vm(), exception ? exception->value() : result); dispatchBreakpointActionProbe(state, breakpointAction, wrappedResult); break; } @@ -137,7 +135,8 @@ void ScriptDebugServer::dispatchDidPause(ScriptDebugListener* listener) JSC::ExecState* state = globalObject->globalExec(); RefPtr<JavaScriptCallFrame> javaScriptCallFrame = JavaScriptCallFrame::create(debuggerCallFrame); JSValue jsCallFrame = toJS(state, globalObject, javaScriptCallFrame.get()); - listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), Deprecated::ScriptValue()); + + listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), exceptionOrCaughtValue(state)); } void ScriptDebugServer::dispatchBreakpointActionLog(ExecState* exec, const String& message) @@ -145,53 +144,52 @@ void ScriptDebugServer::dispatchBreakpointActionLog(ExecState* exec, const Strin if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + ListenerSet& listeners = getListeners(); + if (listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); TemporaryChange<bool> change(m_callingListeners, true); Vector<ScriptDebugListener*> listenersCopy; - copyToVector(*listeners, listenersCopy); + copyToVector(listeners, listenersCopy); for (auto* listener : listenersCopy) listener->breakpointActionLog(exec, message); } -void ScriptDebugServer::dispatchBreakpointActionSound(ExecState* exec, int breakpointActionIdentifier) +void ScriptDebugServer::dispatchBreakpointActionSound(ExecState*, int breakpointActionIdentifier) { if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + ListenerSet& listeners = getListeners(); + if (listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); TemporaryChange<bool> change(m_callingListeners, true); Vector<ScriptDebugListener*> listenersCopy; - copyToVector(*listeners, listenersCopy); + copyToVector(listeners, listenersCopy); for (auto* listener : listenersCopy) listener->breakpointActionSound(breakpointActionIdentifier); } -void ScriptDebugServer::dispatchBreakpointActionProbe(ExecState* exec, const ScriptBreakpointAction& action, const Deprecated::ScriptValue& sample) +void ScriptDebugServer::dispatchBreakpointActionProbe(ExecState* exec, const ScriptBreakpointAction& action, const Deprecated::ScriptValue& sampleValue) { if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + ListenerSet& listeners = getListeners(); + if (listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); TemporaryChange<bool> change(m_callingListeners, true); + unsigned sampleId = m_nextProbeSampleId++; + Vector<ScriptDebugListener*> listenersCopy; - copyToVector(*listeners, listenersCopy); + copyToVector(listeners, listenersCopy); for (auto* listener : listenersCopy) - listener->breakpointActionProbe(exec, action, m_hitCount, sample); + listener->breakpointActionProbe(exec, action, m_currentProbeBatchId, sampleId, sampleValue); } void ScriptDebugServer::dispatchDidContinue(ScriptDebugListener* listener) @@ -249,79 +247,77 @@ void ScriptDebugServer::sourceParsed(ExecState* exec, SourceProvider* sourceProv if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + ListenerSet& listeners = getListeners(); + if (listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); TemporaryChange<bool> change(m_callingListeners, true); bool isError = errorLine != -1; if (isError) - dispatchFailedToParseSource(*listeners, sourceProvider, errorLine, errorMessage); + dispatchFailedToParseSource(listeners, sourceProvider, errorLine, errorMessage); else - dispatchDidParseSource(*listeners, sourceProvider, isContentScript(exec)); + dispatchDidParseSource(listeners, sourceProvider, isContentScript(exec)); } -void ScriptDebugServer::dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback callback) -{ - Vector<ScriptDebugListener*> copy; - copyToVector(listeners, copy); - for (size_t i = 0; i < copy.size(); ++i) - (this->*callback)(copy[i]); -} - -void ScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, JSGlobalObject* globalObject) +void ScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback) { if (m_callingListeners) return; TemporaryChange<bool> change(m_callingListeners, true); - if (ListenerSet* listeners = getListenersForGlobalObject(globalObject)) { - if (!listeners->isEmpty()) - dispatchFunctionToListeners(*listeners, callback); - } + ListenerSet& listeners = getListeners(); + if (!listeners.isEmpty()) + dispatchFunctionToListeners(listeners, callback); } -void ScriptDebugServer::notifyDoneProcessingDebuggerEvents() +void ScriptDebugServer::dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback callback) { - m_doneProcessingDebuggerEvents = true; + Vector<ScriptDebugListener*> copy; + copyToVector(listeners, copy); + for (size_t i = 0; i < copy.size(); ++i) + (this->*callback)(copy[i]); } -bool ScriptDebugServer::needPauseHandling(JSGlobalObject* globalObject) +void ScriptDebugServer::notifyDoneProcessingDebuggerEvents() { - return !!getListenersForGlobalObject(globalObject); + m_doneProcessingDebuggerEvents = true; } -void ScriptDebugServer::handleBreakpointHit(const JSC::Breakpoint& breakpoint) +void ScriptDebugServer::handleBreakpointHit(JSC::JSGlobalObject* globalObject, const JSC::Breakpoint& breakpoint) { - m_hitCount++; + ASSERT(isAttached(globalObject)); + + m_currentProbeBatchId++; + BreakpointIDToActionsMap::iterator it = m_breakpointIDToActions.find(breakpoint.id); if (it != m_breakpointIDToActions.end()) { - BreakpointActions& actions = it->value; + BreakpointActions actions = it->value; for (size_t i = 0; i < actions.size(); ++i) { if (!evaluateBreakpointAction(actions[i])) return; + if (!isAttached(globalObject)) + return; } } } -void ScriptDebugServer::handleExceptionInBreakpointCondition(JSC::ExecState* exec, JSC::JSValue exception) const +void ScriptDebugServer::handleExceptionInBreakpointCondition(JSC::ExecState* exec, JSC::Exception* exception) const { reportException(exec, exception); } -void ScriptDebugServer::handlePause(Debugger::ReasonForPause, JSGlobalObject* vmEntryGlobalObject) +void ScriptDebugServer::handlePause(JSGlobalObject* vmEntryGlobalObject, Debugger::ReasonForPause) { - dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause, vmEntryGlobalObject); + dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause); didPause(vmEntryGlobalObject); m_doneProcessingDebuggerEvents = false; runEventLoopWhilePaused(); didContinue(vmEntryGlobalObject); - dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue, vmEntryGlobalObject); + dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue); } const BreakpointActions& ScriptDebugServer::getActionsForBreakpoint(JSC::BreakpointID breakpointID) @@ -335,6 +331,20 @@ const BreakpointActions& ScriptDebugServer::getActionsForBreakpoint(JSC::Breakpo return emptyActionVector; } -} // namespace Inspector +Deprecated::ScriptValue ScriptDebugServer::exceptionOrCaughtValue(JSC::ExecState* state) +{ + if (reasonForPause() == PausedForException) + return Deprecated::ScriptValue(state->vm(), currentException()); + + RefPtr<DebuggerCallFrame> debuggerCallFrame = currentDebuggerCallFrame(); + while (debuggerCallFrame) { + DebuggerScope* scope = debuggerCallFrame->scope(); + if (scope->isCatchScope()) + return Deprecated::ScriptValue(state->vm(), scope->caughtValue()); + debuggerCallFrame = debuggerCallFrame->callerFrame(); + } -#endif // ENABLE(INSPECTOR) + return Deprecated::ScriptValue(); +} + +} // namespace Inspector diff --git a/inspector/ScriptDebugServer.h b/inspector/ScriptDebugServer.h index a7bf8ef..99eb723 100644 --- a/inspector/ScriptDebugServer.h +++ b/inspector/ScriptDebugServer.h @@ -74,16 +74,16 @@ protected: ScriptDebugServer(bool isInWorkerThread = false); ~ScriptDebugServer(); - virtual ListenerSet* getListenersForGlobalObject(JSC::JSGlobalObject*) = 0; + virtual ListenerSet& getListeners() = 0; virtual void didPause(JSC::JSGlobalObject*) = 0; virtual void didContinue(JSC::JSGlobalObject*) = 0; virtual void runEventLoopWhilePaused() = 0; virtual bool isContentScript(JSC::ExecState*) const = 0; - virtual void reportException(JSC::ExecState*, JSC::JSValue) const = 0; + virtual void reportException(JSC::ExecState*, JSC::Exception*) const = 0; bool evaluateBreakpointAction(const ScriptBreakpointAction&); - void dispatchFunctionToListeners(JavaScriptExecutionCallback, JSC::JSGlobalObject*); + void dispatchFunctionToListeners(JavaScriptExecutionCallback); void dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback); void dispatchDidPause(ScriptDebugListener*); void dispatchDidContinue(ScriptDebugListener*); @@ -93,21 +93,26 @@ protected: void dispatchBreakpointActionSound(JSC::ExecState*, int breakpointActionIdentifier); void dispatchBreakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&, const Deprecated::ScriptValue& sample); - bool m_doneProcessingDebuggerEvents; + bool m_doneProcessingDebuggerEvents {true}; private: typedef HashMap<JSC::BreakpointID, BreakpointActions> BreakpointIDToActionsMap; virtual void sourceParsed(JSC::ExecState*, JSC::SourceProvider*, int errorLine, const String& errorMsg) override final; - virtual bool needPauseHandling(JSC::JSGlobalObject*) override final; - virtual void handleBreakpointHit(const JSC::Breakpoint&) override final; - virtual void handleExceptionInBreakpointCondition(JSC::ExecState*, JSC::JSValue exception) const override final; - virtual void handlePause(JSC::Debugger::ReasonForPause, JSC::JSGlobalObject*) override final; + virtual bool needPauseHandling(JSC::JSGlobalObject*) override final { return true; } + virtual void handleBreakpointHit(JSC::JSGlobalObject*, const JSC::Breakpoint&) override final; + virtual void handleExceptionInBreakpointCondition(JSC::ExecState*, JSC::Exception*) const override final; + virtual void handlePause(JSC::JSGlobalObject*, JSC::Debugger::ReasonForPause) override final; virtual void notifyDoneProcessingDebuggerEvents() override final; - unsigned m_hitCount; - bool m_callingListeners; + Deprecated::ScriptValue exceptionOrCaughtValue(JSC::ExecState*); + + bool m_callingListeners {false}; + BreakpointIDToActionsMap m_breakpointIDToActions; + + unsigned m_nextProbeSampleId {1}; + unsigned m_currentProbeBatchId {0}; }; } // namespace Inspector diff --git a/inspector/agents/InspectorAgent.cpp b/inspector/agents/InspectorAgent.cpp index be09611..0538690 100644 --- a/inspector/agents/InspectorAgent.cpp +++ b/inspector/agents/InspectorAgent.cpp @@ -31,15 +31,15 @@ #include "config.h" #include "InspectorAgent.h" -#if ENABLE(INSPECTOR) - +#include "InspectorEnvironment.h" #include "InspectorValues.h" #include "ScriptValue.h" namespace Inspector { -InspectorAgent::InspectorAgent() +InspectorAgent::InspectorAgent(InspectorEnvironment& environment) : InspectorAgentBase(ASCIILiteral("Inspector")) + , m_environment(environment) , m_enabled(false) { } @@ -48,29 +48,34 @@ InspectorAgent::~InspectorAgent() { } -void InspectorAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) +void InspectorAgent::didCreateFrontendAndBackend(FrontendChannel* frontendChannel, BackendDispatcher* backendDispatcher) { - m_frontendDispatcher = std::make_unique<InspectorInspectorFrontendDispatcher>(frontendChannel); - m_backendDispatcher = InspectorInspectorBackendDispatcher::create(backendDispatcher, this); + m_frontendDispatcher = std::make_unique<InspectorFrontendDispatcher>(frontendChannel); + m_backendDispatcher = InspectorBackendDispatcher::create(backendDispatcher, this); } -void InspectorAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) +void InspectorAgent::willDestroyFrontendAndBackend(DisconnectReason) { m_frontendDispatcher = nullptr; - m_backendDispatcher.clear(); + m_backendDispatcher = nullptr; m_pendingEvaluateTestCommands.clear(); - ErrorString error; - disable(&error); + ErrorString unused; + disable(unused); } -void InspectorAgent::enable(ErrorString*) +void InspectorAgent::enable(ErrorString&) { m_enabled = true; if (m_pendingInspectData.first) - inspect(m_pendingInspectData.first, m_pendingInspectData.second); + inspect(m_pendingInspectData.first.copyRef(), m_pendingInspectData.second.copyRef()); + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_pendingExtraDomainsData) + m_frontendDispatcher->activateExtraDomains(m_pendingExtraDomainsData); +#endif for (auto& testCommand : m_pendingEvaluateTestCommands) { if (!m_frontendDispatcher) @@ -82,12 +87,17 @@ void InspectorAgent::enable(ErrorString*) m_pendingEvaluateTestCommands.clear(); } -void InspectorAgent::disable(ErrorString*) +void InspectorAgent::disable(ErrorString&) { m_enabled = false; } -void InspectorAgent::inspect(PassRefPtr<TypeBuilder::Runtime::RemoteObject> objectToInspect, PassRefPtr<InspectorObject> hints) +void InspectorAgent::initialized(ErrorString&) +{ + m_environment.frontendInitialized(); +} + +void InspectorAgent::inspect(RefPtr<Protocol::Runtime::RemoteObject>&& objectToInspect, RefPtr<InspectorObject>&& hints) { if (m_enabled && m_frontendDispatcher) { m_frontendDispatcher->inspect(objectToInspect, hints); @@ -108,6 +118,35 @@ void InspectorAgent::evaluateForTestInFrontend(const String& script) m_pendingEvaluateTestCommands.append(script); } -} // namespace Inspector +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +void InspectorAgent::activateExtraDomain(const String& domainName) +{ + if (!m_enabled) { + if (!m_pendingExtraDomainsData) + m_pendingExtraDomainsData = Inspector::Protocol::Array<String>::create(); + m_pendingExtraDomainsData->addItem(domainName); + return; + } -#endif // ENABLE(INSPECTOR) + Ref<Inspector::Protocol::Array<String>> domainNames = Inspector::Protocol::Array<String>::create(); + domainNames->addItem(domainName); + m_frontendDispatcher->activateExtraDomains(WTF::move(domainNames)); +} + +void InspectorAgent::activateExtraDomains(const Vector<String>& extraDomains) +{ + if (extraDomains.isEmpty()) + return; + + RefPtr<Inspector::Protocol::Array<String>> domainNames = Inspector::Protocol::Array<String>::create(); + for (auto domainName : extraDomains) + domainNames->addItem(domainName); + + if (!m_enabled) + m_pendingExtraDomainsData = domainNames.release(); + else + m_frontendDispatcher->activateExtraDomains(domainNames.release()); +} +#endif + +} // namespace Inspector diff --git a/inspector/agents/InspectorAgent.h b/inspector/agents/InspectorAgent.h index 1d30e2e..4c6ef78 100644 --- a/inspector/agents/InspectorAgent.h +++ b/inspector/agents/InspectorAgent.h @@ -30,49 +30,54 @@ #ifndef InspectorAgent_h #define InspectorAgent_h -#if ENABLE(INSPECTOR) - -#include "InspectorJSBackendDispatchers.h" -#include "InspectorJSFrontendDispatchers.h" +#include "InspectorBackendDispatchers.h" +#include "InspectorFrontendDispatchers.h" #include "inspector/InspectorAgentBase.h" #include <wtf/Forward.h> #include <wtf/Vector.h> namespace Inspector { +class BackendDispatcher; +class InspectorEnvironment; class InspectorObject; -class InstrumentingAgents; -class InspectorInspectorBackendDispatcher; -class InspectorInspectorFrontendDispatchers; typedef String ErrorString; -class JS_EXPORT_PRIVATE InspectorAgent final : public InspectorAgentBase, public InspectorInspectorBackendDispatcherHandler { +class JS_EXPORT_PRIVATE InspectorAgent final : public InspectorAgentBase, public InspectorBackendDispatcherHandler { WTF_MAKE_NONCOPYABLE(InspectorAgent); WTF_MAKE_FAST_ALLOCATED; public: - InspectorAgent(); + InspectorAgent(InspectorEnvironment&); virtual ~InspectorAgent(); - virtual void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*) override; - virtual void willDestroyFrontendAndBackend(InspectorDisconnectReason reason) override; + virtual void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher*) override; + virtual void willDestroyFrontendAndBackend(DisconnectReason) override; - virtual void enable(ErrorString*) override; - virtual void disable(ErrorString*) override; + virtual void enable(ErrorString&) override; + virtual void disable(ErrorString&) override; + virtual void initialized(ErrorString&) override; - void inspect(PassRefPtr<TypeBuilder::Runtime::RemoteObject> objectToInspect, PassRefPtr<InspectorObject> hints); + void inspect(RefPtr<Protocol::Runtime::RemoteObject>&& objectToInspect, RefPtr<InspectorObject>&& hints); void evaluateForTestInFrontend(const String& script); +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + void activateExtraDomain(const String&); + void activateExtraDomains(const Vector<String>&); +#endif + private: - std::unique_ptr<InspectorInspectorFrontendDispatcher> m_frontendDispatcher; - RefPtr<InspectorInspectorBackendDispatcher> m_backendDispatcher; + InspectorEnvironment& m_environment; + std::unique_ptr<InspectorFrontendDispatcher> m_frontendDispatcher; + RefPtr<InspectorBackendDispatcher> m_backendDispatcher; Vector<String> m_pendingEvaluateTestCommands; - std::pair<RefPtr<TypeBuilder::Runtime::RemoteObject>, RefPtr<InspectorObject>> m_pendingInspectData; + std::pair<RefPtr<Protocol::Runtime::RemoteObject>, RefPtr<InspectorObject>> m_pendingInspectData; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + RefPtr<Inspector::Protocol::Array<String>> m_pendingExtraDomainsData; +#endif bool m_enabled; }; } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(InspectorAgent_h) diff --git a/inspector/agents/InspectorConsoleAgent.cpp b/inspector/agents/InspectorConsoleAgent.cpp index 2ddec37..9ffd048 100644 --- a/inspector/agents/InspectorConsoleAgent.cpp +++ b/inspector/agents/InspectorConsoleAgent.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "InspectorConsoleAgent.h" -#if ENABLE(INSPECTOR) - #include "ConsoleMessage.h" #include "InjectedScriptManager.h" #include "ScriptArguments.h" @@ -57,22 +55,22 @@ InspectorConsoleAgent::~InspectorConsoleAgent() { } -void InspectorConsoleAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) +void InspectorConsoleAgent::didCreateFrontendAndBackend(FrontendChannel* frontendChannel, BackendDispatcher* backendDispatcher) { - m_frontendDispatcher = std::make_unique<InspectorConsoleFrontendDispatcher>(frontendChannel); - m_backendDispatcher = InspectorConsoleBackendDispatcher::create(backendDispatcher, this); + m_frontendDispatcher = std::make_unique<ConsoleFrontendDispatcher>(frontendChannel); + m_backendDispatcher = ConsoleBackendDispatcher::create(backendDispatcher, this); } -void InspectorConsoleAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) +void InspectorConsoleAgent::willDestroyFrontendAndBackend(DisconnectReason) { m_frontendDispatcher = nullptr; - m_backendDispatcher.clear(); + m_backendDispatcher = nullptr; String errorString; - disable(&errorString); + disable(errorString); } -void InspectorConsoleAgent::enable(ErrorString*) +void InspectorConsoleAgent::enable(ErrorString&) { if (m_enabled) return; @@ -89,7 +87,7 @@ void InspectorConsoleAgent::enable(ErrorString*) m_consoleMessages[i]->addToFrontend(m_frontendDispatcher.get(), m_injectedScriptManager, false); } -void InspectorConsoleAgent::disable(ErrorString*) +void InspectorConsoleAgent::disable(ErrorString&) { if (!m_enabled) return; @@ -97,7 +95,7 @@ void InspectorConsoleAgent::disable(ErrorString*) m_enabled = false; } -void InspectorConsoleAgent::clearMessages(ErrorString*) +void InspectorConsoleAgent::clearMessages(ErrorString&) { m_consoleMessages.clear(); m_expiredConsoleMessageCount = 0; @@ -111,50 +109,24 @@ void InspectorConsoleAgent::clearMessages(ErrorString*) void InspectorConsoleAgent::reset() { - ErrorString error; - clearMessages(&error); + ErrorString unused; + clearMessages(unused); m_times.clear(); m_counts.clear(); } -void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptCallStack> callStack, unsigned long requestIdentifier) -{ - if (!m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled()) - return; - - if (type == MessageType::Clear) { - ErrorString error; - clearMessages(&error); - } - - addConsoleMessage(std::make_unique<ConsoleMessage>(source, type, level, message, callStack, requestIdentifier)); -} - -void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, JSC::ExecState* state, PassRefPtr<ScriptArguments> arguments, unsigned long requestIdentifier) +void InspectorConsoleAgent::addMessageToConsole(std::unique_ptr<ConsoleMessage> message) { if (!m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled()) return; - if (type == MessageType::Clear) { - ErrorString error; - clearMessages(&error); + if (message->type() == MessageType::Clear) { + ErrorString unused; + clearMessages(unused); } - addConsoleMessage(std::make_unique<ConsoleMessage>(source, type, level, message, arguments, state, requestIdentifier)); -} - -void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptID, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* state, unsigned long requestIdentifier) -{ - if (!m_injectedScriptManager->inspectorEnvironment().developerExtrasEnabled()) - return; - - if (type == MessageType::Clear) { - ErrorString error; - clearMessages(&error); - } - - addConsoleMessage(std::make_unique<ConsoleMessage>(source, type, level, message, scriptID, lineNumber, columnNumber, state, requestIdentifier)); + addConsoleMessage(WTF::move(message)); } Vector<unsigned> InspectorConsoleAgent::consoleMessageArgumentCounts() const @@ -191,7 +163,7 @@ void InspectorConsoleAgent::stopTiming(const String& title, PassRefPtr<ScriptCal double elapsed = monotonicallyIncreasingTime() - startTime; String message = title + String::format(": %.3fms", elapsed * 1000); - addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Timing, MessageLevel::Debug, message, callStack); + addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Timing, MessageLevel::Debug, message, callStack)); } void InspectorConsoleAgent::count(JSC::ExecState* state, PassRefPtr<ScriptArguments> arguments) @@ -216,7 +188,7 @@ void InspectorConsoleAgent::count(JSC::ExecState* state, PassRefPtr<ScriptArgume m_counts.add(identifier, count); String message = title + ": " + String::number(count); - addMessageToConsole(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Debug, message, callStack); + addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Debug, message, callStack)); } static bool isGroupMessage(MessageType type) @@ -249,5 +221,3 @@ void InspectorConsoleAgent::addConsoleMessage(std::unique_ptr<ConsoleMessage> co } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/agents/InspectorConsoleAgent.h b/inspector/agents/InspectorConsoleAgent.h index 913a7d0..b9da99d 100644 --- a/inspector/agents/InspectorConsoleAgent.h +++ b/inspector/agents/InspectorConsoleAgent.h @@ -26,10 +26,8 @@ #ifndef InspectorConsoleAgent_h #define InspectorConsoleAgent_h -#if ENABLE(INSPECTOR) - -#include "InspectorJSBackendDispatchers.h" -#include "InspectorJSFrontendDispatchers.h" +#include "InspectorBackendDispatchers.h" +#include "InspectorFrontendDispatchers.h" #include "inspector/InspectorAgentBase.h" #include "runtime/ConsoleTypes.h" #include <wtf/Forward.h> @@ -50,30 +48,28 @@ class ScriptArguments; class ScriptCallStack; typedef String ErrorString; -class JS_EXPORT_PRIVATE InspectorConsoleAgent : public InspectorAgentBase, public InspectorConsoleBackendDispatcherHandler { +class JS_EXPORT_PRIVATE InspectorConsoleAgent : public InspectorAgentBase, public ConsoleBackendDispatcherHandler { WTF_MAKE_NONCOPYABLE(InspectorConsoleAgent); WTF_MAKE_FAST_ALLOCATED; public: InspectorConsoleAgent(InjectedScriptManager*); virtual ~InspectorConsoleAgent(); - virtual void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*) override; - virtual void willDestroyFrontendAndBackend(InspectorDisconnectReason) override; + virtual void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher*) override; + virtual void willDestroyFrontendAndBackend(DisconnectReason) override; - virtual void enable(ErrorString*) override; - virtual void disable(ErrorString*) override; - virtual void clearMessages(ErrorString*) override; - virtual void setMonitoringXHREnabled(ErrorString*, bool enabled) = 0; - virtual void addInspectedNode(ErrorString*, int nodeId) = 0; + virtual void enable(ErrorString&) override; + virtual void disable(ErrorString&) override; + virtual void clearMessages(ErrorString&) override; + virtual void setMonitoringXHREnabled(ErrorString&, bool enabled) override = 0; + virtual void addInspectedNode(ErrorString&, int nodeId) override = 0; virtual bool isWorkerAgent() const = 0; bool enabled() const { return m_enabled; } void reset(); - void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, JSC::ExecState*, PassRefPtr<ScriptArguments>, unsigned long requestIdentifier = 0); - void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, const String& scriptID, unsigned lineNumber, unsigned columnNumber, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0); - void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptCallStack>, unsigned long requestIdentifier = 0); + void addMessageToConsole(std::unique_ptr<ConsoleMessage>); Vector<unsigned> consoleMessageArgumentCounts() const; @@ -85,8 +81,8 @@ protected: void addConsoleMessage(std::unique_ptr<ConsoleMessage>); InjectedScriptManager* m_injectedScriptManager; - std::unique_ptr<InspectorConsoleFrontendDispatcher> m_frontendDispatcher; - RefPtr<InspectorConsoleBackendDispatcher> m_backendDispatcher; + std::unique_ptr<ConsoleFrontendDispatcher> m_frontendDispatcher; + RefPtr<ConsoleBackendDispatcher> m_backendDispatcher; ConsoleMessage* m_previousMessage; Vector<std::unique_ptr<ConsoleMessage>> m_consoleMessages; int m_expiredConsoleMessageCount; @@ -97,6 +93,4 @@ protected: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(InspectorConsoleAgent_h) diff --git a/inspector/agents/InspectorDebuggerAgent.cpp b/inspector/agents/InspectorDebuggerAgent.cpp index 5096a6c..f0f0b48 100644 --- a/inspector/agents/InspectorDebuggerAgent.cpp +++ b/inspector/agents/InspectorDebuggerAgent.cpp @@ -30,8 +30,6 @@ #include "config.h" #include "InspectorDebuggerAgent.h" -#if ENABLE(INSPECTOR) - #include "ContentSearchUtilities.h" #include "InjectedScript.h" #include "InjectedScriptManager.h" @@ -40,6 +38,7 @@ #include "ScriptDebugServer.h" #include "ScriptObject.h" #include "ScriptValue.h" +#include <wtf/Stopwatch.h> #include <wtf/text/WTFString.h> namespace Inspector { @@ -59,12 +58,7 @@ static String objectGroupForBreakpointAction(const ScriptBreakpointAction& actio InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager* injectedScriptManager) : InspectorAgentBase(ASCIILiteral("Debugger")) , m_injectedScriptManager(injectedScriptManager) - , m_listener(nullptr) - , m_pausedScriptState(nullptr) , m_continueToLocationBreakpointID(JSC::noBreakpointID) - , m_enabled(false) - , m_javaScriptPauseScheduled(false) - , m_nextProbeSampleId(1) { // FIXME: make breakReason optional so that there was no need to init it with "other". clearBreakDetails(); @@ -74,18 +68,18 @@ InspectorDebuggerAgent::~InspectorDebuggerAgent() { } -void InspectorDebuggerAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) +void InspectorDebuggerAgent::didCreateFrontendAndBackend(FrontendChannel* frontendChannel, BackendDispatcher* backendDispatcher) { - m_frontendDispatcher = std::make_unique<InspectorDebuggerFrontendDispatcher>(frontendChannel); - m_backendDispatcher = InspectorDebuggerBackendDispatcher::create(backendDispatcher, this); + m_frontendDispatcher = std::make_unique<DebuggerFrontendDispatcher>(frontendChannel); + m_backendDispatcher = DebuggerBackendDispatcher::create(backendDispatcher, this); } -void InspectorDebuggerAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason) +void InspectorDebuggerAgent::willDestroyFrontendAndBackend(DisconnectReason reason) { m_frontendDispatcher = nullptr; - m_backendDispatcher.clear(); + m_backendDispatcher = nullptr; - bool skipRecompile = reason == InspectorDisconnectReason::InspectedTargetDestroyed; + bool skipRecompile = reason == DisconnectReason::InspectedTargetDestroyed; disable(skipRecompile); } @@ -119,17 +113,17 @@ void InspectorDebuggerAgent::disable(bool isBeingDestroyed) m_enabled = false; } -void InspectorDebuggerAgent::enable(ErrorString*) +void InspectorDebuggerAgent::enable(ErrorString&) { enable(); } -void InspectorDebuggerAgent::disable(ErrorString*) +void InspectorDebuggerAgent::disable(ErrorString&) { disable(false); } -void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active) +void InspectorDebuggerAgent::setBreakpointsActive(ErrorString&, bool active) { if (active) scriptDebugServer().activateBreakpoints(); @@ -142,18 +136,60 @@ bool InspectorDebuggerAgent::isPaused() return scriptDebugServer().isPaused(); } -void InspectorDebuggerAgent::handleConsoleAssert() +static RefPtr<InspectorObject> buildAssertPauseReason(const String& message) +{ + auto reason = Inspector::Protocol::Debugger::AssertPauseReason::create().release(); + if (!message.isNull()) + reason->setMessage(message); + return reason->openAccessors(); +} + +static RefPtr<InspectorObject> buildCSPViolationPauseReason(const String& directiveText) +{ + auto reason = Inspector::Protocol::Debugger::CSPViolationPauseReason::create() + .setDirective(directiveText) + .release(); + return reason->openAccessors(); +} + +RefPtr<InspectorObject> InspectorDebuggerAgent::buildBreakpointPauseReason(JSC::BreakpointID debuggerBreakpointIdentifier) +{ + ASSERT(debuggerBreakpointIdentifier != JSC::noBreakpointID); + auto it = m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.find(debuggerBreakpointIdentifier); + if (it == m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.end()) + return nullptr; + + auto reason = Inspector::Protocol::Debugger::BreakpointPauseReason::create() + .setBreakpointId(it->value) + .release(); + return reason->openAccessors(); +} + +RefPtr<InspectorObject> InspectorDebuggerAgent::buildExceptionPauseReason(const Deprecated::ScriptValue& exception, const InjectedScript& injectedScript) +{ + ASSERT(!exception.hasNoValue()); + if (exception.hasNoValue()) + return nullptr; + + ASSERT(!injectedScript.hasNoValue()); + if (injectedScript.hasNoValue()) + return nullptr; + + return injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors(); +} + +void InspectorDebuggerAgent::handleConsoleAssert(const String& message) { if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) - breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Assert, nullptr); + breakProgram(DebuggerFrontendDispatcher::Reason::Assert, buildAssertPauseReason(message)); } -static PassRefPtr<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, RefPtr<InspectorArray>& actions, bool isRegex, bool autoContinue) +static Ref<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, RefPtr<InspectorArray>& actions, bool isRegex, bool autoContinue) { - RefPtr<InspectorObject> breakpointObject = InspectorObject::create(); + Ref<InspectorObject> breakpointObject = InspectorObject::create(); breakpointObject->setString(ASCIILiteral("url"), url); - breakpointObject->setNumber(ASCIILiteral("lineNumber"), lineNumber); - breakpointObject->setNumber(ASCIILiteral("columnNumber"), columnNumber); + breakpointObject->setInteger(ASCIILiteral("lineNumber"), lineNumber); + breakpointObject->setInteger(ASCIILiteral("columnNumber"), columnNumber); breakpointObject->setString(ASCIILiteral("condition"), condition); breakpointObject->setBoolean(ASCIILiteral("isRegex"), isRegex); breakpointObject->setBoolean(ASCIILiteral("autoContinue"), autoContinue); @@ -175,19 +211,19 @@ static bool matches(const String& url, const String& pattern, bool isRegex) static bool breakpointActionTypeForString(const String& typeString, ScriptBreakpointActionType* output) { - if (typeString == Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Log)) { + if (typeString == Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Log)) { *output = ScriptBreakpointActionTypeLog; return true; } - if (typeString == Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Evaluate)) { + if (typeString == Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Evaluate)) { *output = ScriptBreakpointActionTypeEvaluate; return true; } - if (typeString == Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Sound)) { + if (typeString == Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Sound)) { *output = ScriptBreakpointActionTypeSound; return true; } - if (typeString == Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Probe)) { + if (typeString == Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Probe)) { *output = ScriptBreakpointActionTypeProbe; return true; } @@ -195,7 +231,7 @@ static bool breakpointActionTypeForString(const String& typeString, ScriptBreakp return false; } -bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString* errorString, RefPtr<InspectorArray>& actions, BreakpointActions* result) +bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString& errorString, RefPtr<InspectorArray>& actions, BreakpointActions* result) { if (!actions) return true; @@ -208,30 +244,30 @@ bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString* errorStr for (unsigned i = 0; i < actionsLength; ++i) { RefPtr<InspectorValue> value = actions->get(i); RefPtr<InspectorObject> object; - if (!value->asObject(&object)) { - *errorString = ASCIILiteral("BreakpointAction of incorrect type, expected object"); + if (!value->asObject(object)) { + errorString = ASCIILiteral("BreakpointAction of incorrect type, expected object"); return false; } String typeString; - if (!object->getString(ASCIILiteral("type"), &typeString)) { - *errorString = ASCIILiteral("BreakpointAction had type missing"); + if (!object->getString(ASCIILiteral("type"), typeString)) { + errorString = ASCIILiteral("BreakpointAction had type missing"); return false; } ScriptBreakpointActionType type; if (!breakpointActionTypeForString(typeString, &type)) { - *errorString = ASCIILiteral("BreakpointAction had unknown type"); + errorString = ASCIILiteral("BreakpointAction had unknown type"); return false; } // Specifying an identifier is optional. They are used to correlate probe samples // in the frontend across multiple backend probe actions and segregate object groups. int identifier = 0; - object->getNumber(ASCIILiteral("id"), &identifier); + object->getInteger(ASCIILiteral("id"), identifier); String data; - object->getString(ASCIILiteral("data"), &data); + object->getString(ASCIILiteral("data"), data); result->append(ScriptBreakpointAction(type, identifier, data)); } @@ -239,11 +275,11 @@ bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString* errorStr return true; } -void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const RefPtr<InspectorObject>* options, Inspector::TypeBuilder::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::Location>>& locations) +void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString& errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Debugger::Location>>& locations) { - locations = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::Location>::create(); + locations = Inspector::Protocol::Array<Inspector::Protocol::Debugger::Location>::create(); if (!optionalURL == !optionalURLRegex) { - *errorString = ASCIILiteral("Either url or urlRegex must be specified."); + errorString = ASCIILiteral("Either url or urlRegex must be specified."); return; } @@ -253,7 +289,7 @@ void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int li String breakpointIdentifier = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber); if (m_javaScriptBreakpoints.contains(breakpointIdentifier)) { - *errorString = ASCIILiteral("Breakpoint at specified location already exists."); + errorString = ASCIILiteral("Breakpoint at specified location already exists."); return; } @@ -261,9 +297,9 @@ void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int li bool autoContinue = false; RefPtr<InspectorArray> actions; if (options) { - (*options)->getString(ASCIILiteral("condition"), &condition); - (*options)->getBoolean(ASCIILiteral("autoContinue"), &autoContinue); - actions = (*options)->getArray(ASCIILiteral("actions")); + options->getString(ASCIILiteral("condition"), condition); + options->getBoolean(ASCIILiteral("autoContinue"), autoContinue); + options->getArray(ASCIILiteral("actions"), actions); } BreakpointActions breakpointActions; @@ -278,43 +314,43 @@ void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int li if (!matches(scriptURL, url, isRegex)) continue; - RefPtr<Inspector::TypeBuilder::Debugger::Location> location = resolveBreakpoint(breakpointIdentifier, it->key, breakpoint); + RefPtr<Inspector::Protocol::Debugger::Location> location = resolveBreakpoint(breakpointIdentifier, it->key, breakpoint); if (location) - locations->addItem(location); + locations->addItem(WTF::move(location)); } *outBreakpointIdentifier = breakpointIdentifier; } -static bool parseLocation(ErrorString* errorString, InspectorObject* location, JSC::SourceID* sourceID, unsigned* lineNumber, unsigned* columnNumber) +static bool parseLocation(ErrorString& errorString, const InspectorObject& location, JSC::SourceID& sourceID, unsigned& lineNumber, unsigned& columnNumber) { String scriptIDStr; - if (!location->getString(ASCIILiteral("scriptId"), &scriptIDStr) || !location->getNumber(ASCIILiteral("lineNumber"), lineNumber)) { - *sourceID = JSC::noSourceID; - *errorString = ASCIILiteral("scriptId and lineNumber are required."); + if (!location.getString(ASCIILiteral("scriptId"), scriptIDStr) || !location.getInteger(ASCIILiteral("lineNumber"), lineNumber)) { + sourceID = JSC::noSourceID; + errorString = ASCIILiteral("scriptId and lineNumber are required."); return false; } - *sourceID = scriptIDStr.toIntPtr(); - *columnNumber = 0; - location->getNumber(ASCIILiteral("columnNumber"), columnNumber); + sourceID = scriptIDStr.toIntPtr(); + columnNumber = 0; + location.getInteger(ASCIILiteral("columnNumber"), columnNumber); return true; } -void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr<InspectorObject>& location, const RefPtr<InspectorObject>* options, Inspector::TypeBuilder::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Inspector::TypeBuilder::Debugger::Location>& actualLocation) +void InspectorDebuggerAgent::setBreakpoint(ErrorString& errorString, const InspectorObject& location, const InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Inspector::Protocol::Debugger::Location>& actualLocation) { JSC::SourceID sourceID; unsigned lineNumber; unsigned columnNumber; - if (!parseLocation(errorString, location.get(), &sourceID, &lineNumber, &columnNumber)) + if (!parseLocation(errorString, location, sourceID, lineNumber, columnNumber)) return; String condition = emptyString(); bool autoContinue = false; RefPtr<InspectorArray> actions; if (options) { - (*options)->getString(ASCIILiteral("condition"), &condition); - (*options)->getBoolean(ASCIILiteral("autoContinue"), &autoContinue); - actions = (*options)->getArray(ASCIILiteral("actions")); + options->getString(ASCIILiteral("condition"), condition); + options->getBoolean(ASCIILiteral("autoContinue"), autoContinue); + options->getArray(ASCIILiteral("actions"), actions); } BreakpointActions breakpointActions; @@ -323,25 +359,27 @@ void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPt String breakpointIdentifier = String::number(sourceID) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber); if (m_breakpointIdentifierToDebugServerBreakpointIDs.find(breakpointIdentifier) != m_breakpointIdentifierToDebugServerBreakpointIDs.end()) { - *errorString = ASCIILiteral("Breakpoint at specified location already exists."); + errorString = ASCIILiteral("Breakpoint at specified location already exists."); return; } ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition, breakpointActions, autoContinue); actualLocation = resolveBreakpoint(breakpointIdentifier, sourceID, breakpoint); if (!actualLocation) { - *errorString = ASCIILiteral("Could not resolve breakpoint"); + errorString = ASCIILiteral("Could not resolve breakpoint"); return; } *outBreakpointIdentifier = breakpointIdentifier; } -void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointIdentifier) +void InspectorDebuggerAgent::removeBreakpoint(ErrorString&, const String& breakpointIdentifier) { m_javaScriptBreakpoints.remove(breakpointIdentifier); for (JSC::BreakpointID breakpointID : m_breakpointIdentifierToDebugServerBreakpointIDs.take(breakpointIdentifier)) { + m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.remove(breakpointID); + const BreakpointActions& breakpointActions = scriptDebugServer().getActionsForBreakpoint(breakpointID); for (auto& action : breakpointActions) m_injectedScriptManager->releaseObjectGroup(objectGroupForBreakpointAction(action)); @@ -350,7 +388,7 @@ void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakp } } -void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<InspectorObject>& location) +void InspectorDebuggerAgent::continueToLocation(ErrorString& errorString, const InspectorObject& location) { if (m_continueToLocationBreakpointID != JSC::noBreakpointID) { scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointID); @@ -360,7 +398,7 @@ void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const JSC::SourceID sourceID; unsigned lineNumber; unsigned columnNumber; - if (!parseLocation(errorString, location.get(), &sourceID, &lineNumber, &columnNumber)) + if (!parseLocation(errorString, location, sourceID, lineNumber, columnNumber)) return; ScriptBreakpoint breakpoint(lineNumber, columnNumber, "", false); @@ -368,7 +406,7 @@ void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const resume(errorString); } -PassRefPtr<Inspector::TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointIdentifier, JSC::SourceID sourceID, const ScriptBreakpoint& breakpoint) +RefPtr<Inspector::Protocol::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointIdentifier, JSC::SourceID sourceID, const ScriptBreakpoint& breakpoint) { ScriptsMap::iterator scriptIterator = m_scripts.find(sourceID); if (scriptIterator == m_scripts.end()) @@ -387,55 +425,59 @@ PassRefPtr<Inspector::TypeBuilder::Debugger::Location> InspectorDebuggerAgent::r if (debugServerBreakpointIDsIterator == m_breakpointIdentifierToDebugServerBreakpointIDs.end()) debugServerBreakpointIDsIterator = m_breakpointIdentifierToDebugServerBreakpointIDs.set(breakpointIdentifier, Vector<JSC::BreakpointID>()).iterator; debugServerBreakpointIDsIterator->value.append(debugServerBreakpointID); + + m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.set(debugServerBreakpointID, breakpointIdentifier); - RefPtr<Inspector::TypeBuilder::Debugger::Location> location = Inspector::TypeBuilder::Debugger::Location::create() + auto location = Inspector::Protocol::Debugger::Location::create() .setScriptId(String::number(sourceID)) - .setLineNumber(actualLineNumber); + .setLineNumber(actualLineNumber) + .release(); location->setColumnNumber(actualColumnNumber); - return location; + return WTF::move(location); } -void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptIDStr, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>>& results) +void InspectorDebuggerAgent::searchInContent(ErrorString& error, const String& scriptIDStr, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>>& results) { + JSC::SourceID sourceID = scriptIDStr.toIntPtr(); + auto it = m_scripts.find(sourceID); + if (it == m_scripts.end()) { + error = ASCIILiteral("No script for id: ") + scriptIDStr; + return; + } + bool isRegex = optionalIsRegex ? *optionalIsRegex : false; bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false; - - JSC::SourceID sourceID = scriptIDStr.toIntPtr(); - ScriptsMap::iterator it = m_scripts.find(sourceID); - if (it != m_scripts.end()) - results = ContentSearchUtilities::searchInTextByLines(it->value.source, query, caseSensitive, isRegex); - else - *error = "No script for id: " + scriptIDStr; + results = ContentSearchUtilities::searchInTextByLines(it->value.source, query, caseSensitive, isRegex); } -void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptIDStr, String* scriptSource) +void InspectorDebuggerAgent::getScriptSource(ErrorString& error, const String& scriptIDStr, String* scriptSource) { JSC::SourceID sourceID = scriptIDStr.toIntPtr(); ScriptsMap::iterator it = m_scripts.find(sourceID); if (it != m_scripts.end()) *scriptSource = it->value.source; else - *error = "No script for id: " + scriptIDStr; + error = ASCIILiteral("No script for id: ") + scriptIDStr; } -void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<Inspector::TypeBuilder::Debugger::FunctionDetails>& details) +void InspectorDebuggerAgent::getFunctionDetails(ErrorString& errorString, const String& functionId, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>& details) { InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId); if (injectedScript.hasNoValue()) { - *errorString = ASCIILiteral("Function object id is obsolete"); + errorString = ASCIILiteral("Function object id is obsolete"); return; } injectedScript.getFunctionDetails(errorString, functionId, &details); } -void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorDebuggerFrontendDispatcher::Reason::Enum breakReason, PassRefPtr<InspectorObject> data) +void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data) { if (m_javaScriptPauseScheduled) return; m_breakReason = breakReason; - m_breakAuxData = data; + m_breakAuxData = WTF::move(data); scriptDebugServer().setPauseOnNextStatement(true); } @@ -448,56 +490,49 @@ void InspectorDebuggerAgent::cancelPauseOnNextStatement() scriptDebugServer().setPauseOnNextStatement(false); } -void InspectorDebuggerAgent::pause(ErrorString*) +void InspectorDebuggerAgent::pause(ErrorString&) { - if (m_javaScriptPauseScheduled) - return; + schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason::PauseOnNextStatement, nullptr); - clearBreakDetails(); - scriptDebugServer().setPauseOnNextStatement(true); m_javaScriptPauseScheduled = true; } -void InspectorDebuggerAgent::resume(ErrorString* errorString) +void InspectorDebuggerAgent::resume(ErrorString& errorString) { if (!assertPaused(errorString)) return; - m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); scriptDebugServer().continueProgram(); } -void InspectorDebuggerAgent::stepOver(ErrorString* errorString) +void InspectorDebuggerAgent::stepOver(ErrorString& errorString) { if (!assertPaused(errorString)) return; - m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); scriptDebugServer().stepOverStatement(); } -void InspectorDebuggerAgent::stepInto(ErrorString* errorString) +void InspectorDebuggerAgent::stepInto(ErrorString& errorString) { if (!assertPaused(errorString)) return; - m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); scriptDebugServer().stepIntoStatement(); if (m_listener) m_listener->stepInto(); } -void InspectorDebuggerAgent::stepOut(ErrorString* errorString) +void InspectorDebuggerAgent::stepOut(ErrorString& errorString) { if (!assertPaused(errorString)) return; - m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); scriptDebugServer().stepOutOfFunction(); } -void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState) +void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString& errorString, const String& stringPauseState) { JSC::Debugger::PauseOnExceptionsState pauseState; if (stringPauseState == "none") @@ -507,20 +542,20 @@ void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, cons else if (stringPauseState == "uncaught") pauseState = JSC::Debugger::PauseOnUncaughtExceptions; else { - *errorString = "Unknown pause on exceptions mode: " + stringPauseState; + errorString = ASCIILiteral("Unknown pause on exceptions mode: ") + stringPauseState; return; } scriptDebugServer().setPauseOnExceptionsState(static_cast<JSC::Debugger::PauseOnExceptionsState>(pauseState)); if (scriptDebugServer().pauseOnExceptionsState() != pauseState) - *errorString = ASCIILiteral("Internal error. Could not change pause on exceptions state"); + errorString = ASCIILiteral("Internal error. Could not change pause on exceptions state"); } -void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) +void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) { InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); if (injectedScript.hasNoValue()) { - *errorString = ASCIILiteral("Inspected frame has gone"); + errorString = ASCIILiteral("Inspected frame has gone"); return; } @@ -531,7 +566,7 @@ void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const muteConsole(); } - injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, &result, wasThrown); + injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, saveResult ? *saveResult : false, &result, wasThrown, savedResultIndex); if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) { unmuteConsole(); @@ -540,29 +575,21 @@ void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const } } -void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*) +void InspectorDebuggerAgent::setOverlayMessage(ErrorString&, const String*) { } void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText) { - if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) { - RefPtr<InspectorObject> directive = InspectorObject::create(); - directive->setString(ASCIILiteral("directiveText"), directiveText); - breakProgram(InspectorDebuggerFrontendDispatcher::Reason::CSPViolation, directive.release()); - } + if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions) + breakProgram(DebuggerFrontendDispatcher::Reason::CSPViolation, buildCSPViolationPauseReason(directiveText)); } -PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::CallFrame>> InspectorDebuggerAgent::currentCallFrames() +Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> InspectorDebuggerAgent::currentCallFrames(InjectedScript injectedScript) { - if (!m_pausedScriptState) - return Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::CallFrame>::create(); - - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState); - if (injectedScript.hasNoValue()) { - ASSERT_NOT_REACHED(); - return Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::CallFrame>::create(); - } + ASSERT(!injectedScript.hasNoValue()); + if (injectedScript.hasNoValue()) + return Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>::create(); return injectedScript.wrapCallFrames(m_currentCallStack); } @@ -593,26 +620,31 @@ void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const Script return; for (auto it = m_javaScriptBreakpoints.begin(), end = m_javaScriptBreakpoints.end(); it != end; ++it) { - RefPtr<InspectorObject> breakpointObject = it->value->asObject(); + RefPtr<InspectorObject> breakpointObject; + if (!it->value->asObject(breakpointObject)) + return; + bool isRegex; - breakpointObject->getBoolean(ASCIILiteral("isRegex"), &isRegex); + breakpointObject->getBoolean(ASCIILiteral("isRegex"), isRegex); String url; - breakpointObject->getString(ASCIILiteral("url"), &url); + breakpointObject->getString(ASCIILiteral("url"), url); if (!matches(scriptURL, url, isRegex)) continue; + ScriptBreakpoint breakpoint; - breakpointObject->getNumber(ASCIILiteral("lineNumber"), &breakpoint.lineNumber); - breakpointObject->getNumber(ASCIILiteral("columnNumber"), &breakpoint.columnNumber); - breakpointObject->getString(ASCIILiteral("condition"), &breakpoint.condition); - breakpointObject->getBoolean(ASCIILiteral("autoContinue"), &breakpoint.autoContinue); + breakpointObject->getInteger(ASCIILiteral("lineNumber"), breakpoint.lineNumber); + breakpointObject->getInteger(ASCIILiteral("columnNumber"), breakpoint.columnNumber); + breakpointObject->getString(ASCIILiteral("condition"), breakpoint.condition); + breakpointObject->getBoolean(ASCIILiteral("autoContinue"), breakpoint.autoContinue); ErrorString errorString; - RefPtr<InspectorArray> actions = breakpointObject->getArray(ASCIILiteral("actions")); - if (!breakpointActionsFromProtocol(&errorString, actions, &breakpoint.actions)) { + RefPtr<InspectorArray> actions; + breakpointObject->getArray(ASCIILiteral("actions"), actions); + if (!breakpointActionsFromProtocol(errorString, actions, &breakpoint.actions)) { ASSERT_NOT_REACHED(); continue; } - RefPtr<Inspector::TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, sourceID, breakpoint); + RefPtr<Inspector::Protocol::Debugger::Location> location = resolveBreakpoint(it->key, sourceID, breakpoint); if (location) m_frontendDispatcher->breakpointResolved(it->key, location); } @@ -623,22 +655,53 @@ void InspectorDebuggerAgent::failedToParseSource(const String& url, const String m_frontendDispatcher->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage); } -void InspectorDebuggerAgent::didPause(JSC::ExecState* scriptState, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exception) +void InspectorDebuggerAgent::didPause(JSC::ExecState* scriptState, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exceptionOrCaughtValue) { ASSERT(scriptState && !m_pausedScriptState); m_pausedScriptState = scriptState; m_currentCallStack = callFrames; - if (!exception.hasNoValue()) { - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); - if (!injectedScript.hasNoValue()) { - m_breakReason = InspectorDebuggerFrontendDispatcher::Reason::Exception; - m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors(); - // m_breakAuxData might be null after this. + InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); + + // If a high level pause pause reason is not already set, try to infer a reason from the debugger. + if (m_breakReason == DebuggerFrontendDispatcher::Reason::Other) { + switch (scriptDebugServer().reasonForPause()) { + case JSC::Debugger::PausedForBreakpoint: { + JSC::BreakpointID debuggerBreakpointId = scriptDebugServer().pausingBreakpointID(); + if (debuggerBreakpointId != m_continueToLocationBreakpointID) { + m_breakReason = DebuggerFrontendDispatcher::Reason::Breakpoint; + m_breakAuxData = buildBreakpointPauseReason(debuggerBreakpointId); + } + break; + } + case JSC::Debugger::PausedForDebuggerStatement: + m_breakReason = DebuggerFrontendDispatcher::Reason::DebuggerStatement; + m_breakAuxData = nullptr; + break; + case JSC::Debugger::PausedForException: + m_breakReason = DebuggerFrontendDispatcher::Reason::Exception; + m_breakAuxData = buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript); + break; + case JSC::Debugger::PausedAtStatement: + case JSC::Debugger::PausedAfterCall: + case JSC::Debugger::PausedBeforeReturn: + case JSC::Debugger::PausedAtStartOfProgram: + case JSC::Debugger::PausedAtEndOfProgram: + // Pause was just stepping. Nothing to report. + break; + case JSC::Debugger::NotPaused: + ASSERT_NOT_REACHED(); + break; } } - m_frontendDispatcher->paused(currentCallFrames(), m_breakReason, m_breakAuxData); + // Set $exception to the exception or caught value. + if (!exceptionOrCaughtValue.hasNoValue() && !injectedScript.hasNoValue()) { + injectedScript.setExceptionValue(exceptionOrCaughtValue); + m_hasExceptionValue = true; + } + + m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_breakReason, m_breakAuxData); m_javaScriptPauseScheduled = false; if (m_continueToLocationBreakpointID != JSC::noBreakpointID) { @@ -648,6 +711,12 @@ void InspectorDebuggerAgent::didPause(JSC::ExecState* scriptState, const Depreca if (m_listener) m_listener->didPause(); + + RefPtr<Stopwatch> stopwatch = m_injectedScriptManager->inspectorEnvironment().executionStopwatch(); + if (stopwatch && stopwatch->isActive()) { + stopwatch->stop(); + m_didPauseStopwatch = true; + } } void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier) @@ -655,35 +724,41 @@ void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifie m_frontendDispatcher->playBreakpointActionSound(breakpointActionIdentifier); } -void InspectorDebuggerAgent::breakpointActionProbe(JSC::ExecState* scriptState, const ScriptBreakpointAction& action, int hitCount, const Deprecated::ScriptValue& sample) +void InspectorDebuggerAgent::breakpointActionProbe(JSC::ExecState* scriptState, const ScriptBreakpointAction& action, unsigned batchId, unsigned sampleId, const Deprecated::ScriptValue& sample) { - int sampleId = m_nextProbeSampleId++; - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); - RefPtr<TypeBuilder::Runtime::RemoteObject> payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(action)); - RefPtr<TypeBuilder::Debugger::ProbeSample> result = TypeBuilder::Debugger::ProbeSample::create() + RefPtr<Protocol::Runtime::RemoteObject> payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(action), true); + auto result = Protocol::Debugger::ProbeSample::create() .setProbeId(action.identifier) + .setBatchId(batchId) .setSampleId(sampleId) - .setBatchId(hitCount) - .setTimestamp(monotonicallyIncreasingTime()) - .setPayload(payload.release()); + .setTimestamp(m_injectedScriptManager->inspectorEnvironment().executionStopwatch()->elapsedTime()) + .setPayload(payload.release()) + .release(); - m_frontendDispatcher->didSampleProbe(result.release()); + m_frontendDispatcher->didSampleProbe(WTF::move(result)); } void InspectorDebuggerAgent::didContinue() { + if (m_didPauseStopwatch) { + m_didPauseStopwatch = false; + m_injectedScriptManager->inspectorEnvironment().executionStopwatch()->start(); + } + m_pausedScriptState = nullptr; m_currentCallStack = Deprecated::ScriptValue(); + m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); clearBreakDetails(); + clearExceptionValue(); m_frontendDispatcher->resumed(); } -void InspectorDebuggerAgent::breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Enum breakReason, PassRefPtr<InspectorObject> data) +void InspectorDebuggerAgent::breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data) { m_breakReason = breakReason; - m_breakAuxData = data; + m_breakAuxData = WTF::move(data); scriptDebugServer().breakProgram(); } @@ -693,7 +768,7 @@ void InspectorDebuggerAgent::clearInspectorBreakpointState() Vector<String> breakpointIdentifiers; copyKeysToVector(m_breakpointIdentifierToDebugServerBreakpointIDs, breakpointIdentifiers); for (const String& identifier : breakpointIdentifiers) - removeBreakpoint(&dummyError, identifier); + removeBreakpoint(dummyError, identifier); m_javaScriptBreakpoints.clear(); @@ -708,9 +783,11 @@ void InspectorDebuggerAgent::clearDebuggerBreakpointState() m_currentCallStack = Deprecated::ScriptValue(); m_scripts.clear(); m_breakpointIdentifierToDebugServerBreakpointIDs.clear(); + m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.clear(); m_continueToLocationBreakpointID = JSC::noBreakpointID; clearBreakDetails(); m_javaScriptPauseScheduled = false; + m_hasExceptionValue = false; scriptDebugServer().continueProgram(); } @@ -725,10 +802,10 @@ void InspectorDebuggerAgent::didClearGlobalObject() m_frontendDispatcher->globalObjectCleared(); } -bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString) +bool InspectorDebuggerAgent::assertPaused(ErrorString& errorString) { if (!m_pausedScriptState) { - *errorString = ASCIILiteral("Can only perform operation while paused."); + errorString = ASCIILiteral("Can only perform operation while paused."); return false; } @@ -737,11 +814,16 @@ bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString) void InspectorDebuggerAgent::clearBreakDetails() { - m_breakReason = InspectorDebuggerFrontendDispatcher::Reason::Other; + m_breakReason = DebuggerFrontendDispatcher::Reason::Other; m_breakAuxData = nullptr; } +void InspectorDebuggerAgent::clearExceptionValue() +{ + if (m_hasExceptionValue) { + m_injectedScriptManager->clearExceptionValue(); + m_hasExceptionValue = false; + } +} } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/agents/InspectorDebuggerAgent.h b/inspector/agents/InspectorDebuggerAgent.h index eb2270a..28249e2 100644 --- a/inspector/agents/InspectorDebuggerAgent.h +++ b/inspector/agents/InspectorDebuggerAgent.h @@ -30,10 +30,8 @@ #ifndef InspectorDebuggerAgent_h #define InspectorDebuggerAgent_h -#if ENABLE(INSPECTOR) - -#include "InspectorJSBackendDispatchers.h" -#include "InspectorJSFrontendDispatchers.h" +#include "InspectorBackendDispatchers.h" +#include "InspectorFrontendDispatchers.h" #include "bindings/ScriptValue.h" #include "debugger/Debugger.h" #include "inspector/InspectorAgentBase.h" @@ -42,11 +40,13 @@ #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> -#include <wtf/PassOwnPtr.h> -#include <wtf/PassRefPtr.h> #include <wtf/Vector.h> #include <wtf/text/StringHash.h> +namespace WTF { +class Stopwatch; +} + namespace Inspector { class InjectedScript; @@ -57,7 +57,7 @@ class InspectorValue; class ScriptDebugServer; typedef String ErrorString; -class JS_EXPORT_PRIVATE InspectorDebuggerAgent : public InspectorAgentBase, public ScriptDebugListener, public InspectorDebuggerBackendDispatcherHandler { +class JS_EXPORT_PRIVATE InspectorDebuggerAgent : public InspectorAgentBase, public ScriptDebugListener, public DebuggerBackendDispatcherHandler { WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent); WTF_MAKE_FAST_ALLOCATED; public: @@ -65,35 +65,35 @@ public: virtual ~InspectorDebuggerAgent(); - virtual void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*) override; - virtual void willDestroyFrontendAndBackend(InspectorDisconnectReason) override; - - virtual void enable(ErrorString*) override; - virtual void disable(ErrorString*) override; - virtual void setBreakpointsActive(ErrorString*, bool active) override; - virtual void setBreakpointByUrl(ErrorString*, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const RefPtr<Inspector::InspectorObject>* options, Inspector::TypeBuilder::Debugger::BreakpointId*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::Location>>& locations) override; - virtual void setBreakpoint(ErrorString*, const RefPtr<Inspector::InspectorObject>& location, const RefPtr<Inspector::InspectorObject>* options, Inspector::TypeBuilder::Debugger::BreakpointId*, RefPtr<Inspector::TypeBuilder::Debugger::Location>& actualLocation) override; - virtual void removeBreakpoint(ErrorString*, const String& breakpointIdentifier) override; - virtual void continueToLocation(ErrorString*, const RefPtr<InspectorObject>& location) override; - virtual void searchInContent(ErrorString*, const String& scriptID, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>>&) override; - virtual void getScriptSource(ErrorString*, const String& scriptID, String* scriptSource) override; - virtual void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<Inspector::TypeBuilder::Debugger::FunctionDetails>&) override; - virtual void pause(ErrorString*) override; - virtual void resume(ErrorString*) override; - virtual void stepOver(ErrorString*) override; - virtual void stepInto(ErrorString*) override; - virtual void stepOut(ErrorString*) override; - virtual void setPauseOnExceptions(ErrorString*, const String& pauseState) override; - virtual void evaluateOnCallFrame(ErrorString*, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) override; - virtual void setOverlayMessage(ErrorString*, const String*) override; + virtual void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher*) override; + virtual void willDestroyFrontendAndBackend(DisconnectReason) override; + + virtual void enable(ErrorString&) override; + virtual void disable(ErrorString&) override; + virtual void setBreakpointsActive(ErrorString&, bool active) override; + virtual void setBreakpointByUrl(ErrorString&, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const Inspector::InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId*, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Debugger::Location>>& locations) override; + virtual void setBreakpoint(ErrorString&, const Inspector::InspectorObject& location, const Inspector::InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId*, RefPtr<Inspector::Protocol::Debugger::Location>& actualLocation) override; + virtual void removeBreakpoint(ErrorString&, const String& breakpointIdentifier) override; + virtual void continueToLocation(ErrorString&, const InspectorObject& location) override; + virtual void searchInContent(ErrorString&, const String& scriptID, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>>&) override; + virtual void getScriptSource(ErrorString&, const String& scriptID, String* scriptSource) override; + virtual void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>&) override; + virtual void pause(ErrorString&) override; + virtual void resume(ErrorString&) override; + virtual void stepOver(ErrorString&) override; + virtual void stepInto(ErrorString&) override; + virtual void stepOut(ErrorString&) override; + virtual void setPauseOnExceptions(ErrorString&, const String& pauseState) override; + virtual void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) override; + virtual void setOverlayMessage(ErrorString&, const String*) override; bool isPaused(); - void handleConsoleAssert(); + void handleConsoleAssert(const String& message); - void schedulePauseOnNextStatement(InspectorDebuggerFrontendDispatcher::Reason::Enum breakReason, PassRefPtr<InspectorObject> data); + void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data); void cancelPauseOnNextStatement(); - void breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Enum breakReason, PassRefPtr<InspectorObject> data); + void breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data); void scriptExecutionBlockedByCSP(const String& directiveText); class Listener { @@ -112,7 +112,7 @@ protected: InspectorDebuggerAgent(InjectedScriptManager*); InjectedScriptManager* injectedScriptManager() const { return m_injectedScriptManager; } - virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) = 0; + virtual InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) = 0; virtual void startListeningScriptDebugServer() = 0; virtual void stopListeningScriptDebugServer(bool skipRecompile) = 0; @@ -121,7 +121,7 @@ protected: virtual void enable(); virtual void disable(bool skipRecompile); - virtual void didPause(JSC::ExecState*, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exception) override; + virtual void didPause(JSC::ExecState*, const Deprecated::ScriptValue& callFrames, const Deprecated::ScriptValue& exceptionOrCaughtValue) override; virtual void didContinue() override; virtual String sourceMapURLForScript(const Script&); @@ -129,45 +129,51 @@ protected: void didClearGlobalObject(); private: - PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Debugger::CallFrame>> currentCallFrames(); + Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> currentCallFrames(InjectedScript); virtual void didParseSource(JSC::SourceID, const Script&) override final; virtual void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) override final; virtual void breakpointActionSound(int breakpointActionIdentifier) override; - virtual void breakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&, int hitCount, const Deprecated::ScriptValue& sample) override final; + virtual void breakpointActionProbe(JSC::ExecState*, const ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, const Deprecated::ScriptValue& sample) override final; - PassRefPtr<Inspector::TypeBuilder::Debugger::Location> resolveBreakpoint(const String& breakpointIdentifier, JSC::SourceID, const ScriptBreakpoint&); - bool assertPaused(ErrorString*); + RefPtr<Inspector::Protocol::Debugger::Location> resolveBreakpoint(const String& breakpointIdentifier, JSC::SourceID, const ScriptBreakpoint&); + bool assertPaused(ErrorString&); void clearDebuggerBreakpointState(); void clearInspectorBreakpointState(); void clearBreakDetails(); + void clearExceptionValue(); - bool breakpointActionsFromProtocol(ErrorString*, RefPtr<InspectorArray>& actions, BreakpointActions* result); + RefPtr<InspectorObject> buildBreakpointPauseReason(JSC::BreakpointID); + RefPtr<InspectorObject> buildExceptionPauseReason(const Deprecated::ScriptValue& exception, const InjectedScript&); + + bool breakpointActionsFromProtocol(ErrorString&, RefPtr<InspectorArray>& actions, BreakpointActions* result); typedef HashMap<JSC::SourceID, Script> ScriptsMap; typedef HashMap<String, Vector<JSC::BreakpointID>> BreakpointIdentifierToDebugServerBreakpointIDsMap; typedef HashMap<String, RefPtr<InspectorObject>> BreakpointIdentifierToBreakpointMap; + typedef HashMap<JSC::BreakpointID, String> DebugServerBreakpointIDToBreakpointIdentifier; InjectedScriptManager* m_injectedScriptManager; - std::unique_ptr<InspectorDebuggerFrontendDispatcher> m_frontendDispatcher; - RefPtr<InspectorDebuggerBackendDispatcher> m_backendDispatcher; - Listener* m_listener; - JSC::ExecState* m_pausedScriptState; + std::unique_ptr<DebuggerFrontendDispatcher> m_frontendDispatcher; + RefPtr<DebuggerBackendDispatcher> m_backendDispatcher; + Listener* m_listener {nullptr}; + JSC::ExecState* m_pausedScriptState {nullptr}; Deprecated::ScriptValue m_currentCallStack; ScriptsMap m_scripts; BreakpointIdentifierToDebugServerBreakpointIDsMap m_breakpointIdentifierToDebugServerBreakpointIDs; BreakpointIdentifierToBreakpointMap m_javaScriptBreakpoints; + DebugServerBreakpointIDToBreakpointIdentifier m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier; JSC::BreakpointID m_continueToLocationBreakpointID; - InspectorDebuggerFrontendDispatcher::Reason::Enum m_breakReason; + DebuggerFrontendDispatcher::Reason m_breakReason; RefPtr<InspectorObject> m_breakAuxData; - bool m_enabled; - bool m_javaScriptPauseScheduled; - int m_nextProbeSampleId; + bool m_enabled {false}; + bool m_javaScriptPauseScheduled {false}; + bool m_hasExceptionValue {false}; + bool m_didPauseStopwatch {false}; + RefPtr<WTF::Stopwatch> m_stopwatch; }; } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(InspectorDebuggerAgent_h) diff --git a/inspector/agents/InspectorProfilerAgent.cpp b/inspector/agents/InspectorProfilerAgent.cpp deleted file mode 100644 index 82d59a0..0000000 --- a/inspector/agents/InspectorProfilerAgent.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 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. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "InspectorProfilerAgent.h" - -#if ENABLE(INSPECTOR) - -#include "InspectorValues.h" -#include "LegacyProfiler.h" -#include "Profile.h" -#include "ScriptDebugServer.h" -#include "ScriptObject.h" -#include <wtf/CurrentTime.h> -#include <wtf/text/StringConcatenate.h> - -namespace Inspector { - -static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated"; -static const char* const CPUProfileType = "CPU"; - -InspectorProfilerAgent::InspectorProfilerAgent() - : InspectorAgentBase(ASCIILiteral("Profiler")) - , m_scriptDebugServer(nullptr) - , m_enabled(false) - , m_profileHeadersRequested(false) - , m_recordingProfileCount(0) - , m_nextUserInitiatedProfileNumber(1) -{ -} - -InspectorProfilerAgent::~InspectorProfilerAgent() -{ -} - -void InspectorProfilerAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) -{ - m_frontendDispatcher = std::make_unique<InspectorProfilerFrontendDispatcher>(frontendChannel); - m_backendDispatcher = InspectorProfilerBackendDispatcher::create(backendDispatcher, this); -} - -void InspectorProfilerAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason) -{ - m_frontendDispatcher = nullptr; - m_backendDispatcher.clear(); - - reset(); - - disable(reason == InspectorDisconnectReason::InspectedTargetDestroyed ? SkipRecompile : Recompile); -} - -void InspectorProfilerAgent::addProfile(PassRefPtr<JSC::Profile> prpProfile) -{ - RefPtr<JSC::Profile> profile = prpProfile; - m_profiles.add(profile->uid(), profile); - - if (m_frontendDispatcher && m_profileHeadersRequested) - m_frontendDispatcher->addProfileHeader(createProfileHeader(*profile)); -} - -PassRefPtr<TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::createProfileHeader(const JSC::Profile& profile) -{ - return TypeBuilder::Profiler::ProfileHeader::create() - .setTypeId(TypeBuilder::Profiler::ProfileHeader::TypeId::CPU) - .setUid(profile.uid()) - .setTitle(profile.title()) - .release(); -} - -void InspectorProfilerAgent::enable(ErrorString*) -{ - enable(Recompile); -} - -void InspectorProfilerAgent::disable(ErrorString*) -{ - disable(Recompile); -} - -void InspectorProfilerAgent::enable(ShouldRecompile shouldRecompile) -{ - if (m_enabled) - return; - - m_enabled = true; - - if (shouldRecompile == Recompile) - m_scriptDebugServer->recompileAllJSFunctions(); -} - -void InspectorProfilerAgent::disable(ShouldRecompile shouldRecompile) -{ - if (!m_enabled) - return; - - m_enabled = false; - m_profileHeadersRequested = false; - - if (shouldRecompile == Recompile) - m_scriptDebugServer->recompileAllJSFunctions(); -} - -String InspectorProfilerAgent::getUserInitiatedProfileName() -{ - return makeString(UserInitiatedProfileName, '.', String::number(m_nextUserInitiatedProfileNumber++)); -} - -void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>>& headers) -{ - m_profileHeadersRequested = true; - headers = TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>::create(); - - for (auto& profile : m_profiles.values()) - headers->addItem(createProfileHeader(*profile.get())); -} - -static PassRefPtr<TypeBuilder::Profiler::CPUProfileNodeCall> buildInspectorObject(const JSC::ProfileNode::Call& call) -{ - RefPtr<TypeBuilder::Profiler::CPUProfileNodeCall> result = TypeBuilder::Profiler::CPUProfileNodeCall::create() - .setStartTime(call.startTime()) - .setTotalTime(call.totalTime()); - return result.release(); -} - -static PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObject(const JSC::ProfileNode* node) -{ - RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNodeCall>> calls = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNodeCall>::create(); - for (const JSC::ProfileNode::Call& call : node->calls()) - calls->addItem(buildInspectorObject(call)); - - RefPtr<TypeBuilder::Profiler::CPUProfileNode> result = TypeBuilder::Profiler::CPUProfileNode::create() - .setId(node->id()) - .setCalls(calls.release()); - - if (!node->functionName().isEmpty()) - result->setFunctionName(node->functionName()); - - if (!node->url().isEmpty()) { - result->setUrl(node->url()); - result->setLineNumber(node->lineNumber()); - result->setColumnNumber(node->columnNumber()); - } - - if (!node->children().isEmpty()) { - RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> children = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create(); - for (RefPtr<JSC::ProfileNode> profileNode : node->children()) - children->addItem(buildInspectorObject(profileNode.get())); - result->setChildren(children); - } - - return result.release(); -} - -PassRefPtr<TypeBuilder::Profiler::CPUProfile> InspectorProfilerAgent::buildProfileInspectorObject(const JSC::Profile* profile) -{ - RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> rootNodes = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create(); - for (RefPtr<JSC::ProfileNode> profileNode : profile->head()->children()) - rootNodes->addItem(buildInspectorObject(profileNode.get())); - - RefPtr<TypeBuilder::Profiler::CPUProfile> result = TypeBuilder::Profiler::CPUProfile::create() - .setRootNodes(rootNodes); - - if (profile->idleTime()) - result->setIdleTime(profile->idleTime()); - - return result.release(); -} - -void InspectorProfilerAgent::getCPUProfile(ErrorString* errorString, int rawUid, RefPtr<TypeBuilder::Profiler::CPUProfile>& profileObject) -{ - unsigned uid = static_cast<unsigned>(rawUid); - auto it = m_profiles.find(uid); - if (it == m_profiles.end()) { - *errorString = ASCIILiteral("Profile wasn't found"); - return; - } - - profileObject = buildProfileInspectorObject(it->value.get()); -} - -void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, int rawUid) -{ - unsigned uid = static_cast<unsigned>(rawUid); - if (type == CPUProfileType) - m_profiles.remove(uid); -} - -void InspectorProfilerAgent::reset() -{ - stop(); - - m_profiles.clear(); - m_nextUserInitiatedProfileNumber = 1; - m_profileHeadersRequested = false; - - if (m_frontendDispatcher && m_profileHeadersRequested) - m_frontendDispatcher->resetProfiles(); -} - -void InspectorProfilerAgent::start(ErrorString*) -{ - startProfiling(); -} - -void InspectorProfilerAgent::stop(ErrorString*) -{ - stopProfiling(); -} - -void InspectorProfilerAgent::setRecordingProfile(bool isProfiling) -{ - if (m_frontendDispatcher) - m_frontendDispatcher->setRecordingProfile(isProfiling); -} - -String InspectorProfilerAgent::startProfiling(const String &title, JSC::ExecState* exec) -{ - if (!enabled()) - enable(Recompile); - - bool wasNotRecording = !m_recordingProfileCount; - ++m_recordingProfileCount; - - String resolvedTitle = title; - if (title.isEmpty()) - resolvedTitle = getUserInitiatedProfileName(); - - if (!exec) - exec = profilingGlobalExecState(); - ASSERT(exec); - - JSC::LegacyProfiler::profiler()->startProfiling(exec, resolvedTitle); - - if (wasNotRecording) - setRecordingProfile(true); - - return resolvedTitle; -} - -PassRefPtr<JSC::Profile> InspectorProfilerAgent::stopProfiling(const String& title, JSC::ExecState* exec) -{ - if (!m_recordingProfileCount) - return nullptr; - - --m_recordingProfileCount; - - if (!exec) - exec = profilingGlobalExecState(); - ASSERT(exec); - - RefPtr<JSC::Profile> profile = JSC::LegacyProfiler::profiler()->stopProfiling(exec, title); - if (profile) - addProfile(profile); - - if (!m_recordingProfileCount) - setRecordingProfile(false); - - return profile.release(); -} - -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/agents/InspectorProfilerAgent.h b/inspector/agents/InspectorProfilerAgent.h deleted file mode 100644 index 5e00fc1..0000000 --- a/inspector/agents/InspectorProfilerAgent.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 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. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef InspectorProfilerAgent_h -#define InspectorProfilerAgent_h - -#if ENABLE(INSPECTOR) - -#include "InspectorJSBackendDispatchers.h" -#include "InspectorJSFrontendDispatchers.h" -#include "inspector/InspectorAgentBase.h" -#include <wtf/Forward.h> -#include <wtf/HashMap.h> -#include <wtf/Noncopyable.h> -#include <wtf/text/WTFString.h> - -namespace JSC { -class ExecState; -class Profile; -} - -namespace Inspector { - -class ScriptDebugServer; - -typedef String ErrorString; - -class JS_EXPORT_PRIVATE InspectorProfilerAgent : public InspectorAgentBase, public InspectorProfilerBackendDispatcherHandler { - WTF_MAKE_NONCOPYABLE(InspectorProfilerAgent); - WTF_MAKE_FAST_ALLOCATED; -public: - virtual ~InspectorProfilerAgent(); - - virtual void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*) override final; - virtual void willDestroyFrontendAndBackend(InspectorDisconnectReason) override final; - - virtual void enable(ErrorString*) override final; - virtual void disable(ErrorString*) override final; - - virtual void start(ErrorString* = nullptr) override final; - virtual void stop(ErrorString* = nullptr) override final; - - virtual void clearProfiles(ErrorString*) override final { reset(); } - - virtual void getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>>&) override final; - virtual void getCPUProfile(ErrorString*, int uid, RefPtr<TypeBuilder::Profiler::CPUProfile>&) override final; - virtual void removeProfile(ErrorString*, const String& type, int uid) override final; - - static PassRefPtr<TypeBuilder::Profiler::CPUProfile> buildProfileInspectorObject(const JSC::Profile*); - - enum ShouldRecompile { SkipRecompile, Recompile }; - - virtual void enable(ShouldRecompile); - virtual void disable(ShouldRecompile); - - bool enabled() const { return m_enabled; } - - void reset(); - - void setScriptDebugServer(ScriptDebugServer* scriptDebugServer) { m_scriptDebugServer = scriptDebugServer; } - - String startProfiling(const String& title = String(), JSC::ExecState* = nullptr); - PassRefPtr<JSC::Profile> stopProfiling(const String& title = String(), JSC::ExecState* = nullptr); - -protected: - InspectorProfilerAgent(); - - virtual JSC::ExecState* profilingGlobalExecState() const = 0; - -private: - void addProfile(PassRefPtr<JSC::Profile>); - - void setRecordingProfile(bool isProfiling); - - String getUserInitiatedProfileName(); - - PassRefPtr<TypeBuilder::Profiler::ProfileHeader> createProfileHeader(const JSC::Profile&); - - std::unique_ptr<InspectorProfilerFrontendDispatcher> m_frontendDispatcher; - RefPtr<InspectorProfilerBackendDispatcher> m_backendDispatcher; - HashMap<unsigned, RefPtr<JSC::Profile>> m_profiles; - ScriptDebugServer* m_scriptDebugServer; - bool m_enabled; - bool m_profileHeadersRequested; - unsigned m_recordingProfileCount; - unsigned m_nextUserInitiatedProfileNumber; -}; - -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) - -#endif // !defined(InspectorProfilerAgent_h) diff --git a/inspector/agents/InspectorRuntimeAgent.cpp b/inspector/agents/InspectorRuntimeAgent.cpp index ac65979..e3ec862 100644 --- a/inspector/agents/InspectorRuntimeAgent.cpp +++ b/inspector/agents/InspectorRuntimeAgent.cpp @@ -32,9 +32,8 @@ #include "config.h" #include "InspectorRuntimeAgent.h" -#if ENABLE(INSPECTOR) - #include "Completion.h" +#include "HeapIterationScope.h" #include "InjectedScript.h" #include "InjectedScriptManager.h" #include "InspectorValues.h" @@ -42,7 +41,10 @@ #include "ParserError.h" #include "ScriptDebugServer.h" #include "SourceCode.h" -#include <wtf/PassRefPtr.h> +#include "TypeProfiler.h" +#include "TypeProfilerLog.h" +#include "VMEntryScope.h" +#include <wtf/CurrentTime.h> using namespace JSC; @@ -58,6 +60,7 @@ InspectorRuntimeAgent::InspectorRuntimeAgent(InjectedScriptManager* injectedScri , m_injectedScriptManager(injectedScriptManager) , m_scriptDebugServer(nullptr) , m_enabled(false) + , m_isTypeProfilingEnabled(false) { } @@ -74,15 +77,15 @@ static ScriptDebugServer::PauseOnExceptionsState setPauseOnExceptionsState(Scrip return presentState; } -static PassRefPtr<Inspector::TypeBuilder::Runtime::ErrorRange> buildErrorRangeObject(const JSTokenLocation& tokenLocation) +static Ref<Inspector::Protocol::Runtime::ErrorRange> buildErrorRangeObject(const JSTokenLocation& tokenLocation) { - RefPtr<Inspector::TypeBuilder::Runtime::ErrorRange> result = Inspector::TypeBuilder::Runtime::ErrorRange::create() + return Inspector::Protocol::Runtime::ErrorRange::create() .setStartOffset(tokenLocation.startOffset) - .setEndOffset(tokenLocation.endOffset); - return result.release(); + .setEndOffset(tokenLocation.endOffset) + .release(); } -void InspectorRuntimeAgent::parse(ErrorString*, const String& expression, Inspector::TypeBuilder::Runtime::SyntaxErrorType::Enum* result, Inspector::TypeBuilder::OptOutput<String>* message, RefPtr<Inspector::TypeBuilder::Runtime::ErrorRange>& range) +void InspectorRuntimeAgent::parse(ErrorString&, const String& expression, Inspector::Protocol::Runtime::SyntaxErrorType* result, Inspector::Protocol::OptOutput<String>* message, RefPtr<Inspector::Protocol::Runtime::ErrorRange>& range) { VM& vm = globalVM(); JSLockHolder lock(vm); @@ -90,28 +93,28 @@ void InspectorRuntimeAgent::parse(ErrorString*, const String& expression, Inspec ParserError error; checkSyntax(vm, JSC::makeSource(expression), error); - switch (error.m_syntaxErrorType) { + switch (error.syntaxErrorType()) { case ParserError::SyntaxErrorNone: - *result = Inspector::TypeBuilder::Runtime::SyntaxErrorType::None; + *result = Inspector::Protocol::Runtime::SyntaxErrorType::None; break; case ParserError::SyntaxErrorIrrecoverable: - *result = Inspector::TypeBuilder::Runtime::SyntaxErrorType::Irrecoverable; + *result = Inspector::Protocol::Runtime::SyntaxErrorType::Irrecoverable; break; case ParserError::SyntaxErrorUnterminatedLiteral: - *result = Inspector::TypeBuilder::Runtime::SyntaxErrorType::UnterminatedLiteral; + *result = Inspector::Protocol::Runtime::SyntaxErrorType::UnterminatedLiteral; break; case ParserError::SyntaxErrorRecoverable: - *result = Inspector::TypeBuilder::Runtime::SyntaxErrorType::Recoverable; + *result = Inspector::Protocol::Runtime::SyntaxErrorType::Recoverable; break; } - if (error.m_syntaxErrorType != ParserError::SyntaxErrorNone) { - *message = error.m_message; - range = buildErrorRangeObject(error.m_token.m_location); + if (error.syntaxErrorType() != ParserError::SyntaxErrorNone) { + *message = error.message(); + range = buildErrorRangeObject(error.token().m_location); } } -void InspectorRuntimeAgent::evaluate(ErrorString* errorString, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* const returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) +void InspectorRuntimeAgent::evaluate(ErrorString& errorString, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* const returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) { InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId); if (injectedScript.hasNoValue()) @@ -123,7 +126,7 @@ void InspectorRuntimeAgent::evaluate(ErrorString* errorString, const String& exp if (asBool(doNotPauseOnExceptionsAndMuteConsole)) muteConsole(); - injectedScript.evaluate(errorString, expression, objectGroup ? *objectGroup : "", asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), &result, wasThrown); + injectedScript.evaluate(errorString, expression, objectGroup ? *objectGroup : String(), asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), asBool(saveResult), &result, wasThrown, savedResultIndex); if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { unmuteConsole(); @@ -131,17 +134,17 @@ void InspectorRuntimeAgent::evaluate(ErrorString* errorString, const String& exp } } -void InspectorRuntimeAgent::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const RefPtr<InspectorArray>* const optionalArguments, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) +void InspectorRuntimeAgent::callFunctionOn(ErrorString& errorString, const String& objectId, const String& expression, const InspectorArray* optionalArguments, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown) { InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); if (injectedScript.hasNoValue()) { - *errorString = ASCIILiteral("Inspected frame has gone"); + errorString = ASCIILiteral("Inspected frame has gone"); return; } String arguments; if (optionalArguments) - arguments = (*optionalArguments)->toJSONString(); + arguments = optionalArguments->toJSONString(); ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = ScriptDebugServer::DontPauseOnExceptions; if (asBool(doNotPauseOnExceptionsAndMuteConsole)) @@ -157,40 +160,243 @@ void InspectorRuntimeAgent::callFunctionOn(ErrorString* errorString, const Strin } } -void InspectorRuntimeAgent::getProperties(ErrorString* errorString, const String& objectId, const bool* const ownProperties, const bool* const ownAndGetterProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties) +void InspectorRuntimeAgent::getProperties(ErrorString& errorString, const String& objectId, const bool* const ownProperties, const bool* const generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) +{ + InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) { + errorString = ASCIILiteral("Inspected frame has gone"); + return; + } + + ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions); + muteConsole(); + + injectedScript.getProperties(errorString, objectId, asBool(ownProperties), asBool(generatePreview), &result); + injectedScript.getInternalProperties(errorString, objectId, asBool(generatePreview), &internalProperties); + + unmuteConsole(); + setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState); +} + +void InspectorRuntimeAgent::getDisplayableProperties(ErrorString& errorString, const String& objectId, const bool* const generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) { InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); if (injectedScript.hasNoValue()) { - *errorString = ASCIILiteral("Inspected frame has gone"); + errorString = ASCIILiteral("Inspected frame has gone"); return; } ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions); muteConsole(); - injectedScript.getProperties(errorString, objectId, ownProperties ? *ownProperties : false, ownAndGetterProperties ? *ownAndGetterProperties : false, &result); - injectedScript.getInternalProperties(errorString, objectId, &internalProperties); + injectedScript.getDisplayableProperties(errorString, objectId, asBool(generatePreview), &result); + injectedScript.getInternalProperties(errorString, objectId, asBool(generatePreview), &internalProperties); unmuteConsole(); setPauseOnExceptionsState(m_scriptDebugServer, previousPauseOnExceptionsState); } -void InspectorRuntimeAgent::releaseObject(ErrorString*, const String& objectId) +void InspectorRuntimeAgent::getCollectionEntries(ErrorString& errorString, const String& objectId, const String* objectGroup, const int* startIndex, const int* numberToFetch, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::CollectionEntry>>& entries) +{ + InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) { + errorString = ASCIILiteral("Inspected frame has gone"); + return; + } + + int start = startIndex && *startIndex >= 0 ? *startIndex : 0; + int fetch = numberToFetch && *numberToFetch >= 0 ? *numberToFetch : 0; + + injectedScript.getCollectionEntries(errorString, objectId, objectGroup ? *objectGroup : String(), start, fetch, &entries); +} + +void InspectorRuntimeAgent::saveResult(ErrorString& errorString, const Inspector::InspectorObject& callArgument, const int* executionContextId, Inspector::Protocol::OptOutput<int>* savedResultIndex) +{ + InjectedScript injectedScript; + + String objectId; + if (callArgument.getString(ASCIILiteral("objectId"), objectId)) { + injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) { + errorString = ASCIILiteral("Inspected frame has gone"); + return; + } + } else { + injectedScript = injectedScriptForEval(errorString, executionContextId); + if (injectedScript.hasNoValue()) + return; + } + + injectedScript.saveResult(errorString, callArgument.toJSONString(), savedResultIndex); +} + +void InspectorRuntimeAgent::releaseObject(ErrorString&, const String& objectId) { InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); if (!injectedScript.hasNoValue()) injectedScript.releaseObject(objectId); } -void InspectorRuntimeAgent::releaseObjectGroup(ErrorString*, const String& objectGroup) +void InspectorRuntimeAgent::releaseObjectGroup(ErrorString&, const String& objectGroup) { m_injectedScriptManager->releaseObjectGroup(objectGroup); } -void InspectorRuntimeAgent::run(ErrorString*) +void InspectorRuntimeAgent::run(ErrorString&) { + // FIXME: <https://webkit.org/b/127634> Web Inspector: support debugging web workers } -} // namespace Inspector +void InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets(ErrorString& errorString, const Inspector::InspectorArray& locations, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>>& typeDescriptions) +{ + static const bool verbose = false; + VM& vm = globalVM(); + typeDescriptions = Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>::create(); + if (!vm.typeProfiler()) { + errorString = ASCIILiteral("The VM does not currently have Type Information."); + return; + } + + double start = currentTimeMS(); + vm.typeProfilerLog()->processLogEntries(ASCIILiteral("User Query")); + + for (size_t i = 0; i < locations.length(); i++) { + RefPtr<Inspector::InspectorValue> value = locations.get(i); + RefPtr<InspectorObject> location; + if (!value->asObject(location)) { + errorString = ASCIILiteral("Array of TypeLocation objects has an object that does not have type of TypeLocation."); + return; + } + + int descriptor; + String sourceIDAsString; + int divot; + location->getInteger(ASCIILiteral("typeInformationDescriptor"), descriptor); + location->getString(ASCIILiteral("sourceID"), sourceIDAsString); + location->getInteger(ASCIILiteral("divot"), divot); + + bool okay; + TypeLocation* typeLocation = vm.typeProfiler()->findLocation(divot, sourceIDAsString.toIntPtrStrict(&okay), static_cast<TypeProfilerSearchDescriptor>(descriptor), vm); + ASSERT(okay); + + RefPtr<TypeSet> typeSet; + if (typeLocation) { + if (typeLocation->m_globalTypeSet && typeLocation->m_globalVariableID != TypeProfilerNoGlobalIDExists) + typeSet = typeLocation->m_globalTypeSet; + else + typeSet = typeLocation->m_instructionTypeSet; + } + + bool isValid = typeLocation && typeSet && !typeSet->isEmpty(); + auto description = Inspector::Protocol::Runtime::TypeDescription::create() + .setIsValid(isValid) + .release(); + + if (isValid) { + description->setLeastCommonAncestor(typeSet->leastCommonAncestor()); + description->setStructures(typeSet->allStructureRepresentations()); + description->setTypeSet(typeSet->inspectorTypeSet()); + description->setIsTruncated(typeSet->isOverflown()); + } + + typeDescriptions->addItem(WTF::move(description)); + } -#endif // ENABLE(INSPECTOR) + double end = currentTimeMS(); + if (verbose) + dataLogF("Inspector::getRuntimeTypesForVariablesAtOffsets took %lfms\n", end - start); +} + +class TypeRecompiler : public MarkedBlock::VoidFunctor { +public: + inline void visit(JSCell* cell) + { + if (!cell->inherits(FunctionExecutable::info())) + return; + + FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell); + executable->clearCode(); + executable->clearUnlinkedCodeForRecompilation(); + } + inline IterationStatus operator()(JSCell* cell) + { + visit(cell); + return IterationStatus::Continue; + } +}; + +static void recompileAllJSFunctionsForTypeProfiling(VM& vm, bool shouldEnableTypeProfiling) +{ + bool shouldRecompileFromTypeProfiler = (shouldEnableTypeProfiling ? vm.enableTypeProfiler() : vm.disableTypeProfiler()); + bool shouldRecompileFromControlFlowProfiler = (shouldEnableTypeProfiling ? vm.enableControlFlowProfiler() : vm.disableControlFlowProfiler()); + bool needsToRecompile = shouldRecompileFromTypeProfiler || shouldRecompileFromControlFlowProfiler; + + if (needsToRecompile) { + vm.prepareToDiscardCode(); + TypeRecompiler recompiler; + HeapIterationScope iterationScope(vm.heap); + vm.heap.objectSpace().forEachLiveCell(iterationScope, recompiler); + } +} + +void InspectorRuntimeAgent::willDestroyFrontendAndBackend(DisconnectReason reason) +{ + if (reason != DisconnectReason::InspectedTargetDestroyed && m_isTypeProfilingEnabled) + setTypeProfilerEnabledState(false); +} + +void InspectorRuntimeAgent::enableTypeProfiler(ErrorString&) +{ + setTypeProfilerEnabledState(true); +} + +void InspectorRuntimeAgent::disableTypeProfiler(ErrorString&) +{ + setTypeProfilerEnabledState(false); +} + +void InspectorRuntimeAgent::setTypeProfilerEnabledState(bool shouldEnableTypeProfiling) +{ + if (m_isTypeProfilingEnabled == shouldEnableTypeProfiling) + return; + + m_isTypeProfilingEnabled = shouldEnableTypeProfiling; + + VM& vm = globalVM(); + + // If JavaScript is running, it's not safe to recompile, since we'll end + // up throwing away code that is live on the stack. + if (vm.entryScope) { + vm.entryScope->setEntryScopeDidPopListener(this, + [=] (VM& vm, JSGlobalObject*) { + recompileAllJSFunctionsForTypeProfiling(vm, shouldEnableTypeProfiling); + } + ); + } else + recompileAllJSFunctionsForTypeProfiling(vm, shouldEnableTypeProfiling); +} + +void InspectorRuntimeAgent::getBasicBlocks(ErrorString& errorString, const String& sourceIDAsString, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::BasicBlock>>& basicBlocks) +{ + VM& vm = globalVM(); + if (!vm.controlFlowProfiler()) { + errorString = ASCIILiteral("The VM does not currently have a Control Flow Profiler."); + return; + } + + bool okay; + intptr_t sourceID = sourceIDAsString.toIntPtrStrict(&okay); + ASSERT(okay); + const Vector<BasicBlockRange>& basicBlockRanges = vm.controlFlowProfiler()->getBasicBlocksForSourceID(sourceID, vm); + basicBlocks = Inspector::Protocol::Array<Inspector::Protocol::Runtime::BasicBlock>::create(); + for (const BasicBlockRange& block : basicBlockRanges) { + Ref<Inspector::Protocol::Runtime::BasicBlock> location = Inspector::Protocol::Runtime::BasicBlock::create() + .setStartOffset(block.m_startOffset) + .setEndOffset(block.m_endOffset) + .setHasExecuted(block.m_hasExecuted) + .release(); + basicBlocks->addItem(WTF::move(location)); + } +} + +} // namespace Inspector diff --git a/inspector/agents/InspectorRuntimeAgent.h b/inspector/agents/InspectorRuntimeAgent.h index faf4378..25f3d7c 100644 --- a/inspector/agents/InspectorRuntimeAgent.h +++ b/inspector/agents/InspectorRuntimeAgent.h @@ -32,10 +32,8 @@ #ifndef InspectorRuntimeAgent_h #define InspectorRuntimeAgent_h -#if ENABLE(INSPECTOR) - -#include "InspectorJSBackendDispatchers.h" -#include "InspectorJSFrontendDispatchers.h" +#include "InspectorBackendDispatchers.h" +#include "InspectorFrontendDispatchers.h" #include "inspector/InspectorAgentBase.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -52,21 +50,30 @@ class InspectorArray; class ScriptDebugServer; typedef String ErrorString; -class JS_EXPORT_PRIVATE InspectorRuntimeAgent : public InspectorAgentBase, public InspectorRuntimeBackendDispatcherHandler { +class JS_EXPORT_PRIVATE InspectorRuntimeAgent : public InspectorAgentBase, public RuntimeBackendDispatcherHandler { WTF_MAKE_NONCOPYABLE(InspectorRuntimeAgent); public: virtual ~InspectorRuntimeAgent(); - virtual void enable(ErrorString*) override { m_enabled = true; } - virtual void disable(ErrorString*) override { m_enabled = false; } - virtual void parse(ErrorString*, const String& expression, Inspector::TypeBuilder::Runtime::SyntaxErrorType::Enum* result, Inspector::TypeBuilder::OptOutput<String>* message, RefPtr<Inspector::TypeBuilder::Runtime::ErrorRange>&) override final; - virtual void evaluate(ErrorString*, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) override final; - virtual void callFunctionOn(ErrorString*, const String& objectId, const String& expression, const RefPtr<Inspector::InspectorArray>* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) override final; - virtual void releaseObject(ErrorString*, const ErrorString& objectId) override final; - virtual void getProperties(ErrorString*, const String& objectId, const bool* ownProperties, const bool* const ownAndGetterProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties) override final; - virtual void releaseObjectGroup(ErrorString*, const String& objectGroup) override final; - virtual void run(ErrorString*) override; - + virtual void willDestroyFrontendAndBackend(DisconnectReason) override; + + virtual void enable(ErrorString&) override { m_enabled = true; } + virtual void disable(ErrorString&) override { m_enabled = false; } + virtual void parse(ErrorString&, const String& expression, Inspector::Protocol::Runtime::SyntaxErrorType* result, Inspector::Protocol::OptOutput<String>* message, RefPtr<Inspector::Protocol::Runtime::ErrorRange>&) override final; + virtual void evaluate(ErrorString&, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex) override final; + virtual void callFunctionOn(ErrorString&, const String& objectId, const String& expression, const Inspector::InspectorArray* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown) override final; + virtual void releaseObject(ErrorString&, const ErrorString& objectId) override final; + virtual void getProperties(ErrorString&, const String& objectId, const bool* ownProperties, const bool* generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) override final; + virtual void getDisplayableProperties(ErrorString&, const String& objectId, const bool* generatePreview, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::InternalPropertyDescriptor>>& internalProperties) override final; + virtual void getCollectionEntries(ErrorString&, const String& objectId, const String* objectGroup, const int* startIndex, const int* numberToFetch, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::CollectionEntry>>& entries) override final; + virtual void saveResult(ErrorString&, const Inspector::InspectorObject& callArgument, const int* executionContextId, Inspector::Protocol::OptOutput<int>* savedResultIndex) override final; + virtual void releaseObjectGroup(ErrorString&, const String& objectGroup) override final; + virtual void run(ErrorString&) override; + virtual void getRuntimeTypesForVariablesAtOffsets(ErrorString&, const Inspector::InspectorArray& locations, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>>&) override; + virtual void enableTypeProfiler(ErrorString&) override; + virtual void disableTypeProfiler(ErrorString&) override; + virtual void getBasicBlocks(ErrorString&, const String& in_sourceID, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::BasicBlock>>& out_basicBlocks) override; + void setScriptDebugServer(ScriptDebugServer* scriptDebugServer) { m_scriptDebugServer = scriptDebugServer; } bool enabled() const { return m_enabled; } @@ -77,18 +84,20 @@ protected: InjectedScriptManager* injectedScriptManager() { return m_injectedScriptManager; } virtual JSC::VM& globalVM() = 0; - virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) = 0; + virtual InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) = 0; virtual void muteConsole() = 0; virtual void unmuteConsole() = 0; private: + void setTypeProfilerEnabledState(bool); + InjectedScriptManager* m_injectedScriptManager; ScriptDebugServer* m_scriptDebugServer; bool m_enabled; + bool m_isTypeProfilingEnabled; }; } // namespace Inspector -#endif // ENABLE(INSPECTOR) #endif // InspectorRuntimeAgent_h diff --git a/inspector/agents/JSGlobalObjectConsoleAgent.cpp b/inspector/agents/JSGlobalObjectConsoleAgent.cpp index fad5075..fe112dd 100644 --- a/inspector/agents/JSGlobalObjectConsoleAgent.cpp +++ b/inspector/agents/JSGlobalObjectConsoleAgent.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "JSGlobalObjectConsoleAgent.h" -#if ENABLE(INSPECTOR) - namespace Inspector { JSGlobalObjectConsoleAgent::JSGlobalObjectConsoleAgent(InjectedScriptManager* injectedScriptManager) @@ -35,16 +33,14 @@ JSGlobalObjectConsoleAgent::JSGlobalObjectConsoleAgent(InjectedScriptManager* in { } -void JSGlobalObjectConsoleAgent::setMonitoringXHREnabled(ErrorString* errorString, bool) +void JSGlobalObjectConsoleAgent::setMonitoringXHREnabled(ErrorString& errorString, bool) { - *errorString = ASCIILiteral("Not supported for JavaScript context"); + errorString = ASCIILiteral("Not supported for JavaScript context"); } -void JSGlobalObjectConsoleAgent::addInspectedNode(ErrorString* errorString, int) +void JSGlobalObjectConsoleAgent::addInspectedNode(ErrorString& errorString, int) { - *errorString = ASCIILiteral("Not supported for JavaScript context"); + errorString = ASCIILiteral("Not supported for JavaScript context"); } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/agents/JSGlobalObjectConsoleAgent.h b/inspector/agents/JSGlobalObjectConsoleAgent.h index 7aa48de..0d79c5d 100644 --- a/inspector/agents/JSGlobalObjectConsoleAgent.h +++ b/inspector/agents/JSGlobalObjectConsoleAgent.h @@ -26,8 +26,6 @@ #ifndef JSGlobalObjectConsoleAgent_h #define JSGlobalObjectConsoleAgent_h -#if ENABLE(INSPECTOR) - #include "InspectorConsoleAgent.h" #include "JSGlobalObjectScriptDebugServer.h" @@ -41,14 +39,12 @@ public: virtual ~JSGlobalObjectConsoleAgent() { } // FIXME: XHRs and Nodes only makes sense debugging a Web context. Can this be moved to a different agent? - virtual void setMonitoringXHREnabled(ErrorString*, bool enabled) override; - virtual void addInspectedNode(ErrorString*, int nodeId) override; + virtual void setMonitoringXHREnabled(ErrorString&, bool enabled) override; + virtual void addInspectedNode(ErrorString&, int nodeId) override; virtual bool isWorkerAgent() const override { return false; } }; } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSGlobalObjectConsoleAgent_h) diff --git a/inspector/agents/JSGlobalObjectDebuggerAgent.cpp b/inspector/agents/JSGlobalObjectDebuggerAgent.cpp index c087e81..9ae76c6 100644 --- a/inspector/agents/JSGlobalObjectDebuggerAgent.cpp +++ b/inspector/agents/JSGlobalObjectDebuggerAgent.cpp @@ -26,8 +26,7 @@ #include "config.h" #include "JSGlobalObjectDebuggerAgent.h" -#if ENABLE(INSPECTOR) - +#include "ConsoleMessage.h" #include "InjectedScriptManager.h" #include "InspectorConsoleAgent.h" #include "JSGlobalObject.h" @@ -56,10 +55,10 @@ void JSGlobalObjectDebuggerAgent::stopListeningScriptDebugServer(bool isBeingDes scriptDebugServer().removeListener(this, isBeingDestroyed); } -InjectedScript JSGlobalObjectDebuggerAgent::injectedScriptForEval(ErrorString* error, const int* executionContextId) +InjectedScript JSGlobalObjectDebuggerAgent::injectedScriptForEval(ErrorString& error, const int* executionContextId) { if (executionContextId) { - *error = ASCIILiteral("Execution context id is not supported for JSContext inspection as there is only one execution context."); + error = ASCIILiteral("Execution context id is not supported for JSContext inspection as there is only one execution context."); return InjectedScript(); } @@ -69,9 +68,7 @@ InjectedScript JSGlobalObjectDebuggerAgent::injectedScriptForEval(ErrorString* e void JSGlobalObjectDebuggerAgent::breakpointActionLog(JSC::ExecState* exec, const String& message) { - m_consoleAgent->addMessageToConsole(MessageSource::JS, MessageType::Log, MessageLevel::Log, message, createScriptCallStack(exec, ScriptCallStack::maxCallStackSizeToCapture), 0); + m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Log, message, createScriptCallStack(exec, ScriptCallStack::maxCallStackSizeToCapture), 0)); } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/agents/JSGlobalObjectDebuggerAgent.h b/inspector/agents/JSGlobalObjectDebuggerAgent.h index 27ee6ac..ac6b871 100644 --- a/inspector/agents/JSGlobalObjectDebuggerAgent.h +++ b/inspector/agents/JSGlobalObjectDebuggerAgent.h @@ -26,8 +26,6 @@ #ifndef JSGlobalObjectDebuggerAgent_h #define JSGlobalObjectDebuggerAgent_h -#if ENABLE(INSPECTOR) - #include "InspectorDebuggerAgent.h" #include "JSGlobalObjectScriptDebugServer.h" @@ -46,7 +44,7 @@ public: virtual void startListeningScriptDebugServer() override; virtual void stopListeningScriptDebugServer(bool isBeingDestroyed) override; - virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) override; + virtual InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) override; virtual void breakpointActionLog(JSC::ExecState*, const String&) override; @@ -62,6 +60,4 @@ private: } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSGlobalObjectDebuggerAgent_h) diff --git a/inspector/agents/JSGlobalObjectRuntimeAgent.cpp b/inspector/agents/JSGlobalObjectRuntimeAgent.cpp index 126189e..46049f5 100644 --- a/inspector/agents/JSGlobalObjectRuntimeAgent.cpp +++ b/inspector/agents/JSGlobalObjectRuntimeAgent.cpp @@ -26,8 +26,6 @@ #include "config.h" #include "JSGlobalObjectRuntimeAgent.h" -#if ENABLE(INSPECTOR) - #include "InjectedScript.h" #include "InjectedScriptManager.h" #include "JSGlobalObject.h" @@ -42,16 +40,18 @@ JSGlobalObjectRuntimeAgent::JSGlobalObjectRuntimeAgent(InjectedScriptManager* in { } -void JSGlobalObjectRuntimeAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) +void JSGlobalObjectRuntimeAgent::didCreateFrontendAndBackend(FrontendChannel* frontendChannel, BackendDispatcher* backendDispatcher) { - m_frontendDispatcher = std::make_unique<InspectorRuntimeFrontendDispatcher>(frontendChannel); - m_backendDispatcher = InspectorRuntimeBackendDispatcher::create(backendDispatcher, this); + m_frontendDispatcher = std::make_unique<RuntimeFrontendDispatcher>(frontendChannel); + m_backendDispatcher = RuntimeBackendDispatcher::create(backendDispatcher, this); } -void JSGlobalObjectRuntimeAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) +void JSGlobalObjectRuntimeAgent::willDestroyFrontendAndBackend(DisconnectReason reason) { m_frontendDispatcher = nullptr; - m_backendDispatcher.clear(); + m_backendDispatcher = nullptr; + + InspectorRuntimeAgent::willDestroyFrontendAndBackend(reason); } VM& JSGlobalObjectRuntimeAgent::globalVM() @@ -59,18 +59,16 @@ VM& JSGlobalObjectRuntimeAgent::globalVM() return m_globalObject.vm(); } -InjectedScript JSGlobalObjectRuntimeAgent::injectedScriptForEval(ErrorString* errorString, const int* executionContextId) +InjectedScript JSGlobalObjectRuntimeAgent::injectedScriptForEval(ErrorString& errorString, const int* executionContextId) { ASSERT_UNUSED(executionContextId, !executionContextId); JSC::ExecState* scriptState = m_globalObject.globalExec(); InjectedScript injectedScript = injectedScriptManager()->injectedScriptFor(scriptState); if (injectedScript.hasNoValue()) - *errorString = ASCIILiteral("Internal error: main world execution context not found."); + errorString = ASCIILiteral("Internal error: main world execution context not found."); return injectedScript; } } // namespace Inspector - -#endif // ENABLE(INSPECTOR) diff --git a/inspector/agents/JSGlobalObjectRuntimeAgent.h b/inspector/agents/JSGlobalObjectRuntimeAgent.h index 0e72e09..631baec 100644 --- a/inspector/agents/JSGlobalObjectRuntimeAgent.h +++ b/inspector/agents/JSGlobalObjectRuntimeAgent.h @@ -26,10 +26,7 @@ #ifndef JSGlobalObjectRuntimeAgent_h #define JSGlobalObjectRuntimeAgent_h -#if ENABLE(INSPECTOR) - #include "InspectorRuntimeAgent.h" -#include <wtf/PassOwnPtr.h> namespace JSC { class JSGlobalObject; @@ -41,11 +38,11 @@ class JSGlobalObjectRuntimeAgent final : public InspectorRuntimeAgent { public: JSGlobalObjectRuntimeAgent(InjectedScriptManager*, JSC::JSGlobalObject&); - virtual void didCreateFrontendAndBackend(InspectorFrontendChannel*, InspectorBackendDispatcher*) override; - virtual void willDestroyFrontendAndBackend(InspectorDisconnectReason) override; + virtual void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher*) override; + virtual void willDestroyFrontendAndBackend(DisconnectReason) override; virtual JSC::VM& globalVM() override; - virtual InjectedScript injectedScriptForEval(ErrorString*, const int* executionContextId) override; + virtual InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) override; // NOTE: JavaScript inspector does not yet need to mute a console because no messages // are sent to the console outside of the API boundary or console object. @@ -53,13 +50,11 @@ public: virtual void unmuteConsole() override { } private: - std::unique_ptr<InspectorRuntimeFrontendDispatcher> m_frontendDispatcher; - RefPtr<InspectorRuntimeBackendDispatcher> m_backendDispatcher; + std::unique_ptr<RuntimeFrontendDispatcher> m_frontendDispatcher; + RefPtr<RuntimeBackendDispatcher> m_backendDispatcher; JSC::JSGlobalObject& m_globalObject; }; } // namespace Inspector -#endif // ENABLE(INSPECTOR) - #endif // !defined(JSGlobalObjectRuntimeAgent_h) diff --git a/inspector/augmentable/AlternateDispatchableAgent.h b/inspector/augmentable/AlternateDispatchableAgent.h new file mode 100644 index 0000000..5ff0353 --- /dev/null +++ b/inspector/augmentable/AlternateDispatchableAgent.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 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 AlternateDispatchableAgent_h +#define AlternateDispatchableAgent_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include "InspectorAlternateBackendDispatchers.h" +#include "InspectorBackendDispatchers.h" +#include <JavaScriptCore/InspectorAgentBase.h> +#include <wtf/Forward.h> + +namespace Inspector { + +template<typename TBackendDispatcher, typename TAlternateDispatcher> +class AlternateDispatchableAgent final : public InspectorAgentBase { + WTF_MAKE_FAST_ALLOCATED; +public: + AlternateDispatchableAgent(const String& domainName, std::unique_ptr<TAlternateDispatcher> alternateDispatcher) + : InspectorAgentBase(domainName) + , m_alternateDispatcher(WTF::move(alternateDispatcher)) + { + } + + virtual void didCreateFrontendAndBackend(FrontendChannel*, BackendDispatcher* backendDispatcher) override + { + m_backendDispatcher = TBackendDispatcher::create(backendDispatcher, nullptr); + m_backendDispatcher->setAlternateDispatcher(m_alternateDispatcher.get()); + m_alternateDispatcher->setBackendDispatcher(backendDispatcher); + } + + virtual void willDestroyFrontendAndBackend(DisconnectReason) override + { + m_backendDispatcher = nullptr; + m_alternateDispatcher->setBackendDispatcher(nullptr); + } + +private: + std::unique_ptr<TAlternateDispatcher> m_alternateDispatcher; + RefPtr<TBackendDispatcher> m_backendDispatcher; +}; + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // AlternateDispatchableAgent_h diff --git a/inspector/augmentable/AugmentableInspectorController.h b/inspector/augmentable/AugmentableInspectorController.h new file mode 100644 index 0000000..2456ac5 --- /dev/null +++ b/inspector/augmentable/AugmentableInspectorController.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 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 AugmentableInspectorController_h +#define AugmentableInspectorController_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include <JavaScriptCore/AugmentableInspectorControllerClient.h> +#include <JavaScriptCore/InspectorFrontendChannel.h> + +namespace Inspector { + +class InspectorAgentBase; + +class AugmentableInspectorController { +public: + virtual ~AugmentableInspectorController() { } + + virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const = 0; + virtual void setAugmentableInspectorControllerClient(AugmentableInspectorControllerClient*) = 0; + + virtual FrontendChannel* frontendChannel() const = 0; + virtual void appendExtraAgent(std::unique_ptr<InspectorAgentBase>) = 0; + + bool connected() const { return !!frontendChannel(); } +}; + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(AugmentableInspectorController_h) diff --git a/inspector/agents/JSGlobalObjectProfilerAgent.cpp b/inspector/augmentable/AugmentableInspectorControllerClient.h similarity index 75% rename from inspector/agents/JSGlobalObjectProfilerAgent.cpp rename to inspector/augmentable/AugmentableInspectorControllerClient.h index 8026b9a..fef1cf9 100644 --- a/inspector/agents/JSGlobalObjectProfilerAgent.cpp +++ b/inspector/augmentable/AugmentableInspectorControllerClient.h @@ -23,28 +23,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "JSGlobalObjectProfilerAgent.h" +#ifndef AugmentableInspectorControllerClient_h +#define AugmentableInspectorControllerClient_h -#if ENABLE(INSPECTOR) - -#include "JSGlobalObject.h" - -using namespace JSC; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) namespace Inspector { -JSGlobalObjectProfilerAgent::JSGlobalObjectProfilerAgent(JSGlobalObject& globalObject) - : InspectorProfilerAgent() - , m_globalObject(globalObject) -{ -} - -ExecState* JSGlobalObjectProfilerAgent::profilingGlobalExecState() const -{ - return m_globalObject.globalExec(); -} +class AugmentableInspectorControllerClient { +public: + virtual ~AugmentableInspectorControllerClient() { } + virtual void inspectorConnected() = 0; + virtual void inspectorDisconnected() = 0; +}; } // namespace Inspector -#endif // ENABLE(INSPECTOR) +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(AugmentableInspectorControllerClient_h) diff --git a/inspector/protocol/ApplicationCache.json b/inspector/protocol/ApplicationCache.json new file mode 100644 index 0000000..86a984a --- /dev/null +++ b/inspector/protocol/ApplicationCache.json @@ -0,0 +1,87 @@ +{ + "domain": "ApplicationCache", + "availability": "web", + "types": [ + { + "id": "ApplicationCacheResource", + "type": "object", + "description": "Detailed application cache resource information.", + "properties": [ + { "name": "url", "type": "string", "description": "Resource url." }, + { "name": "size", "type": "integer", "description": "Resource size." }, + { "name": "type", "type": "string", "description": "Resource type." } + ] + }, + { + "id": "ApplicationCache", + "type": "object", + "description": "Detailed application cache information.", + "properties": [ + { "name": "manifestURL", "type": "string", "description": "Manifest URL." }, + { "name": "size", "type": "number", "description": "Application cache size." }, + { "name": "creationTime", "type": "number", "description": "Application cache creation time." }, + { "name": "updateTime", "type": "number", "description": "Application cache update time." }, + { "name": "resources", "type": "array", "items": { "$ref": "ApplicationCacheResource" }, "description": "Application cache resources." } + ] + }, + { + "id": "FrameWithManifest", + "type": "object", + "description": "Frame identifier - manifest URL pair.", + "properties": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Frame identifier." }, + { "name": "manifestURL", "type": "string", "description": "Manifest URL." }, + { "name": "status", "type": "integer", "description": "Application cache status." } + ] + } + ], + "commands": [ + { + "name": "getFramesWithManifests", + "returns": [ + { "name": "frameIds", "type": "array", "items": { "$ref": "FrameWithManifest" }, "description": "Array of frame identifiers with manifest urls for each frame containing a document associated with some application cache." } + ], + "description": "Returns array of frame identifiers with manifest urls for each frame containing a document associated with some application cache." + }, + { + "name": "enable", + "description": "Enables application cache domain notifications." + }, + { + "name": "getManifestForFrame", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Identifier of the frame containing document whose manifest is retrieved." } + ], + "returns": [ + { "name": "manifestURL", "type": "string", "description": "Manifest URL for document in the given frame." } + ], + "description": "Returns manifest URL for document in the given frame." + }, + { + "name": "getApplicationCacheForFrame", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Identifier of the frame containing document whose application cache is retrieved." } + ], + "returns": [ + { "name": "applicationCache", "$ref": "ApplicationCache", "description": "Relevant application cache data for the document in given frame." } + ], + "description": "Returns relevant application cache data for the document in given frame." + } + ], + "events": [ + { + "name": "applicationCacheStatusUpdated", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Identifier of the frame containing document whose application cache updated status." }, + { "name": "manifestURL", "type": "string", "description": "Manifest URL." }, + { "name": "status", "type": "integer", "description": "Updated application cache status." } + ] + }, + { + "name": "networkStateUpdated", + "parameters": [ + { "name": "isNowOnline", "type": "boolean" } + ] + } + ] +} diff --git a/inspector/protocol/CSS.json b/inspector/protocol/CSS.json new file mode 100644 index 0000000..f02216d --- /dev/null +++ b/inspector/protocol/CSS.json @@ -0,0 +1,423 @@ +{ + "domain": "CSS", + "description": "This domain exposes CSS read/write operations. All CSS objects, like stylesheets, rules, and styles, have an associated <code>id</code> used in subsequent operations on the related object. Each object type has a specific <code>id</code> structure, and those are not interchangeable between objects of different kinds. CSS objects can be loaded using the <code>get*ForNode()</code> calls (which accept a DOM node id). Alternatively, a client can discover all the existing stylesheets with the <code>getAllStyleSheets()</code> method and subsequently load the required stylesheet contents using the <code>getStyleSheet[Text]()</code> methods.", + "availability": "web", + "types": [ + { + "id": "StyleSheetId", + "type": "string" + }, + { + "id": "CSSStyleId", + "type": "object", + "properties": [ + { "name": "styleSheetId", "$ref": "StyleSheetId", "description": "Enclosing stylesheet identifier." }, + { "name": "ordinal", "type": "integer", "description": "The style ordinal within the stylesheet." } + ], + "description": "This object identifies a CSS style in a unique way." + }, + { + "id": "StyleSheetOrigin", + "type": "string", + "enum": ["user", "user-agent", "inspector", "regular"], + "description": "Stylesheet type: \"user\" for user stylesheets, \"user-agent\" for user-agent stylesheets, \"inspector\" for stylesheets created by the inspector (i.e. those holding the \"via inspector\" rules), \"regular\" for regular stylesheets." + }, + { + "id": "CSSRuleId", + "type": "object", + "properties": [ + { "name": "styleSheetId", "$ref": "StyleSheetId", "description": "Enclosing stylesheet identifier." }, + { "name": "ordinal", "type": "integer", "description": "The rule ordinal within the stylesheet." } + ], + "description": "This object identifies a CSS rule in a unique way." + }, + { + "id": "PseudoIdMatches", + "type": "object", + "properties": [ + { "name": "pseudoId", "type": "integer", "description": "Pseudo style identifier (see <code>enum PseudoId</code> in <code>RenderStyleConstants.h</code>)."}, + { "name": "matches", "type": "array", "items": { "$ref": "RuleMatch" }, "description": "Matches of CSS rules applicable to the pseudo style."} + ], + "description": "CSS rule collection for a single pseudo style." + }, + { + "id": "InheritedStyleEntry", + "type": "object", + "properties": [ + { "name": "inlineStyle", "$ref": "CSSStyle", "optional": true, "description": "The ancestor node's inline style, if any, in the style inheritance chain." }, + { "name": "matchedCSSRules", "type": "array", "items": { "$ref": "RuleMatch" }, "description": "Matches of CSS rules matching the ancestor node in the style inheritance chain." } + ], + "description": "CSS rule collection for a single pseudo style." + }, + { + "id": "RuleMatch", + "type": "object", + "properties": [ + { "name": "rule", "$ref": "CSSRule", "description": "CSS rule in the match." }, + { "name": "matchingSelectors", "type": "array", "items": { "type": "integer" }, "description": "Matching selector indices in the rule's selectorList selectors (0-based)." } + ], + "description": "Match data for a CSS rule." + }, + { + "id": "CSSSelector", + "type": "object", + "properties": [ + { "name": "text", "type": "string", "description": "Canonicalized selector text." }, + { "name": "specificity", "optional": true, "type": "array", "items": { "type": "integer" }, "description": "Specificity (a, b, c) tuple. Included if the selector is sent in response to CSS.getMatchedStylesForNode which provides a context element." }, + { "name": "dynamic", "optional": true, "type": "boolean", "description": "Whether or not the specificity can be dynamic. Included if the selector is sent in response to CSS.getMatchedStylesForNode which provides a context element." } + ], + "description": "CSS selector." + }, + { + "id": "SelectorList", + "type": "object", + "properties": [ + { "name": "selectors", "type": "array", "items": { "$ref": "CSSSelector" }, "description": "Selectors in the list." }, + { "name": "text", "type": "string", "description": "Rule selector text." }, + { "name": "range", "$ref": "SourceRange", "optional": true, "description": "Rule selector range in the underlying resource (if available)." } + ], + "description": "Selector list data." + }, + { + "id": "CSSStyleAttribute", + "type": "object", + "properties": [ + { "name": "name", "type": "string", "description": "DOM attribute name (e.g. \"width\")."}, + { "name": "style", "$ref": "CSSStyle", "description": "CSS style generated by the respective DOM attribute."} + ], + "description": "CSS style information for a DOM style attribute." + }, + { + "id": "CSSStyleSheetHeader", + "type": "object", + "properties": [ + { "name": "styleSheetId", "$ref": "StyleSheetId", "description": "The stylesheet identifier."}, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Owner frame identifier."}, + { "name": "sourceURL", "type": "string", "description": "Stylesheet resource URL."}, + { "name": "origin", "$ref": "StyleSheetOrigin", "description": "Stylesheet origin."}, + { "name": "title", "type": "string", "description": "Stylesheet title."}, + { "name": "disabled", "type": "boolean", "description": "Denotes whether the stylesheet is disabled."} + ], + "description": "CSS stylesheet metainformation." + }, + { + "id": "CSSStyleSheetBody", + "type": "object", + "properties": [ + { "name": "styleSheetId", "$ref": "StyleSheetId", "description": "The stylesheet identifier."}, + { "name": "rules", "type": "array", "items": { "$ref": "CSSRule" }, "description": "Stylesheet resource URL."}, + { "name": "text", "type": "string", "optional": true, "description": "Stylesheet resource contents (if available)."} + ], + "description": "CSS stylesheet contents." + }, + { + "id": "CSSRule", + "type": "object", + "properties": [ + { "name": "ruleId", "$ref": "CSSRuleId", "optional": true, "description": "The CSS rule identifier (absent for user agent stylesheet and user-specified stylesheet rules)."}, + { "name": "selectorList", "$ref": "SelectorList", "description": "Rule selector data." }, + { "name": "sourceURL", "type": "string", "optional": true, "description": "Parent stylesheet resource URL (for regular rules)."}, + { "name": "sourceLine", "type": "integer", "description": "Line ordinal of the rule selector start character in the resource."}, + { "name": "origin", "$ref": "StyleSheetOrigin", "description": "Parent stylesheet's origin."}, + { "name": "style", "$ref": "CSSStyle", "description": "Associated style declaration." }, + { "name": "media", "type": "array", "items": { "$ref": "CSSMedia" }, "optional": true, "description": "Media list array (for rules involving media queries). The array enumerates media queries starting with the innermost one, going outwards." } + ], + "description": "CSS rule representation." + }, + { + "id": "SourceRange", + "type": "object", + "properties": [ + { "name": "startLine", "type": "integer", "description": "Start line of range." }, + { "name": "startColumn", "type": "integer", "description": "Start column of range (inclusive)." }, + { "name": "endLine", "type": "integer", "description": "End line of range" }, + { "name": "endColumn", "type": "integer", "description": "End column of range (exclusive)." } + ], + "description": "Text range within a resource." + }, + { + "id": "ShorthandEntry", + "type": "object", + "properties": [ + { "name": "name", "type": "string", "description": "Shorthand name." }, + { "name": "value", "type": "string", "description": "Shorthand value." } + ] + }, + { + "id": "CSSPropertyInfo", + "type": "object", + "properties": [ + { "name": "name", "type": "string", "description": "Property name." }, + { "name": "longhands", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Longhand property names." }, + { "name": "values", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Supported values for this property." } + ] + }, + { + "id": "CSSComputedStyleProperty", + "type": "object", + "properties": [ + { "name": "name", "type": "string", "description": "Computed style property name." }, + { "name": "value", "type": "string", "description": "Computed style property value." } + ] + }, + { + "id": "CSSStyle", + "type": "object", + "properties": [ + { "name": "styleId", "$ref": "CSSStyleId", "optional": true, "description": "The CSS style identifier (absent for attribute styles)." }, + { "name": "cssProperties", "type": "array", "items": { "$ref": "CSSProperty" }, "description": "CSS properties in the style." }, + { "name": "shorthandEntries", "type": "array", "items": { "$ref": "ShorthandEntry" }, "description": "Computed values for all shorthands found in the style." }, + { "name": "cssText", "type": "string", "optional": true, "description": "Style declaration text (if available)." }, + { "name": "range", "$ref": "SourceRange", "optional": true, "description": "Style declaration range in the enclosing stylesheet (if available)." }, + { "name": "width", "type": "string", "optional": true, "description": "The effective \"width\" property value from this style." }, + { "name": "height", "type": "string", "optional": true, "description": "The effective \"height\" property value from this style." } + ], + "description": "CSS style representation." + }, + { + "id": "CSSPropertyStatus", + "type": "string", + "enum": ["active", "inactive", "disabled", "style"], + "description": "The property status: \"active\" if the property is effective in the style, \"inactive\" if the property is overridden by a same-named property in this style later on, \"disabled\" if the property is disabled by the user, \"style\" (implied if absent) if the property is reported by the browser rather than by the CSS source parser." + }, + { + "id": "CSSProperty", + "type": "object", + "properties": [ + { "name": "name", "type": "string", "description": "The property name." }, + { "name": "value", "type": "string", "description": "The property value." }, + { "name": "priority", "type": "string", "optional": true, "description": "The property priority (implies \"\" if absent)." }, + { "name": "implicit", "type": "boolean", "optional": true, "description": "Whether the property is implicit (implies <code>false</code> if absent)." }, + { "name": "text", "type": "string", "optional": true, "description": "The full property text as specified in the style." }, + { "name": "parsedOk", "type": "boolean", "optional": true, "description": "Whether the property is understood by the browser (implies <code>true</code> if absent)." }, + { "name": "status", "$ref": "CSSPropertyStatus", "optional": true, "description": "Whether the property is active or disabled." }, + { "name": "range", "$ref": "SourceRange", "optional": true, "description": "The entire property range in the enclosing style declaration (if available)." } + ], + "description": "CSS style effective visual dimensions and source offsets." + }, + { + "id": "CSSMedia", + "type": "object", + "properties": [ + { "name": "text", "type": "string", "description": "Media query text." }, + { "name": "source", "type": "string", "enum": ["mediaRule", "importRule", "linkedSheet", "inlineSheet"], "description": "Source of the media query: \"mediaRule\" if specified by a @media rule, \"importRule\" if specified by an @import rule, \"linkedSheet\" if specified by a \"media\" attribute in a linked stylesheet's LINK tag, \"inlineSheet\" if specified by a \"media\" attribute in an inline stylesheet's STYLE tag." }, + { "name": "sourceURL", "type": "string", "optional": true, "description": "URL of the document containing the media query description." }, + { "name": "sourceLine", "type": "integer", "optional": true, "description": "Line in the document containing the media query (not defined for the \"stylesheet\" source)." } + ], + "description": "CSS media query descriptor." + }, + { + "id": "Region", + "type": "object", + "properties": [ + { "name": "regionOverset", "type": "string", "enum": ["overset", "fit", "empty"], "description": "The \"overset\" attribute of a Named Flow." }, + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "The corresponding DOM node id." } + ], + "description": "This object represents a region that flows from a Named Flow." + }, + { + "id": "NamedFlow", + "type": "object", + "properties": [ + { "name": "documentNodeId", "$ref": "DOM.NodeId", "description": "The document node id." }, + { "name": "name", "type": "string", "description": "Named Flow identifier." }, + { "name": "overset", "type": "boolean", "description": "The \"overset\" attribute of a Named Flow." }, + { "name": "content", "type": "array", "items": { "$ref": "DOM.NodeId" }, "description": "An array of nodes that flow into the Named Flow." }, + { "name": "regions", "type": "array", "items": { "$ref": "Region" }, "description": "An array of regions associated with the Named Flow." } + ], + "description": "This object represents a Named Flow." + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables the CSS agent for the given page. Clients should not assume that the CSS agent has been enabled until the result of this command is received." + }, + { + "name": "disable", + "description": "Disables the CSS agent for the given page." + }, + { + "name": "getMatchedStylesForNode", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId" }, + { "name": "includePseudo", "type": "boolean", "optional": true, "description": "Whether to include pseudo styles (default: true)." }, + { "name": "includeInherited", "type": "boolean", "optional": true, "description": "Whether to include inherited styles (default: true)." } + ], + "returns": [ + { "name": "matchedCSSRules", "type": "array", "items": { "$ref": "RuleMatch" }, "optional": true, "description": "CSS rules matching this node, from all applicable stylesheets." }, + { "name": "pseudoElements", "type": "array", "items": { "$ref": "PseudoIdMatches" }, "optional": true, "description": "Pseudo style matches for this node." }, + { "name": "inherited", "type": "array", "items": { "$ref": "InheritedStyleEntry" }, "optional": true, "description": "A chain of inherited styles (from the immediate node parent up to the DOM tree root)." } + ], + "description": "Returns requested styles for a DOM node identified by <code>nodeId</code>." + }, + { + "name": "getInlineStylesForNode", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId" } + ], + "returns": [ + { "name": "inlineStyle", "$ref": "CSSStyle", "optional": true, "description": "Inline style for the specified DOM node." }, + { "name": "attributesStyle", "$ref": "CSSStyle", "optional": true, "description": "Attribute-defined element style (e.g. resulting from \"width=20 height=100%\")."} + ], + "description": "Returns the styles defined inline (explicitly in the \"style\" attribute and implicitly, using DOM attributes) for a DOM node identified by <code>nodeId</code>." + }, + { + "name": "getComputedStyleForNode", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId" } + ], + "returns": [ + { "name": "computedStyle", "type": "array", "items": { "$ref": "CSSComputedStyleProperty" }, "description": "Computed style for the specified DOM node." } + ], + "description": "Returns the computed style for a DOM node identified by <code>nodeId</code>." + }, + { + "name": "getAllStyleSheets", + "returns": [ + { "name": "headers", "type": "array", "items": { "$ref": "CSSStyleSheetHeader" }, "description": "Descriptor entries for all available stylesheets." } + ], + "description": "Returns metainfo entries for all known stylesheets." + }, + { + "name": "getStyleSheet", + "parameters": [ + { "name": "styleSheetId", "$ref": "StyleSheetId" } + ], + "returns": [ + { "name": "styleSheet", "$ref": "CSSStyleSheetBody", "description": "Stylesheet contents for the specified <code>styleSheetId</code>." } + ], + "description": "Returns stylesheet data for the specified <code>styleSheetId</code>." + }, + { + "name": "getStyleSheetText", + "parameters": [ + { "name": "styleSheetId", "$ref": "StyleSheetId" } + ], + "returns": [ + { "name": "text", "type": "string", "description": "The stylesheet text." } + ], + "description": "Returns the current textual content and the URL for a stylesheet." + }, + { + "name": "setStyleSheetText", + "parameters": [ + { "name": "styleSheetId", "$ref": "StyleSheetId" }, + { "name": "text", "type": "string" } + ], + "description": "Sets the new stylesheet text, thereby invalidating all existing <code>CSSStyleId</code>'s and <code>CSSRuleId</code>'s contained by this stylesheet." + }, + { + "name": "setStyleText", + "parameters": [ + { "name": "styleId", "$ref": "CSSStyleId" }, + { "name": "text", "type": "string" } + ], + "returns": [ + { "name": "style", "$ref": "CSSStyle", "description": "The resulting style after the text modification." } + ], + "description": "Sets the new <code>text</code> for the respective style." + }, + { + "name": "setRuleSelector", + "parameters": [ + { "name": "ruleId", "$ref": "CSSRuleId" }, + { "name": "selector", "type": "string" } + ], + "returns": [ + { "name": "rule", "$ref": "CSSRule", "description": "The resulting rule after the selector modification." } + ], + "description": "Modifies the rule selector." + }, + { + "name": "addRule", + "parameters": [ + { "name": "contextNodeId", "$ref": "DOM.NodeId" }, + { "name": "selector", "type": "string" } + ], + "returns": [ + { "name": "rule", "$ref": "CSSRule", "description": "The newly created rule." } + ], + "description": "Creates a new empty rule with the given <code>selector</code> in a special \"inspector\" stylesheet in the owner document of the context node." + }, + { + "name": "getSupportedCSSProperties", + "returns": [ + { "name": "cssProperties", "type": "array", "items": { "$ref": "CSSPropertyInfo" }, "description": "Supported property metainfo." } + ], + "description": "Returns all supported CSS property names." + }, + { + "name": "forcePseudoState", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "The element id for which to force the pseudo state." }, + { "name": "forcedPseudoClasses", "type": "array", "items": { "type": "string", "enum": ["active", "focus", "hover", "visited"] }, "description": "Element pseudo classes to force when computing the element's style." } + ], + "description": "Ensures that the given node will have specified pseudo-classes whenever its style is computed by the browser." + }, + { + "name": "getNamedFlowCollection", + "parameters": [ + { "name": "documentNodeId", "$ref": "DOM.NodeId", "description": "The document node id for which to get the Named Flow Collection." } + ], + "returns": [ + { "name": "namedFlows", "type": "array", "items": { "$ref": "NamedFlow" }, "description": "An array containing the Named Flows in the document." } + ], + "description": "Returns the Named Flows from the document." + } + ], + "events": [ + { + "name": "mediaQueryResultChanged", + "description": "Fires whenever a MediaQuery result changes (for example, after a browser window has been resized.) The current implementation considers only viewport-dependent media features." + }, + { + "name": "styleSheetChanged", + "parameters": [ + { "name": "styleSheetId", "$ref": "StyleSheetId" } + ], + "description": "Fired whenever a stylesheet is changed as a result of the client operation." + }, + { + "name": "namedFlowCreated", + "parameters": [ + { "name": "namedFlow", "$ref": "NamedFlow", "description": "The new Named Flow." } + ], + "description": "Fires when a Named Flow is created." + }, + { + "name": "namedFlowRemoved", + "parameters": [ + { "name": "documentNodeId", "$ref": "DOM.NodeId", "description": "The document node id." }, + { "name": "flowName", "type": "string", "description": "Identifier of the removed Named Flow." } + ], + "description": "Fires when a Named Flow is removed: has no associated content nodes and regions." + }, + { + "name": "regionOversetChanged", + "parameters": [ + { "name": "namedFlow", "$ref": "NamedFlow", "description": "The Named Flow containing the regions whose regionOverset values changed." } + ], + "description": "Fires if any of the regionOverset values changed in a Named Flow's region chain." + }, + { + "name": "registeredNamedFlowContentElement", + "parameters": [ + { "name": "documentNodeId", "$ref": "DOM.NodeId", "description": "The document node id." }, + { "name": "flowName", "type": "string", "description": "Named Flow identifier for which the new content element was registered." }, + { "name": "contentNodeId", "$ref": "DOM.NodeId", "description": "The node id of the registered content node." }, + { "name": "nextContentNodeId", "$ref": "DOM.NodeId", "description": "The node id of the element following the registered content node." } + ], + "description": "Fires when a Named Flow's has been registered with a new content node." + }, + { + "name": "unregisteredNamedFlowContentElement", + "parameters": [ + { "name": "documentNodeId", "$ref": "DOM.NodeId", "description": "The document node id." }, + { "name": "flowName", "type": "string", "description": "Named Flow identifier for which the new content element was unregistered." }, + { "name": "contentNodeId", "$ref": "DOM.NodeId", "description": "The node id of the unregistered content node." } + ], + "description": "Fires when a Named Flow's has been registered with a new content node." + } + ] +} diff --git a/inspector/protocol/Console.json b/inspector/protocol/Console.json index 23ad947..5b319d9 100644 --- a/inspector/protocol/Console.json +++ b/inspector/protocol/Console.json @@ -2,23 +2,13 @@ "domain": "Console", "description": "Console domain defines methods and events for interaction with the JavaScript console. Console collects messages created by means of the <a href='http://getfirebug.com/wiki/index.php/Console_API'>JavaScript Console API</a>. One needs to enable this domain using <code>enable</code> command in order to start receiving the console messages. Browser collects messages issued while console domain is not enabled as well and reports them using <code>messageAdded</code> notification upon enabling.", "types": [ - { - "id": "ConsoleNetworkRequestId", - "type": "string", - "description": "Unique request identifier. FIXME: Duplicate of Network.RequestId <https://webkit.org/b/125664> Web Inspector: FIX Type Dependency Issues" - }, - { - "id": "ConsoleDOMNodeId", - "type": "integer", - "description": "Unique DOM node identifier. FIXME: Duplicate of DOM.NodeId <https://webkit.org/b/125664> Web Inspector: FIX Type Dependency Issues" - }, { "id": "ConsoleMessage", "type": "object", "description": "Console message.", "properties": [ - { "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "css", "security", "other"], "description": "Message source." }, - { "name": "level", "type": "string", "enum": ["log", "warning", "error", "debug"], "description": "Message severity." }, + { "name": "source", "type": "string", "enum": ["xml", "javascript", "network", "console-api", "storage", "appcache", "rendering", "css", "security", "content-blocker", "other"], "description": "Message source." }, + { "name": "level", "type": "string", "enum": ["log", "info", "warning", "error", "debug"], "description": "Message severity." }, { "name": "text", "type": "string", "description": "Message text." }, { "name": "type", "type": "string", "optional": true, "enum": ["log", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "timing", "profile", "profileEnd"], "description": "Console message type." }, { "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." }, @@ -27,7 +17,7 @@ { "name": "repeatCount", "type": "integer", "optional": true, "description": "Repeat count for repeated messages." }, { "name": "parameters", "type": "array", "items": { "$ref": "Runtime.RemoteObject" }, "optional": true, "description": "Message parameters in case of the formatted message." }, { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "JavaScript stack trace for assertions and error messages." }, - { "name": "networkRequestId", "$ref": "ConsoleNetworkRequestId", "optional": true, "description": "Identifier of the network request associated with this message." } + { "name": "networkRequestId", "$ref": "Network.RequestId", "optional": true, "description": "Identifier of the network request associated with this message." } ] }, { @@ -71,7 +61,7 @@ { "name": "addInspectedNode", "parameters": [ - { "name": "nodeId", "$ref": "ConsoleDOMNodeId", "description": "DOM node id to be accessible by means of $x command line API." } + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "DOM node id to be accessible by means of $x command line API." } ], "description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions)." } diff --git a/inspector/protocol/DOM.json b/inspector/protocol/DOM.json new file mode 100644 index 0000000..5e28dda --- /dev/null +++ b/inspector/protocol/DOM.json @@ -0,0 +1,531 @@ +{ + "domain": "DOM", + "description": "This domain exposes DOM read/write operations. Each DOM Node is represented with its mirror object that has an <code>id</code>. This <code>id</code> can be used to get additional information on the Node, resolve it into the JavaScript object wrapper, etc. It is important that client receives DOM events only for the nodes that are known to the client. Backend keeps track of the nodes that were sent to the client and never sends the same node twice. It is client's responsibility to collect information about the nodes that were sent to the client.<p>Note that <code>iframe</code> owner elements will return corresponding document elements as their child nodes.</p>", + "availability": "web", + "types": [ + { + "id": "NodeId", + "type": "integer", + "description": "Unique DOM node identifier." + }, + { + "id": "BackendNodeId", + "type": "integer", + "description": "Unique DOM node identifier used to reference a node that may not have been pushed to the front-end." + }, + { + "id": "LiveRegionRelevant", + "type": "string", + "enum": ["additions", "removals", "text"], + "description": "Token values of @aria-relevant attribute." + }, + { + "id": "Node", + "type": "object", + "properties": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Node identifier that is passed into the rest of the DOM messages as the <code>nodeId</code>. Backend will only push node with given <code>id</code> once. It is aware of all requested nodes and will only fire DOM events for nodes known to the client." }, + { "name": "nodeType", "type": "integer", "description": "<code>Node</code>'s nodeType." }, + { "name": "nodeName", "type": "string", "description": "<code>Node</code>'s nodeName." }, + { "name": "localName", "type": "string", "description": "<code>Node</code>'s localName." }, + { "name": "nodeValue", "type": "string", "description": "<code>Node</code>'s nodeValue." }, + { "name": "childNodeCount", "type": "integer", "optional": true, "description": "Child count for <code>Container</code> nodes." }, + { "name": "children", "type": "array", "optional": true, "items": { "$ref": "Node" }, "description": "Child nodes of this node when requested with children." }, + { "name": "attributes", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Attributes of the <code>Element</code> node in the form of flat array <code>[name1, value1, name2, value2]</code>." }, + { "name": "documentURL", "type": "string", "optional": true, "description": "Document URL that <code>Document</code> or <code>FrameOwner</code> node points to." }, + { "name": "baseURL", "type": "string", "optional": true, "description": "Base URL that <code>Document</code> or <code>FrameOwner</code> node uses for URL completion." }, + { "name": "publicId", "type": "string", "optional": true, "description": "<code>DocumentType</code>'s publicId." }, + { "name": "systemId", "type": "string", "optional": true, "description": "<code>DocumentType</code>'s systemId." }, + { "name": "internalSubset", "type": "string", "optional": true, "description": "<code>DocumentType</code>'s internalSubset." }, + { "name": "xmlVersion", "type": "string", "optional": true, "description": "<code>Document</code>'s XML version in case of XML documents." }, + { "name": "name", "type": "string", "optional": true, "description": "<code>Attr</code>'s name." }, + { "name": "value", "type": "string", "optional": true, "description": "<code>Attr</code>'s value." }, + { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Frame ID for frame owner elements." }, + { "name": "contentDocument", "$ref": "Node", "optional": true, "description": "Content document for frame owner elements." }, + { "name": "shadowRoots", "type": "array", "optional": true, "items": { "$ref": "Node" }, "description": "Shadow root list for given element host." }, + { "name": "templateContent", "$ref": "Node", "optional": true, "description": "Content document fragment for template elements" }, + { "name": "role", "type": "string", "optional": true, "description": "Computed value for first recognized role token, default role per element, or overridden role." } + ], + "description": "DOM interaction is implemented in terms of mirror objects that represent the actual DOM nodes. DOMNode is a base node mirror type." + }, + { + "id": "EventListener", + "type": "object", + "properties": [ + { "name": "type", "type": "string", "description": "<code>EventListener</code>'s type." }, + { "name": "useCapture", "type": "boolean", "description": "<code>EventListener</code>'s useCapture." }, + { "name": "isAttribute", "type": "boolean", "description": "<code>EventListener</code>'s isAttribute." }, + { "name": "nodeId", "$ref": "NodeId", "description": "Target <code>DOMNode</code> id." }, + { "name": "handlerBody", "type": "string", "description": "Event handler function body." }, + { "name": "location", "$ref": "Debugger.Location", "optional": true, "description": "Handler code location." }, + { "name": "sourceName", "type": "string", "optional": true, "description": "Source script URL." }, + { "name": "handler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event handler function value." } + ], + "description": "A structure holding event listener properties." + }, + { + "id": "AccessibilityProperties", + "description": "A structure holding accessibility properties.", + "type": "object", + "properties": [ + { "name": "activeDescendantNodeId", "$ref": "NodeId", "optional": true, "description": "<code>DOMNode</code> id of the accessibility object referenced by aria-activedescendant." }, + { "name": "busy", "type": "boolean", "optional": true, "description": "Value of @aria-busy on current or ancestor node." }, + { "name": "checked", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Checked state of certain form controls." }, + { "name": "childNodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Array of <code>DOMNode</code> ids of the accessibility tree children if available." }, + { "name": "controlledNodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Array of <code>DOMNode</code> ids of any nodes referenced via @aria-controls." }, + { "name": "disabled", "type": "boolean", "optional": true, "description": "Disabled state of form controls." }, + { "name": "exists", "type": "boolean", "description": "Indicates whether there is an existing AX object for the DOM node. If this is false, all the other properties will be default values." }, + { "name": "expanded", "type": "boolean", "optional": true, "description": "Expanded state." }, + { "name": "flowedNodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Array of <code>DOMNode</code> ids of any nodes referenced via @aria-flowto." }, + { "name": "focused", "type": "boolean", "optional": true, "description": "Focused state. Only defined on focusable elements." }, + { "name": "ignored", "type": "boolean", "optional": true, "description": "Indicates whether the accessibility of the associated AX object node is ignored, whether heuristically or explicitly." }, + { "name": "ignoredByDefault", "type": "boolean", "optional": true, "description": "State indicating whether the accessibility of the associated AX object node is ignored by default for node type." }, + { "name": "invalid", "type": "string", "optional": true, "enum": ["true", "false", "grammar", "spelling"], "description": "Invalid status of form controls." }, + { "name": "hidden", "type": "boolean", "optional": true, "description": "Hidden state. True if node or an ancestor is hidden via CSS or explicit @aria-hidden, to clarify why the element is ignored." }, + { "name": "label", "type": "string", "description": "Computed label value for the node, sometimes calculated by referencing other nodes." }, + { "name": "liveRegionAtomic", "type": "boolean", "optional": true, "description": "Value of @aria-atomic." }, + { "name": "liveRegionRelevant", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Token value(s) of element's @aria-relevant attribute. Array of string values matching $ref LiveRegionRelevant. FIXME: Enum values blocked by http://webkit.org/b/133711" }, + { "name": "liveRegionStatus", "type": "string", "optional": true, "enum": ["assertive", "polite", "off"], "description": "Value of element's @aria-live attribute." }, + { "name": "mouseEventNodeId", "$ref": "NodeId", "optional": true, "description": "<code>DOMNode</code> id of node or closest ancestor node that has a mousedown, mouseup, or click event handler." }, + { "name": "nodeId", "$ref": "NodeId", "description": "Target <code>DOMNode</code> id." }, + { "name": "ownedNodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Array of <code>DOMNode</code> ids of any nodes referenced via @aria-owns." }, + { "name": "parentNodeId", "$ref": "NodeId", "optional": true, "description": "<code>DOMNode</code> id of the accessibility tree parent object if available." }, + { "name": "pressed", "type": "boolean", "optional": true, "description": "Pressed state for toggle buttons." }, + { "name": "readonly", "type": "boolean", "optional": true, "description": "Readonly state of text controls." }, + { "name": "required", "type": "boolean", "optional": true, "description": "Required state of form controls." }, + { "name": "role", "type": "string", "description": "Computed value for first recognized role token, default role per element, or overridden role." }, + { "name": "selected", "type": "boolean", "optional": true, "description": "Selected state of certain form controls." }, + { "name": "selectedChildNodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Array of <code>DOMNode</code> ids of any children marked as selected." } + ] + }, + { + "id": "RGBAColor", + "type": "object", + "properties": [ + { "name": "r", "type": "integer", "description": "The red component, in the [0-255] range." }, + { "name": "g", "type": "integer", "description": "The green component, in the [0-255] range." }, + { "name": "b", "type": "integer", "description": "The blue component, in the [0-255] range." }, + { "name": "a", "type": "number", "optional": true, "description": "The alpha component, in the [0-1] range (default: 1)." } + ], + "description": "A structure holding an RGBA color." + }, + { + "id": "Quad", + "type": "array", + "items": { "type": "number" }, + "minItems": 8, + "maxItems": 8, + "description": "An array of quad vertices, x immediately followed by y for each point, points clock-wise." + }, + { + "id": "HighlightConfig", + "type": "object", + "properties": [ + { "name": "showInfo", "type": "boolean", "optional": true, "description": "Whether the node info tooltip should be shown (default: false)." }, + { "name": "contentColor", "$ref": "RGBAColor", "optional": true, "description": "The content box highlight fill color (default: transparent)." }, + { "name": "paddingColor", "$ref": "RGBAColor", "optional": true, "description": "The padding highlight fill color (default: transparent)." }, + { "name": "borderColor", "$ref": "RGBAColor", "optional": true, "description": "The border highlight fill color (default: transparent)." }, + { "name": "marginColor", "$ref": "RGBAColor", "optional": true, "description": "The margin highlight fill color (default: transparent)." } + ], + "description": "Configuration data for the highlighting of page elements." + } + ], + "commands": [ + { + "name": "getDocument", + "returns": [ + { "name": "root", "$ref": "Node", "description": "Resulting node." } + ], + "description": "Returns the root DOM node to the caller." + }, + { + "name": "requestChildNodes", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get children for." }, + { "name": "depth", "type": "integer", "optional": true, "description": "The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0." } + ], + "description": "Requests that children of the node with given id are returned to the caller in form of <code>setChildNodes</code> events where not only immediate children are retrieved, but all children down to the specified depth." + }, + { + "name": "querySelector", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to query upon." }, + { "name": "selector", "type": "string", "description": "Selector string." } + ], + "returns": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Query selector result." } + ], + "description": "Executes <code>querySelector</code> on a given node." + }, + { + "name": "querySelectorAll", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to query upon." }, + { "name": "selector", "type": "string", "description": "Selector string." } + ], + "returns": [ + { "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" }, "description": "Query selector result." } + ], + "description": "Executes <code>querySelectorAll</code> on a given node." + }, + { + "name": "setNodeName", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to set name for." }, + { "name": "name", "type": "string", "description": "New node's name." } + ], + "returns": [ + { "name": "nodeId", "$ref": "NodeId", "description": "New node's id." } + ], + "description": "Sets node name for a node with given id." + }, + { + "name": "setNodeValue", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to set value for." }, + { "name": "value", "type": "string", "description": "New node's value." } + ], + "description": "Sets node value for a node with given id." + }, + { + "name": "removeNode", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to remove." } + ], + "description": "Removes node with given id." + }, + { + "name": "setAttributeValue", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the element to set attribute for." }, + { "name": "name", "type": "string", "description": "Attribute name." }, + { "name": "value", "type": "string", "description": "Attribute value." } + ], + "description": "Sets attribute for an element with given id." + }, + { + "name": "setAttributesAsText", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the element to set attributes for." }, + { "name": "text", "type": "string", "description": "Text with a number of attributes. Will parse this text using HTML parser." }, + { "name": "name", "type": "string", "optional": true, "description": "Attribute name to replace with new attributes derived from text in case text parsed successfully." } + ], + "description": "Sets attributes on element with given id. This method is useful when user edits some existing attribute value and types in several attribute name/value pairs." + }, + { + "name": "removeAttribute", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the element to remove attribute from." }, + { "name": "name", "type": "string", "description": "Name of the attribute to remove." } + ], + "description": "Removes attribute with given name from an element with given id." + }, + { + "name": "getEventListenersForNode", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get listeners for." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name for handler value. Handler value is not returned without this parameter specified." } + ], + "returns": [ + { "name": "listeners", "type": "array", "items": { "$ref": "EventListener"}, "description": "Array of relevant listeners." } + ], + "description": "Returns event listeners relevant to the node." + }, + { + "name": "getAccessibilityPropertiesForNode", + "description": "Returns a dictionary of accessibility properties for the node.", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node for which to get accessibility properties." } + ], + "returns": [ + { "name": "properties", "$ref": "AccessibilityProperties", "description": "Dictionary of relevant accessibility properties." } + ] + }, + { + "name": "getOuterHTML", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get markup for." } + ], + "returns": [ + { "name": "outerHTML", "type": "string", "description": "Outer HTML markup." } + ], + "description": "Returns node's HTML markup." + }, + { + "name": "setOuterHTML", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to set markup for." }, + { "name": "outerHTML", "type": "string", "description": "Outer HTML markup to set." } + ], + "description": "Sets node HTML markup, returns new node id." + }, + { + "name": "performSearch", + "parameters": [ + { "name": "query", "type": "string", "description": "Plain text or query selector or XPath search query." }, + { "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" }, "optional": true, "description": "Ids of nodes to use as starting points for the search." } + ], + "returns": [ + { "name": "searchId", "type": "string", "description": "Unique search session identifier." }, + { "name": "resultCount", "type": "integer", "description": "Number of search results." } + ], + "description": "Searches for a given string in the DOM tree. Use <code>getSearchResults</code> to access search results or <code>cancelSearch</code> to end this search session." + }, + { + "name": "getSearchResults", + "parameters": [ + { "name": "searchId", "type": "string", "description": "Unique search session identifier." }, + { "name": "fromIndex", "type": "integer", "description": "Start index of the search result to be returned." }, + { "name": "toIndex", "type": "integer", "description": "End index of the search result to be returned." } + ], + "returns": [ + { "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" }, "description": "Ids of the search result nodes." } + ], + "description": "Returns search results from given <code>fromIndex</code> to given <code>toIndex</code> from the sarch with the given identifier." + }, + { + "name": "discardSearchResults", + "parameters": [ + { "name": "searchId", "type": "string", "description": "Unique search session identifier." } + ], + "description": "Discards search results from the session with the given id. <code>getSearchResults</code> should no longer be called for that search." + }, + { + "name": "requestNode", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id to convert into node." } + ], + "returns": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Node id for given object." } + ], + "description": "Requests that the node is sent to the caller given the JavaScript node object reference. All nodes that form the path from the node to the root are also sent to the client as a series of <code>setChildNodes</code> notifications." + }, + { + "name": "setInspectModeEnabled", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "True to enable inspection mode, false to disable it." }, + { "name": "highlightConfig", "$ref": "HighlightConfig", "optional": true, "description": "A descriptor for the highlight appearance of hovered-over nodes. May be omitted if <code>enabled == false</code>." } + ], + "description": "Enters the 'inspect' mode. In this mode, elements that user is hovering over are highlighted. Backend then generates 'inspect' command upon element selection." + }, + { + "name": "highlightRect", + "parameters": [ + { "name": "x", "type": "integer", "description": "X coordinate" }, + { "name": "y", "type": "integer", "description": "Y coordinate" }, + { "name": "width", "type": "integer", "description": "Rectangle width" }, + { "name": "height", "type": "integer", "description": "Rectangle height" }, + { "name": "color", "$ref": "RGBAColor", "optional": true, "description": "The highlight fill color (default: transparent)." }, + { "name": "outlineColor", "$ref": "RGBAColor", "optional": true, "description": "The highlight outline color (default: transparent)." }, + { "name": "usePageCoordinates", "type": "boolean", "optional": true, "description": "Indicates whether the provided parameters are in page coordinates or in viewport coordinates (the default)." } + ], + "description": "Highlights given rectangle. Coordinates are absolute with respect to the main frame viewport." + }, + { + "name": "highlightQuad", + "parameters": [ + { "name": "quad", "$ref": "Quad", "description": "Quad to highlight" }, + { "name": "color", "$ref": "RGBAColor", "optional": true, "description": "The highlight fill color (default: transparent)." }, + { "name": "outlineColor", "$ref": "RGBAColor", "optional": true, "description": "The highlight outline color (default: transparent)." }, + { "name": "usePageCoordinates", "type": "boolean", "optional": true, "description": "Indicates whether the provided parameters are in page coordinates or in viewport coordinates (the default)." } + ], + "description": "Highlights given quad. Coordinates are absolute with respect to the main frame viewport." + }, + { + "name": "highlightSelector", + "parameters": [ + { "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." }, + { "name": "selectorString", "type": "string", "description": "A CSS selector for finding matching nodes to highlight." }, + { "name": "frameId", "type": "string", "optional": true, "description": "Identifier of the frame which will be searched using the selector. If not provided, the main frame will be used." } + ], + "description": "Highlights all DOM nodes that match a given selector. A string containing a CSS selector must be specified." + }, + { + "name": "highlightNode", + "parameters": [ + { "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." }, + { "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Identifier of the node to highlight." }, + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "JavaScript object id of the node to be highlighted." } + ], + "description": "Highlights DOM node with given id or with the given JavaScript object wrapper. Either nodeId or objectId must be specified." + }, + { + "name": "hideHighlight", + "description": "Hides DOM node highlight." + }, + { + "name": "highlightFrame", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Identifier of the frame to highlight." }, + { "name": "contentColor", "$ref": "RGBAColor", "optional": true, "description": "The content box highlight fill color (default: transparent)." }, + { "name": "contentOutlineColor", "$ref": "RGBAColor", "optional": true, "description": "The content box highlight outline color (default: transparent)." } + ], + "description": "Highlights owner element of the frame with given id." + }, + { + "name": "pushNodeByPathToFrontend", + "parameters": [ + { "name": "path", "type": "string", "description": "Path to node in the proprietary format." } + ], + "returns": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node for given path." } + ], + "description": "Requests that the node is sent to the caller given its path. // FIXME, use XPath" + }, + { + "name": "pushNodeByBackendIdToFrontend", + "parameters": [ + { "name": "backendNodeId", "$ref": "BackendNodeId", "description": "The backend node id of the node." } + ], + "returns": [ + { "name": "nodeId", "$ref": "NodeId", "description": "The pushed node's id." } + ], + "description": "Requests that the node is sent to the caller given its backend node id." + }, + { + "name": "releaseBackendNodeIds", + "parameters": [ + { "name": "nodeGroup", "type": "string", "description": "The backend node ids group name." } + ], + "description": "Requests that group of <code>BackendNodeIds</code> is released." + }, + { + "name": "resolveNode", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to resolve." }, + { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } + ], + "returns": [ + { "name": "object", "$ref": "Runtime.RemoteObject", "description": "JavaScript object wrapper for given node." } + ], + "description": "Resolves JavaScript node object for given node id." + }, + { + "name": "getAttributes", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to retrieve attibutes for." } + ], + "returns": [ + { "name": "attributes", "type": "array", "items": { "type": "string" }, "description": "An interleaved array of node attribute names and values." } + ], + "description": "Returns attributes for the specified node." + }, + { + "name": "moveTo", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to drop." }, + { "name": "targetNodeId", "$ref": "NodeId", "description": "Id of the element to drop into." }, + { "name": "insertBeforeNodeId", "$ref": "NodeId", "optional": true, "description": "Drop node before given one." } + ], + "returns": [ + { "name": "nodeId", "$ref": "NodeId", "description": "New id of the moved node." } + ], + "description": "Moves node into the new container, places it before the given anchor." + }, + { + "name": "undo", + "description": "Undoes the last performed action." + }, + { + "name": "redo", + "description": "Re-does the last undone action." + }, + { + "name": "markUndoableState", + "description": "Marks last undoable state." + }, + { + "name": "focus", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to focus." } + ], + "description": "Focuses the given element." + } + ], + "events": [ + { + "name": "documentUpdated", + "description": "Fired when <code>Document</code> has been totally updated. Node ids are no longer valid." + }, + { + "name": "setChildNodes", + "parameters": [ + { "name": "parentId", "$ref": "NodeId", "description": "Parent node id to populate with children." }, + { "name": "nodes", "type": "array", "items": { "$ref": "Node"}, "description": "Child nodes array." } + ], + "description": "Fired when backend wants to provide client with the missing DOM structure. This happens upon most of the calls requesting node ids." + }, + { + "name": "attributeModified", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node that has changed." }, + { "name": "name", "type": "string", "description": "Attribute name." }, + { "name": "value", "type": "string", "description": "Attribute value." } + ], + "description": "Fired when <code>Element</code>'s attribute is modified." + }, + { + "name": "attributeRemoved", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node that has changed." }, + { "name": "name", "type": "string", "description": "A ttribute name." } + ], + "description": "Fired when <code>Element</code>'s attribute is removed." + }, + { + "name": "inlineStyleInvalidated", + "parameters": [ + { "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" }, "description": "Ids of the nodes for which the inline styles have been invalidated." } + ], + "description": "Fired when <code>Element</code>'s inline style is modified via a CSS property modification." + }, + { + "name": "characterDataModified", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node that has changed." }, + { "name": "characterData", "type": "string", "description": "New text value." } + ], + "description": "Mirrors <code>DOMCharacterDataModified</code> event." + }, + { + "name": "childNodeCountUpdated", + "parameters": [ + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node that has changed." }, + { "name": "childNodeCount", "type": "integer", "description": "New node count." } + ], + "description": "Fired when <code>Container</code>'s child node count has changed." + }, + { + "name": "childNodeInserted", + "parameters": [ + { "name": "parentNodeId", "$ref": "NodeId", "description": "Id of the node that has changed." }, + { "name": "previousNodeId", "$ref": "NodeId", "description": "If of the previous siblint." }, + { "name": "node", "$ref": "Node", "description": "Inserted node data." } + ], + "description": "Mirrors <code>DOMNodeInserted</code> event." + }, + { + "name": "childNodeRemoved", + "parameters": [ + { "name": "parentNodeId", "$ref": "NodeId", "description": "Parent id." }, + { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node that has been removed." } + ], + "description": "Mirrors <code>DOMNodeRemoved</code> event." + }, + { + "name": "shadowRootPushed", + "parameters": [ + { "name": "hostId", "$ref": "NodeId", "description": "Host element id." }, + { "name": "root", "$ref": "Node", "description": "Shadow root." } + ], + "description": "Called when shadow root is pushed into the element." + }, + { + "name": "shadowRootPopped", + "parameters": [ + { "name": "hostId", "$ref": "NodeId", "description": "Host element id." }, + { "name": "rootId", "$ref": "NodeId", "description": "Shadow root id." } + ], + "description": "Called when shadow root is popped from the element." + } + ] +} diff --git a/inspector/protocol/DOMDebugger.json b/inspector/protocol/DOMDebugger.json new file mode 100644 index 0000000..bfab308 --- /dev/null +++ b/inspector/protocol/DOMDebugger.json @@ -0,0 +1,73 @@ +{ + "domain": "DOMDebugger", + "description": "DOM debugging allows setting breakpoints on particular DOM operations and events. JavaScript execution will stop on these operations as if there was a regular breakpoint set.", + "availability": "web", + "types": [ + { + "id": "DOMBreakpointType", + "type": "string", + "enum": ["subtree-modified", "attribute-modified", "node-removed"], + "description": "DOM breakpoint type." + } + ], + "commands": [ + { + "name": "setDOMBreakpoint", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "Identifier of the node to set breakpoint on." }, + { "name": "type", "$ref": "DOMBreakpointType", "description": "Type of the operation to stop upon." } + ], + "description": "Sets breakpoint on particular operation with DOM." + }, + { + "name": "removeDOMBreakpoint", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "Identifier of the node to remove breakpoint from." }, + { "name": "type", "$ref": "DOMBreakpointType", "description": "Type of the breakpoint to remove." } + ], + "description": "Removes DOM breakpoint that was set using <code>setDOMBreakpoint</code>." + }, + { + "name": "setEventListenerBreakpoint", + "parameters": [ + { "name": "eventName", "type": "string", "description": "DOM Event name to stop on (any DOM event will do)." } + ], + "description": "Sets breakpoint on particular DOM event." + }, + { + "name": "removeEventListenerBreakpoint", + "parameters": [ + { "name": "eventName", "type": "string", "description": "Event name." } + ], + "description": "Removes breakpoint on particular DOM event." + }, + { + "name": "setInstrumentationBreakpoint", + "parameters": [ + { "name": "eventName", "type": "string", "description": "Instrumentation name to stop on." } + ], + "description": "Sets breakpoint on particular native event." + }, + { + "name": "removeInstrumentationBreakpoint", + "parameters": [ + { "name": "eventName", "type": "string", "description": "Instrumentation name to stop on." } + ], + "description": "Sets breakpoint on particular native event." + }, + { + "name": "setXHRBreakpoint", + "parameters": [ + { "name": "url", "type": "string", "description": "Resource URL substring. All XHRs having this substring in the URL will get stopped upon." } + ], + "description": "Sets breakpoint on XMLHttpRequest." + }, + { + "name": "removeXHRBreakpoint", + "parameters": [ + { "name": "url", "type": "string", "description": "Resource URL substring." } + ], + "description": "Removes breakpoint from XMLHttpRequest." + } + ] +} diff --git a/inspector/protocol/DOMStorage.json b/inspector/protocol/DOMStorage.json new file mode 100644 index 0000000..812e70d --- /dev/null +++ b/inspector/protocol/DOMStorage.json @@ -0,0 +1,88 @@ +{ + "domain": "DOMStorage", + "description": "Query and modify DOM storage.", + "availability": "web", + "types": [ + { + "id": "StorageId", + "type": "object", + "description": "DOM Storage identifier.", + "properties": [ + { "name": "securityOrigin", "type": "string", "description": "Security origin for the storage." }, + { "name": "isLocalStorage", "type": "boolean", "description": "Whether the storage is local storage (not session storage)." } + ] + }, + { + "id": "Item", + "type": "array", + "description": "DOM Storage item.", + "items": { "type": "string" } + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables storage tracking, storage events will now be delivered to the client." + }, + { + "name": "disable", + "description": "Disables storage tracking, prevents storage events from being sent to the client." + }, + { + "name": "getDOMStorageItems", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" } + ], + "returns": [ + { "name": "entries", "type": "array", "items": { "$ref": "Item" } } + ] + }, + { + "name": "setDOMStorageItem", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" }, + { "name": "key", "type": "string" }, + { "name": "value", "type": "string" } + ] + }, + { + "name": "removeDOMStorageItem", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" }, + { "name": "key", "type": "string" } + ] + } + ], + "events": [ + { + "name": "domStorageItemsCleared", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" } + ] + }, + { + "name": "domStorageItemRemoved", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" }, + { "name": "key", "type": "string" } + ] + }, + { + "name": "domStorageItemAdded", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" }, + { "name": "key", "type": "string" }, + { "name": "newValue", "type": "string" } + ] + }, + { + "name": "domStorageItemUpdated", + "parameters": [ + { "name": "storageId", "$ref": "StorageId" }, + { "name": "key", "type": "string" }, + { "name": "oldValue", "type": "string" }, + { "name": "newValue", "type": "string" } + ] + } + ] +} diff --git a/inspector/protocol/Database.json b/inspector/protocol/Database.json new file mode 100644 index 0000000..b959e0f --- /dev/null +++ b/inspector/protocol/Database.json @@ -0,0 +1,71 @@ +{ + "domain": "Database", + "availability": "web", + "types": [ + { + "id": "DatabaseId", + "type": "string", + "description": "Unique identifier of Database object." + }, + { + "id": "Database", + "type": "object", + "description": "Database object.", + "properties": [ + { "name": "id", "$ref": "DatabaseId", "description": "Database ID." }, + { "name": "domain", "type": "string", "description": "Database domain." }, + { "name": "name", "type": "string", "description": "Database name." }, + { "name": "version", "type": "string", "description": "Database version." } + ] + }, + { + "id": "Error", + "type": "object", + "description": "Database error.", + "properties": [ + { "name": "message", "type": "string", "description": "Error message." }, + { "name": "code", "type": "integer", "description": "Error code." } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables database tracking, database events will now be delivered to the client." + }, + { + "name": "disable", + "description": "Disables database tracking, prevents database events from being sent to the client." + }, + { + "name": "getDatabaseTableNames", + "parameters": [ + { "name": "databaseId", "$ref": "DatabaseId" } + ], + "returns": [ + { "name": "tableNames", "type": "array", "items": { "type": "string" } } + ] + }, + { + "name": "executeSQL", + "async": true, + "parameters": [ + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "query", "type": "string" } + ], + "returns": [ + { "name": "columnNames", "type": "array", "optional": true, "items": { "type": "string" } }, + { "name": "values", "type": "array", "optional": true, "items": { "type": "any" }}, + { "name": "sqlError", "$ref": "Error", "optional": true } + ] + } + ], + "events": [ + { + "name": "addDatabase", + "parameters": [ + { "name": "database", "$ref": "Database" } + ] + } + ] +} diff --git a/inspector/protocol/Debugger.json b/inspector/protocol/Debugger.json index 3b7c4bd..a65522f 100644 --- a/inspector/protocol/Debugger.json +++ b/inspector/protocol/Debugger.json @@ -80,7 +80,7 @@ "id": "Scope", "type": "object", "properties": [ - { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch"], "description": "Scope type." }, + { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "functionName"], "description": "Scope type." }, { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For <code>global</code> and <code>with</code> scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." } ], "description": "Scope description." @@ -96,6 +96,30 @@ { "name": "timestamp", "type": "number", "description": "Timestamp of when the sample was taken." }, { "name": "payload", "$ref": "Runtime.RemoteObject", "description": "Contents of the sample." } ] + }, + { + "id": "AssertPauseReason", + "description": "The pause reason auxiliary data when paused because of an assertion.", + "type": "object", + "properties": [ + { "name": "message", "type": "string", "optional": true, "description": "The console.assert message string if provided." } + ] + }, + { + "id": "BreakpointPauseReason", + "description": "The pause reason auxiliary data when paused because of hitting a breakpoint.", + "type": "object", + "properties": [ + { "name": "breakpointId", "type": "string", "description": "The identifier of the breakpoint causing the pause." } + ] + }, + { + "id": "CSPViolationPauseReason", + "description": "The pause reason auxiliary data when paused because of a Content Security Policy directive.", + "type": "object", + "properties": [ + { "name": "directive", "type": "string", "description": "The CSP directive that blocked script execution." } + ] } ], "commands": [ @@ -177,16 +201,16 @@ }, { "name": "searchInContent", + "description": "Searches for given string in script content.", "parameters": [ { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to search in." }, - { "name": "query", "type": "string", "description": "String to search for." }, + { "name": "query", "type": "string", "description": "String to search for." }, { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } ], "returns": [ { "name": "result", "type": "array", "items": { "$ref": "GenericTypes.SearchMatch" }, "description": "List of search matches." } - ], - "description": "Searches for given string in script content." + ] }, { "name": "getScriptSource", @@ -206,7 +230,7 @@ "returns": [ { "name": "details", "$ref": "FunctionDetails", "description": "Information about the function." } ], - "description": "Returns detailed informtation on given function." + "description": "Returns detailed information on given function." }, { "name": "setPauseOnExceptions", @@ -224,11 +248,13 @@ { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false." }, { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, + { "name": "saveResult", "type": "boolean", "optional": true, "description": "Whether the resulting value should be considered for saving in the $n history." } ], "returns": [ { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, - { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." } + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, + { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." } ], "description": "Evaluates expression on a given call frame." }, @@ -283,7 +309,7 @@ "name": "paused", "parameters": [ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, - { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "CSPViolation", "other" ], "description": "Pause reason." }, + { "name": "reason", "type": "string", "enum": ["XHR", "DOM", "EventListener", "exception", "assert", "CSPViolation", "DebuggerStatement", "Breakpoint", "PauseOnNextStatement", "other"], "description": "Pause reason." }, { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." } ], "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." diff --git a/inspector/protocol/IndexedDB.json b/inspector/protocol/IndexedDB.json new file mode 100644 index 0000000..0e984e4 --- /dev/null +++ b/inspector/protocol/IndexedDB.json @@ -0,0 +1,145 @@ +{ + "domain": "IndexedDB", + "featureGuard": "ENABLE(INDEXED_DATABASE)", + "availability": "web", + "types": [ + { + "id": "DatabaseWithObjectStores", + "type": "object", + "description": "Database with an array of object stores.", + "properties": [ + { "name": "name", "type": "string", "description": "Database name." }, + { "name": "version", "type": "number", "description": "Database version." }, + { "name": "objectStores", "type": "array", "items": { "$ref": "ObjectStore" }, "description": "Object stores in this database." } + ] + }, + { + "id": "ObjectStore", + "type": "object", + "description": "Object store.", + "properties": [ + { "name": "name", "type": "string", "description": "Object store name." }, + { "name": "keyPath", "$ref": "KeyPath", "description": "Object store key path." }, + { "name": "autoIncrement", "type": "boolean", "description": "If true, object store has auto increment flag set." }, + { "name": "indexes", "type": "array", "items": { "$ref": "ObjectStoreIndex" }, "description": "Indexes in this object store." } + ] + }, + { + "id": "ObjectStoreIndex", + "type": "object", + "description": "Object store index.", + "properties": [ + { "name": "name", "type": "string", "description": "Index name." }, + { "name": "keyPath", "$ref": "KeyPath", "description": "Index key path." }, + { "name": "unique", "type": "boolean", "description": "If true, index is unique." }, + { "name": "multiEntry", "type": "boolean", "description": "If true, index allows multiple entries for a key." } + ] + }, + { + "id": "Key", + "type": "object", + "description": "Key.", + "properties": [ + { "name": "type", "type": "string", "enum": ["number", "string", "date", "array"], "description": "Key type." }, + { "name": "number", "type": "number", "optional": true, "description": "Number value." }, + { "name": "string", "type": "string", "optional": true, "description": "String value." }, + { "name": "date", "type": "number", "optional": true, "description": "Date value." }, + { "name": "array", "type": "array", "optional": true, "items": { "$ref": "Key" }, "description": "Array value." } + ] + }, + { + "id": "KeyRange", + "type": "object", + "description": "Key range.", + "properties": [ + { "name": "lower", "$ref": "Key", "optional": true, "description": "Lower bound." }, + { "name": "upper", "$ref": "Key", "optional": true, "description": "Upper bound." }, + { "name": "lowerOpen", "type": "boolean", "description": "If true lower bound is open." }, + { "name": "upperOpen", "type": "boolean", "description": "If true upper bound is open." } + ] + }, + { + "id": "DataEntry", + "type": "object", + "description": "Data entry.", + "properties": [ + { "name": "key", "$ref": "Runtime.RemoteObject", "description": "Key." }, + { "name": "primaryKey", "$ref": "Runtime.RemoteObject", "description": "Primary key." }, + { "name": "value", "$ref": "Runtime.RemoteObject", "description": "Value." } + ] + }, + { + "id": "KeyPath", + "type": "object", + "description": "Key path.", + "properties": [ + { "name": "type", "type": "string", "enum": ["null", "string", "array"], "description": "Key path type." }, + { "name": "string", "type": "string", "optional": true, "description": "String value." }, + { "name": "array", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Array value." } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables events from backend." + }, + { + "name": "disable", + "description": "Disables events from backend." + }, + { + "name": "requestDatabaseNames", + "async": true, + "parameters": [ + { "name": "securityOrigin", "type": "string", "description": "Security origin." } + ], + "returns": [ + { "name": "databaseNames", "type": "array", "items": { "type": "string" }, "description": "Database names for origin." } + ], + "description": "Requests database names for given security origin." + }, + { + "name": "requestDatabase", + "async": true, + "parameters": [ + { "name": "securityOrigin", "type": "string", "description": "Security origin." }, + { "name": "databaseName", "type": "string", "description": "Database name." } + ], + "returns": [ + { "name": "databaseWithObjectStores", "$ref": "DatabaseWithObjectStores", "description": "Database with an array of object stores." } + ], + "description": "Requests database with given name in given frame." + }, + { + "name": "requestData", + "async": true, + "parameters": [ + { "name": "securityOrigin", "type": "string", "description": "Security origin." }, + { "name": "databaseName", "type": "string", "description": "Database name." }, + { "name": "objectStoreName", "type": "string", "description": "Object store name." }, + { "name": "indexName", "type": "string", "description": "Index name, empty string for object store data requests." }, + { "name": "skipCount", "type": "integer", "description": "Number of records to skip." }, + { "name": "pageSize", "type": "integer", "description": "Number of records to fetch." }, + { "name": "keyRange", "$ref": "KeyRange", "optional": true, "description": "Key range." } + ], + "returns": [ + { "name": "objectStoreDataEntries", "type": "array", "items": { "$ref": "DataEntry" }, "description": "Array of object store data entries." }, + { "name": "hasMore", "type": "boolean", "description": "If true, there are more entries to fetch in the given range." } + ], + "description": "Requests data from object store or index." + }, + { + "name": "clearObjectStore", + "async": true, + "parameters": [ + { "name": "securityOrigin", "type": "string", "description": "Security origin." }, + { "name": "databaseName", "type": "string", "description": "Database name." }, + { "name": "objectStoreName", "type": "string", "description": "Object store name." } + ], + "returns": [ + ], + "description": "Clears all entries from an object store." + } + ] +} diff --git a/inspector/protocol/InspectorDomain.json b/inspector/protocol/Inspector.json similarity index 70% rename from inspector/protocol/InspectorDomain.json rename to inspector/protocol/Inspector.json index 410631f..0420ebd 100644 --- a/inspector/protocol/InspectorDomain.json +++ b/inspector/protocol/Inspector.json @@ -9,6 +9,10 @@ { "name": "disable", "description": "Disables inspector domain notifications." + }, + { + "name": "initialized", + "description": "Sent by the frontend after all initialization messages have been sent." } ], "events": [ @@ -32,6 +36,13 @@ { "name": "reason", "type": "string", "description": "The reason why connection has been terminated." } ] }, + { + "name": "activateExtraDomains", + "description": "Fired when the backend has alternate domains that need to be activated.", + "parameters": [ + { "name": "domains", "type": "array", "items": { "type": "string" }, "description": "Domain names that need activation" } + ] + }, { "name": "targetCrashed", "description": "Fired when debugging target has crashed" diff --git a/inspector/protocol/LayerTree.json b/inspector/protocol/LayerTree.json new file mode 100644 index 0000000..61211c2 --- /dev/null +++ b/inspector/protocol/LayerTree.json @@ -0,0 +1,113 @@ +{ + "domain": "LayerTree", + "availability": "web", + "types": [ + { + "id": "LayerId", + "type": "string", + "description": "Unique RenderLayer identifier." + }, + { + "id": "PseudoElementId", + "type": "string", + "description": "Unique PseudoElement identifier." + }, + { + "id": "IntRect", + "type": "object", + "description": "A rectangle.", + "properties": [ + { "name": "x", "type": "integer", "description": "The x position." }, + { "name": "y", "type": "integer", "description": "The y position." }, + { "name": "width", "type": "integer", "description": "The width metric." }, + { "name": "height", "type": "integer", "description": "The height metric." } + ] + }, + { + "id": "Layer", + "type": "object", + "description": "Information about a compositing layer.", + "properties": [ + { "name": "layerId", "$ref": "LayerId", "description": "The unique id for this layer." }, + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "The id for the node associated with this layer." }, + { "name": "bounds", "$ref": "IntRect", "description": "Bounds of the layer in absolute page coordinates." }, + { "name": "paintCount", "type": "integer", "description": "Indicates how many time this layer has painted." }, + { "name": "memory", "type": "integer", "description": "Estimated memory used by this layer." }, + { "name": "compositedBounds", "$ref": "IntRect", "description": "The bounds of the composited layer." }, + { "name": "isInShadowTree", "type": "boolean", "optional": true, "description": "Indicates whether this layer is associated with an element hosted in a shadow tree." }, + { "name": "isReflection", "type": "boolean", "optional": true, "description": "Indicates whether this layer was used to provide a reflection for the element." }, + { "name": "isGeneratedContent", "type": "boolean", "optional": true, "description": "Indicates whether the layer is attached to a pseudo element that is CSS generated content." }, + { "name": "isAnonymous", "type": "boolean", "optional": true, "description": "Indicates whether the layer was created for a CSS anonymous block or box." }, + { "name": "pseudoElementId", "$ref": "PseudoElementId", "optional": true, "description": "The id for the pseudo element associated with this layer." }, + { "name": "pseudoElement", "type": "string", "optional": true, "description": "The name of the CSS pseudo-element that prompted the layer to be generated." } + ] + }, + { + "id": "CompositingReasons", + "type": "object", + "description": "An object containing the reasons why the layer was composited as properties.", + "properties": [ + { "name": "transform3D", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a CSS 3D transform." }, + { "name": "video", "type": "boolean", "optional": true, "description": "Composition due to association with a <video> element." }, + { "name": "canvas", "type": "boolean", "optional": true, "description": "Composition due to the element being a <canvas> element." }, + { "name": "plugin", "type": "boolean", "optional": true, "description": "Composition due to association with a plugin." }, + { "name": "iFrame", "type": "boolean", "optional": true, "description": "Composition due to association with an <iframe> element." }, + { "name": "backfaceVisibilityHidden", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a \"backface-visibility: hidden\" style." }, + { "name": "clipsCompositingDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element clipping compositing descendants." }, + { "name": "animation", "type": "boolean", "optional": true, "description": "Composition due to association with an animated element." }, + { "name": "filters", "type": "boolean", "optional": true, "description": "Composition due to association with an element with CSS filters applied." }, + { "name": "positionFixed", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a \"position: fixed\" style." }, + { "name": "positionSticky", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a \"position: sticky\" style." }, + { "name": "overflowScrollingTouch", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a \"overflow-scrolling: touch\" style." }, + { "name": "stacking", "type": "boolean", "optional": true, "description": "Composition due to association with an element establishing a stacking context." }, + { "name": "overlap", "type": "boolean", "optional": true, "description": "Composition due to association with an element overlapping other composited elements." }, + { "name": "negativeZIndexChildren", "type": "boolean", "optional": true, "description": "Composition due to association with an element with descendants that have a negative z-index." }, + { "name": "transformWithCompositedDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element with composited descendants." }, + { "name": "opacityWithCompositedDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element with opacity applied and composited descendants." }, + { "name": "maskWithCompositedDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with a masked element and composited descendants." }, + { "name": "reflectionWithCompositedDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a reflection and composited descendants." }, + { "name": "filterWithCompositedDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element with CSS filters applied and composited descendants." }, + { "name": "blendingWithCompositedDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element with CSS blending applied and composited descendants." }, + { "name": "isolatesCompositedBlendingDescendants", "type": "boolean", "optional": true, "description": "Composition due to association with an element isolating compositing descendants having CSS blending applied." }, + { "name": "perspective", "type": "boolean", "optional": true, "description": "Composition due to association with an element with perspective applied." }, + { "name": "preserve3D", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a \"transform-style: preserve-3d\" style." }, + { "name": "root", "type": "boolean", "optional": true, "description": "Composition due to association with the root element." }, + { "name": "blending", "type": "boolean", "optional": true, "description": "Composition due to association with an element with a \"blend-mode\" style." } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables compositing tree inspection." + }, + { + "name": "disable", + "description": "Disables compositing tree inspection." + }, + { + "name": "layersForNode", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "Root of the subtree for which we want to gather layers." } ], + "description": "Returns the layer tree structure of the current page.", + "returns": [ + { "name": "layers", "type": "array", "items": { "$ref": "Layer" }, "description": "Child layers." } + ] + }, + { + "name": "reasonsForCompositingLayer", + "parameters": [ + { "name": "layerId", "$ref": "LayerId", "description": "The id of the layer for which we want to get the reasons it was composited." } + ], + "description": "Provides the reasons why the given layer was composited.", + "returns": [ + { "name": "compositingReasons", "$ref": "CompositingReasons", "description": "An object containing the reasons why the layer was composited as properties." } + ] + } + ], + "events": [ + { + "name": "layerTreeDidChange" + } + ] +} diff --git a/inspector/protocol/Network.json b/inspector/protocol/Network.json new file mode 100644 index 0000000..de141d2 --- /dev/null +++ b/inspector/protocol/Network.json @@ -0,0 +1,336 @@ +{ + "domain": "Network", + "description": "Network domain allows tracking network activities of the page. It exposes information about http, file, data and other requests and responses, their headers, bodies, timing, etc.", + "availability": "web", + "types": [ + { + "id": "LoaderId", + "type": "string", + "description": "Unique loader identifier." + }, + { + "id": "FrameId", + "type": "string", + "description": "Unique frame identifier." + }, + { + "id": "RequestId", + "type": "string", + "description": "Unique request identifier." + }, + { + "id": "Timestamp", + "type": "number", + "description": "Number of seconds since epoch." + }, + { + "id": "Headers", + "type": "object", + "description": "Request / response headers as keys / values of JSON object." + }, + { + "id": "ResourceTiming", + "type": "object", + "description": "Timing information for the request.", + "properties": [ + { "name": "navigationStart", "type": "number", "description": "Timing's navigationStart is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this navigationStart." }, + { "name": "domainLookupStart", "type": "number", "description": "Started DNS address resolve." }, + { "name": "domainLookupEnd", "type": "number", "description": "Finished DNS address resolve." }, + { "name": "connectStart", "type": "number", "description": "Started connecting to the remote host." }, + { "name": "connectEnd", "type": "number", "description": "Connected to the remote host." }, + { "name": "secureConnectionStart", "type": "number", "description": "Started SSL handshake." }, + { "name": "requestStart", "type": "number", "description": "Started sending request." }, + { "name": "responseStart", "type": "number", "description": "Started receiving response headers." } + ] + }, + { + "id": "Request", + "type": "object", + "description": "HTTP request data.", + "properties": [ + { "name": "url", "type": "string", "description": "Request URL." }, + { "name": "method", "type": "string", "description": "HTTP request method." }, + { "name": "headers", "$ref": "Headers", "description": "HTTP request headers." }, + { "name": "postData", "type": "string", "optional": true, "description": "HTTP POST request data." } + ] + }, + { + "id": "Response", + "type": "object", + "description": "HTTP response data.", + "properties": [ + { "name": "url", "type": "string", "description": "Response URL. This URL can be different from CachedResource.url in case of redirect." }, + { "name": "status", "type": "number", "description": "HTTP response status code." }, + { "name": "statusText", "type": "string", "description": "HTTP response status text." }, + { "name": "headers", "$ref": "Headers", "description": "HTTP response headers." }, + { "name": "headersText", "type": "string", "optional": true, "description": "HTTP response headers text." }, + { "name": "mimeType", "type": "string", "description": "Resource mimeType as determined by the browser." }, + { "name": "requestHeaders", "$ref": "Headers", "optional": true, "description": "Refined HTTP request headers that were actually transmitted over the network." }, + { "name": "requestHeadersText", "type": "string", "optional": true, "description": "HTTP request headers text." }, + { "name": "fromDiskCache", "type": "boolean", "optional": true, "description": "Specifies that the request was served from the disk cache." }, + { "name": "timing", "$ref": "ResourceTiming", "optional": true, "description": "Timing information for the given request." } + ] + }, + { + "id": "WebSocketRequest", + "type": "object", + "description": "WebSocket request data.", + "properties": [ + { "name": "headers", "$ref": "Headers", "description": "HTTP response headers." } + ] + }, + { + "id": "WebSocketResponse", + "type": "object", + "description": "WebSocket response data.", + "properties": [ + { "name": "status", "type": "number", "description": "HTTP response status code." }, + { "name": "statusText", "type": "string", "description": "HTTP response status text." }, + { "name": "headers", "$ref": "Headers", "description": "HTTP response headers." } + ] + }, + { + "id": "WebSocketFrame", + "type": "object", + "description": "WebSocket frame data.", + "properties": [ + { "name": "opcode", "type": "number", "description": "WebSocket frame opcode." }, + { "name": "mask", "type": "boolean", "description": "WebSocket frame mask." }, + { "name": "payloadData", "type": "string", "description": "WebSocket frame payload data." } + ] + }, + { + "id": "CachedResource", + "type": "object", + "description": "Information about the cached resource.", + "properties": [ + { "name": "url", "type": "string", "description": "Resource URL. This is the url of the original network request." }, + { "name": "type", "$ref": "Page.ResourceType", "description": "Type of this resource." }, + { "name": "response", "$ref": "Response", "optional": true, "description": "Cached response data." }, + { "name": "bodySize", "type": "number", "description": "Cached response body size." }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with this resource (if any)." } + ] + }, + { + "id": "Initiator", + "type": "object", + "description": "Information about the request initiator.", + "properties": [ + { "name": "type", "type": "string", "enum": ["parser", "script", "other"], "description": "Type of this initiator." }, + { "name": "stackTrace", "$ref": "Console.StackTrace", "optional": true, "description": "Initiator JavaScript stack trace, set for Script only." }, + { "name": "url", "type": "string", "optional": true, "description": "Initiator URL, set for Parser type only." }, + { "name": "lineNumber", "type": "number", "optional": true, "description": "Initiator line number, set for Parser type only." } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables network tracking, network events will now be delivered to the client." + }, + { + "name": "disable", + "description": "Disables network tracking, prevents network events from being sent to the client." + }, + { + "name": "setExtraHTTPHeaders", + "description": "Specifies whether to always send extra HTTP headers with the requests from this page.", + "parameters": [ + { "name": "headers", "$ref": "Headers", "description": "Map with extra HTTP headers." } + ] + }, + { + "name": "getResponseBody", + "description": "Returns content served for the given request.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Identifier of the network request to get content for." } + ], + "returns": [ + { "name": "body", "type": "string", "description": "Response body." }, + { "name": "base64Encoded", "type": "boolean", "description": "True, if content was sent as base64." } + ] + }, + { + "name": "canClearBrowserCache", + "description": "Tells whether clearing browser cache is supported.", + "returns": [ + { "name": "result", "type": "boolean", "description": "True if browser cache can be cleared." } + ] + }, + { + "name": "clearBrowserCache", + "description": "Clears browser cache." + }, + { + "name": "canClearBrowserCookies", + "description": "Tells whether clearing browser cookies is supported.", + "returns": [ + { "name": "result", "type": "boolean", "description": "True if browser cookies can be cleared." } + ] + }, + { + "name": "clearBrowserCookies", + "description": "Clears browser cookies." + }, + { + "name": "setCacheDisabled", + "parameters": [ + { "name": "cacheDisabled", "type": "boolean", "description": "Cache disabled state." } + ], + "description": "Toggles ignoring cache for each request. If <code>true</code>, cache will not be used." + }, + { + "name": "loadResource", + "async": true, + "parameters": [ + { "name": "frameId", "$ref": "FrameId", "description": "Frame to load the resource from." }, + { "name": "url", "type": "string", "description": "URL of the resource to load." } + ], + "returns": [ + { "name": "content", "type": "string", "description": "Resource content." }, + { "name": "mimeType", "type": "string", "description": "Resource mimeType." }, + { "name": "status", "type": "number", "description": "HTTP response status code." } + ], + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + } + ], + "events": [ + { + "name": "requestWillBeSent", + "description": "Fired when page is about to send HTTP request.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "frameId", "$ref": "FrameId", "description": "Frame identifier." }, + { "name": "loaderId", "$ref": "LoaderId", "description": "Loader identifier." }, + { "name": "documentURL", "type": "string", "description": "URL of the document this request is loaded for." }, + { "name": "request", "$ref": "Request", "description": "Request data." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "initiator", "$ref": "Initiator", "description": "Request initiator." }, + { "name": "redirectResponse", "optional": true, "$ref": "Response", "description": "Redirect response data." }, + { "name": "type", "$ref": "Page.ResourceType", "optional": true, "description": "Resource type." } + ] + }, + { + "name": "requestServedFromCache", + "description": "Fired if request ended up loading from cache.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." } + ] + }, + { + "name": "responseReceived", + "description": "Fired when HTTP response is available.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "frameId", "$ref": "FrameId", "description": "Frame identifier." }, + { "name": "loaderId", "$ref": "LoaderId", "description": "Loader identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "type", "$ref": "Page.ResourceType", "description": "Resource type." }, + { "name": "response", "$ref": "Response", "description": "Response data." } + ] + }, + { + "name": "dataReceived", + "description": "Fired when data chunk was received over the network.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "dataLength", "type": "integer", "description": "Data chunk length." }, + { "name": "encodedDataLength", "type": "integer", "description": "Actual bytes received (might be less than dataLength for compressed encodings)." } + ] + }, + { + "name": "loadingFinished", + "description": "Fired when HTTP request has finished loading.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with this resource (if any)." } + ] + }, + { + "name": "loadingFailed", + "description": "Fired when HTTP request has failed to load.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "errorText", "type": "string", "description": "User friendly error message." }, + { "name": "canceled", "type": "boolean", "optional": true, "description": "True if loading was canceled." } + ] + }, + { + "name": "requestServedFromMemoryCache", + "description": "Fired when HTTP request has been served from memory cache.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "frameId", "$ref": "FrameId", "description": "Frame identifier." }, + { "name": "loaderId", "$ref": "LoaderId", "description": "Loader identifier." }, + { "name": "documentURL", "type": "string", "description": "URL of the document this request is loaded for." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "initiator", "$ref": "Initiator", "description": "Request initiator." }, + { "name": "resource", "$ref": "CachedResource", "description": "Cached resource data." } + ] + }, + { + "name": "webSocketWillSendHandshakeRequest", + "description": "Fired when WebSocket is about to initiate handshake.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "request", "$ref": "WebSocketRequest", "description": "WebSocket request data." } + ] + }, + { + "name": "webSocketHandshakeResponseReceived", + "description": "Fired when WebSocket handshake response becomes available.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "response", "$ref": "WebSocketResponse", "description": "WebSocket response data." } + ] + }, + { + "name": "webSocketCreated", + "description": "Fired upon WebSocket creation.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "url", "type": "string", "description": "WebSocket request URL." } + ] + }, + { + "name": "webSocketClosed", + "description": "Fired when WebSocket is closed.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." } + ] + }, + { + "name": "webSocketFrameReceived", + "description": "Fired when WebSocket frame is received.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "response", "$ref": "WebSocketFrame", "description": "WebSocket response data." } + ] + }, + { + "name": "webSocketFrameError", + "description": "Fired when WebSocket frame error occurs.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "errorMessage", "type": "string", "description": "WebSocket frame error message." } + ] + }, + { + "name": "webSocketFrameSent", + "description": "Fired when WebSocket frame is sent.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, + { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, + { "name": "response", "$ref": "WebSocketFrame", "description": "WebSocket response data." } + ] + } + ] +} diff --git a/inspector/protocol/OverlayTypes.json b/inspector/protocol/OverlayTypes.json new file mode 100644 index 0000000..47efa75 --- /dev/null +++ b/inspector/protocol/OverlayTypes.json @@ -0,0 +1,129 @@ +{ + "domain": "OverlayTypes", + "description": "Exposes types to be used by the inspector overlay.", + "types": [ + { + "id": "Point", + "type": "object", + "properties": [ + { "name": "x", "type": "number" }, + { "name": "y", "type": "number" } + ] + }, + { + "id": "Size", + "type": "object", + "properties": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" } + ] + }, + { + "id": "Quad", + "description": "A quad is a collection of 4 points. When initialized from a rect, the points are in clockwise order from top left.", + "type": "array", + "items": { "$ref": "Point" } + }, + { + "id": "Rect", + "description": "A rectangle specified by a reference coordinate and width/height offsets.", + "type": "object", + "properties": [ + { "name": "x", "type": "number" }, + { "name": "y", "type": "number" }, + { "name": "width", "type": "number" }, + { "name": "height", "type": "number" } + ] + }, + { + "id": "Region", + "description": "A single region in a flow thread.", + "type": "object", + "properties": [ + { "name": "borderQuad", "$ref": "Quad" }, + { "name": "incomingQuad", "$ref": "Quad" }, + { "name": "outgoingQuad", "$ref": "Quad" }, + { "name": "isHighlighted", "type": "boolean", "optional": true } + ] + }, + { + "id": "DisplayPath", + "description": "A vector path described using SVG path syntax.", + "type": "array", + "items": { "type": "any" } + }, + { + "id": "RegionFlowData", + "type": "object", + "properties": [ + { "name": "regions", "type": "array", "items": { "$ref": "Region"} }, + { "name": "name", "type": "string" } + ] + }, + { + "id": "ContentFlowData", + "type": "object", + "properties": [ + { "name": "name", "type": "string" } + ] + }, + { + "id": "ShapeOutsideData", + "type": "object", + "properties": [ + { "name": "bounds", "$ref": "Quad", "description": "Bounds for the shape-outside paths." }, + { "name": "shape", "$ref": "DisplayPath", "description": "Path for the element's shape.", "optional": true }, + { "name": "marginShape", "$ref": "DisplayPath", "description": "Path for the element's margin shape.", "optional": true } + ] + }, + { + "id": "ElementData", + "description": "Data that describes an element to be highlighted.", + "type": "object", + "properties": [ + { "name": "tagName", "type": "string" }, + { "name": "idValue", "type": "string", "description": "The value of the element's 'id' attribute." }, + { "name": "className", "type": "string", "optional": true }, + { "name": "size", "$ref": "Size", "optional": true }, + { "name": "role", "type": "string", "description": "Computed accessibility role for the element.", "optional": true }, + { "name": "regionFlowData", "$ref": "RegionFlowData", "optional": true }, + { "name": "contentFlowData", "$ref": "ContentFlowData", "optional": true }, + { "name": "shapeOutsideData", "$ref": "ShapeOutsideData", "optional": true } + ] + }, + { + "id": "FragmentHighlightData", + "description": "Data required to highlight multiple quads.", + "type": "object", + "properties": [ + { "name": "quads", "type": "array", "items": { "$ref": "Quad" }, "description": "Quads for which the highlight should be applied."}, + { "name": "contentColor", "type": "string" }, + { "name": "contentOutlineColor", "type": "string" }, + { "name": "paddingColor", "type": "string" }, + { "name": "borderColor", "type": "string" }, + { "name": "marginColor", "type": "string" }, + { "name": "regionClippingArea", "$ref": "Quad", "optional": true } + ] + }, + { + "id": "NodeHighlightData", + "description": "Data required to highlight a DOM node.", + "type": "object", + "properties": [ + { "name": "scrollOffset", "$ref": "Point", "description": "Scroll offset for the MainFrame's FrameView that is shared across all quads." }, + { "name": "fragments", "type": "array", "items": { "$ref": "FragmentHighlightData" } }, + { "name": "elementData", "$ref": "ElementData", "optional": true } + ] + }, + { + "id": "OverlayConfiguration", + "description": "Data required to configure the overlay's size and scaling behavior.", + "type": "object", + "properties": [ + { "name": "deviceScaleFactor", "type": "number" }, + { "name": "viewportSize", "$ref": "Size" }, + { "name": "frameViewFullSize", "$ref": "Size" } + ] + } + ] +} diff --git a/inspector/protocol/Page.json b/inspector/protocol/Page.json new file mode 100644 index 0000000..c210a89 --- /dev/null +++ b/inspector/protocol/Page.json @@ -0,0 +1,357 @@ +{ + "domain": "Page", + "description": "Actions and events related to the inspected page belong to the page domain.", + "availability": "web", + "types": [ + { + "id": "ResourceType", + "type": "string", + "enum": ["Document", "Stylesheet", "Image", "Font", "Script", "XHR", "WebSocket", "Other"], + "description": "Resource type as it was perceived by the rendering engine." + }, + { + "id": "CoordinateSystem", + "type": "string", + "enum": ["Viewport", "Page"], + "description": "Coordinate system used by supplied coordinates." + }, + { + "id": "Frame", + "type": "object", + "description": "Information about the Frame on the page.", + "properties": [ + { "name": "id", "type": "string", "description": "Frame unique identifier." }, + { "name": "parentId", "type": "string", "optional": true, "description": "Parent frame identifier." }, + { "name": "loaderId", "$ref": "Network.LoaderId", "description": "Identifier of the loader associated with this frame." }, + { "name": "name", "type": "string", "optional": true, "description": "Frame's name as specified in the tag." }, + { "name": "url", "type": "string", "description": "Frame document's URL." }, + { "name": "securityOrigin", "type": "string", "description": "Frame document's security origin." }, + { "name": "mimeType", "type": "string", "description": "Frame document's mimeType as determined by the browser." } + ] + }, + { + "id": "FrameResource", + "type": "object", + "properties": [ + { "name": "url", "type": "string", "description": "Resource URL." }, + { "name": "type", "$ref": "ResourceType", "description": "Type of this resource." }, + { "name": "mimeType", "type": "string", "description": "Resource mimeType as determined by the browser." }, + { "name": "failed", "type": "boolean", "optional": true, "description": "True if the resource failed to load." }, + { "name": "canceled", "type": "boolean", "optional": true, "description": "True if the resource was canceled during loading." }, + { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with this resource (if any)." } + ] + }, + { + "id": "FrameResourceTree", + "type": "object", + "description": "Information about the Frame hierarchy along with their cached resources.", + "properties": [ + { "name": "frame", "$ref": "Frame", "description": "Frame information for this tree item." }, + { "name": "childFrames", "type": "array", "optional": true, "items": { "$ref": "FrameResourceTree" }, "description": "Child frames." }, + { "name": "resources", "type": "array", "items": { "$ref": "FrameResource" }, "description": "Information about frame resources." } + ] + }, + { + "id": "SearchResult", + "type": "object", + "description": "Search result for resource.", + "properties": [ + { "name": "url", "type": "string", "description": "Resource URL." }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Resource frame id." }, + { "name": "matchesCount", "type": "number", "description": "Number of matches in the resource content." } + ] + }, + { + "id": "Cookie", + "type": "object", + "description": "Cookie object", + "properties": [ + { "name": "name", "type": "string", "description": "Cookie name." }, + { "name": "value", "type": "string", "description": "Cookie value." }, + { "name": "domain", "type": "string", "description": "Cookie domain." }, + { "name": "path", "type": "string", "description": "Cookie path." }, + { "name": "expires", "type": "number", "description": "Cookie expires." }, + { "name": "size", "type": "integer", "description": "Cookie size." }, + { "name": "httpOnly", "type": "boolean", "description": "True if cookie is http-only." }, + { "name": "secure", "type": "boolean", "description": "True if cookie is secure." }, + { "name": "session", "type": "boolean", "description": "True in case of session cookie." } + ] + }, + { + "id": "ScriptIdentifier", + "type": "string", + "description": "Unique script identifier." + } + ], + "commands": [ + { + "name": "enable", + "description": "Enables page domain notifications." + }, + { + "name": "disable", + "description": "Disables page domain notifications." + }, + { + "name": "addScriptToEvaluateOnLoad", + "parameters": [ + { "name": "scriptSource", "type": "string" } + ], + "returns": [ + { "name": "identifier", "$ref": "ScriptIdentifier", "description": "Identifier of the added script." } + ] + }, + { + "name": "removeScriptToEvaluateOnLoad", + "parameters": [ + { "name": "identifier", "$ref": "ScriptIdentifier" } + ] + }, + { + "name": "reload", + "parameters": [ + { "name": "ignoreCache", "type": "boolean", "optional": true, "description": "If true, browser cache is ignored (as if the user pressed Shift+refresh)." }, + { "name": "scriptToEvaluateOnLoad", "type": "string", "optional": true, "description": "If set, the script will be injected into all frames of the inspected page after reload." } + ], + "description": "Reloads given page optionally ignoring the cache." + }, + { + "name": "navigate", + "parameters": [ + { "name": "url", "type": "string", "description": "URL to navigate the page to." } + ], + "description": "Navigates current page to the given URL." + }, + { + "name": "getCookies", + "returns": [ + { "name": "cookies", "type": "array", "items": { "$ref": "Cookie"}, "description": "Array of cookie objects." } + ], + "description": "Returns all browser cookies. Depending on the backend support, will return detailed cookie information in the <code>cookies</code> field." + }, + { + "name": "deleteCookie", + "parameters": [ + { "name": "cookieName", "type": "string", "description": "Name of the cookie to remove." }, + { "name": "url", "type": "string", "description": "URL to match cooke domain and path." } + ], + "description": "Deletes browser cookie with given name, domain and path." + }, + { + "name": "getResourceTree", + "description": "Returns present frame / resource tree structure.", + "returns": [ + { "name": "frameTree", "$ref": "FrameResourceTree", "description": "Present frame / resource tree structure." } + ] + }, + { + "name": "getResourceContent", + "description": "Returns content of the given resource.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Frame id to get resource for." }, + { "name": "url", "type": "string", "description": "URL of the resource to get content for." } + ], + "returns": [ + { "name": "content", "type": "string", "description": "Resource content." }, + { "name": "base64Encoded", "type": "boolean", "description": "True, if content was served as base64." } + ] + }, + { + "name": "searchInResource", + "description": "Searches for given string in resource content.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Frame id for resource to search in." }, + { "name": "url", "type": "string", "description": "URL of the resource to search in." }, + { "name": "query", "type": "string", "description": "String to search for." }, + { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, + { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } + ], + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "GenericTypes.SearchMatch" }, "description": "List of search matches." } + ] + }, + { + "name": "searchInResources", + "description": "Searches for given string in frame / resource tree structure.", + "parameters": [ + { "name": "text", "type": "string", "description": "String to search for." }, + { "name": "caseSensitive", "type": "boolean", "optional": true, "description": "If true, search is case sensitive." }, + { "name": "isRegex", "type": "boolean", "optional": true, "description": "If true, treats string parameter as regex." } + ], + "returns": [ + { "name": "result", "type": "array", "items": { "$ref": "SearchResult" }, "description": "List of search results." } + ] + }, + { + "name": "setDocumentContent", + "description": "Sets given markup as the document's HTML.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Frame id to set HTML for." }, + { "name": "html", "type": "string", "description": "HTML content to set." } + ] + }, + { + "name": "setShowPaintRects", + "description": "Requests that backend shows paint rectangles", + "parameters": [ + { "name": "result", "type": "boolean", "description": "True for showing paint rectangles" } + ] + }, + { + "name": "getScriptExecutionStatus", + "description": "Determines if scripts can be executed in the page.", + "returns": [ + { "name": "result", "type": "string", "enum": ["allowed", "disabled", "forbidden"], "description": "Script execution status: \"allowed\" if scripts can be executed, \"disabled\" if script execution has been disabled through page settings, \"forbidden\" if script execution for the given page is not possible for other reasons." } + ] + }, + { + "name": "setScriptExecutionDisabled", + "description": "Switches script execution in the page.", + "parameters": [ + { "name": "value", "type": "boolean", "description": "Whether script execution should be disabled in the page." } + ] + }, + { + "name": "setTouchEmulationEnabled", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "Whether the touch event emulation should be enabled." } + ], + "description": "Toggles mouse event-based touch event emulation." + }, + { + "name": "setEmulatedMedia", + "parameters": [ + { "name": "media", "type": "string", "description": "Media type to emulate. Empty string disables the override." } + ], + "description": "Emulates the given media for CSS media queries." + }, + { + "name": "getCompositingBordersVisible", + "description": "Indicates the visibility of compositing borders.", + "returns": [ + { "name": "result", "type": "boolean", "description": "If true, compositing borders are visible." } + ] + }, + { + "name": "setCompositingBordersVisible", + "description": "Controls the visibility of compositing borders.", + "parameters": [ + { "name": "visible", "type": "boolean", "description": "True for showing compositing borders." } + ] + }, + { + "name": "snapshotNode", + "description": "Capture a snapshot of the specified node that does not include unrelated layers.", + "parameters": [ + { "name": "nodeId", "$ref": "DOM.NodeId", "description": "Id of the node to snapshot." } + ], + "returns": [ + { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } + ] + }, + { + "name": "snapshotRect", + "description": "Capture a snapshot of the page within the specified rectangle and coordinate system.", + "parameters": [ + { "name": "x", "type": "integer", "description": "X coordinate" }, + { "name": "y", "type": "integer", "description": "Y coordinate" }, + { "name": "width", "type": "integer", "description": "Rectangle width" }, + { "name": "height", "type": "integer", "description": "Rectangle height" }, + { "name": "coordinateSystem", "$ref": "CoordinateSystem", "description": "Indicates the coordinate system of the supplied rectangle." } + ], + "returns": [ + { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } + ] + }, + { + "name": "handleJavaScriptDialog", + "description": "Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload).", + "parameters": [ + { "name": "accept", "type": "boolean", "description": "Whether to accept or dismiss the dialog." }, + { "name": "promptText", "type": "string", "optional": true, "description": "The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog." } + ] + }, + { + "name": "archive", + "description": "Grab an archive of the page.", + "returns": [ + { "name": "data", "type": "string", "description": "Base64-encoded web archive." } + ] + } + ], + "events": [ + { + "name": "domContentEventFired", + "parameters": [ + { "name": "timestamp", "type": "number" } + ] + }, + { + "name": "loadEventFired", + "parameters": [ + { "name": "timestamp", "type": "number" } + ] + }, + { + "name": "frameNavigated", + "description": "Fired once navigation of the frame has completed. Frame is now associated with the new loader.", + "parameters": [ + { "name": "frame", "$ref": "Frame", "description": "Frame object." } + ] + }, + { + "name": "frameDetached", + "description": "Fired when frame has been detached from its parent.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has been detached." } + ] + }, + { + "name": "frameStartedLoading", + "description": "Fired when frame has started loading.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has started loading." } + ] + }, + { + "name": "frameStoppedLoading", + "description": "Fired when frame has stopped loading.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has stopped loading." } + ] + }, + { + "name": "frameScheduledNavigation", + "description": "Fired when frame schedules a potential navigation.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has scheduled a navigation." }, + { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." } + ] + }, + { + "name": "frameClearedScheduledNavigation", + "description": "Fired when frame no longer has a scheduled navigation.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } + ] + }, + { + "name": "javascriptDialogOpening", + "description": "Fired when a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload) is about to open.", + "parameters": [ + { "name": "message", "type": "string", "description": "Message that will be displayed by the dialog." } + ] + }, + { + "name": "javascriptDialogClosed", + "description": "Fired when a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload) has been closed." + }, + { + "name": "scriptsEnabled", + "description": "Fired when the JavaScript is enabled/disabled on the page", + "parameters": [ + { "name": "isEnabled", "type": "boolean", "description": "Whether script execution is enabled or disabled on the page." } + ] + } + ] +} diff --git a/inspector/protocol/Profiler.json b/inspector/protocol/Profiler.json deleted file mode 100644 index 7a3bf35..0000000 --- a/inspector/protocol/Profiler.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "domain": "Profiler", - "types": [ - { - "id": "ProfileHeader", - "type": "object", - "description": "Profile header.", - "properties": [ - { "name": "typeId", "type": "string", "enum": ["CPU"], "description": "Profile type name." }, - { "name": "title", "type": "string", "description": "Profile title." }, - { "name": "uid", "type": "integer", "description": "Unique identifier of the profile." } - ] - }, - { - "id": "CPUProfileNodeCall", - "type": "object", - "description": "CPU Profile call info. Holds time information for a specific call that happened on a node.", - "properties": [ - { "name": "startTime", "type": "number", "description": "Start time for the call." }, - { "name": "totalTime", "type": "number", "description": "Total execution time for the call." } - ] - }, - { - "id": "CPUProfileNode", - "type": "object", - "description": "CPU Profile node. Holds callsite information, execution statistics and child nodes.", - "properties": [ - { "name": "id", "type": "integer", "description": "Unique identifier for this call site." }, - { "name": "calls", "type": "array", "items": { "$ref": "CPUProfileNodeCall" }, "description": "Calls making up this node." }, - { "name": "functionName", "type": "string", "optional": true, "description": "Function name." }, - { "name": "url", "type": "string", "optional": true, "description": "URL." }, - { "name": "lineNumber", "type": "integer", "optional": true, "description": "Line number." }, - { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number." }, - { "name": "children", "type": "array", "items": { "$ref": "CPUProfileNode" }, "optional": true, "description": "Child nodes." } - ] - }, - { - "id": "CPUProfile", - "type": "object", - "description": "Profile.", - "properties": [ - { "name": "rootNodes", "type": "array", "items": { "$ref": "CPUProfileNode" }, "description": "Top level nodes in the stack." }, - { "name": "idleTime", "type": "number", "optional": true } - ] - } - ], - "commands": [ - { - "name": "enable" - }, - { - "name": "disable" - }, - { - "name": "start" - }, - { - "name": "stop" - }, - { - "name": "getProfileHeaders", - "returns": [ - { "name": "headers", "type": "array", "items": { "$ref": "ProfileHeader"} } - ] - }, - { - "name": "getCPUProfile", - "parameters": [ - { "name": "uid", "type": "integer" } - ], - "returns": [ - { "name": "profile", "$ref": "CPUProfile" } - ] - }, - { - "name": "removeProfile", - "parameters": [ - { "name": "type", "type": "string" }, - { "name": "uid", "type": "integer" } - ] - }, - { - "name": "clearProfiles" - } - ], - "events": [ - { - "name": "addProfileHeader", - "parameters": [ - { "name": "header", "$ref": "ProfileHeader" } - ] - }, - { - "name": "setRecordingProfile", - "parameters": [ - { "name": "isProfiling", "type": "boolean" } - ] - }, - { - "name": "resetProfiles" - } - ] -} diff --git a/inspector/protocol/Replay.json b/inspector/protocol/Replay.json new file mode 100644 index 0000000..7bc26bd --- /dev/null +++ b/inspector/protocol/Replay.json @@ -0,0 +1,264 @@ +{ + "domain": "Replay", + "description": "Controls web replay, and manages recording sessions and segments.", + "featureGuard": "ENABLE(WEB_REPLAY)", + "availability": "web", + "types": [ + { + "id": "SessionIdentifier", "description": "Unique replay session identifier.", + "type": "integer" + }, + { + "id": "SegmentIdentifier", "description": "Unique session segment identifier.", + "type": "integer" + }, + { + "id": "SessionState", "description": "State machine's state for the session.", + "type": "string", + "enum": ["Capturing", "Inactive", "Replaying"] + }, + { + "id": "SegmentState", "description": "State machine's state for the session segment.", + "type": "string", + "enum": ["Appending", "Unloaded", "Loaded", "Dispatching"] + }, + { + "id": "ReplayPosition", + "type": "object", + "properties": [ + { "name": "segmentOffset", "type": "integer", "description": "Offset for a segment within the currently-loaded replay session." }, + { "name": "inputOffset", "type": "integer", "description": "Offset for an event loop input within the specified session segment." } + ] + }, + { + "id": "ReplayInput", + "type": "object", + "properties": [ + { "name": "type", "type": "string", "description": "Input type." }, + { "name": "offset", "type": "integer", "description": "Offset of this input in its respective queue."}, + { "name": "data", "type": "object", "description": "Per-input payload." } + ] + }, + { + "id": "ReplayInputQueue", + "type": "object", + "properties": [ + { "name": "type", "type": "string", "description": "Queue type" }, + { "name": "inputs", "type": "array", "items": { "$ref": "ReplayInput"}, "description": "Inputs belonging to this queue." } + ] + }, + { + "id": "SessionSegment", "description": "A standalone segment of a replay session that corresponds to a single main frame navigation and execution.", + "type": "object", + "properties": [ + { "name": "id", "$ref": "SegmentIdentifier", "description": "Unique session segment identifier." }, + { "name": "timestamp", "type": "number", "description": "Start time of the segment, in milliseconds since the epoch." }, + { "name": "queues", "type": "array", "items": { "$ref": "ReplayInputQueue"} } + ] + }, + { + "id": "ReplaySession", "description": "An ordered collection of replay session segments.", + "type": "object", + "properties": [ + { "name": "id", "$ref": "SessionIdentifier", "description": "Unique replay session identifier." }, + { "name": "timestamp", "type": "number", "description": "Creation time of session, in milliseconds since the epoch." }, + { "name": "segments", "type": "array", "items": { "$ref": "SegmentIdentifier" }, "description": "An ordered list identifiers for the segments that comprise this replay session." } + ] + } + ], + "commands": [ + { + "name": "startCapturing", + "description": "Starts capture of a new replay session." + }, + { + "name": "stopCapturing", + "description": "Stops capture of the currently recording replay session." + }, + { + "name": "replayToPosition", + "description": "Seek execution to a specific position within the replay session.", + "parameters": [ + { "name": "position", "$ref": "ReplayPosition" }, + { "name": "shouldFastForward", "type": "boolean" } + ] + }, + { + "name": "replayToCompletion", + "description": "Replay all session segments completely.", + "parameters": [ + { "name": "shouldFastForward", "type": "boolean" } + ] + }, + { + "name": "pausePlayback", + "description": "Pauses playback in the current segment. Can be resumed by using a replay command." + }, + { + "name": "cancelPlayback", + "description": "Cancels playback of the current segment. Further replaying will start from the beginning of the current segment." + }, + { + "name": "switchSession", + "description": "Unloads the current replay session and loads the specified session", + "parameters": [ + { "name": "sessionIdentifier", "$ref": "SessionIdentifier" } + ] + }, + { + "name": "insertSessionSegment", + "description": "Splices the specified session segment into the session at the specified index.", + "parameters": [ + { "name": "sessionIdentifier", "$ref": "SessionIdentifier" }, + { "name": "segmentIdentifier", "$ref": "SegmentIdentifier" }, + { "name": "segmentIndex", "type": "integer" } + ] + }, + { + "name": "removeSessionSegment", + "description": "Removes the session segment at the specified position from the session.", + "parameters": [ + { "name": "sessionIdentifier", "$ref": "SessionIdentifier" }, + { "name": "segmentIndex", "type": "integer" } + ] + }, + { + "name": "currentReplayState", + "description": "Returns the identifier, position, session state and segment state of the currently loaded session. This is necessary because the inspector may be closed and reopened in the middle of replay.", + "returns": [ + { "name": "sessionIdentifier", "$ref": "SessionIdentifier" }, + { "name": "segmentIdentifier", "$ref": "SegmentIdentifier", "optional": true, "description": "If no segment is currently loaded, then there is no valid segment identifier." }, + { "name": "sessionState", "$ref": "SessionState" }, + { "name": "segmentState", "$ref": "SegmentState" }, + { "name": "replayPosition", "$ref": "ReplayPosition" } + ] + }, + { + "name": "getAvailableSessions", + "description": "Returns identifiers of all available sessions.", + "returns": [ + { "name": "ids", "type": "array", "items": { "$ref": "SessionIdentifier" } } + ] + }, + { + "name": "getSessionData", + "description": "Returns an object for the specified session.", + "parameters": [ + { "name": "sessionIdentifier", "$ref": "SessionIdentifier" } + ], + "returns": [ + { "name": "session", "$ref": "ReplaySession", "optional": true, "description": "The requested serialized replay session." } + ] + }, + { + "name": "getSegmentData", + "description": "Returns an object for the specified session segment.", + "parameters": [ + { "name": "id", "$ref": "SegmentIdentifier" } + ], + "returns": [ + { "name": "segment", "$ref": "SessionSegment", "optional": true, "description": "The requested serialized session segment." } + ] + } + ], + "events": [ + { + "name": "captureStarted", + "description": "Fired when capture has started." + }, + { + "name": "captureStopped", + "description": "Fired when capture has stopped." + }, + { + "name": "playbackHitPosition", + "description": "Playback within the session has progressed up to this position, and is about to replay the input at the specified offset.", + "parameters": [ + { "name": "position", "$ref": "ReplayPosition", "description": "The playback position that was hit." }, + { "name": "timestamp", "type": "number", "description": "A timestamp for the event." } + ] + }, + { + "name": "playbackStarted", + "description": "Fired when session playback has started." + }, + { + "name": "playbackPaused", + "description": "Fired when session playback has paused, but not finished.", + "parameters": [ + { "name": "position", "$ref": "ReplayPosition", "description": "The playback position immediately prior to where playback is paused." } + ] + }, + { + "name": "playbackFinished", + "description": "Fired when session playback has stopped." + }, + { + "name": "inputSuppressionChanged", + "description": "Fired when the replay controller starts or stops suppressing user inputs.", + "parameters": [ + { "name": "willSuppress", "type": "boolean", "description": "Whether user inputs will be suppressed during playback." } + ] + }, + { + "name": "sessionCreated", + "description": "Fired when a new replay session is created", + "parameters": [ + { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the created session." } + ] + }, + { + "name": "sessionModified", + "description": "Fired when a session's segments have changed.", + "parameters": [ + { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the session the segment was added to." } + ] + }, + { + "name": "sessionRemoved", + "description": "Fired when a replay session is removed and can no longer be loaded.", + "parameters": [ + { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the removed session." } + ] + }, + { + "name": "sessionLoaded", + "description": "Fired when a replay session is loaded.", + "parameters": [ + { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the loaded session." } + ] + }, + { + "name": "segmentCreated", + "description": "Fired when a new session segment is created.", + "parameters": [ + { "name": "id", "$ref": "SegmentIdentifier", "description": "Identifier for the created session segment." } + ] + }, + { + "name": "segmentRemoved", + "description": "Fired when a session segment is removed and can no longer be replayed as part of a session.", + "parameters": [ + { "name": "id", "$ref": "SegmentIdentifier", "description": "Identifier for the removed session segment." } + ] + }, + { + "name": "segmentCompleted", + "description": "Fired when a session segment is completed and can no longer have inputs added to it.", + "parameters": [ + { "name": "id", "$ref": "SegmentIdentifier", "description": "Identifier for the completed session segment." } + ] + }, + { + "name": "segmentLoaded", + "description": "Fired when a segment is loaded.", + "parameters": [ + { "name": "segmentIdentifier", "$ref": "SegmentIdentifier", "description": "Id for the loaded segment." } + ] + }, + { + "name": "segmentUnloaded", + "description": "Fired when a segment is unloaded." + } + ] +} diff --git a/inspector/protocol/Runtime.json b/inspector/protocol/Runtime.json index b888aa3..c321f6a 100644 --- a/inspector/protocol/Runtime.json +++ b/inspector/protocol/Runtime.json @@ -12,13 +12,15 @@ "type": "object", "description": "Mirror object referencing original JavaScript object.", "properties": [ - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean"], "description": "Object type." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }, + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap", "weakset", "iterator", "class"], "description": "Object subtype hint. Specified for <code>object</code> <code>function</code> (for class) type values only." }, { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for <code>object</code> type values only." }, { "name": "value", "type": "any", "optional": true, "description": "Remote object value (in case of primitive values or JSON values if it was requested)." }, { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, - { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containsing abbreviated property values." } + { "name": "size", "type": "integer", "optional": true, "description": "Size of the array/collection. Specified for array/map/set/weakmap/weakset object type values only." }, + { "name": "classPrototype", "$ref": "RemoteObject", "optional": true, "description": "Remote object for the class prototype. Specified for class object type values only." }, + { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for <code>object</code> type values only." } ] }, { @@ -26,9 +28,14 @@ "type": "object", "description": "Object containing abbreviated remote object value.", "properties": [ + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap", "weakset", "iterator", "class"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }, + { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, { "name": "lossless", "type": "boolean", "description": "Determines whether preview is lossless (contains all information of the original object)." }, - { "name": "overflow", "type": "boolean", "description": "True iff some of the properties of the original did not fit." }, - { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "description": "List of the properties." } + { "name": "overflow", "type": "boolean", "optional": true, "description": "True iff some of the properties of the original did not fit." }, + { "name": "properties", "type": "array", "items": { "$ref": "PropertyPreview" }, "optional": true, "description": "List of the properties." }, + { "name": "entries", "type": "array", "items": { "$ref": "EntryPreview" }, "optional": true, "description": "List of the entries. Specified for <code>map</code> and <code>set</code> subtype values only." }, + { "name": "size", "type": "integer", "optional": true, "description": "Size of the array/collection. Specified for array/map/set/weakmap/weakset object type values only." } ] }, { @@ -36,10 +43,27 @@ "type": "object", "properties": [ { "name": "name", "type": "string", "description": "Property name." }, - { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean"], "description": "Object type." }, + { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type." }, + { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap", "weakset", "iterator", "class"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }, { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." }, { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." }, - { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date"], "description": "Object subtype hint. Specified for <code>object</code> type values only." } + { "name": "internal", "type": "boolean", "optional": true, "description": "True if this is an internal property." } + ] + }, + { + "id": "EntryPreview", + "type": "object", + "properties": [ + { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Entry key. Specified for map-like collection entries." }, + { "name": "value", "$ref": "ObjectPreview", "description": "Entry value." } + ] + }, + { + "id": "CollectionEntry", + "type": "object", + "properties": [ + { "name": "key", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Entry key of a map-like collection, otherwise not provided." }, + { "name": "value", "$ref": "Runtime.RemoteObject", "description": "Entry value." } ] }, { @@ -47,7 +71,7 @@ "type": "object", "description": "Object property descriptor.", "properties": [ - { "name": "name", "type": "string", "description": "Property name." }, + { "name": "name", "type": "string", "description": "Property name or symbol description." }, { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." }, { "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." }, { "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or <code>undefined</code> if there is no getter (accessor descriptors only)." }, @@ -55,7 +79,9 @@ { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." } + { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." }, + { "name": "symbol", "optional": true, "$ref": "Runtime.RemoteObject", "description": "Property symbol object, if the property is a symbol." }, + { "name": "nativeGetter", "optional": true, "type": "boolean", "description": "True if the property value came from a native getter." } ] }, { @@ -81,11 +107,6 @@ "type": "integer", "description": "Id of an execution context." }, - { - "id": "RuntimeFrameId", - "type": "string", - "description": "Unique frame identifier. FIXME: Duplicate of Network.FrameId <https://webkit.org/b/125664> Web Inspector: FIX Type Dependency Issues" - }, { "id": "ExecutionContextDescription", "type": "object", @@ -94,7 +115,7 @@ { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, { "name": "isPageContext", "type": "boolean", "description": "True if this is a context where inpspected web page scripts run. False if it is a content script isolated context." }, { "name": "name", "type": "string", "description": "Human readable name describing given context."}, - { "name": "frameId", "$ref": "RuntimeFrameId", "description": "Id of the owning frame." } + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the owning frame." } ] }, { @@ -111,6 +132,64 @@ { "name": "startOffset", "type": "integer", "description": "Start offset of range (inclusive)." }, { "name": "endOffset", "type": "integer", "description": "End offset of range (exclusive)." } ] + }, + { + "id": "StructureDescription", + "type": "object", + "properties": [ + { "name": "fields", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Array of strings, where the strings represent object properties." }, + { "name": "optionalFields", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Array of strings, where the strings represent optional object properties." }, + { "name": "constructorName", "type": "string", "optional": true, "description": "Name of the constructor." }, + { "name": "prototypeStructure", "$ref": "StructureDescription", "optional": true, "description": "Pointer to the StructureRepresentation of the protoype if one exists." }, + { "name": "isImprecise", "type": "boolean", "optional": true, "description": "If true, it indicates that the fields in this StructureDescription may be inaccurate. I.e, there might have been fields that have been deleted before it was profiled or it has fields we haven't profiled." } + ] + }, + { + "id": "TypeSet", + "type": "object", + "properties": [ + { "name": "isFunction", "type": "boolean", "description": "Indicates if this type description has been type Function." }, + { "name": "isUndefined", "type": "boolean", "description": "Indicates if this type description has been type Undefined." }, + { "name": "isNull", "type": "boolean", "description": "Indicates if this type description has been type Null." }, + { "name": "isBoolean", "type": "boolean", "description": "Indicates if this type description has been type Boolean." }, + { "name": "isInteger", "type": "boolean", "description": "Indicates if this type description has been type Integer." }, + { "name": "isNumber", "type": "boolean", "description": "Indicates if this type description has been type Number." }, + { "name": "isString", "type": "boolean", "description": "Indicates if this type description has been type String." }, + { "name": "isObject", "type": "boolean", "description": "Indicates if this type description has been type Object." }, + { "name": "isSymbol", "type": "boolean", "description": "Indicates if this type description has been type Symbol." } + ] + }, + { + "id": "TypeDescription", + "type": "object", + "description": "Container for type information that has been gathered.", + "properties": [ + { "name": "isValid", "type": "boolean", "description": "If true, we were able to correlate the offset successfuly with a program location. If false, the offset may be bogus or the offset may be from a CodeBlock that hasn't executed." }, + { "name": "leastCommonAncestor", "type": "string", "optional": true, "description": "Least common ancestor of all Constructors if the TypeDescription has seen any structures. This string is the display name of the shared constructor function." }, + { "name": "typeSet", "$ref": "TypeSet", "optional": true, "description": "Set of booleans for determining the aggregate type of this type description." }, + { "name": "structures", "type": "array", "items": { "$ref": "StructureDescription" }, "optional": true, "description": "Array of descriptions for all structures seen for this variable." }, + { "name": "isTruncated", "type": "boolean", "optional": true, "description": "If true, this indicates that no more structures are being profiled because some maximum threshold has been reached and profiling has stopped because of memory pressure." } + ] + }, + { + "id": "TypeLocation", + "type": "object", + "description": "Describes the location of an expression we want type information for.", + "properties": [ + { "name": "typeInformationDescriptor", "type": "integer", "description": "What kind of type information do we want (normal, function return values, 'this' statement)." }, + { "name": "sourceID", "type": "string", "description": "sourceID uniquely identifying a script" }, + { "name": "divot", "type": "integer", "description": "character offset for assignment range" } + ] + }, + { + "id": "BasicBlock", + "type": "object", + "description": "From Wikipedia: a basic block is a portion of the code within a program with only one entry point and only one exit point. This type gives the location of a basic block and if that basic block has executed.", + "properties": [ + { "name": "startOffset", "type": "integer", "description": "Start offset of the basic block." }, + { "name": "endOffset", "type": "integer", "description": "End offset of the basic block." }, + { "name": "hasExecuted", "type": "boolean", "description": "Indicates if the basic block has executed before." } + ] } ], "commands": [ @@ -135,11 +214,13 @@ { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state." }, { "name": "contextId", "$ref": "Runtime.ExecutionContextId", "optional": true, "description": "Specifies in which isolated context to perform evaluation. Each content script lives in an isolated context and this parameter may be used to specify one of those contexts. If the parameter is omitted or 0 the evaluation will be performed in the context of the inspected page." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." } + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, + { "name": "saveResult", "type": "boolean", "optional": true, "description": "Whether the resulting value should be considered for saving in the $n history." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, - { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." } + { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, + { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the result was saved, this is the $n index that can be used to access the value." } ], "description": "Evaluates expression on global object." }, @@ -164,7 +245,7 @@ "parameters": [ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the object itself, not to its prototype chain." }, - { "name": "ownAndGetterProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging to the object itself, and getters in its prototype chain." } + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for property values." } ], "returns": [ { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor"}, "description": "Object properties." }, @@ -172,6 +253,42 @@ ], "description": "Returns properties of a given object. Object group of the result is inherited from the target object." }, + { + "name": "getDisplayableProperties", + "parameters": [ + { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, + { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for property values." } + ], + "returns": [ + { "name": "properties", "type": "array", "items": { "$ref": "PropertyDescriptor"}, "description": "Object properties." }, + { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor"}, "description": "Internal object properties." } + ], + "description": "Returns displayable properties of a given object. Object group of the result is inherited from the target object. Displayable properties are own properties, internal properties, and native getters in the prototype chain (assumed to be bindings and treated like own properties for the frontend)." + }, + { + "name": "getCollectionEntries", + "description": "Returns entries of given Map / Set collection.", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Id of the collection to get entries for." }, + { "name": "objectGroup", "optional": true, "type": "string", "description": "Symbolic group name that can be used to release multiple. If not provided, it will be the same objectGroup as the RemoteObject determined from <code>objectId</code>. This is useful for WeakMap to release the collection entries." }, + { "name": "startIndex", "optional": true, "type": "integer", "description": "If provided skip to this index before collecting values. Otherwise, 0." }, + { "name": "numberToFetch", "optional": true, "type": "integer", "description": "If provided only return <code>numberToFetch</code> values. Otherwise, return values all the way to the end." } + ], + "returns": [ + { "name": "entries", "type": "array", "items": { "$ref": "CollectionEntry" }, "description": "Array of collection entries." } + ] + }, + { + "name": "saveResult", + "parameters": [ + { "name": "value", "$ref": "CallArgument", "description": "Id or value of the object to save." }, + { "name": "contextId", "optional": true, "$ref": "ExecutionContextId", "description": "Unique id of the execution context. To specify in which execution context script evaluation should be performed. If not provided, determine from the CallArgument's objectId." } + ], + "returns": [ + { "name": "savedResultIndex", "type": "integer", "optional": true, "description": "If the value was saved, this is the $n index that can be used to access the value." } + ], + "description": "Assign a saved result index to this value." + }, { "name": "releaseObject", "parameters": [ @@ -197,6 +314,34 @@ { "name": "disable", "description": "Disables reporting of execution contexts creation." + }, + { + "name": "getRuntimeTypesForVariablesAtOffsets", + "parameters": [ + { "name": "locations", "type": "array", "items": { "$ref": "TypeLocation" }, "description": "An array of type locations we're requesting information for. Results are expected in the same order they're sent in."} + ], + "returns": [ + { "name": "types", "type": "array", "items": { "$ref": "TypeDescription", "description": "Types for requested variable." } } + ], + "description": "Returns detailed informtation on given function." + }, + { + "name": "enableTypeProfiler", + "description": "Enables type profiling on the VM." + }, + { + "name": "disableTypeProfiler", + "description": "Disables type profiling on the VM." + }, + { + "name": "getBasicBlocks", + "parameters": [ + { "name": "sourceID", "type": "string", "description": "Indicates which sourceID information is requested for." } + ], + "returns": [ + { "name": "basicBlocks", "type": "array", "items": { "$ref": "BasicBlock", "description": "Array of basic blocks." } } + ], + "description": "Returns a list of basic blocks for the given sourceID with information about their text ranges and whether or not they have executed." } ], "events": [ diff --git a/inspector/protocol/Timeline.json b/inspector/protocol/Timeline.json new file mode 100644 index 0000000..6e34297 --- /dev/null +++ b/inspector/protocol/Timeline.json @@ -0,0 +1,120 @@ +{ + "domain": "Timeline", + "description": "Timeline provides its clients with instrumentation records that are generated during the page runtime. Timeline instrumentation can be started and stopped using corresponding commands. While timeline is started, it is generating timeline event records.", + "availability": "web", + "types": [ + { + "id": "EventType", + "type": "string", + "enum": [ + "EventDispatch", + "ScheduleStyleRecalculation", + "RecalculateStyles", + "InvalidateLayout", + "Layout", + "Paint", + "Composite", + "RenderingFrame", + "ScrollLayer", + "ParseHTML", + "TimerInstall", + "TimerRemove", + "TimerFire", + "EvaluateScript", + "MarkLoad", + "MarkDOMContent", + "TimeStamp", + "Time", + "TimeEnd", + "XHRReadyStateChange", + "XHRLoad", + "FunctionCall", + "ProbeSample", + "ConsoleProfile", + "GCEvent", + "RequestAnimationFrame", + "CancelAnimationFrame", + "FireAnimationFrame", + "WebSocketCreate", + "WebSocketSendHandshakeRequest", + "WebSocketReceiveHandshakeResponse", + "WebSocketDestroy" + ], + "description": "Timeline record type." + }, + { + "id": "TimelineEvent", + "type": "object", + "properties": [ + { "name": "type", "$ref": "EventType", "description": "Event type." }, + { "name": "data", "type": "object", "description": "Event data." }, + { "name": "children", "type": "array", "optional": true, "items": { "$ref": "TimelineEvent" }, "description": "Nested records." } + ], + "description": "Timeline record contains information about the recorded activity." + }, + { + "id": "CPUProfileNodeAggregateCallInfo", + "type": "object", + "description": "Aggregate CPU Profile call info. Holds time information for all the calls that happened on a node.", + "properties": [ + { "name": "callCount", "type": "number", "description": "Total number of calls." }, + { "name": "startTime", "type": "number", "description": "Start time for the first call." }, + { "name": "endTime", "type": "number", "description": "End time for the last call." }, + { "name": "totalTime", "type": "number", "description": "Total execution time for all calls combined." } + ] + }, + { + "id": "CPUProfileNode", + "type": "object", + "description": "CPU Profile node. Holds callsite information, execution statistics and child nodes.", + "properties": [ + { "name": "id", "type": "integer", "description": "Unique identifier for this call site." }, + { "name": "callInfo", "$ref": "CPUProfileNodeAggregateCallInfo", "description": "Aggregate info about all the calls that making up this node." }, + { "name": "functionName", "type": "string", "optional": true, "description": "Function name." }, + { "name": "url", "type": "string", "optional": true, "description": "URL." }, + { "name": "lineNumber", "type": "integer", "optional": true, "description": "Line number." }, + { "name": "columnNumber", "type": "integer", "optional": true, "description": "Column number." }, + { "name": "children", "type": "array", "items": { "$ref": "CPUProfileNode" }, "optional": true, "description": "Child nodes." } + ] + }, + { + "id": "CPUProfile", + "type": "object", + "description": "Profile.", + "properties": [ + { "name": "rootNodes", "type": "array", "items": { "$ref": "CPUProfileNode" }, "description": "Top level nodes in the stack." }, + { "name": "idleTime", "type": "number", "optional": true } + ] + } + ], + "commands": [ + { + "name": "start", + "parameters": [ + { "name": "maxCallStackDepth", "optional": true, "type": "integer", "description": "Samples JavaScript stack traces up to <code>maxCallStackDepth</code>, defaults to 5." } + ], + "description": "Starts capturing instrumentation events." + }, + { + "name": "stop", + "description": "Stops capturing instrumentation events." + } + ], + "events": [ + { + "name": "eventRecorded", + "parameters": [ + { "name": "record", "$ref": "TimelineEvent", "description": "Timeline event record data." } + ], + "description": "Fired for every instrumentation event while timeline is started." + }, + { + "name": "recordingStarted", + "description": "Fired when recording has started." + }, + { + "name": "recordingStopped", + "description": "Fired when recording has stopped." + } + ] +} diff --git a/inspector/protocol/Worker.json b/inspector/protocol/Worker.json new file mode 100644 index 0000000..5269e13 --- /dev/null +++ b/inspector/protocol/Worker.json @@ -0,0 +1,71 @@ +{ + "domain": "Worker", + "types": [], + "availability": "web", + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "sendMessageToWorker", + "parameters": [ + { "name": "workerId", "type": "integer" }, + { "name": "message", "type": "object" } + ] + }, + { + "name": "canInspectWorkers", + "description": "Tells whether browser supports workers inspection.", + "returns": [ + { "name": "result", "type": "boolean", "description": "True if browser has workers support." } + ] + }, + { + "name": "connectToWorker", + "parameters": [ + { "name": "workerId", "type": "integer" } + ] + }, + { + "name": "disconnectFromWorker", + "parameters": [ + { "name": "workerId", "type": "integer" } + ] + }, + { + "name": "setAutoconnectToWorkers", + "parameters": [ + { "name": "value", "type": "boolean" } + ] + } + ], + "events": [ + { + "name": "workerCreated", + "parameters": [ + { "name": "workerId", "type": "integer" }, + { "name": "url", "type": "string" }, + { "name": "inspectorConnected", "type": "boolean" } + ] + }, + { + "name": "workerTerminated", + "parameters": [ + { "name": "workerId", "type": "integer" } + ] + }, + { + "name": "dispatchMessageFromWorker", + "parameters": [ + { "name": "workerId", "type": "integer" }, + { "name": "message", "type": "object" } + ] + }, + { + "name": "disconnectedFromWorker" + } + ] +} diff --git a/inspector/remote/RemoteInspector.h b/inspector/remote/RemoteInspector.h index fb6a78a..2cd8519 100644 --- a/inspector/remote/RemoteInspector.h +++ b/inspector/remote/RemoteInspector.h @@ -46,14 +46,17 @@ struct RemoteInspectorDebuggableInfo; class JS_EXPORT_PRIVATE RemoteInspector final : public RemoteInspectorXPCConnection::Client { public: static void startDisabled(); - static RemoteInspector& shared(); + static RemoteInspector& singleton(); friend class NeverDestroyed<RemoteInspector>; void registerDebuggable(RemoteInspectorDebuggable*); void unregisterDebuggable(RemoteInspectorDebuggable*); void updateDebuggable(RemoteInspectorDebuggable*); + void updateDebuggableAutomaticInspectCandidate(RemoteInspectorDebuggable*); void sendMessageToRemoteFrontend(unsigned identifier, const String& message); void setupFailed(unsigned identifier); + void setupCompleted(unsigned identifier); + bool waitingForAutomaticInspection(unsigned identifier); bool enabled() const { return m_enabled; } bool hasActiveDebugSession() const { return m_hasActiveDebugSession; } @@ -83,6 +86,8 @@ private: void updateHasActiveDebugSession(); + void sendAutomaticInspectionCandidateMessage(); + virtual void xpcConnectionReceivedMessage(RemoteInspectorXPCConnection*, NSString *messageName, NSDictionary *userInfo) override; virtual void xpcConnectionFailed(RemoteInspectorXPCConnection*) override; virtual void xpcConnectionUnhandledMessage(RemoteInspectorXPCConnection*, xpc_object_t) override; @@ -94,6 +99,8 @@ private: void receivedIndicateMessage(NSDictionary *userInfo); void receivedProxyApplicationSetupMessage(NSDictionary *userInfo); void receivedConnectionDiedMessage(NSDictionary *userInfo); + void receivedAutomaticInspectionConfigurationMessage(NSDictionary *userInfo); + void receivedAutomaticInspectionRejectMessage(NSDictionary *userInfo); static bool startEnabled; @@ -117,6 +124,9 @@ private: pid_t m_parentProcessIdentifier; RetainPtr<CFDataRef> m_parentProcessAuditData; bool m_shouldSendParentProcessInformation; + bool m_automaticInspectionEnabled; + bool m_automaticInspectionPaused; + unsigned m_automaticInspectionCandidateIdentifier; }; } // namespace Inspector diff --git a/inspector/remote/RemoteInspector.mm b/inspector/remote/RemoteInspector.mm index 9e05801..6814dd3 100644 --- a/inspector/remote/RemoteInspector.mm +++ b/inspector/remote/RemoteInspector.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2013, 2014 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,28 +33,41 @@ #import "RemoteInspectorDebuggable.h" #import "RemoteInspectorDebuggableConnection.h" #import <Foundation/Foundation.h> +#import <dispatch/dispatch.h> #import <notify.h> #import <wtf/Assertions.h> +#import <wtf/MainThread.h> #import <wtf/NeverDestroyed.h> +#import <wtf/spi/darwin/XPCSPI.h> #import <wtf/text/WTFString.h> -#import <xpc/xpc.h> -#if PLATFORM(IOS) -#import <wtf/ios/WebCoreThread.h> +#if __has_include(<sandbox/private.h>) +#import <sandbox/private.h> +#else +enum sandbox_filter_type { + SANDBOX_FILTER_GLOBAL_NAME = 2, +}; #endif +extern "C" int sandbox_check(pid_t, const char *operation, enum sandbox_filter_type, ...); +extern "C" const enum sandbox_filter_type SANDBOX_CHECK_NO_REPORT; + namespace Inspector { -static void dispatchAsyncOnQueueSafeForAnyDebuggable(void (^block)()) +static bool canAccessWebInspectorMachPort() { -#if PLATFORM(IOS) - if (WebCoreWebThreadIsEnabled && WebCoreWebThreadIsEnabled()) { - WebCoreWebThreadRun(block); - return; - } -#endif + return sandbox_check(getpid(), "mach-lookup", static_cast<enum sandbox_filter_type>(SANDBOX_FILTER_GLOBAL_NAME | SANDBOX_CHECK_NO_REPORT), WIRXPCMachPortName) == 0; +} + +static bool globalAutomaticInspectionState() +{ + int token = 0; + if (notify_register_check(WIRAutomaticInspectionEnabledState, &token) != NOTIFY_STATUS_OK) + return false; - dispatch_async(dispatch_get_main_queue(), block); + uint64_t automaticInspectionEnabled = 0; + notify_get_state(token, &automaticInspectionEnabled); + return automaticInspectionEnabled == 1; } bool RemoteInspector::startEnabled = true; @@ -64,15 +77,29 @@ void RemoteInspector::startDisabled() RemoteInspector::startEnabled = false; } -RemoteInspector& RemoteInspector::shared() +RemoteInspector& RemoteInspector::singleton() { static NeverDestroyed<RemoteInspector> shared; static dispatch_once_t once; dispatch_once(&once, ^{ - JSC::initializeThreading(); - if (RemoteInspector::startEnabled) - shared.get().start(); + if (canAccessWebInspectorMachPort()) { + dispatch_block_t initialize = ^{ + WTF::initializeMainThread(); + JSC::initializeThreading(); + if (RemoteInspector::startEnabled) + shared.get().start(); + }; + + if ([NSThread isMainThread]) + initialize(); + else { + // FIXME: This means that we may miss an auto-attach to a JSContext created on a non-main thread. + // The main thread initialization is required for certain WTF values that need to be initialized + // on the "real" main thread. We should investigate a better way to handle this. + dispatch_async(dispatch_get_main_queue(), initialize); + } + } }); return shared; @@ -87,6 +114,9 @@ RemoteInspector::RemoteInspector() , m_pushScheduled(false) , m_parentProcessIdentifier(0) , m_shouldSendParentProcessInformation(false) + , m_automaticInspectionEnabled(false) + , m_automaticInspectionPaused(false) + , m_automaticInspectionCandidateIdentifier(0) { } @@ -145,6 +175,74 @@ void RemoteInspector::updateDebuggable(RemoteInspectorDebuggable* debuggable) pushListingSoon(); } +void RemoteInspector::updateDebuggableAutomaticInspectCandidate(RemoteInspectorDebuggable* debuggable) +{ + { + std::lock_guard<std::mutex> lock(m_mutex); + + unsigned identifier = debuggable->identifier(); + if (!identifier) + return; + + auto result = m_debuggableMap.set(identifier, std::make_pair(debuggable, debuggable->info())); + ASSERT_UNUSED(result, !result.isNewEntry); + + // Don't allow automatic inspection unless it is allowed or we are stopped. + if (!m_automaticInspectionEnabled || !m_enabled) { + pushListingSoon(); + return; + } + + // FIXME: We should handle multiple debuggables trying to pause at the same time on different threads. + // To make this work we will need to change m_automaticInspectionCandidateIdentifier to be a per-thread value. + // Multiple attempts on the same thread should not be possible because our nested run loop is in a special RWI mode. + if (m_automaticInspectionPaused) { + LOG_ERROR("Skipping Automatic Inspection Candidate with pageId(%u) because we are already paused waiting for pageId(%u)", identifier, m_automaticInspectionCandidateIdentifier); + pushListingSoon(); + return; + } + + m_automaticInspectionPaused = true; + m_automaticInspectionCandidateIdentifier = identifier; + + // If we are pausing before we have connected to webinspectord the candidate message will be sent as soon as the connection is established. + if (m_xpcConnection) { + pushListingNow(); + sendAutomaticInspectionCandidateMessage(); + } + + // In case debuggers fail to respond, or we cannot connect to webinspectord, automatically continue after a short period of time. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.8 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + std::lock_guard<std::mutex> lock(m_mutex); + if (m_automaticInspectionCandidateIdentifier == identifier) { + LOG_ERROR("Skipping Automatic Inspection Candidate with pageId(%u) because we failed to receive a response in time.", m_automaticInspectionCandidateIdentifier); + m_automaticInspectionPaused = false; + } + }); + } + + debuggable->pauseWaitingForAutomaticInspection(); + + { + std::lock_guard<std::mutex> lock(m_mutex); + + ASSERT(m_automaticInspectionCandidateIdentifier); + m_automaticInspectionCandidateIdentifier = 0; + } +} + +void RemoteInspector::sendAutomaticInspectionCandidateMessage() +{ + ASSERT(m_enabled); + ASSERT(m_automaticInspectionEnabled); + ASSERT(m_automaticInspectionPaused); + ASSERT(m_automaticInspectionCandidateIdentifier); + ASSERT(m_xpcConnection); + + NSDictionary *details = @{WIRPageIdentifierKey: @(m_automaticInspectionCandidateIdentifier)}; + m_xpcConnection->sendMessage(WIRAutomaticInspectionCandidateMessage, details); +} + void RemoteInspector::sendMessageToRemoteFrontend(unsigned identifier, const String& message) { std::lock_guard<std::mutex> lock(m_mutex); @@ -173,9 +271,26 @@ void RemoteInspector::setupFailed(unsigned identifier) updateHasActiveDebugSession(); + if (identifier == m_automaticInspectionCandidateIdentifier) + m_automaticInspectionPaused = false; + pushListingSoon(); } +void RemoteInspector::setupCompleted(unsigned identifier) +{ + std::lock_guard<std::mutex> lock(m_mutex); + + if (identifier == m_automaticInspectionCandidateIdentifier) + m_automaticInspectionPaused = false; +} + +bool RemoteInspector::waitingForAutomaticInspection(unsigned) +{ + // We don't take the lock to check this because we assume it will be checked repeatedly. + return m_automaticInspectionPaused; +} + void RemoteInspector::start() { std::lock_guard<std::mutex> lock(m_mutex); @@ -185,8 +300,14 @@ void RemoteInspector::start() m_enabled = true; + // Load the initial automatic inspection state when first started, so we know it before we have even connected to webinspectord. + static dispatch_once_t once; + dispatch_once(&once, ^{ + m_automaticInspectionEnabled = globalAutomaticInspectionState(); + }); + notify_register_dispatch(WIRServiceAvailableNotification, &m_notifyToken, m_xpcQueue, ^(int) { - RemoteInspector::shared().setupXPCConnectionIfNeeded(); + RemoteInspector::singleton().setupXPCConnectionIfNeeded(); }); notify_post(WIRServiceAvailabilityCheckNotification); @@ -214,6 +335,8 @@ void RemoteInspector::stopInternal(StopSource source) updateHasActiveDebugSession(); + m_automaticInspectionPaused = false; + if (m_xpcConnection) { switch (source) { case StopSource::API: @@ -245,7 +368,12 @@ void RemoteInspector::setupXPCConnectionIfNeeded() m_xpcConnection->sendMessage(@"syn", nil); // Send a simple message to initialize the XPC connection. xpc_release(connection); - pushListingSoon(); + if (m_automaticInspectionCandidateIdentifier) { + // We already have a debuggable waiting to be automatically inspected. + pushListingNow(); + sendAutomaticInspectionCandidateMessage(); + } else + pushListingSoon(); } #pragma mark - Proxy Application Information @@ -289,6 +417,10 @@ void RemoteInspector::xpcConnectionReceivedMessage(RemoteInspectorXPCConnection* receivedProxyApplicationSetupMessage(userInfo); else if ([messageName isEqualToString:WIRConnectionDiedMessage]) receivedConnectionDiedMessage(userInfo); + else if ([messageName isEqualToString:WIRAutomaticInspectionConfigurationMessage]) + receivedAutomaticInspectionConfigurationMessage(userInfo); + else if ([messageName isEqualToString:WIRAutomaticInspectionRejectMessage]) + receivedAutomaticInspectionRejectMessage(userInfo); else NSLog(@"Unrecognized RemoteInspector XPC Message: %@", messageName); } @@ -309,6 +441,8 @@ void RemoteInspector::xpcConnectionFailed(RemoteInspectorXPCConnection* connecti updateHasActiveDebugSession(); + m_automaticInspectionPaused = false; + // The connection will close itself. m_xpcConnection = nullptr; } @@ -408,6 +542,7 @@ void RemoteInspector::updateHasActiveDebugSession() // Legacy iOS WebKit 1 had a notification. This will need to be smarter with WebKit2. } + #pragma mark - Received XPC Messages void RemoteInspector::receivedSetupMessage(NSDictionary *userInfo) @@ -436,7 +571,14 @@ void RemoteInspector::receivedSetupMessage(NSDictionary *userInfo) RemoteInspectorDebuggable* debuggable = it->value.first; RemoteInspectorDebuggableInfo debuggableInfo = it->value.second; RefPtr<RemoteInspectorDebuggableConnection> connection = adoptRef(new RemoteInspectorDebuggableConnection(debuggable, connectionIdentifier, sender, debuggableInfo.type)); - if (!connection->setup()) { + bool isAutomaticInspection = m_automaticInspectionCandidateIdentifier == debuggable->identifier(); + + bool automaticallyPause = false; + NSNumber *automaticallyPauseObject = [userInfo objectForKey:WIRAutomaticallyPause]; + if ([automaticallyPauseObject isKindOfClass:[NSNumber class]]) + automaticallyPause = [automaticallyPauseObject boolValue]; + + if (!connection->setup(isAutomaticInspection, automaticallyPause)) { connection->close(); return; } @@ -504,7 +646,7 @@ void RemoteInspector::receivedIndicateMessage(NSDictionary *userInfo) unsigned identifier = [pageId unsignedIntValue]; BOOL indicateEnabled = [[userInfo objectForKey:WIRIndicateEnabledKey] boolValue]; - dispatchAsyncOnQueueSafeForAnyDebuggable(^{ + callOnWebThreadOrDispatchAsyncOnMainThread(^{ RemoteInspectorDebuggable* debuggable = nullptr; { std::lock_guard<std::mutex> lock(m_mutex); @@ -568,6 +710,23 @@ void RemoteInspector::receivedConnectionDiedMessage(NSDictionary *userInfo) updateHasActiveDebugSession(); } +void RemoteInspector::receivedAutomaticInspectionConfigurationMessage(NSDictionary *userInfo) +{ + m_automaticInspectionEnabled = [[userInfo objectForKey:WIRAutomaticInspectionEnabledKey] boolValue]; + + if (!m_automaticInspectionEnabled && m_automaticInspectionPaused) + m_automaticInspectionPaused = false; +} + +void RemoteInspector::receivedAutomaticInspectionRejectMessage(NSDictionary *userInfo) +{ + unsigned rejectionIdentifier = [[userInfo objectForKey:WIRPageIdentifierKey] unsignedIntValue]; + + ASSERT(rejectionIdentifier == m_automaticInspectionCandidateIdentifier); + if (rejectionIdentifier == m_automaticInspectionCandidateIdentifier) + m_automaticInspectionPaused = false; +} + } // namespace Inspector #endif // ENABLE(REMOTE_INSPECTOR) diff --git a/inspector/remote/RemoteInspectorConstants.h b/inspector/remote/RemoteInspectorConstants.h index 647b22e..5d9ddbd 100644 --- a/inspector/remote/RemoteInspectorConstants.h +++ b/inspector/remote/RemoteInspectorConstants.h @@ -37,12 +37,14 @@ #define WIRServiceAvailabilityCheckNotification "com.apple.webinspectord.availability_check" #define WIRServiceEnabledNotification "com.apple.webinspectord.enabled" #define WIRServiceDisabledNotification "com.apple.webinspectord.disabled" +#define WIRAutomaticInspectionEnabledState "com.apple.webinspectord.automatic_inspection_enabled" #define WIRApplicationIdentifierKey @"WIRApplicationIdentifierKey" #define WIRApplicationBundleIdentifierKey @"WIRApplicationBundleIdentifierKey" #define WIRApplicationNameKey @"WIRApplicationNameKey" #define WIRIsApplicationProxyKey @"WIRIsApplicationProxyKey" +#define WIRIsApplicationActiveKey @"WIRIsApplicationActiveKey" #define WIRHostApplicationIdentifierKey @"WIRHostApplicationIdentifierKey" #define WIRHostApplicationNameKey @"WIRHostApplicationNameKey" #define WIRConnectionIdentifierKey @"WIRConnectionIdentifierKey" @@ -70,6 +72,13 @@ #define WIRTypeKey @"WIRTypeKey" #define WIRTypeJavaScript @"WIRTypeJavaScript" #define WIRTypeWeb @"WIRTypeWeb" +#define WIRAutomaticallyPause @"WIRAutomaticallyPause" + +#define WIRAutomaticInspectionEnabledKey @"WIRAutomaticInspectionEnabledKey" +#define WIRAutomaticInspectionSessionIdentifierKey @"WIRAutomaticInspectionSessionIdentifierKey" +#define WIRAutomaticInspectionConfigurationMessage @"WIRAutomaticInspectionConfigurationMessage" +#define WIRAutomaticInspectionRejectMessage @"WIRAutomaticInspectionRejectMessage" +#define WIRAutomaticInspectionCandidateMessage @"WIRAutomaticInspectionCandidateMessage" // These definitions are shared with a Simulator webinspectord and // OS X process communicating with it. diff --git a/inspector/remote/RemoteInspectorDebuggable.cpp b/inspector/remote/RemoteInspectorDebuggable.cpp index fdf1d96..ac83a18 100644 --- a/inspector/remote/RemoteInspectorDebuggable.cpp +++ b/inspector/remote/RemoteInspectorDebuggable.cpp @@ -28,6 +28,7 @@ #if ENABLE(REMOTE_INSPECTOR) +#include "EventLoop.h" #include "InspectorFrontendChannel.h" #include "RemoteInspector.h" @@ -41,17 +42,17 @@ RemoteInspectorDebuggable::RemoteInspectorDebuggable() RemoteInspectorDebuggable::~RemoteInspectorDebuggable() { - RemoteInspector::shared().unregisterDebuggable(this); + RemoteInspector::singleton().unregisterDebuggable(this); } void RemoteInspectorDebuggable::init() { - RemoteInspector::shared().registerDebuggable(this); + RemoteInspector::singleton().registerDebuggable(this); } void RemoteInspectorDebuggable::update() { - RemoteInspector::shared().updateDebuggable(this); + RemoteInspector::singleton().updateDebuggable(this); } void RemoteInspectorDebuggable::setRemoteDebuggingAllowed(bool allowed) @@ -61,7 +62,10 @@ void RemoteInspectorDebuggable::setRemoteDebuggingAllowed(bool allowed) m_allowed = allowed; - update(); + if (m_allowed && automaticInspectionAllowed()) + RemoteInspector::singleton().updateDebuggableAutomaticInspectCandidate(this); + else + RemoteInspector::singleton().updateDebuggable(this); } RemoteInspectorDebuggableInfo RemoteInspectorDebuggable::info() const @@ -76,6 +80,22 @@ RemoteInspectorDebuggableInfo RemoteInspectorDebuggable::info() const return info; } +void RemoteInspectorDebuggable::pauseWaitingForAutomaticInspection() +{ + ASSERT(m_identifier); + ASSERT(m_allowed); + ASSERT(automaticInspectionAllowed()); + + EventLoop loop; + while (RemoteInspector::singleton().waitingForAutomaticInspection(identifier()) && !loop.ended()) + loop.cycle(); +} + +void RemoteInspectorDebuggable::unpauseForInitializedInspector() +{ + RemoteInspector::singleton().setupCompleted(identifier()); +} + } // namespace Inspector #endif // ENABLE(REMOTE_INSPECTOR) diff --git a/inspector/remote/RemoteInspectorDebuggable.h b/inspector/remote/RemoteInspectorDebuggable.h index d480968..064b83a 100644 --- a/inspector/remote/RemoteInspectorDebuggable.h +++ b/inspector/remote/RemoteInspectorDebuggable.h @@ -34,7 +34,8 @@ namespace Inspector { -class InspectorFrontendChannel; +class FrontendChannel; + struct RemoteInspectorDebuggableInfo; class JS_EXPORT_PRIVATE RemoteInspectorDebuggable { @@ -62,10 +63,15 @@ public: virtual String url() const { return String(); } // Web virtual bool hasLocalDebugger() const = 0; - virtual void connect(InspectorFrontendChannel*) = 0; + virtual void connect(FrontendChannel*, bool isAutomaticInspection) = 0; virtual void disconnect() = 0; virtual void dispatchMessageFromRemoteFrontend(const String& message) = 0; virtual void setIndicating(bool) { } // Default is to do nothing. + virtual void pause() { }; + + virtual bool automaticInspectionAllowed() const { return false; } + virtual void pauseWaitingForAutomaticInspection(); + virtual void unpauseForInitializedInspector(); private: unsigned m_identifier; diff --git a/inspector/remote/RemoteInspectorDebuggableConnection.h b/inspector/remote/RemoteInspectorDebuggableConnection.h index 2bec437..cedb7ab 100644 --- a/inspector/remote/RemoteInspectorDebuggableConnection.h +++ b/inspector/remote/RemoteInspectorDebuggableConnection.h @@ -30,7 +30,6 @@ #import "InspectorFrontendChannel.h" #import "RemoteInspectorDebuggable.h" -#import <dispatch/dispatch.h> #import <mutex> #import <wtf/RetainPtr.h> #import <wtf/ThreadSafeRefCounted.h> @@ -75,7 +74,7 @@ private: typedef Vector<RemoteInspectorBlock> RemoteInspectorQueue; -class RemoteInspectorDebuggableConnection final : public ThreadSafeRefCounted<RemoteInspectorDebuggableConnection>, public InspectorFrontendChannel { +class RemoteInspectorDebuggableConnection final : public ThreadSafeRefCounted<RemoteInspectorDebuggableConnection>, public FrontendChannel { public: RemoteInspectorDebuggableConnection(RemoteInspectorDebuggable*, NSString *connectionIdentifier, NSString *destination, RemoteInspectorDebuggable::DebuggableType); virtual ~RemoteInspectorDebuggableConnection(); @@ -84,7 +83,7 @@ public: NSString *connectionIdentifier() const; unsigned identifier() const { return m_identifier; } - bool setup(); + bool setup(bool isAutomaticInspection, bool automaticallyPause); void close(); void closeFromDebuggable(); diff --git a/inspector/remote/RemoteInspectorDebuggableConnection.mm b/inspector/remote/RemoteInspectorDebuggableConnection.mm index 9b2d008..0821266 100644 --- a/inspector/remote/RemoteInspectorDebuggableConnection.mm +++ b/inspector/remote/RemoteInspectorDebuggableConnection.mm @@ -30,6 +30,7 @@ #import "EventLoop.h" #import "RemoteInspector.h" +#import <dispatch/dispatch.h> #import <wtf/Vector.h> #if PLATFORM(IOS) @@ -83,7 +84,7 @@ static void RemoteInspectorInitializeGlobalQueue() rwiQueueMutex = std::make_unique<std::mutex>().release(); CFRunLoopSourceContext runLoopSourceContext = {0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteInspectorHandleRunSourceGlobal}; - rwiRunLoopSource = CFRunLoopSourceCreate(nullptr, 1, &runLoopSourceContext); + rwiRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext); // Add to the default run loop mode for default handling, and the JSContext remote inspector run loop mode when paused. CFRunLoopAddSource(CFRunLoopGetMain(), rwiRunLoopSource, kCFRunLoopDefaultMode); @@ -149,7 +150,7 @@ void RemoteInspectorDebuggableConnection::dispatchAsyncOnDebuggable(void (^block RemoteInspectorQueueTaskOnGlobalQueue(block); } -bool RemoteInspectorDebuggableConnection::setup() +bool RemoteInspectorDebuggableConnection::setup(bool isAutomaticInspection, bool automaticallyPause) { std::lock_guard<std::mutex> lock(m_debuggableMutex); @@ -161,11 +162,14 @@ bool RemoteInspectorDebuggableConnection::setup() { std::lock_guard<std::mutex> lock(m_debuggableMutex); if (!m_debuggable || !m_debuggable->remoteDebuggingAllowed() || m_debuggable->hasLocalDebugger()) { - RemoteInspector::shared().setupFailed(identifier()); + RemoteInspector::singleton().setupFailed(identifier()); m_debuggable = nullptr; } else { - m_debuggable->connect(this); + m_debuggable->connect(this, isAutomaticInspection); m_connected = true; + + if (automaticallyPause) + m_debuggable->pause(); } } deref(); @@ -220,7 +224,7 @@ void RemoteInspectorDebuggableConnection::sendMessageToBackend(NSString *message bool RemoteInspectorDebuggableConnection::sendMessageToFrontend(const String& message) { - RemoteInspector::shared().sendMessageToRemoteFrontend(identifier(), message); + RemoteInspector::singleton().sendMessageToRemoteFrontend(identifier(), message); return true; } @@ -236,7 +240,7 @@ void RemoteInspectorDebuggableConnection::setupRunLoop() m_runLoop = debuggerRunLoop; CFRunLoopSourceContext runLoopSourceContext = {0, this, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RemoteInspectorHandleRunSourceWithInfo}; - m_runLoopSource = CFRunLoopSourceCreate(nullptr, 1, &runLoopSourceContext); + m_runLoopSource = adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 1, &runLoopSourceContext)); CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopDefaultMode); CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), EventLoop::remoteInspectorRunLoopMode()); diff --git a/inspector/remote/RemoteInspectorXPCConnection.h b/inspector/remote/RemoteInspectorXPCConnection.h index f1fe819..023db2b 100644 --- a/inspector/remote/RemoteInspectorXPCConnection.h +++ b/inspector/remote/RemoteInspectorXPCConnection.h @@ -31,7 +31,7 @@ #import <dispatch/dispatch.h> #import <mutex> #import <wtf/ThreadSafeRefCounted.h> -#import <xpc/xpc.h> +#import <wtf/spi/darwin/XPCSPI.h> OBJC_CLASS NSDictionary; OBJC_CLASS NSString; diff --git a/inspector/remote/RemoteInspectorXPCConnection.mm b/inspector/remote/RemoteInspectorXPCConnection.mm index af1ccc5..6c337d8 100644 --- a/inspector/remote/RemoteInspectorXPCConnection.mm +++ b/inspector/remote/RemoteInspectorXPCConnection.mm @@ -31,12 +31,16 @@ #import <Foundation/Foundation.h> #import <wtf/Assertions.h> #import <wtf/Ref.h> +#import <wtf/RetainPtr.h> +#import <wtf/spi/darwin/XPCSPI.h> #if __has_include(<CoreFoundation/CFXPCBridge.h>) #import <CoreFoundation/CFXPCBridge.h> #else -extern "C" xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef); -extern "C" CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t); +extern "C" { + xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef); + CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t); +} #endif namespace Inspector { @@ -96,12 +100,12 @@ void RemoteInspectorXPCConnection::closeOnQueue() if (m_connection) { xpc_connection_cancel(m_connection); xpc_release(m_connection); - m_connection = NULL; + m_connection = nullptr; } if (m_queue) { dispatch_release(m_queue); - m_queue = NULL; + m_queue = nullptr; } } @@ -118,9 +122,9 @@ NSDictionary *RemoteInspectorXPCConnection::deserializeMessage(xpc_object_t obje return nil; } - NSDictionary *dictionary = static_cast<NSDictionary *>(_CFXPCCreateCFObjectFromXPCMessage(xpcDictionary)); + RetainPtr<CFDictionaryRef> dictionary = adoptCF((CFDictionaryRef)_CFXPCCreateCFObjectFromXPCMessage(xpcDictionary)); ASSERT_WITH_MESSAGE(dictionary, "Unable to deserialize xpc message"); - return [dictionary autorelease]; + return (NSDictionary *)dictionary.autorelease(); } void RemoteInspectorXPCConnection::handleEvent(xpc_object_t object) @@ -170,7 +174,7 @@ void RemoteInspectorXPCConnection::sendMessage(NSString *messageName, NSDictiona if (!xpcDictionary) return; - xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_object_t msg = xpc_dictionary_create(nullptr, nullptr, 0); xpc_dictionary_set_value(msg, RemoteInspectorXPCConnectionSerializedMessageKey, xpcDictionary); xpc_release(xpcDictionary); diff --git a/inspector/scripts/CodeGeneratorInspector.py b/inspector/scripts/CodeGeneratorInspector.py deleted file mode 100755 index 91fa8c9..0000000 --- a/inspector/scripts/CodeGeneratorInspector.py +++ /dev/null @@ -1,2614 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2011 Google Inc. All rights reserved. -# Copyright (c) 2012 Intel Corporation. All rights reserved. -# Copyright (c) 2013 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: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER 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. - -import os.path -import sys -import string -import optparse -import re -try: - import json -except ImportError: - import simplejson as json - -import CodeGeneratorInspectorStrings - - -DOMAIN_DEFINE_NAME_MAP = { - "Database": "SQL_DATABASE", - "IndexedDB": "INDEXED_DATABASE", - "Replay": "WEB_REPLAY", -} - - -# Manually-filled map of type name replacements. -TYPE_NAME_FIX_MAP = { - "RGBA": "Rgba", # RGBA is reported to be conflicting with a define name in Windows CE. - "": "Empty", -} - - -TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.PropertyDescriptor", "Runtime.InternalPropertyDescriptor", - "Debugger.FunctionDetails", "Debugger.CallFrame", - "Canvas.TraceLog", "Canvas.ResourceInfo", "Canvas.ResourceState", - # This should be a temporary hack. TimelineEvent should be created via generated C++ API. - "Timeline.TimelineEvent"]) - -TYPES_WITH_OPEN_FIELD_LIST_SET = frozenset(["Timeline.TimelineEvent", - # InspectorStyleSheet not only creates this property but wants to read it and modify it. - "CSS.CSSProperty", - # InspectorResourceAgent needs to update mime-type. - "Network.Response"]) - -EXACTLY_INT_SUPPORTED = False - -INSPECTOR_TYPES_GENERATOR_CONFIG_MAP = { - "JavaScript": { - "prefix": "JS", - "typebuilder_dependency": "", - "export_macro": "JS_EXPORT_PRIVATE", - }, - "Web": { - "prefix": "Web", - "typebuilder_dependency": "#include <inspector/InspectorJSTypeBuilders.h>", - "export_macro": "", - }, -} - -cmdline_parser = optparse.OptionParser(usage="usage: %prog [options] <Inspector.json>") -cmdline_parser.add_option("--output_h_dir") -cmdline_parser.add_option("--output_cpp_dir") -cmdline_parser.add_option("--output_js_dir") -cmdline_parser.add_option("--output_type") # JavaScript, Web -cmdline_parser.add_option("--write_always", action="store_true") -cmdline_parser.add_option("--no_verification", action="store_true") - -try: - arg_options, arg_values = cmdline_parser.parse_args() - if (len(arg_values) < 1): - raise Exception("At least one plain argument expected") - - input_json_filename = arg_values[0] - dependency_json_filenames = arg_values[1:] - - output_header_dirname = arg_options.output_h_dir - output_cpp_dirname = arg_options.output_cpp_dir - output_js_dirname = arg_options.output_js_dir - output_type = arg_options.output_type - - write_always = arg_options.write_always - verification = not arg_options.no_verification - if not output_header_dirname: - raise Exception("Output .h directory must be specified") - if not output_cpp_dirname: - raise Exception("Output .cpp directory must be specified") - if not output_js_dirname: - raise Exception("Output .js directory must be specified") - if output_type not in INSPECTOR_TYPES_GENERATOR_CONFIG_MAP.keys(): - raise Exception("Unknown output type. Allowed types are: %s" % INSPECTOR_TYPES_GENERATOR_CONFIG_MAP.keys()) -except Exception: - # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html - exc = sys.exc_info()[1] - sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) - sys.stderr.write("Usage: <script> Inspector.json --output_h_dir <output_header_dir> --output_cpp_dir <output_cpp_dir> --output_js_dir <output_js_dir> [--write_always] [--no_verification]\n") - exit(1) - - -def dash_to_camelcase(word): - return ''.join(x.capitalize() or '-' for x in word.split('-')) - - -def fix_camel_case(name): - refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name) - refined = to_title_case(refined) - return re.sub(r'(?i)HTML|XML|WML|API|GC|XHR|DOM|CSS', lambda pat: pat.group(0).upper(), refined) - - -def to_title_case(name): - return name[:1].upper() + name[1:] - - -class Capitalizer: - @staticmethod - def lower_camel_case_to_upper(str): - if len(str) > 0 and str[0].islower(): - str = str[0].upper() + str[1:] - return str - - @staticmethod - def upper_camel_case_to_lower(str): - pos = 0 - while pos < len(str) and str[pos].isupper(): - pos += 1 - if pos == 0: - return str - if pos == 1: - return str[0].lower() + str[1:] - if pos < len(str): - pos -= 1 - possible_abbreviation = str[0:pos] - if possible_abbreviation not in Capitalizer.ABBREVIATION: - raise Exception("Unknown abbreviation %s" % possible_abbreviation) - str = possible_abbreviation.lower() + str[pos:] - return str - - @staticmethod - def camel_case_to_capitalized_with_underscores(str): - if len(str) == 0: - return str - output = Capitalizer.split_camel_case_(str) - return "_".join(output).upper() - - @staticmethod - def split_camel_case_(str): - output = [] - pos_being = 0 - pos = 1 - has_oneletter = False - while pos < len(str): - if str[pos].isupper(): - output.append(str[pos_being:pos].upper()) - if pos - pos_being == 1: - has_oneletter = True - pos_being = pos - pos += 1 - output.append(str[pos_being:]) - if has_oneletter: - array_pos = 0 - while array_pos < len(output) - 1: - if len(output[array_pos]) == 1: - array_pos_end = array_pos + 1 - while array_pos_end < len(output) and len(output[array_pos_end]) == 1: - array_pos_end += 1 - if array_pos_end - array_pos > 1: - possible_abbreviation = "".join(output[array_pos:array_pos_end]) - if possible_abbreviation.upper() in Capitalizer.ABBREVIATION: - output[array_pos:array_pos_end] = [possible_abbreviation] - else: - array_pos = array_pos_end - 1 - array_pos += 1 - return output - - ABBREVIATION = frozenset(["XHR", "DOM", "CSS"]) - -VALIDATOR_IFDEF_NAME = "!ASSERT_DISABLED" - - -class DomainNameFixes: - @classmethod - def get_fixed_data(cls, domain_name): - field_name_res = Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent" - - class Res(object): - skip_js_bind = domain_name in cls.skip_js_bind_domains - - @staticmethod - def get_guard(): - if domain_name in DOMAIN_DEFINE_NAME_MAP: - define_name = DOMAIN_DEFINE_NAME_MAP[domain_name] - - class Guard: - @staticmethod - def generate_open(output): - output.append("#if ENABLE(%s)\n" % define_name) - - @staticmethod - def generate_close(output): - output.append("#endif // ENABLE(%s)\n" % define_name) - - return Guard - - return Res - - skip_js_bind_domains = set(["DOMDebugger"]) - - -class RawTypes(object): - @staticmethod - def get(json_type): - if json_type == "boolean": - return RawTypes.Bool - elif json_type == "string": - return RawTypes.String - elif json_type == "array": - return RawTypes.Array - elif json_type == "object": - return RawTypes.Object - elif json_type == "integer": - return RawTypes.Int - elif json_type == "number": - return RawTypes.Number - elif json_type == "any": - return RawTypes.Any - else: - raise Exception("Unknown type: %s" % json_type) - - # For output parameter all values are passed by pointer except RefPtr-based types. - class OutputPassModel: - class ByPointer: - @staticmethod - def get_argument_prefix(): - return "&" - - @staticmethod - def get_parameter_type_suffix(): - return "*" - - class ByReference: - @staticmethod - def get_argument_prefix(): - return "" - - @staticmethod - def get_parameter_type_suffix(): - return "&" - - class BaseType(object): - need_internal_runtime_cast_ = False - - @classmethod - def request_raw_internal_runtime_cast(cls): - if not cls.need_internal_runtime_cast_: - cls.need_internal_runtime_cast_ = True - - @classmethod - def get_raw_validator_call_text(cls): - return "RuntimeCastHelper::assertType<Inspector::InspectorValue::Type%s>" % cls.get_validate_method_params().template_type - - class String(BaseType): - @staticmethod - def get_getter_name(): - return "String" - - get_setter_name = get_getter_name - - @staticmethod - def get_c_initializer(): - return "\"\"" - - @staticmethod - def get_js_bind_type(): - return "string" - - @staticmethod - def get_validate_method_params(): - class ValidateMethodParams: - template_type = "String" - return ValidateMethodParams - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByPointer - - @staticmethod - def is_heavy_value(): - return True - - @staticmethod - def get_array_item_raw_c_type_text(): - return "String" - - @staticmethod - def get_raw_type_model(): - return TypeModel.String - - class Int(BaseType): - @staticmethod - def get_getter_name(): - return "Int" - - @staticmethod - def get_setter_name(): - return "Number" - - @staticmethod - def get_c_initializer(): - return "0" - - @staticmethod - def get_js_bind_type(): - return "number" - - @classmethod - def get_raw_validator_call_text(cls): - return "RuntimeCastHelper::assertInt" - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByPointer - - @staticmethod - def is_heavy_value(): - return False - - @staticmethod - def get_array_item_raw_c_type_text(): - return "int" - - @staticmethod - def get_raw_type_model(): - return TypeModel.Int - - class Number(BaseType): - @staticmethod - def get_getter_name(): - return "Double" - - @staticmethod - def get_setter_name(): - return "Number" - - @staticmethod - def get_c_initializer(): - return "0" - - @staticmethod - def get_js_bind_type(): - return "number" - - @staticmethod - def get_validate_method_params(): - class ValidateMethodParams: - template_type = "Number" - return ValidateMethodParams - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByPointer - - @staticmethod - def is_heavy_value(): - return False - - @staticmethod - def get_array_item_raw_c_type_text(): - return "double" - - @staticmethod - def get_raw_type_model(): - return TypeModel.Number - - class Bool(BaseType): - @staticmethod - def get_getter_name(): - return "Boolean" - - get_setter_name = get_getter_name - - @staticmethod - def get_c_initializer(): - return "false" - - @staticmethod - def get_js_bind_type(): - return "boolean" - - @staticmethod - def get_validate_method_params(): - class ValidateMethodParams: - template_type = "Boolean" - return ValidateMethodParams - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByPointer - - @staticmethod - def is_heavy_value(): - return False - - @staticmethod - def get_array_item_raw_c_type_text(): - return "bool" - - @staticmethod - def get_raw_type_model(): - return TypeModel.Bool - - class Object(BaseType): - @staticmethod - def get_getter_name(): - return "Object" - - @staticmethod - def get_setter_name(): - return "Value" - - @staticmethod - def get_c_initializer(): - return "InspectorObject::create()" - - @staticmethod - def get_js_bind_type(): - return "object" - - @staticmethod - def get_output_argument_prefix(): - return "" - - @staticmethod - def get_validate_method_params(): - class ValidateMethodParams: - template_type = "Object" - return ValidateMethodParams - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByReference - - @staticmethod - def is_heavy_value(): - return True - - @staticmethod - def get_array_item_raw_c_type_text(): - return "Inspector::InspectorObject" - - @staticmethod - def get_raw_type_model(): - return TypeModel.Object - - class Any(BaseType): - @staticmethod - def get_getter_name(): - return "Value" - - get_setter_name = get_getter_name - - @staticmethod - def get_c_initializer(): - raise Exception("Unsupported") - - @staticmethod - def get_js_bind_type(): - raise Exception("Unsupported") - - @staticmethod - def get_raw_validator_call_text(): - return "RuntimeCastHelper::assertAny" - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByReference - - @staticmethod - def is_heavy_value(): - return True - - @staticmethod - def get_array_item_raw_c_type_text(): - return "Inspector::InspectorValue" - - @staticmethod - def get_raw_type_model(): - return TypeModel.Any - - class Array(BaseType): - @staticmethod - def get_getter_name(): - return "Array" - - @staticmethod - def get_setter_name(): - return "Value" - - @staticmethod - def get_c_initializer(): - return "InspectorArray::create()" - - @staticmethod - def get_js_bind_type(): - return "object" - - @staticmethod - def get_output_argument_prefix(): - return "" - - @staticmethod - def get_validate_method_params(): - class ValidateMethodParams: - template_type = "Array" - return ValidateMethodParams - - @staticmethod - def get_output_pass_model(): - return RawTypes.OutputPassModel.ByReference - - @staticmethod - def is_heavy_value(): - return True - - @staticmethod - def get_array_item_raw_c_type_text(): - return "Inspector::InspectorArray" - - @staticmethod - def get_raw_type_model(): - return TypeModel.Array - - -def replace_right_shift(input_str): - return input_str.replace(">>", "> >") - - -class CommandReturnPassModel: - class ByReference: - def __init__(self, var_type, set_condition): - self.var_type = var_type - self.set_condition = set_condition - - def get_return_var_type(self): - return self.var_type - - @staticmethod - def get_output_argument_prefix(): - return "" - - @staticmethod - def get_output_to_raw_expression(): - return "%s" - - def get_output_parameter_type(self): - return self.var_type + "&" - - def get_set_return_condition(self): - return self.set_condition - - class ByPointer: - def __init__(self, var_type): - self.var_type = var_type - - def get_return_var_type(self): - return self.var_type - - @staticmethod - def get_output_argument_prefix(): - return "&" - - @staticmethod - def get_output_to_raw_expression(): - return "%s" - - def get_output_parameter_type(self): - return self.var_type + "*" - - @staticmethod - def get_set_return_condition(): - return None - - class OptOutput: - def __init__(self, var_type): - self.var_type = var_type - - def get_return_var_type(self): - return "Inspector::TypeBuilder::OptOutput<%s>" % self.var_type - - @staticmethod - def get_output_argument_prefix(): - return "&" - - @staticmethod - def get_output_to_raw_expression(): - return "%s.getValue()" - - def get_output_parameter_type(self): - return "Inspector::TypeBuilder::OptOutput<%s>*" % self.var_type - - @staticmethod - def get_set_return_condition(): - return "%s.isAssigned()" - - -class TypeModel: - class RefPtrBased(object): - def __init__(self, class_name): - self.class_name = class_name - self.optional = False - - def get_optional(self): - result = TypeModel.RefPtrBased(self.class_name) - result.optional = True - return result - - def get_command_return_pass_model(self): - if self.optional: - set_condition = "%s" - else: - set_condition = None - return CommandReturnPassModel.ByReference(replace_right_shift("RefPtr<%s>" % self.class_name), set_condition) - - def get_input_param_type_text(self): - return replace_right_shift("PassRefPtr<%s>" % self.class_name) - - @staticmethod - def get_event_setter_expression_pattern(): - return "%s" - - class Enum(object): - def __init__(self, base_type_name): - self.type_name = base_type_name + "::Enum" - - def get_optional(base_self): - class EnumOptional: - @classmethod - def get_optional(cls): - return cls - - @staticmethod - def get_command_return_pass_model(): - return CommandReturnPassModel.OptOutput(base_self.type_name) - - @staticmethod - def get_input_param_type_text(): - return base_self.type_name + "*" - - @staticmethod - def get_event_setter_expression_pattern(): - raise Exception("TODO") - return EnumOptional - - def get_command_return_pass_model(self): - return CommandReturnPassModel.ByPointer(self.type_name) - - def get_input_param_type_text(self): - return self.type_name - - @staticmethod - def get_event_setter_expression_pattern(): - return "%s" - - class ValueType(object): - def __init__(self, type_name, is_heavy): - self.type_name = type_name - self.is_heavy = is_heavy - - def get_optional(self): - return self.ValueOptional(self) - - def get_command_return_pass_model(self): - return CommandReturnPassModel.ByPointer(self.type_name) - - def get_input_param_type_text(self): - if self.is_heavy: - return "const %s&" % self.type_name - else: - return self.type_name - - def get_opt_output_type_(self): - return self.type_name - - @staticmethod - def get_event_setter_expression_pattern(): - return "%s" - - class ValueOptional: - def __init__(self, base): - self.base = base - - def get_optional(self): - return self - - def get_command_return_pass_model(self): - return CommandReturnPassModel.OptOutput(self.base.get_opt_output_type_()) - - def get_input_param_type_text(self): - return "const %s* const" % self.base.type_name - - @staticmethod - def get_event_setter_expression_pattern(): - return "*%s" - - class ExactlyInt(ValueType): - def __init__(self): - TypeModel.ValueType.__init__(self, "int", False) - - def get_input_param_type_text(self): - return "Inspector::TypeBuilder::ExactlyInt" - - def get_opt_output_type_(self): - return "Inspector::TypeBuilder::ExactlyInt" - - @classmethod - def init_class(cls): - cls.Bool = cls.ValueType("bool", False) - if EXACTLY_INT_SUPPORTED: - cls.Int = cls.ExactlyInt() - else: - cls.Int = cls.ValueType("int", False) - cls.Number = cls.ValueType("double", False) - cls.String = cls.ValueType("String", True,) - cls.Object = cls.RefPtrBased("Inspector::InspectorObject") - cls.Array = cls.RefPtrBased("Inspector::InspectorArray") - cls.Any = cls.RefPtrBased("Inspector::InspectorValue") - -TypeModel.init_class() - - -# Collection of InspectorObject class methods that are likely to be overloaded in generated class. -# We must explicitly import all overloaded methods or they won't be available to user. -INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"]) - - -def fix_type_name(json_name): - if json_name in TYPE_NAME_FIX_MAP: - fixed = TYPE_NAME_FIX_MAP[json_name] - - class Result(object): - class_name = fixed - - @staticmethod - def output_comment(writer): - writer.newline("// Type originally was named '%s'.\n" % json_name) - else: - - class Result(object): - class_name = json_name - - @staticmethod - def output_comment(writer): - pass - - return Result - - -class Writer: - def __init__(self, output, indent): - self.output = output - self.indent = indent - - def newline(self, str): - if (self.indent): - self.output.append(self.indent) - self.output.append(str) - - def append(self, str): - self.output.append(str) - - def newline_multiline(self, str): - parts = str.split('\n') - self.newline(parts[0]) - for p in parts[1:]: - self.output.append('\n') - if p: - self.newline(p) - - def append_multiline(self, str): - parts = str.split('\n') - self.append(parts[0]) - for p in parts[1:]: - self.output.append('\n') - if p: - self.newline(p) - - def get_indent(self): - return self.indent - - def get_indented(self, additional_indent): - return Writer(self.output, self.indent + additional_indent) - - def insert_writer(self, additional_indent): - new_output = [] - self.output.append(new_output) - return Writer(new_output, self.indent + additional_indent) - - -class EnumConstants: - map_ = {} - constants_ = [] - - @classmethod - def add_constant(cls, value): - if value in cls.map_: - return cls.map_[value] - else: - pos = len(cls.map_) - cls.map_[value] = pos - cls.constants_.append(value) - return pos - - @classmethod - def get_enum_constant_code(cls): - output = [] - for item in cls.constants_: - output.append(" \"" + item + "\"") - return ",\n".join(output) + "\n" - - -# Typebuilder code is generated in several passes: first typedefs, then other classes. -# Manual pass management is needed because we cannot have forward declarations for typedefs. -class TypeBuilderPass: - TYPEDEF = "typedef" - MAIN = "main" - - -class TypeBindings: - @staticmethod - def create_named_type_declaration(json_typable, context_domain_name, type_data): - json_type = type_data.get_json_type() - - class Helper: - is_ad_hoc = False - full_name_prefix_for_use = "Inspector::TypeBuilder::" + context_domain_name + "::" - full_name_prefix_for_impl = "Inspector::TypeBuilder::" + context_domain_name + "::" - - @staticmethod - def write_doc(writer): - if "description" in json_type: - writer.newline("/* ") - writer.append(json_type["description"]) - writer.append(" */\n") - - @staticmethod - def add_to_forward_listener(forward_listener): - forward_listener.add_type_data(type_data) - - - fixed_type_name = fix_type_name(json_type["id"]) - return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper) - - @staticmethod - def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc_type_context): - class Helper: - is_ad_hoc = True - full_name_prefix_for_use = ad_hoc_type_context.container_relative_name_prefix - full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_prefix - - @staticmethod - def write_doc(writer): - pass - - @staticmethod - def add_to_forward_listener(forward_listener): - pass - fixed_type_name = ad_hoc_type_context.get_type_name_fix() - return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper) - - @staticmethod - def create_type_declaration_(json_typable, context_domain_name, fixed_type_name, helper): - if json_typable["type"] == "string": - if "enum" in json_typable: - - class EnumBinding: - need_user_runtime_cast_ = False - need_internal_runtime_cast_ = False - - @classmethod - def resolve_inner(cls, resolve_context): - pass - - @classmethod - def request_user_runtime_cast(cls, request): - if request: - cls.need_user_runtime_cast_ = True - request.acknowledge() - - @classmethod - def request_internal_runtime_cast(cls): - cls.need_internal_runtime_cast_ = True - - @classmethod - def get_code_generator(enum_binding_cls): - #FIXME: generate ad-hoc enums too once we figure out how to better implement them in C++. - comment_out = helper.is_ad_hoc - - class CodeGenerator: - @staticmethod - def generate_type_builder(writer, generate_context): - enum = json_typable["enum"] - helper.write_doc(writer) - enum_name = fixed_type_name.class_name - fixed_type_name.output_comment(writer) - writer.newline("struct ") - writer.append(enum_name) - writer.append(" {\n") - writer.newline(" enum Enum {\n") - for enum_item in enum: - enum_pos = EnumConstants.add_constant(enum_item) - - item_c_name = fix_camel_case(enum_item) - if item_c_name in TYPE_NAME_FIX_MAP: - item_c_name = TYPE_NAME_FIX_MAP[item_c_name] - writer.newline(" ") - writer.append(item_c_name) - writer.append(" = ") - writer.append("%s" % enum_pos) - writer.append(",\n") - writer.newline(" };\n") - if enum_binding_cls.need_user_runtime_cast_: - raise Exception("Not yet implemented") - - if enum_binding_cls.need_internal_runtime_cast_: - writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME) - writer.newline(" static void assertCorrectValue(Inspector::InspectorValue* value);\n") - writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME) - - validator_writer = generate_context.validator_writer - - domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name) - domain_guard = domain_fixes.get_guard() - if domain_guard: - domain_guard.generate_open(validator_writer) - - validator_writer.newline("void %s%s::assertCorrectValue(Inspector::InspectorValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name)) - validator_writer.newline("{\n") - validator_writer.newline(" WTF::String s;\n") - validator_writer.newline(" bool cast_res = value->asString(&s);\n") - validator_writer.newline(" ASSERT(cast_res);\n") - if len(enum) > 0: - condition_list = [] - for enum_item in enum: - enum_pos = EnumConstants.add_constant(enum_item) - condition_list.append("s == \"%s\"" % enum_item) - validator_writer.newline(" ASSERT(%s);\n" % " || ".join(condition_list)) - validator_writer.newline("}\n") - - if domain_guard: - domain_guard.generate_close(validator_writer) - - validator_writer.newline("\n\n") - - writer.newline("}; // struct ") - writer.append(enum_name) - writer.append("\n") - - @staticmethod - def register_use(forward_listener): - pass - - @staticmethod - def get_generate_pass_id(): - return TypeBuilderPass.MAIN - - return CodeGenerator - - @classmethod - def get_validator_call_text(cls): - return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue" - - @classmethod - def get_array_item_c_type_text(cls): - return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::Enum" - - @staticmethod - def get_setter_value_expression_pattern(): - return "Inspector::TypeBuilder::get%sEnumConstantValue(%s)" - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.String - - @staticmethod - def get_type_model(): - return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name) - - return EnumBinding - else: - if helper.is_ad_hoc: - - class PlainString: - @classmethod - def resolve_inner(cls, resolve_context): - pass - - @staticmethod - def request_user_runtime_cast(request): - raise Exception("Unsupported") - - @staticmethod - def request_internal_runtime_cast(): - pass - - @staticmethod - def get_code_generator(): - return None - - @classmethod - def get_validator_call_text(cls): - return RawTypes.String.get_raw_validator_call_text() - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.String - - @staticmethod - def get_type_model(): - return TypeModel.String - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @classmethod - def get_array_item_c_type_text(cls): - return cls.reduce_to_raw_type().get_array_item_raw_c_type_text() - - return PlainString - - else: - - class TypedefString: - @classmethod - def resolve_inner(cls, resolve_context): - pass - - @staticmethod - def request_user_runtime_cast(request): - raise Exception("Unsupported") - - @staticmethod - def request_internal_runtime_cast(): - RawTypes.String.request_raw_internal_runtime_cast() - - @staticmethod - def get_code_generator(): - class CodeGenerator: - @staticmethod - def generate_type_builder(writer, generate_context): - helper.write_doc(writer) - fixed_type_name.output_comment(writer) - writer.newline("typedef String ") - writer.append(fixed_type_name.class_name) - writer.append(";\n\n") - - @staticmethod - def register_use(forward_listener): - pass - - @staticmethod - def get_generate_pass_id(): - return TypeBuilderPass.TYPEDEF - - return CodeGenerator - - @classmethod - def get_validator_call_text(cls): - return RawTypes.String.get_raw_validator_call_text() - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.String - - @staticmethod - def get_type_model(): - return TypeModel.ValueType("%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name), True) - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @classmethod - def get_array_item_c_type_text(cls): - return "const %s%s&" % (helper.full_name_prefix_for_use, fixed_type_name.class_name) - - return TypedefString - - elif json_typable["type"] == "integer": - if helper.is_ad_hoc: - - class PlainInteger: - @classmethod - def resolve_inner(cls, resolve_context): - pass - - @staticmethod - def request_user_runtime_cast(request): - raise Exception("Unsupported") - - @staticmethod - def request_internal_runtime_cast(): - pass - - @staticmethod - def get_code_generator(): - return None - - @classmethod - def get_validator_call_text(cls): - return RawTypes.Int.get_raw_validator_call_text() - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.Int - - @staticmethod - def get_type_model(): - return TypeModel.Int - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @classmethod - def get_array_item_c_type_text(cls): - return cls.reduce_to_raw_type().get_array_item_raw_c_type_text() - - return PlainInteger - - else: - - class TypedefInteger: - @classmethod - def resolve_inner(cls, resolve_context): - pass - - @staticmethod - def request_user_runtime_cast(request): - raise Exception("Unsupported") - - @staticmethod - def request_internal_runtime_cast(): - RawTypes.Int.request_raw_internal_runtime_cast() - - @staticmethod - def get_code_generator(): - class CodeGenerator: - @staticmethod - def generate_type_builder(writer, generate_context): - helper.write_doc(writer) - fixed_type_name.output_comment(writer) - writer.newline("typedef int ") - writer.append(fixed_type_name.class_name) - writer.append(";\n\n") - - @staticmethod - def register_use(forward_listener): - pass - - @staticmethod - def get_generate_pass_id(): - return TypeBuilderPass.TYPEDEF - - return CodeGenerator - - @classmethod - def get_validator_call_text(cls): - return RawTypes.Int.get_raw_validator_call_text() - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.Int - - @staticmethod - def get_type_model(): - return TypeModel.Int - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @classmethod - def get_array_item_c_type_text(cls): - return helper.full_name_prefix_for_use + fixed_type_name.class_name - - return TypedefInteger - - elif json_typable["type"] == "object": - if "properties" in json_typable: - - class ClassBinding: - resolve_data_ = None - need_user_runtime_cast_ = False - need_internal_runtime_cast_ = False - - @classmethod - def resolve_inner(cls, resolve_context): - if cls.resolve_data_: - return - - properties = json_typable["properties"] - main = [] - optional = [] - - ad_hoc_type_list = [] - - for prop in properties: - prop_name = prop["name"] - ad_hoc_type_context = cls.AdHocTypeContextImpl(prop_name, fixed_type_name.class_name, resolve_context, ad_hoc_type_list, helper.full_name_prefix_for_impl) - binding = resolve_param_type(prop, context_domain_name, ad_hoc_type_context) - - code_generator = binding.get_code_generator() - if code_generator: - code_generator.register_use(resolve_context.forward_listener) - - class PropertyData: - param_type_binding = binding - p = prop - - if prop.get("optional"): - optional.append(PropertyData) - else: - main.append(PropertyData) - - class ResolveData: - main_properties = main - optional_properties = optional - ad_hoc_types = ad_hoc_type_list - - cls.resolve_data_ = ResolveData - - for ad_hoc in ad_hoc_type_list: - ad_hoc.resolve_inner(resolve_context) - - @classmethod - def request_user_runtime_cast(cls, request): - if not request: - return - cls.need_user_runtime_cast_ = True - request.acknowledge() - cls.request_internal_runtime_cast() - - @classmethod - def request_internal_runtime_cast(cls): - if cls.need_internal_runtime_cast_: - return - cls.need_internal_runtime_cast_ = True - for p in cls.resolve_data_.main_properties: - p.param_type_binding.request_internal_runtime_cast() - for p in cls.resolve_data_.optional_properties: - p.param_type_binding.request_internal_runtime_cast() - - @classmethod - def get_code_generator(class_binding_cls): - class CodeGenerator: - @classmethod - def generate_type_builder(cls, writer, generate_context): - resolve_data = class_binding_cls.resolve_data_ - helper.write_doc(writer) - class_name = fixed_type_name.class_name - - is_open_type = (context_domain_name + "." + class_name) in TYPES_WITH_OPEN_FIELD_LIST_SET - - fixed_type_name.output_comment(writer) - writer.newline("class ") - writer.append(class_name) - writer.append(" : public ") - if is_open_type: - writer.append("Inspector::InspectorObject") - else: - writer.append("Inspector::InspectorObjectBase") - writer.append(" {\n") - writer.newline("public:\n") - ad_hoc_type_writer = writer.insert_writer(" ") - - for ad_hoc_type in resolve_data.ad_hoc_types: - code_generator = ad_hoc_type.get_code_generator() - if code_generator: - code_generator.generate_type_builder(ad_hoc_type_writer, generate_context) - - writer.newline_multiline( -""" enum { - NoFieldsSet = 0, -""") - - state_enum_items = [] - if len(resolve_data.main_properties) > 0: - pos = 0 - for prop_data in resolve_data.main_properties: - item_name = Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]) + "Set" - state_enum_items.append(item_name) - writer.newline(" %s = 1 << %s,\n" % (item_name, pos)) - pos += 1 - all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")" - else: - all_fields_set_value = "0" - - writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_1 - % (all_fields_set_value, class_name, class_name)) - - pos = 0 - for prop_data in resolve_data.main_properties: - prop_name = prop_data.p["name"] - - param_type_binding = prop_data.param_type_binding - param_raw_type = param_type_binding.reduce_to_raw_type() - - writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_2 - % (state_enum_items[pos], - Capitalizer.lower_camel_case_to_upper(prop_name), - param_type_binding.get_type_model().get_input_param_type_text(), - state_enum_items[pos], prop_name, - param_raw_type.get_setter_name(), prop_name, - format_setter_value_expression(param_type_binding, "value"), - state_enum_items[pos])) - - pos += 1 - - writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_3 - % (class_name, class_name, class_name, class_name, class_name)) - - writer.newline(" /*\n") - writer.newline(" * Synthetic constructor:\n") - writer.newline(" * RefPtr<%s> result = %s::create()" % (class_name, class_name)) - for prop_data in resolve_data.main_properties: - writer.append_multiline("\n * .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"])) - writer.append_multiline(";\n */\n") - - writer.newline_multiline(CodeGeneratorInspectorStrings.class_binding_builder_part_4) - - writer.newline(" typedef Inspector::TypeBuilder::StructItemTraits ItemTraits;\n") - - for prop_data in resolve_data.optional_properties: - prop_name = prop_data.p["name"] - param_type_binding = prop_data.param_type_binding - setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop_name) - - writer.append_multiline("\n void %s" % setter_name) - writer.append("(%s value)\n" % param_type_binding.get_type_model().get_input_param_type_text()) - writer.newline(" {\n") - writer.newline(" this->set%s(ASCIILiteral(\"%s\"), %s);\n" - % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"], - format_setter_value_expression(param_type_binding, "value"))) - writer.newline(" }\n") - - - if setter_name in INSPECTOR_OBJECT_SETTER_NAMES: - writer.newline(" using Inspector::InspectorObjectBase::%s;\n\n" % setter_name) - - if class_binding_cls.need_user_runtime_cast_: - writer.newline(" static PassRefPtr<%s> runtimeCast(PassRefPtr<Inspector::InspectorValue> value)\n" % class_name) - writer.newline(" {\n") - writer.newline(" RefPtr<Inspector::InspectorObject> object;\n") - writer.newline(" bool castRes = value->asObject(&object);\n") - writer.newline(" ASSERT_UNUSED(castRes, castRes);\n") - writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME) - writer.newline(" assertCorrectValue(object.get());\n") - writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME) - writer.newline(" COMPILE_ASSERT(sizeof(%s) == sizeof(Inspector::InspectorObjectBase), type_cast_problem);\n" % class_name) - writer.newline(" return static_cast<%s*>(static_cast<Inspector::InspectorObjectBase*>(object.get()));\n" % class_name) - writer.newline(" }\n") - writer.append("\n") - - if class_binding_cls.need_internal_runtime_cast_: - writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME) - writer.newline(" static %s void assertCorrectValue(Inspector::InspectorValue* value);\n" % INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"]) - writer.append("#endif // %s\n" % VALIDATOR_IFDEF_NAME) - - closed_field_set = (context_domain_name + "." + class_name) not in TYPES_WITH_OPEN_FIELD_LIST_SET - - validator_writer = generate_context.validator_writer - - domain_fixes = DomainNameFixes.get_fixed_data(context_domain_name) - domain_guard = domain_fixes.get_guard() - if domain_guard: - domain_guard.generate_open(validator_writer) - - validator_writer.newline("void %s%s::assertCorrectValue(Inspector::InspectorValue* value)\n" % (helper.full_name_prefix_for_impl, class_name)) - validator_writer.newline("{\n") - validator_writer.newline(" RefPtr<InspectorObject> object;\n") - validator_writer.newline(" bool castRes = value->asObject(&object);\n") - validator_writer.newline(" ASSERT_UNUSED(castRes, castRes);\n") - for prop_data in resolve_data.main_properties: - validator_writer.newline(" {\n") - it_name = "%sPos" % prop_data.p["name"] - validator_writer.newline(" InspectorObject::iterator %s;\n" % it_name) - validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"])) - validator_writer.newline(" ASSERT(%s != object->end());\n" % it_name) - validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name)) - validator_writer.newline(" }\n") - - if closed_field_set: - validator_writer.newline(" int foundPropertiesCount = %s;\n" % len(resolve_data.main_properties)) - - for prop_data in resolve_data.optional_properties: - validator_writer.newline(" {\n") - it_name = "%sPos" % prop_data.p["name"] - validator_writer.newline(" InspectorObject::iterator %s;\n" % it_name) - validator_writer.newline(" %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"])) - validator_writer.newline(" if (%s != object->end()) {\n" % it_name) - validator_writer.newline(" %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name)) - if closed_field_set: - validator_writer.newline(" ++foundPropertiesCount;\n") - validator_writer.newline(" }\n") - validator_writer.newline(" }\n") - - if closed_field_set: - validator_writer.newline(" if (foundPropertiesCount != object->size())\n") - validator_writer.newline(" FATAL(\"Unexpected properties in object: %s\\n\", object->toJSONString().ascii().data());\n") - validator_writer.newline("}\n") - - if domain_guard: - domain_guard.generate_close(validator_writer) - - validator_writer.newline("\n\n") - - if is_open_type: - cpp_writer = generate_context.cpp_writer - writer.append("\n") - writer.newline(" // Property names for type generated as open.\n") - for prop_data in resolve_data.main_properties + resolve_data.optional_properties: - prop_name = prop_data.p["name"] - prop_field_name = Capitalizer.lower_camel_case_to_upper(prop_name) - writer.newline(" static const char* %s;\n" % (prop_field_name)) - cpp_writer.newline("const char* %s%s::%s = \"%s\";\n" % (helper.full_name_prefix_for_impl, class_name, prop_field_name, prop_name)) - - - writer.newline("};\n\n") - - @staticmethod - def generate_forward_declaration(writer): - class_name = fixed_type_name.class_name - writer.newline("class ") - writer.append(class_name) - writer.append(";\n") - - @staticmethod - def register_use(forward_listener): - helper.add_to_forward_listener(forward_listener) - - @staticmethod - def get_generate_pass_id(): - return TypeBuilderPass.MAIN - - return CodeGenerator - - @staticmethod - def get_validator_call_text(): - return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue" - - @classmethod - def get_array_item_c_type_text(cls): - return helper.full_name_prefix_for_use + fixed_type_name.class_name - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.Object - - @staticmethod - def get_type_model(): - return TypeModel.RefPtrBased(helper.full_name_prefix_for_use + fixed_type_name.class_name) - - class AdHocTypeContextImpl: - def __init__(self, property_name, class_name, resolve_context, ad_hoc_type_list, parent_full_name_prefix): - self.property_name = property_name - self.class_name = class_name - self.resolve_context = resolve_context - self.ad_hoc_type_list = ad_hoc_type_list - self.container_full_name_prefix = parent_full_name_prefix + class_name + "::" - self.container_relative_name_prefix = "" - - def get_type_name_fix(self): - class NameFix: - class_name = Capitalizer.lower_camel_case_to_upper(self.property_name) - - @staticmethod - def output_comment(writer): - writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name)) - - return NameFix - - def add_type(self, binding): - self.ad_hoc_type_list.append(binding) - - return ClassBinding - else: - - class PlainObjectBinding: - @classmethod - def resolve_inner(cls, resolve_context): - pass - - @staticmethod - def request_user_runtime_cast(request): - pass - - @staticmethod - def request_internal_runtime_cast(): - RawTypes.Object.request_raw_internal_runtime_cast() - - @staticmethod - def get_code_generator(): - pass - - @staticmethod - def get_validator_call_text(): - return "RuntimeCastHelper::assertType<InspectorValue::TypeObject>" - - @classmethod - def get_array_item_c_type_text(cls): - return cls.reduce_to_raw_type().get_array_item_raw_c_type_text() - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.Object - - @staticmethod - def get_type_model(): - return TypeModel.Object - - return PlainObjectBinding - elif json_typable["type"] == "array": - if "items" in json_typable: - - ad_hoc_types = [] - - class AdHocTypeContext: - container_full_name_prefix = "<not yet defined>" - container_relative_name_prefix = "" - - @staticmethod - def get_type_name_fix(): - return fixed_type_name - - @staticmethod - def add_type(binding): - ad_hoc_types.append(binding) - - item_binding = resolve_param_type(json_typable["items"], context_domain_name, AdHocTypeContext) - - class ArrayBinding: - resolve_data_ = None - need_internal_runtime_cast_ = False - - @classmethod - def resolve_inner(cls, resolve_context): - if cls.resolve_data_: - return - - class ResolveData: - item_type_binding = item_binding - ad_hoc_type_list = ad_hoc_types - - cls.resolve_data_ = ResolveData - - for t in ad_hoc_types: - t.resolve_inner(resolve_context) - - @classmethod - def request_user_runtime_cast(cls, request): - raise Exception("Not implemented yet") - - @classmethod - def request_internal_runtime_cast(cls): - if cls.need_internal_runtime_cast_: - return - cls.need_internal_runtime_cast_ = True - cls.resolve_data_.item_type_binding.request_internal_runtime_cast() - - @classmethod - def get_code_generator(array_binding_cls): - - class CodeGenerator: - @staticmethod - def generate_type_builder(writer, generate_context): - ad_hoc_type_writer = writer - - resolve_data = array_binding_cls.resolve_data_ - - for ad_hoc_type in resolve_data.ad_hoc_type_list: - code_generator = ad_hoc_type.get_code_generator() - if code_generator: - code_generator.generate_type_builder(ad_hoc_type_writer, generate_context) - - @staticmethod - def generate_forward_declaration(writer): - pass - - @staticmethod - def register_use(forward_listener): - item_code_generator = item_binding.get_code_generator() - if item_code_generator: - item_code_generator.register_use(forward_listener) - - @staticmethod - def get_generate_pass_id(): - return TypeBuilderPass.MAIN - - return CodeGenerator - - @classmethod - def get_validator_call_text(cls): - return cls.get_array_item_c_type_text() + "::assertCorrectValue" - - @classmethod - def get_array_item_c_type_text(cls): - return replace_right_shift("Inspector::TypeBuilder::Array<%s>" % cls.resolve_data_.item_type_binding.get_array_item_c_type_text()) - - @staticmethod - def get_setter_value_expression_pattern(): - return None - - @staticmethod - def reduce_to_raw_type(): - return RawTypes.Array - - @classmethod - def get_type_model(cls): - return TypeModel.RefPtrBased(cls.get_array_item_c_type_text()) - - return ArrayBinding - else: - # Fall-through to raw type. - pass - - raw_type = RawTypes.get(json_typable["type"]) - - return RawTypeBinding(raw_type) - - -class RawTypeBinding: - def __init__(self, raw_type): - self.raw_type_ = raw_type - - def resolve_inner(self, resolve_context): - pass - - def request_user_runtime_cast(self, request): - raise Exception("Unsupported") - - def request_internal_runtime_cast(self): - self.raw_type_.request_raw_internal_runtime_cast() - - def get_code_generator(self): - return None - - def get_validator_call_text(self): - return self.raw_type_.get_raw_validator_call_text() - - def get_array_item_c_type_text(self): - return self.raw_type_.get_array_item_raw_c_type_text() - - def get_setter_value_expression_pattern(self): - return None - - def reduce_to_raw_type(self): - return self.raw_type_ - - def get_type_model(self): - return self.raw_type_.get_raw_type_model() - - -class TypeData(object): - def __init__(self, json_type, json_domain, domain_data): - self.json_type_ = json_type - self.json_domain_ = json_domain - self.domain_data_ = domain_data - - if "type" not in json_type: - raise Exception("Unknown type") - - json_type_name = json_type["type"] - self.raw_type_ = RawTypes.get(json_type_name) - self.binding_being_resolved_ = False - self.binding_ = None - - def get_raw_type(self): - return self.raw_type_ - - def get_binding(self): - if not self.binding_: - if self.binding_being_resolved_: - raise Exception("Type %s is already being resolved" % self.json_type_["type"]) - # Resolve only lazily, because resolving one named type may require resolving some other named type. - self.binding_being_resolved_ = True - try: - self.binding_ = TypeBindings.create_named_type_declaration(self.json_type_, self.json_domain_["domain"], self) - finally: - self.binding_being_resolved_ = False - - return self.binding_ - - def get_json_type(self): - return self.json_type_ - - def get_name(self): - return self.json_type_["id"] - - def get_domain_name(self): - return self.json_domain_["domain"] - - -class DomainData: - def __init__(self, json_domain): - self.json_domain = json_domain - self.types_ = [] - - def add_type(self, type_data): - self.types_.append(type_data) - - def name(self): - return self.json_domain["domain"] - - def types(self): - return self.types_ - - -class TypeMap: - def __init__(self, api, dependency_api): - self.map_ = {} - self.domains_ = [] - self.domains_to_generate_ = [] - for json_domain in api["domains"]: - self.add_domain(json_domain, True) - for json_domain in dependency_api["domains"]: - self.add_domain(json_domain, False) - - def add_domain(self, json_domain, should_generate): - domain_name = json_domain["domain"] - - domain_map = {} - self.map_[domain_name] = domain_map - - domain_data = DomainData(json_domain) - self.domains_.append(domain_data) - - if should_generate: - # FIXME: The order of types should not matter. The generated code should work regardless of the order of types. - if domain_name == "Page": - self.domains_to_generate_.insert(0, domain_data) - else: - self.domains_to_generate_.append(domain_data) - - if "types" in json_domain: - for json_type in json_domain["types"]: - type_name = json_type["id"] - type_data = TypeData(json_type, json_domain, domain_data) - domain_map[type_name] = type_data - domain_data.add_type(type_data) - - def domains(self): - return self.domains_ - - def domains_to_generate(self): - return self.domains_to_generate_ - - def get(self, domain_name, type_name): - return self.map_[domain_name][type_name] - - -def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context): - if "$ref" in json_parameter: - json_ref = json_parameter["$ref"] - type_data = get_ref_data(json_ref, scope_domain_name) - return type_data.get_binding() - elif "type" in json_parameter: - result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, scope_domain_name, ad_hoc_type_context) - ad_hoc_type_context.add_type(result) - return result - else: - raise Exception("Unknown type") - - -def resolve_param_raw_type(json_parameter, scope_domain_name): - if "$ref" in json_parameter: - json_ref = json_parameter["$ref"] - type_data = get_ref_data(json_ref, scope_domain_name) - return type_data.get_raw_type() - elif "type" in json_parameter: - json_type = json_parameter["type"] - return RawTypes.get(json_type) - else: - raise Exception("Unknown type") - - -def get_ref_data(json_ref, scope_domain_name): - dot_pos = json_ref.find(".") - if dot_pos == -1: - domain_name = scope_domain_name - type_name = json_ref - else: - domain_name = json_ref[:dot_pos] - type_name = json_ref[dot_pos + 1:] - - return type_map.get(domain_name, type_name) - - -input_file = open(input_json_filename, "r") -json_string = input_file.read() -json_api = json.loads(json_string) -input_file.close() -if not "domains" in json_api: - json_api = {"domains": [json_api]} - -dependency_api = {"domains": []} -for dependency_json_filename in dependency_json_filenames: - dependency_input_file = open(dependency_json_filename, "r") - dependency_json_string = dependency_input_file.read() - dependency_json_api = json.loads(dependency_json_string) - dependency_input_file.close() - if not "domains" in dependency_json_api: - dependency_json_api = {"domains": [dependency_json_api]} - dependency_api["domains"] += dependency_json_api["domains"] - - -class Templates: - def get_this_script_path_(absolute_path): - absolute_path = os.path.abspath(absolute_path) - components = [] - - def fill_recursive(path_part, depth): - if depth <= 0 or path_part == '/': - return - fill_recursive(os.path.dirname(path_part), depth - 1) - components.append(os.path.basename(path_part)) - - # Typical path is /Source/WebCore/inspector/CodeGeneratorInspector.py - # Let's take 4 components from the real path then. - fill_recursive(absolute_path, 4) - - return "/".join(components) - - file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) + -"""// Copyright (c) 2013 Apple Inc. All Rights Reserved. -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -""") - - frontend_domain_class = string.Template(CodeGeneratorInspectorStrings.frontend_domain_class) - backend_dispatcher_constructor = string.Template(CodeGeneratorInspectorStrings.backend_dispatcher_constructor) - backend_dispatcher_dispatch_method = string.Template(CodeGeneratorInspectorStrings.backend_dispatcher_dispatch_method) - backend_dispatcher_dispatch_method_simple = string.Template(CodeGeneratorInspectorStrings.backend_dispatcher_dispatch_method_simple) - backend_method = string.Template(CodeGeneratorInspectorStrings.backend_method) - frontend_method = string.Template(CodeGeneratorInspectorStrings.frontend_method) - callback_method = string.Template(CodeGeneratorInspectorStrings.callback_method) - frontend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_h) - backend_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_h) - backend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_cpp) - frontend_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.frontend_cpp) - typebuilder_h = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_h) - typebuilder_cpp = string.Template(file_header_ + CodeGeneratorInspectorStrings.typebuilder_cpp) - backend_js = string.Template(file_header_ + CodeGeneratorInspectorStrings.backend_js) - param_container_access_code = CodeGeneratorInspectorStrings.param_container_access_code - - - - - -type_map = TypeMap(json_api, dependency_api) - - -class NeedRuntimeCastRequest: - def __init__(self): - self.ack_ = None - - def acknowledge(self): - self.ack_ = True - - def is_acknowledged(self): - return self.ack_ - - -def resolve_all_types(): - runtime_cast_generate_requests = {} - for type_name in TYPES_WITH_RUNTIME_CAST_SET: - runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest() - - class ForwardListener: - type_data_set = set() - already_declared_set = set() - - @classmethod - def add_type_data(cls, type_data): - if type_data not in cls.already_declared_set: - cls.type_data_set.add(type_data) - - class ResolveContext: - forward_listener = ForwardListener - - for domain_data in type_map.domains(): - for type_data in domain_data.types(): - binding = type_data.get_binding() - binding.resolve_inner(ResolveContext) - # Do not generate forwards for this type any longer. - ForwardListener.already_declared_set.add(type_data) - - for domain_data in type_map.domains(): - for type_data in domain_data.types(): - full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.get_name()) - request = runtime_cast_generate_requests.pop(full_type_name, None) - binding = type_data.get_binding() - if request: - binding.request_user_runtime_cast(request) - - if request and not request.is_acknowledged(): - raise Exception("Failed to generate runtimeCast in " + full_type_name) - - # FIXME: This assumes all the domains are processed at once. Change this verification - # to only verify runtime casts for the domains being generated. - # if verification: - # for full_type_name in runtime_cast_generate_requests: - # raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found") - - return ForwardListener - - -global_forward_listener = resolve_all_types() - - -def get_annotated_type_text(raw_type, annotated_type): - if annotated_type != raw_type: - return "/*%s*/ %s" % (annotated_type, raw_type) - else: - return raw_type - - -def format_setter_value_expression(param_type_binding, value_ref): - pattern = param_type_binding.get_setter_value_expression_pattern() - if pattern: - return pattern % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"], value_ref) - else: - return value_ref - - -class Generator: - frontend_domain_class_lines = [] - - backend_method_implementation_list = [] - frontend_method_list = [] - backend_js_domain_initializer_list = [] - - backend_handler_interface_list = [] - backend_handler_implementation_list = [] - backend_dispatcher_interface_list = [] - type_builder_fragments = [] - type_builder_forwards = [] - validator_impl_list = [] - type_builder_impl_list = [] - - - @staticmethod - def go(): - Generator.process_types(type_map) - - first_cycle_guardable_list_list = [ - Generator.backend_method_implementation_list, - Generator.backend_handler_interface_list, - Generator.backend_handler_implementation_list, - Generator.backend_dispatcher_interface_list] - - for json_domain in json_api["domains"]: - domain_name = json_domain["domain"] - domain_name_lower = domain_name.lower() - - domain_fixes = DomainNameFixes.get_fixed_data(domain_name) - - domain_guard = domain_fixes.get_guard() - - if domain_guard: - for l in first_cycle_guardable_list_list: - domain_guard.generate_open(l) - - frontend_method_declaration_lines = [] - - if ("commands" in json_domain or "events" in json_domain): - Generator.backend_js_domain_initializer_list.append("// %s.\n" % domain_name) - if not domain_fixes.skip_js_bind: - Generator.backend_js_domain_initializer_list.append("InspectorBackend.register%sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"%s\");\n" % (domain_name, domain_name)) - - if "types" in json_domain: - for json_type in json_domain["types"]: - if "type" in json_type and json_type["type"] == "string" and "enum" in json_type: - enum_name = "%s.%s" % (domain_name, json_type["id"]) - Generator.process_enum(json_type, enum_name) - elif json_type["type"] == "object": - if "properties" in json_type: - for json_property in json_type["properties"]: - if "type" in json_property and json_property["type"] == "string" and "enum" in json_property: - enum_name = "%s.%s%s" % (domain_name, json_type["id"], to_title_case(json_property["name"])) - Generator.process_enum(json_property, enum_name) - - if "events" in json_domain: - if domain_guard: - domain_guard.generate_open(Generator.frontend_method_list) - domain_guard.generate_open(Generator.frontend_domain_class_lines) - - for json_event in json_domain["events"]: - Generator.process_event(json_event, domain_name, frontend_method_declaration_lines) - - Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None, - exportMacro=INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"], - domainClassName="Inspector%sFrontendDispatcher" % domain_name, - frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines)))) - - if domain_guard: - domain_guard.generate_close(Generator.frontend_method_list) - domain_guard.generate_close(Generator.frontend_domain_class_lines) - - dispatcher_name = "Inspector" + Capitalizer.lower_camel_case_to_upper(domain_name) + "BackendDispatcher" - agent_interface_name = dispatcher_name + "Handler" - - if "commands" in json_domain: - Generator.backend_dispatcher_interface_list.append("class %s %s final : public Inspector::InspectorSupplementalBackendDispatcher {\n" % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"], dispatcher_name)) - Generator.backend_dispatcher_interface_list.append("public:\n") - Generator.backend_dispatcher_interface_list.append(" static PassRefPtr<%s> create(Inspector::InspectorBackendDispatcher*, %s*);\n" % (dispatcher_name, agent_interface_name)) - Generator.backend_dispatcher_interface_list.append(" virtual void dispatch(long callId, const String& method, PassRefPtr<Inspector::InspectorObject> message) override;\n") - Generator.backend_dispatcher_interface_list.append("private:\n") - - Generator.backend_handler_interface_list.append("class %s %s {\n" % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"], agent_interface_name)) - Generator.backend_handler_interface_list.append("public:\n") - - backend_method_count = len(Generator.backend_method_implementation_list) - - dispatcher_if_chain = [] - dispatcher_commands_list = [] - for json_command in json_domain["commands"]: - Generator.process_command(json_command, domain_name, agent_interface_name, dispatcher_name, dispatcher_if_chain, dispatcher_commands_list) - - Generator.backend_handler_interface_list.append("protected:\n") - Generator.backend_handler_interface_list.append(" virtual ~%s();\n" % agent_interface_name) - Generator.backend_handler_interface_list.append("};\n\n") - - Generator.backend_handler_implementation_list.append("%s::~%s() { }\n" % (agent_interface_name, agent_interface_name)) - - Generator.backend_dispatcher_interface_list.append("private:\n") - Generator.backend_dispatcher_interface_list.append(" %s(Inspector::InspectorBackendDispatcher*, %s*);\n" % (dispatcher_name, agent_interface_name)) - Generator.backend_dispatcher_interface_list.append(" %s* m_agent;\n" % agent_interface_name) - Generator.backend_dispatcher_interface_list.append("};\n\n") - - Generator.backend_method_implementation_list.insert(backend_method_count, Templates.backend_dispatcher_constructor.substitute(None, - domainName=domain_name, - dispatcherName=dispatcher_name, - agentName=agent_interface_name)) - - if len(json_domain["commands"]) <= 5: - Generator.backend_method_implementation_list.insert(backend_method_count + 1, Templates.backend_dispatcher_dispatch_method_simple.substitute(None, - domainName=domain_name, - dispatcherName=dispatcher_name, - ifChain="\n".join(dispatcher_if_chain))) - else: - Generator.backend_method_implementation_list.insert(backend_method_count + 1, Templates.backend_dispatcher_dispatch_method.substitute(None, - domainName=domain_name, - dispatcherName=dispatcher_name, - dispatcherCommands="\n".join(dispatcher_commands_list))) - - if domain_guard: - for l in reversed(first_cycle_guardable_list_list): - domain_guard.generate_close(l) - Generator.backend_js_domain_initializer_list.append("\n") - - @staticmethod - def process_enum(json_enum, enum_name): - enum_members = [] - for member in json_enum["enum"]: - enum_members.append("%s: \"%s\"" % (fix_camel_case(member), member)) - - Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEnum(\"%s\", {%s});\n" % ( - enum_name, ", ".join(enum_members))) - - @staticmethod - def process_event(json_event, domain_name, frontend_method_declaration_lines): - event_name = json_event["name"] - - ad_hoc_type_output = [] - frontend_method_declaration_lines.append(ad_hoc_type_output) - ad_hoc_type_writer = Writer(ad_hoc_type_output, " ") - - decl_parameter_list = [] - - json_parameters = json_event.get("parameters") - Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer, - decl_parameter_list, - Generator.EventMethodStructTemplate, - Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name}) - - backend_js_event_param_list = [] - if json_parameters: - for parameter in json_parameters: - parameter_name = parameter["name"] - backend_js_event_param_list.append("\"%s\"" % parameter_name) - - frontend_method_declaration_lines.append( - " void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list))) - - Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEvent(\"%s.%s\", [%s]);\n" % ( - domain_name, event_name, ", ".join(backend_js_event_param_list))) - - class EventMethodStructTemplate: - @staticmethod - def append_prolog(line_list): - line_list.append(" RefPtr<InspectorObject> paramsObject = InspectorObject::create();\n") - - @staticmethod - def append_epilog(line_list): - line_list.append(" jsonMessage->setObject(ASCIILiteral(\"params\"), paramsObject);\n") - - container_name = "paramsObject" - - @staticmethod - def process_command(json_command, domain_name, agent_interface_name, dispatcher_name, dispatcher_if_chain, dispatcher_commands_list): - json_command_name = json_command["name"] - - ad_hoc_type_output = [] - Generator.backend_handler_interface_list.append(ad_hoc_type_output) - ad_hoc_type_writer = Writer(ad_hoc_type_output, " ") - - Generator.backend_dispatcher_interface_list.append(" void %s(long callId, const Inspector::InspectorObject& message);\n" % json_command_name) - - Generator.backend_handler_interface_list.append(" virtual void %s(ErrorString*" % json_command_name) - - if not dispatcher_if_chain: - dispatcher_if_chain.append(" if (method == \"%s\")" % json_command_name) - else: - dispatcher_if_chain.append(" else if (method == \"%s\")" % json_command_name) - dispatcher_if_chain.append(" %s(callId, *message.get());" % json_command_name) - dispatcher_commands_list.append(" { \"%s\", &%s::%s }," % (json_command_name, dispatcher_name, json_command_name)) - - method_in_params_handling = [] - method_dispatch_handling = [] - method_out_params_handling = [] - method_ending_handling = [] - method_request_message_param_name = "" - agent_call_param_list = [] - js_parameters_text = "" - if "parameters" in json_command: - json_params = json_command["parameters"] - method_request_message_param_name = " message" - method_in_params_handling.append(" RefPtr<InspectorArray> protocolErrors = InspectorArray::create();\n") - method_in_params_handling.append(" RefPtr<InspectorObject> paramsContainer = message.getObject(ASCIILiteral(\"params\"));\n") - method_in_params_handling.append(" InspectorObject* paramsContainerPtr = paramsContainer.get();\n") - method_in_params_handling.append(" InspectorArray* protocolErrorsPtr = protocolErrors.get();\n") - js_param_list = [] - - for json_parameter in json_params: - json_param_name = json_parameter["name"] - param_raw_type = resolve_param_raw_type(json_parameter, domain_name) - - getter_name = param_raw_type.get_getter_name() - - optional = json_parameter.get("optional") - - non_optional_type_model = param_raw_type.get_raw_type_model() - if optional: - type_model = non_optional_type_model.get_optional() - else: - type_model = non_optional_type_model - - if optional: - code = (" bool %s_valueFound = false;\n" - " %s in_%s = InspectorBackendDispatcher::get%s(paramsContainerPtr, ASCIILiteral(\"%s\"), &%s_valueFound, protocolErrorsPtr);\n" % - (json_param_name, non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name, json_param_name)) - param = ", %s_valueFound ? &in_%s : nullptr" % (json_param_name, json_param_name) - # FIXME: pass optional refptr-values as PassRefPtr - formal_param_type_pattern = "const %s*" - else: - code = (" %s in_%s = InspectorBackendDispatcher::get%s(paramsContainerPtr, ASCIILiteral(\"%s\"), nullptr, protocolErrorsPtr);\n" % - (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name)) - param = ", in_%s" % json_param_name - # FIXME: pass not-optional refptr-values as NonNullPassRefPtr - if param_raw_type.is_heavy_value(): - formal_param_type_pattern = "const %s&" - else: - formal_param_type_pattern = "%s" - - method_in_params_handling.append(code) - agent_call_param_list.append(param) - Generator.backend_handler_interface_list.append(", %s in_%s" % (formal_param_type_pattern % non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name)) - - js_bind_type = param_raw_type.get_js_bind_type() - js_param_text = "{\"name\": \"%s\", \"type\": \"%s\", \"optional\": %s}" % ( - json_param_name, - js_bind_type, - ("true" if ("optional" in json_parameter and json_parameter["optional"]) else "false")) - - js_param_list.append(js_param_text) - - method_in_params_handling.append(" if (protocolErrors->length()) {\n") - method_in_params_handling.append(" String errorMessage = String::format(\"Some arguments of method '%%s' can't be processed\", \"%s.%s\");\n" % (domain_name, json_command_name)) - method_in_params_handling.append(" m_backendDispatcher->reportProtocolError(&callId, InspectorBackendDispatcher::InvalidParams, errorMessage, protocolErrors.release());\n") - method_in_params_handling.append(" return;\n") - method_in_params_handling.append(" }\n") - method_in_params_handling.append("\n") - - js_parameters_text = ", ".join(js_param_list) - - method_dispatch_handling.append(" ErrorString error;\n") - method_dispatch_handling.append(" RefPtr<InspectorObject> result = InspectorObject::create();\n") - - if json_command.get("async") == True: - callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback" - - callback_output = [] - callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent()) - - decl_parameter_list = [] - Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer, - decl_parameter_list, - Generator.CallbackMethodStructTemplate, - Generator.backend_method_implementation_list, Templates.callback_method, - {"callbackName": callback_name, "handlerName": agent_interface_name}) - - callback_writer.newline("class " + callback_name + " : public Inspector::InspectorBackendDispatcher::CallbackBase {\n") - callback_writer.newline("public:\n") - callback_writer.newline(" " + callback_name + "(PassRefPtr<Inspector::InspectorBackendDispatcher>, int id);\n") - callback_writer.newline(" void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n") - callback_writer.newline("};\n") - - ad_hoc_type_output.append(callback_output) - - method_dispatch_handling.append(" RefPtr<%s::%s> callback = adoptRef(new %s::%s(m_backendDispatcher,callId));\n" % (agent_interface_name, callback_name, agent_interface_name, callback_name)) - method_ending_handling.append(" if (error.length()) {\n") - method_ending_handling.append(" callback->disable();\n") - method_ending_handling.append(" m_backendDispatcher->reportProtocolError(&callId, Inspector::InspectorBackendDispatcher::ServerError, error);\n") - method_ending_handling.append(" return;\n") - method_ending_handling.append(" }") - - agent_call_param_list.append(", callback") - Generator.backend_handler_interface_list.append(", PassRefPtr<%s> callback" % callback_name) - elif "returns" in json_command: - has_multiple_returns = len(json_command["returns"]) > 1 - if has_multiple_returns: - method_out_params_handling.append(" if (!error.length()) {\n") - else: - method_out_params_handling.append(" if (!error.length())\n") - - for json_return in json_command["returns"]: - - json_return_name = json_return["name"] - - optional = bool(json_return.get("optional")) - - return_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::") - - raw_type = return_type_binding.reduce_to_raw_type() - setter_type = raw_type.get_setter_name() - initializer = raw_type.get_c_initializer() - - type_model = return_type_binding.get_type_model() - if optional: - type_model = type_model.get_optional() - - code = " %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name) - param = ", %sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name) - var_name = "out_%s" % json_return_name - setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name - if return_type_binding.get_setter_value_expression_pattern(): - setter_argument = return_type_binding.get_setter_value_expression_pattern() % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"], setter_argument) - - cook = " result->set%s(ASCIILiteral(\"%s\"), %s);\n" % (setter_type, json_return_name, setter_argument) - - set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition() - if set_condition_pattern: - cook = (" if (%s)\n " % (set_condition_pattern % var_name)) + cook - annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type() - - param_name = "out_%s" % json_return_name - if optional: - param_name = "opt_" + param_name - - Generator.backend_handler_interface_list.append(", %s %s" % (annotated_type, param_name)) - method_out_params_handling.append(cook) - method_dispatch_handling.append(code) - - agent_call_param_list.append(param) - - if has_multiple_returns: - method_out_params_handling.append(" }\n") - method_out_params_handling.append("\n") - - method_dispatch_handling.append(" m_agent->%s(&error%s);\n" % (json_command_name, "".join(agent_call_param_list))) - method_dispatch_handling.append("\n") - - if not method_ending_handling: - method_ending_handling.append(" m_backendDispatcher->sendResponse(callId, result.release(), error);") - - backend_js_reply_param_list = [] - if "returns" in json_command: - for json_return in json_command["returns"]: - json_return_name = json_return["name"] - backend_js_reply_param_list.append("\"%s\"" % json_return_name) - - js_reply_list = "[%s]" % ", ".join(backend_js_reply_param_list) - - Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None, - dispatcherName=dispatcher_name, - methodName=json_command_name, - requestMessageObject=method_request_message_param_name, - methodInParametersHandling="".join(method_in_params_handling), - methodDispatchHandling="".join(method_dispatch_handling), - methodOutParametersHandling="".join(method_out_params_handling), - methodEndingHandling="".join(method_ending_handling))) - - Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerCommand(\"%s.%s\", [%s], %s);\n" % (domain_name, json_command_name, js_parameters_text, js_reply_list)) - Generator.backend_handler_interface_list.append(") = 0;\n") - - class CallbackMethodStructTemplate: - @staticmethod - def append_prolog(line_list): - pass - - @staticmethod - def append_epilog(line_list): - pass - - container_name = "jsonMessage" - - # Generates common code for event sending and callback response data sending. - @staticmethod - def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list, - method_struct_template, - generator_method_list, method_template, template_params): - method_line_list = [] - if parameters: - method_struct_template.append_prolog(method_line_list) - for json_parameter in parameters: - parameter_name = json_parameter["name"] - - param_type_binding = Generator.resolve_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "") - - raw_type = param_type_binding.reduce_to_raw_type() - raw_type_binding = RawTypeBinding(raw_type) - - optional = bool(json_parameter.get("optional")) - - setter_type = raw_type.get_setter_name() - - type_model = param_type_binding.get_type_model() - raw_type_model = raw_type_binding.get_type_model() - if optional: - type_model = type_model.get_optional() - raw_type_model = raw_type_model.get_optional() - - annotated_type = type_model.get_input_param_type_text() - mode_type_binding = param_type_binding - - decl_parameter_list.append("%s %s" % (annotated_type, parameter_name)) - - setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name - if mode_type_binding.get_setter_value_expression_pattern(): - setter_argument = mode_type_binding.get_setter_value_expression_pattern() % (INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"], setter_argument) - - setter_code = " %s->set%s(ASCIILiteral(\"%s\"), %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument) - if optional: - setter_code = (" if (%s)\n " % parameter_name) + setter_code - method_line_list.append(setter_code) - - method_struct_template.append_epilog(method_line_list) - - generator_method_list.append(method_template.substitute(None, - domainName=domain_name, - parameters=", ".join(decl_parameter_list), - code="".join(method_line_list), **template_params)) - - @staticmethod - def resolve_type_and_generate_ad_hoc(json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param): - param_name = json_param["name"] - ad_hoc_type_list = [] - - class AdHocTypeContext: - container_full_name_prefix = "<not yet defined>" - container_relative_name_prefix = container_relative_name_prefix_param - - @staticmethod - def get_type_name_fix(): - class NameFix: - class_name = Capitalizer.lower_camel_case_to_upper(param_name) - - @staticmethod - def output_comment(writer): - writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (param_name, method_name)) - - return NameFix - - @staticmethod - def add_type(binding): - ad_hoc_type_list.append(binding) - - type_binding = resolve_param_type(json_param, domain_name, AdHocTypeContext) - - class InterfaceForwardListener: - @staticmethod - def add_type_data(type_data): - pass - - class InterfaceResolveContext: - forward_listener = InterfaceForwardListener - - for type in ad_hoc_type_list: - type.resolve_inner(InterfaceResolveContext) - - class InterfaceGenerateContext: - validator_writer = "not supported in InterfaceGenerateContext" - cpp_writer = validator_writer - - for type in ad_hoc_type_list: - generator = type.get_code_generator() - if generator: - generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext) - - return type_binding - - @staticmethod - def process_types(type_map): - output = Generator.type_builder_fragments - - class GenerateContext: - validator_writer = Writer(Generator.validator_impl_list, "") - cpp_writer = Writer(Generator.type_builder_impl_list, "") - - def generate_all_domains_code(out, type_data_callback): - writer = Writer(out, "") - for domain_data in type_map.domains_to_generate(): - domain_fixes = DomainNameFixes.get_fixed_data(domain_data.name()) - domain_guard = domain_fixes.get_guard() - - namespace_declared = [] - - def namespace_lazy_generator(): - if not namespace_declared: - if domain_guard: - domain_guard.generate_open(out) - writer.newline("namespace ") - writer.append(domain_data.name()) - writer.append(" {\n") - # What is a better way to change value from outer scope? - namespace_declared.append(True) - return writer - - for type_data in domain_data.types(): - type_data_callback(type_data, namespace_lazy_generator) - - if namespace_declared: - writer.append("} // ") - writer.append(domain_data.name()) - writer.append("\n\n") - - if domain_guard: - domain_guard.generate_close(out) - - def create_type_builder_caller(generate_pass_id): - def call_type_builder(type_data, writer_getter): - code_generator = type_data.get_binding().get_code_generator() - if code_generator and generate_pass_id == code_generator.get_generate_pass_id(): - writer = writer_getter() - - code_generator.generate_type_builder(writer, GenerateContext) - return call_type_builder - - generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN)) - - Generator.type_builder_forwards.append("// Forward declarations.\n") - - def generate_forward_callback(type_data, writer_getter): - if type_data in global_forward_listener.type_data_set: - binding = type_data.get_binding() - binding.get_code_generator().generate_forward_declaration(writer_getter()) - generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback) - - Generator.type_builder_forwards.append("// End of forward declarations.\n\n") - - Generator.type_builder_forwards.append("// Typedefs.\n") - - generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF)) - - Generator.type_builder_forwards.append("// End of typedefs.\n\n") - - -def flatten_list(input): - res = [] - - def fill_recursive(l): - for item in l: - if isinstance(item, list): - fill_recursive(item) - else: - res.append(item) - fill_recursive(input) - return res - - -# A writer that only updates file if it actually changed to better support incremental build. -class SmartOutput: - def __init__(self, file_name): - self.file_name_ = file_name - self.output_ = "" - - def write(self, text): - self.output_ += text - - def close(self): - text_changed = True - self.output_ = self.output_.rstrip() + "\n" - - try: - read_file = open(self.file_name_, "r") - old_text = read_file.read() - read_file.close() - text_changed = old_text != self.output_ - except: - # Ignore, just overwrite by default - pass - - if text_changed or write_always: - out_file = open(self.file_name_, "w") - out_file.write(self.output_) - out_file.close() - - -Generator.go() - -output_file_name_prefix = INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["prefix"] - -backend_h_file = SmartOutput(output_header_dirname + ("/Inspector%sBackendDispatchers.h" % output_file_name_prefix)) -backend_cpp_file = SmartOutput(output_cpp_dirname + ("/Inspector%sBackendDispatchers.cpp" % output_file_name_prefix)) - -frontend_h_file = SmartOutput(output_header_dirname + ("/Inspector%sFrontendDispatchers.h" % output_file_name_prefix)) -frontend_cpp_file = SmartOutput(output_cpp_dirname + ("/Inspector%sFrontendDispatchers.cpp" % output_file_name_prefix)) - -typebuilder_h_file = SmartOutput(output_header_dirname + ("/Inspector%sTypeBuilders.h" % output_file_name_prefix)) -typebuilder_cpp_file = SmartOutput(output_cpp_dirname + ("/Inspector%sTypeBuilders.cpp" % output_file_name_prefix)) - -backend_js_file = SmartOutput(output_js_dirname + ("/Inspector%sBackendCommands.js" % output_file_name_prefix)) - - -backend_h_file.write(Templates.backend_h.substitute(None, - outputFileNamePrefix=output_file_name_prefix, - handlerInterfaces="".join(flatten_list(Generator.backend_handler_interface_list)), - dispatcherInterfaces="".join(flatten_list(Generator.backend_dispatcher_interface_list)))) - -backend_cpp_file.write(Templates.backend_cpp.substitute(None, - outputFileNamePrefix=output_file_name_prefix, - handlerImplementations="".join(flatten_list(Generator.backend_handler_implementation_list)), - methods="\n".join(Generator.backend_method_implementation_list))) - -frontend_h_file.write(Templates.frontend_h.substitute(None, - outputFileNamePrefix=output_file_name_prefix, - domainClassList="".join(Generator.frontend_domain_class_lines))) - -frontend_cpp_file.write(Templates.frontend_cpp.substitute(None, - outputFileNamePrefix=output_file_name_prefix, - methods="\n".join(Generator.frontend_method_list))) - -typebuilder_h_file.write(Templates.typebuilder_h.substitute(None, - outputFileNamePrefix=output_file_name_prefix, - typeBuilderDependencies=INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["typebuilder_dependency"], - exportMacro=INSPECTOR_TYPES_GENERATOR_CONFIG_MAP[output_type]["export_macro"], - typeBuilders="".join(flatten_list(Generator.type_builder_fragments)), - forwards="".join(Generator.type_builder_forwards), - validatorIfdefName=VALIDATOR_IFDEF_NAME)) - -typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None, - outputFileNamePrefix=output_file_name_prefix, - enumConstantValues=EnumConstants.get_enum_constant_code(), - implCode="".join(flatten_list(Generator.type_builder_impl_list)), - validatorCode="".join(flatten_list(Generator.validator_impl_list)), - validatorIfdefName=VALIDATOR_IFDEF_NAME)) - -backend_js_file.write(Templates.backend_js.substitute(None, - domainInitializers="".join(Generator.backend_js_domain_initializer_list))) - -backend_h_file.close() -backend_cpp_file.close() - -frontend_h_file.close() -frontend_cpp_file.close() - -typebuilder_h_file.close() -typebuilder_cpp_file.close() - -backend_js_file.close() diff --git a/inspector/scripts/CodeGeneratorInspectorStrings.py b/inspector/scripts/CodeGeneratorInspectorStrings.py deleted file mode 100644 index 2763744..0000000 --- a/inspector/scripts/CodeGeneratorInspectorStrings.py +++ /dev/null @@ -1,348 +0,0 @@ -# Copyright (c) 2013 Google Inc. All rights reserved. -# Copyright (c) 2013 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: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER 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. - -# This file contains string resources for CodeGeneratorInspector. -# Its syntax is a Python syntax subset, suitable for manual parsing. - -frontend_domain_class = ( -"""class ${exportMacro} ${domainClassName} { -public: - ${domainClassName}(InspectorFrontendChannel* inspectorFrontendChannel) : m_inspectorFrontendChannel(inspectorFrontendChannel) { } -${frontendDomainMethodDeclarations}private: - InspectorFrontendChannel* m_inspectorFrontendChannel; -}; - -""") - -backend_dispatcher_constructor = ( -"""PassRefPtr<${dispatcherName}> ${dispatcherName}::create(InspectorBackendDispatcher* backendDispatcher, ${agentName}* agent) -{ - return adoptRef(new ${dispatcherName}(backendDispatcher, agent)); -} - -${dispatcherName}::${dispatcherName}(InspectorBackendDispatcher* backendDispatcher, ${agentName}* agent) - : InspectorSupplementalBackendDispatcher(backendDispatcher) - , m_agent(agent) -{ - m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("${domainName}"), this); -} -""") - -backend_dispatcher_dispatch_method_simple = ( -"""void ${dispatcherName}::dispatch(long callId, const String& method, PassRefPtr<InspectorObject> message) -{ - Ref<${dispatcherName}> protect(*this); - -${ifChain} - else - m_backendDispatcher->reportProtocolError(&callId, InspectorBackendDispatcher::MethodNotFound, String("'") + "${domainName}" + '.' + method + "' was not found"); -} -""") - -backend_dispatcher_dispatch_method = ( -"""void ${dispatcherName}::dispatch(long callId, const String& method, PassRefPtr<InspectorObject> message) -{ - Ref<${dispatcherName}> protect(*this); - - typedef void (${dispatcherName}::*CallHandler)(long callId, const Inspector::InspectorObject& message); - typedef HashMap<String, CallHandler> DispatchMap; - DEPRECATED_DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, ()); - if (dispatchMap.isEmpty()) { - static const struct MethodTable { - const char* name; - CallHandler handler; - } commands[] = { -${dispatcherCommands} - }; - size_t length = WTF_ARRAY_LENGTH(commands); - for (size_t i = 0; i < length; ++i) - dispatchMap.add(commands[i].name, commands[i].handler); - } - - HashMap<String, CallHandler>::iterator it = dispatchMap.find(method); - if (it == dispatchMap.end()) { - m_backendDispatcher->reportProtocolError(&callId, InspectorBackendDispatcher::MethodNotFound, String("'") + "${domainName}" + '.' + method + "' was not found"); - return; - } - - ((*this).*it->value)(callId, *message.get()); -} -""") - -backend_method = ( -"""void ${dispatcherName}::${methodName}(long callId, const InspectorObject&${requestMessageObject}) -{ -${methodInParametersHandling}${methodDispatchHandling}${methodOutParametersHandling}${methodEndingHandling} -} -""") - -frontend_method = ("""void Inspector${domainName}FrontendDispatcher::${eventName}(${parameters}) -{ - RefPtr<InspectorObject> jsonMessage = InspectorObject::create(); - jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("${domainName}.${eventName}")); -${code} - m_inspectorFrontendChannel->sendMessageToFrontend(jsonMessage->toJSONString()); -} -""") - -callback_method = ( -"""${handlerName}::${callbackName}::${callbackName}(PassRefPtr<InspectorBackendDispatcher> backendDispatcher, int id) : Inspector::InspectorBackendDispatcher::CallbackBase(backendDispatcher, id) { } - -void ${handlerName}::${callbackName}::sendSuccess(${parameters}) -{ - RefPtr<InspectorObject> jsonMessage = InspectorObject::create(); -${code} sendIfActive(jsonMessage, ErrorString()); -} -""") - -frontend_h = ( -"""#ifndef Inspector${outputFileNamePrefix}FrontendDispatchers_h -#define Inspector${outputFileNamePrefix}FrontendDispatchers_h - -#include "Inspector${outputFileNamePrefix}TypeBuilders.h" -#include <inspector/InspectorFrontendChannel.h> -#include <inspector/InspectorValues.h> -#include <wtf/PassRefPtr.h> -#include <wtf/text/WTFString.h> - -namespace Inspector { - -#if ENABLE(INSPECTOR) - -${domainClassList} - -#endif // ENABLE(INSPECTOR) - -} // namespace Inspector - -#endif // !defined(Inspector${outputFileNamePrefix}FrontendDispatchers_h) -""") - -backend_h = ( -"""#ifndef Inspector${outputFileNamePrefix}BackendDispatchers_h -#define Inspector${outputFileNamePrefix}BackendDispatchers_h - -#if ENABLE(INSPECTOR) - -#include "Inspector${outputFileNamePrefix}TypeBuilders.h" -#include <inspector/InspectorBackendDispatcher.h> -#include <wtf/PassRefPtr.h> -#include <wtf/text/WTFString.h> - -namespace Inspector { - -typedef String ErrorString; - -${handlerInterfaces} - -${dispatcherInterfaces} -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) - -#endif // !defined(Inspector${outputFileNamePrefix}BackendDispatchers_h) -""") - -backend_cpp = ( -""" -#include "config.h" - -#if ENABLE(INSPECTOR) - -#include "Inspector${outputFileNamePrefix}BackendDispatchers.h" - -#include <inspector/InspectorFrontendChannel.h> -#include <inspector/InspectorValues.h> -#include <wtf/text/CString.h> -#include <wtf/text/WTFString.h> - -namespace Inspector { - -${handlerImplementations} - -${methods} -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) -""") - -frontend_cpp = ( -""" - -#include "config.h" - -#if ENABLE(INSPECTOR) - -#include "Inspector${outputFileNamePrefix}FrontendDispatchers.h" - -#include <wtf/text/CString.h> -#include <wtf/text/WTFString.h> - -namespace Inspector { - -${methods} - -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) -""") - -typebuilder_h = ( -""" -#ifndef Inspector${outputFileNamePrefix}TypeBuilders_h -#define Inspector${outputFileNamePrefix}TypeBuilders_h - -#if ENABLE(INSPECTOR) - -#include <inspector/InspectorTypeBuilder.h> -${typeBuilderDependencies} -#include <wtf/Assertions.h> -#include <wtf/PassRefPtr.h> - -namespace Inspector { - -namespace TypeBuilder { - -${forwards} - -${exportMacro} String get${outputFileNamePrefix}EnumConstantValue(int code); - -${typeBuilders} -} // namespace TypeBuilder - -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) - -#endif // !defined(Inspector${outputFileNamePrefix}TypeBuilders_h) - -""") - -typebuilder_cpp = ( -""" - -#include "config.h" -#include "Inspector${outputFileNamePrefix}TypeBuilders.h" - -#if ENABLE(INSPECTOR) - -#include <wtf/text/CString.h> - -namespace Inspector { - -namespace TypeBuilder { - -static const char* const enum_constant_values[] = { -${enumConstantValues}}; - -String get${outputFileNamePrefix}EnumConstantValue(int code) { - return enum_constant_values[code]; -} - -} // namespace TypeBuilder - -${implCode} - -#if ${validatorIfdefName} - -${validatorCode} - -#endif // ${validatorIfdefName} - -} // namespace Inspector - -#endif // ENABLE(INSPECTOR) -""") - -backend_js = ( -""" - -${domainInitializers} -""") - -param_container_access_code = """ - RefPtr<InspectorObject> paramsContainer = message.getObject("params"); - InspectorObject* paramsContainerPtr = paramsContainer.get(); - InspectorArray* protocolErrorsPtr = protocolErrors.get(); -""" - -class_binding_builder_part_1 = ( -""" AllFieldsSet = %s - }; - - template<int STATE> - class Builder { - private: - RefPtr<Inspector::InspectorObject> m_result; - - template<int STEP> Builder<STATE | STEP>& castState() - { - return *reinterpret_cast<Builder<STATE | STEP>*>(this); - } - - Builder(PassRefPtr</*%s*/Inspector::InspectorObject> ptr) - { - COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state); - m_result = ptr; - } - friend class %s; - public: -""") - -class_binding_builder_part_2 = (""" - Builder<STATE | %s>& set%s(%s value) - { - COMPILE_ASSERT(!(STATE & %s), property_%s_already_set); - m_result->set%s(ASCIILiteral("%s"), %s); - return castState<%s>(); - } -""") - -class_binding_builder_part_3 = (""" - operator RefPtr<%s>& () - { - COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready); - COMPILE_ASSERT(sizeof(%s) == sizeof(Inspector::InspectorObject), cannot_cast); - return *reinterpret_cast<RefPtr<%s>*>(&m_result); - } - - PassRefPtr<%s> release() - { - return RefPtr<%s>(*this).release(); - } - }; - -""") - -class_binding_builder_part_4 = ( -""" static Builder<NoFieldsSet> create() - { - return Builder<NoFieldsSet>(Inspector::InspectorObject::create()); - } -""") diff --git a/inspector/scripts/codegen/__init__.py b/inspector/scripts/codegen/__init__.py new file mode 100644 index 0000000..6077fa9 --- /dev/null +++ b/inspector/scripts/codegen/__init__.py @@ -0,0 +1,24 @@ +# Required for Python to search this directory for module files + +from models import * +from generator import * +from cpp_generator import * +from objc_generator import * + +from generate_cpp_alternate_backend_dispatcher_header import * +from generate_cpp_backend_dispatcher_header import * +from generate_cpp_backend_dispatcher_implementation import * +from generate_cpp_frontend_dispatcher_header import * +from generate_cpp_frontend_dispatcher_implementation import * +from generate_cpp_protocol_types_header import * +from generate_cpp_protocol_types_implementation import * +from generate_js_backend_commands import * +from generate_objc_backend_dispatcher_header import * +from generate_objc_backend_dispatcher_implementation import * +from generate_objc_configuration_header import * +from generate_objc_configuration_implementation import * +from generate_objc_conversion_helpers import * +from generate_objc_frontend_dispatcher_implementation import * +from generate_objc_header import * +from generate_objc_internal_header import * +from generate_objc_protocol_types_implementation import * diff --git a/inspector/scripts/codegen/cpp_generator.py b/inspector/scripts/codegen/cpp_generator.py new file mode 100644 index 0000000..edd330d --- /dev/null +++ b/inspector/scripts/codegen/cpp_generator.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +import logging +import os.path +import re + +from generator import ucfirst +from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks + +log = logging.getLogger('global') + +_PRIMITIVE_TO_CPP_NAME_MAP = { + 'boolean': 'bool', + 'integer': 'int', + 'number': 'double', + 'string': 'String', + 'object': 'Inspector::InspectorObject', + 'array': 'Inspector::InspectorArray', + 'any': 'Inspector::InspectorValue' +} + +# This class contains extra static methods used for generation, but does +# not participate in any inheritance hierarchy. File generators should +# extend the generic "Generator" class instead. +class CppGenerator: + + # Miscellaneous text manipulation routines. + @staticmethod + def cpp_getter_method_for_type(_type): + if isinstance(_type, ObjectType): + return 'getObject' + if isinstance(_type, ArrayType): + return 'getArray' + if isinstance(_type, PrimitiveType): + if _type.raw_name() is 'integer': + return 'getInteger' + elif _type.raw_name() is 'number': + return 'getDouble' + elif _type.raw_name() is 'any': + return 'getValue' + else: + return 'get' + ucfirst(_type.raw_name()) + if isinstance(_type, AliasedType): + return CppGenerator.cpp_getter_method_for_type(_type.aliased_type) + if isinstance(_type, EnumType): + return CppGenerator.cpp_getter_method_for_type(_type.primitive_type) + + @staticmethod + def cpp_setter_method_for_type(_type): + if isinstance(_type, ObjectType): + return 'setObject' + if isinstance(_type, ArrayType): + return 'setArray' + if isinstance(_type, PrimitiveType): + if _type.raw_name() is 'integer': + return 'setInteger' + elif _type.raw_name() is 'number': + return 'setDouble' + elif _type.raw_name() is 'any': + return 'setValue' + else: + return 'set' + ucfirst(_type.raw_name()) + if isinstance(_type, AliasedType): + return CppGenerator.cpp_setter_method_for_type(_type.aliased_type) + if isinstance(_type, EnumType): + return CppGenerator.cpp_setter_method_for_type(_type.primitive_type) + + # Generate type representations for various situations. + @staticmethod + def cpp_protocol_type_for_type(_type): + if isinstance(_type, ObjectType) and len(_type.members) == 0: + return 'Inspector::InspectorObject' + if isinstance(_type, ArrayType): + if _type.raw_name() is None: # Otherwise, fall through and use typedef'd name. + return 'Inspector::Protocol::Array<%s>' % CppGenerator.cpp_protocol_type_for_type(_type.element_type) + if isinstance(_type, (ObjectType, AliasedType, EnumType, ArrayType)): + return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) + if isinstance(_type, PrimitiveType): + return CppGenerator.cpp_name_for_primitive_type(_type) + + @staticmethod + def cpp_protocol_type_for_type_member(type_member, object_declaration): + if isinstance(type_member.type, EnumType) and type_member.type.is_anonymous: + return '::'.join([CppGenerator.cpp_protocol_type_for_type(object_declaration.type), ucfirst(type_member.member_name)]) + else: + return CppGenerator.cpp_protocol_type_for_type(type_member.type) + + @staticmethod + def cpp_type_for_unchecked_formal_in_parameter(parameter): + _type = parameter.type + if isinstance(_type, AliasedType): + _type = _type.aliased_type # Fall through to enum or primitive. + + if isinstance(_type, EnumType): + _type = _type.primitive_type # Fall through to primitive. + + # This handles the 'any' type and objects with defined properties. + if isinstance(_type, ObjectType) or _type.qualified_name() is 'object': + cpp_name = 'Inspector::InspectorObject' + if parameter.is_optional: + return 'const %s*' % cpp_name + else: + return 'const %s&' % cpp_name + if isinstance(_type, ArrayType): + cpp_name = 'Inspector::InspectorArray' + if parameter.is_optional: + return 'const %s*' % cpp_name + else: + return 'const %s&' % cpp_name + if isinstance(_type, PrimitiveType): + cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) + if parameter.is_optional: + return 'const %s*' % cpp_name + elif _type.raw_name() in ['string']: + return 'const %s&' % cpp_name + else: + return cpp_name + + return "unknown_unchecked_formal_in_parameter_type" + + @staticmethod + def cpp_type_for_checked_formal_event_parameter(parameter): + return CppGenerator.cpp_type_for_type_with_name(parameter.type, parameter.parameter_name, parameter.is_optional) + + @staticmethod + def cpp_type_for_type_member(member): + return CppGenerator.cpp_type_for_type_with_name(member.type, member.member_name, False) + + @staticmethod + def cpp_type_for_type_with_name(_type, type_name, is_optional): + if isinstance(_type, (ArrayType, ObjectType)): + return 'RefPtr<%s>' % CppGenerator.cpp_protocol_type_for_type(_type) + if isinstance(_type, AliasedType): + builder_type = CppGenerator.cpp_protocol_type_for_type(_type) + if is_optional: + return 'const %s* const' % builder_type + elif _type.aliased_type.qualified_name() in ['integer', 'number']: + return CppGenerator.cpp_name_for_primitive_type(_type.aliased_type) + elif _type.aliased_type.qualified_name() in ['string']: + return 'const %s&' % builder_type + else: + return builder_type + if isinstance(_type, PrimitiveType): + cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) + if _type.qualified_name() in ['object']: + return 'RefPtr<Inspector::InspectorObject>' + elif _type.qualified_name() in ['any']: + return 'RefPtr<Inspector::InspectorValue>' + elif is_optional: + return 'const %s* const' % cpp_name + elif _type.qualified_name() in ['string']: + return 'const %s&' % cpp_name + else: + return cpp_name + if isinstance(_type, EnumType): + if _type.is_anonymous: + enum_type_name = ucfirst(type_name) + else: + enum_type_name = 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) + + if is_optional: + return '%s*' % enum_type_name + else: + return '%s' % enum_type_name + + @staticmethod + def cpp_type_for_formal_out_parameter(parameter): + _type = parameter.type + + if isinstance(_type, AliasedType): + _type = _type.aliased_type # Fall through. + + if isinstance(_type, (ObjectType, ArrayType)): + return 'RefPtr<%s>&' % CppGenerator.cpp_protocol_type_for_type(_type) + if isinstance(_type, PrimitiveType): + cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) + if parameter.is_optional: + return "Inspector::Protocol::OptOutput<%s>*" % cpp_name + else: + return '%s*' % cpp_name + if isinstance(_type, EnumType): + if _type.is_anonymous: + return '%sBackendDispatcherHandler::%s*' % (_type.type_domain().domain_name, ucfirst(parameter.parameter_name)) + else: + return 'Inspector::Protocol::%s::%s*' % (_type.type_domain().domain_name, _type.raw_name()) + + raise ValueError("unknown formal out parameter type.") + + # FIXME: this is only slightly different from out parameters; they could be unified. + @staticmethod + def cpp_type_for_formal_async_parameter(parameter): + _type = parameter.type + if isinstance(_type, AliasedType): + _type = _type.aliased_type # Fall through. + + if isinstance(_type, EnumType): + _type = _type.primitive_type # Fall through. + + if isinstance(_type, (ObjectType, ArrayType)): + return 'RefPtr<%s>&&' % CppGenerator.cpp_protocol_type_for_type(_type) + if isinstance(_type, PrimitiveType): + cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) + if parameter.is_optional: + return "Inspector::Protocol::OptOutput<%s>*" % cpp_name + elif _type.qualified_name() in ['integer', 'number']: + return CppGenerator.cpp_name_for_primitive_type(_type) + elif _type.qualified_name() in ['string']: + return 'const %s&' % cpp_name + else: + return cpp_name + + raise ValueError("Unknown formal async parameter type.") + + # In-parameters don't use builder types, because they could be passed + # "open types" that are manually constructed out of InspectorObjects. + + # FIXME: Only parameters that are actually open types should need non-builder parameter types. + @staticmethod + def cpp_type_for_stack_in_parameter(parameter): + _type = parameter.type + if isinstance(_type, AliasedType): + _type = _type.aliased_type # Fall through. + + if isinstance(_type, EnumType): + _type = _type.primitive_type # Fall through. + + if isinstance(_type, ObjectType): + return "RefPtr<Inspector::InspectorObject>" + if isinstance(_type, ArrayType): + return "RefPtr<Inspector::InspectorArray>" + if isinstance(_type, PrimitiveType): + cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) + if _type.qualified_name() in ['any', 'object']: + return "RefPtr<%s>" % CppGenerator.cpp_name_for_primitive_type(_type) + elif parameter.is_optional and _type.qualified_name() not in ['boolean', 'string', 'integer']: + return "Inspector::Protocol::OptOutput<%s>" % cpp_name + else: + return cpp_name + + @staticmethod + def cpp_type_for_stack_out_parameter(parameter): + _type = parameter.type + if isinstance(_type, (ArrayType, ObjectType)): + return 'RefPtr<%s>' % CppGenerator.cpp_protocol_type_for_type(_type) + if isinstance(_type, AliasedType): + builder_type = CppGenerator.cpp_protocol_type_for_type(_type) + if parameter.is_optional: + return "Inspector::Protocol::OptOutput<%s>" % builder_type + return '%s' % builder_type + if isinstance(_type, PrimitiveType): + cpp_name = CppGenerator.cpp_name_for_primitive_type(_type) + if parameter.is_optional: + return "Inspector::Protocol::OptOutput<%s>" % cpp_name + else: + return cpp_name + if isinstance(_type, EnumType): + if _type.is_anonymous: + return '%sBackendDispatcherHandler::%s' % (_type.type_domain().domain_name, ucfirst(parameter.parameter_name)) + else: + return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) + + @staticmethod + def cpp_assertion_method_for_type_member(type_member, object_declaration): + + def assertion_method_for_type(_type): + return 'BindingTraits<%s>::assertValueHasExpectedType' % CppGenerator.cpp_protocol_type_for_type(_type) + + if isinstance(type_member.type, AliasedType): + return assertion_method_for_type(type_member.type.aliased_type) + if isinstance(type_member.type, EnumType) and type_member.type.is_anonymous: + return 'BindingTraits<%s>::assertValueHasExpectedType' % CppGenerator.cpp_protocol_type_for_type_member(type_member, object_declaration) + + return assertion_method_for_type(type_member.type) + + @staticmethod + def cpp_name_for_primitive_type(_type): + return _PRIMITIVE_TO_CPP_NAME_MAP.get(_type.raw_name()) + + # Decide whether certain helpers are necessary in a situation. + @staticmethod + def should_use_wrapper_for_return_type(_type): + return not isinstance(_type, (ArrayType, ObjectType)) + + @staticmethod + def should_use_references_for_type(_type): + return isinstance(_type, (ArrayType, ObjectType)) or (isinstance(_type, (PrimitiveType)) and _type.qualified_name() in ["any", "object"]) + + @staticmethod + def should_pass_by_copy_for_return_type(_type): + return isinstance(_type, (ArrayType, ObjectType)) or (isinstance(_type, (PrimitiveType)) and _type.qualified_name() == "object") diff --git a/inspector/scripts/codegen/cpp_generator_templates.py b/inspector/scripts/codegen/cpp_generator_templates.py new file mode 100755 index 0000000..05f3530 --- /dev/null +++ b/inspector/scripts/codegen/cpp_generator_templates.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +# Generator templates, which can be filled with string.Template. +# Following are classes that fill the templates from the typechecked model. + +class CppGeneratorTemplates: + + HeaderPrelude = ( + """#ifndef ${headerGuardString} +#define ${headerGuardString} + +${includes} + +namespace Inspector { + +${typedefs}""") + + HeaderPostlude = ( + """} // namespace Inspector + +#endif // !defined(${headerGuardString})""") + + ImplementationPrelude = ( + """#include "config.h" +#include ${primaryInclude} + +${secondaryIncludes} + +namespace Inspector {""") + + ImplementationPostlude = ( + """} // namespace Inspector +""") + + AlternateDispatchersHeaderPrelude = ( + """#ifndef ${headerGuardString} +#define ${headerGuardString} + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +${includes} + +namespace Inspector { + +class AlternateBackendDispatcher { +public: + void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTF::move(dispatcher); } + BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); } +private: + RefPtr<BackendDispatcher> m_backendDispatcher; +}; +""") + + AlternateDispatchersHeaderPostlude = ( + """} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(${headerGuardString})""") + + AlternateBackendDispatcherHeaderDomainHandlerInterfaceDeclaration = ( + """class Alternate${domainName}BackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~Alternate${domainName}BackendDispatcher() { } +${commandDeclarations} +};""") + + BackendDispatcherHeaderDomainHandlerDeclaration = ( + """${classAndExportMacro} ${domainName}BackendDispatcherHandler { +public: +${commandDeclarations} +protected: + virtual ~${domainName}BackendDispatcherHandler(); +};""") + + BackendDispatcherHeaderDomainDispatcherDeclaration = ( + """${classAndExportMacro} ${domainName}BackendDispatcher final : public SupplementalBackendDispatcher { +public: + static Ref<${domainName}BackendDispatcher> create(BackendDispatcher*, ${domainName}BackendDispatcherHandler*); + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) override; +${commandDeclarations} +private: + ${domainName}BackendDispatcher(BackendDispatcher&, ${domainName}BackendDispatcherHandler*); + ${domainName}BackendDispatcherHandler* m_agent; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +public: + void setAlternateDispatcher(Alternate${domainName}BackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; } +private: + Alternate${domainName}BackendDispatcher* m_alternateDispatcher; +#endif +};""") + + BackendDispatcherHeaderAsyncCommandDeclaration = ( + """ ${classAndExportMacro} ${callbackName} : public BackendDispatcher::CallbackBase { + public: + ${callbackName}(Ref<BackendDispatcher>&&, int id); + void sendSuccess(${outParameters}); + }; + virtual void ${commandName}(${inParameters}) = 0;""") + + BackendDispatcherImplementationSmallSwitch = ( + """void ${domainName}BackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<${domainName}BackendDispatcher> protect(*this); + +${dispatchCases} + else + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\\'', "${domainName}", '.', method, "' was not found")); +}""") + + BackendDispatcherImplementationLargeSwitch = ( +"""void ${domainName}BackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<${domainName}BackendDispatcher> protect(*this); + + typedef void (${domainName}BackendDispatcher::*CallHandler)(long callId, const InspectorObject& message); + typedef HashMap<String, CallHandler> DispatchMap; + DEPRECATED_DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, ()); + if (dispatchMap.isEmpty()) { + static const struct MethodTable { + const char* name; + CallHandler handler; + } commands[] = { +${dispatchCases} + }; + size_t length = WTF_ARRAY_LENGTH(commands); + for (size_t i = 0; i < length; ++i) + dispatchMap.add(commands[i].name, commands[i].handler); + } + + HashMap<String, CallHandler>::iterator it = dispatchMap.find(method); + if (it == dispatchMap.end()) { + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\\'', "${domainName}", '.', method, "' was not found")); + return; + } + + ((*this).*it->value)(callId, message.get()); +}""") + + BackendDispatcherImplementationDomainConstructor = ( + """Ref<${domainName}BackendDispatcher> ${domainName}BackendDispatcher::create(BackendDispatcher* backendDispatcher, ${domainName}BackendDispatcherHandler* agent) +{ + return adoptRef(*new ${domainName}BackendDispatcher(*backendDispatcher, agent)); +} + +${domainName}BackendDispatcher::${domainName}BackendDispatcher(BackendDispatcher& backendDispatcher, ${domainName}BackendDispatcherHandler* agent) + : SupplementalBackendDispatcher(backendDispatcher) + , m_agent(agent) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_alternateDispatcher(nullptr) +#endif +{ + m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("${domainName}"), this); +}""") + + BackendDispatcherImplementationPrepareCommandArguments = ( +""" auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); +${inParameterDeclarations} + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method \'%s\' can't be processed", "${domainName}.${commandName}"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } +""") + + BackendDispatcherImplementationAsyncCommand = ( +"""${domainName}BackendDispatcherHandler::${callbackName}::${callbackName}(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTF::move(backendDispatcher), id) { } + +void ${domainName}BackendDispatcherHandler::${callbackName}::sendSuccess(${formalParameters}) +{ + Ref<InspectorObject> jsonMessage = InspectorObject::create(); +${outParameterAssignments} + sendIfActive(WTF::move(jsonMessage), ErrorString()); +}""") + + FrontendDispatcherDomainDispatcherDeclaration = ( +"""${classAndExportMacro} ${domainName}FrontendDispatcher { +public: + ${domainName}FrontendDispatcher(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { } +${eventDeclarations} +private: + FrontendChannel* m_frontendChannel; +};""") + + ProtocolObjectBuilderDeclarationPrelude = ( +""" template<int STATE> + class Builder { + private: + RefPtr<InspectorObject> m_result; + + template<int STEP> Builder<STATE | STEP>& castState() + { + return *reinterpret_cast<Builder<STATE | STEP>*>(this); + } + + Builder(Ref</*${objectType}*/InspectorObject>&& object) + : m_result(WTF::move(object)) + { + COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state); + } + friend class ${objectType}; + public:""") + + ProtocolObjectBuilderDeclarationPostlude = ( +""" + Ref<${objectType}> release() + { + COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready); + COMPILE_ASSERT(sizeof(${objectType}) == sizeof(InspectorObject), cannot_cast); + + Ref<InspectorObject> result = m_result.releaseNonNull(); + return WTF::move(*reinterpret_cast<Ref<${objectType}>*>(&result)); + } + }; + + /* + * Synthetic constructor: +${constructorExample} + */ + static Builder<NoFieldsSet> create() + { + return Builder<NoFieldsSet>(InspectorObject::create()); + }""") + + ProtocolObjectRuntimeCast = ( +"""RefPtr<${objectType}> BindingTraits<${objectType}>::runtimeCast(RefPtr<InspectorValue>&& value) +{ + RefPtr<InspectorObject> result; + bool castSucceeded = value->asObject(result); + ASSERT_UNUSED(castSucceeded, castSucceeded); +#if !ASSERT_DISABLED + BindingTraits<${objectType}>::assertValueHasExpectedType(result.get()); +#endif // !ASSERT_DISABLED + COMPILE_ASSERT(sizeof(${objectType}) == sizeof(InspectorObjectBase), type_cast_problem); + return static_cast<${objectType}*>(static_cast<InspectorObjectBase*>(result.get())); +} +""") diff --git a/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py b/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py new file mode 100755 index 0000000..d4a8d5a --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_alternate_backend_dispatcher_header.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +import re +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator + +log = logging.getLogger('global') + + +class CppAlternateBackendDispatcherHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return 'InspectorAlternateBackendDispatchers.h' + + def generate_output(self): + headers = [ + '"InspectorProtocolTypes.h"', + '<JavaScriptCore/InspectorBackendDispatcher.h>', + ] + + header_args = { + 'headerGuardString': re.sub('\W+', '_', self.output_filename()), + 'includes': '\n'.join(['#include ' + header for header in headers]), + } + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.AlternateDispatchersHeaderPrelude).substitute(None, **header_args)) + sections.append('\n'.join(filter(None, map(self._generate_handler_declarations_for_domain, domains)))) + sections.append(Template(CppTemplates.AlternateDispatchersHeaderPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_handler_declarations_for_domain(self, domain): + if not domain.commands: + return '' + + command_declarations = [] + for command in domain.commands: + command_declarations.append(self._generate_handler_declaration_for_command(command)) + + handler_args = { + 'domainName': domain.domain_name, + 'commandDeclarations': '\n'.join(command_declarations), + } + + return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.AlternateBackendDispatcherHeaderDomainHandlerInterfaceDeclaration).substitute(None, **handler_args)) + + def _generate_handler_declaration_for_command(self, command): + lines = [] + parameters = ['long callId'] + for _parameter in command.call_parameters: + parameters.append('%s in_%s' % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), _parameter.parameter_name)) + + command_args = { + 'commandName': command.command_name, + 'parameters': ', '.join(parameters), + } + lines.append(' virtual void %(commandName)s(%(parameters)s) = 0;' % command_args) + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py b/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py new file mode 100755 index 0000000..54bdb3e --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_backend_dispatcher_header.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import re +import string +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator, ucfirst +from models import EnumType + +log = logging.getLogger('global') + + +class CppBackendDispatcherHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorBackendDispatchers.h" + + def domains_to_generate(self): + return filter(lambda domain: len(domain.commands) > 0, Generator.domains_to_generate(self)) + + def generate_output(self): + headers = [ + '"InspectorProtocolObjects.h"', + '<inspector/InspectorBackendDispatcher.h>', + '<wtf/text/WTFString.h>'] + + typedefs = [('String', 'ErrorString')] + + header_args = { + 'headerGuardString': re.sub('\W+', '_', self.output_filename()), + 'includes': '\n'.join(['#include ' + header for header in headers]), + 'typedefs': '\n'.join(['typedef %s %s;' % typedef for typedef in typedefs]), + } + + domains = self.domains_to_generate() + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.HeaderPrelude).substitute(None, **header_args)) + sections.append(self._generate_alternate_handler_forward_declarations_for_domains(domains)) + sections.extend(map(self._generate_handler_declarations_for_domain, domains)) + sections.extend(map(self._generate_dispatcher_declarations_for_domain, domains)) + sections.append(Template(CppTemplates.HeaderPostlude).substitute(None, **header_args)) + return "\n\n".join(sections) + + # Private methods. + + def _generate_alternate_handler_forward_declarations_for_domains(self, domains): + if not domains: + return '' + + lines = [] + lines.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)') + for domain in domains: + lines.append(self.wrap_with_guard_for_domain(domain, 'class Alternate%sBackendDispatcher;' % domain.domain_name)) + lines.append('#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)') + return '\n'.join(lines) + + def _generate_handler_declarations_for_domain(self, domain): + classComponents = ['class'] + exportMacro = self.model().framework.setting('export_macro', None) + if exportMacro is not None: + classComponents.append(exportMacro) + + used_enum_names = set() + + command_declarations = [] + for command in domain.commands: + command_declarations.append(self._generate_handler_declaration_for_command(command, used_enum_names)) + + handler_args = { + 'classAndExportMacro': " ".join(classComponents), + 'domainName': domain.domain_name, + 'commandDeclarations': "\n".join(command_declarations) + } + + return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.BackendDispatcherHeaderDomainHandlerDeclaration).substitute(None, **handler_args)) + + def _generate_anonymous_enum_for_parameter(self, parameter, command): + enum_args = { + 'parameterName': parameter.parameter_name, + 'commandName': command.command_name + } + + lines = [] + lines.append(' // Named after parameter \'%(parameterName)s\' while generating command/event %(commandName)s.' % enum_args) + lines.append(' enum class %s {' % ucfirst(parameter.parameter_name)) + for enum_value in parameter.type.enum_values(): + lines.append(' %s = %d,' % (Generator.stylized_name_for_enum_value(enum_value), self.encoding_for_enum_value(enum_value))) + lines.append(' }; // enum class %s' % ucfirst(parameter.parameter_name)) + return '\n'.join(lines) + + def _generate_handler_declaration_for_command(self, command, used_enum_names): + if command.is_async: + return self._generate_async_handler_declaration_for_command(command) + + lines = [] + parameters = ['ErrorString&'] + for _parameter in command.call_parameters: + parameter_name = 'in_' + _parameter.parameter_name + if _parameter.is_optional: + parameter_name = 'opt_' + parameter_name + + parameters.append("%s %s" % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), parameter_name)) + + if isinstance(_parameter.type, EnumType) and _parameter.parameter_name not in used_enum_names: + lines.append(self._generate_anonymous_enum_for_parameter(_parameter, command)) + used_enum_names.add(_parameter.parameter_name) + + for _parameter in command.return_parameters: + parameter_name = 'out_' + _parameter.parameter_name + if _parameter.is_optional: + parameter_name = 'opt_' + parameter_name + parameters.append("%s %s" % (CppGenerator.cpp_type_for_formal_out_parameter(_parameter), parameter_name)) + + if isinstance(_parameter.type, EnumType) and _parameter.parameter_name not in used_enum_names: + lines.append(self._generate_anonymous_enum_for_parameter(_parameter, command)) + used_enum_names.add(_parameter.parameter_name) + + command_args = { + 'commandName': command.command_name, + 'parameters': ", ".join(parameters) + } + lines.append(' virtual void %(commandName)s(%(parameters)s) = 0;' % command_args) + return '\n'.join(lines) + + def _generate_async_handler_declaration_for_command(self, command): + callbackName = "%sCallback" % ucfirst(command.command_name) + + in_parameters = ['ErrorString&'] + for _parameter in command.call_parameters: + parameter_name = 'in_' + _parameter.parameter_name + if _parameter.is_optional: + parameter_name = 'opt_' + parameter_name + + in_parameters.append("%s %s" % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), parameter_name)) + in_parameters.append("Ref<%s>&& callback" % callbackName) + + out_parameters = [] + for _parameter in command.return_parameters: + out_parameters.append("%s %s" % (CppGenerator.cpp_type_for_formal_async_parameter(_parameter), _parameter.parameter_name)) + + class_components = ['class'] + export_macro = self.model().framework.setting('export_macro', None) + if export_macro: + class_components.append(export_macro) + + command_args = { + 'classAndExportMacro': ' '.join(class_components), + 'callbackName': callbackName, + 'commandName': command.command_name, + 'inParameters': ", ".join(in_parameters), + 'outParameters': ", ".join(out_parameters), + } + + return Template(CppTemplates.BackendDispatcherHeaderAsyncCommandDeclaration).substitute(None, **command_args) + + def _generate_dispatcher_declarations_for_domain(self, domain): + classComponents = ['class'] + exportMacro = self.model().framework.setting('export_macro', None) + if exportMacro is not None: + classComponents.append(exportMacro) + + declarations = [] + if len(domain.commands) > 0: + declarations.append('private:') + declarations.extend(map(self._generate_dispatcher_declaration_for_command, domain.commands)) + + handler_args = { + 'classAndExportMacro': " ".join(classComponents), + 'domainName': domain.domain_name, + 'commandDeclarations': "\n".join(declarations) + } + + return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.BackendDispatcherHeaderDomainDispatcherDeclaration).substitute(None, **handler_args)) + + def _generate_dispatcher_declaration_for_command(self, command): + return " void %s(long callId, const InspectorObject& message);" % command.command_name diff --git a/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py b/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py new file mode 100755 index 0000000..350f085 --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_backend_dispatcher_implementation.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator, ucfirst +from models import ObjectType, ArrayType + +log = logging.getLogger('global') + + +class CppBackendDispatcherImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorBackendDispatchers.cpp" + + def domains_to_generate(self): + return filter(lambda domain: len(domain.commands) > 0, Generator.domains_to_generate(self)) + + def generate_output(self): + secondary_headers = [ + '<inspector/InspectorFrontendChannel.h>', + '<inspector/InspectorValues.h>', + '<wtf/text/CString.h>'] + + secondary_includes = ['#include %s' % header for header in secondary_headers] + secondary_includes.append('') + secondary_includes.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)') + secondary_includes.append('#include "InspectorAlternateBackendDispatchers.h"') + secondary_includes.append('#endif') + + header_args = { + 'primaryInclude': '"InspectorBackendDispatchers.h"', + 'secondaryIncludes': '\n'.join(secondary_includes), + } + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args)) + sections.append("\n".join(map(self._generate_handler_class_destructor_for_domain, self.domains_to_generate()))) + sections.extend(map(self._generate_dispatcher_implementations_for_domain, self.domains_to_generate())) + sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args)) + return "\n\n".join(sections) + + # Private methods. + + def _generate_handler_class_destructor_for_domain(self, domain): + destructor_args = { + 'domainName': domain.domain_name + } + destructor = '%(domainName)sBackendDispatcherHandler::~%(domainName)sBackendDispatcherHandler() { }' % destructor_args + return self.wrap_with_guard_for_domain(domain, destructor) + + def _generate_dispatcher_implementations_for_domain(self, domain): + implementations = [] + + constructor_args = { + 'domainName': domain.domain_name, + } + implementations.append(Template(CppTemplates.BackendDispatcherImplementationDomainConstructor).substitute(None, **constructor_args)) + + if len(domain.commands) <= 5: + implementations.append(self._generate_small_dispatcher_switch_implementation_for_domain(domain)) + else: + implementations.append(self._generate_large_dispatcher_switch_implementation_for_domain(domain)) + + for command in domain.commands: + if command.is_async: + implementations.append(self._generate_async_dispatcher_class_for_domain(command, domain)) + implementations.append(self._generate_dispatcher_implementation_for_command(command, domain)) + + return self.wrap_with_guard_for_domain(domain, '\n\n'.join(implementations)) + + def _generate_small_dispatcher_switch_implementation_for_domain(self, domain): + cases = [] + cases.append(' if (method == "%s")' % domain.commands[0].command_name) + cases.append(' %s(callId, message);' % domain.commands[0].command_name) + for command in domain.commands[1:]: + cases.append(' else if (method == "%s")' % command.command_name) + cases.append(' %s(callId, message);' % command.command_name) + + switch_args = { + 'domainName': domain.domain_name, + 'dispatchCases': "\n".join(cases) + } + + return Template(CppTemplates.BackendDispatcherImplementationSmallSwitch).substitute(None, **switch_args) + + def _generate_large_dispatcher_switch_implementation_for_domain(self, domain): + cases = [] + for command in domain.commands: + args = { + 'domainName': domain.domain_name, + 'commandName': command.command_name + } + cases.append(' { "%(commandName)s", &%(domainName)sBackendDispatcher::%(commandName)s },' % args) + + switch_args = { + 'domainName': domain.domain_name, + 'dispatchCases': "\n".join(cases) + } + + return Template(CppTemplates.BackendDispatcherImplementationLargeSwitch).substitute(None, **switch_args) + + def _generate_async_dispatcher_class_for_domain(self, command, domain): + out_parameter_assignments = [] + formal_parameters = [] + + for parameter in command.return_parameters: + param_args = { + 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type), + 'parameterKey': parameter.parameter_name, + 'parameterName': parameter.parameter_name, + 'parameterType': CppGenerator.cpp_type_for_stack_in_parameter(parameter), + } + + formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_formal_async_parameter(parameter), parameter.parameter_name)) + + if parameter.is_optional: + if CppGenerator.should_use_wrapper_for_return_type(parameter.type): + out_parameter_assignments.append(' if (%(parameterName)s.isAssigned())' % param_args) + out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s.getValue());' % param_args) + else: + out_parameter_assignments.append(' if (%(parameterName)s)' % param_args) + out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s);' % param_args) + elif parameter.type.is_enum(): + out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), Inspector::Protocol::getEnumConstantValue(%(parameterName)s));' % param_args) + else: + out_parameter_assignments.append(' jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s);' % param_args) + + async_args = { + 'domainName': domain.domain_name, + 'callbackName': ucfirst(command.command_name) + 'Callback', + 'formalParameters': ", ".join(formal_parameters), + 'outParameterAssignments': "\n".join(out_parameter_assignments) + } + return Template(CppTemplates.BackendDispatcherImplementationAsyncCommand).substitute(None, **async_args) + + def _generate_dispatcher_implementation_for_command(self, command, domain): + in_parameter_declarations = [] + out_parameter_declarations = [] + out_parameter_assignments = [] + alternate_dispatcher_method_parameters = ['callId'] + method_parameters = ['error'] + + for parameter in command.call_parameters: + parameter_name = 'in_' + parameter.parameter_name + if parameter.is_optional: + parameter_name = 'opt_' + parameter_name + + out_success_argument = 'nullptr' + if parameter.is_optional: + out_success_argument = '&%s_valueFound' % parameter_name + in_parameter_declarations.append(' bool %s_valueFound = false;' % parameter_name) + + # Now add appropriate operators. + parameter_expression = parameter_name + + if CppGenerator.should_use_references_for_type(parameter.type): + if parameter.is_optional: + parameter_expression = '%s.get()' % parameter_expression + else: + # This assumes that we have already proved the object is non-null. + # If a required property is missing, InspectorBackend::getObject will + # append a protocol error, and the method dispatcher will return without + # invoking the backend method (and dereferencing the object). + parameter_expression = '*%s' % parameter_expression + elif parameter.is_optional: + parameter_expression = '&%s' % parameter_expression + + param_args = { + 'parameterType': CppGenerator.cpp_type_for_stack_in_parameter(parameter), + 'parameterKey': parameter.parameter_name, + 'parameterName': parameter_name, + 'parameterExpression': parameter_expression, + 'keyedGetMethod': CppGenerator.cpp_getter_method_for_type(parameter.type), + 'successOutParam': out_success_argument + } + + in_parameter_declarations.append(' %(parameterType)s %(parameterName)s = BackendDispatcher::%(keyedGetMethod)s(paramsContainer.get(), ASCIILiteral("%(parameterKey)s"), %(successOutParam)s, protocolErrors.get());' % param_args) + + if parameter.is_optional: + optional_in_parameter_string = '%(parameterName)s_valueFound ? %(parameterExpression)s : nullptr' % param_args + alternate_dispatcher_method_parameters.append(optional_in_parameter_string) + method_parameters.append(optional_in_parameter_string) + else: + alternate_dispatcher_method_parameters.append(parameter_expression) + method_parameters.append(parameter_expression) + + if command.is_async: + async_args = { + 'domainName': domain.domain_name, + 'callbackName': ucfirst(command.command_name) + 'Callback' + } + + out_parameter_assignments.append(' callback->disable();') + out_parameter_assignments.append(' m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::ServerError, error);') + out_parameter_assignments.append(' return;') + method_parameters.append('callback.copyRef()') + + else: + for parameter in command.return_parameters: + param_args = { + 'parameterType': CppGenerator.cpp_type_for_stack_out_parameter(parameter), + 'parameterKey': parameter.parameter_name, + 'parameterName': parameter.parameter_name, + 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type), + + } + + out_parameter_declarations.append(' %(parameterType)s out_%(parameterName)s;' % param_args) + if parameter.is_optional: + if CppGenerator.should_use_wrapper_for_return_type(parameter.type): + out_parameter_assignments.append(' if (out_%(parameterName)s.isAssigned())' % param_args) + out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s.getValue());' % param_args) + else: + out_parameter_assignments.append(' if (out_%(parameterName)s)' % param_args) + out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s);' % param_args) + elif parameter.type.is_enum(): + out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), Inspector::Protocol::getEnumConstantValue(out_%(parameterName)s));' % param_args) + else: + out_parameter_assignments.append(' result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s);' % param_args) + + if CppGenerator.should_pass_by_copy_for_return_type(parameter.type): + method_parameters.append('out_' + parameter.parameter_name) + else: + method_parameters.append('&out_' + parameter.parameter_name) + + command_args = { + 'domainName': domain.domain_name, + 'callbackName': '%sCallback' % ucfirst(command.command_name), + 'commandName': command.command_name, + 'inParameterDeclarations': '\n'.join(in_parameter_declarations), + 'invocationParameters': ', '.join(method_parameters), + 'alternateInvocationParameters': ', '.join(alternate_dispatcher_method_parameters), + } + + lines = [] + if len(command.call_parameters) == 0: + lines.append('void %(domainName)sBackendDispatcher::%(commandName)s(long callId, const InspectorObject&)' % command_args) + else: + lines.append('void %(domainName)sBackendDispatcher::%(commandName)s(long callId, const InspectorObject& message)' % command_args) + lines.append('{') + + if len(command.call_parameters) > 0: + lines.append(Template(CppTemplates.BackendDispatcherImplementationPrepareCommandArguments).substitute(None, **command_args)) + + lines.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)') + lines.append(' if (m_alternateDispatcher) {') + lines.append(' m_alternateDispatcher->%(commandName)s(%(alternateInvocationParameters)s);' % command_args) + lines.append(' return;') + lines.append(' }') + lines.append('#endif') + lines.append('') + + lines.append(' ErrorString error;') + lines.append(' Ref<InspectorObject> result = InspectorObject::create();') + if command.is_async: + lines.append(' Ref<%(domainName)sBackendDispatcherHandler::%(callbackName)s> callback = adoptRef(*new %(domainName)sBackendDispatcherHandler::%(callbackName)s(m_backendDispatcher.copyRef(), callId));' % command_args) + if len(command.return_parameters) > 0: + lines.extend(out_parameter_declarations) + lines.append(' m_agent->%(commandName)s(%(invocationParameters)s);' % command_args) + lines.append('') + if command.is_async: + lines.append(' if (error.length()) {') + lines.extend(out_parameter_assignments) + lines.append(' }') + elif len(command.return_parameters) > 1: + lines.append(' if (!error.length()) {') + lines.extend(out_parameter_assignments) + lines.append(' }') + elif len(command.return_parameters) == 1: + lines.append(' if (!error.length())') + lines.extend(out_parameter_assignments) + lines.append('') + + if not command.is_async: + lines.append(' m_backendDispatcher->sendResponse(callId, WTF::move(result), error);') + lines.append('}') + return "\n".join(lines) diff --git a/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py b/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py new file mode 100755 index 0000000..ff09ab3 --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_header.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import re +import string +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator, ucfirst +from models import EnumType + +log = logging.getLogger('global') + + +class CppFrontendDispatcherHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorFrontendDispatchers.h" + + def domains_to_generate(self): + return filter(lambda domain: len(domain.events) > 0, Generator.domains_to_generate(self)) + + def generate_output(self): + headers = [ + '"InspectorProtocolObjects.h"', + '<inspector/InspectorFrontendChannel.h>', + '<inspector/InspectorValues.h>', + '<wtf/text/WTFString.h>'] + + header_args = { + 'headerGuardString': re.sub('\W+', '_', self.output_filename()), + 'includes': '\n'.join(['#include ' + header for header in headers]), + 'typedefs': '', + } + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.HeaderPrelude).substitute(None, **header_args)) + sections.extend(map(self._generate_dispatcher_declarations_for_domain, self.domains_to_generate())) + sections.append(Template(CppTemplates.HeaderPostlude).substitute(None, **header_args)) + return "\n\n".join(sections) + + # Private methods. + + def _generate_anonymous_enum_for_parameter(self, parameter, event): + enum_args = { + 'parameterName': parameter.parameter_name, + 'eventName': event.event_name + } + + lines = [] + lines.append(' // Named after parameter \'%(parameterName)s\' while generating command/event %(eventName)s.' % enum_args) + lines.append(' enum class %s {' % ucfirst(parameter.parameter_name)) + for enum_value in parameter.type.enum_values(): + lines.append(' %s = %d,' % (Generator.stylized_name_for_enum_value(enum_value), self.encoding_for_enum_value(enum_value))) + lines.append(' }; // enum class %s' % ucfirst(parameter.parameter_name)) + return "\n".join(lines) + + def _generate_dispatcher_declarations_for_domain(self, domain): + classComponents = ['class'] + exportMacro = self.model().framework.setting('export_macro', None) + if exportMacro is not None: + classComponents.append(exportMacro) + + used_enum_names = set([]) + + event_declarations = [] + for event in domain.events: + event_declarations.append(self._generate_dispatcher_declaration_for_event(event, domain, used_enum_names)) + + handler_args = { + 'classAndExportMacro': " ".join(classComponents), + 'domainName': domain.domain_name, + 'eventDeclarations': "\n".join(event_declarations) + } + + return self.wrap_with_guard_for_domain(domain, Template(CppTemplates.FrontendDispatcherDomainDispatcherDeclaration).substitute(None, **handler_args)) + + def _generate_dispatcher_declaration_for_event(self, event, domain, used_enum_names): + formal_parameters = [] + lines = [] + for parameter in event.event_parameters: + formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_checked_formal_event_parameter(parameter), parameter.parameter_name)) + if isinstance(parameter.type, EnumType) and parameter.parameter_name not in used_enum_names: + lines.append(self._generate_anonymous_enum_for_parameter(parameter, event)) + used_enum_names.add(parameter.parameter_name) + + lines.append(" void %s(%s);" % (event.event_name, ", ".join(formal_parameters))) + return "\n".join(lines) diff --git a/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py b/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py new file mode 100755 index 0000000..798157a --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_frontend_dispatcher_implementation.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator, ucfirst +from models import ObjectType, ArrayType + +log = logging.getLogger('global') + + +class CppFrontendDispatcherImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorFrontendDispatchers.cpp" + + def domains_to_generate(self): + return filter(lambda domain: len(domain.events) > 0, Generator.domains_to_generate(self)) + + def generate_output(self): + secondary_headers = ['<wtf/text/CString.h>'] + + header_args = { + 'primaryInclude': '"InspectorFrontendDispatchers.h"', + 'secondaryIncludes': "\n".join(['#include %s' % header for header in secondary_headers]), + } + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args)) + sections.extend(map(self._generate_dispatcher_implementations_for_domain, self.domains_to_generate())) + sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args)) + return "\n\n".join(sections) + + # Private methods. + + def _generate_dispatcher_implementations_for_domain(self, domain): + implementations = [] + for event in domain.events: + implementations.append(self._generate_dispatcher_implementation_for_event(event, domain)) + + return self.wrap_with_guard_for_domain(domain, '\n\n'.join(implementations)) + + def _generate_dispatcher_implementation_for_event(self, event, domain): + lines = [] + parameter_assignments = [] + formal_parameters = [] + + for parameter in event.event_parameters: + + parameter_value = parameter.parameter_name + if parameter.is_optional and not CppGenerator.should_pass_by_copy_for_return_type(parameter.type): + parameter_value = '*' + parameter_value + if parameter.type.is_enum(): + parameter_value = 'Inspector::Protocol::getEnumConstantValue(%s)' % parameter_value + + parameter_args = { + 'parameterType': CppGenerator.cpp_type_for_stack_out_parameter(parameter), + 'parameterName': parameter.parameter_name, + 'parameterValue': parameter_value, + 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type), + } + + if parameter.is_optional: + parameter_assignments.append(' if (%(parameterName)s)' % parameter_args) + parameter_assignments.append(' paramsObject->%(keyedSetMethod)s(ASCIILiteral("%(parameterName)s"), %(parameterValue)s);' % parameter_args) + else: + parameter_assignments.append(' paramsObject->%(keyedSetMethod)s(ASCIILiteral("%(parameterName)s"), %(parameterValue)s);' % parameter_args) + + formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_checked_formal_event_parameter(parameter), parameter.parameter_name)) + + event_args = { + 'domainName': domain.domain_name, + 'eventName': event.event_name, + 'formalParameters': ", ".join(formal_parameters) + } + + lines.append('void %(domainName)sFrontendDispatcher::%(eventName)s(%(formalParameters)s)' % event_args) + lines.append('{') + lines.append(' Ref<InspectorObject> jsonMessage = InspectorObject::create();') + lines.append(' jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("%(domainName)s.%(eventName)s"));' % event_args) + + if len(parameter_assignments) > 0: + lines.append(' Ref<InspectorObject> paramsObject = InspectorObject::create();') + lines.extend(parameter_assignments) + lines.append(' jsonMessage->setObject(ASCIILiteral("params"), WTF::move(paramsObject));') + + lines.append('') + lines.append(' m_frontendChannel->sendMessageToFrontend(jsonMessage->toJSONString());') + lines.append('}') + return "\n".join(lines) diff --git a/inspector/scripts/codegen/generate_cpp_protocol_types_header.py b/inspector/scripts/codegen/generate_cpp_protocol_types_header.py new file mode 100755 index 0000000..b07b0b9 --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_protocol_types_header.py @@ -0,0 +1,352 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import re +import string +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator, ucfirst +from models import EnumType, ObjectType, PrimitiveType, AliasedType, ArrayType, Frameworks + +log = logging.getLogger('global') + + +class CppProtocolTypesHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorProtocolObjects.h" + + def generate_output(self): + domains = self.domains_to_generate() + self.calculate_types_requiring_shape_assertions(domains) + + headers = set([ + '<inspector/InspectorProtocolTypes.h>', + '<wtf/Assertions.h>', + ]) + + export_macro = self.model().framework.setting('export_macro', None) + + header_args = { + 'headerGuardString': re.sub('\W+', '_', self.output_filename()), + 'includes': '\n'.join(['#include ' + header for header in sorted(headers)]), + 'typedefs': '', + } + + return_type = 'String' + return_type_with_export_macro = [return_type] + if export_macro is not None: + return_type_with_export_macro[:0] = [export_macro] + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.HeaderPrelude).substitute(None, **header_args)) + sections.append('namespace Protocol {') + sections.append(self._generate_forward_declarations(domains)) + sections.append(self._generate_typedefs(domains)) + sections.append('%s getEnumConstantValue(int code);' % ' '.join(return_type_with_export_macro)) + sections.append('\n'.join([ + 'template<typename T> %s getEnumConstantValue(T enumValue)' % return_type, + '{', + ' return getEnumConstantValue(static_cast<int>(enumValue));', + '}'])) + + builder_sections = map(self._generate_builders_for_domain, domains) + sections.extend(filter(lambda section: len(section) > 0, builder_sections)) + sections.append(self._generate_forward_declarations_for_binding_traits()) + sections.append('} // namespace Protocol') + sections.append(Template(CppTemplates.HeaderPostlude).substitute(None, **header_args)) + return "\n\n".join(sections) + + # Private methods. + + # FIXME: move builders out of classes, uncomment forward declaration + + def _generate_forward_declarations(self, domains): + sections = [] + + for domain in domains: + declaration_types = [decl.type for decl in domain.type_declarations] + object_types = filter(lambda _type: isinstance(_type, ObjectType), declaration_types) + enum_types = filter(lambda _type: isinstance(_type, EnumType), declaration_types) + if len(object_types) + len(enum_types) == 0: + continue + + domain_lines = [] + domain_lines.append('namespace %s {' % domain.domain_name) + + object_type_names = [_type.raw_name() for _type in object_types] + enum_type_names = [_type.raw_name() for _type in enum_types] + + # Forward-declare all classes so the type builders won't break if rearranged. + domain_lines.extend('class %s;' % name for name in sorted(object_type_names)) + domain_lines.extend('enum class %s;' % name for name in sorted(enum_type_names)) + domain_lines.append('} // %s' % domain.domain_name) + sections.append(self.wrap_with_guard_for_domain(domain, '\n'.join(domain_lines))) + + if len(sections) == 0: + return '' + else: + return """// Forward declarations. +%s +// End of forward declarations. +""" % '\n\n'.join(sections) + + def _generate_typedefs(self, domains): + sections = map(self._generate_typedefs_for_domain, domains) + sections = filter(lambda text: len(text) > 0, sections) + + if len(sections) == 0: + return '' + else: + return """// Typedefs. +%s +// End of typedefs.""" % '\n\n'.join(sections) + + def _generate_typedefs_for_domain(self, domain): + primitive_declarations = filter(lambda decl: isinstance(decl.type, AliasedType), domain.type_declarations) + array_declarations = filter(lambda decl: isinstance(decl.type, ArrayType), domain.type_declarations) + if len(primitive_declarations) == 0 and len(array_declarations) == 0: + return '' + + sections = [] + for declaration in primitive_declarations: + primitive_name = CppGenerator.cpp_name_for_primitive_type(declaration.type.aliased_type) + typedef_lines = [] + if len(declaration.description) > 0: + typedef_lines.append('/* %s */' % declaration.description) + typedef_lines.append('typedef %s %s;' % (primitive_name, declaration.type_name)) + sections.append('\n'.join(typedef_lines)) + + for declaration in array_declarations: + element_type = CppGenerator.cpp_protocol_type_for_type(declaration.type.element_type) + typedef_lines = [] + if len(declaration.description) > 0: + typedef_lines.append('/* %s */' % declaration.description) + typedef_lines.append('typedef Inspector::Protocol::Array<%s> %s;' % (element_type, declaration.type_name)) + sections.append('\n'.join(typedef_lines)) + + lines = [] + lines.append('namespace %s {' % domain.domain_name) + lines.append('\n'.join(sections)) + lines.append('} // %s' % domain.domain_name) + return self.wrap_with_guard_for_domain(domain, '\n'.join(lines)) + + def _generate_builders_for_domain(self, domain): + sections = [] + + for type_declaration in domain.type_declarations: + if isinstance(type_declaration.type, EnumType): + sections.append(self._generate_struct_for_enum_declaration(type_declaration)) + elif isinstance(type_declaration.type, ObjectType): + sections.append(self._generate_class_for_object_declaration(type_declaration, domain)) + + sections = filter(lambda section: len(section) > 0, sections) + if len(sections) == 0: + return '' + + lines = [] + lines.append('namespace %s {' % domain.domain_name) + lines.append('\n'.join(sections)) + lines.append('} // %s' % domain.domain_name) + return self.wrap_with_guard_for_domain(domain, '\n'.join(lines)) + + def _generate_class_for_object_declaration(self, type_declaration, domain): + if len(type_declaration.type_members) == 0: + return '' + + enum_members = filter(lambda member: isinstance(member.type, EnumType) and member.type.is_anonymous, type_declaration.type_members) + required_members = filter(lambda member: not member.is_optional, type_declaration.type_members) + optional_members = filter(lambda member: member.is_optional, type_declaration.type_members) + object_name = type_declaration.type_name + + lines = [] + if len(type_declaration.description) > 0: + lines.append('/* %s */' % type_declaration.description) + base_class = 'Inspector::InspectorObject' + if not Generator.type_has_open_fields(type_declaration.type): + base_class = base_class + 'Base' + lines.append('class %s : public %s {' % (object_name, base_class)) + lines.append('public:') + for enum_member in enum_members: + lines.append(' // Named after property name \'%s\' while generating %s.' % (enum_member.member_name, object_name)) + lines.append(self._generate_struct_for_anonymous_enum_member(enum_member)) + lines.append(self._generate_builder_state_enum(type_declaration)) + + constructor_example = [] + constructor_example.append(' * Ref<%s> result = %s::create()' % (object_name, object_name)) + for member in required_members: + constructor_example.append(' * .set%s(...)' % ucfirst(member.member_name)) + constructor_example.append(' * .release()') + + builder_args = { + 'objectType': object_name, + 'constructorExample': '\n'.join(constructor_example) + ';', + } + + lines.append(Template(CppTemplates.ProtocolObjectBuilderDeclarationPrelude).substitute(None, **builder_args)) + for type_member in required_members: + lines.append(self._generate_builder_setter_for_member(type_member, domain)) + lines.append(Template(CppTemplates.ProtocolObjectBuilderDeclarationPostlude).substitute(None, **builder_args)) + for member in optional_members: + lines.append(self._generate_unchecked_setter_for_member(member, domain)) + + if Generator.type_has_open_fields(type_declaration.type): + lines.append('') + lines.append(' // Property names for type generated as open.') + for type_member in type_declaration.type_members: + export_macro = self.model().framework.setting('export_macro', None) + lines.append(' %s static const char* %s;' % (export_macro, ucfirst(type_member.member_name))) + + lines.append('};') + lines.append('') + return '\n'.join(lines) + + def _generate_struct_for_enum_declaration(self, enum_declaration): + lines = [] + lines.append('/* %s */' % enum_declaration.description) + lines.extend(self._generate_struct_for_enum_type(enum_declaration.type_name, enum_declaration.type)) + return '\n'.join(lines) + + def _generate_struct_for_anonymous_enum_member(self, enum_member): + def apply_indentation(line): + if line.startswith(('#', '/*', '*/', '//')) or len(line) is 0: + return line + else: + return ' ' + line + + indented_lines = map(apply_indentation, self._generate_struct_for_enum_type(enum_member.member_name, enum_member.type)) + return '\n'.join(indented_lines) + + def _generate_struct_for_enum_type(self, enum_name, enum_type): + lines = [] + enum_name = ucfirst(enum_name) + lines.append('enum class %s {' % enum_name) + for enum_value in enum_type.enum_values(): + lines.append(' %s = %s,' % (Generator.stylized_name_for_enum_value(enum_value), self.encoding_for_enum_value(enum_value))) + lines.append('}; // enum class %s' % enum_name) + return lines # The caller may want to adjust indentation, so don't join these lines. + + def _generate_builder_state_enum(self, type_declaration): + lines = [] + required_members = filter(lambda member: not member.is_optional, type_declaration.type_members) + enum_values = [] + + lines.append(' enum {') + lines.append(' NoFieldsSet = 0,') + for i in range(len(required_members)): + enum_value = "%sSet" % ucfirst(required_members[i].member_name) + enum_values.append(enum_value) + lines.append(' %s = 1 << %d,' % (enum_value, i)) + if len(enum_values) > 0: + lines.append(' AllFieldsSet = (%s)' % ' | '.join(enum_values)) + else: + lines.append(' AllFieldsSet = 0') + lines.append(' };') + lines.append('') + return '\n'.join(lines) + + def _generate_builder_setter_for_member(self, type_member, domain): + setter_args = { + 'camelName': ucfirst(type_member.member_name), + 'keyedSet': CppGenerator.cpp_setter_method_for_type(type_member.type), + 'name': type_member.member_name, + 'parameterType': CppGenerator.cpp_type_for_type_member(type_member) + } + + lines = [] + lines.append('') + lines.append(' Builder<STATE | %(camelName)sSet>& set%(camelName)s(%(parameterType)s value)' % setter_args) + lines.append(' {') + lines.append(' COMPILE_ASSERT(!(STATE & %(camelName)sSet), property_%(name)s_already_set);' % setter_args) + + if isinstance(type_member.type, EnumType): + lines.append(' m_result->%(keyedSet)s(ASCIILiteral("%(name)s"), Inspector::Protocol::getEnumConstantValue(static_cast<int>(value)));' % setter_args) + else: + lines.append(' m_result->%(keyedSet)s(ASCIILiteral("%(name)s"), value);' % setter_args) + lines.append(' return castState<%(camelName)sSet>();' % setter_args) + lines.append(' }') + return '\n'.join(lines) + + def _generate_unchecked_setter_for_member(self, type_member, domain): + setter_args = { + 'camelName': ucfirst(type_member.member_name), + 'keyedSet': CppGenerator.cpp_setter_method_for_type(type_member.type), + 'name': type_member.member_name, + 'parameterType': CppGenerator.cpp_type_for_type_member(type_member) + } + + lines = [] + lines.append('') + lines.append(' void set%(camelName)s(%(parameterType)s value)' % setter_args) + lines.append(' {') + if isinstance(type_member.type, EnumType): + lines.append(' InspectorObjectBase::%(keyedSet)s(ASCIILiteral("%(name)s"), Inspector::Protocol::getEnumConstantValue(static_cast<int>(value)));' % setter_args) + elif CppGenerator.should_use_references_for_type(type_member.type): + lines.append(' InspectorObjectBase::%(keyedSet)s(ASCIILiteral("%(name)s"), WTF::move(value));' % setter_args) + else: + lines.append(' InspectorObjectBase::%(keyedSet)s(ASCIILiteral("%(name)s"), value);' % setter_args) + lines.append(' }') + return '\n'.join(lines) + + def _generate_forward_declarations_for_binding_traits(self): + # A list of (builder_type, needs_runtime_cast) + type_arguments = [] + + for domain in self.domains_to_generate(): + declarations_to_generate = filter(lambda decl: self.type_needs_shape_assertions(decl.type), domain.type_declarations) + + for type_declaration in declarations_to_generate: + for type_member in type_declaration.type_members: + if isinstance(type_member.type, EnumType): + type_arguments.append((CppGenerator.cpp_protocol_type_for_type_member(type_member, type_declaration), False)) + + if isinstance(type_declaration.type, ObjectType): + type_arguments.append((CppGenerator.cpp_protocol_type_for_type(type_declaration.type), Generator.type_needs_runtime_casts(type_declaration.type))) + + struct_keywords = ['struct'] + function_keywords = ['static void'] + export_macro = self.model().framework.setting('export_macro', None) + if export_macro is not None: + struct_keywords.append(export_macro) + #function_keywords[1:1] = [export_macro] + + lines = [] + for argument in type_arguments: + lines.append('template<> %s BindingTraits<%s> {' % (' '.join(struct_keywords), argument[0])) + if argument[1]: + lines.append('static RefPtr<%s> runtimeCast(RefPtr<Inspector::InspectorValue>&& value);' % argument[0]) + lines.append('#if !ASSERT_DISABLED') + lines.append('%s assertValueHasExpectedType(Inspector::InspectorValue*);' % ' '.join(function_keywords)) + lines.append('#endif // !ASSERT_DISABLED') + lines.append('};') + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py b/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py new file mode 100755 index 0000000..2c263b5 --- /dev/null +++ b/inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from cpp_generator import CppGenerator +from cpp_generator_templates import CppGeneratorTemplates as CppTemplates +from generator import Generator, ucfirst +from models import AliasedType, ArrayType, EnumType, ObjectType + +log = logging.getLogger('global') + + +class CppProtocolTypesImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorProtocolObjects.cpp" + + def generate_output(self): + domains = self.domains_to_generate() + self.calculate_types_requiring_shape_assertions(domains) + + secondary_headers = ['<wtf/text/CString.h>'] + + header_args = { + 'primaryInclude': '"InspectorProtocolObjects.h"', + 'secondaryIncludes': "\n".join(['#include %s' % header for header in secondary_headers]), + } + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args)) + sections.append('namespace Protocol {') + sections.append(self._generate_enum_mapping()) + sections.append(self._generate_open_field_names()) + builder_sections = map(self._generate_builders_for_domain, domains) + sections.extend(filter(lambda section: len(section) > 0, builder_sections)) + sections.append('} // namespace Protocol') + sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args)) + + return "\n\n".join(sections) + + # Private methods. + + def _generate_enum_mapping(self): + lines = [] + lines.append('static const char* const enum_constant_values[] = {') + lines.extend([' "%s",' % enum_value for enum_value in self.assigned_enum_values()]) + lines.append('};') + lines.append('') + lines.append('String getEnumConstantValue(int code) {') + lines.append(' return enum_constant_values[code];') + lines.append('}') + return '\n'.join(lines) + + def _generate_open_field_names(self): + lines = [] + for domain in self.domains_to_generate(): + for type_declaration in filter(lambda decl: Generator.type_has_open_fields(decl.type), domain.type_declarations): + for type_member in sorted(type_declaration.type_members, key=lambda member: member.member_name): + field_name = '::'.join(['Inspector', 'Protocol', domain.domain_name, ucfirst(type_declaration.type_name), ucfirst(type_member.member_name)]) + lines.append('const char* %s = "%s";' % (field_name, type_member.member_name)) + + return '\n'.join(lines) + + def _generate_builders_for_domain(self, domain): + sections = [] + declarations_to_generate = filter(lambda decl: self.type_needs_shape_assertions(decl.type), domain.type_declarations) + + for type_declaration in declarations_to_generate: + for type_member in type_declaration.type_members: + if isinstance(type_member.type, EnumType): + sections.append(self._generate_assertion_for_enum(type_member, type_declaration)) + + if isinstance(type_declaration.type, ObjectType): + sections.append(self._generate_assertion_for_object_declaration(type_declaration)) + if Generator.type_needs_runtime_casts(type_declaration.type): + sections.append(self._generate_runtime_cast_for_object_declaration(type_declaration)) + + return '\n\n'.join(sections) + + def _generate_runtime_cast_for_object_declaration(self, object_declaration): + args = { + 'objectType': CppGenerator.cpp_protocol_type_for_type(object_declaration.type) + } + return Template(CppTemplates.ProtocolObjectRuntimeCast).substitute(None, **args) + + def _generate_assertion_for_object_declaration(self, object_declaration): + required_members = filter(lambda member: not member.is_optional, object_declaration.type_members) + optional_members = filter(lambda member: member.is_optional, object_declaration.type_members) + should_count_properties = not Generator.type_has_open_fields(object_declaration.type) + lines = [] + + lines.append('#if !ASSERT_DISABLED') + lines.append('void BindingTraits<%s>::assertValueHasExpectedType(Inspector::InspectorValue* value)' % (CppGenerator.cpp_protocol_type_for_type(object_declaration.type))) + lines.append("""{ + ASSERT_ARG(value, value); + RefPtr<InspectorObject> object; + bool castSucceeded = value->asObject(object); + ASSERT_UNUSED(castSucceeded, castSucceeded);""") + for type_member in required_members: + args = { + 'memberName': type_member.member_name, + 'assertMethod': CppGenerator.cpp_assertion_method_for_type_member(type_member, object_declaration) + } + + lines.append(""" { + InspectorObject::iterator %(memberName)sPos = object->find(ASCIILiteral("%(memberName)s")); + ASSERT(%(memberName)sPos != object->end()); + %(assertMethod)s(%(memberName)sPos->value.get()); + }""" % args) + + if should_count_properties: + lines.append('') + lines.append(' int foundPropertiesCount = %s;' % len(required_members)) + + for type_member in optional_members: + args = { + 'memberName': type_member.member_name, + 'assertMethod': CppGenerator.cpp_assertion_method_for_type_member(type_member, object_declaration) + } + + lines.append(""" { + InspectorObject::iterator %(memberName)sPos = object->find(ASCIILiteral("%(memberName)s")); + if (%(memberName)sPos != object->end()) { + %(assertMethod)s(%(memberName)sPos->value.get());""" % args) + + if should_count_properties: + lines.append(' ++foundPropertiesCount;') + lines.append(' }') + lines.append(' }') + + if should_count_properties: + lines.append(' if (foundPropertiesCount != object->size())') + lines.append(' FATAL("Unexpected properties in object: %s\\n", object->toJSONString().ascii().data());') + lines.append('}') + lines.append('#endif // !ASSERT_DISABLED') + return '\n'.join(lines) + + def _generate_assertion_for_enum(self, enum_member, object_declaration): + lines = [] + lines.append('#if !ASSERT_DISABLED') + lines.append('void %s(Inspector::InspectorValue* value)' % CppGenerator.cpp_assertion_method_for_type_member(enum_member, object_declaration)) + lines.append('{') + lines.append(' ASSERT_ARG(value, value);') + lines.append(' String result;') + lines.append(' bool castSucceeded = value->asString(result);') + lines.append(' ASSERT(castSucceeded);') + + assert_condition = ' || '.join(['result == "%s"' % enum_value for enum_value in enum_member.type.enum_values()]) + lines.append(' ASSERT(%s);' % assert_condition) + lines.append('}') + lines.append('#endif // !ASSERT_DISABLED') + + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generate_js_backend_commands.py b/inspector/scripts/codegen/generate_js_backend_commands.py new file mode 100755 index 0000000..3392c78 --- /dev/null +++ b/inspector/scripts/codegen/generate_js_backend_commands.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator, ucfirst +from generator_templates import GeneratorTemplates as Templates +from models import EnumType + +log = logging.getLogger('global') + + +class JSBackendCommandsGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return "InspectorBackendCommands.js" + + def domains_to_generate(self): + def should_generate_domain(domain): + domain_enum_types = filter(lambda declaration: isinstance(declaration.type, EnumType), domain.type_declarations) + return len(domain.commands) > 0 or len(domain.events) > 0 or len(domain_enum_types) > 0 + + return filter(should_generate_domain, Generator.domains_to_generate(self)) + + def generate_output(self): + sections = [] + sections.append(self.generate_license()) + sections.extend(map(self.generate_domain, self.domains_to_generate())) + return "\n\n".join(sections) + + def generate_domain(self, domain): + lines = [] + args = { + 'domain': domain.domain_name + } + + lines.append('// %(domain)s.' % args) + + has_async_commands = any(map(lambda command: command.is_async, domain.commands)) + if len(domain.events) > 0 or has_async_commands: + lines.append('InspectorBackend.register%(domain)sDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "%(domain)s");' % args) + + for declaration in domain.type_declarations: + if declaration.type.is_enum(): + enum_args = { + 'domain': domain.domain_name, + 'enumName': declaration.type_name, + 'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in declaration.type.enum_values()]) + } + lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args) + + def is_anonymous_enum_member(type_member): + return isinstance(type_member.type, EnumType) and type_member.type.is_anonymous + + for _member in filter(is_anonymous_enum_member, declaration.type_members): + enum_args = { + 'domain': domain.domain_name, + 'enumName': '%s%s' % (declaration.type_name, ucfirst(_member.member_name)), + 'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in _member.type.enum_values()]) + } + lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args) + + def is_anonymous_enum_param(param): + return isinstance(param.type, EnumType) and param.type.is_anonymous + + for event in domain.events: + for param in filter(is_anonymous_enum_param, event.event_parameters): + enum_args = { + 'domain': domain.domain_name, + 'enumName': '%s%s' % (ucfirst(event.event_name), ucfirst(param.parameter_name)), + 'enumMap': ", ".join(['%s: "%s"' % (Generator.stylized_name_for_enum_value(enum_value), enum_value) for enum_value in param.type.enum_values()]) + } + lines.append('InspectorBackend.registerEnum("%(domain)s.%(enumName)s", {%(enumMap)s});' % enum_args) + + event_args = { + 'domain': domain.domain_name, + 'eventName': event.event_name, + 'params': ", ".join(['"%s"' % parameter.parameter_name for parameter in event.event_parameters]) + } + lines.append('InspectorBackend.registerEvent("%(domain)s.%(eventName)s", [%(params)s]);' % event_args) + + for command in domain.commands: + def generate_parameter_object(parameter): + optional_string = "true" if parameter.is_optional else "false" + pairs = [] + pairs.append('"name": "%s"' % parameter.parameter_name) + pairs.append('"type": "%s"' % Generator.js_name_for_parameter_type(parameter.type)) + pairs.append('"optional": %s' % optional_string) + return "{%s}" % ", ".join(pairs) + + command_args = { + 'domain': domain.domain_name, + 'commandName': command.command_name, + 'callParams': ", ".join([generate_parameter_object(parameter) for parameter in command.call_parameters]), + 'returnParams': ", ".join(['"%s"' % parameter.parameter_name for parameter in command.return_parameters]), + } + lines.append('InspectorBackend.registerCommand("%(domain)s.%(commandName)s", [%(callParams)s], [%(returnParams)s]);' % command_args) + + if domain.commands or domain.events: + activate_args = { + 'domain': domain.domain_name, + 'availability': domain.availability, + } + if domain.availability: + lines.append('InspectorBackend.activateDomain("%(domain)s", "%(availability)s");' % activate_args) + else: + lines.append('InspectorBackend.activateDomain("%(domain)s");' % activate_args) + + return "\n".join(lines) diff --git a/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py b/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py new file mode 100755 index 0000000..29b38e8 --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_backend_dispatcher_header.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +import re +from string import Template + +from cpp_generator import CppGenerator +from generator import Generator +from models import Frameworks +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +class ObjCBackendDispatcherHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sBackendDispatchers.h' % ObjCGenerator.OBJC_PREFIX + + def domains_to_generate(self): + return filter(ObjCGenerator.should_generate_domain_command_handler_filter(self.model()), Generator.domains_to_generate(self)) + + def generate_output(self): + headers = [ + '<JavaScriptCore/InspectorAlternateBackendDispatchers.h>', + '<wtf/RetainPtr.h>', + ] + + header_args = { + 'headerGuardString': re.sub('\W+', '_', self.output_filename()), + 'includes': '\n'.join(['#include ' + header for header in headers]), + 'forwardDeclarations': self._generate_objc_forward_declarations(), + } + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.BackendDispatcherHeaderPrelude).substitute(None, **header_args)) + sections.extend(map(self._generate_objc_handler_declarations_for_domain, domains)) + sections.append(Template(ObjCTemplates.BackendDispatcherHeaderPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_objc_forward_declarations(self): + lines = [] + for domain in self.domains_to_generate(): + if domain.commands: + lines.append('@protocol %s%sDomainHandler;' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name)) + return '\n'.join(lines) + + def _generate_objc_handler_declarations_for_domain(self, domain): + if not domain.commands: + return '' + + command_declarations = [] + for command in domain.commands: + command_declarations.append(self._generate_objc_handler_declaration_for_command(command)) + + handler_args = { + 'domainName': domain.domain_name, + 'commandDeclarations': '\n'.join(command_declarations), + 'objcPrefix': ObjCGenerator.OBJC_PREFIX, + } + + return self.wrap_with_guard_for_domain(domain, Template(ObjCTemplates.BackendDispatcherHeaderDomainHandlerObjCDeclaration).substitute(None, **handler_args)) + + def _generate_objc_handler_declaration_for_command(self, command): + lines = [] + parameters = ['long callId'] + for _parameter in command.call_parameters: + parameters.append('%s in_%s' % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(_parameter), _parameter.parameter_name)) + + command_args = { + 'commandName': command.command_name, + 'parameters': ', '.join(parameters), + } + lines.append(' virtual void %(commandName)s(%(parameters)s) override;' % command_args) + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py b/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py new file mode 100755 index 0000000..27bdd4a --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_backend_dispatcher_implementation.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +import re +from string import Template + +from cpp_generator import CppGenerator +from generator import Generator +from models import PrimitiveType, EnumType, AliasedType, Frameworks +from objc_generator import ObjCTypeCategory, ObjCGenerator, join_type_and_name +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +class ObjCConfigurationImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sBackendDispatchers.mm' % ObjCGenerator.OBJC_PREFIX + + def domains_to_generate(self): + return filter(ObjCGenerator.should_generate_domain_command_handler_filter(self.model()), Generator.domains_to_generate(self)) + + def generate_output(self): + secondary_headers = [ + '"%sInternal.h"' % ObjCGenerator.OBJC_PREFIX, + '"%sEnumConversionHelpers.h"' % ObjCGenerator.OBJC_PREFIX, + '<JavaScriptCore/InspectorFrontendChannel.h>', + '<JavaScriptCore/InspectorValues.h>', + ] + + header_args = { + 'primaryInclude': '"%sBackendDispatchers.h"' % ObjCGenerator.OBJC_PREFIX, + 'secondaryIncludes': '\n'.join(['#include %s' % header for header in secondary_headers]), + } + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.BackendDispatcherImplementationPrelude).substitute(None, **header_args)) + sections.extend(map(self._generate_handler_implementation_for_domain, domains)) + sections.append(Template(ObjCTemplates.BackendDispatcherImplementationPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_handler_implementation_for_domain(self, domain): + if not domain.commands: + return '' + + command_declarations = [] + for command in domain.commands: + command_declarations.append(self._generate_handler_implementation_for_command(domain, command)) + + return '\n'.join(command_declarations) + + def _generate_handler_implementation_for_command(self, domain, command): + lines = [] + parameters = ['long callId'] + for parameter in command.call_parameters: + parameters.append('%s in_%s' % (CppGenerator.cpp_type_for_unchecked_formal_in_parameter(parameter), parameter.parameter_name)) + + command_args = { + 'domainName': domain.domain_name, + 'commandName': command.command_name, + 'parameters': ', '.join(parameters), + 'successCallback': self._generate_success_block_for_command(domain, command), + 'conversions': self._generate_conversions_for_command(domain, command), + 'invocation': self._generate_invocation_for_command(domain, command), + } + + return self.wrap_with_guard_for_domain(domain, Template(ObjCTemplates.BackendDispatcherHeaderDomainHandlerImplementation).substitute(None, **command_args)) + + def _generate_success_block_for_command(self, domain, command): + lines = [] + + if command.return_parameters: + success_block_parameters = [] + for parameter in command.return_parameters: + objc_type = ObjCGenerator.objc_type_for_param(domain, command.command_name, parameter) + var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name) + success_block_parameters.append(join_type_and_name(objc_type, var_name)) + lines.append(' id successCallback = ^(%s) {' % ', '.join(success_block_parameters)) + else: + lines.append(' id successCallback = ^{') + + if command.return_parameters: + lines.append(' Ref<InspectorObject> resultObject = InspectorObject::create();') + + required_pointer_parameters = filter(lambda parameter: not parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), command.return_parameters) + for parameter in required_pointer_parameters: + var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name) + lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(%s, @"%s");' % (var_name, var_name)) + objc_array_class = ObjCGenerator.objc_class_for_array_type(parameter.type) + if objc_array_class and objc_array_class.startswith(ObjCGenerator.OBJC_PREFIX): + lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class)) + + optional_pointer_parameters = filter(lambda parameter: parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), command.return_parameters) + for parameter in optional_pointer_parameters: + var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name) + lines.append(' THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(%s, @"%s");' % (var_name, var_name)) + objc_array_class = ObjCGenerator.objc_class_for_array_type(parameter.type) + if objc_array_class and objc_array_class.startswith(ObjCGenerator.OBJC_PREFIX): + lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_OPTIONAL_ARRAY(%s, [%s class]);' % (var_name, objc_array_class)) + + for parameter in command.return_parameters: + keyed_set_method = CppGenerator.cpp_setter_method_for_type(parameter.type) + var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name) + var_expression = '*%s' % var_name if parameter.is_optional else var_name + export_expression = ObjCGenerator.objc_protocol_export_expression_for_variable(parameter.type, var_expression) + if not parameter.is_optional: + lines.append(' resultObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression)) + else: + lines.append(' if (%s)' % var_name) + lines.append(' resultObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression)) + lines.append(' backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String());') + else: + lines.append(' backendDispatcher()->sendResponse(callId, InspectorObject::create(), String());') + + lines.append(' };') + return '\n'.join(lines) + + def _generate_conversions_for_command(self, domain, command): + lines = [] + if command.call_parameters: + lines.append('') + + def in_param_expression(param_name, parameter): + _type = parameter.type + if isinstance(_type, AliasedType): + _type = _type.aliased_type # Fall through to enum or primitive. + if isinstance(_type, EnumType): + _type = _type.primitive_type # Fall through to primitive. + if isinstance(_type, PrimitiveType): + if _type.raw_name() in ['array', 'any', 'object']: + return '&%s' % param_name if not parameter.is_optional else param_name + return '*%s' % param_name if parameter.is_optional else param_name + return '&%s' % param_name if not parameter.is_optional else param_name + + for parameter in command.call_parameters: + in_param_name = 'in_%s' % parameter.parameter_name + objc_in_param_name = 'o_%s' % in_param_name + objc_type = ObjCGenerator.objc_type_for_param(domain, command.command_name, parameter, False) + param_expression = in_param_expression(in_param_name, parameter) + import_expression = ObjCGenerator.objc_protocol_import_expression_for_parameter(param_expression, domain, command.command_name, parameter) + if not parameter.is_optional: + lines.append(' %s = %s;' % (join_type_and_name(objc_type, objc_in_param_name), import_expression)) + else: + lines.append(' %s;' % join_type_and_name(objc_type, objc_in_param_name)) + lines.append(' if (%s)' % in_param_name) + lines.append(' %s = %s;' % (objc_in_param_name, import_expression)) + + if lines: + lines.append('') + return '\n'.join(lines) + + def _generate_invocation_for_command(self, domain, command): + pairs = [] + pairs.append('WithErrorCallback:errorCallback') + pairs.append('successCallback:successCallback') + for parameter in command.call_parameters: + in_param_name = 'in_%s' % parameter.parameter_name + objc_in_param_name = 'o_%s' % in_param_name + if not parameter.is_optional: + pairs.append('%s:%s' % (parameter.parameter_name, objc_in_param_name)) + else: + optional_expression = '(%s ? &%s : nil)' % (in_param_name, objc_in_param_name) + pairs.append('%s:%s' % (parameter.parameter_name, optional_expression)) + return ' [m_delegate %s%s];' % (command.command_name, ' '.join(pairs)) diff --git a/inspector/scripts/codegen/generate_objc_configuration_header.py b/inspector/scripts/codegen/generate_objc_configuration_header.py new file mode 100755 index 0000000..2002227 --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_configuration_header.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +class ObjCConfigurationHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sConfiguration.h' % ObjCGenerator.OBJC_PREFIX + + def generate_output(self): + headers = [ + '"%s.h"' % ObjCGenerator.OBJC_PREFIX, + ] + + header_args = { + 'includes': '\n'.join(['#import ' + header for header in headers]), + } + + self._command_filter = ObjCGenerator.should_generate_domain_command_handler_filter(self.model()) + self._event_filter = ObjCGenerator.should_generate_domain_event_dispatcher_filter(self.model()) + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.GenericHeaderPrelude).substitute(None, **header_args)) + sections.append(self._generate_configuration_interface_for_domains(domains)) + sections.append(Template(ObjCTemplates.GenericHeaderPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_configuration_interface_for_domains(self, domains): + lines = [] + lines.append('__attribute__((visibility ("default")))') + lines.append('@interface RWIProtocolConfiguration : NSObject') + for domain in domains: + lines.extend(self._generate_properties_for_domain(domain)) + lines.append('@end') + return '\n'.join(lines) + + def _generate_properties_for_domain(self, domain): + property_args = { + 'objcPrefix': ObjCGenerator.OBJC_PREFIX, + 'domainName': domain.domain_name, + 'variableNamePrefix': ObjCGenerator.variable_name_prefix_for_domain(domain), + } + + lines = [] + if domain.commands and self._command_filter(domain): + lines.append(Template(ObjCTemplates.ConfigurationCommandProperty).substitute(None, **property_args)) + if domain.events and self._event_filter(domain): + lines.append(Template(ObjCTemplates.ConfigurationEventProperty).substitute(None, **property_args)) + return lines diff --git a/inspector/scripts/codegen/generate_objc_configuration_implementation.py b/inspector/scripts/codegen/generate_objc_configuration_implementation.py new file mode 100755 index 0000000..53205cb --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_configuration_implementation.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +class ObjCBackendDispatcherImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sConfiguration.mm' % ObjCGenerator.OBJC_PREFIX + + def generate_output(self): + secondary_headers = [ + '"%sInternal.h"' % ObjCGenerator.OBJC_PREFIX, + '"%sBackendDispatchers.h"' % ObjCGenerator.OBJC_PREFIX, + '<JavaScriptCore/AlternateDispatchableAgent.h>', + '<JavaScriptCore/AugmentableInspectorController.h>', + '<JavaScriptCore/InspectorAlternateBackendDispatchers.h>', + '<JavaScriptCore/InspectorBackendDispatchers.h>', + ] + + header_args = { + 'primaryInclude': '"%sConfiguration.h"' % ObjCGenerator.OBJC_PREFIX, + 'secondaryIncludes': '\n'.join(['#import %s' % header for header in secondary_headers]), + } + + self._command_filter = ObjCGenerator.should_generate_domain_command_handler_filter(self.model()) + self._event_filter = ObjCGenerator.should_generate_domain_event_dispatcher_filter(self.model()) + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args)) + sections.append(self._generate_configuration_implementation_for_domains(domains)) + sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_configuration_implementation_for_domains(self, domains): + lines = [] + lines.append('@implementation RWIProtocolConfiguration') + lines.append('{') + lines.append(' AugmentableInspectorController* _controller;') + lines.extend(self._generate_ivars(domains)) + lines.append('}') + lines.append('') + lines.append('- (instancetype)initWithController:(AugmentableInspectorController*)controller') + lines.append('{') + lines.append(' self = [super init];') + lines.append(' if (!self)') + lines.append(' return nil;') + lines.append(' ASSERT(controller);') + lines.append(' _controller = controller;') + lines.append(' return self;') + lines.append('}') + lines.append('') + lines.extend(self._generate_dealloc(domains)) + lines.append('') + for domain in domains: + if domain.commands and self._command_filter(domain): + lines.append(self._generate_handler_setter_for_domain(domain)) + lines.append('') + if domain.events and self._event_filter(domain): + lines.append(self._generate_event_dispatcher_getter_for_domain(domain)) + lines.append('') + lines.append('@end') + return '\n'.join(lines) + + def _generate_ivars(self, domains): + lines = [] + for domain in domains: + if domain.commands and self._command_filter(domain): + objc_class_name = '%s%sDomainHandler' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name) + ivar_name = '_%sHandler' % ObjCGenerator.variable_name_prefix_for_domain(domain) + lines.append(' id<%s> %s;' % (objc_class_name, ivar_name)) + if domain.events and self._event_filter(domain): + objc_class_name = '%s%sDomainEventDispatcher' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name) + ivar_name = '_%sEventDispatcher' % ObjCGenerator.variable_name_prefix_for_domain(domain) + lines.append(' %s *%s;' % (objc_class_name, ivar_name)) + return lines + + def _generate_dealloc(self, domains): + lines = [] + lines.append('- (void)dealloc') + lines.append('{') + for domain in domains: + if domain.commands and self._command_filter(domain): + lines.append(' [_%sHandler release];' % ObjCGenerator.variable_name_prefix_for_domain(domain)) + if domain.events and self._event_filter(domain): + lines.append(' [_%sEventDispatcher release];' % ObjCGenerator.variable_name_prefix_for_domain(domain)) + lines.append(' [super dealloc];') + lines.append('}') + return lines + + def _generate_handler_setter_for_domain(self, domain): + setter_args = { + 'objcPrefix': ObjCGenerator.OBJC_PREFIX, + 'domainName': domain.domain_name, + 'variableNamePrefix': ObjCGenerator.variable_name_prefix_for_domain(domain), + } + return Template(ObjCTemplates.ConfigurationCommandPropertyImplementation).substitute(None, **setter_args) + + def _generate_event_dispatcher_getter_for_domain(self, domain): + getter_args = { + 'objcPrefix': ObjCGenerator.OBJC_PREFIX, + 'domainName': domain.domain_name, + 'variableNamePrefix': ObjCGenerator.variable_name_prefix_for_domain(domain), + } + return Template(ObjCTemplates.ConfigurationGetterImplementation).substitute(None, **getter_args) + + def _variable_name_prefix_for_domain(self, domain): + domain_name = domain.domain_name + if domain_name.startswith('DOM'): + return 'dom' + domain_name[3:] + if domain_name.startswith('CSS'): + return 'css' + domain_name[3:] + return domain_name[:1].lower() + domain_name[1:] diff --git a/inspector/scripts/codegen/generate_objc_conversion_helpers.py b/inspector/scripts/codegen/generate_objc_conversion_helpers.py new file mode 100755 index 0000000..c31e991 --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_conversion_helpers.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator +from models import EnumType +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +def add_newline(lines): + if lines and lines[-1] == '': + return + lines.append('') + + +class ObjCConversionHelpersGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sEnumConversionHelpers.h' % ObjCGenerator.OBJC_PREFIX + + def domains_to_generate(self): + return filter(ObjCGenerator.should_generate_domain_types_filter(self.model()), Generator.domains_to_generate(self)) + + def generate_output(self): + headers = [ + '"%sArrayConversionHelpers.h"' % ObjCGenerator.OBJC_PREFIX, + ] + + header_args = { + 'includes': '\n'.join(['#import ' + header for header in headers]), + } + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.ConversionHelpersPrelude).substitute(None, **header_args)) + sections.append(Template(ObjCTemplates.ConversionHelpersStandard).substitute(None)) + sections.extend(map(self._generate_enum_conversion_functions, domains)) + sections.append(Template(ObjCTemplates.ConversionHelpersPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_enum_conversion_functions(self, domain): + lines = [] + + # Type enums and member enums. + for declaration in domain.type_declarations: + if isinstance(declaration.type, EnumType): + add_newline(lines) + lines.append(self._generate_anonymous_enum_conversion_for_declaration(domain, declaration)) + else: + for member in declaration.type_members: + if (isinstance(member.type, EnumType) and member.type.is_anonymous): + add_newline(lines) + lines.append(self._generate_anonymous_enum_conversion_for_member(domain, declaration, member)) + + # Anonymous command enums. + for command in domain.commands: + for parameter in command.call_parameters: + if (isinstance(parameter.type, EnumType) and parameter.type.is_anonymous): + add_newline(lines) + lines.append(self._generate_anonymous_enum_conversion_for_parameter(domain, command.command_name, parameter)) + for parameter in command.return_parameters: + if (isinstance(parameter.type, EnumType) and parameter.type.is_anonymous): + add_newline(lines) + lines.append(self._generate_anonymous_enum_conversion_for_parameter(domain, command.command_name, parameter)) + + # Anonymous event enums. + for event in domain.events: + for parameter in event.event_parameters: + if (isinstance(parameter.type, EnumType) and parameter.type.is_anonymous): + add_newline(lines) + lines.append(self._generate_anonymous_enum_conversion_for_parameter(domain, event.event_name, parameter)) + + return '\n'.join(lines) + + def _generate_anonymous_enum_conversion_for_declaration(self, domain, declaration): + objc_enum_name = ObjCGenerator.objc_enum_name_for_anonymous_enum_declaration(declaration) + enum_values = declaration.type.enum_values() + lines = [] + lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values)) + lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values)) + return '\n\n'.join(lines) + + def _generate_anonymous_enum_conversion_for_member(self, domain, declaration, member): + objc_enum_name = ObjCGenerator.objc_enum_name_for_anonymous_enum_member(declaration, member) + enum_values = member.type.enum_values() + lines = [] + lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values)) + lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values)) + return '\n\n'.join(lines) + + def _generate_anonymous_enum_conversion_for_parameter(self, domain, event_or_command_name, parameter): + objc_enum_name = ObjCGenerator.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter) + enum_values = parameter.type.enum_values() + lines = [] + lines.append(self._generate_enum_objc_to_protocol_string(objc_enum_name, enum_values)) + lines.append(self._generate_enum_from_protocol_string(objc_enum_name, enum_values)) + return '\n\n'.join(lines) + + def _generate_enum_objc_to_protocol_string(self, objc_enum_name, enum_values): + lines = [] + lines.append('inline String toProtocolString(%s value)' % objc_enum_name) + lines.append('{') + lines.append(' switch(value) {') + for enum_value in enum_values: + lines.append(' case %s%s:' % (objc_enum_name, Generator.stylized_name_for_enum_value(enum_value))) + lines.append(' return ASCIILiteral("%s");' % enum_value) + lines.append(' }') + lines.append('}') + return '\n'.join(lines) + + def _generate_enum_from_protocol_string(self, objc_enum_name, enum_values): + lines = [] + lines.append('template<>') + lines.append('inline %s fromProtocolString(const String& value)' % objc_enum_name) + lines.append('{') + for enum_value in enum_values: + lines.append(' if (value == "%s")' % enum_value) + lines.append(' return %s%s;' % (objc_enum_name, Generator.stylized_name_for_enum_value(enum_value))) + lines.append(' ASSERT_NOT_REACHED();') + lines.append(' return %s%s;' % (objc_enum_name, Generator.stylized_name_for_enum_value(enum_values[0]))) + lines.append('}') + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py b/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py new file mode 100755 index 0000000..fb2de4f --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_frontend_dispatcher_implementation.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from cpp_generator import CppGenerator +from generator import Generator, ucfirst +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +class ObjCFrontendDispatcherImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sEventDispatchers.mm' % ObjCGenerator.OBJC_PREFIX + + def domains_to_generate(self): + return filter(ObjCGenerator.should_generate_domain_event_dispatcher_filter(self.model()), Generator.domains_to_generate(self)) + + def generate_output(self): + secondary_headers = [ + '"%sEnumConversionHelpers.h"' % ObjCGenerator.OBJC_PREFIX, + '<JavaScriptCore/InspectorFrontendChannel.h>', + '<JavaScriptCore/InspectorValues.h>', + ] + + header_args = { + 'primaryInclude': '"%sInternal.h"' % ObjCGenerator.OBJC_PREFIX, + 'secondaryIncludes': '\n'.join(['#import %s' % header for header in secondary_headers]), + } + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args)) + sections.extend(map(self._generate_event_dispatcher_implementations, domains)) + sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_event_dispatcher_implementations(self, domain): + if not domain.events: + return '' + + lines = [] + objc_name = '%s%sDomainEventDispatcher' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name) + lines.append('@implementation %s' % objc_name) + lines.append('{') + lines.append(' AugmentableInspectorController* _controller;') + lines.append('}') + lines.append('') + lines.append('- (instancetype)initWithController:(AugmentableInspectorController*)controller;') + lines.append('{') + lines.append(' self = [super init];') + lines.append(' if (!self)') + lines.append(' return nil;') + lines.append(' ASSERT(controller);') + lines.append(' _controller = controller;') + lines.append(' return self;') + lines.append('}') + lines.append('') + for event in domain.events: + lines.append(self._generate_event(domain, event)) + lines.append('') + lines.append('@end') + return '\n'.join(lines) + + def _generate_event(self, domain, event): + lines = [] + lines.append(self._generate_event_signature(domain, event)) + lines.append('{') + lines.append(' FrontendChannel* frontendChannel = _controller->frontendChannel();') + lines.append(' if (!frontendChannel)') + lines.append(' return;') + lines.append('') + + required_pointer_parameters = filter(lambda parameter: not parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), event.event_parameters) + for parameter in required_pointer_parameters: + var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name) + lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(%s, @"%s");' % (var_name, var_name)) + objc_array_class = ObjCGenerator.objc_class_for_array_type(parameter.type) + if objc_array_class and objc_array_class.startswith(ObjCGenerator.OBJC_PREFIX): + lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class)) + + optional_pointer_parameters = filter(lambda parameter: parameter.is_optional and ObjCGenerator.is_type_objc_pointer_type(parameter.type), event.event_parameters) + for parameter in optional_pointer_parameters: + var_name = ObjCGenerator.identifier_to_objc_identifier(parameter.parameter_name) + lines.append(' THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(%s, @"%s");' % (var_name, var_name)) + objc_array_class = ObjCGenerator.objc_class_for_array_type(parameter.type) + if objc_array_class and objc_array_class.startswith(ObjCGenerator.OBJC_PREFIX): + lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_OPTIONAL_ARRAY(%s, [%s class]);' % (var_name, objc_array_class)) + + if required_pointer_parameters or optional_pointer_parameters: + lines.append('') + + lines.append(' Ref<InspectorObject> jsonMessage = InspectorObject::create();') + lines.append(' jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("%s.%s"));' % (domain.domain_name, event.event_name)) + if event.event_parameters: + lines.extend(self._generate_event_out_parameters(domain, event)) + lines.append(' frontendChannel->sendMessageToFrontend(jsonMessage->toJSONString());') + lines.append('}') + return '\n'.join(lines) + + def _generate_event_signature(self, domain, event): + if not event.event_parameters: + return '- (void)%s' % event.event_name + pairs = [] + for parameter in event.event_parameters: + param_name = parameter.parameter_name + pairs.append('%s:(%s)%s' % (param_name, ObjCGenerator.objc_type_for_param(domain, event.event_name, parameter), param_name)) + pairs[0] = ucfirst(pairs[0]) + return '- (void)%sWith%s' % (event.event_name, ' '.join(pairs)) + + def _generate_event_out_parameters(self, domain, event): + lines = [] + lines.append(' Ref<InspectorObject> paramsObject = InspectorObject::create();') + for parameter in event.event_parameters: + keyed_set_method = CppGenerator.cpp_setter_method_for_type(parameter.type) + var_name = parameter.parameter_name + safe_var_name = '(*%s)' % var_name if parameter.is_optional else var_name + export_expression = ObjCGenerator.objc_protocol_export_expression_for_variable(parameter.type, safe_var_name) + if not parameter.is_optional: + lines.append(' paramsObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression)) + else: + lines.append(' if (%s)' % (parameter.parameter_name)) + lines.append(' paramsObject->%s(ASCIILiteral("%s"), %s);' % (keyed_set_method, parameter.parameter_name, export_expression)) + lines.append(' jsonMessage->setObject(ASCIILiteral("params"), WTF::move(paramsObject));') + return lines diff --git a/inspector/scripts/codegen/generate_objc_header.py b/inspector/scripts/codegen/generate_objc_header.py new file mode 100755 index 0000000..1d3751f --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_header.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator, ucfirst +from models import ObjectType, EnumType +from objc_generator import ObjCGenerator, join_type_and_name +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +def add_newline(lines): + if lines and lines[-1] == '': + return + lines.append('') + + +class ObjCHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%s.h' % ObjCGenerator.OBJC_PREFIX + + def generate_output(self): + headers = set([ + '<WebInspector/RWIProtocolJSONObject.h>', + ]) + + header_args = { + 'includes': '\n'.join(['#import ' + header for header in sorted(headers)]), + } + + domains = self.domains_to_generate() + type_domains = filter(ObjCGenerator.should_generate_domain_types_filter(self.model()), domains) + command_domains = filter(ObjCGenerator.should_generate_domain_command_handler_filter(self.model()), domains) + event_domains = filter(ObjCGenerator.should_generate_domain_event_dispatcher_filter(self.model()), domains) + + # FIXME: <https://webkit.org/b/138222> Web Inspector: Reduce unnecessary enums/types generated in ObjC Protocol Interfaces + # Currently we generate enums/types for all types in the type_domains. For the built-in + # JSC domains (Debugger, Runtime) this produces extra unused types. We only need to + # generate these types if they are referenced by the command_domains or event_domains. + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.HeaderPrelude).substitute(None, **header_args)) + sections.append('\n'.join(filter(None, map(self._generate_forward_declarations, type_domains)))) + sections.append('\n'.join(filter(None, map(self._generate_enums, type_domains)))) + sections.append('\n'.join(filter(None, map(self._generate_types, type_domains)))) + sections.append('\n\n'.join(filter(None, map(self._generate_command_protocols, command_domains)))) + sections.append('\n\n'.join(filter(None, map(self._generate_event_interfaces, event_domains)))) + sections.append(Template(ObjCTemplates.HeaderPostlude).substitute(None)) + return '\n\n'.join(sections) + + def _generate_forward_declarations(self, domain): + lines = [] + for declaration in domain.type_declarations: + if (isinstance(declaration.type, ObjectType)): + objc_name = ObjCGenerator.objc_name_for_type(declaration.type) + lines.append('@class %s;' % objc_name) + return '\n'.join(lines) + + def _generate_enums(self, domain): + lines = [] + + # Type enums and member enums. + for declaration in domain.type_declarations: + if isinstance(declaration.type, EnumType): + add_newline(lines) + lines.append(self._generate_anonymous_enum_for_declaration(domain, declaration)) + else: + for member in declaration.type_members: + if isinstance(member.type, EnumType) and member.type.is_anonymous: + add_newline(lines) + lines.append(self._generate_anonymous_enum_for_member(domain, declaration, member)) + + # Anonymous command enums. + for command in domain.commands: + for parameter in command.call_parameters: + if isinstance(parameter.type, EnumType) and parameter.type.is_anonymous: + add_newline(lines) + lines.append(self._generate_anonymous_enum_for_parameter(domain, command.command_name, parameter)) + for parameter in command.return_parameters: + if isinstance(parameter.type, EnumType) and parameter.type.is_anonymous: + add_newline(lines) + lines.append(self._generate_anonymous_enum_for_parameter(domain, command.command_name, parameter)) + + # Anonymous event enums. + for event in domain.events: + for parameter in event.event_parameters: + if isinstance(parameter.type, EnumType) and parameter.type.is_anonymous: + add_newline(lines) + lines.append(self._generate_anonymous_enum_for_parameter(domain, event.event_name, parameter)) + + return '\n'.join(lines) + + def _generate_types(self, domain): + lines = [] + # Type interfaces. + for declaration in domain.type_declarations: + if isinstance(declaration.type, ObjectType): + add_newline(lines) + lines.append(self._generate_type_interface(domain, declaration)) + return '\n'.join(lines) + + def _generate_anonymous_enum_for_declaration(self, domain, declaration): + objc_enum_name = ObjCGenerator.objc_enum_name_for_anonymous_enum_declaration(declaration) + return self._generate_enum(objc_enum_name, declaration.type.enum_values()) + + def _generate_anonymous_enum_for_member(self, domain, declaration, member): + objc_enum_name = ObjCGenerator.objc_enum_name_for_anonymous_enum_member(declaration, member) + return self._generate_enum(objc_enum_name, member.type.enum_values()) + + def _generate_anonymous_enum_for_parameter(self, domain, event_or_command_name, parameter): + objc_enum_name = ObjCGenerator.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter) + return self._generate_enum(objc_enum_name, parameter.type.enum_values()) + + def _generate_enum(self, enum_name, enum_values): + lines = [] + lines.append('typedef NS_ENUM(NSInteger, %s) {' % enum_name) + for enum_value in enum_values: + lines.append(' %s%s,' % (enum_name, Generator.stylized_name_for_enum_value(enum_value))) + lines.append('};') + return '\n'.join(lines) + + def _generate_type_interface(self, domain, declaration): + lines = [] + objc_name = ObjCGenerator.objc_name_for_type(declaration.type) + lines.append('__attribute__((visibility ("default")))') + lines.append('@interface %s : %s' % (objc_name, ObjCGenerator.OBJC_JSON_OBJECT_BASE)) + required_members = filter(lambda member: not member.is_optional, declaration.type_members) + optional_members = filter(lambda member: member.is_optional, declaration.type_members) + if required_members: + lines.append(self._generate_init_method_for_required_members(domain, declaration, required_members)) + for member in required_members: + lines.append('/* required */ ' + self._generate_member_property(declaration, member)) + for member in optional_members: + lines.append('/* optional */ ' + self._generate_member_property(declaration, member)) + lines.append('@end') + return '\n'.join(lines) + + def _generate_init_method_for_required_members(self, domain, declaration, required_members): + pairs = [] + for member in required_members: + objc_type = ObjCGenerator.objc_type_for_member(declaration, member) + var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name) + pairs.append('%s:(%s)%s' % (var_name, objc_type, var_name)) + pairs[0] = ucfirst(pairs[0]) + return '- (instancetype)initWith%s;' % ' '.join(pairs) + + def _generate_member_property(self, declaration, member): + accessor_type = ObjCGenerator.objc_accessor_type_for_member(member) + objc_type = ObjCGenerator.objc_type_for_member(declaration, member) + return '@property (nonatomic, %s) %s;' % (accessor_type, join_type_and_name(objc_type, ObjCGenerator.identifier_to_objc_identifier(member.member_name))) + + def _generate_command_protocols(self, domain): + lines = [] + if domain.commands: + objc_name = '%s%sDomainHandler' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name) + lines.append('@protocol %s <NSObject>' % objc_name) + lines.append('@required') + for command in domain.commands: + lines.append(self._generate_single_command_protocol(domain, command)) + lines.append('@end') + return '\n'.join(lines) + + def _generate_single_command_protocol(self, domain, command): + pairs = [] + pairs.append('ErrorCallback:(void(^)(NSString *error))errorCallback') + pairs.append('successCallback:(%s)successCallback' % self._callback_block_for_command(domain, command)) + for parameter in command.call_parameters: + param_name = parameter.parameter_name + pairs.append('%s:(%s)%s' % (param_name, ObjCGenerator.objc_type_for_param(domain, command.command_name, parameter), param_name)) + return '- (void)%sWith%s;' % (command.command_name, ' '.join(pairs)) + + def _callback_block_for_command(self, domain, command): + pairs = [] + for parameter in command.return_parameters: + pairs.append(join_type_and_name(ObjCGenerator.objc_type_for_param(domain, command.command_name, parameter), parameter.parameter_name)) + return 'void(^)(%s)' % ', '.join(pairs) + + def _generate_event_interfaces(self, domain): + lines = [] + if domain.events: + objc_name = '%s%sDomainEventDispatcher' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name) + lines.append('__attribute__((visibility ("default")))') + lines.append('@interface %s : NSObject' % objc_name) + for event in domain.events: + lines.append(self._generate_single_event_interface(domain, event)) + lines.append('@end') + return '\n'.join(lines) + + def _generate_single_event_interface(self, domain, event): + if not event.event_parameters: + return '- (void)%s;' % event.event_name + pairs = [] + for parameter in event.event_parameters: + param_name = parameter.parameter_name + pairs.append('%s:(%s)%s' % (param_name, ObjCGenerator.objc_type_for_param(domain, event.event_name, parameter), param_name)) + pairs[0] = ucfirst(pairs[0]) + return '- (void)%sWith%s;' % (event.event_name, ' '.join(pairs)) diff --git a/inspector/scripts/codegen/generate_objc_internal_header.py b/inspector/scripts/codegen/generate_objc_internal_header.py new file mode 100755 index 0000000..2501ad3 --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_internal_header.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator, ucfirst +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +class ObjCInternalHeaderGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sInternal.h' % ObjCGenerator.OBJC_PREFIX + + def generate_output(self): + headers = set([ + '"%s.h"' % ObjCGenerator.OBJC_PREFIX, + '"RWIProtocolJSONObjectInternal.h"', + '<JavaScriptCore/InspectorValues.h>', + '<JavaScriptCore/AugmentableInspectorController.h>', + ]) + + header_args = { + 'includes': '\n'.join(['#import ' + header for header in sorted(headers)]), + } + + domains = self.domains_to_generate() + event_domains = filter(ObjCGenerator.should_generate_domain_event_dispatcher_filter(self.model()), domains) + + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.GenericHeaderPrelude).substitute(None, **header_args)) + sections.append('\n\n'.join(filter(None, map(self._generate_event_dispatcher_private_interfaces, event_domains)))) + sections.append(Template(ObjCTemplates.GenericHeaderPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def _generate_event_dispatcher_private_interfaces(self, domain): + lines = [] + if domain.events: + objc_name = '%s%sDomainEventDispatcher' % (ObjCGenerator.OBJC_PREFIX, domain.domain_name) + lines.append('@interface %s (Private)' % objc_name) + lines.append('- (instancetype)initWithController:(Inspector::AugmentableInspectorController*)controller;') + lines.append('@end') + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py b/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py new file mode 100755 index 0000000..95b57f6 --- /dev/null +++ b/inspector/scripts/codegen/generate_objc_protocol_types_implementation.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + + +import logging +import string +from string import Template + +from generator import Generator, ucfirst +from models import ObjectType +from objc_generator import ObjCGenerator +from objc_generator_templates import ObjCGeneratorTemplates as ObjCTemplates + +log = logging.getLogger('global') + + +def add_newline(lines): + if lines and lines[-1] == '': + return + lines.append('') + + +class ObjCProtocolTypesImplementationGenerator(Generator): + def __init__(self, model, input_filepath): + Generator.__init__(self, model, input_filepath) + + def output_filename(self): + return '%sTypes.mm' % ObjCGenerator.OBJC_PREFIX + + def domains_to_generate(self): + return filter(ObjCGenerator.should_generate_domain_types_filter(self.model()), Generator.domains_to_generate(self)) + + def generate_output(self): + secondary_headers = [ + '"%sEnumConversionHelpers.h"' % ObjCGenerator.OBJC_PREFIX, + '<JavaScriptCore/InspectorValues.h>', + '<wtf/Assertions.h>', + ] + + header_args = { + 'primaryInclude': '"%sInternal.h"' % ObjCGenerator.OBJC_PREFIX, + 'secondaryIncludes': '\n'.join(['#import %s' % header for header in secondary_headers]), + } + + domains = self.domains_to_generate() + sections = [] + sections.append(self.generate_license()) + sections.append(Template(ObjCTemplates.ImplementationPrelude).substitute(None, **header_args)) + sections.extend(map(self.generate_type_implementations, domains)) + sections.append(Template(ObjCTemplates.ImplementationPostlude).substitute(None, **header_args)) + return '\n\n'.join(sections) + + def generate_type_implementations(self, domain): + lines = [] + for declaration in domain.type_declarations: + if (isinstance(declaration.type, ObjectType)): + add_newline(lines) + lines.append(self.generate_type_implementation(domain, declaration)) + return '\n'.join(lines) + + def generate_type_implementation(self, domain, declaration): + lines = [] + lines.append('@implementation %s' % ObjCGenerator.objc_name_for_type(declaration.type)) + required_members = filter(lambda member: not member.is_optional, declaration.type_members) + if required_members: + lines.append('') + lines.append(self._generate_init_method_for_required_members(domain, declaration, required_members)) + for member in declaration.type_members: + lines.append('') + lines.append(self._generate_setter_for_member(domain, declaration, member)) + lines.append('') + lines.append(self._generate_getter_for_member(domain, declaration, member)) + lines.append('') + lines.append('@end') + return '\n'.join(lines) + + def _generate_init_method_for_required_members(self, domain, declaration, required_members): + pairs = [] + for member in required_members: + objc_type = ObjCGenerator.objc_type_for_member(declaration, member) + var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name) + pairs.append('%s:(%s)%s' % (var_name, objc_type, var_name)) + pairs[0] = ucfirst(pairs[0]) + lines = [] + lines.append('- (instancetype)initWith%s;' % ' '.join(pairs)) + lines.append('{') + lines.append(' self = [super init];') + lines.append(' if (!self)') + lines.append(' return nil;') + lines.append('') + + required_pointer_members = filter(lambda member: ObjCGenerator.is_type_objc_pointer_type(member.type), required_members) + if required_pointer_members: + for member in required_pointer_members: + var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name) + lines.append(' THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(%s, @"%s");' % (var_name, var_name)) + objc_array_class = ObjCGenerator.objc_class_for_array_type(member.type) + if objc_array_class and objc_array_class.startswith(ObjCGenerator.OBJC_PREFIX): + lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class)) + lines.append('') + + for member in required_members: + var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name) + lines.append(' self.%s = %s;' % (var_name, var_name)) + + lines.append('') + lines.append(' return self;') + lines.append('}') + return '\n'.join(lines) + + def _generate_setter_for_member(self, domain, declaration, member): + objc_type = ObjCGenerator.objc_type_for_member(declaration, member) + var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name) + setter_method = ObjCGenerator.objc_setter_method_for_member(declaration, member) + conversion_expression = ObjCGenerator.objc_to_protocol_expression_for_member(declaration, member, var_name) + lines = [] + lines.append('- (void)set%s:(%s)%s' % (ucfirst(var_name), objc_type, var_name)) + lines.append('{') + objc_array_class = ObjCGenerator.objc_class_for_array_type(member.type) + if objc_array_class and objc_array_class.startswith(ObjCGenerator.OBJC_PREFIX): + lines.append(' THROW_EXCEPTION_FOR_BAD_TYPE_IN_ARRAY(%s, [%s class]);' % (var_name, objc_array_class)) + lines.append(' [super %s:%s forKey:@"%s"];' % (setter_method, conversion_expression, member.member_name)) + lines.append('}') + return '\n'.join(lines) + + def _generate_getter_for_member(self, domain, declaration, member): + objc_type = ObjCGenerator.objc_type_for_member(declaration, member) + var_name = ObjCGenerator.identifier_to_objc_identifier(member.member_name) + getter_method = ObjCGenerator.objc_getter_method_for_member(declaration, member) + basic_expression = '[super %s:@"%s"]' % (getter_method, member.member_name) + conversion_expression = ObjCGenerator.protocol_to_objc_expression_for_member(declaration, member, basic_expression) + lines = [] + lines.append('- (%s)%s' % (objc_type, var_name)) + lines.append('{') + lines.append(' return %s;' % conversion_expression) + lines.append('}') + return '\n'.join(lines) diff --git a/inspector/scripts/codegen/generator.py b/inspector/scripts/codegen/generator.py new file mode 100755 index 0000000..a1923fe --- /dev/null +++ b/inspector/scripts/codegen/generator.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +import logging +import os.path +import re +from string import Template + +from generator_templates import GeneratorTemplates as Templates +from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks + +log = logging.getLogger('global') + + +def ucfirst(str): + return str[:1].upper() + str[1:] + +_ALWAYS_UPPERCASED_ENUM_VALUE_SUBSTRINGS = set(['API', 'CSS', 'DOM', 'HTML', 'XHR', 'XML']) + +# These objects are built manually by creating and setting InspectorValues. +# Before sending these over the protocol, their shapes are checked against the specification. +# So, any types referenced by these types require debug-only assertions that check values. +# Calculating necessary assertions is annoying, and adds a lot of complexity to the generator. + +# FIXME: This should be converted into a property in JSON. +_TYPES_NEEDING_RUNTIME_CASTS = set([ + "Runtime.RemoteObject", + "Runtime.PropertyDescriptor", + "Runtime.InternalPropertyDescriptor", + "Runtime.CollectionEntry", + "Debugger.FunctionDetails", + "Debugger.CallFrame", + "Canvas.TraceLog", + "Canvas.ResourceInfo", + "Canvas.ResourceState", + # This should be a temporary hack. TimelineEvent should be created via generated C++ API. + "Timeline.TimelineEvent", + # For testing purposes only. + "Test.TypeNeedingCast" +]) + +# FIXME: This should be converted into a property in JSON. +_TYPES_WITH_OPEN_FIELDS = set([ + "Timeline.TimelineEvent", + # InspectorStyleSheet not only creates this property but wants to read it and modify it. + "CSS.CSSProperty", + # InspectorResourceAgent needs to update mime-type. + "Network.Response", + # For testing purposes only. + "Test.OpenParameterBundle" +]) + + +class Generator: + def __init__(self, model, input_filepath): + self._model = model + self._input_filepath = input_filepath + + def model(self): + return self._model + + def generate_license(self): + return Template(Templates.CopyrightBlock).substitute(None, inputFilename=os.path.basename(self._input_filepath)) + + # These methods are overridden by subclasses. + def non_supplemental_domains(self): + return filter(lambda domain: not domain.is_supplemental, self.model().domains) + + def domains_to_generate(self): + return self.non_supplemental_domains() + + def generate_output(self): + pass + + def output_filename(self): + pass + + def encoding_for_enum_value(self, enum_value): + if not hasattr(self, "_assigned_enum_values"): + self._traverse_and_assign_enum_values() + + return self._enum_value_encodings[enum_value] + + def assigned_enum_values(self): + if not hasattr(self, "_assigned_enum_values"): + self._traverse_and_assign_enum_values() + + return self._assigned_enum_values[:] # Slice. + + @staticmethod + def type_needs_runtime_casts(_type): + return _type.qualified_name() in _TYPES_NEEDING_RUNTIME_CASTS + + @staticmethod + def type_has_open_fields(_type): + return _type.qualified_name() in _TYPES_WITH_OPEN_FIELDS + + def type_needs_shape_assertions(self, _type): + if not hasattr(self, "_types_needing_shape_assertions"): + self.calculate_types_requiring_shape_assertions(self.model().domains) + + return _type in self._types_needing_shape_assertions + + # To restrict the domains over which we compute types needing assertions, call this method + # before generating any output with the desired domains parameter. The computed + # set of types will not be automatically regenerated on subsequent calls to + # Generator.types_needing_shape_assertions(). + def calculate_types_requiring_shape_assertions(self, domains): + domain_names = map(lambda domain: domain.domain_name, domains) + log.debug("> Calculating types that need shape assertions (eligible domains: %s)" % ", ".join(domain_names)) + + # Mutates the passed-in set; this simplifies checks to prevent infinite recursion. + def gather_transitively_referenced_types(_type, gathered_types): + if _type in gathered_types: + return + + if isinstance(_type, ObjectType): + log.debug("> Adding type %s to list of types needing shape assertions." % _type.qualified_name()) + gathered_types.add(_type) + for type_member in _type.members: + gather_transitively_referenced_types(type_member.type, gathered_types) + elif isinstance(_type, EnumType): + log.debug("> Adding type %s to list of types needing shape assertions." % _type.qualified_name()) + gathered_types.add(_type) + elif isinstance(_type, AliasedType): + gather_transitively_referenced_types(_type.aliased_type, gathered_types) + elif isinstance(_type, ArrayType): + gather_transitively_referenced_types(_type.element_type, gathered_types) + + found_types = set() + for domain in domains: + for declaration in domain.type_declarations: + if declaration.type.qualified_name() in _TYPES_NEEDING_RUNTIME_CASTS: + log.debug("> Gathering types referenced by %s to generate shape assertions." % declaration.type.qualified_name()) + gather_transitively_referenced_types(declaration.type, found_types) + + self._types_needing_shape_assertions = found_types + + # Private helper instance methods. + def _traverse_and_assign_enum_values(self): + self._enum_value_encodings = {} + self._assigned_enum_values = [] + all_types = [] + + domains = self.non_supplemental_domains() + + for domain in domains: + for type_declaration in domain.type_declarations: + all_types.append(type_declaration.type) + for type_member in type_declaration.type_members: + all_types.append(type_member.type) + + for domain in domains: + for event in domain.events: + all_types.extend([parameter.type for parameter in event.event_parameters]) + + for domain in domains: + for command in domain.commands: + all_types.extend([parameter.type for parameter in command.call_parameters]) + all_types.extend([parameter.type for parameter in command.return_parameters]) + + for _type in all_types: + if not isinstance(_type, EnumType): + continue + map(self._assign_encoding_for_enum_value, _type.enum_values()) + + def _assign_encoding_for_enum_value(self, enum_value): + if enum_value in self._enum_value_encodings: + return + + self._enum_value_encodings[enum_value] = len(self._assigned_enum_values) + self._assigned_enum_values.append(enum_value) + + # Miscellaneous text manipulation routines. + def wrap_with_guard_for_domain(self, domain, text): + if self.model().framework is Frameworks.WebInspector: + return text + guard = domain.feature_guard + if guard: + return Generator.wrap_with_guard(guard, text) + return text + + @staticmethod + def wrap_with_guard(guard, text): + return '\n'.join([ + '#if %s' % guard, + text, + '#endif // %s' % guard, + ]) + + @staticmethod + def stylized_name_for_enum_value(enum_value): + regex = '(%s)' % "|".join(_ALWAYS_UPPERCASED_ENUM_VALUE_SUBSTRINGS) + + def replaceCallback(match): + return match.group(1).upper() + + # Split on hyphen, introduce camelcase, and force uppercasing of acronyms. + subwords = map(ucfirst, enum_value.split('-')) + return re.sub(re.compile(regex, re.IGNORECASE), replaceCallback, "".join(subwords)) + + @staticmethod + def js_name_for_parameter_type(_type): + _type = _type + if isinstance(_type, AliasedType): + _type = _type.aliased_type # Fall through. + if isinstance(_type, EnumType): + _type = _type.primitive_type # Fall through. + + if isinstance(_type, (ArrayType, ObjectType)): + return 'object' + if isinstance(_type, PrimitiveType): + if _type.qualified_name() in ['object', 'any']: + return 'object' + elif _type.qualified_name() in ['integer', 'number']: + return 'number' + else: + return _type.qualified_name() diff --git a/inspector/scripts/codegen/generator_templates.py b/inspector/scripts/codegen/generator_templates.py new file mode 100644 index 0000000..f2e330a --- /dev/null +++ b/inspector/scripts/codegen/generator_templates.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +# Generator templates, which can be filled with string.Template. +# Following are classes that fill the templates from the typechecked model. + + +class GeneratorTemplates: + CopyrightBlock = ( + """/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from ${inputFilename} +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py""") diff --git a/inspector/scripts/codegen/models.py b/inspector/scripts/codegen/models.py new file mode 100755 index 0000000..2dabdc0 --- /dev/null +++ b/inspector/scripts/codegen/models.py @@ -0,0 +1,591 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +import logging +import collections + +log = logging.getLogger('global') + + +def ucfirst(str): + return str[:1].upper() + str[1:] + + +def find_duplicates(l): + return [key for key, count in collections.Counter(l).items() if count > 1] + + +_FRAMEWORK_CONFIG_MAP = { + "Global": { + }, + "JavaScriptCore": { + "export_macro": "JS_EXPORT_PRIVATE" + }, + "WebInspector": { + }, + # Used for code generator tests. + "Test": { + } +} + + +class ParseException(Exception): + pass + + +class TypecheckException(Exception): + pass + + +class Framework: + def __init__(self, name): + self._settings = _FRAMEWORK_CONFIG_MAP[name] + self.name = name + + def setting(self, key, default=''): + return self._settings.get(key, default) + + @staticmethod + def fromString(frameworkString): + if frameworkString == "Global": + return Frameworks.Global + + if frameworkString == "JavaScriptCore": + return Frameworks.JavaScriptCore + + if frameworkString == "WebInspector": + return Frameworks.WebInspector + + if frameworkString == "Test": + return Frameworks.Test + + raise ParseException("Unknown framework: %s" % frameworkString) + + +class Frameworks: + Global = Framework("Global") + JavaScriptCore = Framework("JavaScriptCore") + WebInspector = Framework("WebInspector") + Test = Framework("Test") + + +class TypeReference: + def __init__(self, type_kind, referenced_type_name, enum_values, array_items): + self.type_kind = type_kind + self.referenced_type_name = referenced_type_name + self.enum_values = enum_values + if array_items is None: + self.array_type_ref = None + else: + self.array_type_ref = TypeReference(array_items.get('type'), array_items.get('$ref'), array_items.get('enum'), array_items.get('items')) + + if type_kind is not None and referenced_type_name is not None: + raise ParseException("Type reference cannot have both 'type' and '$ref' keys.") + + if type_kind == "array" and array_items is None: + raise ParseException("Type reference with type 'array' must have key 'items' to define array element type.") + + if enum_values is not None and len(enum_values) == 0: + raise ParseException("Type reference with enum values must have at least one enum value.") + + def referenced_name(self): + if self.referenced_type_name is not None: + return self.referenced_type_name + else: + return self.type_kind # integer, string, number, boolean, enum, object, array + + +class Type: + def __init__(self): + pass + + def __eq__(self, other): + return self.qualified_name() == other.qualified_name() + + def __hash__(self): + return self.qualified_name().__hash__() + + def raw_name(self): + return self._name + + # These methods should be overridden by subclasses. + def is_enum(self): + return False + + def type_domain(self): + pass + + def qualified_name(self): + pass + + # This is used to resolve nested types after instances are created. + def resolve_type_references(self, protocol): + pass + + +class PrimitiveType(Type): + def __init__(self, name): + self._name = name + + def __repr__(self): + return 'PrimitiveType[%s]' % self.qualified_name() + + def type_domain(self): + return None + + def qualified_name(self): + return self.raw_name() + + +class AliasedType(Type): + def __init__(self, name, domain, aliased_type_ref): + self._name = name + self._domain = domain + self._aliased_type_ref = aliased_type_ref + self.aliased_type = None + + def __repr__(self): + if self.aliased_type is not None: + return 'AliasedType[%s -> %r]' % (self.qualified_name(), self.aliased_type) + else: + return 'AliasedType[%s -> (unresolved)]' % self.qualified_name() + + def is_enum(self): + return self.aliased_type.is_enum() + + def type_domain(self): + return self._domain + + def qualified_name(self): + return ".".join([self.type_domain().domain_name, self.raw_name()]) + + def resolve_type_references(self, protocol): + if self.aliased_type is not None: + return + + self.aliased_type = protocol.lookup_type_reference(self._aliased_type_ref, self.type_domain()) + log.debug("< Resolved type reference for aliased type in %s: %s" % (self.qualified_name(), self.aliased_type.qualified_name())) + + +class EnumType(Type): + def __init__(self, name, domain, values, primitive_type_ref, is_anonymous=False): + self._name = name + self._domain = domain + self._values = values + self._primitive_type_ref = primitive_type_ref + self.primitive_type = None + self.is_anonymous = is_anonymous + + def __repr__(self): + return 'EnumType[value_type=%s; values=%s]' % (self.qualified_name(), ', '.join(map(str, self.enum_values()))) + + def is_enum(self): + return True + + def type_domain(self): + return self._domain + + def enum_values(self): + return self._values + + def qualified_name(self): + return ".".join([self.type_domain().domain_name, self.raw_name()]) + + def resolve_type_references(self, protocol): + if self.primitive_type is not None: + return + + self.primitive_type = protocol.lookup_type_reference(self._primitive_type_ref, Domains.GLOBAL) + log.debug("< Resolved type reference for enum type in %s: %s" % (self.qualified_name(), self.primitive_type.qualified_name())) + log.debug("<< enum values: %s" % self.enum_values()) + + +class ArrayType(Type): + def __init__(self, name, element_type_ref, domain): + self._name = name + self._domain = domain + self._element_type_ref = element_type_ref + self.element_type = None + + def __repr__(self): + if self.element_type is not None: + return 'ArrayType[element_type=%r]' % self.element_type + else: + return 'ArrayType[element_type=(unresolved)]' + + def type_domain(self): + return self._domain + + def qualified_name(self): + return ".".join(["array", self.element_type.qualified_name()]) + + def resolve_type_references(self, protocol): + if self.element_type is not None: + return + + self.element_type = protocol.lookup_type_reference(self._element_type_ref, self.type_domain()) + log.debug("< Resolved type reference for element type in %s: %s" % (self.qualified_name(), self.element_type.qualified_name())) + + +class ObjectType(Type): + def __init__(self, name, domain, members): + self._name = name + self._domain = domain + self.members = members + + def __repr__(self): + return 'ObjectType[%s]' % self.qualified_name() + + def type_domain(self): + return self._domain + + def qualified_name(self): + return ".".join([self.type_domain().domain_name, self.raw_name()]) + + +def check_for_required_properties(props, obj, what): + for prop in props: + if prop not in obj: + raise ParseException("When parsing %s, required property missing: %s" % (what, prop)) + + +class Protocol: + def __init__(self, framework_name): + self.domains = [] + self.types_by_name = {} + self.framework = Framework.fromString(framework_name) + + def parse_specification(self, json, isSupplemental): + log.debug("parse toplevel") + + if isinstance(json, dict) and 'domains' in json: + json = json['domains'] + if not isinstance(json, list): + json = [json] + + for domain in json: + self.parse_domain(domain, isSupplemental) + + def parse_domain(self, json, isSupplemental): + check_for_required_properties(['domain'], json, "domain") + log.debug("parse domain " + json['domain']) + + types = [] + commands = [] + events = [] + + if 'types' in json: + if not isinstance(json['types'], list): + raise ParseException("Malformed domain specification: types is not an array") + types.extend([self.parse_type_declaration(declaration) for declaration in json['types']]) + + if 'commands' in json: + if not isinstance(json['commands'], list): + raise ParseException("Malformed domain specification: commands is not an array") + commands.extend([self.parse_command(command) for command in json['commands']]) + + if 'events' in json: + if not isinstance(json['events'], list): + raise ParseException("Malformed domain specification: events is not an array") + events.extend([self.parse_event(event) for event in json['events']]) + + if 'availability' in json: + if not commands and not events: + raise ParseException("Malformed domain specification: availability should only be included if there are commands or events.") + allowed_activation_strings = set(['web']) + if json['availability'] not in allowed_activation_strings: + raise ParseException('Malformed domain specification: availability is an unsupported string. Was: "%s", Allowed values: %s' % (json['availability'], ', '.join(allowed_activation_strings))) + + self.domains.append(Domain(json['domain'], json.get('description', ''), json.get('featureGuard'), json.get('availability'), isSupplemental, types, commands, events)) + + def parse_type_declaration(self, json): + check_for_required_properties(['id', 'type'], json, "type") + log.debug("parse type %s" % json['id']) + + type_members = [] + + if 'properties' in json: + if not isinstance(json['properties'], list): + raise ParseException("Malformed type specification: properties is not an array") + type_members.extend([self.parse_type_member(member) for member in json['properties']]) + + duplicate_names = find_duplicates([member.member_name for member in type_members]) + if len(duplicate_names) > 0: + raise ParseException("Malformed domain specification: type declaration for %s has duplicate member names" % json['id']) + + type_ref = TypeReference(json['type'], json.get('$ref'), json.get('enum'), json.get('items')) + return TypeDeclaration(json['id'], type_ref, json.get("description", ""), type_members) + + def parse_type_member(self, json): + check_for_required_properties(['name'], json, "type member") + log.debug("parse type member %s" % json['name']) + + type_ref = TypeReference(json.get('type'), json.get('$ref'), json.get('enum'), json.get('items')) + return TypeMember(json['name'], type_ref, json.get('optional', False), json.get('description', "")) + + def parse_command(self, json): + check_for_required_properties(['name'], json, "command") + log.debug("parse command %s" % json['name']) + + call_parameters = [] + return_parameters = [] + + if 'parameters' in json: + if not isinstance(json['parameters'], list): + raise ParseException("Malformed command specification: parameters is not an array") + call_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['parameters']]) + + duplicate_names = find_duplicates([param.parameter_name for param in call_parameters]) + if len(duplicate_names) > 0: + raise ParseException("Malformed domain specification: call parameter list for command %s has duplicate parameter names" % json['name']) + + if 'returns' in json: + if not isinstance(json['returns'], list): + raise ParseException("Malformed command specification: returns is not an array") + return_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['returns']]) + + duplicate_names = find_duplicates([param.parameter_name for param in return_parameters]) + if len(duplicate_names) > 0: + raise ParseException("Malformed domain specification: return parameter list for command %s has duplicate parameter names" % json['name']) + + return Command(json['name'], call_parameters, return_parameters, json.get('description', ""), json.get('async', False)) + + def parse_event(self, json): + check_for_required_properties(['name'], json, "event") + log.debug("parse event %s" % json['name']) + + event_parameters = [] + + if 'parameters' in json: + if not isinstance(json['parameters'], list): + raise ParseException("Malformed event specification: parameters is not an array") + event_parameters.extend([self.parse_call_or_return_parameter(parameter) for parameter in json['parameters']]) + + duplicate_names = find_duplicates([param.parameter_name for param in event_parameters]) + if len(duplicate_names) > 0: + raise ParseException("Malformed domain specification: parameter list for event %s has duplicate parameter names" % json['name']) + + return Event(json['name'], event_parameters, json.get('description', "")) + + def parse_call_or_return_parameter(self, json): + check_for_required_properties(['name'], json, "parameter") + log.debug("parse parameter %s" % json['name']) + + type_ref = TypeReference(json.get('type'), json.get('$ref'), json.get('enum'), json.get('items')) + return Parameter(json['name'], type_ref, json.get('optional', False), json.get('description', "")) + + def resolve_types(self): + qualified_declared_type_names = set(['boolean', 'string', 'integer', 'number', 'enum', 'array', 'object', 'any']) + + self.types_by_name['string'] = PrimitiveType('string') + for _primitive_type in ['boolean', 'integer', 'number']: + self.types_by_name[_primitive_type] = PrimitiveType(_primitive_type) + for _object_type in ['any', 'object']: + self.types_by_name[_object_type] = PrimitiveType(_object_type) + + # Gather qualified type names from type declarations in each domain. + for domain in self.domains: + for declaration in domain.type_declarations: + # Basic sanity checking. + if declaration.type_ref.referenced_type_name is not None: + raise TypecheckException("Type declarations must name a base type, not a type reference.") + + # Find duplicate qualified type names. + qualified_type_name = ".".join([domain.domain_name, declaration.type_name]) + if qualified_type_name in qualified_declared_type_names: + raise TypecheckException("Duplicate type declaration: %s" % qualified_type_name) + + qualified_declared_type_names.add(qualified_type_name) + + type_instance = None + + kind = declaration.type_ref.type_kind + if declaration.type_ref.enum_values is not None: + primitive_type_ref = TypeReference(declaration.type_ref.type_kind, None, None, None) + type_instance = EnumType(declaration.type_name, domain, declaration.type_ref.enum_values, primitive_type_ref) + elif kind == "array": + type_instance = ArrayType(declaration.type_name, declaration.type_ref.array_type_ref, domain) + elif kind == "object": + type_instance = ObjectType(declaration.type_name, domain, declaration.type_members) + else: + type_instance = AliasedType(declaration.type_name, domain, declaration.type_ref) + + log.debug("< Created fresh type %r for declaration %s" % (type_instance, qualified_type_name)) + self.types_by_name[qualified_type_name] = type_instance + + # Resolve all type references recursively. + for domain in self.domains: + domain.resolve_type_references(self) + + def lookup_type_for_declaration(self, declaration, domain): + # This will only match a type defined in the same domain, where prefixes aren't required. + qualified_name = ".".join([domain.domain_name, declaration.type_name]) + if qualified_name in self.types_by_name: + found_type = self.types_by_name[qualified_name] + found_type.resolve_type_references(self) + return found_type + + raise TypecheckException("Lookup failed for type declaration: %s (referenced from domain: %s)" % (declaration.type_name, domain.domain_name)) + + def lookup_type_reference(self, type_ref, domain): + # If reference is to an anonymous array type, create a fresh instance. + if type_ref.type_kind == "array": + type_instance = ArrayType(None, type_ref.array_type_ref, domain) + type_instance.resolve_type_references(self) + log.debug("< Created fresh type instance for anonymous array type: %s" % type_instance.qualified_name()) + return type_instance + + # If reference is to an anonymous enum type, create a fresh instance. + if type_ref.enum_values is not None: + # We need to create a type reference without enum values as the enum's nested type. + primitive_type_ref = TypeReference(type_ref.type_kind, None, None, None) + type_instance = EnumType("(anonymous)", domain, type_ref.enum_values, primitive_type_ref, True) + type_instance.resolve_type_references(self) + log.debug("< Created fresh type instance for anonymous enum type: %s" % type_instance.qualified_name()) + return type_instance + + # This will match when referencing a type defined in the same domain, where prefixes aren't required. + qualified_name = ".".join([domain.domain_name, type_ref.referenced_name()]) + if qualified_name in self.types_by_name: + found_type = self.types_by_name[qualified_name] + found_type.resolve_type_references(self) + log.debug("< Lookup succeeded for unqualified type: %s" % found_type.qualified_name()) + return found_type + + # This will match primitive types and fully-qualified types from a different domain. + if type_ref.referenced_name() in self.types_by_name: + found_type = self.types_by_name[type_ref.referenced_name()] + found_type.resolve_type_references(self) + log.debug("< Lookup succeeded for primitive or qualified type: %s" % found_type.qualified_name()) + return found_type + + raise TypecheckException("Lookup failed for type reference: %s (referenced from domain: %s)" % (type_ref.referenced_name(), domain.domain_name)) + + +class Domain: + def __init__(self, domain_name, description, feature_guard, availability, isSupplemental, type_declarations, commands, events): + self.domain_name = domain_name + self.description = description + self.feature_guard = feature_guard + self.availability = availability + self.is_supplemental = isSupplemental + self.type_declarations = type_declarations + self.commands = commands + self.events = events + + def resolve_type_references(self, protocol): + log.debug("> Resolving type declarations for domain: %s" % self.domain_name) + for declaration in self.type_declarations: + declaration.resolve_type_references(protocol, self) + + log.debug("> Resolving types in commands for domain: %s" % self.domain_name) + for command in self.commands: + command.resolve_type_references(protocol, self) + + log.debug("> Resolving types in events for domain: %s" % self.domain_name) + for event in self.events: + event.resolve_type_references(protocol, self) + + +class Domains: + GLOBAL = Domain("", "The global domain, in which primitive types are implicitly declared.", None, None, True, [], [], []) + + +class TypeDeclaration: + def __init__(self, type_name, type_ref, description, type_members): + self.type_name = type_name + self.type_ref = type_ref + self.description = description + self.type_members = type_members + + if self.type_name != ucfirst(self.type_name): + raise ParseException("Types must begin with an uppercase character.") + + def resolve_type_references(self, protocol, domain): + log.debug(">> Resolving type references for type declaration: %s" % self.type_name) + self.type = protocol.lookup_type_for_declaration(self, domain) + for member in self.type_members: + member.resolve_type_references(protocol, domain) + + +class TypeMember: + def __init__(self, member_name, type_ref, is_optional, description): + self.member_name = member_name + self.type_ref = type_ref + self.is_optional = is_optional + self.description = description + + if self.is_optional not in [True, False]: + raise ParseException("The 'optional' flag for a type member must be a boolean literal.") + + def resolve_type_references(self, protocol, domain): + log.debug(">>> Resolving type references for type member: %s" % self.member_name) + self.type = protocol.lookup_type_reference(self.type_ref, domain) + + +class Parameter: + def __init__(self, parameter_name, type_ref, is_optional, description): + self.parameter_name = parameter_name + self.type_ref = type_ref + self.is_optional = is_optional + self.description = description + + if self.is_optional not in [True, False]: + raise ParseException("The 'optional' flag for a parameter must be a boolean literal.") + + def resolve_type_references(self, protocol, domain): + log.debug(">>> Resolving type references for parameter: %s" % self.parameter_name) + self.type = protocol.lookup_type_reference(self.type_ref, domain) + + +class Command: + def __init__(self, command_name, call_parameters, return_parameters, description, is_async): + self.command_name = command_name + self.call_parameters = call_parameters + self.return_parameters = return_parameters + self.description = description + self.is_async = is_async + + def resolve_type_references(self, protocol, domain): + log.debug(">> Resolving type references for call parameters in command: %s" % self.command_name) + for parameter in self.call_parameters: + parameter.resolve_type_references(protocol, domain) + + log.debug(">> Resolving type references for return parameters in command: %s" % self.command_name) + for parameter in self.return_parameters: + parameter.resolve_type_references(protocol, domain) + + +class Event: + def __init__(self, event_name, event_parameters, description): + self.event_name = event_name + self.event_parameters = event_parameters + self.description = description + + def resolve_type_references(self, protocol, domain): + log.debug(">> Resolving type references for parameters in event: %s" % self.event_name) + for parameter in self.event_parameters: + parameter.resolve_type_references(protocol, domain) diff --git a/inspector/scripts/codegen/objc_generator.py b/inspector/scripts/codegen/objc_generator.py new file mode 100755 index 0000000..f6dd03c --- /dev/null +++ b/inspector/scripts/codegen/objc_generator.py @@ -0,0 +1,523 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +import logging +from generator import Generator, ucfirst +from models import PrimitiveType, ObjectType, ArrayType, EnumType, AliasedType, Frameworks + +log = logging.getLogger('global') + + +def join_type_and_name(type_str, name_str): + if type_str.endswith('*'): + return type_str + name_str + return type_str + ' ' + name_str + + +def strip_block_comment_markers(str): + return str.replace('/*', '').replace('*/', '') + + +def remove_duplicate_from_str(str, possible_duplicate): + return str.replace(possible_duplicate + possible_duplicate, possible_duplicate) + + +_OBJC_IDENTIFIER_RENAME_MAP = { + 'this': 'thisObject', # Debugger.CallFrame.this + 'description': 'stringRepresentation', # Runtime.RemoteObject.description + 'id': 'identifier', # Page.Frame.id, Runtime.ExecutionContextDescription.id, Debugger.BreakpointAction.id +} + +_OBJC_IDENTIFIER_REVERSE_RENAME_MAP = dict((v, k) for k, v in _OBJC_IDENTIFIER_RENAME_MAP.iteritems()) + + +class ObjCTypeCategory: + Simple = 0 + String = 1 + Object = 2 + Array = 3 + + @staticmethod + def category_for_type(_type): + if (isinstance(_type, PrimitiveType)): + if _type.raw_name() is 'string': + return ObjCTypeCategory.String + if _type.raw_name() in ['object', 'any']: + return ObjCTypeCategory.Object + if _type.raw_name() is 'array': + return ObjCTypeCategory.Array + return ObjCTypeCategory.Simple + if (isinstance(_type, ObjectType)): + return ObjCTypeCategory.Object + if (isinstance(_type, ArrayType)): + return ObjCTypeCategory.Array + if (isinstance(_type, AliasedType)): + return ObjCTypeCategory.category_for_type(_type.aliased_type) + if (isinstance(_type, EnumType)): + return ObjCTypeCategory.category_for_type(_type.primitive_type) + return None + + + +# This class contains extra static methods used for generation, but does +# not participate in any inheritance hierarchy. File generators should +# extend the generic "Generator" class instead. +class ObjCGenerator: + OBJC_PREFIX = 'RWIProtocol' + OBJC_JSON_OBJECT_BASE = '%sJSONObject' % OBJC_PREFIX + + # Adjust identifier names that collide with ObjC keywords. + + @staticmethod + def identifier_to_objc_identifier(name): + return _OBJC_IDENTIFIER_RENAME_MAP.get(name, name) + + @staticmethod + def objc_identifier_to_identifier(name): + return _OBJC_IDENTIFIER_REVERSE_RENAME_MAP.get(name, name) + + # Generate ObjC types, command handlers, and event dispatchers for a subset of domains. + + DOMAINS_TO_GENERATE = ['CSS', 'DOM', 'DOMStorage', 'Network', 'Page', 'GenericTypes'] + + @staticmethod + def should_generate_domain_types_filter(model): + def should_generate_domain_types(domain): + if model.framework is Frameworks.Test: + return True + whitelist = set(ObjCGenerator.DOMAINS_TO_GENERATE) + whitelist.update(set(['Console', 'Debugger', 'Runtime'])) + return domain.domain_name in whitelist + return should_generate_domain_types + + @staticmethod + def should_generate_domain_command_handler_filter(model): + def should_generate_domain_command_handler(domain): + if model.framework is Frameworks.Test: + return True + whitelist = set(ObjCGenerator.DOMAINS_TO_GENERATE) + return domain.domain_name in whitelist + return should_generate_domain_command_handler + + @staticmethod + def should_generate_domain_event_dispatcher_filter(model): + def should_generate_domain_event_dispatcher(domain): + if model.framework is Frameworks.Test: + return True + whitelist = set(ObjCGenerator.DOMAINS_TO_GENERATE) + whitelist.add('Console') + return domain.domain_name in whitelist + return should_generate_domain_event_dispatcher + + # ObjC enum and type names. + + @staticmethod + def objc_name_for_type(type): + name = type.qualified_name().replace('.', '') + name = remove_duplicate_from_str(name, type.type_domain().domain_name) + return '%s%s' % (ObjCGenerator.OBJC_PREFIX, name) + + @staticmethod + def objc_enum_name_for_anonymous_enum_declaration(declaration): + domain_name = declaration.type.type_domain().domain_name + name = '%s%s' % (domain_name, declaration.type.raw_name()) + name = remove_duplicate_from_str(name, domain_name) + return '%s%s' % (ObjCGenerator.OBJC_PREFIX, name) + + @staticmethod + def objc_enum_name_for_anonymous_enum_member(declaration, member): + domain_name = member.type.type_domain().domain_name + name = '%s%s%s' % (domain_name, declaration.type.raw_name(), ucfirst(member.member_name)) + name = remove_duplicate_from_str(name, domain_name) + return '%s%s' % (ObjCGenerator.OBJC_PREFIX, name) + + @staticmethod + def objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter): + domain_name = domain.domain_name + name = '%s%s%s' % (domain_name, ucfirst(event_or_command_name), ucfirst(parameter.parameter_name)) + name = remove_duplicate_from_str(name, domain_name) + return '%s%s' % (ObjCGenerator.OBJC_PREFIX, name) + + @staticmethod + def objc_enum_name_for_non_anonymous_enum(_type): + domain_name = _type.type_domain().domain_name + name = _type.qualified_name().replace('.', '') + name = remove_duplicate_from_str(name, domain_name) + return '%s%s' % (ObjCGenerator.OBJC_PREFIX, name) + + # Miscellaneous name handling. + + @staticmethod + def variable_name_prefix_for_domain(domain): + domain_name = domain.domain_name + if domain_name.startswith('DOM'): + return 'dom' + domain_name[3:] + if domain_name.startswith('CSS'): + return 'css' + domain_name[3:] + return domain_name[:1].lower() + domain_name[1:] + + # Type basics. + + @staticmethod + def objc_accessor_type_for_raw_name(raw_name): + if raw_name in ['string', 'array']: + return 'copy' + if raw_name in ['integer', 'number', 'boolean']: + return 'assign' + if raw_name in ['any', 'object']: + return 'retain' + return None + + @staticmethod + def objc_type_for_raw_name(raw_name): + if raw_name is 'string': + return 'NSString *' + if raw_name is 'array': + return 'NSArray *' + if raw_name is 'integer': + return 'int' + if raw_name is 'number': + return 'double' + if raw_name is 'boolean': + return 'BOOL' + if raw_name in ['any', 'object']: + return '%s *' % ObjCGenerator.OBJC_JSON_OBJECT_BASE + return None + + @staticmethod + def objc_class_for_raw_name(raw_name): + if raw_name is 'string': + return 'NSString' + if raw_name is 'array': + return 'NSArray' + if raw_name in ['integer', 'number', 'boolean']: + return 'NSNumber' + if raw_name in ['any', 'object']: + return ObjCGenerator.OBJC_JSON_OBJECT_BASE + return None + + # FIXME: Can these protocol_type functions be removed in favor of C++ generators functions? + + @staticmethod + def protocol_type_for_raw_name(raw_name): + if raw_name is 'string': + return 'String' + if raw_name is 'integer': + return 'int' + if raw_name is 'number': + return 'double' + if raw_name is 'boolean': + return 'bool' + if raw_name in ['any', 'object']: + return 'InspectorObject' + return None + + @staticmethod + def protocol_type_for_type(_type): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + return ObjCGenerator.protocol_type_for_raw_name(_type.raw_name()) + if (isinstance(_type, EnumType)): + return ObjCGenerator.protocol_type_for_type(_type.primitive_type) + if (isinstance(_type, ObjectType)): + return 'Inspector::Protocol::%s::%s' % (_type.type_domain().domain_name, _type.raw_name()) + if (isinstance(_type, ArrayType)): + sub_type = ObjCGenerator.protocol_type_for_type(_type.element_type) + return 'Inspector::Protocol::Array<%s>' % sub_type + return None + + @staticmethod + def is_type_objc_pointer_type(_type): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + return _type.raw_name() in ['string', 'array', 'any', 'object'] + if (isinstance(_type, EnumType)): + return False + if (isinstance(_type, ObjectType)): + return True + if (isinstance(_type, ArrayType)): + return True + return None + + @staticmethod + def objc_class_for_type(_type): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + return ObjCGenerator.objc_class_for_raw_name(_type.raw_name()) + if (isinstance(_type, EnumType)): + return ObjCGenerator.objc_class_for_raw_name(_type.primitive_type.raw_name()) + if (isinstance(_type, ObjectType)): + return ObjCGenerator.objc_name_for_type(_type) + if (isinstance(_type, ArrayType)): + sub_type = strip_block_comment_markers(ObjCGenerator.objc_class_for_type(_type.element_type)) + return 'NSArray/*<%s>*/' % sub_type + return None + + @staticmethod + def objc_class_for_array_type(_type): + if isinstance(_type, AliasedType): + _type = _type.aliased_type + if isinstance(_type, ArrayType): + return ObjCGenerator.objc_class_for_type(_type.element_type) + return None + + @staticmethod + def objc_accessor_type_for_member(member): + return ObjCGenerator.objc_accessor_type_for_member_internal(member.type) + + @staticmethod + def objc_accessor_type_for_member_internal(_type): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + return ObjCGenerator.objc_accessor_type_for_raw_name(_type.raw_name()) + if (isinstance(_type, EnumType)): + return 'assign' + if (isinstance(_type, ObjectType)): + return 'retain' + if (isinstance(_type, ArrayType)): + return 'copy' + return None + + @staticmethod + def objc_type_for_member(declaration, member): + return ObjCGenerator.objc_type_for_member_internal(member.type, declaration, member) + + @staticmethod + def objc_type_for_member_internal(_type, declaration, member): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + return ObjCGenerator.objc_type_for_raw_name(_type.raw_name()) + if (isinstance(_type, EnumType)): + if (_type.is_anonymous): + return ObjCGenerator.objc_enum_name_for_anonymous_enum_member(declaration, member) + return ObjCGenerator.objc_enum_name_for_non_anonymous_enum(_type) + if (isinstance(_type, ObjectType)): + return ObjCGenerator.objc_name_for_type(_type) + ' *' + if (isinstance(_type, ArrayType)): + sub_type = strip_block_comment_markers(ObjCGenerator.objc_class_for_type(_type.element_type)) + return 'NSArray/*<%s>*/ *' % sub_type + return None + + @staticmethod + def objc_type_for_param(domain, event_or_command_name, parameter, respect_optional=True): + objc_type = ObjCGenerator.objc_type_for_param_internal(parameter.type, domain, event_or_command_name, parameter) + if respect_optional and parameter.is_optional: + if objc_type.endswith('*'): + return objc_type + '*' + return objc_type + ' *' + return objc_type + + @staticmethod + def objc_type_for_param_internal(_type, domain, event_or_command_name, parameter): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + return ObjCGenerator.objc_type_for_raw_name(_type.raw_name()) + if (isinstance(_type, EnumType)): + if _type.is_anonymous: + return ObjCGenerator.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter) + return ObjCGenerator.objc_enum_name_for_non_anonymous_enum(_type) + if (isinstance(_type, ObjectType)): + return ObjCGenerator.objc_name_for_type(_type) + ' *' + if (isinstance(_type, ArrayType)): + sub_type = strip_block_comment_markers(ObjCGenerator.objc_class_for_type(_type.element_type)) + return 'NSArray/*<%s>*/ *' % sub_type + return None + + # ObjC <-> Protocol conversion for commands and events. + # - convert a command call parameter received from Protocol to ObjC for handler + # - convert a command return parameter in callback block from ObjC to Protocol to send + # - convert an event parameter from ObjC API to Protocol to send + + @staticmethod + def objc_protocol_export_expression_for_variable(var_type, var_name): + category = ObjCTypeCategory.category_for_type(var_type) + if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]: + if isinstance(var_type, EnumType): + return 'toProtocolString(%s)' % var_name + return var_name + if category is ObjCTypeCategory.Object: + return '[%s toInspectorObject]' % var_name + if category is ObjCTypeCategory.Array: + protocol_type = ObjCGenerator.protocol_type_for_type(var_type.element_type) + objc_class = ObjCGenerator.objc_class_for_type(var_type.element_type) + if protocol_type == 'Inspector::Protocol::Array<String>': + return 'inspectorStringArrayArray(%s)' % var_name + if protocol_type is 'String' and objc_class is 'NSString': + return 'inspectorStringArray(%s)' % var_name + if protocol_type is 'int' and objc_class is 'NSNumber': + return 'inspectorIntegerArray(%s)' % var_name + if protocol_type is 'double' and objc_class is 'NSNumber': + return 'inspectorDoubleArray(%s)' % var_name + return 'inspectorObjectArray(%s)' % var_name + + @staticmethod + def objc_protocol_import_expression_for_member(name, declaration, member): + if isinstance(member.type, EnumType): + if member.type.is_anonymous: + return 'fromProtocolString<%s>(%s)' % (ObjCGenerator.objc_enum_name_for_anonymous_enum_member(declaration, member), name) + return 'fromProtocolString<%s>(%s)' % (ObjCGenerator.objc_enum_name_for_non_anonymous_enum(member.type), name) + return ObjCGenerator.objc_protocol_import_expression_for_variable(member.type, name) + + @staticmethod + def objc_protocol_import_expression_for_parameter(name, domain, event_or_command_name, parameter): + if isinstance(parameter.type, EnumType): + if parameter.type.is_anonymous: + return 'fromProtocolString<%s>(%s)' % (ObjCGenerator.objc_enum_name_for_anonymous_enum_parameter(domain, event_or_command_name, parameter), name) + return 'fromProtocolString<%s>(%s)' % (ObjCGenerator.objc_enum_name_for_non_anonymous_enum(parameter.type), name) + return ObjCGenerator.objc_protocol_import_expression_for_variable(parameter.type, name) + + @staticmethod + def objc_protocol_import_expression_for_variable(var_type, var_name): + category = ObjCTypeCategory.category_for_type(var_type) + if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]: + return var_name + if category is ObjCTypeCategory.Object: + objc_class = ObjCGenerator.objc_class_for_type(var_type) + return '[[[%s alloc] initWithInspectorObject:%s] autorelease]' % (objc_class, var_name) + if category is ObjCTypeCategory.Array: + objc_class = ObjCGenerator.objc_class_for_type(var_type.element_type) + if objc_class is 'NSString': + return 'objcStringArray(%s)' % var_name + if objc_class is 'NSNumber': # FIXME: Integer or Double? + return 'objcIntegerArray(%s)' % var_name + return 'objcArray<%s>(%s)' % (objc_class, var_name) + + # ObjC <-> JSON object conversion for types getters/setters. + # - convert a member setter from ObjC API to JSON object setter + # - convert a member getter from JSON object to ObjC API + + @staticmethod + def objc_to_protocol_expression_for_member(declaration, member, sub_expression): + category = ObjCTypeCategory.category_for_type(member.type) + if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]: + if isinstance(member.type, EnumType): + return 'toProtocolString(%s)' % sub_expression + return sub_expression + if category is ObjCTypeCategory.Object: + return sub_expression + if category is ObjCTypeCategory.Array: + objc_class = ObjCGenerator.objc_class_for_type(member.type.element_type) + if objc_class is 'NSString': + return 'inspectorStringArray(%s)' % sub_expression + if objc_class is 'NSNumber': + protocol_type = ObjCGenerator.protocol_type_for_type(member.type.element_type) + if protocol_type is 'double': + return 'inspectorDoubleArray(%s)' % sub_expression + return 'inspectorIntegerArray(%s)' % sub_expression + return 'inspectorObjectArray(%s)' % sub_expression + + @staticmethod + def protocol_to_objc_expression_for_member(declaration, member, sub_expression): + category = ObjCTypeCategory.category_for_type(member.type) + if category in [ObjCTypeCategory.Simple, ObjCTypeCategory.String]: + if isinstance(member.type, EnumType): + if member.type.is_anonymous: + return 'fromProtocolString<%s>(%s)' % (ObjCGenerator.objc_enum_name_for_anonymous_enum_member(declaration, member), sub_expression) + return 'fromProtocolString<%s>(%s)' % (ObjCGenerator.objc_enum_name_for_non_anonymous_enum(member.type), sub_expression) + return sub_expression + if category is ObjCTypeCategory.Object: + objc_type = ObjCGenerator.objc_type_for_member(declaration, member) + return '(%s)%s' % (objc_type, sub_expression) + if category is ObjCTypeCategory.Array: + protocol_type = ObjCGenerator.protocol_type_for_type(member.type.element_type) + objc_class = ObjCGenerator.objc_class_for_type(member.type.element_type) + if objc_class is 'NSString': + return 'objcStringArray(%s)' % sub_expression + if objc_class is 'NSNumber': + protocol_type = ObjCGenerator.protocol_type_for_type(member.type.element_type) + if protocol_type is 'double': + return 'objcDoubleArray(%s)' % sub_expression + return 'objcIntegerArray(%s)' % sub_expression + return 'objcArray<%s>(%s)' % (objc_class, sub_expression) + + # JSON object setter/getter selectors for types. + + @staticmethod + def objc_setter_method_for_member(declaration, member): + return ObjCGenerator.objc_setter_method_for_member_internal(member.type, declaration, member) + + @staticmethod + def objc_setter_method_for_member_internal(_type, declaration, member): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + raw_name = _type.raw_name() + if raw_name is 'boolean': + return 'setBool' + if raw_name is 'integer': + return 'setInteger' + if raw_name is 'number': + return 'setDouble' + if raw_name is 'string': + return 'setString' + if raw_name in ['any', 'object']: + return 'setObject' + if raw_name is 'array': + return 'setInspectorArray' + return None + if (isinstance(_type, EnumType)): + return 'setString' + if (isinstance(_type, ObjectType)): + return 'setObject' + if (isinstance(_type, ArrayType)): + return 'setInspectorArray' + return None + + @staticmethod + def objc_getter_method_for_member(declaration, member): + return ObjCGenerator.objc_getter_method_for_member_internal(member.type, declaration, member) + + @staticmethod + def objc_getter_method_for_member_internal(_type, declaration, member): + if (isinstance(_type, AliasedType)): + _type = _type.aliased_type + if (isinstance(_type, PrimitiveType)): + raw_name = _type.raw_name() + if raw_name is 'boolean': + return 'boolForKey' + if raw_name is 'integer': + return 'integerForKey' + if raw_name is 'number': + return 'doubleForKey' + if raw_name is 'string': + return 'stringForKey' + if raw_name in ['any', 'object']: + return 'objectForKey' + if raw_name is 'array': + return 'inspectorArrayForKey' + return None + if (isinstance(_type, EnumType)): + return 'stringForKey' + if (isinstance(_type, ObjectType)): + return 'objectForKey' + if (isinstance(_type, ArrayType)): + return 'inspectorArrayForKey' + return None diff --git a/inspector/scripts/codegen/objc_generator_templates.py b/inspector/scripts/codegen/objc_generator_templates.py new file mode 100755 index 0000000..ef712b8 --- /dev/null +++ b/inspector/scripts/codegen/objc_generator_templates.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +# Generator templates, which can be filled with string.Template. +# Following are classes that fill the templates from the typechecked model. + +class ObjCGeneratorTemplates: + + HeaderPrelude = ( + """#import <Foundation/Foundation.h> + +${includes} +""") + + HeaderPostlude = ( + """""") + + ConversionHelpersPrelude = ( + """${includes} + +namespace Inspector {""") + + ConversionHelpersPostlude = ( + """} // namespace Inspector +""") + + GenericHeaderPrelude = ( + """${includes}""") + + GenericHeaderPostlude = ( + """""") + + ConversionHelpersStandard = ( + """template<typename ObjCEnumType> +ObjCEnumType fromProtocolString(const String& value);""") + + BackendDispatcherHeaderPrelude = ( + """${includes} + +${forwardDeclarations} + +namespace Inspector { +""") + + BackendDispatcherHeaderPostlude = ( + """} // namespace Inspector +""") + + BackendDispatcherImplementationPrelude = ( + """#import "config.h" +#import ${primaryInclude} + +${secondaryIncludes} + +namespace Inspector {""") + + BackendDispatcherImplementationPostlude = ( + """} // namespace Inspector +""") + + ImplementationPrelude = ( + """#import "config.h" +#import ${primaryInclude} + +${secondaryIncludes} + +using namespace Inspector;""") + + ImplementationPostlude = ( + """""") + + BackendDispatcherHeaderDomainHandlerInterfaceDeclaration = ( + """class Alternate${domainName}BackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~Alternate${domainName}BackendDispatcher() { } +${commandDeclarations} +};""") + + BackendDispatcherHeaderDomainHandlerObjCDeclaration = ( + """class ObjCInspector${domainName}BackendDispatcher final : public Alternate${domainName}BackendDispatcher { +public: + ObjCInspector${domainName}BackendDispatcher(id<${objcPrefix}${domainName}DomainHandler> handler) { m_delegate = handler; } +${commandDeclarations} +private: + RetainPtr<id<${objcPrefix}${domainName}DomainHandler>> m_delegate; +};""") + + BackendDispatcherHeaderDomainHandlerImplementation = ( + """void ObjCInspector${domainName}BackendDispatcher::${commandName}(${parameters}) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + +${successCallback} +${conversions} +${invocation} +} +""") + + ConfigurationCommandProperty = ( + """@property (nonatomic, retain, setter=set${domainName}Handler:) id<${objcPrefix}${domainName}DomainHandler> ${variableNamePrefix}Handler;""") + + ConfigurationEventProperty = ( + """@property (nonatomic, readonly) ${objcPrefix}${domainName}DomainEventDispatcher *${variableNamePrefix}EventDispatcher;""") + + ConfigurationCommandPropertyImplementation = ( + """- (void)set${domainName}Handler:(id<${objcPrefix}${domainName}DomainHandler>)handler +{ + if (handler == _${variableNamePrefix}Handler) + return; + + [_${variableNamePrefix}Handler release]; + _${variableNamePrefix}Handler = [handler retain]; + + auto alternateDispatcher = std::make_unique<ObjCInspector${domainName}BackendDispatcher>(handler); + auto alternateAgent = std::make_unique<AlternateDispatchableAgent<${domainName}BackendDispatcher, Alternate${domainName}BackendDispatcher>>(ASCIILiteral("${domainName}"), WTF::move(alternateDispatcher)); + _controller->appendExtraAgent(WTF::move(alternateAgent)); +} + +- (id<${objcPrefix}${domainName}DomainHandler>)${variableNamePrefix}Handler +{ + return _${variableNamePrefix}Handler; +}""") + + ConfigurationGetterImplementation = ( + """- (${objcPrefix}${domainName}DomainEventDispatcher *)${variableNamePrefix}EventDispatcher +{ + if (!_${variableNamePrefix}EventDispatcher) + _${variableNamePrefix}EventDispatcher = [[${objcPrefix}${domainName}DomainEventDispatcher alloc] initWithController:_controller]; + return _${variableNamePrefix}EventDispatcher; +}""") diff --git a/inspector/scripts/generate-inspector-protocol-bindings.py b/inspector/scripts/generate-inspector-protocol-bindings.py new file mode 100755 index 0000000..a1987aa --- /dev/null +++ b/inspector/scripts/generate-inspector-protocol-bindings.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 Apple Inc. All rights reserved. +# Copyright (c) 2014 University of Washington. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +# This script generates JS, Objective C, and C++ bindings for the inspector protocol. +# Generators for individual files are located in the codegen/ directory. + +import os.path +import re +import sys +import string +from string import Template +import optparse +import logging + +try: + import json +except ImportError: + import simplejson as json + +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) +log = logging.getLogger('global') + +try: + from codegen import * + +# When copying generator files to JavaScriptCore's private headers on Mac, +# the codegen/ module directory is flattened. So, import directly. +except ImportError, e: + # log.error(e) # Uncomment this to debug early import errors. + import models + from models import * + from generator import * + from cpp_generator import * + from objc_generator import * + + from generate_cpp_alternate_backend_dispatcher_header import * + from generate_cpp_backend_dispatcher_header import * + from generate_cpp_backend_dispatcher_implementation import * + from generate_cpp_frontend_dispatcher_header import * + from generate_cpp_frontend_dispatcher_implementation import * + from generate_cpp_protocol_types_header import * + from generate_cpp_protocol_types_implementation import * + from generate_js_backend_commands import * + from generate_objc_backend_dispatcher_header import * + from generate_objc_backend_dispatcher_implementation import * + from generate_objc_configuration_header import * + from generate_objc_configuration_implementation import * + from generate_objc_conversion_helpers import * + from generate_objc_frontend_dispatcher_implementation import * + from generate_objc_header import * + from generate_objc_internal_header import * + from generate_objc_protocol_types_implementation import * + + +# A writer that only updates file if it actually changed. +class IncrementalFileWriter: + def __init__(self, filepath, force_output): + self._filepath = filepath + self._output = "" + self.force_output = force_output + + def write(self, text): + self._output += text + + def close(self): + text_changed = True + self._output = self._output.rstrip() + "\n" + + try: + if self.force_output: + raise + + read_file = open(self._filepath, "r") + old_text = read_file.read() + read_file.close() + text_changed = old_text != self._output + except: + # Ignore, just overwrite by default + pass + + if text_changed or self.force_output: + out_file = open(self._filepath, "w") + out_file.write(self._output) + out_file.close() + + +def generate_from_specification(primary_specification_filepath=None, + supplemental_specification_filepaths=[], + concatenate_output=False, + output_dirpath=None, + force_output=False, + framework_name=""): + + def load_specification(protocol, filepath, isSupplemental=False): + try: + with open(filepath, "r") as input_file: + parsed_json = json.load(input_file) + protocol.parse_specification(parsed_json, isSupplemental) + except ValueError as e: + raise Exception("Error parsing valid JSON in file: " + filepath) + + protocol = models.Protocol(framework_name) + for specification in supplemental_specification_filepaths: + load_specification(protocol, specification, isSupplemental=True) + load_specification(protocol, primary_specification_filepath, isSupplemental=False) + + protocol.resolve_types() + + generators = [] + is_test = protocol.framework is Frameworks.Test + if is_test or protocol.framework is not Frameworks.WebInspector: + generators.append(CppAlternateBackendDispatcherHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(JSBackendCommandsGenerator(protocol, primary_specification_filepath)) + generators.append(CppBackendDispatcherHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(CppBackendDispatcherImplementationGenerator(protocol, primary_specification_filepath)) + generators.append(CppFrontendDispatcherHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(CppFrontendDispatcherImplementationGenerator(protocol, primary_specification_filepath)) + generators.append(CppProtocolTypesHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(CppProtocolTypesImplementationGenerator(protocol, primary_specification_filepath)) + if is_test or protocol.framework is Frameworks.WebInspector: + generators.append(ObjCBackendDispatcherHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCBackendDispatcherImplementationGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCConfigurationHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCConfigurationImplementationGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCConversionHelpersGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCFrontendDispatcherImplementationGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCHeaderGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCProtocolTypesImplementationGenerator(protocol, primary_specification_filepath)) + generators.append(ObjCInternalHeaderGenerator(protocol, primary_specification_filepath)) + + single_output_file_contents = [] + + for generator in generators: + output = generator.generate_output() + if concatenate_output: + single_output_file_contents.append('### Begin File: %s' % generator.output_filename()) + single_output_file_contents.append(output) + single_output_file_contents.append('### End File: %s' % generator.output_filename()) + single_output_file_contents.append('') + else: + output_file = IncrementalFileWriter(os.path.join(output_dirpath, generator.output_filename()), force_output) + output_file.write(output) + output_file.close() + + if concatenate_output: + filename = os.path.join(os.path.basename(primary_specification_filepath) + '-result') + output_file = IncrementalFileWriter(os.path.join(output_dirpath, filename), force_output) + output_file.write('\n'.join(single_output_file_contents)) + output_file.close() + + +if __name__ == '__main__': + allowed_framework_names = ['JavaScriptCore', 'WebInspector', 'Test'] + cli_parser = optparse.OptionParser(usage="usage: %prog [options] PrimaryProtocol.json [SupplementalProtocol.json ...]") + cli_parser.add_option("-o", "--outputDir", help="Directory where generated files should be written.") + cli_parser.add_option("--framework", type="choice", choices=allowed_framework_names, help="The framework that the primary specification belongs to.") + cli_parser.add_option("--force", action="store_true", help="Force output of generated scripts, even if nothing changed.") + cli_parser.add_option("-v", "--debug", action="store_true", help="Log extra output for debugging the generator itself.") + cli_parser.add_option("-t", "--test", action="store_true", help="Enable test mode. Use unique output filenames created by prepending the input filename.") + + options = None + + arg_options, arg_values = cli_parser.parse_args() + if (len(arg_values) < 1): + raise ParseException("At least one plain argument expected") + + if not arg_options.outputDir: + raise ParseException("Missing output directory") + + if arg_options.debug: + log.setLevel(logging.DEBUG) + + options = { + 'primary_specification_filepath': arg_values[0], + 'supplemental_specification_filepaths': arg_values[1:], + 'output_dirpath': arg_options.outputDir, + 'concatenate_output': arg_options.test, + 'framework_name': arg_options.framework, + 'force_output': arg_options.force + } + + try: + generate_from_specification(**options) + except (ParseException, TypecheckException) as e: + if arg_options.test: + log.error(e.message) + else: + raise # Force the build to fail. diff --git a/inspector/scripts/tests/commands-with-async-attribute.json b/inspector/scripts/tests/commands-with-async-attribute.json new file mode 100644 index 0000000..11262e8 --- /dev/null +++ b/inspector/scripts/tests/commands-with-async-attribute.json @@ -0,0 +1,109 @@ +{ + "domain": "Database", + "types": [ + { + "id": "DatabaseId", + "type": "integer", + "description": "Unique identifier of Database object." + }, + { + "id": "PrimaryColors", + "type": "string", + "enum": ["red", "green", "blue"] + }, + { + "id": "ColorList", + "type": "array", + "items": { "$ref": "PrimaryColors" } + }, + { + "id": "Error", + "type": "object", + "description": "Database error.", + "properties": [ + { "name": "message", "type": "string", "description": "Error message." }, + { "name": "code", "type": "integer", "description": "Error code." } + ] + } + ], + "commands": [ + { + "name": "executeSQLSyncOptionalReturnValues", + "parameters": [ + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "query", "type": "string" } + ], + "returns": [ + { "name": "columnNames", "type": "array", "optional": true, "items": { "type": "string" } }, + { "name": "notes", "type": "string", "optional": true }, + { "name": "timestamp", "type": "number", "optional": true }, + { "name": "values", "type": "object", "optional": true }, + { "name": "payload", "type": "any", "optional": true }, + { "name": "databaseId", "$ref": "DatabaseId", "optional": true }, + { "name": "sqlError", "$ref": "Error", "optional": true }, + { "name": "screenColor", "$ref": "PrimaryColors", "optional": true }, + { "name": "alternateColors", "$ref": "ColorList", "optional": true }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"], "optional": true } + ] + }, + { + "name": "executeSQLAsyncOptionalReturnValues", + "async": true, + "parameters": [ + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "query", "type": "string" } + ], + "returns": [ + { "name": "columnNames", "type": "array", "optional": true, "items": { "type": "string" } }, + { "name": "notes", "type": "string", "optional": true }, + { "name": "timestamp", "type": "number", "optional": true }, + { "name": "values", "type": "object", "optional": true }, + { "name": "payload", "type": "any", "optional": true }, + { "name": "databaseId", "$ref": "DatabaseId", "optional": true }, + { "name": "sqlError", "$ref": "Error", "optional": true }, + { "name": "screenColor", "$ref": "PrimaryColors", "optional": true }, + { "name": "alternateColors", "$ref": "ColorList", "optional": true }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"], "optional": true } + ] + }, + { + "name": "executeSQLSync", + "parameters": [ + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "query", "type": "string" } + ], + "returns": [ + { "name": "columnNames", "type": "array", "items": { "type": "string" } }, + { "name": "notes", "type": "string" }, + { "name": "timestamp", "type": "number" }, + { "name": "values", "type": "object" }, + { "name": "payload", "type": "any" }, + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "sqlError", "$ref": "Error" }, + { "name": "alternateColors", "$ref": "ColorList" }, + { "name": "screenColor", "$ref": "PrimaryColors" }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"] } + ] + }, + { + "name": "executeSQLAsync", + "async": true, + "parameters": [ + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "query", "type": "string" } + ], + "returns": [ + { "name": "columnNames", "type": "array", "items": { "type": "string" } }, + { "name": "notes", "type": "string" }, + { "name": "timestamp", "type": "number" }, + { "name": "values", "type": "object" }, + { "name": "payload", "type": "any" }, + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "sqlError", "$ref": "Error" }, + { "name": "screenColor", "$ref": "PrimaryColors" }, + { "name": "alternateColors", "$ref": "ColorList" }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"] } + ] + } + ] +} diff --git a/inspector/scripts/tests/commands-with-optional-call-return-parameters.json b/inspector/scripts/tests/commands-with-optional-call-return-parameters.json new file mode 100644 index 0000000..361d57d --- /dev/null +++ b/inspector/scripts/tests/commands-with-optional-call-return-parameters.json @@ -0,0 +1,85 @@ +{ + "domain": "Database", + "types": [ + { + "id": "DatabaseId", + "type": "integer", + "description": "Unique identifier of Database object." + }, + { + "id": "PrimaryColors", + "type": "string", + "enum": ["red", "green", "blue"] + }, + { + "id": "ColorList", + "type": "array", + "items": { "$ref": "PrimaryColors" } + }, + { + "id": "Error", + "type": "object", + "description": "Database error.", + "properties": [ + { "name": "message", "type": "string", "description": "Error message." }, + { "name": "code", "type": "integer", "description": "Error code." } + ] + } + ], + "commands": [ + { + "name": "executeAllOptionalParameters", + "parameters": [ + { "name": "columnNames", "type": "array", "optional": true, "items": { "type": "string" } }, + { "name": "notes", "type": "string", "optional": true }, + { "name": "timestamp", "type": "number", "optional": true }, + { "name": "values", "type": "object", "optional": true }, + { "name": "payload", "type": "any", "optional": true }, + { "name": "databaseId", "$ref": "DatabaseId", "optional": true }, + { "name": "sqlError", "$ref": "Error", "optional": true }, + { "name": "screenColor", "$ref": "PrimaryColors", "optional": true }, + { "name": "alternateColors", "$ref": "ColorList", "optional": true }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"], "optional": true } + ], + "returns": [ + { "name": "columnNames", "type": "array", "optional": true, "items": { "type": "string" } }, + { "name": "notes", "type": "string", "optional": true }, + { "name": "timestamp", "type": "number", "optional": true }, + { "name": "values", "type": "object", "optional": true }, + { "name": "payload", "type": "any", "optional": true }, + { "name": "databaseId", "$ref": "DatabaseId", "optional": true }, + { "name": "sqlError", "$ref": "Error", "optional": true }, + { "name": "screenColor", "$ref": "PrimaryColors", "optional": true }, + { "name": "alternateColors", "$ref": "ColorList", "optional": true }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"], "optional": true } + ] + }, + { + "name": "executeNoOptionalParameters", + "parameters": [ + { "name": "columnNames", "type": "array", "items": { "type": "string" } }, + { "name": "notes", "type": "string" }, + { "name": "timestamp", "type": "number" }, + { "name": "values", "type": "object" }, + { "name": "payload", "type": "any" }, + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "sqlError", "$ref": "Error" }, + { "name": "screenColor", "$ref": "PrimaryColors" }, + { "name": "alternateColors", "$ref": "ColorList" }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"] } + ], + "returns": [ + { "name": "columnNames", "type": "array", "items": { "type": "string" } }, + { "name": "notes", "type": "string" }, + { "name": "timestamp", "type": "number" }, + { "name": "values", "type": "object" }, + { "name": "payload", "type": "any" }, + { "name": "databaseId", "$ref": "DatabaseId" }, + { "name": "sqlError", "$ref": "Error" }, + { "name": "screenColor", "$ref": "PrimaryColors" }, + { "name": "alternateColors", "$ref": "ColorList" }, + { "name": "printColor", "type": "string", "enum": ["cyan", "magenta", "yellow", "black"] } + ] + } + ] +} diff --git a/inspector/scripts/tests/domains-with-varying-command-sizes.json b/inspector/scripts/tests/domains-with-varying-command-sizes.json new file mode 100644 index 0000000..94a8ecb --- /dev/null +++ b/inspector/scripts/tests/domains-with-varying-command-sizes.json @@ -0,0 +1,54 @@ +[ +{ + "domain": "Network1", + "commands": [ + { + "name": "loadResource1", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + } + ] +}, +{ + "domain": "Network2", + "types": [ + { + "id": "LoaderId", + "type": "string", + "description": "Unique loader identifier." + } + ] +}, +{ + "domain": "Network3", + "commands": [ + { + "name": "loadResource1", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + }, + { + "name": "loadResource2", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + }, + { + "name": "loadResource3", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + }, + { + "name": "loadResource4", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + }, + { + "name": "loadResource5", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + }, + { + "name": "loadResource6", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + }, + { + "name": "loadResource7", + "description": "Loads a resource in the context of a frame on the inspected page without cross origin checks." + } + ] +} +] diff --git a/inspector/scripts/tests/enum-values.json b/inspector/scripts/tests/enum-values.json new file mode 100644 index 0000000..cdad61d --- /dev/null +++ b/inspector/scripts/tests/enum-values.json @@ -0,0 +1,35 @@ +{"domains":[ +{ + "domain": "TypeDomain", + "types": [ + { + "id": "TypeDomainEnum", + "type": "string", + "enum": ["shared", "red", "green", "blue"] + } + ] +}, +{ + "domain": "CommandDomain", + "commands": [ + { + "name": "commandWithEnumReturnValue", + "parameters": [], + "returns": [ + { "name": "returnValue", "type": "string", "enum": ["shared", "cyan", "magenta", "yellow"] } + ] + } + ] +}, +{ + "domain": "EventDomain", + "events": [ + { + "name": "eventWithEnumParameter", + "parameters": [ + { "name": "parameter", "type": "string", "enum": ["shared", "black", "white"] } + ] + } + ] +} +]} diff --git a/inspector/scripts/tests/events-with-optional-parameters.json b/inspector/scripts/tests/events-with-optional-parameters.json new file mode 100644 index 0000000..cabbf10 --- /dev/null +++ b/inspector/scripts/tests/events-with-optional-parameters.json @@ -0,0 +1,59 @@ +{ + "domain": "Database", + "types": [ + { + "id": "DatabaseId", + "type": "string", + "description": "Unique identifier of Database object." + }, + { + "id": "PrimaryColors", + "type": "string", + "values": ["red", "green", "blue"] + }, + { + "id": "ColorList", + "type": "array", + "items": { "$ref": "PrimaryColors" } + }, + { + "id": "Error", + "type": "object", + "description": "Database error.", + "properties": [ + { "name": "message", "type": "string", "description": "Error message." }, + { "name": "code", "type": "integer", "description": "Error code." } + ] + } + ], + "events": [ + { + "name": "didExecuteOptionalParameters", + "parameters": [ + { "name": "columnNames", "type": "array", "optional": true, "items": { "type": "string" } }, + { "name": "notes", "type": "string", "optional": true }, + { "name": "timestamp", "type": "number", "optional": true }, + { "name": "values", "type": "object", "optional": true }, + { "name": "payload", "type": "any", "optional": true }, + { "name": "sqlError", "$ref": "Error", "optional": true }, + { "name": "screenColor", "$ref": "PrimaryColors", "optional": true }, + { "name": "alternateColors", "$ref": "ColorList", "optional": true }, + { "name": "printColor", "type": "string", "values": ["cyan", "magenta", "yellow", "black"], "optional": true } + ] + }, + { + "name": "didExecuteNoOptionalParameters", + "parameters": [ + { "name": "columnNames", "type": "array", "items": { "type": "string" } }, + { "name": "notes", "type": "string" }, + { "name": "timestamp", "type": "number" }, + { "name": "values", "type": "object" }, + { "name": "payload", "type": "any" }, + { "name": "sqlError", "$ref": "Error" }, + { "name": "screenColor", "$ref": "PrimaryColors" }, + { "name": "alternateColors", "$ref": "ColorList" }, + { "name": "printColor", "type": "string", "values": ["cyan", "magenta", "yellow", "black"] } + ] + } + ] +} diff --git a/inspector/scripts/tests/expected/commands-with-async-attribute.json-result b/inspector/scripts/tests/expected/commands-with-async-attribute.json-result new file mode 100644 index 0000000..15d6a4d --- /dev/null +++ b/inspector/scripts/tests/expected/commands-with-async-attribute.json-result @@ -0,0 +1,1637 @@ +### Begin File: InspectorAlternateBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorAlternateBackendDispatchers_h +#define InspectorAlternateBackendDispatchers_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include "InspectorProtocolTypes.h" +#include <JavaScriptCore/InspectorBackendDispatcher.h> + +namespace Inspector { + +class AlternateBackendDispatcher { +public: + void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTF::move(dispatcher); } + BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); } +private: + RefPtr<BackendDispatcher> m_backendDispatcher; +}; + + +class AlternateDatabaseBackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~AlternateDatabaseBackendDispatcher() { } + virtual void executeSQLSyncOptionalReturnValues(long callId, int in_databaseId, const String& in_query) = 0; + virtual void executeSQLAsyncOptionalReturnValues(long callId, int in_databaseId, const String& in_query) = 0; + virtual void executeSQLSync(long callId, int in_databaseId, const String& in_query) = 0; + virtual void executeSQLAsync(long callId, int in_databaseId, const String& in_query) = 0; +}; + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(InspectorAlternateBackendDispatchers_h) +### End File: InspectorAlternateBackendDispatchers.h + +### Begin File: InspectorBackendCommands.js +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +// Database. +InspectorBackend.registerDatabaseDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Database"); +InspectorBackend.registerEnum("Database.PrimaryColors", {Red: "red", Green: "green", Blue: "blue"}); +InspectorBackend.registerCommand("Database.executeSQLSyncOptionalReturnValues", [{"name": "databaseId", "type": "number", "optional": false}, {"name": "query", "type": "string", "optional": false}], ["columnNames", "notes", "timestamp", "values", "payload", "databaseId", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.registerCommand("Database.executeSQLAsyncOptionalReturnValues", [{"name": "databaseId", "type": "number", "optional": false}, {"name": "query", "type": "string", "optional": false}], ["columnNames", "notes", "timestamp", "values", "payload", "databaseId", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.registerCommand("Database.executeSQLSync", [{"name": "databaseId", "type": "number", "optional": false}, {"name": "query", "type": "string", "optional": false}], ["columnNames", "notes", "timestamp", "values", "payload", "databaseId", "sqlError", "alternateColors", "screenColor", "printColor"]); +InspectorBackend.registerCommand("Database.executeSQLAsync", [{"name": "databaseId", "type": "number", "optional": false}, {"name": "query", "type": "string", "optional": false}], ["columnNames", "notes", "timestamp", "values", "payload", "databaseId", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.activateDomain("Database"); +### End File: InspectorBackendCommands.js + +### Begin File: InspectorBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorBackendDispatchers_h +#define InspectorBackendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorBackendDispatcher.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + +typedef String ErrorString; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +class AlternateDatabaseBackendDispatcher; +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +class DatabaseBackendDispatcherHandler { +public: + // Named after parameter 'screenColor' while generating command/event executeSQLSyncOptionalReturnValues. + enum class ScreenColor { + Red = 0, + Green = 1, + Blue = 2, + }; // enum class ScreenColor + // Named after parameter 'printColor' while generating command/event executeSQLSyncOptionalReturnValues. + enum class PrintColor { + Cyan = 3, + Magenta = 4, + Yellow = 5, + Black = 6, + }; // enum class PrintColor + virtual void executeSQLSyncOptionalReturnValues(ErrorString&, int in_databaseId, const String& in_query, RefPtr<Inspector::Protocol::Array<String>>& opt_out_columnNames, Inspector::Protocol::OptOutput<String>* opt_out_notes, Inspector::Protocol::OptOutput<double>* opt_out_timestamp, Inspector::Protocol::OptOutput<Inspector::InspectorObject>* opt_out_values, Inspector::Protocol::OptOutput<Inspector::InspectorValue>* opt_out_payload, Inspector::Protocol::OptOutput<int>* opt_out_databaseId, RefPtr<Inspector::Protocol::Database::Error>& opt_out_sqlError, Inspector::Protocol::Database::PrimaryColors* opt_out_screenColor, RefPtr<Inspector::Protocol::Database::ColorList>& opt_out_alternateColors, DatabaseBackendDispatcherHandler::PrintColor* opt_out_printColor) = 0; + class ExecuteSQLAsyncOptionalReturnValuesCallback : public BackendDispatcher::CallbackBase { + public: + ExecuteSQLAsyncOptionalReturnValuesCallback(Ref<BackendDispatcher>&&, int id); + void sendSuccess(RefPtr<Inspector::Protocol::Array<String>>&& columnNames, Inspector::Protocol::OptOutput<String>* notes, Inspector::Protocol::OptOutput<double>* timestamp, Inspector::Protocol::OptOutput<Inspector::InspectorObject>* values, Inspector::Protocol::OptOutput<Inspector::InspectorValue>* payload, Inspector::Protocol::OptOutput<int>* databaseId, RefPtr<Inspector::Protocol::Database::Error>&& sqlError, Inspector::Protocol::OptOutput<String>* screenColor, RefPtr<Inspector::Protocol::Database::ColorList>&& alternateColors, Inspector::Protocol::OptOutput<String>* printColor); + }; + virtual void executeSQLAsyncOptionalReturnValues(ErrorString&, int in_databaseId, const String& in_query, Ref<ExecuteSQLAsyncOptionalReturnValuesCallback>&& callback) = 0; + virtual void executeSQLSync(ErrorString&, int in_databaseId, const String& in_query, RefPtr<Inspector::Protocol::Array<String>>& out_columnNames, String* out_notes, double* out_timestamp, Inspector::InspectorObject* out_values, Inspector::InspectorValue* out_payload, int* out_databaseId, RefPtr<Inspector::Protocol::Database::Error>& out_sqlError, RefPtr<Inspector::Protocol::Database::ColorList>& out_alternateColors, Inspector::Protocol::Database::PrimaryColors* out_screenColor, DatabaseBackendDispatcherHandler::PrintColor* out_printColor) = 0; + class ExecuteSQLAsyncCallback : public BackendDispatcher::CallbackBase { + public: + ExecuteSQLAsyncCallback(Ref<BackendDispatcher>&&, int id); + void sendSuccess(RefPtr<Inspector::Protocol::Array<String>>&& columnNames, const String& notes, double timestamp, Inspector::InspectorObject values, Inspector::InspectorValue payload, int databaseId, RefPtr<Inspector::Protocol::Database::Error>&& sqlError, const String& screenColor, RefPtr<Inspector::Protocol::Database::ColorList>&& alternateColors, const String& printColor); + }; + virtual void executeSQLAsync(ErrorString&, int in_databaseId, const String& in_query, Ref<ExecuteSQLAsyncCallback>&& callback) = 0; +protected: + virtual ~DatabaseBackendDispatcherHandler(); +}; + +class DatabaseBackendDispatcher final : public SupplementalBackendDispatcher { +public: + static Ref<DatabaseBackendDispatcher> create(BackendDispatcher*, DatabaseBackendDispatcherHandler*); + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) override; +private: + void executeSQLSyncOptionalReturnValues(long callId, const InspectorObject& message); + void executeSQLAsyncOptionalReturnValues(long callId, const InspectorObject& message); + void executeSQLSync(long callId, const InspectorObject& message); + void executeSQLAsync(long callId, const InspectorObject& message); +private: + DatabaseBackendDispatcher(BackendDispatcher&, DatabaseBackendDispatcherHandler*); + DatabaseBackendDispatcherHandler* m_agent; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +public: + void setAlternateDispatcher(AlternateDatabaseBackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; } +private: + AlternateDatabaseBackendDispatcher* m_alternateDispatcher; +#endif +}; + +} // namespace Inspector + +#endif // !defined(InspectorBackendDispatchers_h) +### End File: InspectorBackendDispatchers.h + +### Begin File: InspectorBackendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorBackendDispatchers.h" + +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/CString.h> + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "InspectorAlternateBackendDispatchers.h" +#endif + +namespace Inspector { + +DatabaseBackendDispatcherHandler::~DatabaseBackendDispatcherHandler() { } + +Ref<DatabaseBackendDispatcher> DatabaseBackendDispatcher::create(BackendDispatcher* backendDispatcher, DatabaseBackendDispatcherHandler* agent) +{ + return adoptRef(*new DatabaseBackendDispatcher(*backendDispatcher, agent)); +} + +DatabaseBackendDispatcher::DatabaseBackendDispatcher(BackendDispatcher& backendDispatcher, DatabaseBackendDispatcherHandler* agent) + : SupplementalBackendDispatcher(backendDispatcher) + , m_agent(agent) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_alternateDispatcher(nullptr) +#endif +{ + m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("Database"), this); +} + +void DatabaseBackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<DatabaseBackendDispatcher> protect(*this); + + if (method == "executeSQLSyncOptionalReturnValues") + executeSQLSyncOptionalReturnValues(callId, message); + else if (method == "executeSQLAsyncOptionalReturnValues") + executeSQLAsyncOptionalReturnValues(callId, message); + else if (method == "executeSQLSync") + executeSQLSync(callId, message); + else if (method == "executeSQLAsync") + executeSQLAsync(callId, message); + else + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\'', "Database", '.', method, "' was not found")); +} + +void DatabaseBackendDispatcher::executeSQLSyncOptionalReturnValues(long callId, const InspectorObject& message) +{ + auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); + int in_databaseId = BackendDispatcher::getInteger(paramsContainer.get(), ASCIILiteral("databaseId"), nullptr, protocolErrors.get()); + String in_query = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("query"), nullptr, protocolErrors.get()); + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method '%s' can't be processed", "Database.executeSQLSyncOptionalReturnValues"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->executeSQLSyncOptionalReturnValues(callId, in_databaseId, in_query); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + RefPtr<Inspector::Protocol::Array<String>> out_columnNames; + Inspector::Protocol::OptOutput<String> out_notes; + Inspector::Protocol::OptOutput<double> out_timestamp; + Inspector::Protocol::OptOutput<Inspector::InspectorObject> out_values; + Inspector::Protocol::OptOutput<Inspector::InspectorValue> out_payload; + Inspector::Protocol::OptOutput<Inspector::Protocol::Database::DatabaseId> out_databaseId; + RefPtr<Inspector::Protocol::Database::Error> out_sqlError; + Inspector::Protocol::Database::PrimaryColors out_screenColor; + RefPtr<Inspector::Protocol::Database::ColorList> out_alternateColors; + DatabaseBackendDispatcherHandler::PrintColor out_printColor; + m_agent->executeSQLSyncOptionalReturnValues(error, in_databaseId, in_query, out_columnNames, &out_notes, &out_timestamp, out_values, &out_payload, &out_databaseId, out_sqlError, &out_screenColor, out_alternateColors, &out_printColor); + + if (!error.length()) { + if (out_columnNames) + result->setArray(ASCIILiteral("columnNames"), out_columnNames); + if (out_notes.isAssigned()) + result->setString(ASCIILiteral("notes"), out_notes.getValue()); + if (out_timestamp.isAssigned()) + result->setDouble(ASCIILiteral("timestamp"), out_timestamp.getValue()); + if (out_values.isAssigned()) + result->setObject(ASCIILiteral("values"), out_values.getValue()); + if (out_payload.isAssigned()) + result->setValue(ASCIILiteral("payload"), out_payload.getValue()); + if (out_databaseId.isAssigned()) + result->setInteger(ASCIILiteral("databaseId"), out_databaseId.getValue()); + if (out_sqlError) + result->setObject(ASCIILiteral("sqlError"), out_sqlError); + if (out_screenColor.isAssigned()) + result->setString(ASCIILiteral("screenColor"), out_screenColor.getValue()); + if (out_alternateColors) + result->setArray(ASCIILiteral("alternateColors"), out_alternateColors); + if (out_printColor.isAssigned()) + result->setString(ASCIILiteral("printColor"), out_printColor.getValue()); + } + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +DatabaseBackendDispatcherHandler::ExecuteSQLAsyncOptionalReturnValuesCallback::ExecuteSQLAsyncOptionalReturnValuesCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTF::move(backendDispatcher), id) { } + +void DatabaseBackendDispatcherHandler::ExecuteSQLAsyncOptionalReturnValuesCallback::sendSuccess(RefPtr<Inspector::Protocol::Array<String>>&& columnNames, Inspector::Protocol::OptOutput<String>* notes, Inspector::Protocol::OptOutput<double>* timestamp, Inspector::Protocol::OptOutput<Inspector::InspectorObject>* values, Inspector::Protocol::OptOutput<Inspector::InspectorValue>* payload, Inspector::Protocol::OptOutput<int>* databaseId, RefPtr<Inspector::Protocol::Database::Error>&& sqlError, Inspector::Protocol::OptOutput<String>* screenColor, RefPtr<Inspector::Protocol::Database::ColorList>&& alternateColors, Inspector::Protocol::OptOutput<String>* printColor) +{ + Ref<InspectorObject> jsonMessage = InspectorObject::create(); + if (columnNames) + jsonMessage->setArray(ASCIILiteral("columnNames"), columnNames); + if (notes.isAssigned()) + jsonMessage->setString(ASCIILiteral("notes"), notes.getValue()); + if (timestamp.isAssigned()) + jsonMessage->setDouble(ASCIILiteral("timestamp"), timestamp.getValue()); + if (values.isAssigned()) + jsonMessage->setObject(ASCIILiteral("values"), values.getValue()); + if (payload.isAssigned()) + jsonMessage->setValue(ASCIILiteral("payload"), payload.getValue()); + if (databaseId.isAssigned()) + jsonMessage->setInteger(ASCIILiteral("databaseId"), databaseId.getValue()); + if (sqlError) + jsonMessage->setObject(ASCIILiteral("sqlError"), sqlError); + if (screenColor.isAssigned()) + jsonMessage->setString(ASCIILiteral("screenColor"), screenColor.getValue()); + if (alternateColors) + jsonMessage->setArray(ASCIILiteral("alternateColors"), alternateColors); + if (printColor.isAssigned()) + jsonMessage->setString(ASCIILiteral("printColor"), printColor.getValue()); + sendIfActive(WTF::move(jsonMessage), ErrorString()); +} + +void DatabaseBackendDispatcher::executeSQLAsyncOptionalReturnValues(long callId, const InspectorObject& message) +{ + auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); + int in_databaseId = BackendDispatcher::getInteger(paramsContainer.get(), ASCIILiteral("databaseId"), nullptr, protocolErrors.get()); + String in_query = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("query"), nullptr, protocolErrors.get()); + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method '%s' can't be processed", "Database.executeSQLAsyncOptionalReturnValues"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->executeSQLAsyncOptionalReturnValues(callId, in_databaseId, in_query); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + Ref<DatabaseBackendDispatcherHandler::ExecuteSQLAsyncOptionalReturnValuesCallback> callback = adoptRef(*new DatabaseBackendDispatcherHandler::ExecuteSQLAsyncOptionalReturnValuesCallback(m_backendDispatcher.copyRef(), callId)); + m_agent->executeSQLAsyncOptionalReturnValues(error, in_databaseId, in_query, callback.copyRef()); + + if (error.length()) { + callback->disable(); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::ServerError, error); + return; + } +} + +void DatabaseBackendDispatcher::executeSQLSync(long callId, const InspectorObject& message) +{ + auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); + int in_databaseId = BackendDispatcher::getInteger(paramsContainer.get(), ASCIILiteral("databaseId"), nullptr, protocolErrors.get()); + String in_query = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("query"), nullptr, protocolErrors.get()); + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method '%s' can't be processed", "Database.executeSQLSync"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->executeSQLSync(callId, in_databaseId, in_query); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + RefPtr<Inspector::Protocol::Array<String>> out_columnNames; + String out_notes; + double out_timestamp; + Inspector::InspectorObject out_values; + Inspector::InspectorValue out_payload; + Inspector::Protocol::Database::DatabaseId out_databaseId; + RefPtr<Inspector::Protocol::Database::Error> out_sqlError; + RefPtr<Inspector::Protocol::Database::ColorList> out_alternateColors; + Inspector::Protocol::Database::PrimaryColors out_screenColor; + DatabaseBackendDispatcherHandler::PrintColor out_printColor; + m_agent->executeSQLSync(error, in_databaseId, in_query, out_columnNames, &out_notes, &out_timestamp, out_values, &out_payload, &out_databaseId, out_sqlError, out_alternateColors, &out_screenColor, &out_printColor); + + if (!error.length()) { + result->setArray(ASCIILiteral("columnNames"), out_columnNames); + result->setString(ASCIILiteral("notes"), out_notes); + result->setDouble(ASCIILiteral("timestamp"), out_timestamp); + result->setObject(ASCIILiteral("values"), out_values); + result->setValue(ASCIILiteral("payload"), out_payload); + result->setInteger(ASCIILiteral("databaseId"), out_databaseId); + result->setObject(ASCIILiteral("sqlError"), out_sqlError); + result->setArray(ASCIILiteral("alternateColors"), out_alternateColors); + result->setString(ASCIILiteral("screenColor"), Inspector::Protocol::getEnumConstantValue(out_screenColor)); + result->setString(ASCIILiteral("printColor"), Inspector::Protocol::getEnumConstantValue(out_printColor)); + } + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +DatabaseBackendDispatcherHandler::ExecuteSQLAsyncCallback::ExecuteSQLAsyncCallback(Ref<BackendDispatcher>&& backendDispatcher, int id) : BackendDispatcher::CallbackBase(WTF::move(backendDispatcher), id) { } + +void DatabaseBackendDispatcherHandler::ExecuteSQLAsyncCallback::sendSuccess(RefPtr<Inspector::Protocol::Array<String>>&& columnNames, const String& notes, double timestamp, Inspector::InspectorObject values, Inspector::InspectorValue payload, int databaseId, RefPtr<Inspector::Protocol::Database::Error>&& sqlError, const String& screenColor, RefPtr<Inspector::Protocol::Database::ColorList>&& alternateColors, const String& printColor) +{ + Ref<InspectorObject> jsonMessage = InspectorObject::create(); + jsonMessage->setArray(ASCIILiteral("columnNames"), columnNames); + jsonMessage->setString(ASCIILiteral("notes"), notes); + jsonMessage->setDouble(ASCIILiteral("timestamp"), timestamp); + jsonMessage->setObject(ASCIILiteral("values"), values); + jsonMessage->setValue(ASCIILiteral("payload"), payload); + jsonMessage->setInteger(ASCIILiteral("databaseId"), databaseId); + jsonMessage->setObject(ASCIILiteral("sqlError"), sqlError); + jsonMessage->setString(ASCIILiteral("screenColor"), Inspector::Protocol::getEnumConstantValue(screenColor)); + jsonMessage->setArray(ASCIILiteral("alternateColors"), alternateColors); + jsonMessage->setString(ASCIILiteral("printColor"), Inspector::Protocol::getEnumConstantValue(printColor)); + sendIfActive(WTF::move(jsonMessage), ErrorString()); +} + +void DatabaseBackendDispatcher::executeSQLAsync(long callId, const InspectorObject& message) +{ + auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); + int in_databaseId = BackendDispatcher::getInteger(paramsContainer.get(), ASCIILiteral("databaseId"), nullptr, protocolErrors.get()); + String in_query = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("query"), nullptr, protocolErrors.get()); + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method '%s' can't be processed", "Database.executeSQLAsync"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->executeSQLAsync(callId, in_databaseId, in_query); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + Ref<DatabaseBackendDispatcherHandler::ExecuteSQLAsyncCallback> callback = adoptRef(*new DatabaseBackendDispatcherHandler::ExecuteSQLAsyncCallback(m_backendDispatcher.copyRef(), callId)); + m_agent->executeSQLAsync(error, in_databaseId, in_query, callback.copyRef()); + + if (error.length()) { + callback->disable(); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::ServerError, error); + return; + } +} + +} // namespace Inspector + +### End File: InspectorBackendDispatchers.cpp + +### Begin File: InspectorFrontendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorFrontendDispatchers_h +#define InspectorFrontendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + + + +} // namespace Inspector + +#endif // !defined(InspectorFrontendDispatchers_h) +### End File: InspectorFrontendDispatchers.h + +### Begin File: InspectorFrontendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorFrontendDispatchers.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +} // namespace Inspector + +### End File: InspectorFrontendDispatchers.cpp + +### Begin File: InspectorProtocolObjects.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorProtocolObjects_h +#define InspectorProtocolObjects_h + +#include <inspector/InspectorProtocolTypes.h> +#include <wtf/Assertions.h> + +namespace Inspector { + + + +namespace Protocol { + +// Forward declarations. +namespace Database { +class Error; +enum class PrimaryColors; +} // Database +// End of forward declarations. + + +// Typedefs. +namespace Database { +/* Unique identifier of Database object. */ +typedef int DatabaseId; +typedef Inspector::Protocol::Array<Inspector::Protocol::Database::PrimaryColors> ColorList; +} // Database +// End of typedefs. + +String getEnumConstantValue(int code); + +template<typename T> String getEnumConstantValue(T enumValue) +{ + return getEnumConstantValue(static_cast<int>(enumValue)); +} + +namespace Database { +/* */ +enum class PrimaryColors { + Red = 0, + Green = 1, + Blue = 2, +}; // enum class PrimaryColors +/* Database error. */ +class Error : public Inspector::InspectorObjectBase { +public: + enum { + NoFieldsSet = 0, + MessageSet = 1 << 0, + CodeSet = 1 << 1, + AllFieldsSet = (MessageSet | CodeSet) + }; + + template<int STATE> + class Builder { + private: + RefPtr<InspectorObject> m_result; + + template<int STEP> Builder<STATE | STEP>& castState() + { + return *reinterpret_cast<Builder<STATE | STEP>*>(this); + } + + Builder(Ref</*Error*/InspectorObject>&& object) + : m_result(WTF::move(object)) + { + COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state); + } + friend class Error; + public: + + Builder<STATE | MessageSet>& setMessage(const String& value) + { + COMPILE_ASSERT(!(STATE & MessageSet), property_message_already_set); + m_result->setString(ASCIILiteral("message"), value); + return castState<MessageSet>(); + } + + Builder<STATE | CodeSet>& setCode(int value) + { + COMPILE_ASSERT(!(STATE & CodeSet), property_code_already_set); + m_result->setInteger(ASCIILiteral("code"), value); + return castState<CodeSet>(); + } + + Ref<Error> release() + { + COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready); + COMPILE_ASSERT(sizeof(Error) == sizeof(InspectorObject), cannot_cast); + + Ref<InspectorObject> result = m_result.releaseNonNull(); + return WTF::move(*reinterpret_cast<Ref<Error>*>(&result)); + } + }; + + /* + * Synthetic constructor: + * Ref<Error> result = Error::create() + * .setMessage(...) + * .setCode(...) + * .release(); + */ + static Builder<NoFieldsSet> create() + { + return Builder<NoFieldsSet>(InspectorObject::create()); + } +}; + +} // Database + + + +} // namespace Protocol + +} // namespace Inspector + +#endif // !defined(InspectorProtocolObjects_h) +### End File: InspectorProtocolObjects.h + +### Begin File: InspectorProtocolObjects.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorProtocolObjects.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +namespace Protocol { + +static const char* const enum_constant_values[] = { + "red", + "green", + "blue", + "cyan", + "magenta", + "yellow", + "black", +}; + +String getEnumConstantValue(int code) { + return enum_constant_values[code]; +} + + + +} // namespace Protocol + +} // namespace Inspector + +### End File: InspectorProtocolObjects.cpp + +### Begin File: RWIProtocolBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#include <wtf/RetainPtr.h> + +@protocol RWIProtocolDatabaseDomainHandler; + +namespace Inspector { + + +class ObjCInspectorDatabaseBackendDispatcher final : public AlternateDatabaseBackendDispatcher { +public: + ObjCInspectorDatabaseBackendDispatcher(id<RWIProtocolDatabaseDomainHandler> handler) { m_delegate = handler; } + virtual void executeSQLSyncOptionalReturnValues(long callId, int in_databaseId, const String& in_query) override; + virtual void executeSQLAsyncOptionalReturnValues(long callId, int in_databaseId, const String& in_query) override; + virtual void executeSQLSync(long callId, int in_databaseId, const String& in_query) override; + virtual void executeSQLAsync(long callId, int in_databaseId, const String& in_query) override; +private: + RetainPtr<id<RWIProtocolDatabaseDomainHandler>> m_delegate; +}; + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.h + +### Begin File: RWIProtocolConfiguration.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolConfiguration.h" + +#import "RWIProtocolInternal.h" +#import "RWIProtocolBackendDispatchers.h" +#import <JavaScriptCore/AlternateDispatchableAgent.h> +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#import <JavaScriptCore/InspectorBackendDispatchers.h> + +using namespace Inspector; + +@implementation RWIProtocolConfiguration +{ + AugmentableInspectorController* _controller; + id<RWIProtocolDatabaseDomainHandler> _databaseHandler; +} + +- (instancetype)initWithController:(AugmentableInspectorController*)controller +{ + self = [super init]; + if (!self) + return nil; + ASSERT(controller); + _controller = controller; + return self; +} + +- (void)dealloc +{ + [_databaseHandler release]; + [super dealloc]; +} + +- (void)setDatabaseHandler:(id<RWIProtocolDatabaseDomainHandler>)handler +{ + if (handler == _databaseHandler) + return; + + [_databaseHandler release]; + _databaseHandler = [handler retain]; + + auto alternateDispatcher = std::make_unique<ObjCInspectorDatabaseBackendDispatcher>(handler); + auto alternateAgent = std::make_unique<AlternateDispatchableAgent<DatabaseBackendDispatcher, AlternateDatabaseBackendDispatcher>>(ASCIILiteral("Database"), WTF::move(alternateDispatcher)); + _controller->appendExtraAgent(WTF::move(alternateAgent)); +} + +- (id<RWIProtocolDatabaseDomainHandler>)databaseHandler +{ + return _databaseHandler; +} + +@end + + +### End File: RWIProtocolConfiguration.mm + +### Begin File: RWIProtocolConfiguration.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" + +__attribute__((visibility ("default"))) +@interface RWIProtocolConfiguration : NSObject +@property (nonatomic, retain, setter=setDatabaseHandler:) id<RWIProtocolDatabaseDomainHandler> databaseHandler; +@end + + +### End File: RWIProtocolConfiguration.h + +### Begin File: RWIProtocolBackendDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolBackendDispatchers.h" + +#include "RWIProtocolInternal.h" +#include "RWIProtocolEnumConversionHelpers.h" +#include <JavaScriptCore/InspectorFrontendChannel.h> +#include <JavaScriptCore/InspectorValues.h> + +namespace Inspector { + +void ObjCInspectorDatabaseBackendDispatcher::executeSQLSyncOptionalReturnValues(long callId, int in_databaseId, const String& in_query) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(NSArray/*<NSString>*/ **columnNames, NSString **notes, double *timestamp, RWIProtocolJSONObject **values, RWIProtocolJSONObject **payload, int *databaseId, RWIProtocolDatabaseError **sqlError, RWIProtocolDatabasePrimaryColors *screenColor, NSArray/*<NSString>*/ **alternateColors, RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColor *printColor) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(columnNames, @"columnNames"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(notes, @"notes"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(values, @"values"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(payload, @"payload"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(sqlError, @"sqlError"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(alternateColors, @"alternateColors"); + if (columnNames) + resultObject->setArray(ASCIILiteral("columnNames"), inspectorStringArray(*columnNames)); + if (notes) + resultObject->setString(ASCIILiteral("notes"), *notes); + if (timestamp) + resultObject->setDouble(ASCIILiteral("timestamp"), *timestamp); + if (values) + resultObject->setObject(ASCIILiteral("values"), [*values toInspectorObject]); + if (payload) + resultObject->setValue(ASCIILiteral("payload"), [*payload toInspectorObject]); + if (databaseId) + resultObject->setInteger(ASCIILiteral("databaseId"), *databaseId); + if (sqlError) + resultObject->setObject(ASCIILiteral("sqlError"), [*sqlError toInspectorObject]); + if (screenColor) + resultObject->setString(ASCIILiteral("screenColor"), toProtocolString(*screenColor)); + if (alternateColors) + resultObject->setArray(ASCIILiteral("alternateColors"), inspectorStringArray(*alternateColors)); + if (printColor) + resultObject->setString(ASCIILiteral("printColor"), toProtocolString(*printColor)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + int o_in_databaseId = in_databaseId; + NSString *o_in_query = in_query; + + [m_delegate executeSQLSyncOptionalReturnValuesWithErrorCallback:errorCallback successCallback:successCallback databaseId:o_in_databaseId query:o_in_query]; +} + +void ObjCInspectorDatabaseBackendDispatcher::executeSQLAsyncOptionalReturnValues(long callId, int in_databaseId, const String& in_query) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(NSArray/*<NSString>*/ **columnNames, NSString **notes, double *timestamp, RWIProtocolJSONObject **values, RWIProtocolJSONObject **payload, int *databaseId, RWIProtocolDatabaseError **sqlError, RWIProtocolDatabasePrimaryColors *screenColor, NSArray/*<NSString>*/ **alternateColors, RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColor *printColor) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(columnNames, @"columnNames"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(notes, @"notes"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(values, @"values"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(payload, @"payload"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(sqlError, @"sqlError"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(alternateColors, @"alternateColors"); + if (columnNames) + resultObject->setArray(ASCIILiteral("columnNames"), inspectorStringArray(*columnNames)); + if (notes) + resultObject->setString(ASCIILiteral("notes"), *notes); + if (timestamp) + resultObject->setDouble(ASCIILiteral("timestamp"), *timestamp); + if (values) + resultObject->setObject(ASCIILiteral("values"), [*values toInspectorObject]); + if (payload) + resultObject->setValue(ASCIILiteral("payload"), [*payload toInspectorObject]); + if (databaseId) + resultObject->setInteger(ASCIILiteral("databaseId"), *databaseId); + if (sqlError) + resultObject->setObject(ASCIILiteral("sqlError"), [*sqlError toInspectorObject]); + if (screenColor) + resultObject->setString(ASCIILiteral("screenColor"), toProtocolString(*screenColor)); + if (alternateColors) + resultObject->setArray(ASCIILiteral("alternateColors"), inspectorStringArray(*alternateColors)); + if (printColor) + resultObject->setString(ASCIILiteral("printColor"), toProtocolString(*printColor)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + int o_in_databaseId = in_databaseId; + NSString *o_in_query = in_query; + + [m_delegate executeSQLAsyncOptionalReturnValuesWithErrorCallback:errorCallback successCallback:successCallback databaseId:o_in_databaseId query:o_in_query]; +} + +void ObjCInspectorDatabaseBackendDispatcher::executeSQLSync(long callId, int in_databaseId, const String& in_query) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(NSArray/*<NSString>*/ *columnNames, NSString *notes, double timestamp, RWIProtocolJSONObject *values, RWIProtocolJSONObject *payload, int databaseId, RWIProtocolDatabaseError *sqlError, NSArray/*<NSString>*/ *alternateColors, RWIProtocolDatabasePrimaryColors screenColor, RWIProtocolDatabaseExecuteSQLSyncPrintColor printColor) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(columnNames, @"columnNames"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(notes, @"notes"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(values, @"values"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(payload, @"payload"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(sqlError, @"sqlError"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(alternateColors, @"alternateColors"); + resultObject->setArray(ASCIILiteral("columnNames"), inspectorStringArray(columnNames)); + resultObject->setString(ASCIILiteral("notes"), notes); + resultObject->setDouble(ASCIILiteral("timestamp"), timestamp); + resultObject->setObject(ASCIILiteral("values"), [values toInspectorObject]); + resultObject->setValue(ASCIILiteral("payload"), [payload toInspectorObject]); + resultObject->setInteger(ASCIILiteral("databaseId"), databaseId); + resultObject->setObject(ASCIILiteral("sqlError"), [sqlError toInspectorObject]); + resultObject->setArray(ASCIILiteral("alternateColors"), inspectorStringArray(alternateColors)); + resultObject->setString(ASCIILiteral("screenColor"), toProtocolString(screenColor)); + resultObject->setString(ASCIILiteral("printColor"), toProtocolString(printColor)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + int o_in_databaseId = in_databaseId; + NSString *o_in_query = in_query; + + [m_delegate executeSQLSyncWithErrorCallback:errorCallback successCallback:successCallback databaseId:o_in_databaseId query:o_in_query]; +} + +void ObjCInspectorDatabaseBackendDispatcher::executeSQLAsync(long callId, int in_databaseId, const String& in_query) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(NSArray/*<NSString>*/ *columnNames, NSString *notes, double timestamp, RWIProtocolJSONObject *values, RWIProtocolJSONObject *payload, int databaseId, RWIProtocolDatabaseError *sqlError, RWIProtocolDatabasePrimaryColors screenColor, NSArray/*<NSString>*/ *alternateColors, RWIProtocolDatabaseExecuteSQLAsyncPrintColor printColor) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(columnNames, @"columnNames"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(notes, @"notes"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(values, @"values"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(payload, @"payload"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(sqlError, @"sqlError"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(alternateColors, @"alternateColors"); + resultObject->setArray(ASCIILiteral("columnNames"), inspectorStringArray(columnNames)); + resultObject->setString(ASCIILiteral("notes"), notes); + resultObject->setDouble(ASCIILiteral("timestamp"), timestamp); + resultObject->setObject(ASCIILiteral("values"), [values toInspectorObject]); + resultObject->setValue(ASCIILiteral("payload"), [payload toInspectorObject]); + resultObject->setInteger(ASCIILiteral("databaseId"), databaseId); + resultObject->setObject(ASCIILiteral("sqlError"), [sqlError toInspectorObject]); + resultObject->setString(ASCIILiteral("screenColor"), toProtocolString(screenColor)); + resultObject->setArray(ASCIILiteral("alternateColors"), inspectorStringArray(alternateColors)); + resultObject->setString(ASCIILiteral("printColor"), toProtocolString(printColor)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + int o_in_databaseId = in_databaseId; + NSString *o_in_query = in_query; + + [m_delegate executeSQLAsyncWithErrorCallback:errorCallback successCallback:successCallback databaseId:o_in_databaseId query:o_in_query]; +} + + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.mm + +### Begin File: RWIProtocolEnumConversionHelpers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocolArrayConversionHelpers.h" + +namespace Inspector { + +template<typename ObjCEnumType> +ObjCEnumType fromProtocolString(const String& value); + + +inline String toProtocolString(RWIProtocolDatabasePrimaryColors value) +{ + switch(value) { + case RWIProtocolDatabasePrimaryColorsRed: + return ASCIILiteral("red"); + case RWIProtocolDatabasePrimaryColorsGreen: + return ASCIILiteral("green"); + case RWIProtocolDatabasePrimaryColorsBlue: + return ASCIILiteral("blue"); + } +} + +template<> +inline RWIProtocolDatabasePrimaryColors fromProtocolString(const String& value) +{ + if (value == "red") + return RWIProtocolDatabasePrimaryColorsRed; + if (value == "green") + return RWIProtocolDatabasePrimaryColorsGreen; + if (value == "blue") + return RWIProtocolDatabasePrimaryColorsBlue; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabasePrimaryColorsRed; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorCyan; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorCyan; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteSQLSyncPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteSQLSyncPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteSQLSyncPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteSQLSyncPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteSQLSyncPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteSQLSyncPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteSQLSyncPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteSQLSyncPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteSQLSyncPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteSQLSyncPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteSQLSyncPrintColorCyan; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteSQLAsyncPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteSQLAsyncPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteSQLAsyncPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteSQLAsyncPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteSQLAsyncPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteSQLAsyncPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteSQLAsyncPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteSQLAsyncPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteSQLAsyncPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteSQLAsyncPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteSQLAsyncPrintColorCyan; +} + +} // namespace Inspector + +### End File: RWIProtocolEnumConversionHelpers.h + +### Begin File: RWIProtocolEventDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorFrontendChannel.h> +#import <JavaScriptCore/InspectorValues.h> + +using namespace Inspector; + + + + +### End File: RWIProtocolEventDispatchers.mm + +### Begin File: RWIProtocol.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import <Foundation/Foundation.h> + +#import <WebInspector/RWIProtocolJSONObject.h> + + +@class RWIProtocolDatabaseError; + + +typedef NS_ENUM(NSInteger, RWIProtocolDatabasePrimaryColors) { + RWIProtocolDatabasePrimaryColorsRed, + RWIProtocolDatabasePrimaryColorsGreen, + RWIProtocolDatabasePrimaryColorsBlue, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColor) { + RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorCyan, + RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorMagenta, + RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorYellow, + RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColorBlack, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColor) { + RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorCyan, + RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorMagenta, + RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorYellow, + RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColorBlack, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteSQLSyncPrintColor) { + RWIProtocolDatabaseExecuteSQLSyncPrintColorCyan, + RWIProtocolDatabaseExecuteSQLSyncPrintColorMagenta, + RWIProtocolDatabaseExecuteSQLSyncPrintColorYellow, + RWIProtocolDatabaseExecuteSQLSyncPrintColorBlack, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteSQLAsyncPrintColor) { + RWIProtocolDatabaseExecuteSQLAsyncPrintColorCyan, + RWIProtocolDatabaseExecuteSQLAsyncPrintColorMagenta, + RWIProtocolDatabaseExecuteSQLAsyncPrintColorYellow, + RWIProtocolDatabaseExecuteSQLAsyncPrintColorBlack, +}; + + +__attribute__((visibility ("default"))) +@interface RWIProtocolDatabaseError : RWIProtocolJSONObject +- (instancetype)initWithMessage:(NSString *)message code:(int)code; +/* required */ @property (nonatomic, copy) NSString *message; +/* required */ @property (nonatomic, assign) int code; +@end + +@protocol RWIProtocolDatabaseDomainHandler <NSObject> +@required +- (void)executeSQLSyncOptionalReturnValuesWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(NSArray/*<NSString>*/ **columnNames, NSString **notes, double *timestamp, RWIProtocolJSONObject **values, RWIProtocolJSONObject **payload, int *databaseId, RWIProtocolDatabaseError **sqlError, RWIProtocolDatabasePrimaryColors *screenColor, NSArray/*<NSString>*/ **alternateColors, RWIProtocolDatabaseExecuteSQLSyncOptionalReturnValuesPrintColor *printColor))successCallback databaseId:(int)databaseId query:(NSString *)query; +- (void)executeSQLAsyncOptionalReturnValuesWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(NSArray/*<NSString>*/ **columnNames, NSString **notes, double *timestamp, RWIProtocolJSONObject **values, RWIProtocolJSONObject **payload, int *databaseId, RWIProtocolDatabaseError **sqlError, RWIProtocolDatabasePrimaryColors *screenColor, NSArray/*<NSString>*/ **alternateColors, RWIProtocolDatabaseExecuteSQLAsyncOptionalReturnValuesPrintColor *printColor))successCallback databaseId:(int)databaseId query:(NSString *)query; +- (void)executeSQLSyncWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(NSArray/*<NSString>*/ *columnNames, NSString *notes, double timestamp, RWIProtocolJSONObject *values, RWIProtocolJSONObject *payload, int databaseId, RWIProtocolDatabaseError *sqlError, NSArray/*<NSString>*/ *alternateColors, RWIProtocolDatabasePrimaryColors screenColor, RWIProtocolDatabaseExecuteSQLSyncPrintColor printColor))successCallback databaseId:(int)databaseId query:(NSString *)query; +- (void)executeSQLAsyncWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(NSArray/*<NSString>*/ *columnNames, NSString *notes, double timestamp, RWIProtocolJSONObject *values, RWIProtocolJSONObject *payload, int databaseId, RWIProtocolDatabaseError *sqlError, RWIProtocolDatabasePrimaryColors screenColor, NSArray/*<NSString>*/ *alternateColors, RWIProtocolDatabaseExecuteSQLAsyncPrintColor printColor))successCallback databaseId:(int)databaseId query:(NSString *)query; +@end + + + + +### End File: RWIProtocol.h + +### Begin File: RWIProtocolTypes.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorValues.h> +#import <wtf/Assertions.h> + +using namespace Inspector; + + +@implementation RWIProtocolDatabaseError + +- (instancetype)initWithMessage:(NSString *)message code:(int)code; +{ + self = [super init]; + if (!self) + return nil; + + THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(message, @"message"); + + self.message = message; + self.code = code; + + return self; +} + +- (void)setMessage:(NSString *)message +{ + [super setString:message forKey:@"message"]; +} + +- (NSString *)message +{ + return [super stringForKey:@"message"]; +} + +- (void)setCode:(int)code +{ + [super setInteger:code forKey:@"code"]; +} + +- (int)code +{ + return [super integerForKey:@"code"]; +} + +@end + + +### End File: RWIProtocolTypes.mm + +### Begin File: RWIProtocolInternal.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-async-attribute.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" +#import "RWIProtocolJSONObjectInternal.h" +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorValues.h> + + + + +### End File: RWIProtocolInternal.h diff --git a/inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result b/inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result new file mode 100644 index 0000000..e349ecf --- /dev/null +++ b/inspector/scripts/tests/expected/commands-with-optional-call-return-parameters.json-result @@ -0,0 +1,1486 @@ +### Begin File: InspectorAlternateBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorAlternateBackendDispatchers_h +#define InspectorAlternateBackendDispatchers_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include "InspectorProtocolTypes.h" +#include <JavaScriptCore/InspectorBackendDispatcher.h> + +namespace Inspector { + +class AlternateBackendDispatcher { +public: + void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTF::move(dispatcher); } + BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); } +private: + RefPtr<BackendDispatcher> m_backendDispatcher; +}; + + +class AlternateDatabaseBackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~AlternateDatabaseBackendDispatcher() { } + virtual void executeAllOptionalParameters(long callId, const Inspector::InspectorArray* in_columnNames, const String* in_notes, const double* in_timestamp, const Inspector::InspectorObject* in_values, const Inspector::InspectorValue* in_payload, const int* in_databaseId, const Inspector::InspectorObject* in_sqlError, const String* in_screenColor, const Inspector::InspectorArray* in_alternateColors, const String* in_printColor) = 0; + virtual void executeNoOptionalParameters(long callId, const Inspector::InspectorArray& in_columnNames, const String& in_notes, double in_timestamp, const Inspector::InspectorObject& in_values, Inspector::InspectorValue in_payload, int in_databaseId, const Inspector::InspectorObject& in_sqlError, const String& in_screenColor, const Inspector::InspectorArray& in_alternateColors, const String& in_printColor) = 0; +}; + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(InspectorAlternateBackendDispatchers_h) +### End File: InspectorAlternateBackendDispatchers.h + +### Begin File: InspectorBackendCommands.js +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +// Database. +InspectorBackend.registerEnum("Database.PrimaryColors", {Red: "red", Green: "green", Blue: "blue"}); +InspectorBackend.registerCommand("Database.executeAllOptionalParameters", [{"name": "columnNames", "type": "object", "optional": true}, {"name": "notes", "type": "string", "optional": true}, {"name": "timestamp", "type": "number", "optional": true}, {"name": "values", "type": "object", "optional": true}, {"name": "payload", "type": "object", "optional": true}, {"name": "databaseId", "type": "number", "optional": true}, {"name": "sqlError", "type": "object", "optional": true}, {"name": "screenColor", "type": "string", "optional": true}, {"name": "alternateColors", "type": "object", "optional": true}, {"name": "printColor", "type": "string", "optional": true}], ["columnNames", "notes", "timestamp", "values", "payload", "databaseId", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.registerCommand("Database.executeNoOptionalParameters", [{"name": "columnNames", "type": "object", "optional": false}, {"name": "notes", "type": "string", "optional": false}, {"name": "timestamp", "type": "number", "optional": false}, {"name": "values", "type": "object", "optional": false}, {"name": "payload", "type": "object", "optional": false}, {"name": "databaseId", "type": "number", "optional": false}, {"name": "sqlError", "type": "object", "optional": false}, {"name": "screenColor", "type": "string", "optional": false}, {"name": "alternateColors", "type": "object", "optional": false}, {"name": "printColor", "type": "string", "optional": false}], ["columnNames", "notes", "timestamp", "values", "payload", "databaseId", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.activateDomain("Database"); +### End File: InspectorBackendCommands.js + +### Begin File: InspectorBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorBackendDispatchers_h +#define InspectorBackendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorBackendDispatcher.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + +typedef String ErrorString; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +class AlternateDatabaseBackendDispatcher; +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +class DatabaseBackendDispatcherHandler { +public: + // Named after parameter 'screenColor' while generating command/event executeAllOptionalParameters. + enum class ScreenColor { + Red = 0, + Green = 1, + Blue = 2, + }; // enum class ScreenColor + // Named after parameter 'printColor' while generating command/event executeAllOptionalParameters. + enum class PrintColor { + Cyan = 3, + Magenta = 4, + Yellow = 5, + Black = 6, + }; // enum class PrintColor + virtual void executeAllOptionalParameters(ErrorString&, const Inspector::InspectorArray* opt_in_columnNames, const String* opt_in_notes, const double* opt_in_timestamp, const Inspector::InspectorObject* opt_in_values, const Inspector::InspectorValue* opt_in_payload, const int* opt_in_databaseId, const Inspector::InspectorObject* opt_in_sqlError, const String* opt_in_screenColor, const Inspector::InspectorArray* opt_in_alternateColors, const String* opt_in_printColor, RefPtr<Inspector::Protocol::Array<String>>& opt_out_columnNames, Inspector::Protocol::OptOutput<String>* opt_out_notes, Inspector::Protocol::OptOutput<double>* opt_out_timestamp, Inspector::Protocol::OptOutput<Inspector::InspectorObject>* opt_out_values, Inspector::Protocol::OptOutput<Inspector::InspectorValue>* opt_out_payload, Inspector::Protocol::OptOutput<int>* opt_out_databaseId, RefPtr<Inspector::Protocol::Database::Error>& opt_out_sqlError, Inspector::Protocol::Database::PrimaryColors* opt_out_screenColor, RefPtr<Inspector::Protocol::Database::ColorList>& opt_out_alternateColors, DatabaseBackendDispatcherHandler::PrintColor* opt_out_printColor) = 0; + virtual void executeNoOptionalParameters(ErrorString&, const Inspector::InspectorArray& in_columnNames, const String& in_notes, double in_timestamp, const Inspector::InspectorObject& in_values, Inspector::InspectorValue in_payload, int in_databaseId, const Inspector::InspectorObject& in_sqlError, const String& in_screenColor, const Inspector::InspectorArray& in_alternateColors, const String& in_printColor, RefPtr<Inspector::Protocol::Array<String>>& out_columnNames, String* out_notes, double* out_timestamp, Inspector::InspectorObject* out_values, Inspector::InspectorValue* out_payload, int* out_databaseId, RefPtr<Inspector::Protocol::Database::Error>& out_sqlError, Inspector::Protocol::Database::PrimaryColors* out_screenColor, RefPtr<Inspector::Protocol::Database::ColorList>& out_alternateColors, DatabaseBackendDispatcherHandler::PrintColor* out_printColor) = 0; +protected: + virtual ~DatabaseBackendDispatcherHandler(); +}; + +class DatabaseBackendDispatcher final : public SupplementalBackendDispatcher { +public: + static Ref<DatabaseBackendDispatcher> create(BackendDispatcher*, DatabaseBackendDispatcherHandler*); + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) override; +private: + void executeAllOptionalParameters(long callId, const InspectorObject& message); + void executeNoOptionalParameters(long callId, const InspectorObject& message); +private: + DatabaseBackendDispatcher(BackendDispatcher&, DatabaseBackendDispatcherHandler*); + DatabaseBackendDispatcherHandler* m_agent; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +public: + void setAlternateDispatcher(AlternateDatabaseBackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; } +private: + AlternateDatabaseBackendDispatcher* m_alternateDispatcher; +#endif +}; + +} // namespace Inspector + +#endif // !defined(InspectorBackendDispatchers_h) +### End File: InspectorBackendDispatchers.h + +### Begin File: InspectorBackendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorBackendDispatchers.h" + +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/CString.h> + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "InspectorAlternateBackendDispatchers.h" +#endif + +namespace Inspector { + +DatabaseBackendDispatcherHandler::~DatabaseBackendDispatcherHandler() { } + +Ref<DatabaseBackendDispatcher> DatabaseBackendDispatcher::create(BackendDispatcher* backendDispatcher, DatabaseBackendDispatcherHandler* agent) +{ + return adoptRef(*new DatabaseBackendDispatcher(*backendDispatcher, agent)); +} + +DatabaseBackendDispatcher::DatabaseBackendDispatcher(BackendDispatcher& backendDispatcher, DatabaseBackendDispatcherHandler* agent) + : SupplementalBackendDispatcher(backendDispatcher) + , m_agent(agent) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_alternateDispatcher(nullptr) +#endif +{ + m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("Database"), this); +} + +void DatabaseBackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<DatabaseBackendDispatcher> protect(*this); + + if (method == "executeAllOptionalParameters") + executeAllOptionalParameters(callId, message); + else if (method == "executeNoOptionalParameters") + executeNoOptionalParameters(callId, message); + else + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\'', "Database", '.', method, "' was not found")); +} + +void DatabaseBackendDispatcher::executeAllOptionalParameters(long callId, const InspectorObject& message) +{ + auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); + bool opt_in_columnNames_valueFound = false; + RefPtr<Inspector::InspectorArray> opt_in_columnNames = BackendDispatcher::getArray(paramsContainer.get(), ASCIILiteral("columnNames"), &opt_in_columnNames_valueFound, protocolErrors.get()); + bool opt_in_notes_valueFound = false; + String opt_in_notes = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("notes"), &opt_in_notes_valueFound, protocolErrors.get()); + bool opt_in_timestamp_valueFound = false; + Inspector::Protocol::OptOutput<double> opt_in_timestamp = BackendDispatcher::getDouble(paramsContainer.get(), ASCIILiteral("timestamp"), &opt_in_timestamp_valueFound, protocolErrors.get()); + bool opt_in_values_valueFound = false; + RefPtr<Inspector::InspectorObject> opt_in_values = BackendDispatcher::getObject(paramsContainer.get(), ASCIILiteral("values"), &opt_in_values_valueFound, protocolErrors.get()); + bool opt_in_payload_valueFound = false; + RefPtr<Inspector::InspectorValue> opt_in_payload = BackendDispatcher::getValue(paramsContainer.get(), ASCIILiteral("payload"), &opt_in_payload_valueFound, protocolErrors.get()); + bool opt_in_databaseId_valueFound = false; + int opt_in_databaseId = BackendDispatcher::getInteger(paramsContainer.get(), ASCIILiteral("databaseId"), &opt_in_databaseId_valueFound, protocolErrors.get()); + bool opt_in_sqlError_valueFound = false; + RefPtr<Inspector::InspectorObject> opt_in_sqlError = BackendDispatcher::getObject(paramsContainer.get(), ASCIILiteral("sqlError"), &opt_in_sqlError_valueFound, protocolErrors.get()); + bool opt_in_screenColor_valueFound = false; + String opt_in_screenColor = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("screenColor"), &opt_in_screenColor_valueFound, protocolErrors.get()); + bool opt_in_alternateColors_valueFound = false; + RefPtr<Inspector::InspectorArray> opt_in_alternateColors = BackendDispatcher::getArray(paramsContainer.get(), ASCIILiteral("alternateColors"), &opt_in_alternateColors_valueFound, protocolErrors.get()); + bool opt_in_printColor_valueFound = false; + String opt_in_printColor = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("printColor"), &opt_in_printColor_valueFound, protocolErrors.get()); + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method '%s' can't be processed", "Database.executeAllOptionalParameters"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->executeAllOptionalParameters(callId, opt_in_columnNames_valueFound ? opt_in_columnNames.get() : nullptr, opt_in_notes_valueFound ? &opt_in_notes : nullptr, opt_in_timestamp_valueFound ? &opt_in_timestamp : nullptr, opt_in_values_valueFound ? opt_in_values.get() : nullptr, opt_in_payload_valueFound ? opt_in_payload.get() : nullptr, opt_in_databaseId_valueFound ? &opt_in_databaseId : nullptr, opt_in_sqlError_valueFound ? opt_in_sqlError.get() : nullptr, opt_in_screenColor_valueFound ? &opt_in_screenColor : nullptr, opt_in_alternateColors_valueFound ? opt_in_alternateColors.get() : nullptr, opt_in_printColor_valueFound ? &opt_in_printColor : nullptr); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + RefPtr<Inspector::Protocol::Array<String>> out_columnNames; + Inspector::Protocol::OptOutput<String> out_notes; + Inspector::Protocol::OptOutput<double> out_timestamp; + Inspector::Protocol::OptOutput<Inspector::InspectorObject> out_values; + Inspector::Protocol::OptOutput<Inspector::InspectorValue> out_payload; + Inspector::Protocol::OptOutput<Inspector::Protocol::Database::DatabaseId> out_databaseId; + RefPtr<Inspector::Protocol::Database::Error> out_sqlError; + Inspector::Protocol::Database::PrimaryColors out_screenColor; + RefPtr<Inspector::Protocol::Database::ColorList> out_alternateColors; + DatabaseBackendDispatcherHandler::PrintColor out_printColor; + m_agent->executeAllOptionalParameters(error, opt_in_columnNames_valueFound ? opt_in_columnNames.get() : nullptr, opt_in_notes_valueFound ? &opt_in_notes : nullptr, opt_in_timestamp_valueFound ? &opt_in_timestamp : nullptr, opt_in_values_valueFound ? opt_in_values.get() : nullptr, opt_in_payload_valueFound ? opt_in_payload.get() : nullptr, opt_in_databaseId_valueFound ? &opt_in_databaseId : nullptr, opt_in_sqlError_valueFound ? opt_in_sqlError.get() : nullptr, opt_in_screenColor_valueFound ? &opt_in_screenColor : nullptr, opt_in_alternateColors_valueFound ? opt_in_alternateColors.get() : nullptr, opt_in_printColor_valueFound ? &opt_in_printColor : nullptr, out_columnNames, &out_notes, &out_timestamp, out_values, &out_payload, &out_databaseId, out_sqlError, &out_screenColor, out_alternateColors, &out_printColor); + + if (!error.length()) { + if (out_columnNames) + result->setArray(ASCIILiteral("columnNames"), out_columnNames); + if (out_notes.isAssigned()) + result->setString(ASCIILiteral("notes"), out_notes.getValue()); + if (out_timestamp.isAssigned()) + result->setDouble(ASCIILiteral("timestamp"), out_timestamp.getValue()); + if (out_values.isAssigned()) + result->setObject(ASCIILiteral("values"), out_values.getValue()); + if (out_payload.isAssigned()) + result->setValue(ASCIILiteral("payload"), out_payload.getValue()); + if (out_databaseId.isAssigned()) + result->setInteger(ASCIILiteral("databaseId"), out_databaseId.getValue()); + if (out_sqlError) + result->setObject(ASCIILiteral("sqlError"), out_sqlError); + if (out_screenColor.isAssigned()) + result->setString(ASCIILiteral("screenColor"), out_screenColor.getValue()); + if (out_alternateColors) + result->setArray(ASCIILiteral("alternateColors"), out_alternateColors); + if (out_printColor.isAssigned()) + result->setString(ASCIILiteral("printColor"), out_printColor.getValue()); + } + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void DatabaseBackendDispatcher::executeNoOptionalParameters(long callId, const InspectorObject& message) +{ + auto protocolErrors = Inspector::Protocol::Array<String>::create(); + RefPtr<InspectorObject> paramsContainer; + message.getObject(ASCIILiteral("params"), paramsContainer); + RefPtr<Inspector::InspectorArray> in_columnNames = BackendDispatcher::getArray(paramsContainer.get(), ASCIILiteral("columnNames"), nullptr, protocolErrors.get()); + String in_notes = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("notes"), nullptr, protocolErrors.get()); + double in_timestamp = BackendDispatcher::getDouble(paramsContainer.get(), ASCIILiteral("timestamp"), nullptr, protocolErrors.get()); + RefPtr<Inspector::InspectorObject> in_values = BackendDispatcher::getObject(paramsContainer.get(), ASCIILiteral("values"), nullptr, protocolErrors.get()); + RefPtr<Inspector::InspectorValue> in_payload = BackendDispatcher::getValue(paramsContainer.get(), ASCIILiteral("payload"), nullptr, protocolErrors.get()); + int in_databaseId = BackendDispatcher::getInteger(paramsContainer.get(), ASCIILiteral("databaseId"), nullptr, protocolErrors.get()); + RefPtr<Inspector::InspectorObject> in_sqlError = BackendDispatcher::getObject(paramsContainer.get(), ASCIILiteral("sqlError"), nullptr, protocolErrors.get()); + String in_screenColor = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("screenColor"), nullptr, protocolErrors.get()); + RefPtr<Inspector::InspectorArray> in_alternateColors = BackendDispatcher::getArray(paramsContainer.get(), ASCIILiteral("alternateColors"), nullptr, protocolErrors.get()); + String in_printColor = BackendDispatcher::getString(paramsContainer.get(), ASCIILiteral("printColor"), nullptr, protocolErrors.get()); + if (protocolErrors->length()) { + String errorMessage = String::format("Some arguments of method '%s' can't be processed", "Database.executeNoOptionalParameters"); + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::InvalidParams, errorMessage, WTF::move(protocolErrors)); + return; + } + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->executeNoOptionalParameters(callId, *in_columnNames, in_notes, in_timestamp, *in_values, *in_payload, in_databaseId, *in_sqlError, in_screenColor, *in_alternateColors, in_printColor); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + RefPtr<Inspector::Protocol::Array<String>> out_columnNames; + String out_notes; + double out_timestamp; + Inspector::InspectorObject out_values; + Inspector::InspectorValue out_payload; + Inspector::Protocol::Database::DatabaseId out_databaseId; + RefPtr<Inspector::Protocol::Database::Error> out_sqlError; + Inspector::Protocol::Database::PrimaryColors out_screenColor; + RefPtr<Inspector::Protocol::Database::ColorList> out_alternateColors; + DatabaseBackendDispatcherHandler::PrintColor out_printColor; + m_agent->executeNoOptionalParameters(error, *in_columnNames, in_notes, in_timestamp, *in_values, *in_payload, in_databaseId, *in_sqlError, in_screenColor, *in_alternateColors, in_printColor, out_columnNames, &out_notes, &out_timestamp, out_values, &out_payload, &out_databaseId, out_sqlError, &out_screenColor, out_alternateColors, &out_printColor); + + if (!error.length()) { + result->setArray(ASCIILiteral("columnNames"), out_columnNames); + result->setString(ASCIILiteral("notes"), out_notes); + result->setDouble(ASCIILiteral("timestamp"), out_timestamp); + result->setObject(ASCIILiteral("values"), out_values); + result->setValue(ASCIILiteral("payload"), out_payload); + result->setInteger(ASCIILiteral("databaseId"), out_databaseId); + result->setObject(ASCIILiteral("sqlError"), out_sqlError); + result->setString(ASCIILiteral("screenColor"), Inspector::Protocol::getEnumConstantValue(out_screenColor)); + result->setArray(ASCIILiteral("alternateColors"), out_alternateColors); + result->setString(ASCIILiteral("printColor"), Inspector::Protocol::getEnumConstantValue(out_printColor)); + } + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +} // namespace Inspector + +### End File: InspectorBackendDispatchers.cpp + +### Begin File: InspectorFrontendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorFrontendDispatchers_h +#define InspectorFrontendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + + + +} // namespace Inspector + +#endif // !defined(InspectorFrontendDispatchers_h) +### End File: InspectorFrontendDispatchers.h + +### Begin File: InspectorFrontendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorFrontendDispatchers.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +} // namespace Inspector + +### End File: InspectorFrontendDispatchers.cpp + +### Begin File: InspectorProtocolObjects.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorProtocolObjects_h +#define InspectorProtocolObjects_h + +#include <inspector/InspectorProtocolTypes.h> +#include <wtf/Assertions.h> + +namespace Inspector { + + + +namespace Protocol { + +// Forward declarations. +namespace Database { +class Error; +enum class PrimaryColors; +} // Database +// End of forward declarations. + + +// Typedefs. +namespace Database { +/* Unique identifier of Database object. */ +typedef int DatabaseId; +typedef Inspector::Protocol::Array<Inspector::Protocol::Database::PrimaryColors> ColorList; +} // Database +// End of typedefs. + +String getEnumConstantValue(int code); + +template<typename T> String getEnumConstantValue(T enumValue) +{ + return getEnumConstantValue(static_cast<int>(enumValue)); +} + +namespace Database { +/* */ +enum class PrimaryColors { + Red = 0, + Green = 1, + Blue = 2, +}; // enum class PrimaryColors +/* Database error. */ +class Error : public Inspector::InspectorObjectBase { +public: + enum { + NoFieldsSet = 0, + MessageSet = 1 << 0, + CodeSet = 1 << 1, + AllFieldsSet = (MessageSet | CodeSet) + }; + + template<int STATE> + class Builder { + private: + RefPtr<InspectorObject> m_result; + + template<int STEP> Builder<STATE | STEP>& castState() + { + return *reinterpret_cast<Builder<STATE | STEP>*>(this); + } + + Builder(Ref</*Error*/InspectorObject>&& object) + : m_result(WTF::move(object)) + { + COMPILE_ASSERT(STATE == NoFieldsSet, builder_created_in_non_init_state); + } + friend class Error; + public: + + Builder<STATE | MessageSet>& setMessage(const String& value) + { + COMPILE_ASSERT(!(STATE & MessageSet), property_message_already_set); + m_result->setString(ASCIILiteral("message"), value); + return castState<MessageSet>(); + } + + Builder<STATE | CodeSet>& setCode(int value) + { + COMPILE_ASSERT(!(STATE & CodeSet), property_code_already_set); + m_result->setInteger(ASCIILiteral("code"), value); + return castState<CodeSet>(); + } + + Ref<Error> release() + { + COMPILE_ASSERT(STATE == AllFieldsSet, result_is_not_ready); + COMPILE_ASSERT(sizeof(Error) == sizeof(InspectorObject), cannot_cast); + + Ref<InspectorObject> result = m_result.releaseNonNull(); + return WTF::move(*reinterpret_cast<Ref<Error>*>(&result)); + } + }; + + /* + * Synthetic constructor: + * Ref<Error> result = Error::create() + * .setMessage(...) + * .setCode(...) + * .release(); + */ + static Builder<NoFieldsSet> create() + { + return Builder<NoFieldsSet>(InspectorObject::create()); + } +}; + +} // Database + + + +} // namespace Protocol + +} // namespace Inspector + +#endif // !defined(InspectorProtocolObjects_h) +### End File: InspectorProtocolObjects.h + +### Begin File: InspectorProtocolObjects.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorProtocolObjects.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +namespace Protocol { + +static const char* const enum_constant_values[] = { + "red", + "green", + "blue", + "cyan", + "magenta", + "yellow", + "black", +}; + +String getEnumConstantValue(int code) { + return enum_constant_values[code]; +} + + + +} // namespace Protocol + +} // namespace Inspector + +### End File: InspectorProtocolObjects.cpp + +### Begin File: RWIProtocolBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#include <wtf/RetainPtr.h> + +@protocol RWIProtocolDatabaseDomainHandler; + +namespace Inspector { + + +class ObjCInspectorDatabaseBackendDispatcher final : public AlternateDatabaseBackendDispatcher { +public: + ObjCInspectorDatabaseBackendDispatcher(id<RWIProtocolDatabaseDomainHandler> handler) { m_delegate = handler; } + virtual void executeAllOptionalParameters(long callId, const Inspector::InspectorArray* in_columnNames, const String* in_notes, const double* in_timestamp, const Inspector::InspectorObject* in_values, const Inspector::InspectorValue* in_payload, const int* in_databaseId, const Inspector::InspectorObject* in_sqlError, const String* in_screenColor, const Inspector::InspectorArray* in_alternateColors, const String* in_printColor) override; + virtual void executeNoOptionalParameters(long callId, const Inspector::InspectorArray& in_columnNames, const String& in_notes, double in_timestamp, const Inspector::InspectorObject& in_values, Inspector::InspectorValue in_payload, int in_databaseId, const Inspector::InspectorObject& in_sqlError, const String& in_screenColor, const Inspector::InspectorArray& in_alternateColors, const String& in_printColor) override; +private: + RetainPtr<id<RWIProtocolDatabaseDomainHandler>> m_delegate; +}; + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.h + +### Begin File: RWIProtocolConfiguration.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolConfiguration.h" + +#import "RWIProtocolInternal.h" +#import "RWIProtocolBackendDispatchers.h" +#import <JavaScriptCore/AlternateDispatchableAgent.h> +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#import <JavaScriptCore/InspectorBackendDispatchers.h> + +using namespace Inspector; + +@implementation RWIProtocolConfiguration +{ + AugmentableInspectorController* _controller; + id<RWIProtocolDatabaseDomainHandler> _databaseHandler; +} + +- (instancetype)initWithController:(AugmentableInspectorController*)controller +{ + self = [super init]; + if (!self) + return nil; + ASSERT(controller); + _controller = controller; + return self; +} + +- (void)dealloc +{ + [_databaseHandler release]; + [super dealloc]; +} + +- (void)setDatabaseHandler:(id<RWIProtocolDatabaseDomainHandler>)handler +{ + if (handler == _databaseHandler) + return; + + [_databaseHandler release]; + _databaseHandler = [handler retain]; + + auto alternateDispatcher = std::make_unique<ObjCInspectorDatabaseBackendDispatcher>(handler); + auto alternateAgent = std::make_unique<AlternateDispatchableAgent<DatabaseBackendDispatcher, AlternateDatabaseBackendDispatcher>>(ASCIILiteral("Database"), WTF::move(alternateDispatcher)); + _controller->appendExtraAgent(WTF::move(alternateAgent)); +} + +- (id<RWIProtocolDatabaseDomainHandler>)databaseHandler +{ + return _databaseHandler; +} + +@end + + +### End File: RWIProtocolConfiguration.mm + +### Begin File: RWIProtocolConfiguration.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" + +__attribute__((visibility ("default"))) +@interface RWIProtocolConfiguration : NSObject +@property (nonatomic, retain, setter=setDatabaseHandler:) id<RWIProtocolDatabaseDomainHandler> databaseHandler; +@end + + +### End File: RWIProtocolConfiguration.h + +### Begin File: RWIProtocolBackendDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolBackendDispatchers.h" + +#include "RWIProtocolInternal.h" +#include "RWIProtocolEnumConversionHelpers.h" +#include <JavaScriptCore/InspectorFrontendChannel.h> +#include <JavaScriptCore/InspectorValues.h> + +namespace Inspector { + +void ObjCInspectorDatabaseBackendDispatcher::executeAllOptionalParameters(long callId, const Inspector::InspectorArray* in_columnNames, const String* in_notes, const double* in_timestamp, const Inspector::InspectorObject* in_values, const Inspector::InspectorValue* in_payload, const int* in_databaseId, const Inspector::InspectorObject* in_sqlError, const String* in_screenColor, const Inspector::InspectorArray* in_alternateColors, const String* in_printColor) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(NSArray/*<NSString>*/ **columnNames, NSString **notes, double *timestamp, RWIProtocolJSONObject **values, RWIProtocolJSONObject **payload, int *databaseId, RWIProtocolDatabaseError **sqlError, RWIProtocolDatabasePrimaryColors *screenColor, NSArray/*<NSString>*/ **alternateColors, RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor *printColor) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(columnNames, @"columnNames"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(notes, @"notes"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(values, @"values"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(payload, @"payload"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(sqlError, @"sqlError"); + THROW_EXCEPTION_FOR_BAD_OPTIONAL_PARAMETER(alternateColors, @"alternateColors"); + if (columnNames) + resultObject->setArray(ASCIILiteral("columnNames"), inspectorStringArray(*columnNames)); + if (notes) + resultObject->setString(ASCIILiteral("notes"), *notes); + if (timestamp) + resultObject->setDouble(ASCIILiteral("timestamp"), *timestamp); + if (values) + resultObject->setObject(ASCIILiteral("values"), [*values toInspectorObject]); + if (payload) + resultObject->setValue(ASCIILiteral("payload"), [*payload toInspectorObject]); + if (databaseId) + resultObject->setInteger(ASCIILiteral("databaseId"), *databaseId); + if (sqlError) + resultObject->setObject(ASCIILiteral("sqlError"), [*sqlError toInspectorObject]); + if (screenColor) + resultObject->setString(ASCIILiteral("screenColor"), toProtocolString(*screenColor)); + if (alternateColors) + resultObject->setArray(ASCIILiteral("alternateColors"), inspectorStringArray(*alternateColors)); + if (printColor) + resultObject->setString(ASCIILiteral("printColor"), toProtocolString(*printColor)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + NSArray/*<NSString>*/ *o_in_columnNames; + if (in_columnNames) + o_in_columnNames = objcStringArray(in_columnNames); + NSString *o_in_notes; + if (in_notes) + o_in_notes = *in_notes; + double o_in_timestamp; + if (in_timestamp) + o_in_timestamp = *in_timestamp; + RWIProtocolJSONObject *o_in_values; + if (in_values) + o_in_values = [[[RWIProtocolJSONObject alloc] initWithInspectorObject:in_values] autorelease]; + RWIProtocolJSONObject *o_in_payload; + if (in_payload) + o_in_payload = [[[RWIProtocolJSONObject alloc] initWithInspectorObject:in_payload] autorelease]; + int o_in_databaseId; + if (in_databaseId) + o_in_databaseId = *in_databaseId; + RWIProtocolDatabaseError *o_in_sqlError; + if (in_sqlError) + o_in_sqlError = [[[RWIProtocolDatabaseError alloc] initWithInspectorObject:in_sqlError] autorelease]; + RWIProtocolDatabasePrimaryColors o_in_screenColor; + if (in_screenColor) + o_in_screenColor = fromProtocolString<RWIProtocolDatabasePrimaryColors>(*in_screenColor); + NSArray/*<NSString>*/ *o_in_alternateColors; + if (in_alternateColors) + o_in_alternateColors = objcStringArray(in_alternateColors); + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor o_in_printColor; + if (in_printColor) + o_in_printColor = fromProtocolString<RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor>(*in_printColor); + + [m_delegate executeAllOptionalParametersWithErrorCallback:errorCallback successCallback:successCallback columnNames:(in_columnNames ? &o_in_columnNames : nil) notes:(in_notes ? &o_in_notes : nil) timestamp:(in_timestamp ? &o_in_timestamp : nil) values:(in_values ? &o_in_values : nil) payload:(in_payload ? &o_in_payload : nil) databaseId:(in_databaseId ? &o_in_databaseId : nil) sqlError:(in_sqlError ? &o_in_sqlError : nil) screenColor:(in_screenColor ? &o_in_screenColor : nil) alternateColors:(in_alternateColors ? &o_in_alternateColors : nil) printColor:(in_printColor ? &o_in_printColor : nil)]; +} + +void ObjCInspectorDatabaseBackendDispatcher::executeNoOptionalParameters(long callId, const Inspector::InspectorArray& in_columnNames, const String& in_notes, double in_timestamp, const Inspector::InspectorObject& in_values, Inspector::InspectorValue in_payload, int in_databaseId, const Inspector::InspectorObject& in_sqlError, const String& in_screenColor, const Inspector::InspectorArray& in_alternateColors, const String& in_printColor) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(NSArray/*<NSString>*/ *columnNames, NSString *notes, double timestamp, RWIProtocolJSONObject *values, RWIProtocolJSONObject *payload, int databaseId, RWIProtocolDatabaseError *sqlError, RWIProtocolDatabasePrimaryColors screenColor, NSArray/*<NSString>*/ *alternateColors, RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor printColor) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(columnNames, @"columnNames"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(notes, @"notes"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(values, @"values"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(payload, @"payload"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(sqlError, @"sqlError"); + THROW_EXCEPTION_FOR_REQUIRED_PARAMETER(alternateColors, @"alternateColors"); + resultObject->setArray(ASCIILiteral("columnNames"), inspectorStringArray(columnNames)); + resultObject->setString(ASCIILiteral("notes"), notes); + resultObject->setDouble(ASCIILiteral("timestamp"), timestamp); + resultObject->setObject(ASCIILiteral("values"), [values toInspectorObject]); + resultObject->setValue(ASCIILiteral("payload"), [payload toInspectorObject]); + resultObject->setInteger(ASCIILiteral("databaseId"), databaseId); + resultObject->setObject(ASCIILiteral("sqlError"), [sqlError toInspectorObject]); + resultObject->setString(ASCIILiteral("screenColor"), toProtocolString(screenColor)); + resultObject->setArray(ASCIILiteral("alternateColors"), inspectorStringArray(alternateColors)); + resultObject->setString(ASCIILiteral("printColor"), toProtocolString(printColor)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + NSArray/*<NSString>*/ *o_in_columnNames = objcStringArray(&in_columnNames); + NSString *o_in_notes = in_notes; + double o_in_timestamp = in_timestamp; + RWIProtocolJSONObject *o_in_values = [[[RWIProtocolJSONObject alloc] initWithInspectorObject:&in_values] autorelease]; + RWIProtocolJSONObject *o_in_payload = [[[RWIProtocolJSONObject alloc] initWithInspectorObject:&in_payload] autorelease]; + int o_in_databaseId = in_databaseId; + RWIProtocolDatabaseError *o_in_sqlError = [[[RWIProtocolDatabaseError alloc] initWithInspectorObject:&in_sqlError] autorelease]; + RWIProtocolDatabasePrimaryColors o_in_screenColor = fromProtocolString<RWIProtocolDatabasePrimaryColors>(in_screenColor); + NSArray/*<NSString>*/ *o_in_alternateColors = objcStringArray(&in_alternateColors); + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor o_in_printColor = fromProtocolString<RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor>(in_printColor); + + [m_delegate executeNoOptionalParametersWithErrorCallback:errorCallback successCallback:successCallback columnNames:o_in_columnNames notes:o_in_notes timestamp:o_in_timestamp values:o_in_values payload:o_in_payload databaseId:o_in_databaseId sqlError:o_in_sqlError screenColor:o_in_screenColor alternateColors:o_in_alternateColors printColor:o_in_printColor]; +} + + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.mm + +### Begin File: RWIProtocolEnumConversionHelpers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocolArrayConversionHelpers.h" + +namespace Inspector { + +template<typename ObjCEnumType> +ObjCEnumType fromProtocolString(const String& value); + + +inline String toProtocolString(RWIProtocolDatabasePrimaryColors value) +{ + switch(value) { + case RWIProtocolDatabasePrimaryColorsRed: + return ASCIILiteral("red"); + case RWIProtocolDatabasePrimaryColorsGreen: + return ASCIILiteral("green"); + case RWIProtocolDatabasePrimaryColorsBlue: + return ASCIILiteral("blue"); + } +} + +template<> +inline RWIProtocolDatabasePrimaryColors fromProtocolString(const String& value) +{ + if (value == "red") + return RWIProtocolDatabasePrimaryColorsRed; + if (value == "green") + return RWIProtocolDatabasePrimaryColorsGreen; + if (value == "blue") + return RWIProtocolDatabasePrimaryColorsBlue; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabasePrimaryColorsRed; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan; +} + +inline String toProtocolString(RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor value) +{ + switch(value) { + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan: + return ASCIILiteral("cyan"); + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorYellow: + return ASCIILiteral("yellow"); + case RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorBlack: + return ASCIILiteral("black"); + } +} + +template<> +inline RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor fromProtocolString(const String& value) +{ + if (value == "cyan") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan; + if (value == "magenta") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorMagenta; + if (value == "yellow") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorYellow; + if (value == "black") + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorBlack; + ASSERT_NOT_REACHED(); + return RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan; +} + +} // namespace Inspector + +### End File: RWIProtocolEnumConversionHelpers.h + +### Begin File: RWIProtocolEventDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorFrontendChannel.h> +#import <JavaScriptCore/InspectorValues.h> + +using namespace Inspector; + + + + +### End File: RWIProtocolEventDispatchers.mm + +### Begin File: RWIProtocol.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import <Foundation/Foundation.h> + +#import <WebInspector/RWIProtocolJSONObject.h> + + +@class RWIProtocolDatabaseError; + + +typedef NS_ENUM(NSInteger, RWIProtocolDatabasePrimaryColors) { + RWIProtocolDatabasePrimaryColorsRed, + RWIProtocolDatabasePrimaryColorsGreen, + RWIProtocolDatabasePrimaryColorsBlue, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor) { + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan, + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorMagenta, + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorYellow, + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorBlack, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor) { + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorCyan, + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorMagenta, + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorYellow, + RWIProtocolDatabaseExecuteAllOptionalParametersPrintColorBlack, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor) { + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan, + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorMagenta, + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorYellow, + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorBlack, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor) { + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorCyan, + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorMagenta, + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorYellow, + RWIProtocolDatabaseExecuteNoOptionalParametersPrintColorBlack, +}; + + +__attribute__((visibility ("default"))) +@interface RWIProtocolDatabaseError : RWIProtocolJSONObject +- (instancetype)initWithMessage:(NSString *)message code:(int)code; +/* required */ @property (nonatomic, copy) NSString *message; +/* required */ @property (nonatomic, assign) int code; +@end + +@protocol RWIProtocolDatabaseDomainHandler <NSObject> +@required +- (void)executeAllOptionalParametersWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(NSArray/*<NSString>*/ **columnNames, NSString **notes, double *timestamp, RWIProtocolJSONObject **values, RWIProtocolJSONObject **payload, int *databaseId, RWIProtocolDatabaseError **sqlError, RWIProtocolDatabasePrimaryColors *screenColor, NSArray/*<NSString>*/ **alternateColors, RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor *printColor))successCallback columnNames:(NSArray/*<NSString>*/ **)columnNames notes:(NSString **)notes timestamp:(double *)timestamp values:(RWIProtocolJSONObject **)values payload:(RWIProtocolJSONObject **)payload databaseId:(int *)databaseId sqlError:(RWIProtocolDatabaseError **)sqlError screenColor:(RWIProtocolDatabasePrimaryColors *)screenColor alternateColors:(NSArray/*<NSString>*/ **)alternateColors printColor:(RWIProtocolDatabaseExecuteAllOptionalParametersPrintColor *)printColor; +- (void)executeNoOptionalParametersWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(NSArray/*<NSString>*/ *columnNames, NSString *notes, double timestamp, RWIProtocolJSONObject *values, RWIProtocolJSONObject *payload, int databaseId, RWIProtocolDatabaseError *sqlError, RWIProtocolDatabasePrimaryColors screenColor, NSArray/*<NSString>*/ *alternateColors, RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor printColor))successCallback columnNames:(NSArray/*<NSString>*/ *)columnNames notes:(NSString *)notes timestamp:(double)timestamp values:(RWIProtocolJSONObject *)values payload:(RWIProtocolJSONObject *)payload databaseId:(int)databaseId sqlError:(RWIProtocolDatabaseError *)sqlError screenColor:(RWIProtocolDatabasePrimaryColors)screenColor alternateColors:(NSArray/*<NSString>*/ *)alternateColors printColor:(RWIProtocolDatabaseExecuteNoOptionalParametersPrintColor)printColor; +@end + + + + +### End File: RWIProtocol.h + +### Begin File: RWIProtocolTypes.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorValues.h> +#import <wtf/Assertions.h> + +using namespace Inspector; + + +@implementation RWIProtocolDatabaseError + +- (instancetype)initWithMessage:(NSString *)message code:(int)code; +{ + self = [super init]; + if (!self) + return nil; + + THROW_EXCEPTION_FOR_REQUIRED_PROPERTY(message, @"message"); + + self.message = message; + self.code = code; + + return self; +} + +- (void)setMessage:(NSString *)message +{ + [super setString:message forKey:@"message"]; +} + +- (NSString *)message +{ + return [super stringForKey:@"message"]; +} + +- (void)setCode:(int)code +{ + [super setInteger:code forKey:@"code"]; +} + +- (int)code +{ + return [super integerForKey:@"code"]; +} + +@end + + +### End File: RWIProtocolTypes.mm + +### Begin File: RWIProtocolInternal.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from commands-with-optional-call-return-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" +#import "RWIProtocolJSONObjectInternal.h" +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorValues.h> + + + + +### End File: RWIProtocolInternal.h diff --git a/inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result b/inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result new file mode 100644 index 0000000..190b260 --- /dev/null +++ b/inspector/scripts/tests/expected/domains-with-varying-command-sizes.json-result @@ -0,0 +1,1318 @@ +### Begin File: InspectorAlternateBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorAlternateBackendDispatchers_h +#define InspectorAlternateBackendDispatchers_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include "InspectorProtocolTypes.h" +#include <JavaScriptCore/InspectorBackendDispatcher.h> + +namespace Inspector { + +class AlternateBackendDispatcher { +public: + void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTF::move(dispatcher); } + BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); } +private: + RefPtr<BackendDispatcher> m_backendDispatcher; +}; + + +class AlternateNetwork1BackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~AlternateNetwork1BackendDispatcher() { } + virtual void loadResource1(long callId) = 0; +}; +class AlternateNetwork3BackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~AlternateNetwork3BackendDispatcher() { } + virtual void loadResource1(long callId) = 0; + virtual void loadResource2(long callId) = 0; + virtual void loadResource3(long callId) = 0; + virtual void loadResource4(long callId) = 0; + virtual void loadResource5(long callId) = 0; + virtual void loadResource6(long callId) = 0; + virtual void loadResource7(long callId) = 0; +}; + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(InspectorAlternateBackendDispatchers_h) +### End File: InspectorAlternateBackendDispatchers.h + +### Begin File: InspectorBackendCommands.js +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +// Network1. +InspectorBackend.registerCommand("Network1.loadResource1", [], []); +InspectorBackend.activateDomain("Network1"); + +// Network3. +InspectorBackend.registerCommand("Network3.loadResource1", [], []); +InspectorBackend.registerCommand("Network3.loadResource2", [], []); +InspectorBackend.registerCommand("Network3.loadResource3", [], []); +InspectorBackend.registerCommand("Network3.loadResource4", [], []); +InspectorBackend.registerCommand("Network3.loadResource5", [], []); +InspectorBackend.registerCommand("Network3.loadResource6", [], []); +InspectorBackend.registerCommand("Network3.loadResource7", [], []); +InspectorBackend.activateDomain("Network3"); +### End File: InspectorBackendCommands.js + +### Begin File: InspectorBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorBackendDispatchers_h +#define InspectorBackendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorBackendDispatcher.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + +typedef String ErrorString; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +class AlternateNetwork1BackendDispatcher; +class AlternateNetwork3BackendDispatcher; +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +class Network1BackendDispatcherHandler { +public: + virtual void loadResource1(ErrorString&) = 0; +protected: + virtual ~Network1BackendDispatcherHandler(); +}; + +class Network3BackendDispatcherHandler { +public: + virtual void loadResource1(ErrorString&) = 0; + virtual void loadResource2(ErrorString&) = 0; + virtual void loadResource3(ErrorString&) = 0; + virtual void loadResource4(ErrorString&) = 0; + virtual void loadResource5(ErrorString&) = 0; + virtual void loadResource6(ErrorString&) = 0; + virtual void loadResource7(ErrorString&) = 0; +protected: + virtual ~Network3BackendDispatcherHandler(); +}; + +class Network1BackendDispatcher final : public SupplementalBackendDispatcher { +public: + static Ref<Network1BackendDispatcher> create(BackendDispatcher*, Network1BackendDispatcherHandler*); + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) override; +private: + void loadResource1(long callId, const InspectorObject& message); +private: + Network1BackendDispatcher(BackendDispatcher&, Network1BackendDispatcherHandler*); + Network1BackendDispatcherHandler* m_agent; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +public: + void setAlternateDispatcher(AlternateNetwork1BackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; } +private: + AlternateNetwork1BackendDispatcher* m_alternateDispatcher; +#endif +}; + +class Network3BackendDispatcher final : public SupplementalBackendDispatcher { +public: + static Ref<Network3BackendDispatcher> create(BackendDispatcher*, Network3BackendDispatcherHandler*); + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) override; +private: + void loadResource1(long callId, const InspectorObject& message); + void loadResource2(long callId, const InspectorObject& message); + void loadResource3(long callId, const InspectorObject& message); + void loadResource4(long callId, const InspectorObject& message); + void loadResource5(long callId, const InspectorObject& message); + void loadResource6(long callId, const InspectorObject& message); + void loadResource7(long callId, const InspectorObject& message); +private: + Network3BackendDispatcher(BackendDispatcher&, Network3BackendDispatcherHandler*); + Network3BackendDispatcherHandler* m_agent; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +public: + void setAlternateDispatcher(AlternateNetwork3BackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; } +private: + AlternateNetwork3BackendDispatcher* m_alternateDispatcher; +#endif +}; + +} // namespace Inspector + +#endif // !defined(InspectorBackendDispatchers_h) +### End File: InspectorBackendDispatchers.h + +### Begin File: InspectorBackendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorBackendDispatchers.h" + +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/CString.h> + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "InspectorAlternateBackendDispatchers.h" +#endif + +namespace Inspector { + +Network1BackendDispatcherHandler::~Network1BackendDispatcherHandler() { } +Network3BackendDispatcherHandler::~Network3BackendDispatcherHandler() { } + +Ref<Network1BackendDispatcher> Network1BackendDispatcher::create(BackendDispatcher* backendDispatcher, Network1BackendDispatcherHandler* agent) +{ + return adoptRef(*new Network1BackendDispatcher(*backendDispatcher, agent)); +} + +Network1BackendDispatcher::Network1BackendDispatcher(BackendDispatcher& backendDispatcher, Network1BackendDispatcherHandler* agent) + : SupplementalBackendDispatcher(backendDispatcher) + , m_agent(agent) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_alternateDispatcher(nullptr) +#endif +{ + m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("Network1"), this); +} + +void Network1BackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<Network1BackendDispatcher> protect(*this); + + if (method == "loadResource1") + loadResource1(callId, message); + else + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\'', "Network1", '.', method, "' was not found")); +} + +void Network1BackendDispatcher::loadResource1(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource1(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource1(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +Ref<Network3BackendDispatcher> Network3BackendDispatcher::create(BackendDispatcher* backendDispatcher, Network3BackendDispatcherHandler* agent) +{ + return adoptRef(*new Network3BackendDispatcher(*backendDispatcher, agent)); +} + +Network3BackendDispatcher::Network3BackendDispatcher(BackendDispatcher& backendDispatcher, Network3BackendDispatcherHandler* agent) + : SupplementalBackendDispatcher(backendDispatcher) + , m_agent(agent) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_alternateDispatcher(nullptr) +#endif +{ + m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("Network3"), this); +} + +void Network3BackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<Network3BackendDispatcher> protect(*this); + + typedef void (Network3BackendDispatcher::*CallHandler)(long callId, const InspectorObject& message); + typedef HashMap<String, CallHandler> DispatchMap; + DEPRECATED_DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, ()); + if (dispatchMap.isEmpty()) { + static const struct MethodTable { + const char* name; + CallHandler handler; + } commands[] = { + { "loadResource1", &Network3BackendDispatcher::loadResource1 }, + { "loadResource2", &Network3BackendDispatcher::loadResource2 }, + { "loadResource3", &Network3BackendDispatcher::loadResource3 }, + { "loadResource4", &Network3BackendDispatcher::loadResource4 }, + { "loadResource5", &Network3BackendDispatcher::loadResource5 }, + { "loadResource6", &Network3BackendDispatcher::loadResource6 }, + { "loadResource7", &Network3BackendDispatcher::loadResource7 }, + }; + size_t length = WTF_ARRAY_LENGTH(commands); + for (size_t i = 0; i < length; ++i) + dispatchMap.add(commands[i].name, commands[i].handler); + } + + HashMap<String, CallHandler>::iterator it = dispatchMap.find(method); + if (it == dispatchMap.end()) { + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\'', "Network3", '.', method, "' was not found")); + return; + } + + ((*this).*it->value)(callId, message.get()); +} + +void Network3BackendDispatcher::loadResource1(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource1(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource1(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void Network3BackendDispatcher::loadResource2(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource2(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource2(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void Network3BackendDispatcher::loadResource3(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource3(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource3(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void Network3BackendDispatcher::loadResource4(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource4(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource4(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void Network3BackendDispatcher::loadResource5(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource5(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource5(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void Network3BackendDispatcher::loadResource6(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource6(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource6(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +void Network3BackendDispatcher::loadResource7(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->loadResource7(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + m_agent->loadResource7(error); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +} // namespace Inspector + +### End File: InspectorBackendDispatchers.cpp + +### Begin File: InspectorFrontendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorFrontendDispatchers_h +#define InspectorFrontendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + + + +} // namespace Inspector + +#endif // !defined(InspectorFrontendDispatchers_h) +### End File: InspectorFrontendDispatchers.h + +### Begin File: InspectorFrontendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorFrontendDispatchers.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +} // namespace Inspector + +### End File: InspectorFrontendDispatchers.cpp + +### Begin File: InspectorProtocolObjects.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorProtocolObjects_h +#define InspectorProtocolObjects_h + +#include <inspector/InspectorProtocolTypes.h> +#include <wtf/Assertions.h> + +namespace Inspector { + + + +namespace Protocol { + + + +// Typedefs. +namespace Network2 { +/* Unique loader identifier. */ +typedef String LoaderId; +} // Network2 +// End of typedefs. + +String getEnumConstantValue(int code); + +template<typename T> String getEnumConstantValue(T enumValue) +{ + return getEnumConstantValue(static_cast<int>(enumValue)); +} + + + +} // namespace Protocol + +} // namespace Inspector + +#endif // !defined(InspectorProtocolObjects_h) +### End File: InspectorProtocolObjects.h + +### Begin File: InspectorProtocolObjects.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorProtocolObjects.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +namespace Protocol { + +static const char* const enum_constant_values[] = { +}; + +String getEnumConstantValue(int code) { + return enum_constant_values[code]; +} + + + +} // namespace Protocol + +} // namespace Inspector + +### End File: InspectorProtocolObjects.cpp + +### Begin File: RWIProtocolBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#include <wtf/RetainPtr.h> + +@protocol RWIProtocolNetwork1DomainHandler; +@protocol RWIProtocolNetwork3DomainHandler; + +namespace Inspector { + + +class ObjCInspectorNetwork1BackendDispatcher final : public AlternateNetwork1BackendDispatcher { +public: + ObjCInspectorNetwork1BackendDispatcher(id<RWIProtocolNetwork1DomainHandler> handler) { m_delegate = handler; } + virtual void loadResource1(long callId) override; +private: + RetainPtr<id<RWIProtocolNetwork1DomainHandler>> m_delegate; +}; + + + +class ObjCInspectorNetwork3BackendDispatcher final : public AlternateNetwork3BackendDispatcher { +public: + ObjCInspectorNetwork3BackendDispatcher(id<RWIProtocolNetwork3DomainHandler> handler) { m_delegate = handler; } + virtual void loadResource1(long callId) override; + virtual void loadResource2(long callId) override; + virtual void loadResource3(long callId) override; + virtual void loadResource4(long callId) override; + virtual void loadResource5(long callId) override; + virtual void loadResource6(long callId) override; + virtual void loadResource7(long callId) override; +private: + RetainPtr<id<RWIProtocolNetwork3DomainHandler>> m_delegate; +}; + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.h + +### Begin File: RWIProtocolConfiguration.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolConfiguration.h" + +#import "RWIProtocolInternal.h" +#import "RWIProtocolBackendDispatchers.h" +#import <JavaScriptCore/AlternateDispatchableAgent.h> +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#import <JavaScriptCore/InspectorBackendDispatchers.h> + +using namespace Inspector; + +@implementation RWIProtocolConfiguration +{ + AugmentableInspectorController* _controller; + id<RWIProtocolNetwork1DomainHandler> _network1Handler; + id<RWIProtocolNetwork3DomainHandler> _network3Handler; +} + +- (instancetype)initWithController:(AugmentableInspectorController*)controller +{ + self = [super init]; + if (!self) + return nil; + ASSERT(controller); + _controller = controller; + return self; +} + +- (void)dealloc +{ + [_network1Handler release]; + [_network3Handler release]; + [super dealloc]; +} + +- (void)setNetwork1Handler:(id<RWIProtocolNetwork1DomainHandler>)handler +{ + if (handler == _network1Handler) + return; + + [_network1Handler release]; + _network1Handler = [handler retain]; + + auto alternateDispatcher = std::make_unique<ObjCInspectorNetwork1BackendDispatcher>(handler); + auto alternateAgent = std::make_unique<AlternateDispatchableAgent<Network1BackendDispatcher, AlternateNetwork1BackendDispatcher>>(ASCIILiteral("Network1"), WTF::move(alternateDispatcher)); + _controller->appendExtraAgent(WTF::move(alternateAgent)); +} + +- (id<RWIProtocolNetwork1DomainHandler>)network1Handler +{ + return _network1Handler; +} + +- (void)setNetwork3Handler:(id<RWIProtocolNetwork3DomainHandler>)handler +{ + if (handler == _network3Handler) + return; + + [_network3Handler release]; + _network3Handler = [handler retain]; + + auto alternateDispatcher = std::make_unique<ObjCInspectorNetwork3BackendDispatcher>(handler); + auto alternateAgent = std::make_unique<AlternateDispatchableAgent<Network3BackendDispatcher, AlternateNetwork3BackendDispatcher>>(ASCIILiteral("Network3"), WTF::move(alternateDispatcher)); + _controller->appendExtraAgent(WTF::move(alternateAgent)); +} + +- (id<RWIProtocolNetwork3DomainHandler>)network3Handler +{ + return _network3Handler; +} + +@end + + +### End File: RWIProtocolConfiguration.mm + +### Begin File: RWIProtocolConfiguration.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" + +__attribute__((visibility ("default"))) +@interface RWIProtocolConfiguration : NSObject +@property (nonatomic, retain, setter=setNetwork1Handler:) id<RWIProtocolNetwork1DomainHandler> network1Handler; +@property (nonatomic, retain, setter=setNetwork3Handler:) id<RWIProtocolNetwork3DomainHandler> network3Handler; +@end + + +### End File: RWIProtocolConfiguration.h + +### Begin File: RWIProtocolBackendDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolBackendDispatchers.h" + +#include "RWIProtocolInternal.h" +#include "RWIProtocolEnumConversionHelpers.h" +#include <JavaScriptCore/InspectorFrontendChannel.h> +#include <JavaScriptCore/InspectorValues.h> + +namespace Inspector { + +void ObjCInspectorNetwork1BackendDispatcher::loadResource1(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource1WithErrorCallback:errorCallback successCallback:successCallback]; +} + + + + +void ObjCInspectorNetwork3BackendDispatcher::loadResource1(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource1WithErrorCallback:errorCallback successCallback:successCallback]; +} + +void ObjCInspectorNetwork3BackendDispatcher::loadResource2(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource2WithErrorCallback:errorCallback successCallback:successCallback]; +} + +void ObjCInspectorNetwork3BackendDispatcher::loadResource3(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource3WithErrorCallback:errorCallback successCallback:successCallback]; +} + +void ObjCInspectorNetwork3BackendDispatcher::loadResource4(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource4WithErrorCallback:errorCallback successCallback:successCallback]; +} + +void ObjCInspectorNetwork3BackendDispatcher::loadResource5(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource5WithErrorCallback:errorCallback successCallback:successCallback]; +} + +void ObjCInspectorNetwork3BackendDispatcher::loadResource6(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource6WithErrorCallback:errorCallback successCallback:successCallback]; +} + +void ObjCInspectorNetwork3BackendDispatcher::loadResource7(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^{ + backendDispatcher()->sendResponse(callId, InspectorObject::create(), String()); + }; + + [m_delegate loadResource7WithErrorCallback:errorCallback successCallback:successCallback]; +} + + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.mm + +### Begin File: RWIProtocolEnumConversionHelpers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocolArrayConversionHelpers.h" + +namespace Inspector { + +template<typename ObjCEnumType> +ObjCEnumType fromProtocolString(const String& value); + + + + + + + +} // namespace Inspector + +### End File: RWIProtocolEnumConversionHelpers.h + +### Begin File: RWIProtocolEventDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorFrontendChannel.h> +#import <JavaScriptCore/InspectorValues.h> + +using namespace Inspector; + + + + + + + + +### End File: RWIProtocolEventDispatchers.mm + +### Begin File: RWIProtocol.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import <Foundation/Foundation.h> + +#import <WebInspector/RWIProtocolJSONObject.h> + + + + + + + + +@protocol RWIProtocolNetwork1DomainHandler <NSObject> +@required +- (void)loadResource1WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +@end + +@protocol RWIProtocolNetwork3DomainHandler <NSObject> +@required +- (void)loadResource1WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +- (void)loadResource2WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +- (void)loadResource3WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +- (void)loadResource4WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +- (void)loadResource5WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +- (void)loadResource6WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +- (void)loadResource7WithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)())successCallback; +@end + + + + +### End File: RWIProtocol.h + +### Begin File: RWIProtocolTypes.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorValues.h> +#import <wtf/Assertions.h> + +using namespace Inspector; + + + + + + + + +### End File: RWIProtocolTypes.mm + +### Begin File: RWIProtocolInternal.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from domains-with-varying-command-sizes.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" +#import "RWIProtocolJSONObjectInternal.h" +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorValues.h> + + + + +### End File: RWIProtocolInternal.h diff --git a/inspector/scripts/tests/expected/enum-values.json-result b/inspector/scripts/tests/expected/enum-values.json-result new file mode 100644 index 0000000..9d74853 --- /dev/null +++ b/inspector/scripts/tests/expected/enum-values.json-result @@ -0,0 +1,1172 @@ +### Begin File: InspectorAlternateBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorAlternateBackendDispatchers_h +#define InspectorAlternateBackendDispatchers_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include "InspectorProtocolTypes.h" +#include <JavaScriptCore/InspectorBackendDispatcher.h> + +namespace Inspector { + +class AlternateBackendDispatcher { +public: + void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTF::move(dispatcher); } + BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); } +private: + RefPtr<BackendDispatcher> m_backendDispatcher; +}; + + +class AlternateCommandDomainBackendDispatcher : public AlternateBackendDispatcher { +public: + virtual ~AlternateCommandDomainBackendDispatcher() { } + virtual void commandWithEnumReturnValue(long callId) = 0; +}; + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(InspectorAlternateBackendDispatchers_h) +### End File: InspectorAlternateBackendDispatchers.h + +### Begin File: InspectorBackendCommands.js +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +// TypeDomain. +InspectorBackend.registerEnum("TypeDomain.TypeDomainEnum", {Shared: "shared", Red: "red", Green: "green", Blue: "blue"}); + +// CommandDomain. +InspectorBackend.registerCommand("CommandDomain.commandWithEnumReturnValue", [], ["returnValue"]); +InspectorBackend.activateDomain("CommandDomain"); + +// EventDomain. +InspectorBackend.registerEventDomainDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "EventDomain"); +InspectorBackend.registerEnum("EventDomain.EventWithEnumParameterParameter", {Shared: "shared", Black: "black", White: "white"}); +InspectorBackend.registerEvent("EventDomain.eventWithEnumParameter", ["parameter"]); +InspectorBackend.activateDomain("EventDomain"); +### End File: InspectorBackendCommands.js + +### Begin File: InspectorBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorBackendDispatchers_h +#define InspectorBackendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorBackendDispatcher.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + +typedef String ErrorString; + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +class AlternateCommandDomainBackendDispatcher; +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +class CommandDomainBackendDispatcherHandler { +public: + // Named after parameter 'returnValue' while generating command/event commandWithEnumReturnValue. + enum class ReturnValue { + Shared = 0, + Cyan = 6, + Magenta = 7, + Yellow = 8, + }; // enum class ReturnValue + virtual void commandWithEnumReturnValue(ErrorString&, CommandDomainBackendDispatcherHandler::ReturnValue* out_returnValue) = 0; +protected: + virtual ~CommandDomainBackendDispatcherHandler(); +}; + +class CommandDomainBackendDispatcher final : public SupplementalBackendDispatcher { +public: + static Ref<CommandDomainBackendDispatcher> create(BackendDispatcher*, CommandDomainBackendDispatcherHandler*); + virtual void dispatch(long callId, const String& method, Ref<InspectorObject>&& message) override; +private: + void commandWithEnumReturnValue(long callId, const InspectorObject& message); +private: + CommandDomainBackendDispatcher(BackendDispatcher&, CommandDomainBackendDispatcherHandler*); + CommandDomainBackendDispatcherHandler* m_agent; +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +public: + void setAlternateDispatcher(AlternateCommandDomainBackendDispatcher* alternateDispatcher) { m_alternateDispatcher = alternateDispatcher; } +private: + AlternateCommandDomainBackendDispatcher* m_alternateDispatcher; +#endif +}; + +} // namespace Inspector + +#endif // !defined(InspectorBackendDispatchers_h) +### End File: InspectorBackendDispatchers.h + +### Begin File: InspectorBackendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorBackendDispatchers.h" + +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/CString.h> + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "InspectorAlternateBackendDispatchers.h" +#endif + +namespace Inspector { + +CommandDomainBackendDispatcherHandler::~CommandDomainBackendDispatcherHandler() { } + +Ref<CommandDomainBackendDispatcher> CommandDomainBackendDispatcher::create(BackendDispatcher* backendDispatcher, CommandDomainBackendDispatcherHandler* agent) +{ + return adoptRef(*new CommandDomainBackendDispatcher(*backendDispatcher, agent)); +} + +CommandDomainBackendDispatcher::CommandDomainBackendDispatcher(BackendDispatcher& backendDispatcher, CommandDomainBackendDispatcherHandler* agent) + : SupplementalBackendDispatcher(backendDispatcher) + , m_agent(agent) +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + , m_alternateDispatcher(nullptr) +#endif +{ + m_backendDispatcher->registerDispatcherForDomain(ASCIILiteral("CommandDomain"), this); +} + +void CommandDomainBackendDispatcher::dispatch(long callId, const String& method, Ref<InspectorObject>&& message) +{ + Ref<CommandDomainBackendDispatcher> protect(*this); + + if (method == "commandWithEnumReturnValue") + commandWithEnumReturnValue(callId, message); + else + m_backendDispatcher->reportProtocolError(&callId, BackendDispatcher::MethodNotFound, makeString('\'', "CommandDomain", '.', method, "' was not found")); +} + +void CommandDomainBackendDispatcher::commandWithEnumReturnValue(long callId, const InspectorObject&) +{ +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + if (m_alternateDispatcher) { + m_alternateDispatcher->commandWithEnumReturnValue(callId); + return; + } +#endif + + ErrorString error; + Ref<InspectorObject> result = InspectorObject::create(); + CommandDomainBackendDispatcherHandler::ReturnValue out_returnValue; + m_agent->commandWithEnumReturnValue(error, &out_returnValue); + + if (!error.length()) + result->setString(ASCIILiteral("returnValue"), Inspector::Protocol::getEnumConstantValue(out_returnValue)); + + m_backendDispatcher->sendResponse(callId, WTF::move(result), error); +} + +} // namespace Inspector + +### End File: InspectorBackendDispatchers.cpp + +### Begin File: InspectorFrontendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorFrontendDispatchers_h +#define InspectorFrontendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + + + +class EventDomainFrontendDispatcher { +public: + EventDomainFrontendDispatcher(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { } + // Named after parameter 'parameter' while generating command/event eventWithEnumParameter. + enum class Parameter { + Shared = 0, + Black = 4, + White = 5, + }; // enum class Parameter + void eventWithEnumParameter(Parameter parameter); +private: + FrontendChannel* m_frontendChannel; +}; + +} // namespace Inspector + +#endif // !defined(InspectorFrontendDispatchers_h) +### End File: InspectorFrontendDispatchers.h + +### Begin File: InspectorFrontendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorFrontendDispatchers.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +void EventDomainFrontendDispatcher::eventWithEnumParameter(Parameter parameter) +{ + Ref<InspectorObject> jsonMessage = InspectorObject::create(); + jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("EventDomain.eventWithEnumParameter")); + Ref<InspectorObject> paramsObject = InspectorObject::create(); + paramsObject->setString(ASCIILiteral("parameter"), Inspector::Protocol::getEnumConstantValue(parameter)); + jsonMessage->setObject(ASCIILiteral("params"), WTF::move(paramsObject)); + + m_frontendChannel->sendMessageToFrontend(jsonMessage->toJSONString()); +} + +} // namespace Inspector + +### End File: InspectorFrontendDispatchers.cpp + +### Begin File: InspectorProtocolObjects.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorProtocolObjects_h +#define InspectorProtocolObjects_h + +#include <inspector/InspectorProtocolTypes.h> +#include <wtf/Assertions.h> + +namespace Inspector { + + + +namespace Protocol { + +// Forward declarations. +namespace TypeDomain { +enum class TypeDomainEnum; +} // TypeDomain +// End of forward declarations. + + + + +String getEnumConstantValue(int code); + +template<typename T> String getEnumConstantValue(T enumValue) +{ + return getEnumConstantValue(static_cast<int>(enumValue)); +} + +namespace TypeDomain { +/* */ +enum class TypeDomainEnum { + Shared = 0, + Red = 1, + Green = 2, + Blue = 3, +}; // enum class TypeDomainEnum +} // TypeDomain + + + +} // namespace Protocol + +} // namespace Inspector + +#endif // !defined(InspectorProtocolObjects_h) +### End File: InspectorProtocolObjects.h + +### Begin File: InspectorProtocolObjects.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorProtocolObjects.h" + +#include <wtf/text/CString.h> + +namespace Inspector { + +namespace Protocol { + +static const char* const enum_constant_values[] = { + "shared", + "red", + "green", + "blue", + "black", + "white", + "cyan", + "magenta", + "yellow", +}; + +String getEnumConstantValue(int code) { + return enum_constant_values[code]; +} + + + +} // namespace Protocol + +} // namespace Inspector + +### End File: InspectorProtocolObjects.cpp + +### Begin File: RWIProtocolBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#include <wtf/RetainPtr.h> + +@protocol RWIProtocolCommandDomainDomainHandler; + +namespace Inspector { + + + + +class ObjCInspectorCommandDomainBackendDispatcher final : public AlternateCommandDomainBackendDispatcher { +public: + ObjCInspectorCommandDomainBackendDispatcher(id<RWIProtocolCommandDomainDomainHandler> handler) { m_delegate = handler; } + virtual void commandWithEnumReturnValue(long callId) override; +private: + RetainPtr<id<RWIProtocolCommandDomainDomainHandler>> m_delegate; +}; + + + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.h + +### Begin File: RWIProtocolConfiguration.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolConfiguration.h" + +#import "RWIProtocolInternal.h" +#import "RWIProtocolBackendDispatchers.h" +#import <JavaScriptCore/AlternateDispatchableAgent.h> +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorAlternateBackendDispatchers.h> +#import <JavaScriptCore/InspectorBackendDispatchers.h> + +using namespace Inspector; + +@implementation RWIProtocolConfiguration +{ + AugmentableInspectorController* _controller; + id<RWIProtocolCommandDomainDomainHandler> _commandDomainHandler; + RWIProtocolEventDomainDomainEventDispatcher *_eventDomainEventDispatcher; +} + +- (instancetype)initWithController:(AugmentableInspectorController*)controller +{ + self = [super init]; + if (!self) + return nil; + ASSERT(controller); + _controller = controller; + return self; +} + +- (void)dealloc +{ + [_commandDomainHandler release]; + [_eventDomainEventDispatcher release]; + [super dealloc]; +} + +- (void)setCommandDomainHandler:(id<RWIProtocolCommandDomainDomainHandler>)handler +{ + if (handler == _commandDomainHandler) + return; + + [_commandDomainHandler release]; + _commandDomainHandler = [handler retain]; + + auto alternateDispatcher = std::make_unique<ObjCInspectorCommandDomainBackendDispatcher>(handler); + auto alternateAgent = std::make_unique<AlternateDispatchableAgent<CommandDomainBackendDispatcher, AlternateCommandDomainBackendDispatcher>>(ASCIILiteral("CommandDomain"), WTF::move(alternateDispatcher)); + _controller->appendExtraAgent(WTF::move(alternateAgent)); +} + +- (id<RWIProtocolCommandDomainDomainHandler>)commandDomainHandler +{ + return _commandDomainHandler; +} + +- (RWIProtocolEventDomainDomainEventDispatcher *)eventDomainEventDispatcher +{ + if (!_eventDomainEventDispatcher) + _eventDomainEventDispatcher = [[RWIProtocolEventDomainDomainEventDispatcher alloc] initWithController:_controller]; + return _eventDomainEventDispatcher; +} + +@end + + +### End File: RWIProtocolConfiguration.mm + +### Begin File: RWIProtocolConfiguration.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" + +__attribute__((visibility ("default"))) +@interface RWIProtocolConfiguration : NSObject +@property (nonatomic, retain, setter=setCommandDomainHandler:) id<RWIProtocolCommandDomainDomainHandler> commandDomainHandler; +@property (nonatomic, readonly) RWIProtocolEventDomainDomainEventDispatcher *eventDomainEventDispatcher; +@end + + +### End File: RWIProtocolConfiguration.h + +### Begin File: RWIProtocolBackendDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolBackendDispatchers.h" + +#include "RWIProtocolInternal.h" +#include "RWIProtocolEnumConversionHelpers.h" +#include <JavaScriptCore/InspectorFrontendChannel.h> +#include <JavaScriptCore/InspectorValues.h> + +namespace Inspector { + + + +void ObjCInspectorCommandDomainBackendDispatcher::commandWithEnumReturnValue(long callId) +{ + id errorCallback = ^(NSString *error) { + backendDispatcher()->sendResponse(callId, InspectorObject::create(), error); + }; + + id successCallback = ^(RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValue returnValue) { + Ref<InspectorObject> resultObject = InspectorObject::create(); + resultObject->setString(ASCIILiteral("returnValue"), toProtocolString(returnValue)); + backendDispatcher()->sendResponse(callId, WTF::move(resultObject), String()); + }; + + [m_delegate commandWithEnumReturnValueWithErrorCallback:errorCallback successCallback:successCallback]; +} + + + + +} // namespace Inspector + +### End File: RWIProtocolBackendDispatchers.mm + +### Begin File: RWIProtocolEnumConversionHelpers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocolArrayConversionHelpers.h" + +namespace Inspector { + +template<typename ObjCEnumType> +ObjCEnumType fromProtocolString(const String& value); + + +inline String toProtocolString(RWIProtocolTypeDomainEnum value) +{ + switch(value) { + case RWIProtocolTypeDomainEnumShared: + return ASCIILiteral("shared"); + case RWIProtocolTypeDomainEnumRed: + return ASCIILiteral("red"); + case RWIProtocolTypeDomainEnumGreen: + return ASCIILiteral("green"); + case RWIProtocolTypeDomainEnumBlue: + return ASCIILiteral("blue"); + } +} + +template<> +inline RWIProtocolTypeDomainEnum fromProtocolString(const String& value) +{ + if (value == "shared") + return RWIProtocolTypeDomainEnumShared; + if (value == "red") + return RWIProtocolTypeDomainEnumRed; + if (value == "green") + return RWIProtocolTypeDomainEnumGreen; + if (value == "blue") + return RWIProtocolTypeDomainEnumBlue; + ASSERT_NOT_REACHED(); + return RWIProtocolTypeDomainEnumShared; +} + + +inline String toProtocolString(RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValue value) +{ + switch(value) { + case RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueShared: + return ASCIILiteral("shared"); + case RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueCyan: + return ASCIILiteral("cyan"); + case RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueMagenta: + return ASCIILiteral("magenta"); + case RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueYellow: + return ASCIILiteral("yellow"); + } +} + +template<> +inline RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValue fromProtocolString(const String& value) +{ + if (value == "shared") + return RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueShared; + if (value == "cyan") + return RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueCyan; + if (value == "magenta") + return RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueMagenta; + if (value == "yellow") + return RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueYellow; + ASSERT_NOT_REACHED(); + return RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueShared; +} + + +inline String toProtocolString(RWIProtocolEventDomainEventWithEnumParameterParameter value) +{ + switch(value) { + case RWIProtocolEventDomainEventWithEnumParameterParameterShared: + return ASCIILiteral("shared"); + case RWIProtocolEventDomainEventWithEnumParameterParameterBlack: + return ASCIILiteral("black"); + case RWIProtocolEventDomainEventWithEnumParameterParameterWhite: + return ASCIILiteral("white"); + } +} + +template<> +inline RWIProtocolEventDomainEventWithEnumParameterParameter fromProtocolString(const String& value) +{ + if (value == "shared") + return RWIProtocolEventDomainEventWithEnumParameterParameterShared; + if (value == "black") + return RWIProtocolEventDomainEventWithEnumParameterParameterBlack; + if (value == "white") + return RWIProtocolEventDomainEventWithEnumParameterParameterWhite; + ASSERT_NOT_REACHED(); + return RWIProtocolEventDomainEventWithEnumParameterParameterShared; +} + +} // namespace Inspector + +### End File: RWIProtocolEnumConversionHelpers.h + +### Begin File: RWIProtocolEventDispatchers.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorFrontendChannel.h> +#import <JavaScriptCore/InspectorValues.h> + +using namespace Inspector; + + + + + +@implementation RWIProtocolEventDomainDomainEventDispatcher +{ + AugmentableInspectorController* _controller; +} + +- (instancetype)initWithController:(AugmentableInspectorController*)controller; +{ + self = [super init]; + if (!self) + return nil; + ASSERT(controller); + _controller = controller; + return self; +} + +- (void)eventWithEnumParameterWithParameter:(RWIProtocolEventDomainEventWithEnumParameterParameter)parameter +{ + FrontendChannel* frontendChannel = _controller->frontendChannel(); + if (!frontendChannel) + return; + + Ref<InspectorObject> jsonMessage = InspectorObject::create(); + jsonMessage->setString(ASCIILiteral("method"), ASCIILiteral("EventDomain.eventWithEnumParameter")); + Ref<InspectorObject> paramsObject = InspectorObject::create(); + paramsObject->setString(ASCIILiteral("parameter"), toProtocolString(parameter)); + jsonMessage->setObject(ASCIILiteral("params"), WTF::move(paramsObject)); + frontendChannel->sendMessageToFrontend(jsonMessage->toJSONString()); +} + +@end + + +### End File: RWIProtocolEventDispatchers.mm + +### Begin File: RWIProtocol.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import <Foundation/Foundation.h> + +#import <WebInspector/RWIProtocolJSONObject.h> + + + + + +typedef NS_ENUM(NSInteger, RWIProtocolTypeDomainEnum) { + RWIProtocolTypeDomainEnumShared, + RWIProtocolTypeDomainEnumRed, + RWIProtocolTypeDomainEnumGreen, + RWIProtocolTypeDomainEnumBlue, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValue) { + RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueShared, + RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueCyan, + RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueMagenta, + RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValueYellow, +}; + +typedef NS_ENUM(NSInteger, RWIProtocolEventDomainEventWithEnumParameterParameter) { + RWIProtocolEventDomainEventWithEnumParameterParameterShared, + RWIProtocolEventDomainEventWithEnumParameterParameterBlack, + RWIProtocolEventDomainEventWithEnumParameterParameterWhite, +}; + + + +@protocol RWIProtocolCommandDomainDomainHandler <NSObject> +@required +- (void)commandWithEnumReturnValueWithErrorCallback:(void(^)(NSString *error))errorCallback successCallback:(void(^)(RWIProtocolCommandDomainCommandWithEnumReturnValueReturnValue returnValue))successCallback; +@end + +__attribute__((visibility ("default"))) +@interface RWIProtocolEventDomainDomainEventDispatcher : NSObject +- (void)eventWithEnumParameterWithParameter:(RWIProtocolEventDomainEventWithEnumParameterParameter)parameter; +@end + + +### End File: RWIProtocol.h + +### Begin File: RWIProtocolTypes.mm +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "config.h" +#import "RWIProtocolInternal.h" + +#import "RWIProtocolEnumConversionHelpers.h" +#import <JavaScriptCore/InspectorValues.h> +#import <wtf/Assertions.h> + +using namespace Inspector; + + + + + + + + +### End File: RWIProtocolTypes.mm + +### Begin File: RWIProtocolInternal.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from enum-values.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#import "RWIProtocol.h" +#import "RWIProtocolJSONObjectInternal.h" +#import <JavaScriptCore/AugmentableInspectorController.h> +#import <JavaScriptCore/InspectorValues.h> + +@interface RWIProtocolEventDomainDomainEventDispatcher (Private) +- (instancetype)initWithController:(Inspector::AugmentableInspectorController*)controller; +@end + + +### End File: RWIProtocolInternal.h diff --git a/inspector/scripts/tests/expected/events-with-optional-parameters.json-result b/inspector/scripts/tests/expected/events-with-optional-parameters.json-result new file mode 100644 index 0000000..4b622d9 --- /dev/null +++ b/inspector/scripts/tests/expected/events-with-optional-parameters.json-result @@ -0,0 +1,1108 @@ +### Begin File: InspectorAlternateBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from events-with-optional-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorAlternateBackendDispatchers_h +#define InspectorAlternateBackendDispatchers_h + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#include "InspectorProtocolTypes.h" +#include <JavaScriptCore/InspectorBackendDispatcher.h> + +namespace Inspector { + +class AlternateBackendDispatcher { +public: + void setBackendDispatcher(RefPtr<BackendDispatcher>&& dispatcher) { m_backendDispatcher = WTF::move(dispatcher); } + BackendDispatcher* backendDispatcher() const { return m_backendDispatcher.get(); } +private: + RefPtr<BackendDispatcher> m_backendDispatcher; +}; + + + + +} // namespace Inspector + +#endif // ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) + +#endif // !defined(InspectorAlternateBackendDispatchers_h) +### End File: InspectorAlternateBackendDispatchers.h + +### Begin File: InspectorBackendCommands.js +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from events-with-optional-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +// Database. +InspectorBackend.registerDatabaseDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Database"); +InspectorBackend.registerEvent("Database.didExecuteOptionalParameters", ["columnNames", "notes", "timestamp", "values", "payload", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.registerEvent("Database.didExecuteNoOptionalParameters", ["columnNames", "notes", "timestamp", "values", "payload", "sqlError", "screenColor", "alternateColors", "printColor"]); +InspectorBackend.activateDomain("Database"); +### End File: InspectorBackendCommands.js + +### Begin File: InspectorBackendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from events-with-optional-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#ifndef InspectorBackendDispatchers_h +#define InspectorBackendDispatchers_h + +#include "InspectorProtocolObjects.h" +#include <inspector/InspectorBackendDispatcher.h> +#include <wtf/text/WTFString.h> + +namespace Inspector { + +typedef String ErrorString; + + + +} // namespace Inspector + +#endif // !defined(InspectorBackendDispatchers_h) +### End File: InspectorBackendDispatchers.h + +### Begin File: InspectorBackendDispatchers.cpp +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// DO NOT EDIT THIS FILE. It is automatically generated from events-with-optional-parameters.json +// by the script: Source/JavaScriptCore/inspector/scripts/generate-inspector-protocol-bindings.py + +#include "config.h" +#include "InspectorBackendDispatchers.h" + +#include <inspector/InspectorFrontendChannel.h> +#include <inspector/InspectorValues.h> +#include <wtf/text/CString.h> + +#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) +#include "InspectorAlternateBackendDispatchers.h" +#endif + +namespace Inspector { + + + +} // namespace Inspector + +### End File: InspectorBackendDispatchers.cpp + +### Begin File: InspectorFrontendDispatchers.h +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 University of Washington. 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