Title: [244309] trunk/Source/_javascript_Core
Revision
244309
Author
[email protected]
Date
2019-04-15 16:53:23 -0700 (Mon, 15 Apr 2019)

Log Message

B3::Value should have different kinds of adjacency lists
https://bugs.webkit.org/show_bug.cgi?id=196091

Reviewed by Filip Pizlo.

The key idea of this optimization is to replace the Vector<Value*, 3> m_children in B3::Value (40 bytes on 64-bits platform) by one of the following:
- Nothing (0 bytes)
- 1 Value* (8 bytes)
- 2 Value* (16 bytes)
- 3 Value* (24 bytes)
- A Vector<Value*, 3>
after the end of the Value object, depending on the kind of the Value.
So for example, when allocating an Add, we would allocate an extra 16 bytes into which to store 2 Values.
This would halve the memory consumption of Const64/Const32/Nop/Identity and a bunch more kinds of values, and reduce by a more moderate amount the memory consumption of the rest of non-varargs values (e.g. Add would go from 72 to 48 bytes).

A few implementation points:
- Even if there is no children, we must remember to allocate at least enough space for replaceWithIdentity to work later. It needs sizeof(Value) (for the object itself) + sizeof(Value*) (for the pointer to its child)
- We must make sure to destroy the vector whenever we destroy a Value which is VarArgs
- We must remember how many elements there are in the case where we did not allocate a Vector. We cannot do it purely by relying on the kind, both for speed reasons and because Return can have either 0 or 1 argument in B3
  Thankfully, we have an extra byte of padding to use in the middle of B3::Value
- In order to support clone(), we must have a separate version of allocate, which extracts the opcode from the to-be-cloned object instead of from the call to the constructor
- Speaking of which, we need a special templated function opcodeFromConstructor, because some of the constructors of subclasses of Value don't take an explicit Opcode as argument, typically because they match a single one.
- To maximize performance, we provide specialized versions of child/lastChild/numChildren/children in the subclasses of Value, skipping checks when the actual type of the Value is already known.
  This is done through the B3_SPECIALIZE_VALUE_FOR_... defined at the bottom of B3Value.h
- In the constructors of Value, we convert all extra children arguments to Value* eagerly. It is not required for correctness (they will be converted when put into a Vector<Value*> or a Value* in the end), but it helps limit an explosion in the number of template instantiations.
- I moved DeepValueDump::dump from the .h to the .cpp, as there is no good reason to inline it, and recompiling JSC is already slow enough

* _javascript_Core.xcodeproj/project.pbxproj:
* b3/B3ArgumentRegValue.cpp:
(JSC::B3::ArgumentRegValue::cloneImpl const): Deleted.
* b3/B3ArgumentRegValue.h:
* b3/B3AtomicValue.cpp:
(JSC::B3::AtomicValue::AtomicValue):
(JSC::B3::AtomicValue::cloneImpl const): Deleted.
* b3/B3AtomicValue.h:
* b3/B3BasicBlock.h:
* b3/B3BasicBlockInlines.h:
(JSC::B3::BasicBlock::appendNewNonTerminal): Deleted.
* b3/B3CCallValue.cpp:
(JSC::B3::CCallValue::appendArgs):
(JSC::B3::CCallValue::cloneImpl const): Deleted.
* b3/B3CCallValue.h:
* b3/B3CheckValue.cpp:
(JSC::B3::CheckValue::cloneImpl const): Deleted.
* b3/B3CheckValue.h:
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::cloneImpl const): Deleted.
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::cloneImpl const): Deleted.
* b3/B3Const64Value.h:
* b3/B3ConstDoubleValue.cpp:
(JSC::B3::ConstDoubleValue::cloneImpl const): Deleted.
* b3/B3ConstDoubleValue.h:
* b3/B3ConstFloatValue.cpp:
(JSC::B3::ConstFloatValue::cloneImpl const): Deleted.
* b3/B3ConstFloatValue.h:
* b3/B3ConstPtrValue.h:
(JSC::B3::ConstPtrValue::opcodeFromConstructor):
* b3/B3FenceValue.cpp:
(JSC::B3::FenceValue::FenceValue):
(JSC::B3::FenceValue::cloneImpl const): Deleted.
* b3/B3FenceValue.h:
* b3/B3MemoryValue.cpp:
(JSC::B3::MemoryValue::MemoryValue):
(JSC::B3::MemoryValue::cloneImpl const): Deleted.
* b3/B3MemoryValue.h:
* b3/B3MoveConstants.cpp:
* b3/B3PatchpointValue.cpp:
(JSC::B3::PatchpointValue::cloneImpl const): Deleted.
* b3/B3PatchpointValue.h:
(JSC::B3::PatchpointValue::opcodeFromConstructor):
* b3/B3Procedure.cpp:
* b3/B3Procedure.h:
* b3/B3ProcedureInlines.h:
(JSC::B3::Procedure::add):
* b3/B3SlotBaseValue.cpp:
(JSC::B3::SlotBaseValue::cloneImpl const): Deleted.
* b3/B3SlotBaseValue.h:
* b3/B3StackmapSpecial.cpp:
(JSC::B3::StackmapSpecial::forEachArgImpl):
(JSC::B3::StackmapSpecial::isValidImpl):
* b3/B3StackmapValue.cpp:
(JSC::B3::StackmapValue::append):
(JSC::B3::StackmapValue::StackmapValue):
* b3/B3StackmapValue.h:
* b3/B3SwitchValue.cpp:
(JSC::B3::SwitchValue::SwitchValue):
(JSC::B3::SwitchValue::cloneImpl const): Deleted.
* b3/B3SwitchValue.h:
(JSC::B3::SwitchValue::opcodeFromConstructor):
* b3/B3UpsilonValue.cpp:
(JSC::B3::UpsilonValue::cloneImpl const): Deleted.
* b3/B3UpsilonValue.h:
* b3/B3Value.cpp:
(JSC::B3::DeepValueDump::dump const):
(JSC::B3::Value::~Value):
(JSC::B3::Value::replaceWithIdentity):
(JSC::B3::Value::replaceWithNopIgnoringType):
(JSC::B3::Value::replaceWithPhi):
(JSC::B3::Value::replaceWithJump):
(JSC::B3::Value::replaceWithOops):
(JSC::B3::Value::replaceWith):
(JSC::B3::Value::invertedCompare const):
(JSC::B3::Value::returnsBool const):
(JSC::B3::Value::cloneImpl const): Deleted.
* b3/B3Value.h:
(JSC::B3::DeepValueDump::dump const): Deleted.
* b3/B3ValueInlines.h:
(JSC::B3::Value::adjacencyListOffset const):
(JSC::B3::Value::cloneImpl const):
* b3/B3VariableValue.cpp:
(JSC::B3::VariableValue::VariableValue):
(JSC::B3::VariableValue::cloneImpl const): Deleted.
* b3/B3VariableValue.h:
* b3/B3WasmAddressValue.cpp:
(JSC::B3::WasmAddressValue::WasmAddressValue):
(JSC::B3::WasmAddressValue::cloneImpl const): Deleted.
* b3/B3WasmAddressValue.h:
* b3/B3WasmBoundsCheckValue.cpp:
(JSC::B3::WasmBoundsCheckValue::WasmBoundsCheckValue):
(JSC::B3::WasmBoundsCheckValue::cloneImpl const): Deleted.
* b3/B3WasmBoundsCheckValue.h:
(JSC::B3::WasmBoundsCheckValue::accepts):
(JSC::B3::WasmBoundsCheckValue::opcodeFromConstructor):
* b3/testb3.cpp:
(JSC::B3::testCallFunctionWithHellaArguments):
(JSC::B3::testCallFunctionWithHellaArguments2):
(JSC::B3::testCallFunctionWithHellaArguments3):
(JSC::B3::testCallFunctionWithHellaDoubleArguments):
(JSC::B3::testCallFunctionWithHellaFloatArguments):
* ftl/FTLOutput.h:
(JSC::FTL::Output::call):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (244308 => 244309)


