B3::Value should have different kinds of adjacency lists
authorrmorisset@apple.com <rmorisset@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Apr 2019 23:53:23 +0000 (23:53 +0000)
committerrmorisset@apple.com <rmorisset@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Apr 2019 23:53:23 +0000 (23:53 +0000)
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

* JavaScriptCore.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):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244309 268f45cc-cd09-0410-ab3c-d52691b4dbfc

51 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/b3/B3ArgumentRegValue.cpp
Source/JavaScriptCore/b3/B3ArgumentRegValue.h
Source/JavaScriptCore/b3/B3AtomicValue.cpp
Source/JavaScriptCore/b3/B3AtomicValue.h
Source/JavaScriptCore/b3/B3BasicBlock.h
Source/JavaScriptCore/b3/B3BasicBlockInlines.h
Source/JavaScriptCore/b3/B3CCallValue.cpp
Source/JavaScriptCore/b3/B3CCallValue.h
Source/JavaScriptCore/b3/B3CheckValue.cpp
Source/JavaScriptCore/b3/B3CheckValue.h
Source/JavaScriptCore/b3/B3Const32Value.cpp
Source/JavaScriptCore/b3/B3Const32Value.h
Source/JavaScriptCore/b3/B3Const64Value.cpp
Source/JavaScriptCore/b3/B3Const64Value.h
Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp
Source/JavaScriptCore/b3/B3ConstDoubleValue.h
Source/JavaScriptCore/b3/B3ConstFloatValue.cpp
Source/JavaScriptCore/b3/B3ConstFloatValue.h
Source/JavaScriptCore/b3/B3ConstPtrValue.h
Source/JavaScriptCore/b3/B3FenceValue.cpp
Source/JavaScriptCore/b3/B3FenceValue.h
Source/JavaScriptCore/b3/B3MemoryValue.cpp
Source/JavaScriptCore/b3/B3MemoryValue.h
Source/JavaScriptCore/b3/B3MoveConstants.cpp
Source/JavaScriptCore/b3/B3PatchpointValue.cpp
Source/JavaScriptCore/b3/B3PatchpointValue.h
Source/JavaScriptCore/b3/B3Procedure.cpp
Source/JavaScriptCore/b3/B3Procedure.h
Source/JavaScriptCore/b3/B3ProcedureInlines.h
Source/JavaScriptCore/b3/B3SlotBaseValue.cpp
Source/JavaScriptCore/b3/B3SlotBaseValue.h
Source/JavaScriptCore/b3/B3StackmapSpecial.cpp
Source/JavaScriptCore/b3/B3StackmapValue.cpp
Source/JavaScriptCore/b3/B3StackmapValue.h
Source/JavaScriptCore/b3/B3SwitchValue.cpp
Source/JavaScriptCore/b3/B3SwitchValue.h
Source/JavaScriptCore/b3/B3UpsilonValue.cpp
Source/JavaScriptCore/b3/B3UpsilonValue.h
Source/JavaScriptCore/b3/B3Value.cpp
Source/JavaScriptCore/b3/B3Value.h
Source/JavaScriptCore/b3/B3ValueInlines.h
Source/JavaScriptCore/b3/B3VariableValue.cpp
Source/JavaScriptCore/b3/B3VariableValue.h
Source/JavaScriptCore/b3/B3WasmAddressValue.cpp
Source/JavaScriptCore/b3/B3WasmAddressValue.h
Source/JavaScriptCore/b3/B3WasmBoundsCheckValue.cpp
Source/JavaScriptCore/b3/B3WasmBoundsCheckValue.h
Source/JavaScriptCore/b3/testb3.cpp
Source/JavaScriptCore/ftl/FTLOutput.h

index 50da1dc..888287c 100644 (file)
@@ -1,3 +1,139 @@
+2019-04-15  Robin Morisset  <rmorisset@apple.com>
+
+        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
+
+        * JavaScriptCore.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  <tzagallo@apple.com>
 
         Bytecode cache should not encode the SourceProvider for UnlinkedFunctionExecutable's classSource
index 15a48b4..3400288 100644 (file)
                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 */; };
                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, ); }; };
                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, ); }; };
                                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 */,
                                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 */,
                                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 */,
                                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 */,
index 594d0d6..3e544eb 100644 (file)
@@ -39,11 +39,6 @@ void ArgumentRegValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     out.print(comma, m_reg);
 }
 