--- trunk/Source/_javascript_Core/ChangeLog	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-04-15 23:53:23 UTC (rev 244309)
@@ -1,3 +1,139 @@
+2019-04-15  Robin Morisset  <[email protected]>
+
+        B3::Value should have different kinds of adjacency lists
+        https://bugs.webkit.org/show_bug.cgi?id=196091
+
+        Reviewed by Filip Pizlo.
+
+        The key idea of this optimization is to replace the Vector<Value*, 3> m_children in B3::Value (40 bytes on 64-bits platform) by one of the following:
+        - Nothing (0 bytes)
+        - 1 Value* (8 bytes)
+        - 2 Value* (16 bytes)
+        - 3 Value* (24 bytes)
+        - A Vector<Value*, 3>
+        after the end of the Value object, depending on the kind of the Value.
+        So for example, when allocating an Add, we would allocate an extra 16 bytes into which to store 2 Values.
+        This would halve the memory consumption of Const64/Const32/Nop/Identity and a bunch more kinds of values, and reduce by a more moderate amount the memory consumption of the rest of non-varargs values (e.g. Add would go from 72 to 48 bytes).
+
+        A few implementation points:
+        - Even if there is no children, we must remember to allocate at least enough space for replaceWithIdentity to work later. It needs sizeof(Value) (for the object itself) + sizeof(Value*) (for the pointer to its child)
+        - We must make sure to destroy the vector whenever we destroy a Value which is VarArgs
+        - We must remember how many elements there are in the case where we did not allocate a Vector. We cannot do it purely by relying on the kind, both for speed reasons and because Return can have either 0 or 1 argument in B3
+          Thankfully, we have an extra byte of padding to use in the middle of B3::Value
+        - In order to support clone(), we must have a separate version of allocate, which extracts the opcode from the to-be-cloned object instead of from the call to the constructor
+        - Speaking of which, we need a special templated function opcodeFromConstructor, because some of the constructors of subclasses of Value don't take an explicit Opcode as argument, typically because they match a single one.
+        - To maximize performance, we provide specialized versions of child/lastChild/numChildren/children in the subclasses of Value, skipping checks when the actual type of the Value is already known.
+          This is done through the B3_SPECIALIZE_VALUE_FOR_... defined at the bottom of B3Value.h
+        - In the constructors of Value, we convert all extra children arguments to Value* eagerly. It is not required for correctness (they will be converted when put into a Vector<Value*> or a Value* in the end), but it helps limit an explosion in the number of template instantiations.
+        - I moved DeepValueDump::dump from the .h to the .cpp, as there is no good reason to inline it, and recompiling JSC is already slow enough
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * b3/B3ArgumentRegValue.cpp:
+        (JSC::B3::ArgumentRegValue::cloneImpl const): Deleted.
+        * b3/B3ArgumentRegValue.h:
+        * b3/B3AtomicValue.cpp:
+        (JSC::B3::AtomicValue::AtomicValue):
+        (JSC::B3::AtomicValue::cloneImpl const): Deleted.
+        * b3/B3AtomicValue.h:
+        * b3/B3BasicBlock.h:
+        * b3/B3BasicBlockInlines.h:
+        (JSC::B3::BasicBlock::appendNewNonTerminal): Deleted.
+        * b3/B3CCallValue.cpp:
+        (JSC::B3::CCallValue::appendArgs):
+        (JSC::B3::CCallValue::cloneImpl const): Deleted.
+        * b3/B3CCallValue.h:
+        * b3/B3CheckValue.cpp:
+        (JSC::B3::CheckValue::cloneImpl const): Deleted.
+        * b3/B3CheckValue.h:
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::cloneImpl const): Deleted.
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::cloneImpl const): Deleted.
+        * b3/B3Const64Value.h:
+        * b3/B3ConstDoubleValue.cpp:
+        (JSC::B3::ConstDoubleValue::cloneImpl const): Deleted.
+        * b3/B3ConstDoubleValue.h:
+        * b3/B3ConstFloatValue.cpp:
+        (JSC::B3::ConstFloatValue::cloneImpl const): Deleted.
+        * b3/B3ConstFloatValue.h:
+        * b3/B3ConstPtrValue.h:
+        (JSC::B3::ConstPtrValue::opcodeFromConstructor):
+        * b3/B3FenceValue.cpp:
+        (JSC::B3::FenceValue::FenceValue):
+        (JSC::B3::FenceValue::cloneImpl const): Deleted.
+        * b3/B3FenceValue.h:
+        * b3/B3MemoryValue.cpp:
+        (JSC::B3::MemoryValue::MemoryValue):
+        (JSC::B3::MemoryValue::cloneImpl const): Deleted.
+        * b3/B3MemoryValue.h:
+        * b3/B3MoveConstants.cpp:
+        * b3/B3PatchpointValue.cpp:
+        (JSC::B3::PatchpointValue::cloneImpl const): Deleted.
+        * b3/B3PatchpointValue.h:
+        (JSC::B3::PatchpointValue::opcodeFromConstructor):
+        * b3/B3Procedure.cpp:
+        * b3/B3Procedure.h:
+        * b3/B3ProcedureInlines.h:
+        (JSC::B3::Procedure::add):
+        * b3/B3SlotBaseValue.cpp:
+        (JSC::B3::SlotBaseValue::cloneImpl const): Deleted.
+        * b3/B3SlotBaseValue.h:
+        * b3/B3StackmapSpecial.cpp:
+        (JSC::B3::StackmapSpecial::forEachArgImpl):
+        (JSC::B3::StackmapSpecial::isValidImpl):
+        * b3/B3StackmapValue.cpp:
+        (JSC::B3::StackmapValue::append):
+        (JSC::B3::StackmapValue::StackmapValue):
+        * b3/B3StackmapValue.h:
+        * b3/B3SwitchValue.cpp:
+        (JSC::B3::SwitchValue::SwitchValue):
+        (JSC::B3::SwitchValue::cloneImpl const): Deleted.
+        * b3/B3SwitchValue.h:
+        (JSC::B3::SwitchValue::opcodeFromConstructor):
+        * b3/B3UpsilonValue.cpp:
+        (JSC::B3::UpsilonValue::cloneImpl const): Deleted.
+        * b3/B3UpsilonValue.h:
+        * b3/B3Value.cpp:
+        (JSC::B3::DeepValueDump::dump const):
+        (JSC::B3::Value::~Value):
+        (JSC::B3::Value::replaceWithIdentity):
+        (JSC::B3::Value::replaceWithNopIgnoringType):
+        (JSC::B3::Value::replaceWithPhi):
+        (JSC::B3::Value::replaceWithJump):
+        (JSC::B3::Value::replaceWithOops):
+        (JSC::B3::Value::replaceWith):
+        (JSC::B3::Value::invertedCompare const):
+        (JSC::B3::Value::returnsBool const):
+        (JSC::B3::Value::cloneImpl const): Deleted.
+        * b3/B3Value.h:
+        (JSC::B3::DeepValueDump::dump const): Deleted.
+        * b3/B3ValueInlines.h:
+        (JSC::B3::Value::adjacencyListOffset const):
+        (JSC::B3::Value::cloneImpl const):
+        * b3/B3VariableValue.cpp:
+        (JSC::B3::VariableValue::VariableValue):
+        (JSC::B3::VariableValue::cloneImpl const): Deleted.
+        * b3/B3VariableValue.h:
+        * b3/B3WasmAddressValue.cpp:
+        (JSC::B3::WasmAddressValue::WasmAddressValue):
+        (JSC::B3::WasmAddressValue::cloneImpl const): Deleted.
+        * b3/B3WasmAddressValue.h:
+        * b3/B3WasmBoundsCheckValue.cpp:
+        (JSC::B3::WasmBoundsCheckValue::WasmBoundsCheckValue):
+        (JSC::B3::WasmBoundsCheckValue::cloneImpl const): Deleted.
+        * b3/B3WasmBoundsCheckValue.h:
+        (JSC::B3::WasmBoundsCheckValue::accepts):
+        (JSC::B3::WasmBoundsCheckValue::opcodeFromConstructor):
+        * b3/testb3.cpp:
+        (JSC::B3::testCallFunctionWithHellaArguments):
+        (JSC::B3::testCallFunctionWithHellaArguments2):
+        (JSC::B3::testCallFunctionWithHellaArguments3):
+        (JSC::B3::testCallFunctionWithHellaDoubleArguments):
+        (JSC::B3::testCallFunctionWithHellaFloatArguments):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::call):
+
 2019-04-15  Tadeu Zagallo  <[email protected]>
 
         Bytecode cache should not encode the SourceProvider for UnlinkedFunctionExecutable's classSource

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (244308 => 244309)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-04-15 23:53:23 UTC (rev 244309)
@@ -669,7 +669,6 @@
 		0FEC85401BDACDAC0080FF74 /* B3UseCounts.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84F61BDACDAC0080FF74 /* B3UseCounts.h */; };
 		0FEC85421BDACDAC0080FF74 /* B3Validate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84F81BDACDAC0080FF74 /* B3Validate.h */; };
 		0FEC85441BDACDAC0080FF74 /* B3Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FA1BDACDAC0080FF74 /* B3Value.h */; };
-		0FEC85451BDACDAC0080FF74 /* B3ValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FB1BDACDAC0080FF74 /* B3ValueInlines.h */; };
 		0FEC85471BDACDAC0080FF74 /* B3ValueRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FD1BDACDAC0080FF74 /* B3ValueRep.h */; };
 		0FEC856E1BDACDC70080FF74 /* AirAllocateStackByGraphColoring.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85491BDACDC70080FF74 /* AirAllocateStackByGraphColoring.h */; };
 		0FEC85701BDACDC70080FF74 /* AirArg.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC854B1BDACDC70080FF74 /* AirArg.h */; };
@@ -857,6 +856,8 @@
 		2AF7382D18BBBF92008A5A37 /* StructureIDTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AF7382B18BBBF92008A5A37 /* StructureIDTable.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		2D342F36F7244096804ADB24 /* SourceOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 425BA1337E4344E1B269A671 /* SourceOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		3395C70722555F6D00BDBFAD /* B3EliminateDeadCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3395C70522555F6D00BDBFAD /* B3EliminateDeadCode.h */; };
+		33B2A54722653481005A0F79 /* B3ValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FB1BDACDAC0080FF74 /* B3ValueInlines.h */; };
+		33B2A548226543BF005A0F79 /* FTLLowerDFGToB3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEA0A04170513DB00BB722C /* FTLLowerDFGToB3.cpp */; };
 		371D842D17C98B6E00ECF994 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 371D842C17C98B6E00ECF994 /* libz.dylib */; };
 		37C738D21EDB56E4003F2B0B /* ParseInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 37C738D11EDB5672003F2B0B /* ParseInt.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		412952771D2CF6BC00E78B89 /* builtins_generate_internals_wrapper_header.py in Headers */ = {isa = PBXBuildFile; fileRef = 412952731D2CF6AC00E78B89 /* builtins_generate_internals_wrapper_header.py */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -918,7 +919,6 @@
 		5333BBDB2110F7D2007618EC /* DFGSpeculativeJIT32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */; };
 		5333BBDC2110F7D9007618EC /* DFGSpeculativeJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EC9DC21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp */; };
 		5333BBDD2110F7E1007618EC /* DFGSpeculativeJIT64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */; };
-		5333BBDE2110FA3E007618EC /* FTLLowerDFGToB3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEA0A04170513DB00BB722C /* FTLLowerDFGToB3.cpp */; };
 		5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */; };
 		534638711E70CF3D00F12AC1 /* JSRunLoopTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		534638751E70DDEC00F12AC1 /* PromiseDeferredTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 534638741E70DDEC00F12AC1 /* PromiseDeferredTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -8506,6 +8506,7 @@
 				0F2C63BC1E63440C00C13839 /* AirBlockInsertionSet.h in Headers */,
 				0FB3878E1BFBC44D00E3AB1E /* AirBlockWorklist.h in Headers */,
 				0F79C7CA1E74C93B00EB34D1 /* AirBreakCriticalEdges.h in Headers */,
+				33B2A54722653481005A0F79 /* B3ValueInlines.h in Headers */,
 				0F61832A1C45BF070072450B /* AirCCallingConvention.h in Headers */,
 				0FEC85741BDACDC70080FF74 /* AirCCallSpecial.h in Headers */,
 				0FF4B4C71E8893C500DBBE86 /* AirCFG.h in Headers */,
@@ -8698,7 +8699,6 @@
 				0FEC85401BDACDAC0080FF74 /* B3UseCounts.h in Headers */,
 				0FEC85421BDACDAC0080FF74 /* B3Validate.h in Headers */,
 				0FEC85441BDACDAC0080FF74 /* B3Value.h in Headers */,
-				0FEC85451BDACDAC0080FF74 /* B3ValueInlines.h in Headers */,
 				0F338E151BF0276C0013C88F /* B3ValueKey.h in Headers */,
 				0F338E161BF0276C0013C88F /* B3ValueKeyInlines.h in Headers */,
 				0FEC85471BDACDAC0080FF74 /* B3ValueRep.h in Headers */,
@@ -10703,7 +10703,6 @@
 				5333BBDC2110F7D9007618EC /* DFGSpeculativeJIT.cpp in Sources */,
 				5333BBDB2110F7D2007618EC /* DFGSpeculativeJIT32_64.cpp in Sources */,
 				5333BBDD2110F7E1007618EC /* DFGSpeculativeJIT64.cpp in Sources */,
-				5333BBDE2110FA3E007618EC /* FTLLowerDFGToB3.cpp in Sources */,
 				536B319E1F735F160037FC33 /* LowLevelInterpreter.cpp in Sources */,
 				0FF4274A158EBE91004CB9FF /* udis86.c in Sources */,
 				0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */,
@@ -10837,6 +10836,7 @@
 				536B310C1F71C5990037FC33 /* UnifiedSource119.cpp in Sources */,
 				536B31261F71C5990037FC33 /* UnifiedSource120.cpp in Sources */,
 				536B312D1F71C5990037FC33 /* UnifiedSource121.cpp in Sources */,
+				33B2A548226543BF005A0F79 /* FTLLowerDFGToB3.cpp in Sources */,
 				536B31251F71C5990037FC33 /* UnifiedSource122.cpp in Sources */,
 				536B311E1F71C5990037FC33 /* UnifiedSource123.cpp in Sources */,
 				536B31141F71C5990037FC33 /* UnifiedSource124.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/b3/B3ArgumentRegValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ArgumentRegValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ArgumentRegValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -39,11 +39,6 @@
     out.print(comma, m_reg);
 }
 
-Value* ArgumentRegValue::cloneImpl() const
-{
-    return new ArgumentRegValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3ArgumentRegValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ArgumentRegValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ArgumentRegValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -40,16 +40,19 @@
 
     Reg argumentReg() const { return m_reg; }
 
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
+    
+    static Opcode opcodeFromConstructor(Origin, Reg) { return ArgumentReg; }
 
     ArgumentRegValue(Origin origin, Reg reg)
-        : Value(CheckedOpcode, ArgumentReg, reg.isGPR() ? pointerType() : Double, origin)
+        : Value(CheckedOpcode, ArgumentReg, reg.isGPR() ? pointerType() : Double, Zero, origin)
         , m_reg(reg)
     {
         ASSERT(reg.isSet());

Modified: trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -41,13 +41,8 @@
     MemoryValue::dumpMeta(comma, out);
 }
 
-Value* AtomicValue::cloneImpl() const
-{
-    return new AtomicValue(*this);
-}
-
 AtomicValue::AtomicValue(AtomicValue::AtomicValueRMW, Kind kind, Origin origin, Width width, Value* operand, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
-    : MemoryValue(CheckedOpcode, kind, operand->type(), origin, offset, range, fenceRange, operand, pointer)
+    : MemoryValue(CheckedOpcode, kind, operand->type(), Two, origin, offset, range, fenceRange, operand, pointer)
     , m_width(width)
 {
     ASSERT(bestType(GP, accessWidth()) == accessType());
@@ -66,7 +61,7 @@
 }
 
 AtomicValue::AtomicValue(AtomicValue::AtomicValueCAS, Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
-    : MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), origin, offset, range, fenceRange, expectedValue, newValue, pointer)
+    : MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), Three, origin, offset, range, fenceRange, expectedValue, newValue, pointer)
     , m_width(width)
 {
     ASSERT(bestType(GP, accessWidth()) == accessType());

Modified: trunk/Source/_javascript_Core/b3/B3AtomicValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3AtomicValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3AtomicValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -44,14 +44,15 @@
     Type accessType() const { return child(0)->type(); }
     
     Width accessWidth() const { return m_width; }
+
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
-    
-    Value* cloneImpl() const override;
-    
+
 private:
     friend class Procedure;
+    friend class Value;
 
     enum AtomicValueRMW { AtomicValueRMWTag };
     enum AtomicValueCAS { AtomicValueCASTag };

Modified: trunk/Source/_javascript_Core/b3/B3BasicBlock.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3BasicBlock.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3BasicBlock.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -84,8 +84,6 @@
 
     template<typename ValueType, typename... Arguments>
     ValueType* appendNew(Procedure&, Arguments...);
-    template<typename ValueType, typename... Arguments>
-    ValueType* appendNewNonTerminal(Procedure&, Arguments...);
 
     JS_EXPORT_PRIVATE Value* appendIntConstant(Procedure&, Origin, Type, int64_t value);
     Value* appendIntConstant(Procedure&, Value* likeValue, int64_t value);

Modified: trunk/Source/_javascript_Core/b3/B3BasicBlockInlines.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3BasicBlockInlines.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3BasicBlockInlines.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -42,14 +42,6 @@
 }
 
 template<typename ValueType, typename... Arguments>
-ValueType* BasicBlock::appendNewNonTerminal(Procedure& procedure, Arguments... arguments)
-{
-    ValueType* result = procedure.add<ValueType>(arguments...);
-    appendNonTerminal(result);
-    return result;
-}
-
-template<typename ValueType, typename... Arguments>
 ValueType* BasicBlock::replaceLastWithNew(Procedure& procedure, Arguments... arguments)
 {
     ValueType* result = procedure.add<ValueType>(arguments...);

Modified: trunk/Source/_javascript_Core/b3/B3CCallValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3CCallValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3CCallValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -34,9 +34,9 @@
 {
 }
 
-Value* CCallValue::cloneImpl() const
+void CCallValue::appendArgs(const Vector<Value*>& args)
 {
-    return new CCallValue(*this);
+    childrenVector().appendVector(args);
 }
 
 } } // namespace JSC::B3

Modified: trunk/Source/_javascript_Core/b3/B3CCallValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3CCallValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3CCallValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -38,17 +38,23 @@
 
     ~CCallValue();
 
+    void appendArgs(const Vector<Value*>&);
+    
     Effects effects;
 
-protected:
-    Value* cloneImpl() const override;
-    
+    B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
+
 private:
     friend class Procedure;
+    friend class Value;
 
     template<typename... Arguments>
+    static Opcode opcodeFromConstructor(Arguments...) { return CCall; }
+
+    template<typename... Arguments>
     CCallValue(Type type, Origin origin, Arguments... arguments)
-        : Value(CheckedOpcode, CCall, type, origin, arguments...)
+        : Value(CheckedOpcode, CCall, type, VarArgs, origin, static_cast<Value*>(arguments)...)
         , effects(Effects::forCall())
     {
         RELEASE_ASSERT(numChildren() >= 1);
@@ -56,7 +62,7 @@
 
     template<typename... Arguments>
     CCallValue(Type type, Origin origin, const Effects& effects, Arguments... arguments)
-        : Value(CheckedOpcode, CCall, type, origin, arguments...)
+        : Value(CheckedOpcode, CCall, type, VarArgs, origin, static_cast<Value*>(arguments)...)
         , effects(effects)
     {
         RELEASE_ASSERT(numChildren() >= 1);

Modified: trunk/Source/_javascript_Core/b3/B3CheckValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3CheckValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3CheckValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -40,11 +40,6 @@
     m_kind = CheckAdd;
 }
 
-Value* CheckValue::cloneImpl() const
-{
-    return new CheckValue(*this);
-}
-
 // Use this form for CheckAdd, CheckSub, and CheckMul.
 CheckValue::CheckValue(Kind kind, Origin origin, Value* left, Value* right)
     : StackmapValue(CheckedOpcode, kind, left->type(), origin)

Modified: trunk/Source/_javascript_Core/b3/B3CheckValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3CheckValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3CheckValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -50,11 +50,11 @@
 
     void convertToAdd();
 
-protected:
-    Value* cloneImpl() const override;
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
     
 private:
     friend class Procedure;
+    friend class Value;
 
     // Use this form for CheckAdd, CheckSub, and CheckMul.
     JS_EXPORT_PRIVATE CheckValue(Kind, Origin, Value* left, Value* right);

Modified: trunk/Source/_javascript_Core/b3/B3Const32Value.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Const32Value.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Const32Value.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -303,11 +303,6 @@
     out.print(comma, m_value);
 }
 
-Value* Const32Value::cloneImpl() const
-{
-    return new Const32Value(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3Const32Value.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Const32Value.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Const32Value.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -75,20 +75,24 @@
     TriState aboveEqualConstant(const Value* other) const override;
     TriState belowEqualConstant(const Value* other) const override;
 
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
+    // Protected because of ConstPtrValue
+    static Opcode opcodeFromConstructor(Origin = Origin(), int32_t = 0) { return Const32; }
 
-    friend class Procedure;
-
     Const32Value(Origin origin, int32_t value)
-        : Value(CheckedOpcode, Const32, Int32, origin)
+        : Value(CheckedOpcode, Const32, Int32, Zero, origin)
         , m_value(value)
     {
     }
 
 private:
+    friend class Procedure;
+    friend class Value;
+
     int32_t m_value;
 };
 

Modified: trunk/Source/_javascript_Core/b3/B3Const64Value.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Const64Value.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Const64Value.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -303,11 +303,6 @@
     out.print(comma, m_value);
 }
 
-Value* Const64Value::cloneImpl() const
-{
-    return new Const64Value(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3Const64Value.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Const64Value.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Const64Value.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -75,20 +75,24 @@
     TriState aboveEqualConstant(const Value* other) const override;
     TriState belowEqualConstant(const Value* other) const override;
 
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
+    // Protected because of ConstPtrValue
+    static Opcode opcodeFromConstructor(Origin = Origin(), int64_t = 0) { return Const64; }
 
-    friend class Procedure;
-
     Const64Value(Origin origin, int64_t value)
-        : Value(CheckedOpcode, Const64, Int64, origin)
+        : Value(CheckedOpcode, Const64, Int64, Zero, origin)
         , m_value(value)
     {
     }
-    
+
 private:
+    friend class Procedure;
+    friend class Value;
+
     int64_t m_value;
 };
 

Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -197,11 +197,6 @@
     out.printf("%le", m_value);
 }
 
-Value* ConstDoubleValue::cloneImpl() const
-{
-    return new ConstDoubleValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -64,16 +64,18 @@
     TriState greaterEqualConstant(const Value* other) const override;
     TriState equalOrUnorderedConstant(const Value* other) const override;
 
-protected:
-    void dumpMeta(CommaPrinter&, PrintStream&) const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    void dumpMeta(CommaPrinter&, PrintStream&) const override;
+
+    static Opcode opcodeFromConstructor(Origin, double) { return ConstDouble; }
+
     ConstDoubleValue(Origin origin, double value)
-        : Value(CheckedOpcode, ConstDouble, Double, origin)
+        : Value(CheckedOpcode, ConstDouble, Double, Zero, origin)
         , m_value(value)
     {
     }

Modified: trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -189,11 +189,6 @@
     out.printf("%le", m_value);
 }
 
-Value* ConstFloatValue::cloneImpl() const
-{
-    return new ConstFloatValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -63,16 +63,18 @@
     TriState greaterEqualConstant(const Value* other) const override;
     TriState equalOrUnorderedConstant(const Value* other) const override;
 
-protected:
-    void dumpMeta(CommaPrinter&, PrintStream&) const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    void dumpMeta(CommaPrinter&, PrintStream&) const override;
+
+    static Opcode opcodeFromConstructor(Origin, float) { return ConstFloat; }
+
     ConstFloatValue(Origin origin, float value)
-        : Value(CheckedOpcode, ConstFloat, Float, origin)
+        : Value(CheckedOpcode, ConstFloat, Float, Zero, origin)
         , m_value(value)
     {
     }

Modified: trunk/Source/_javascript_Core/b3/B3ConstPtrValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ConstPtrValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ConstPtrValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -51,13 +51,18 @@
 
 private:
     friend class Procedure;
+    friend class Value;
 
     template<typename T>
+    static Opcode opcodeFromConstructor(Origin, T*) { return ConstPtrValueBase::opcodeFromConstructor(); }
+    template<typename T>
     ConstPtrValue(Origin origin, T* pointer)
         : ConstPtrValueBase(origin, bitwise_cast<intptr_t>(pointer))
     {
     }
     template<typename T>
+    static Opcode opcodeFromConstructor(Origin, T) { return ConstPtrValueBase::opcodeFromConstructor(); }
+    template<typename T>
     ConstPtrValue(Origin origin, T pointer)
         : ConstPtrValueBase(origin, static_cast<intptr_t>(pointer))
     {

Modified: trunk/Source/_javascript_Core/b3/B3FenceValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3FenceValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3FenceValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -34,13 +34,8 @@
 {
 }
 
-Value* FenceValue::cloneImpl() const
-{
-    return new FenceValue(*this);
-}
-
 FenceValue::FenceValue(Origin origin, HeapRange read, HeapRange write)
-    : Value(CheckedOpcode, Fence, Void, origin)
+    : Value(CheckedOpcode, Fence, Void, Zero, origin)
     , read(read)
     , write(write)
 {

Modified: trunk/Source/_javascript_Core/b3/B3FenceValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3FenceValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3FenceValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -72,14 +72,14 @@
     HeapRange read { HeapRange::top() };
     HeapRange write { HeapRange::top() };
 
-protected:
-    Value* cloneImpl() const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
 private:
     friend class Procedure;
+    friend class Value;
     
+    static Opcode opcodeFromConstructor(Origin, HeapRange = HeapRange(), HeapRange = HeapRange()) { return Fence; }
     FenceValue(Origin origin, HeapRange read, HeapRange write);
-    
     FenceValue(Origin origin);
 };
 

Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -73,15 +73,10 @@
         out.print(comma, "fenceRange = ", fenceRange());
 }
 
-Value* MemoryValue::cloneImpl() const
-{
-    return new MemoryValue(*this);
-}
-
 // Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
 // describes the returned type).
 MemoryValue::MemoryValue(MemoryValue::MemoryValueLoad, Kind kind, Type type, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
-    : Value(CheckedOpcode, kind, type, origin, pointer)
+    : Value(CheckedOpcode, kind, type, One, origin, pointer)
     , m_offset(offset)
     , m_range(range)
     , m_fenceRange(fenceRange)
@@ -126,7 +121,7 @@
 
 // Use this form for stores.
 MemoryValue::MemoryValue(MemoryValue::MemoryValueStore, Kind kind, Origin origin, Value* value, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
-    : Value(CheckedOpcode, kind, Void, origin, value, pointer)
+    : Value(CheckedOpcode, kind, Void, Two, origin, value, pointer)
     , m_offset(offset)
     , m_range(range)
     , m_fenceRange(fenceRange)

Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3MemoryValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -84,14 +84,14 @@
 
     bool isCanonicalWidth() const { return B3::isCanonicalWidth(accessWidth()); }
 
+    B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
-
-    Value* cloneImpl() const override;
-
+    
     template<typename Int, typename = IsLegalOffset<Int>, typename... Arguments>
-    MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Int offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
-        : Value(CheckedOpcode, kind, type, origin, arguments...)
+    MemoryValue(CheckedOpcodeTag, Kind kind, Type type, NumChildren numChildren, Origin origin, Int offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
+        : Value(CheckedOpcode, kind, type, numChildren, origin, static_cast<Value*>(arguments)...)
         , m_offset(offset)
         , m_range(range)
         , m_fenceRange(fenceRange)
@@ -100,6 +100,7 @@
     
 private:
     friend class Procedure;
+    friend class Value;
 
     bool isLegalOffsetImpl(int32_t offset) const;
     bool isLegalOffsetImpl(int64_t offset) const;

Modified: trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -58,7 +58,7 @@
             [&] (const ValueKey& key) -> bool {
                 return key.opcode() == ConstFloat || key.opcode() == ConstDouble;
             });
-        
+
         lowerFPConstants();
         
         hoistConstants(

Modified: trunk/Source/_javascript_Core/b3/B3PatchpointValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3PatchpointValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3PatchpointValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -44,11 +44,6 @@
         out.print(comma, "numFPScratchRegisters = ", numFPScratchRegisters);
 }
 
-Value* PatchpointValue::cloneImpl() const
-{
-    return new PatchpointValue(*this);
-}
-
 PatchpointValue::PatchpointValue(Type type, Origin origin)
     : Base(CheckedOpcode, Patchpoint, type, origin)
     , effects(Effects::forCall())

Modified: trunk/Source/_javascript_Core/b3/B3PatchpointValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3PatchpointValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3PatchpointValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -61,14 +61,16 @@
     uint8_t numGPScratchRegisters { 0 };
     uint8_t numFPScratchRegisters { 0 };
 
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    static Opcode opcodeFromConstructor(Type, Origin) { return Patchpoint; }
     JS_EXPORT_PRIVATE PatchpointValue(Type, Origin);
 };
 

Modified: trunk/Source/_javascript_Core/b3/B3Procedure.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Procedure.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Procedure.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -93,7 +93,6 @@
     return m_values.add(WTFMove(clone));
 }
 
-
 Value* Procedure::addIntConstant(Origin origin, Type type, int64_t value)
 {
     switch (type) {

Modified: trunk/Source/_javascript_Core/b3/B3Procedure.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Procedure.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Procedure.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -292,7 +292,7 @@
     bool m_needsUsedRegisters { true };
     bool m_hasQuirks { false };
 };
-
+    
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3ProcedureInlines.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ProcedureInlines.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ProcedureInlines.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -29,13 +29,14 @@
 
 #include "B3BasicBlock.h"
 #include "B3Procedure.h"
+#include "B3Value.h"
 
 namespace JSC { namespace B3 {
-
+    
 template<typename ValueType, typename... Arguments>
 ValueType* Procedure::add(Arguments... arguments)
 {
-    return static_cast<ValueType*>(addValueImpl(new ValueType(arguments...)));
+    return static_cast<ValueType*>(addValueImpl(Value::allocate<ValueType>(arguments...)));
 }
 
 } } // namespace JSC::B3

Modified: trunk/Source/_javascript_Core/b3/B3SlotBaseValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3SlotBaseValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3SlotBaseValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -41,11 +41,6 @@
     out.print(comma, pointerDump(m_slot));
 }
 
-Value* SlotBaseValue::cloneImpl() const
-{
-    return new SlotBaseValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3SlotBaseValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3SlotBaseValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3SlotBaseValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -41,16 +41,17 @@
 
     StackSlot* slot() const { return m_slot; }
 
-protected:
-    void dumpMeta(CommaPrinter&, PrintStream&) const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    void dumpMeta(CommaPrinter&, PrintStream&) const override;
+
+    static Opcode opcodeFromConstructor(Origin, StackSlot*) { return SlotBase; }
     SlotBaseValue(Origin origin, StackSlot* slot)
-        : Value(CheckedOpcode, SlotBase, pointerType(), origin)
+        : Value(CheckedOpcode, SlotBase, pointerType(), Zero, origin)
         , m_slot(slot)
     {
     }

Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -83,11 +83,11 @@
 
     // Check that insane things have not happened.
     ASSERT(inst.args.size() >= numIgnoredAirArgs);
-    ASSERT(value->children().size() >= numIgnoredB3Args);
-    ASSERT(inst.args.size() - numIgnoredAirArgs >= value->children().size() - numIgnoredB3Args);
+    ASSERT(value->numChildren() >= numIgnoredB3Args);
+    ASSERT(inst.args.size() - numIgnoredAirArgs >= value->numChildren() - numIgnoredB3Args);
     ASSERT(inst.args[0].kind() == Arg::Kind::Special);
 
-    for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
+    for (unsigned i = 0; i < value->numChildren() - numIgnoredB3Args; ++i) {
         Arg& arg = inst.args[i + numIgnoredAirArgs];
         ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args);
 
@@ -160,16 +160,16 @@
 
     // Check that insane things have not happened.
     ASSERT(inst.args.size() >= numIgnoredAirArgs);
-    ASSERT(value->children().size() >= numIgnoredB3Args);
+    ASSERT(value->numChildren() >= numIgnoredB3Args);
 
     // For the Inst to be valid, it needs to have the right number of arguments.
-    if (inst.args.size() - numIgnoredAirArgs < value->children().size() - numIgnoredB3Args)
+    if (inst.args.size() - numIgnoredAirArgs < value->numChildren() - numIgnoredB3Args)
         return false;
 
     // Regardless of constraints, stackmaps have some basic requirements for their arguments. For
     // example, you can't have a non-FP-offset address. This verifies those conditions as well as the
     // argument types.
-    for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
+    for (unsigned i = 0; i < value->numChildren() - numIgnoredB3Args; ++i) {
         Value* child = value->child(i + numIgnoredB3Args);
         Arg& arg = inst.args[i + numIgnoredAirArgs];
 
@@ -178,7 +178,7 @@
     }
 
     // The number of constraints has to be no greater than the number of B3 children.
-    ASSERT(value->m_reps.size() <= value->children().size());
+    ASSERT(value->m_reps.size() <= value->numChildren());
 
     // Verify any explicitly supplied constraints.
     for (unsigned i = numIgnoredB3Args; i < value->m_reps.size(); ++i) {

Modified: trunk/Source/_javascript_Core/b3/B3StackmapValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3StackmapValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3StackmapValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -37,7 +37,7 @@
 void StackmapValue::append(Value* value, const ValueRep& rep)
 {
     if (rep == ValueRep::ColdAny) {
-        children().append(value);
+        childrenVector().append(value);
         return;
     }
 
@@ -44,7 +44,7 @@
     while (m_reps.size() < numChildren())
         m_reps.append(ValueRep::ColdAny);
 
-    children().append(value);
+    childrenVector().append(value);
     m_reps.append(rep);
 }
 
@@ -89,7 +89,7 @@
 }
 
 StackmapValue::StackmapValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
-    : Value(CheckedOpcode, kind, type, origin)
+    : Value(CheckedOpcode, kind, type, VarArgs, origin)
 {
     ASSERT(accepts(kind));
 }

Modified: trunk/Source/_javascript_Core/b3/B3StackmapValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3StackmapValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3StackmapValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -60,8 +60,7 @@
 
     ~StackmapValue();
 
-    // Use this to add children. Note that you could also add children by doing
-    // children().append(). That will work fine, but it's not recommended.
+    // Use this to add children.
     void append(const ConstrainedValue& value)
     {
         append(value.value(), value.rep());
@@ -285,6 +284,8 @@
         return ConstrainedValueCollection(*this);
     }
 
+    B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN
+
 protected:
     void dumpChildren(CommaPrinter&, PrintStream&) const override;
     void dumpMeta(CommaPrinter&, PrintStream&) const override;

Modified: trunk/Source/_javascript_Core/b3/B3SwitchValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3SwitchValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3SwitchValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -106,13 +106,8 @@
     out.print(comma, "cases = [", listDump(m_values), "]");
 }
 
-Value* SwitchValue::cloneImpl() const
-{
-    return new SwitchValue(*this);
-}
-
 SwitchValue::SwitchValue(Origin origin, Value* child)
-    : Value(CheckedOpcode, Switch, Void, origin, child)
+    : Value(CheckedOpcode, Switch, Void, One, origin, child)
 {
 }
 

Modified: trunk/Source/_javascript_Core/b3/B3SwitchValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3SwitchValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3SwitchValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -64,14 +64,17 @@
 
     void dumpSuccessors(const BasicBlock*, PrintStream&) const override;
 
+    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    static Opcode opcodeFromConstructor(Origin, Value*) { return Switch; }
     JS_EXPORT_PRIVATE SwitchValue(Origin, Value* child);
 
     Vector<int64_t> m_values;

Modified: trunk/Source/_javascript_Core/b3/B3UpsilonValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3UpsilonValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3UpsilonValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -45,11 +45,6 @@
     }
 }
 
-Value* UpsilonValue::cloneImpl() const
-{
-    return new UpsilonValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3UpsilonValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3UpsilonValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3UpsilonValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -45,19 +45,22 @@
         m_phi = phi;
     }
 
+    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    static Opcode opcodeFromConstructor(Origin, Value*, Value* = nullptr) { return Upsilon; }
     // Note that passing the Phi during construction is optional. A valid pattern is to first create
     // the Upsilons without the Phi, then create the Phi, then go back and tell the Upsilons about
     // the Phi. This allows you to emit code in its natural order.
     UpsilonValue(Origin origin, Value* value, Value* phi = nullptr)
-        : Value(CheckedOpcode, Upsilon, Void, origin, value)
+        : Value(CheckedOpcode, Upsilon, Void, One, origin, value)
         , m_phi(phi)
     {
         if (phi)

Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Value.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -47,13 +47,23 @@
 #include <wtf/CommaPrinter.h>
 #include <wtf/ListDump.h>
 #include <wtf/StringPrintStream.h>
+#include <wtf/Vector.h>
 
 namespace JSC { namespace B3 {
 
 const char* const Value::dumpPrefix = "@";
+void DeepValueDump::dump(PrintStream& out) const
+{
+    if (m_value)
+        m_value->deepDump(m_proc, out);
+    else
+        out.print("<null>");
+}
 
 Value::~Value()
 {
+    if (m_numChildren == VarArgs)
+        bitwise_cast<Vector<Value*, 3> *>(childrenAlloc())->Vector<Value*, 3>::~Vector();
 }
 
 void Value::replaceWithIdentity(Value* value)
@@ -62,27 +72,13 @@
     // a plain Identity Value. We first collect all of the information we need, then we destruct the
     // previous value in place, and then we construct the Identity Value in place.
 
-    ASSERT(m_type == value->m_type);
+    RELEASE_ASSERT(m_type == value->m_type);
     ASSERT(value != this);
 
-    if (m_type == Void) {
+    if (m_type == Void)
         replaceWithNopIgnoringType();
-        return;
-    }
-
-    unsigned index = m_index;
-    Type type = m_type;
-    Origin origin = m_origin;
-    BasicBlock* owner = this->owner;
-
-    RELEASE_ASSERT(type == value->type());
-
-    this->~Value();
-
-    new (this) Value(Identity, type, origin, value);
-
-    this->owner = owner;
-    this->m_index = index;
+    else
+        replaceWith(Identity, m_type, this->owner, value);
 }
 
 void Value::replaceWithBottom(InsertionSet& insertionSet, size_t index)
@@ -98,16 +94,7 @@
 
 void Value::replaceWithNopIgnoringType()
 {
-    unsigned index = m_index;
-    Origin origin = m_origin;
-    BasicBlock* owner = this->owner;
-
-    this->~Value();
-
-    new (this) Value(Nop, Void, origin);
-
-    this->owner = owner;
-    this->m_index = index;
+    replaceWith(Nop, Void, this->owner);
 }
 
 void Value::replaceWithPhi()
@@ -116,34 +103,14 @@
         replaceWithNop();
         return;
     }
-    
-    unsigned index = m_index;
-    Origin origin = m_origin;
-    BasicBlock* owner = this->owner;
-    Type type = m_type;
 
-    this->~Value();
-
-    new (this) Value(Phi, type, origin);
-
-    this->owner = owner;
-    this->m_index = index;
+    replaceWith(Phi, m_type, this->owner);
 }
 
 void Value::replaceWithJump(BasicBlock* owner, FrequentedBlock target)
 {
     RELEASE_ASSERT(owner->last() == this);
-    
-    unsigned index = m_index;
-    Origin origin = m_origin;
-    
-    this->~Value();
-    
-    new (this) Value(Jump, Void, origin);
-    
-    this->owner = owner;
-    this->m_index = index;
-    
+    replaceWith(Jump, Void, this->owner);
     owner->setSuccessors(target);
 }
 
@@ -150,17 +117,7 @@
 void Value::replaceWithOops(BasicBlock* owner)
 {
     RELEASE_ASSERT(owner->last() == this);
-    
-    unsigned index = m_index;
-    Origin origin = m_origin;
-    
-    this->~Value();
-    
-    new (this) Value(Oops, Void, origin);
-    
-    this->owner = owner;
-    this->m_index = index;
-    
+    replaceWith(Oops, Void, this->owner);
     owner->clearSuccessors();
 }
 
@@ -174,6 +131,30 @@
     replaceWithOops(owner);
 }
 
+void Value::replaceWith(Kind kind, Type type, BasicBlock* owner)
+{
+    unsigned index = m_index;
+
+    this->~Value();
+
+    new (this) Value(kind, type, m_origin);
+
+    this->m_index = index;
+    this->owner = owner;
+}
+
+void Value::replaceWith(Kind kind, Type type, BasicBlock* owner, Value* value)
+{
+    unsigned index = m_index;
+
+    this->~Value();
+
+    new (this) Value(kind, type, m_origin, value);
+
+    this->m_index = index;
+    this->owner = owner;
+}
+
 void Value::dump(PrintStream& out) const
 {
     bool isConstant = false;
@@ -205,11 +186,6 @@
         out.print(")");
 }
 
-Value* Value::cloneImpl() const
-{
-    return new Value(*this);
-}
-
 void Value::dumpChildren(CommaPrinter& comma, PrintStream& out) const
 {
     for (Value* child : children())
@@ -458,11 +434,11 @@
 
 Value* Value::invertedCompare(Procedure& proc) const
 {
-    if (!numChildren())
+    if (numChildren() != 2)
         return nullptr;
     if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type())) {
         ASSERT(!kind().hasExtraBits());
-        return proc.add<Value>(*invertedOpcode, type(), origin(), children());
+        return proc.add<Value>(*invertedOpcode, type(), origin(), child(0), child(1));
     }
     return nullptr;
 }
@@ -496,6 +472,7 @@
 {
     if (type() != Int32)
         return false;
+
     switch (opcode()) {
     case Const32:
         return asInt32() == 0 || asInt32() == 1;

Modified: trunk/Source/_javascript_Core/b3/B3Value.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3Value.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3Value.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -38,7 +38,7 @@
 #include "B3Width.h"
 #include <wtf/CommaPrinter.h>
 #include <wtf/FastMalloc.h>
-#include <wtf/Noncopyable.h>
+#include <wtf/IteratorRange.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/TriState.h>
 
@@ -53,8 +53,6 @@
 class JS_EXPORT_PRIVATE Value {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    typedef Vector<Value*, 3> AdjacencyList;
-
     static const char* const dumpPrefix;
 
     static bool accepts(Kind) { return true; }
@@ -82,14 +80,6 @@
     Origin origin() const { return m_origin; }
     void setOrigin(Origin origin) { m_origin = origin; }
     
-    Value*& child(unsigned index) { return m_children[index]; }
-    Value* child(unsigned index) const { return m_children[index]; }
-
-    Value*& lastChild() { return m_children.last(); }
-    Value* lastChild() const { return m_children.last(); }
-
-    unsigned numChildren() const { return m_children.size(); }
-
     Type type() const { return m_type; }
     void setType(Type type) { m_type = type; }
 
@@ -97,9 +87,58 @@
     Bank resultBank() const { return bankForType(type()); }
     Width resultWidth() const { return widthForType(type()); }
 
-    AdjacencyList& children() { return m_children; } 
-    const AdjacencyList& children() const { return m_children; }
+    unsigned numChildren() const
+    {
+        if (m_numChildren == VarArgs)
+            return childrenVector().size();
+        return m_numChildren;
+    }
+    
+    Value*& child(unsigned index)
+    {
+        ASSERT(index < numChildren());
+        return m_numChildren == VarArgs ? childrenVector()[index] : childrenArray()[index];
+    }
+    Value* child(unsigned index) const
+    {
+        ASSERT(index < numChildren());
+        return m_numChildren == VarArgs ? childrenVector()[index] : childrenArray()[index];
+    }
+    
+    Value*& lastChild()
+    {
+        if (m_numChildren == VarArgs)
+            return childrenVector().last();
+        ASSERT(m_numChildren >= 1);
+        return childrenArray()[m_numChildren - 1];
+    }
+    Value* lastChild() const
+    {
+        if (m_numChildren == VarArgs)
+            return childrenVector().last();
+        ASSERT(m_numChildren >= 1);
+        return childrenArray()[m_numChildren - 1];
+    }
 
+    WTF::IteratorRange<Value**> children()
+    {
+        if (m_numChildren == VarArgs) {
+            Vector<Value*, 3>& vec = childrenVector();
+            return WTF::makeIteratorRange(&*vec.begin(), &*vec.end());
+        }
+        Value** buffer = childrenArray();
+        return {buffer, buffer + m_numChildren };
+    }
+    WTF::IteratorRange<Value* const*> children() const
+    {
+        if (m_numChildren == VarArgs) {
+            const Vector<Value*, 3>& vec = childrenVector();
+            return WTF::makeIteratorRange(&*vec.begin(), &*vec.end());
+        }
+        Value* const* buffer = childrenArray();
+        return {buffer, buffer + m_numChildren };
+    }
+
     // If you want to replace all uses of this value with a different value, then replace this
     // value with Identity. Then do a pass of performSubstitution() on all of the values that use
     // this one. Usually we do all of this in one pass in pre-order, which ensures that the
@@ -301,19 +340,218 @@
         typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
     > { };
 
+protected:
+    Value* cloneImpl() const;
 
-protected:
-    virtual Value* cloneImpl() const;
-    
+    void replaceWith(Kind, Type, BasicBlock*);
+    void replaceWith(Kind, Type, BasicBlock*, Value*);
+
     virtual void dumpChildren(CommaPrinter&, PrintStream&) const;
     virtual void dumpMeta(CommaPrinter&, PrintStream&) const;
 
+    // The specific value of VarArgs does not matter, but the value of the others is assumed to match their meaning.
+    enum NumChildren : uint8_t { Zero = 0, _One_ = 1, Two = 2, Three = 3, VarArgs = 4};
+
+    char* childrenAlloc() { return bitwise_cast<char*>(this) + adjacencyListOffset(); }
+    const char* childrenAlloc() const { return bitwise_cast<const char*>(this) + adjacencyListOffset(); }
+    Vector<Value*, 3>& childrenVector()
+    {
+        ASSERT(m_numChildren == VarArgs);
+        return *bitwise_cast<Vector<Value*, 3>*>(childrenAlloc());
+    }
+    const Vector<Value*, 3>& childrenVector() const
+    {
+        ASSERT(m_numChildren == VarArgs);
+        return *bitwise_cast<Vector<Value*, 3> const*>(childrenAlloc());
+    }
+    Value** childrenArray()
+    {
+        ASSERT(m_numChildren != VarArgs);
+        return bitwise_cast<Value**>(childrenAlloc());
+    }
+    Value* const* childrenArray() const
+    {
+        ASSERT(m_numChildren != VarArgs);
+        return bitwise_cast<Value* const*>(childrenAlloc());
+    }
+
+    template<typename... Arguments>
+    static Opcode opcodeFromConstructor(Kind kind, Arguments...) { return kind.opcode(); }
+    ALWAYS_INLINE static size_t adjacencyListSpace(Kind kind)
+    {
+        switch (kind.opcode()) {
+        case FramePointer:
+        case Nop:
+        case Phi:
+        case Jump:
+        case Oops:
+        case EntrySwitch:
+        case ArgumentReg:
+        case Const32:
+        case Const64:
+        case ConstFloat:
+        case ConstDouble:
+        case Fence:
+        case SlotBase:
+        case Get:
+            return 0;
+        case Return:
+        case Identity:
+        case Opaque:
+        case Neg:
+        case Clz:
+        case Abs:
+        case Ceil:
+        case Floor:
+        case Sqrt:
+        case SExt8:
+        case SExt16:
+        case Trunc:
+        case SExt32:
+        case ZExt32:
+        case FloatToDouble:
+        case IToD:
+        case DoubleToFloat:
+        case IToF:
+        case BitwiseCast:
+        case Branch:
+        case Depend:
+        case Load8Z:
+        case Load8S:
+        case Load16Z:
+        case Load16S:
+        case Load:
+        case Switch:
+        case Upsilon:
+        case Set:
+        case WasmAddress:
+        case WasmBoundsCheck:
+            return sizeof(Value*);
+        case Add:
+        case Sub:
+        case Mul:
+        case Div:
+        case UDiv:
+        case Mod:
+        case UMod:
+        case BitAnd:
+        case BitOr:
+        case BitXor:
+        case Shl:
+        case SShr:
+        case ZShr:
+        case RotR:
+        case RotL:
+        case Equal:
+        case NotEqual:
+        case LessThan:
+        case GreaterThan:
+        case LessEqual:
+        case GreaterEqual:
+        case Above:
+        case Below:
+        case AboveEqual:
+        case BelowEqual:
+        case EqualOrUnordered:
+        case AtomicXchgAdd:
+        case AtomicXchgAnd:
+        case AtomicXchgOr:
+        case AtomicXchgSub:
+        case AtomicXchgXor:
+        case AtomicXchg:
+        case Store8:
+        case Store16:
+        case Store:
+            return 2 * sizeof(Value*);
+        case Select:
+        case AtomicWeakCAS:
+        case AtomicStrongCAS:
+            return 3 * sizeof(Value*);
+        case CCall:
+        case Check:
+        case CheckAdd:
+        case CheckSub:
+        case CheckMul:
+        case Patchpoint:
+            return sizeof(Vector<Value*, 3>);
+        default:
+            break;
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+
 private:
+    static char* allocateSpace(Opcode opcode, size_t size)
+    {
+        size_t adjacencyListSpace = Value::adjacencyListSpace(opcode);
+        // We must allocate enough space that replaceWithIdentity can work without buffer overflow.
+        size_t allocIdentitySize = sizeof(Value) + sizeof(Value*);
+        size_t allocSize = std::max(size + adjacencyListSpace, allocIdentitySize);
+        return static_cast<char*>(WTF::fastMalloc(allocSize));
+    }
+
+protected:
+    template<typename ValueType, typename... Arguments>
+    static ValueType* allocate(Arguments... arguments)
+    {
+        char* alloc = allocateSpace(ValueType::opcodeFromConstructor(arguments...), sizeof(ValueType));
+        return new (alloc) ValueType(arguments...);
+    }
+    template<typename ValueType>
+    static ValueType* allocate(const ValueType& valueToClone)
+    {
+        char* alloc = allocateSpace(valueToClone.opcode(), sizeof(ValueType));
+        ValueType* result = new (alloc) ValueType(valueToClone);
+        result->buildAdjacencyList(sizeof(ValueType), valueToClone);
+        return result;
+    }
+
+    // Protected so it will only be called from allocate above, possibly through the subclasses'copy constructors
+    Value(const Value&) = default;
+
+    Value(Value&&) = delete;
+    Value& operator=(const Value&) = delete;
+    Value& operator=(Value&&) = delete;
+    
+    size_t adjacencyListOffset() const;
+
     friend class Procedure;
     friend class SparseCollection<Value>;
 
+private:
+    template<typename... Arguments>
+    void buildAdjacencyList(NumChildren numChildren, Arguments... arguments)
+    {
+        if (numChildren == VarArgs) {
+            new (childrenAlloc()) Vector<Value*, 3> { arguments... };
+            return;
+        }
+        ASSERT(numChildren == sizeof...(arguments));
+        new (childrenAlloc()) Value*[sizeof...(arguments)] { arguments... };
+    }
+    void buildAdjacencyList(size_t offset, const Value& valueToClone)
+    {
+        switch (valueToClone.m_numChildren) {
+        case VarArgs:
+            new (bitwise_cast<char*>(this) + offset) Vector<Value*, 3> (valueToClone.childrenVector());
+            break;
+        case Three:
+            bitwise_cast<Value**>(bitwise_cast<char*>(this) + offset)[2] = valueToClone.childrenArray()[2];
+            FALLTHROUGH;
+        case Two:
+            bitwise_cast<Value**>(bitwise_cast<char*>(this) + offset)[1] = valueToClone.childrenArray()[1];
+            FALLTHROUGH;
+        case One:
+            bitwise_cast<Value**>(bitwise_cast<char*>(this) + offset)[0] = valueToClone.childrenArray()[0];
+            break;
+        case Zero:
+            break;
+        }
+    }
+    
     // Checks that this kind is valid for use with B3::Value.
-    ALWAYS_INLINE static void checkKind(Kind kind, unsigned numArgs)
+    ALWAYS_INLINE static NumChildren numChildrenForKind(Kind kind, unsigned numArgs)
     {
         switch (kind.opcode()) {
         case FramePointer:
@@ -324,11 +562,11 @@
         case EntrySwitch:
             if (UNLIKELY(numArgs))
                 badKind(kind, numArgs);
-            break;
+            return Zero;
         case Return:
             if (UNLIKELY(numArgs > 1))
                 badKind(kind, numArgs);
-            break;
+            return numArgs ? One : Zero;
         case Identity:
         case Opaque:
         case Neg:
@@ -351,7 +589,7 @@
         case Depend:
             if (UNLIKELY(numArgs != 1))
                 badKind(kind, numArgs);
-            break;
+            return One;
         case Add:
         case Sub:
         case Mul:
@@ -380,129 +618,105 @@
         case EqualOrUnordered:
             if (UNLIKELY(numArgs != 2))
                 badKind(kind, numArgs);
-            break;
+            return Two;
         case Select:
             if (UNLIKELY(numArgs != 3))
                 badKind(kind, numArgs);
-            break;
+            return Three;
         default:
             badKind(kind, numArgs);
             break;
         }
+        return VarArgs;
     }
 
 protected:
     enum CheckedOpcodeTag { CheckedOpcode };
-
-    Value(const Value&) = default;
-    Value& operator=(const Value&) = default;
     
     // Instantiate values via Procedure.
     // This form requires specifying the type explicitly:
     template<typename... Arguments>
-    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Value* firstChild, Arguments... arguments)
+    explicit Value(CheckedOpcodeTag, Kind kind, Type type, NumChildren numChildren, Origin origin, Value* firstChild, Arguments... arguments)
         : m_kind(kind)
         , m_type(type)
+        , m_numChildren(numChildren)
         , m_origin(origin)
-        , m_children{ firstChild, arguments... }
     {
+        buildAdjacencyList(numChildren, firstChild, arguments...);
     }
     // This form is for specifying the type explicitly when the opcode has no children:
-    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
+    explicit Value(CheckedOpcodeTag, Kind kind, Type type, NumChildren numChildren, Origin origin)
         : m_kind(kind)
         , m_type(type)
+        , m_numChildren(numChildren)
         , m_origin(origin)
     {
+        buildAdjacencyList(numChildren);
     }
-    // This form is for those opcodes that can infer their type from the opcode and first child:
-    template<typename... Arguments>
-    explicit Value(CheckedOpcodeTag, Kind kind, Origin origin, Value* firstChild)
-        : m_kind(kind)
-        , m_type(typeFor(kind, firstChild))
-        , m_origin(origin)
-        , m_children{ firstChild }
-    {
-    }
-    // This form is for those opcodes that can infer their type from the opcode and first and second child:
-    template<typename... Arguments>
-    explicit Value(CheckedOpcodeTag, Kind kind, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
-        : m_kind(kind)
-        , m_type(typeFor(kind, firstChild, secondChild))
-        , m_origin(origin)
-        , m_children{ firstChild, secondChild, arguments... }
-    {
-    }
     // This form is for those opcodes that can infer their type from the opcode alone, and that don't
     // take any arguments:
-    explicit Value(CheckedOpcodeTag, Kind kind, Origin origin)
+    explicit Value(CheckedOpcodeTag, Kind kind, NumChildren numChildren, Origin origin)
         : m_kind(kind)
         , m_type(typeFor(kind, nullptr))
+        , m_numChildren(numChildren)
         , m_origin(origin)
     {
+        buildAdjacencyList(numChildren);
     }
-    // Use this form for varargs.
-    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, const AdjacencyList& children)
+    // This form is for those opcodes that can infer their type from the opcode and first child:
+    explicit Value(CheckedOpcodeTag, Kind kind, NumChildren numChildren, Origin origin, Value* firstChild)
         : m_kind(kind)
-        , m_type(type)
+        , m_type(typeFor(kind, firstChild))
+        , m_numChildren(numChildren)
         , m_origin(origin)
-        , m_children(children)
     {
+        buildAdjacencyList(numChildren, firstChild);
     }
-    explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, AdjacencyList&& children)
+    // This form is for those opcodes that can infer their type from the opcode and first and second child:
+    template<typename... Arguments>
+    explicit Value(CheckedOpcodeTag, Kind kind, NumChildren numChildren, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
         : m_kind(kind)
-        , m_type(type)
+        , m_type(typeFor(kind, firstChild, secondChild))
+        , m_numChildren(numChildren)
         , m_origin(origin)
-        , m_children(WTFMove(children))
     {
+        buildAdjacencyList(numChildren, firstChild, secondChild, arguments...);
     }
 
     // This is the constructor you end up actually calling, if you're instantiating Value
     // directly.
-    template<typename... Arguments>
-        explicit Value(Kind kind, Type type, Origin origin)
-        : Value(CheckedOpcode, kind, type, origin)
+    explicit Value(Kind kind, Type type, Origin origin)
+        : Value(CheckedOpcode, kind, type, Zero, origin)
     {
-        checkKind(kind, 0);
+        RELEASE_ASSERT(numChildrenForKind(kind, 0) == Zero);
     }
+    // We explicitly convert the extra arguments to Value* (they may be pointers to some subclasses of Value) to limit template explosion
     template<typename... Arguments>
-        explicit Value(Kind kind, Type type, Origin origin, Value* firstChild, Arguments&&... arguments)
-        : Value(CheckedOpcode, kind, type, origin, firstChild, std::forward<Arguments>(arguments)...)
+    explicit Value(Kind kind, Origin origin, Arguments... arguments)
+        : Value(CheckedOpcode, kind, numChildrenForKind(kind, sizeof...(arguments)), origin, static_cast<Value*>(arguments)...)
     {
-        checkKind(kind, 1 + sizeof...(arguments));
     }
     template<typename... Arguments>
-        explicit Value(Kind kind, Type type, Origin origin, const AdjacencyList& children)
-        : Value(CheckedOpcode, kind, type, origin, children)
+    explicit Value(Kind kind, Type type, Origin origin, Value* firstChild, Arguments... arguments)
+        : Value(CheckedOpcode, kind, type, numChildrenForKind(kind, 1 + sizeof...(arguments)), origin, firstChild, static_cast<Value*>(arguments)...)
     {
-        checkKind(kind, children.size());
     }
-    template<typename... Arguments>
-        explicit Value(Kind kind, Type type, Origin origin, AdjacencyList&& children)
-        : Value(CheckedOpcode, kind, type, origin, WTFMove(children))
-    {
-        checkKind(kind, m_children.size());
-    }
-    template<typename... Arguments>
-        explicit Value(Kind kind, Origin origin, Arguments&&... arguments)
-        : Value(CheckedOpcode, kind, origin, std::forward<Arguments>(arguments)...)
-    {
-        checkKind(kind, sizeof...(arguments));
-    }
 
 private:
     friend class CheckValue; // CheckValue::convertToAdd() modifies m_kind.
-    
+
     static Type typeFor(Kind, Value* firstChild, Value* secondChild = nullptr);
 
-    // This group of fields is arranged to fit in 64 bits.
+    // m_index to m_numChildren are arranged to fit in 64 bits.
 protected:
     unsigned m_index { UINT_MAX };
 private:
     Kind m_kind;
     Type m_type;
-    
+protected:
+    NumChildren m_numChildren;
+private:
     Origin m_origin;
-    AdjacencyList m_children;
 
     NO_RETURN_DUE_TO_CRASH static void badKind(Kind, unsigned);
 
@@ -518,13 +732,7 @@
     {
     }
 
-    void dump(PrintStream& out) const
-    {
-        if (m_value)
-            m_value->deepDump(m_proc, out);
-        else
-            out.print("<null>");
-    }
+    void dump(PrintStream& out) const;
 
 private:
     const Procedure* m_proc;
@@ -540,6 +748,116 @@
     return DeepValueDump(nullptr, value);
 }
 
+// The following macros are designed for subclasses of B3::Value to use.
+// They are never required for correctness, but can improve the performance of child/lastChild/numChildren/children methods,
+// for users that already know the specific subclass of Value they are manipulating.
+// The first set is to be used when you know something about the number of children of all values of a class, including its subclasses:
+// - B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN: always 0 children (e.g. Const32Value)
+// - B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(n): always n children, with n in {1, 2, 3} (e.g. UpsilonValue, with n = 1)
+// - B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN: different numbers of children, but never a variable number at runtime (e.g. MemoryValue, that can have between 1 and 3 children)
+// - B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN: always a varargs (e.g. CCallValue)
+// The second set is only to be used by classes that we know are not further subclassed by anyone adding fields,
+// as they hardcode the offset of the children array/vector (which is equal to the size of the object).
+// - B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
+// - B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
+#define B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN \
+    unsigned numChildren() const { return 0; } \
+    WTF::IteratorRange<Value**> children() { return {nullptr, nullptr}; } \
+    WTF::IteratorRange<Value* const*> children() const { return { nullptr, nullptr}; }
+
+#define B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(n) \
+public: \
+    unsigned numChildren() const { return n; } \
+    Value*& child(unsigned index) \
+    { \
+        ASSERT(index <= n); \
+        return childrenArray()[index]; \
+    } \
+    Value* child(unsigned index) const \
+    { \
+        ASSERT(index <= n); \
+        return childrenArray()[index]; \
+    } \
+    Value*& lastChild() \
+    { \
+        return childrenArray()[n - 1]; \
+    } \
+    Value* lastChild() const \
+    { \
+        return childrenArray()[n - 1]; \
+    } \
+    WTF::IteratorRange<Value**> children() \
+    { \
+        Value** buffer = childrenArray(); \
+        return {buffer, buffer + n }; \
+    } \
+    WTF::IteratorRange<Value* const*> children() const \
+    { \
+        Value* const* buffer = childrenArray(); \
+        return {buffer, buffer + n }; \
+    } \
+
+#define B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN \
+public: \
+    unsigned numChildren() const { return m_numChildren; } \
+    Value*& child(unsigned index) { return childrenArray()[index]; } \
+    Value* child(unsigned index) const { return childrenArray()[index]; } \
+    Value*& lastChild() { return childrenArray()[numChildren() - 1]; } \
+    Value* lastChild() const { return childrenArray()[numChildren() - 1]; } \
+    WTF::IteratorRange<Value**> children() \
+    { \
+        Value** buffer = childrenArray(); \
+        return {buffer, buffer + numChildren() }; \
+    } \
+    WTF::IteratorRange<Value* const*> children() const \
+    { \
+        Value* const* buffer = childrenArray(); \
+        return {buffer, buffer + numChildren() }; \
+    } \
+
+#define B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN \
+public: \
+    unsigned numChildren() const { return childrenVector().size(); } \
+    Value*& child(unsigned index) { return childrenVector()[index]; } \
+    Value* child(unsigned index) const { return childrenVector()[index]; } \
+    Value*& lastChild() { return childrenVector().last(); } \
+    Value* lastChild() const { return childrenVector().last(); } \
+    WTF::IteratorRange<Value**> children() \
+    { \
+        Vector<Value*, 3>& vec = childrenVector(); \
+        return WTF::makeIteratorRange(&*vec.begin(), &*vec.end()); \
+    } \
+    WTF::IteratorRange<Value* const*> children() const \
+    { \
+        const Vector<Value*, 3>& vec = childrenVector(); \
+        return WTF::makeIteratorRange(&*vec.begin(), &*vec.end()); \
+    } \
+
+// Only use this for classes with no subclass that add new fields (as it uses sizeof(*this))
+// Also there is no point in applying this to classes with no children, as they don't have a children array to access.
+#define B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN \
+private: \
+    Value** childrenArray() \
+    { \
+        return bitwise_cast<Value**>(bitwise_cast<char*>(this) + sizeof(*this)); \
+    } \
+    Value* const* childrenArray() const \
+    { \
+        return bitwise_cast<Value* const*>(bitwise_cast<char const*>(this) + sizeof(*this)); \
+    }
+
+// Only use this for classes with no subclass that add new fields (as it uses sizeof(*this))
+#define B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN \
+private: \
+    Vector<Value*, 3>& childrenVector() \
+    { \
+        return *bitwise_cast<Vector<Value*, 3>*>(bitwise_cast<char*>(this) + sizeof(*this)); \
+    } \
+    const Vector<Value*, 3>& childrenVector() const \
+    { \
+        return *bitwise_cast<Vector<Value*, 3> const*>(bitwise_cast<char const*>(this) + sizeof(*this)); \
+    } \
+
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3ValueInlines.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3ValueInlines.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3ValueInlines.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -27,19 +27,157 @@
 
 #if ENABLE(B3_JIT)
 
+#include "B3ArgumentRegValue.h"
+#include "B3AtomicValue.h"
+#include "B3CCallValue.h"
 #include "B3CheckValue.h"
 #include "B3Const32Value.h"
 #include "B3Const64Value.h"
 #include "B3ConstDoubleValue.h"
 #include "B3ConstFloatValue.h"
+#include "B3FenceValue.h"
+#include "B3MemoryValue.h"
 #include "B3PatchpointValue.h"
 #include "B3PhiChildren.h"
 #include "B3Procedure.h"
+#include "B3SlotBaseValue.h"
+#include "B3SwitchValue.h"
+#include "B3UpsilonValue.h"
 #include "B3Value.h"
+#include "B3VariableValue.h"
+#include "B3WasmAddressValue.h"
+#include "B3WasmBoundsCheckValue.h"
 #include <wtf/GraphNodeWorklist.h>
 
 namespace JSC { namespace B3 {
 
+#define DISPATCH_ON_KIND(MACRO) \
+    switch (kind().opcode()) { \
+    case FramePointer: \
+    case Nop: \
+    case Phi: \
+    case Jump: \
+    case Oops: \
+    case EntrySwitch: \
+    case Return: \
+    case Identity: \
+    case Opaque: \
+    case Neg: \
+    case Clz: \
+    case Abs: \
+    case Ceil: \
+    case Floor: \
+    case Sqrt: \
+    case SExt8: \
+    case SExt16: \
+    case Trunc: \
+    case SExt32: \
+    case ZExt32: \
+    case FloatToDouble: \
+    case IToD: \
+    case DoubleToFloat: \
+    case IToF: \
+    case BitwiseCast: \
+    case Branch: \
+    case Depend: \
+    case Add: \
+    case Sub: \
+    case Mul: \
+    case Div: \
+    case UDiv: \
+    case Mod: \
+    case UMod: \
+    case BitAnd: \
+    case BitOr: \
+    case BitXor: \
+    case Shl: \
+    case SShr: \
+    case ZShr: \
+    case RotR: \
+    case RotL: \
+    case Equal: \
+    case NotEqual: \
+    case LessThan: \
+    case GreaterThan: \
+    case LessEqual: \
+    case GreaterEqual: \
+    case Above: \
+    case Below: \
+    case AboveEqual: \
+    case BelowEqual: \
+    case EqualOrUnordered: \
+    case Select: \
+        return MACRO(Value); \
+    case ArgumentReg: \
+        return MACRO(ArgumentRegValue); \
+    case Const32: \
+        return MACRO(Const32Value); \
+    case Const64: \
+        return MACRO(Const64Value); \
+    case ConstFloat: \
+        return MACRO(ConstFloatValue); \
+    case ConstDouble: \
+        return MACRO(ConstDoubleValue); \
+    case Fence: \
+        return MACRO(FenceValue); \
+    case SlotBase: \
+        return MACRO(SlotBaseValue); \
+    case Get: \
+    case Set: \
+        return MACRO(VariableValue); \
+    case Load8Z: \
+    case Load8S: \
+    case Load16Z: \
+    case Load16S: \
+    case Load: \
+    case Store8: \
+    case Store16: \
+    case Store: \
+        return MACRO(MemoryValue); \
+    case Switch: \
+        return MACRO(SwitchValue); \
+    case Upsilon: \
+        return MACRO(UpsilonValue); \
+    case WasmAddress: \
+        return MACRO(WasmAddressValue); \
+    case WasmBoundsCheck: \
+        return MACRO(WasmBoundsCheckValue); \
+    case AtomicXchgAdd: \
+    case AtomicXchgAnd: \
+    case AtomicXchgOr: \
+    case AtomicXchgSub: \
+    case AtomicXchgXor: \
+    case AtomicXchg: \
+    case AtomicWeakCAS: \
+    case AtomicStrongCAS: \
+        return MACRO(AtomicValue); \
+    case CCall: \
+        return MACRO(CCallValue); \
+    case Check: \
+    case CheckAdd: \
+    case CheckSub: \
+    case CheckMul: \
+        return MACRO(CheckValue); \
+    case Patchpoint: \
+        return MACRO(PatchpointValue); \
+    default: \
+        RELEASE_ASSERT_NOT_REACHED(); \
+    }
+
+ALWAYS_INLINE size_t Value::adjacencyListOffset() const
+{
+#define VALUE_TYPE_SIZE(ValueType) sizeof(ValueType)
+    DISPATCH_ON_KIND(VALUE_TYPE_SIZE);
+#undef VALUE_TYPE_SIZE
+}
+
+ALWAYS_INLINE Value* Value::cloneImpl() const
+{
+#define VALUE_TYPE_CLONE(ValueType) allocate<ValueType>(*static_cast<const ValueType*>(this))
+    DISPATCH_ON_KIND(VALUE_TYPE_CLONE);
+#undef VALUE_TYPE_CLONE
+}
+
 template<typename BottomProvider>
 void Value::replaceWithBottom(const BottomProvider& bottomProvider)
 {

Modified: trunk/Source/_javascript_Core/b3/B3VariableValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3VariableValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3VariableValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -41,13 +41,8 @@
     out.print(comma, pointerDump(m_variable));
 }
 
-Value* VariableValue::cloneImpl() const
-{
-    return new VariableValue(*this);
-}
-
 VariableValue::VariableValue(Kind kind, Origin origin, Variable* variable, Value* value)
-    : Value(CheckedOpcode, kind, Void, origin, value)
+    : Value(CheckedOpcode, kind, Void, One, origin, value)
     , m_variable(variable)
 {
     ASSERT(kind == Set);
@@ -54,7 +49,7 @@
 }
 
 VariableValue::VariableValue(Kind kind, Origin origin, Variable* variable)
-    : Value(CheckedOpcode, kind, variable->type(), origin)
+    : Value(CheckedOpcode, kind, variable->type(), Zero, origin)
     , m_variable(variable)
 {
     ASSERT(kind == Get);

Modified: trunk/Source/_javascript_Core/b3/B3VariableValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3VariableValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3VariableValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -41,13 +41,15 @@
 
     Variable* variable() const { return m_variable; }
 
+    B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
     // Use this for Set.
     VariableValue(Kind, Origin, Variable*, Value*);

Modified: trunk/Source/_javascript_Core/b3/B3WasmAddressValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3WasmAddressValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3WasmAddressValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -39,13 +39,8 @@
     out.print(comma, m_pinnedGPR);
 }
 
-Value* WasmAddressValue::cloneImpl() const
-{
-    return new WasmAddressValue(*this);
-}
-
 WasmAddressValue::WasmAddressValue(Origin origin, Value* value, GPRReg pinnedGPR)
-    : Value(CheckedOpcode, WasmAddress, Int64, origin, value)
+    : Value(CheckedOpcode, WasmAddress, Int64, One, origin, value)
     , m_pinnedGPR(pinnedGPR)
 {
 }

Modified: trunk/Source/_javascript_Core/b3/B3WasmAddressValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3WasmAddressValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3WasmAddressValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -40,14 +40,17 @@
 
     GPRReg pinnedGPR() const { return m_pinnedGPR; }
 
+    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    static Opcode opcodeFromConstructor(Origin, Value*, GPRReg) { return WasmAddress; }
     WasmAddressValue(Origin, Value*, GPRReg);
 
     GPRReg m_pinnedGPR;

Modified: trunk/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -36,7 +36,7 @@
 }
 
 WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, GPRReg pinnedSize, Value* ptr, unsigned offset)
-    : Value(CheckedOpcode, WasmBoundsCheck, origin, ptr)
+    : Value(CheckedOpcode, WasmBoundsCheck, One, origin, ptr)
     , m_offset(offset)
     , m_boundsType(Type::Pinned)
 {
@@ -44,7 +44,7 @@
 }
 
 WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, Value* ptr, unsigned offset, size_t maximum)
-    : Value(CheckedOpcode, WasmBoundsCheck, origin, ptr)
+    : Value(CheckedOpcode, WasmBoundsCheck, One, origin, ptr)
     , m_offset(offset)
     , m_boundsType(Type::Maximum)
 {
@@ -55,11 +55,6 @@
     m_bounds.maximum = maximum;
 }
 
-Value* WasmBoundsCheckValue::cloneImpl() const
-{
-    return new WasmBoundsCheckValue(*this);
-}
-
 void WasmBoundsCheckValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
 {
     switch (m_boundsType) {

Modified: trunk/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.h (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -34,15 +34,7 @@
 
 class WasmBoundsCheckValue : public Value {
 public:
-    static bool accepts(Kind kind)
-    {
-        switch (kind.opcode()) {
-        case WasmBoundsCheck:
-            return true;
-        default:
-            return false;
-        }
-    }
+    static bool accepts(Kind kind) { return kind == WasmBoundsCheck; }
     
     ~WasmBoundsCheckValue();
 
@@ -60,15 +52,20 @@
     Type boundsType() const { return m_boundsType; }
     Bounds bounds() const { return m_bounds; }
 
+    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
+    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
+
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
 
-    Value* cloneImpl() const override;
-
 private:
     friend class Procedure;
+    friend class Value;
 
+    static Opcode opcodeFromConstructor(Origin, GPRReg, Value*, unsigned) { return WasmBoundsCheck; }
     JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, GPRReg pinnedGPR, Value* ptr, unsigned offset);
+
+    static Opcode opcodeFromConstructor(Origin, Value*, unsigned, size_t) { return WasmBoundsCheck; }
     JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, Value* ptr, unsigned offset, size_t maximum);
 
     unsigned m_offset;

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (244308 => 244309)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2019-04-15 23:53:23 UTC (rev 244309)
@@ -10960,7 +10960,7 @@
     CCallValue* call = root->appendNew<CCallValue>(
         proc, Int32, Origin(),
         root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaArguments, B3CCallPtrTag)));
-    call->children().appendVector(args);
+    call->appendArgs(args);
     
     root->appendNewControlValue(proc, Return, Origin(), call);
 
@@ -10986,7 +10986,7 @@
     CCallValue* call = root->appendNew<CCallValue>(
         proc, Int64, Origin(),
         root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaArguments2, B3CCallPtrTag)));
-    call->children().appendVector(args);
+    call->appendArgs(args);
     
     root->appendNewControlValue(proc, Return, Origin(), call);
 
@@ -11008,7 +11008,7 @@
     CCallValue* call = root->appendNew<CCallValue>(
         proc, Int32, Origin(),
         root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaArguments3, B3CCallPtrTag)));
-    call->children().appendVector(args);
+    call->appendArgs(args);
     
     root->appendNewControlValue(proc, Return, Origin(), call);
 
@@ -11108,7 +11108,7 @@
     CCallValue* call = root->appendNew<CCallValue>(
         proc, Double, Origin(),
         root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaDoubleArguments, B3CCallPtrTag)));
-    call->children().appendVector(args);
+    call->appendArgs(args);
     
     root->appendNewControlValue(proc, Return, Origin(), call);
 
@@ -11132,7 +11132,7 @@
     CCallValue* call = root->appendNew<CCallValue>(
         proc, Float, Origin(),
         root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaFloatArguments, B3CCallPtrTag)));
-    call->children().appendVector(args);
+    call->appendArgs(args);
     
     root->appendNewControlValue(proc, Return, Origin(), call);
 

Modified: trunk/Source/_javascript_Core/ftl/FTLOutput.h (244308 => 244309)


--- trunk/Source/_javascript_Core/ftl/FTLOutput.h	2019-04-15 23:48:57 UTC (rev 244308)
+++ trunk/Source/_javascript_Core/ftl/FTLOutput.h	2019-04-15 23:53:23 UTC (rev 244309)
@@ -380,7 +380,7 @@
     LValue call(LType type, LValue function, const VectorType& vector)
     {
         B3::CCallValue* result = m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function);
-        result->children().appendVector(vector);
+        result->appendArgs(vector);
         return result;
     }
     LValue call(LType type, LValue function) { return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function); }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to