-Value* ArgumentRegValue::cloneImpl() const
-{
-    return new ArgumentRegValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index 55b365f..879e01c 100644 (file)
@@ -40,16 +40,19 @@ public:
 
     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());
index 20fce40..ec544ed 100644 (file)
@@ -41,13 +41,8 @@ void AtomicValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     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::AtomicValueRMW, Kind kind, Origin origin,
 }
 
 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());
index 292cf9e..085a9e1 100644 (file)
@@ -44,14 +44,15 @@ public:
     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 };
index 1805857..de79eba 100644 (file)
@@ -84,8 +84,6 @@ public:
 
     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);
index 26c2df4..5a6b2bd 100644 (file)
@@ -42,14 +42,6 @@ ValueType* BasicBlock::appendNew(Procedure& procedure, Arguments... arguments)
 }
 
 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...);
index 518d723..90bd60e 100644 (file)
@@ -34,9 +34,9 @@ CCallValue::~CCallValue()
 {
 }
 
-Value* CCallValue::cloneImpl() const
+void CCallValue::appendArgs(const Vector<Value*>& args)
 {
-    return new CCallValue(*this);
+    childrenVector().appendVector(args);
 }
 
 } } // namespace JSC::B3
index 44ec349..2f60a01 100644 (file)
@@ -38,17 +38,23 @@ public:
 
     ~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 @@ private:
 
     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);
index 79b6c6e..c117137 100644 (file)
@@ -40,11 +40,6 @@ void CheckValue::convertToAdd()
     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)
index e3d94ba..897320c 100644 (file)
@@ -50,11 +50,11 @@ public:
 
     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);
index 512be88..5ace364 100644 (file)
@@ -303,11 +303,6 @@ void Const32Value::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     out.print(comma, m_value);
 }
 
-Value* Const32Value::cloneImpl() const
-{
-    return new Const32Value(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index af4d08b..4ffee11 100644 (file)
@@ -75,20 +75,24 @@ public:
     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;
-
-    friend class Procedure;
+    // Protected because of ConstPtrValue
+    static Opcode opcodeFromConstructor(Origin = Origin(), int32_t = 0) { return Const32; }
 
     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;
 };
 
index 73a4cec..8d795b0 100644 (file)
@@ -303,11 +303,6 @@ void Const64Value::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     out.print(comma, m_value);
 }
 
-Value* Const64Value::cloneImpl() const
-{
-    return new Const64Value(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index 3efd558..47c1b56 100644 (file)
@@ -75,20 +75,24 @@ public:
     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;
-
-    friend class Procedure;
+    // Protected because of ConstPtrValue
+    static Opcode opcodeFromConstructor(Origin = Origin(), int64_t = 0) { return Const64; }
 
     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;
 };
 
index 0a7d748..5dd7d91 100644 (file)
@@ -197,11 +197,6 @@ void ConstDoubleValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     out.printf("%le", m_value);
 }
 
-Value* ConstDoubleValue::cloneImpl() const
-{
-    return new ConstDoubleValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index fdfaddc..403bd3f 100644 (file)
@@ -64,16 +64,18 @@ public:
     TriState greaterEqualConstant(const Value* other) const override;
     TriState equalOrUnorderedConstant(const Value* other) const override;
 
-protected:
-    void dumpMeta(CommaPrinter&, PrintStream&) const override;
-
-    Value* cloneImpl() const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
 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)
     {
     }
index d3cb033..2270f00 100644 (file)
@@ -189,11 +189,6 @@ void ConstFloatValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     out.printf("%le", m_value);
 }
 
-Value* ConstFloatValue::cloneImpl() const
-{
-    return new ConstFloatValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index 35dd2e0..bc3bbee 100644 (file)
@@ -63,16 +63,18 @@ public:
     TriState greaterEqualConstant(const Value* other) const override;
     TriState equalOrUnorderedConstant(const Value* other) const override;
 
-protected:
-    void dumpMeta(CommaPrinter&, PrintStream&) const override;
-
-    Value* cloneImpl() const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
 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)
     {
     }
index 9c993fc..cb66436 100644 (file)
@@ -51,13 +51,18 @@ public:
 
 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))
     {
index 80e2792..386bfde 100644 (file)
@@ -34,13 +34,8 @@ FenceValue::~FenceValue()
 {
 }
 
-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)
 {
index 9c7c5c3..513bad5 100644 (file)
@@ -72,14 +72,14 @@ public:
     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);
 };
 
index 1043d5b..3b8727f 100644 (file)
@@ -73,15 +73,10 @@ void MemoryValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
         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 @@ MemoryValue::MemoryValue(MemoryValue::MemoryValueLoadImplied, Kind kind, Origin
 
 // 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)
index 6af3b26..aac3828 100644 (file)
@@ -84,14 +84,14 @@ public:
 
     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 @@ protected:
     
 private:
     friend class Procedure;
+    friend class Value;
 
     bool isLegalOffsetImpl(int32_t offset) const;
     bool isLegalOffsetImpl(int64_t offset) const;
index c98172b..7acba1e 100644 (file)
@@ -58,7 +58,7 @@ public:
             [&] (const ValueKey& key) -> bool {
                 return key.opcode() == ConstFloat || key.opcode() == ConstDouble;
             });
-        
+
         lowerFPConstants();
         
         hoistConstants(
index b33c558..c7f7678 100644 (file)
@@ -44,11 +44,6 @@ void PatchpointValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
         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())
index 3378dc4..42b5471 100644 (file)
@@ -61,14 +61,16 @@ public:
     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);
 };
 
index 7b73de3..9f816c9 100644 (file)
@@ -93,7 +93,6 @@ Value* Procedure::clone(Value* value)
     return m_values.add(WTFMove(clone));
 }
 
-
 Value* Procedure::addIntConstant(Origin origin, Type type, int64_t value)
 {
     switch (type) {
index ff61ccd..e2106ec 100644 (file)
@@ -292,7 +292,7 @@ private:
     bool m_needsUsedRegisters { true };
     bool m_hasQuirks { false };
 };
-
+    
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index 990ba31..1156a55 100644 (file)
 
 #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
index b5fd69b..a0be1f5 100644 (file)
@@ -41,11 +41,6 @@ void SlotBaseValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     out.print(comma, pointerDump(m_slot));
 }
 
-Value* SlotBaseValue::cloneImpl() const
-{
-    return new SlotBaseValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index 19392ea..7600d81 100644 (file)
@@ -41,16 +41,17 @@ public:
 
     StackSlot* slot() const { return m_slot; }
 
-protected:
-    void dumpMeta(CommaPrinter&, PrintStream&) const override;
-
-    Value* cloneImpl() const override;
+    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
 
 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)
     {
     }
index e7c6b49..2f07111 100644 (file)
@@ -83,11 +83,11 @@ void StackmapSpecial::forEachArgImpl(
 
     // 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 @@ bool StackmapSpecial::isValidImpl(
 
     // 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 @@ bool StackmapSpecial::isValidImpl(
     }
 
     // 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) {
index 0ebaf8a..ba317ba 100644 (file)
@@ -37,14 +37,14 @@ StackmapValue::~StackmapValue()
 void StackmapValue::append(Value* value, const ValueRep& rep)
 {
     if (rep == ValueRep::ColdAny) {
-        children().append(value);
+        childrenVector().append(value);
         return;
     }
 
     while (m_reps.size() < numChildren())
         m_reps.append(ValueRep::ColdAny);
 
-    children().append(value);
+    childrenVector().append(value);
     m_reps.append(rep);
 }
 
@@ -89,7 +89,7 @@ void StackmapValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
 }
 
 StackmapValue::StackmapValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
-    : Value(CheckedOpcode, kind, type, origin)
+    : Value(CheckedOpcode, kind, type, VarArgs, origin)
 {
     ASSERT(accepts(kind));
 }
index 52b2101..be99d8c 100644 (file)
@@ -60,8 +60,7 @@ public:
 
     ~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 @@ public:
         return ConstrainedValueCollection(*this);
     }
 
+    B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN
+
 protected:
     void dumpChildren(CommaPrinter&, PrintStream&) const override;
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
index f8709b4..51165bc 100644 (file)
@@ -106,13 +106,8 @@ void SwitchValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     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)
 {
 }
 
index 61a4fed..aca8770 100644 (file)
@@ -64,14 +64,17 @@ public:
 
     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;
index c87432f..a91d07b 100644 (file)
@@ -45,11 +45,6 @@ void UpsilonValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     }
 }
 
-Value* UpsilonValue::cloneImpl() const
-{
-    return new UpsilonValue(*this);
-}
-
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
index 4c479e4..9d63c46 100644 (file)
@@ -45,19 +45,22 @@ public:
         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)
index dfcc9e4..a80d661 100644 (file)
 #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 @@ void Value::replaceWithIdentity(Value* value)
     // 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::replaceWithNop()
 
 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,51 +103,21 @@ void Value::replaceWithPhi()
         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);
 }
 
 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 @@ void Value::replaceWithOops()
     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 @@ void Value::dump(PrintStream& out) const
         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 @@ TriState Value::equalOrUnorderedConstant(const Value*) const
 
 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 @@ bool Value::returnsBool() const
 {
     if (type() != Int32)
         return false;
+
     switch (opcode()) {
     case Const32:
         return asInt32() == 0 || asInt32() == 1;
index 014e78e..b4bd313 100644 (file)
@@ -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 Procedure;
 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 @@ public:
     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,8 +87,57 @@ public:
     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
@@ -301,19 +340,218 @@ public:
         typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
     > { };
 
-
 protected:
-    virtual Value* cloneImpl() const;
-    
+    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 @@ private:
         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 @@ private:
         case Depend:
             if (UNLIKELY(numArgs != 1))
                 badKind(kind, numArgs);
-            break;
+            return One;
         case Add:
         case Sub:
         case Mul:
@@ -380,129 +618,105 @@ private:
         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)
     {
-    }
-    // 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... }
-    {
+        buildAdjacencyList(numChildren);
     }
     // 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)
-    {
-        checkKind(kind, 0);
-    }
-    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)...)
-    {
-        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(CheckedOpcode, kind, type, Zero, origin)
     {
-        checkKind(kind, children.size());
+        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, AdjacencyList&& children)
-        : Value(CheckedOpcode, kind, type, origin, WTFMove(children))
+    explicit Value(Kind kind, Origin origin, Arguments... arguments)
+        : Value(CheckedOpcode, kind, numChildrenForKind(kind, sizeof...(arguments)), origin, static_cast<Value*>(arguments)...)
     {
-        checkKind(kind, m_children.size());
     }
     template<typename... Arguments>
-        explicit Value(Kind kind, Origin origin, Arguments&&... arguments)
-        : Value(CheckedOpcode, kind, origin, std::forward<Arguments>(arguments)...)
+    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, 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 @@ public:
     {
     }
 
-    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 @@ inline DeepValueDump deepDump(const Value* value)
     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)
index 57f93d6..5c3c47f 100644 (file)
 
 #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)
 {
index 6aeef47..887c0b6 100644 (file)
@@ -41,20 +41,15 @@ void VariableValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     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);
 }
 
 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);
index 067ba42..1ecc7e4 100644 (file)
@@ -41,13 +41,15 @@ public:
 
     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*);
index 57d7628..ba7c937 100644 (file)
@@ -39,13 +39,8 @@ void WasmAddressValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
     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)
 {
 }
index 1a24c13..59bb110 100644 (file)
@@ -40,14 +40,17 @@ public:
 
     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;
index 18628b2..3833ef5 100644 (file)
@@ -36,7 +36,7 @@ WasmBoundsCheckValue::~WasmBoundsCheckValue()
 }
 
 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, GPRReg pinnedSize, Val
 }
 
 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 @@ WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, Value* ptr, unsigned o
     m_bounds.maximum = maximum;
 }
 
-Value* WasmBoundsCheckValue::cloneImpl() const
-{
-    return new WasmBoundsCheckValue(*this);
-}
-
 void WasmBoundsCheckValue::dumpMeta(CommaPrinter& comma, PrintStream& out) const
 {
     switch (m_boundsType) {
index 06f6613..b69d24e 100644 (file)
@@ -34,15 +34,7 @@ namespace JSC { namespace B3 {
 
 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 @@ public:
     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;
index aa8e499..4d694f7 100644 (file)
@@ -10960,7 +10960,7 @@ void testCallFunctionWithHellaArguments()
     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 @@ void testCallFunctionWithHellaArguments2()
     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 @@ void testCallFunctionWithHellaArguments3()
     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 @@ void testCallFunctionWithHellaDoubleArguments()
     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 @@ void testCallFunctionWithHellaFloatArguments()
     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);
 
index 7a1faee..b0a2fa9 100644 (file)
@@ -380,7 +380,7 @@ public:
     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); }