⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 244309 in webkit


Ignore:
Timestamp:
Apr 15, 2019, 4:53:23 PM (7 years ago)
Author:
rmorisset@apple.com
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

(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):

Location:
trunk/Source/JavaScriptCore
Files:
51 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r244300 r244309  
     12019-04-15  Robin Morisset  <rmorisset@apple.com>
     2
     3        B3::Value should have different kinds of adjacency lists
     4        https://bugs.webkit.org/show_bug.cgi?id=196091
     5
     6        Reviewed by Filip Pizlo.
     7
     8        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:
     9        - Nothing (0 bytes)
     10        - 1 Value* (8 bytes)
     11        - 2 Value* (16 bytes)
     12        - 3 Value* (24 bytes)
     13        - A Vector<Value*, 3>
     14        after the end of the Value object, depending on the kind of the Value.
     15        So for example, when allocating an Add, we would allocate an extra 16 bytes into which to store 2 Values.
     16        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).
     17
     18        A few implementation points:
     19        - 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)
     20        - We must make sure to destroy the vector whenever we destroy a Value which is VarArgs
     21        - 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
     22          Thankfully, we have an extra byte of padding to use in the middle of B3::Value
     23        - 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
     24        - 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.
     25        - 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.
     26          This is done through the B3_SPECIALIZE_VALUE_FOR_... defined at the bottom of B3Value.h
     27        - 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.
     28        - 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
     29
     30        * JavaScriptCore.xcodeproj/project.pbxproj:
     31        * b3/B3ArgumentRegValue.cpp:
     32        (JSC::B3::ArgumentRegValue::cloneImpl const): Deleted.
     33        * b3/B3ArgumentRegValue.h:
     34        * b3/B3AtomicValue.cpp:
     35        (JSC::B3::AtomicValue::AtomicValue):
     36        (JSC::B3::AtomicValue::cloneImpl const): Deleted.
     37        * b3/B3AtomicValue.h:
     38        * b3/B3BasicBlock.h:
     39        * b3/B3BasicBlockInlines.h:
     40        (JSC::B3::BasicBlock::appendNewNonTerminal): Deleted.
     41        * b3/B3CCallValue.cpp:
     42        (JSC::B3::CCallValue::appendArgs):
     43        (JSC::B3::CCallValue::cloneImpl const): Deleted.
     44        * b3/B3CCallValue.h:
     45        * b3/B3CheckValue.cpp:
     46        (JSC::B3::CheckValue::cloneImpl const): Deleted.
     47        * b3/B3CheckValue.h:
     48        * b3/B3Const32Value.cpp:
     49        (JSC::B3::Const32Value::cloneImpl const): Deleted.
     50        * b3/B3Const32Value.h:
     51        * b3/B3Const64Value.cpp:
     52        (JSC::B3::Const64Value::cloneImpl const): Deleted.
     53        * b3/B3Const64Value.h:
     54        * b3/B3ConstDoubleValue.cpp:
     55        (JSC::B3::ConstDoubleValue::cloneImpl const): Deleted.
     56        * b3/B3ConstDoubleValue.h:
     57        * b3/B3ConstFloatValue.cpp:
     58        (JSC::B3::ConstFloatValue::cloneImpl const): Deleted.
     59        * b3/B3ConstFloatValue.h:
     60        * b3/B3ConstPtrValue.h:
     61        (JSC::B3::ConstPtrValue::opcodeFromConstructor):
     62        * b3/B3FenceValue.cpp:
     63        (JSC::B3::FenceValue::FenceValue):
     64        (JSC::B3::FenceValue::cloneImpl const): Deleted.
     65        * b3/B3FenceValue.h:
     66        * b3/B3MemoryValue.cpp:
     67        (JSC::B3::MemoryValue::MemoryValue):
     68        (JSC::B3::MemoryValue::cloneImpl const): Deleted.
     69        * b3/B3MemoryValue.h:
     70        * b3/B3MoveConstants.cpp:
     71        * b3/B3PatchpointValue.cpp:
     72        (JSC::B3::PatchpointValue::cloneImpl const): Deleted.
     73        * b3/B3PatchpointValue.h:
     74        (JSC::B3::PatchpointValue::opcodeFromConstructor):
     75        * b3/B3Procedure.cpp:
     76        * b3/B3Procedure.h:
     77        * b3/B3ProcedureInlines.h:
     78        (JSC::B3::Procedure::add):
     79        * b3/B3SlotBaseValue.cpp:
     80        (JSC::B3::SlotBaseValue::cloneImpl const): Deleted.
     81        * b3/B3SlotBaseValue.h:
     82        * b3/B3StackmapSpecial.cpp:
     83        (JSC::B3::StackmapSpecial::forEachArgImpl):
     84        (JSC::B3::StackmapSpecial::isValidImpl):
     85        * b3/B3StackmapValue.cpp:
     86        (JSC::B3::StackmapValue::append):
     87        (JSC::B3::StackmapValue::StackmapValue):
     88        * b3/B3StackmapValue.h:
     89        * b3/B3SwitchValue.cpp:
     90        (JSC::B3::SwitchValue::SwitchValue):
     91        (JSC::B3::SwitchValue::cloneImpl const): Deleted.
     92        * b3/B3SwitchValue.h:
     93        (JSC::B3::SwitchValue::opcodeFromConstructor):
     94        * b3/B3UpsilonValue.cpp:
     95        (JSC::B3::UpsilonValue::cloneImpl const): Deleted.
     96        * b3/B3UpsilonValue.h:
     97        * b3/B3Value.cpp:
     98        (JSC::B3::DeepValueDump::dump const):
     99        (JSC::B3::Value::~Value):
     100        (JSC::B3::Value::replaceWithIdentity):
     101        (JSC::B3::Value::replaceWithNopIgnoringType):
     102        (JSC::B3::Value::replaceWithPhi):
     103        (JSC::B3::Value::replaceWithJump):
     104        (JSC::B3::Value::replaceWithOops):
     105        (JSC::B3::Value::replaceWith):
     106        (JSC::B3::Value::invertedCompare const):
     107        (JSC::B3::Value::returnsBool const):
     108        (JSC::B3::Value::cloneImpl const): Deleted.
     109        * b3/B3Value.h:
     110        (JSC::B3::DeepValueDump::dump const): Deleted.
     111        * b3/B3ValueInlines.h:
     112        (JSC::B3::Value::adjacencyListOffset const):
     113        (JSC::B3::Value::cloneImpl const):
     114        * b3/B3VariableValue.cpp:
     115        (JSC::B3::VariableValue::VariableValue):
     116        (JSC::B3::VariableValue::cloneImpl const): Deleted.
     117        * b3/B3VariableValue.h:
     118        * b3/B3WasmAddressValue.cpp:
     119        (JSC::B3::WasmAddressValue::WasmAddressValue):
     120        (JSC::B3::WasmAddressValue::cloneImpl const): Deleted.
     121        * b3/B3WasmAddressValue.h:
     122        * b3/B3WasmBoundsCheckValue.cpp:
     123        (JSC::B3::WasmBoundsCheckValue::WasmBoundsCheckValue):
     124        (JSC::B3::WasmBoundsCheckValue::cloneImpl const): Deleted.
     125        * b3/B3WasmBoundsCheckValue.h:
     126        (JSC::B3::WasmBoundsCheckValue::accepts):
     127        (JSC::B3::WasmBoundsCheckValue::opcodeFromConstructor):
     128        * b3/testb3.cpp:
     129        (JSC::B3::testCallFunctionWithHellaArguments):
     130        (JSC::B3::testCallFunctionWithHellaArguments2):
     131        (JSC::B3::testCallFunctionWithHellaArguments3):
     132        (JSC::B3::testCallFunctionWithHellaDoubleArguments):
     133        (JSC::B3::testCallFunctionWithHellaFloatArguments):
     134        * ftl/FTLOutput.h:
     135        (JSC::FTL::Output::call):
     136
    11372019-04-15  Tadeu Zagallo  <tzagallo@apple.com>
    2138
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r244298 r244309  
    670670                0FEC85421BDACDAC0080FF74 /* B3Validate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84F81BDACDAC0080FF74 /* B3Validate.h */; };
    671671                0FEC85441BDACDAC0080FF74 /* B3Value.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FA1BDACDAC0080FF74 /* B3Value.h */; };
    672                 0FEC85451BDACDAC0080FF74 /* B3ValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FB1BDACDAC0080FF74 /* B3ValueInlines.h */; };
    673672                0FEC85471BDACDAC0080FF74 /* B3ValueRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FD1BDACDAC0080FF74 /* B3ValueRep.h */; };
    674673                0FEC856E1BDACDC70080FF74 /* AirAllocateStackByGraphColoring.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC85491BDACDC70080FF74 /* AirAllocateStackByGraphColoring.h */; };
     
    858857                2D342F36F7244096804ADB24 /* SourceOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 425BA1337E4344E1B269A671 /* SourceOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; };
    859858                3395C70722555F6D00BDBFAD /* B3EliminateDeadCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3395C70522555F6D00BDBFAD /* B3EliminateDeadCode.h */; };
     859                33B2A54722653481005A0F79 /* B3ValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FB1BDACDAC0080FF74 /* B3ValueInlines.h */; };
     860                33B2A548226543BF005A0F79 /* FTLLowerDFGToB3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEA0A04170513DB00BB722C /* FTLLowerDFGToB3.cpp */; };
    860861                371D842D17C98B6E00ECF994 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 371D842C17C98B6E00ECF994 /* libz.dylib */; };
    861862                37C738D21EDB56E4003F2B0B /* ParseInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 37C738D11EDB5672003F2B0B /* ParseInt.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    919920                5333BBDC2110F7D9007618EC /* DFGSpeculativeJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86EC9DC21328DF82002B2AD7 /* DFGSpeculativeJIT.cpp */; };
    920921                5333BBDD2110F7E1007618EC /* DFGSpeculativeJIT64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */; };
    921                 5333BBDE2110FA3E007618EC /* FTLLowerDFGToB3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FEA0A04170513DB00BB722C /* FTLLowerDFGToB3.cpp */; };
    922922                5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */; };
    923923                534638711E70CF3D00F12AC1 /* JSRunLoopTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    85078507                                0FB3878E1BFBC44D00E3AB1E /* AirBlockWorklist.h in Headers */,
    85088508                                0F79C7CA1E74C93B00EB34D1 /* AirBreakCriticalEdges.h in Headers */,
     8509                                33B2A54722653481005A0F79 /* B3ValueInlines.h in Headers */,
    85098510                                0F61832A1C45BF070072450B /* AirCCallingConvention.h in Headers */,
    85108511                                0FEC85741BDACDC70080FF74 /* AirCCallSpecial.h in Headers */,
     
    86998700                                0FEC85421BDACDAC0080FF74 /* B3Validate.h in Headers */,
    87008701                                0FEC85441BDACDAC0080FF74 /* B3Value.h in Headers */,
    8701                                 0FEC85451BDACDAC0080FF74 /* B3ValueInlines.h in Headers */,
    87028702                                0F338E151BF0276C0013C88F /* B3ValueKey.h in Headers */,
    87038703                                0F338E161BF0276C0013C88F /* B3ValueKeyInlines.h in Headers */,
     
    1070410704                                5333BBDB2110F7D2007618EC /* DFGSpeculativeJIT32_64.cpp in Sources */,
    1070510705                                5333BBDD2110F7E1007618EC /* DFGSpeculativeJIT64.cpp in Sources */,
    10706                                 5333BBDE2110FA3E007618EC /* FTLLowerDFGToB3.cpp in Sources */,
    1070710706                                536B319E1F735F160037FC33 /* LowLevelInterpreter.cpp in Sources */,
    1070810707                                0FF4274A158EBE91004CB9FF /* udis86.c in Sources */,
     
    1083810837                                536B31261F71C5990037FC33 /* UnifiedSource120.cpp in Sources */,
    1083910838                                536B312D1F71C5990037FC33 /* UnifiedSource121.cpp in Sources */,
     10839                                33B2A548226543BF005A0F79 /* FTLLowerDFGToB3.cpp in Sources */,
    1084010840                                536B31251F71C5990037FC33 /* UnifiedSource122.cpp in Sources */,
    1084110841                                536B311E1F71C5990037FC33 /* UnifiedSource123.cpp in Sources */,
  • trunk/Source/JavaScriptCore/b3/B3ArgumentRegValue.cpp

    r195395 r244309  
    4040}
    4141
    42 Value* ArgumentRegValue::cloneImpl() const
    43 {
    44     return new ArgumentRegValue(*this);
    45 }
    46 
    4742} } // namespace JSC::B3
    4843
  • trunk/Source/JavaScriptCore/b3/B3ArgumentRegValue.h

    r209764 r244309  
    4141    Reg argumentReg() const { return m_reg; }
    4242
     43    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
     44
    4345protected:
    4446    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    4547
    46     Value* cloneImpl() const override;
    47 
    4848private:
    4949    friend class Procedure;
     50    friend class Value;
     51   
     52    static Opcode opcodeFromConstructor(Origin, Reg) { return ArgumentReg; }
    5053
    5154    ArgumentRegValue(Origin origin, Reg reg)
    52         : Value(CheckedOpcode, ArgumentReg, reg.isGPR() ? pointerType() : Double, origin)
     55        : Value(CheckedOpcode, ArgumentReg, reg.isGPR() ? pointerType() : Double, Zero, origin)
    5356        , m_reg(reg)
    5457    {
  • trunk/Source/JavaScriptCore/b3/B3AtomicValue.cpp

    r215407 r244309  
    4242}
    4343
    44 Value* AtomicValue::cloneImpl() const
    45 {
    46     return new AtomicValue(*this);
    47 }
    48 
    4944AtomicValue::AtomicValue(AtomicValue::AtomicValueRMW, Kind kind, Origin origin, Width width, Value* operand, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    50     : MemoryValue(CheckedOpcode, kind, operand->type(), origin, offset, range, fenceRange, operand, pointer)
     45    : MemoryValue(CheckedOpcode, kind, operand->type(), Two, origin, offset, range, fenceRange, operand, pointer)
    5146    , m_width(width)
    5247{
     
    6762
    6863AtomicValue::AtomicValue(AtomicValue::AtomicValueCAS, Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    69     : MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), origin, offset, range, fenceRange, expectedValue, newValue, pointer)
     64    : MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), Three, origin, offset, range, fenceRange, expectedValue, newValue, pointer)
    7065    , m_width(width)
    7166{
  • trunk/Source/JavaScriptCore/b3/B3AtomicValue.h

    r215407 r244309  
    4545   
    4646    Width accessWidth() const { return m_width; }
     47
     48    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
    4749   
    4850protected:
    4951    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    50    
    51     Value* cloneImpl() const override;
    52    
     52
    5353private:
    5454    friend class Procedure;
     55    friend class Value;
    5556
    5657    enum AtomicValueRMW { AtomicValueRMWTag };
  • trunk/Source/JavaScriptCore/b3/B3BasicBlock.h

    r214410 r244309  
    8585    template<typename ValueType, typename... Arguments>
    8686    ValueType* appendNew(Procedure&, Arguments...);
    87     template<typename ValueType, typename... Arguments>
    88     ValueType* appendNewNonTerminal(Procedure&, Arguments...);
    8987
    9088    JS_EXPORT_PRIVATE Value* appendIntConstant(Procedure&, Origin, Type, int64_t value);
  • trunk/Source/JavaScriptCore/b3/B3BasicBlockInlines.h

    r206525 r244309  
    3939    ValueType* result = procedure.add<ValueType>(arguments...);
    4040    append(result);
    41     return result;
    42 }
    43 
    44 template<typename ValueType, typename... Arguments>
    45 ValueType* BasicBlock::appendNewNonTerminal(Procedure& procedure, Arguments... arguments)
    46 {
    47     ValueType* result = procedure.add<ValueType>(arguments...);
    48     appendNonTerminal(result);
    4941    return result;
    5042}
  • trunk/Source/JavaScriptCore/b3/B3CCallValue.cpp

    r195395 r244309  
    3535}
    3636
    37 Value* CCallValue::cloneImpl() const
     37void CCallValue::appendArgs(const Vector<Value*>& args)
    3838{
    39     return new CCallValue(*this);
     39    childrenVector().appendVector(args);
    4040}
    4141
  • trunk/Source/JavaScriptCore/b3/B3CCallValue.h

    r206595 r244309  
    3939    ~CCallValue();
    4040
     41    void appendArgs(const Vector<Value*>&);
     42   
    4143    Effects effects;
    4244
    43 protected:
    44     Value* cloneImpl() const override;
    45    
     45    B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN
     46    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
     47
    4648private:
    4749    friend class Procedure;
     50    friend class Value;
     51
     52    template<typename... Arguments>
     53    static Opcode opcodeFromConstructor(Arguments...) { return CCall; }
    4854
    4955    template<typename... Arguments>
    5056    CCallValue(Type type, Origin origin, Arguments... arguments)
    51         : Value(CheckedOpcode, CCall, type, origin, arguments...)
     57        : Value(CheckedOpcode, CCall, type, VarArgs, origin, static_cast<Value*>(arguments)...)
    5258        , effects(Effects::forCall())
    5359    {
     
    5763    template<typename... Arguments>
    5864    CCallValue(Type type, Origin origin, const Effects& effects, Arguments... arguments)
    59         : Value(CheckedOpcode, CCall, type, origin, arguments...)
     65        : Value(CheckedOpcode, CCall, type, VarArgs, origin, static_cast<Value*>(arguments)...)
    6066        , effects(effects)
    6167    {
  • trunk/Source/JavaScriptCore/b3/B3CheckValue.cpp

    r206595 r244309  
    4141}
    4242
    43 Value* CheckValue::cloneImpl() const
    44 {
    45     return new CheckValue(*this);
    46 }
    47 
    4843// Use this form for CheckAdd, CheckSub, and CheckMul.
    4944CheckValue::CheckValue(Kind kind, Origin origin, Value* left, Value* right)
  • trunk/Source/JavaScriptCore/b3/B3CheckValue.h

    r206595 r244309  
    5151    void convertToAdd();
    5252
    53 protected:
    54     Value* cloneImpl() const override;
     53    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
    5554   
    5655private:
    5756    friend class Procedure;
     57    friend class Value;
    5858
    5959    // Use this form for CheckAdd, CheckSub, and CheckMul.
  • trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp

    r229517 r244309  
    304304}
    305305
    306 Value* Const32Value::cloneImpl() const
    307 {
    308     return new Const32Value(*this);
    309 }
    310 
    311306} } // namespace JSC::B3
    312307
  • trunk/Source/JavaScriptCore/b3/B3Const32Value.h

    r208848 r244309  
    7676    TriState belowEqualConstant(const Value* other) const override;
    7777
     78    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
     79
    7880protected:
    7981    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    8082
    81     Value* cloneImpl() const override;
    82 
    83     friend class Procedure;
     83    // Protected because of ConstPtrValue
     84    static Opcode opcodeFromConstructor(Origin = Origin(), int32_t = 0) { return Const32; }
    8485
    8586    Const32Value(Origin origin, int32_t value)
    86         : Value(CheckedOpcode, Const32, Int32, origin)
     87        : Value(CheckedOpcode, Const32, Int32, Zero, origin)
    8788        , m_value(value)
    8889    {
     
    9091
    9192private:
     93    friend class Procedure;
     94    friend class Value;
     95
    9296    int32_t m_value;
    9397};
  • trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp

    r229517 r244309  
    304304}
    305305
    306 Value* Const64Value::cloneImpl() const
    307 {
    308     return new Const64Value(*this);
    309 }
    310 
    311306} } // namespace JSC::B3
    312307
  • trunk/Source/JavaScriptCore/b3/B3Const64Value.h

    r208848 r244309  
    7676    TriState belowEqualConstant(const Value* other) const override;
    7777
     78    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
     79
    7880protected:
    7981    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    8082
    81     Value* cloneImpl() const override;
    82 
    83     friend class Procedure;
     83    // Protected because of ConstPtrValue
     84    static Opcode opcodeFromConstructor(Origin = Origin(), int64_t = 0) { return Const64; }
    8485
    8586    Const64Value(Origin origin, int64_t value)
    86         : Value(CheckedOpcode, Const64, Int64, origin)
     87        : Value(CheckedOpcode, Const64, Int64, Zero, origin)
    8788        , m_value(value)
    8889    {
    8990    }
    90    
     91
    9192private:
     93    friend class Procedure;
     94    friend class Value;
     95
    9296    int64_t m_value;
    9397};
  • trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.cpp

    r210124 r244309  
    198198}
    199199
    200 Value* ConstDoubleValue::cloneImpl() const
    201 {
    202     return new ConstDoubleValue(*this);
    203 }
    204 
    205200} } // namespace JSC::B3
    206201
  • trunk/Source/JavaScriptCore/b3/B3ConstDoubleValue.h

    r210124 r244309  
    6565    TriState equalOrUnorderedConstant(const Value* other) const override;
    6666
    67 protected:
    68     void dumpMeta(CommaPrinter&, PrintStream&) const override;
    69 
    70     Value* cloneImpl() const override;
     67    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
    7168
    7269private:
    7370    friend class Procedure;
     71    friend class Value;
     72
     73    void dumpMeta(CommaPrinter&, PrintStream&) const override;
     74
     75    static Opcode opcodeFromConstructor(Origin, double) { return ConstDouble; }
    7476
    7577    ConstDoubleValue(Origin origin, double value)
    76         : Value(CheckedOpcode, ConstDouble, Double, origin)
     78        : Value(CheckedOpcode, ConstDouble, Double, Zero, origin)
    7779        , m_value(value)
    7880    {
  • trunk/Source/JavaScriptCore/b3/B3ConstFloatValue.cpp

    r219038 r244309  
    190190}
    191191
    192 Value* ConstFloatValue::cloneImpl() const
    193 {
    194     return new ConstFloatValue(*this);
    195 }
    196 
    197192} } // namespace JSC::B3
    198193
  • trunk/Source/JavaScriptCore/b3/B3ConstFloatValue.h

    r219038 r244309  
    6464    TriState equalOrUnorderedConstant(const Value* other) const override;
    6565
    66 protected:
    67     void dumpMeta(CommaPrinter&, PrintStream&) const override;
    68 
    69     Value* cloneImpl() const override;
     66    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
    7067
    7168private:
    7269    friend class Procedure;
     70    friend class Value;
     71
     72    void dumpMeta(CommaPrinter&, PrintStream&) const override;
     73
     74    static Opcode opcodeFromConstructor(Origin, float) { return ConstFloat; }
    7375
    7476    ConstFloatValue(Origin origin, float value)
    75         : Value(CheckedOpcode, ConstFloat, Float, origin)
     77        : Value(CheckedOpcode, ConstFloat, Float, Zero, origin)
    7678        , m_value(value)
    7779    {
  • trunk/Source/JavaScriptCore/b3/B3ConstPtrValue.h

    r237173 r244309  
    5252private:
    5353    friend class Procedure;
     54    friend class Value;
    5455
     56    template<typename T>
     57    static Opcode opcodeFromConstructor(Origin, T*) { return ConstPtrValueBase::opcodeFromConstructor(); }
    5558    template<typename T>
    5659    ConstPtrValue(Origin origin, T* pointer)
     
    5861    {
    5962    }
     63    template<typename T>
     64    static Opcode opcodeFromConstructor(Origin, T) { return ConstPtrValueBase::opcodeFromConstructor(); }
    6065    template<typename T>
    6166    ConstPtrValue(Origin origin, T pointer)
  • trunk/Source/JavaScriptCore/b3/B3FenceValue.cpp

    r206226 r244309  
    3535}
    3636
    37 Value* FenceValue::cloneImpl() const
    38 {
    39     return new FenceValue(*this);
    40 }
    41 
    4237FenceValue::FenceValue(Origin origin, HeapRange read, HeapRange write)
    43     : Value(CheckedOpcode, Fence, Void, origin)
     38    : Value(CheckedOpcode, Fence, Void, Zero, origin)
    4439    , read(read)
    4540    , write(write)
  • trunk/Source/JavaScriptCore/b3/B3FenceValue.h

    r213704 r244309  
    7373    HeapRange write { HeapRange::top() };
    7474
    75 protected:
    76     Value* cloneImpl() const override;
     75    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
    7776
    7877private:
    7978    friend class Procedure;
     79    friend class Value;
    8080   
     81    static Opcode opcodeFromConstructor(Origin, HeapRange = HeapRange(), HeapRange = HeapRange()) { return Fence; }
    8182    FenceValue(Origin origin, HeapRange read, HeapRange write);
    82    
    8383    FenceValue(Origin origin);
    8484};
  • trunk/Source/JavaScriptCore/b3/B3MemoryValue.cpp

    r215407 r244309  
    7474}
    7575
    76 Value* MemoryValue::cloneImpl() const
    77 {
    78     return new MemoryValue(*this);
    79 }
    80 
    8176// Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
    8277// describes the returned type).
    8378MemoryValue::MemoryValue(MemoryValue::MemoryValueLoad, Kind kind, Type type, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    84     : Value(CheckedOpcode, kind, type, origin, pointer)
     79    : Value(CheckedOpcode, kind, type, One, origin, pointer)
    8580    , m_offset(offset)
    8681    , m_range(range)
     
    127122// Use this form for stores.
    128123MemoryValue::MemoryValue(MemoryValue::MemoryValueStore, Kind kind, Origin origin, Value* value, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    129     : Value(CheckedOpcode, kind, Void, origin, value, pointer)
     124    : Value(CheckedOpcode, kind, Void, Two, origin, value, pointer)
    130125    , m_offset(offset)
    131126    , m_range(range)
  • trunk/Source/JavaScriptCore/b3/B3MemoryValue.h

    r215407 r244309  
    8585    bool isCanonicalWidth() const { return B3::isCanonicalWidth(accessWidth()); }
    8686
     87    B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN
     88
    8789protected:
    8890    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    89 
    90     Value* cloneImpl() const override;
    91 
     91   
    9292    template<typename Int, typename = IsLegalOffset<Int>, typename... Arguments>
    93     MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Int offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
    94         : Value(CheckedOpcode, kind, type, origin, arguments...)
     93    MemoryValue(CheckedOpcodeTag, Kind kind, Type type, NumChildren numChildren, Origin origin, Int offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
     94        : Value(CheckedOpcode, kind, type, numChildren, origin, static_cast<Value*>(arguments)...)
    9595        , m_offset(offset)
    9696        , m_range(range)
     
    101101private:
    102102    friend class Procedure;
     103    friend class Value;
    103104
    104105    bool isLegalOffsetImpl(int32_t offset) const;
  • trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp

    r225375 r244309  
    5959                return key.opcode() == ConstFloat || key.opcode() == ConstDouble;
    6060            });
    61        
     61
    6262        lowerFPConstants();
    6363       
  • trunk/Source/JavaScriptCore/b3/B3PatchpointValue.cpp

    r196032 r244309  
    4545}
    4646
    47 Value* PatchpointValue::cloneImpl() const
    48 {
    49     return new PatchpointValue(*this);
    50 }
    51 
    5247PatchpointValue::PatchpointValue(Type type, Origin origin)
    5348    : Base(CheckedOpcode, Patchpoint, type, origin)
  • trunk/Source/JavaScriptCore/b3/B3PatchpointValue.h

    r206595 r244309  
    6262    uint8_t numFPScratchRegisters { 0 };
    6363
     64    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
     65
    6466protected:
    6567    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    6668
    67     Value* cloneImpl() const override;
    68 
    6969private:
    7070    friend class Procedure;
     71    friend class Value;
    7172
     73    static Opcode opcodeFromConstructor(Type, Origin) { return Patchpoint; }
    7274    JS_EXPORT_PRIVATE PatchpointValue(Type, Origin);
    7375};
  • trunk/Source/JavaScriptCore/b3/B3Procedure.cpp

    r221703 r244309  
    9494}
    9595
    96 
    9796Value* Procedure::addIntConstant(Origin origin, Type type, int64_t value)
    9897{
  • trunk/Source/JavaScriptCore/b3/B3Procedure.h

    r221703 r244309  
    293293    bool m_hasQuirks { false };
    294294};
    295 
     295   
    296296} } // namespace JSC::B3
    297297
  • trunk/Source/JavaScriptCore/b3/B3ProcedureInlines.h

    r206525 r244309  
    3030#include "B3BasicBlock.h"
    3131#include "B3Procedure.h"
     32#include "B3Value.h"
    3233
    3334namespace JSC { namespace B3 {
    34 
     35   
    3536template<typename ValueType, typename... Arguments>
    3637ValueType* Procedure::add(Arguments... arguments)
    3738{
    38     return static_cast<ValueType*>(addValueImpl(new ValueType(arguments...)));
     39    return static_cast<ValueType*>(addValueImpl(Value::allocate<ValueType>(arguments...)));
    3940}
    4041
  • trunk/Source/JavaScriptCore/b3/B3SlotBaseValue.cpp

    r195620 r244309  
    4242}
    4343
    44 Value* SlotBaseValue::cloneImpl() const
    45 {
    46     return new SlotBaseValue(*this);
    47 }
    48 
    4944} } // namespace JSC::B3
    5045
  • trunk/Source/JavaScriptCore/b3/B3SlotBaseValue.h

    r206595 r244309  
    4242    StackSlot* slot() const { return m_slot; }
    4343
    44 protected:
    45     void dumpMeta(CommaPrinter&, PrintStream&) const override;
    46 
    47     Value* cloneImpl() const override;
     44    B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN
    4845
    4946private:
    5047    friend class Procedure;
     48    friend class Value;
    5149
     50    void dumpMeta(CommaPrinter&, PrintStream&) const override;
     51
     52    static Opcode opcodeFromConstructor(Origin, StackSlot*) { return SlotBase; }
    5253    SlotBaseValue(Origin origin, StackSlot* slot)
    53         : Value(CheckedOpcode, SlotBase, pointerType(), origin)
     54        : Value(CheckedOpcode, SlotBase, pointerType(), Zero, origin)
    5455        , m_slot(slot)
    5556    {
  • trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp

    r239427 r244309  
    8484    // Check that insane things have not happened.
    8585    ASSERT(inst.args.size() >= numIgnoredAirArgs);
    86     ASSERT(value->children().size() >= numIgnoredB3Args);
    87     ASSERT(inst.args.size() - numIgnoredAirArgs >= value->children().size() - numIgnoredB3Args);
     86    ASSERT(value->numChildren() >= numIgnoredB3Args);
     87    ASSERT(inst.args.size() - numIgnoredAirArgs >= value->numChildren() - numIgnoredB3Args);
    8888    ASSERT(inst.args[0].kind() == Arg::Kind::Special);
    8989
    90     for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
     90    for (unsigned i = 0; i < value->numChildren() - numIgnoredB3Args; ++i) {
    9191        Arg& arg = inst.args[i + numIgnoredAirArgs];
    9292        ConstrainedValue child = value->constrainedChild(i + numIgnoredB3Args);
     
    161161    // Check that insane things have not happened.
    162162    ASSERT(inst.args.size() >= numIgnoredAirArgs);
    163     ASSERT(value->children().size() >= numIgnoredB3Args);
     163    ASSERT(value->numChildren() >= numIgnoredB3Args);
    164164
    165165    // For the Inst to be valid, it needs to have the right number of arguments.
    166     if (inst.args.size() - numIgnoredAirArgs < value->children().size() - numIgnoredB3Args)
     166    if (inst.args.size() - numIgnoredAirArgs < value->numChildren() - numIgnoredB3Args)
    167167        return false;
    168168
     
    170170    // example, you can't have a non-FP-offset address. This verifies those conditions as well as the
    171171    // argument types.
    172     for (unsigned i = 0; i < value->children().size() - numIgnoredB3Args; ++i) {
     172    for (unsigned i = 0; i < value->numChildren() - numIgnoredB3Args; ++i) {
    173173        Value* child = value->child(i + numIgnoredB3Args);
    174174        Arg& arg = inst.args[i + numIgnoredAirArgs];
     
    179179
    180180    // The number of constraints has to be no greater than the number of B3 children.
    181     ASSERT(value->m_reps.size() <= value->children().size());
     181    ASSERT(value->m_reps.size() <= value->numChildren());
    182182
    183183    // Verify any explicitly supplied constraints.
  • trunk/Source/JavaScriptCore/b3/B3StackmapValue.cpp

    r227617 r244309  
    3838{
    3939    if (rep == ValueRep::ColdAny) {
    40         children().append(value);
     40        childrenVector().append(value);
    4141        return;
    4242    }
     
    4545        m_reps.append(ValueRep::ColdAny);
    4646
    47     children().append(value);
     47    childrenVector().append(value);
    4848    m_reps.append(rep);
    4949}
     
    9090
    9191StackmapValue::StackmapValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
    92     : Value(CheckedOpcode, kind, type, origin)
     92    : Value(CheckedOpcode, kind, type, VarArgs, origin)
    9393{
    9494    ASSERT(accepts(kind));
  • trunk/Source/JavaScriptCore/b3/B3StackmapValue.h

    r227617 r244309  
    6161    ~StackmapValue();
    6262
    63     // Use this to add children. Note that you could also add children by doing
    64     // children().append(). That will work fine, but it's not recommended.
     63    // Use this to add children.
    6564    void append(const ConstrainedValue& value)
    6665    {
     
    285284        return ConstrainedValueCollection(*this);
    286285    }
     286
     287    B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN
    287288
    288289protected:
  • trunk/Source/JavaScriptCore/b3/B3SwitchValue.cpp

    r227597 r244309  
    107107}
    108108
    109 Value* SwitchValue::cloneImpl() const
    110 {
    111     return new SwitchValue(*this);
    112 }
    113 
    114109SwitchValue::SwitchValue(Origin origin, Value* child)
    115     : Value(CheckedOpcode, Switch, Void, origin, child)
     110    : Value(CheckedOpcode, Switch, Void, One, origin, child)
    116111{
    117112}
  • trunk/Source/JavaScriptCore/b3/B3SwitchValue.h

    r215908 r244309  
    6565    void dumpSuccessors(const BasicBlock*, PrintStream&) const override;
    6666
     67    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
     68    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     69
    6770protected:
    6871    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    6972
    70     Value* cloneImpl() const override;
    71 
    7273private:
    7374    friend class Procedure;
     75    friend class Value;
    7476
     77    static Opcode opcodeFromConstructor(Origin, Value*) { return Switch; }
    7578    JS_EXPORT_PRIVATE SwitchValue(Origin, Value* child);
    7679
  • trunk/Source/JavaScriptCore/b3/B3UpsilonValue.cpp

    r195395 r244309  
    4646}
    4747
    48 Value* UpsilonValue::cloneImpl() const
    49 {
    50     return new UpsilonValue(*this);
    51 }
    52 
    5348} } // namespace JSC::B3
    5449
  • trunk/Source/JavaScriptCore/b3/B3UpsilonValue.h

    r206595 r244309  
    4646    }
    4747
     48    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
     49    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     50
    4851protected:
    4952    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    5053
    51     Value* cloneImpl() const override;
    52 
    5354private:
    5455    friend class Procedure;
     56    friend class Value;
    5557
     58    static Opcode opcodeFromConstructor(Origin, Value*, Value* = nullptr) { return Upsilon; }
    5659    // Note that passing the Phi during construction is optional. A valid pattern is to first create
    5760    // the Upsilons without the Phi, then create the Phi, then go back and tell the Upsilons about
    5861    // the Phi. This allows you to emit code in its natural order.
    5962    UpsilonValue(Origin origin, Value* value, Value* phi = nullptr)
    60         : Value(CheckedOpcode, Upsilon, Void, origin, value)
     63        : Value(CheckedOpcode, Upsilon, Void, One, origin, value)
    6164        , m_phi(phi)
    6265    {
  • trunk/Source/JavaScriptCore/b3/B3Value.cpp

    r243851 r244309  
    4848#include <wtf/ListDump.h>
    4949#include <wtf/StringPrintStream.h>
     50#include <wtf/Vector.h>
    5051
    5152namespace JSC { namespace B3 {
    5253
    5354const char* const Value::dumpPrefix = "@";
     55void DeepValueDump::dump(PrintStream& out) const
     56{
     57    if (m_value)
     58        m_value->deepDump(m_proc, out);
     59    else
     60        out.print("<null>");
     61}
    5462
    5563Value::~Value()
    5664{
     65    if (m_numChildren == VarArgs)
     66        bitwise_cast<Vector<Value*, 3> *>(childrenAlloc())->Vector<Value*, 3>::~Vector();
    5767}
    5868
     
    6373    // previous value in place, and then we construct the Identity Value in place.
    6474
    65     ASSERT(m_type == value->m_type);
     75    RELEASE_ASSERT(m_type == value->m_type);
    6676    ASSERT(value != this);
    6777
    68     if (m_type == Void) {
     78    if (m_type == Void)
    6979        replaceWithNopIgnoringType();
    70         return;
    71     }
    72 
    73     unsigned index = m_index;
    74     Type type = m_type;
    75     Origin origin = m_origin;
    76     BasicBlock* owner = this->owner;
    77 
    78     RELEASE_ASSERT(type == value->type());
    79 
    80     this->~Value();
    81 
    82     new (this) Value(Identity, type, origin, value);
    83 
    84     this->owner = owner;
    85     this->m_index = index;
     80    else
     81        replaceWith(Identity, m_type, this->owner, value);
    8682}
    8783
     
    9995void Value::replaceWithNopIgnoringType()
    10096{
    101     unsigned index = m_index;
    102     Origin origin = m_origin;
    103     BasicBlock* owner = this->owner;
    104 
    105     this->~Value();
    106 
    107     new (this) Value(Nop, Void, origin);
    108 
    109     this->owner = owner;
    110     this->m_index = index;
     97    replaceWith(Nop, Void, this->owner);
    11198}
    11299
     
    117104        return;
    118105    }
    119    
     106
     107    replaceWith(Phi, m_type, this->owner);
     108}
     109
     110void Value::replaceWithJump(BasicBlock* owner, FrequentedBlock target)
     111{
     112    RELEASE_ASSERT(owner->last() == this);
     113    replaceWith(Jump, Void, this->owner);
     114    owner->setSuccessors(target);
     115}
     116
     117void Value::replaceWithOops(BasicBlock* owner)
     118{
     119    RELEASE_ASSERT(owner->last() == this);
     120    replaceWith(Oops, Void, this->owner);
     121    owner->clearSuccessors();
     122}
     123
     124void Value::replaceWithJump(FrequentedBlock target)
     125{
     126    replaceWithJump(owner, target);
     127}
     128
     129void Value::replaceWithOops()
     130{
     131    replaceWithOops(owner);
     132}
     133
     134void Value::replaceWith(Kind kind, Type type, BasicBlock* owner)
     135{
    120136    unsigned index = m_index;
    121     Origin origin = m_origin;
    122     BasicBlock* owner = this->owner;
    123     Type type = m_type;
    124137
    125138    this->~Value();
    126139
    127     new (this) Value(Phi, type, origin);
    128 
     140    new (this) Value(kind, type, m_origin);
     141
     142    this->m_index = index;
    129143    this->owner = owner;
     144}
     145
     146void Value::replaceWith(Kind kind, Type type, BasicBlock* owner, Value* value)
     147{
     148    unsigned index = m_index;
     149
     150    this->~Value();
     151
     152    new (this) Value(kind, type, m_origin, value);
     153
    130154    this->m_index = index;
    131 }
    132 
    133 void Value::replaceWithJump(BasicBlock* owner, FrequentedBlock target)
    134 {
    135     RELEASE_ASSERT(owner->last() == this);
    136    
    137     unsigned index = m_index;
    138     Origin origin = m_origin;
    139    
    140     this->~Value();
    141    
    142     new (this) Value(Jump, Void, origin);
    143    
    144155    this->owner = owner;
    145     this->m_index = index;
    146    
    147     owner->setSuccessors(target);
    148 }
    149 
    150 void Value::replaceWithOops(BasicBlock* owner)
    151 {
    152     RELEASE_ASSERT(owner->last() == this);
    153    
    154     unsigned index = m_index;
    155     Origin origin = m_origin;
    156    
    157     this->~Value();
    158    
    159     new (this) Value(Oops, Void, origin);
    160    
    161     this->owner = owner;
    162     this->m_index = index;
    163    
    164     owner->clearSuccessors();
    165 }
    166 
    167 void Value::replaceWithJump(FrequentedBlock target)
    168 {
    169     replaceWithJump(owner, target);
    170 }
    171 
    172 void Value::replaceWithOops()
    173 {
    174     replaceWithOops(owner);
    175156}
    176157
     
    204185    if (isConstant)
    205186        out.print(")");
    206 }
    207 
    208 Value* Value::cloneImpl() const
    209 {
    210     return new Value(*this);
    211187}
    212188
     
    459435Value* Value::invertedCompare(Procedure& proc) const
    460436{
    461     if (!numChildren())
     437    if (numChildren() != 2)
    462438        return nullptr;
    463439    if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type())) {
    464440        ASSERT(!kind().hasExtraBits());
    465         return proc.add<Value>(*invertedOpcode, type(), origin(), children());
     441        return proc.add<Value>(*invertedOpcode, type(), origin(), child(0), child(1));
    466442    }
    467443    return nullptr;
     
    497473    if (type() != Int32)
    498474        return false;
     475
    499476    switch (opcode()) {
    500477    case Const32:
  • trunk/Source/JavaScriptCore/b3/B3Value.h

    r231204 r244309  
    3939#include <wtf/CommaPrinter.h>
    4040#include <wtf/FastMalloc.h>
    41 #include <wtf/Noncopyable.h>
     41#include <wtf/IteratorRange.h>
    4242#include <wtf/StdLibExtras.h>
    4343#include <wtf/TriState.h>
     
    5454    WTF_MAKE_FAST_ALLOCATED;
    5555public:
    56     typedef Vector<Value*, 3> AdjacencyList;
    57 
    5856    static const char* const dumpPrefix;
    5957
     
    8381    void setOrigin(Origin origin) { m_origin = origin; }
    8482   
    85     Value*& child(unsigned index) { return m_children[index]; }
    86     Value* child(unsigned index) const { return m_children[index]; }
    87 
    88     Value*& lastChild() { return m_children.last(); }
    89     Value* lastChild() const { return m_children.last(); }
    90 
    91     unsigned numChildren() const { return m_children.size(); }
    92 
    9383    Type type() const { return m_type; }
    9484    void setType(Type type) { m_type = type; }
     
    9888    Width resultWidth() const { return widthForType(type()); }
    9989
    100     AdjacencyList& children() { return m_children; }
    101     const AdjacencyList& children() const { return m_children; }
     90    unsigned numChildren() const
     91    {
     92        if (m_numChildren == VarArgs)
     93            return childrenVector().size();
     94        return m_numChildren;
     95    }
     96   
     97    Value*& child(unsigned index)
     98    {
     99        ASSERT(index < numChildren());
     100        return m_numChildren == VarArgs ? childrenVector()[index] : childrenArray()[index];
     101    }
     102    Value* child(unsigned index) const
     103    {
     104        ASSERT(index < numChildren());
     105        return m_numChildren == VarArgs ? childrenVector()[index] : childrenArray()[index];
     106    }
     107   
     108    Value*& lastChild()
     109    {
     110        if (m_numChildren == VarArgs)
     111            return childrenVector().last();
     112        ASSERT(m_numChildren >= 1);
     113        return childrenArray()[m_numChildren - 1];
     114    }
     115    Value* lastChild() const
     116    {
     117        if (m_numChildren == VarArgs)
     118            return childrenVector().last();
     119        ASSERT(m_numChildren >= 1);
     120        return childrenArray()[m_numChildren - 1];
     121    }
     122
     123    WTF::IteratorRange<Value**> children()
     124    {
     125        if (m_numChildren == VarArgs) {
     126            Vector<Value*, 3>& vec = childrenVector();
     127            return WTF::makeIteratorRange(&*vec.begin(), &*vec.end());
     128        }
     129        Value** buffer = childrenArray();
     130        return {buffer, buffer + m_numChildren };
     131    }
     132    WTF::IteratorRange<Value* const*> children() const
     133    {
     134        if (m_numChildren == VarArgs) {
     135            const Vector<Value*, 3>& vec = childrenVector();
     136            return WTF::makeIteratorRange(&*vec.begin(), &*vec.end());
     137        }
     138        Value* const* buffer = childrenArray();
     139        return {buffer, buffer + m_numChildren };
     140    }
    102141
    103142    // If you want to replace all uses of this value with a different value, then replace this
     
    302341    > { };
    303342
    304 
    305343protected:
    306     virtual Value* cloneImpl() const;
    307    
     344    Value* cloneImpl() const;
     345
     346    void replaceWith(Kind, Type, BasicBlock*);
     347    void replaceWith(Kind, Type, BasicBlock*, Value*);
     348
    308349    virtual void dumpChildren(CommaPrinter&, PrintStream&) const;
    309350    virtual void dumpMeta(CommaPrinter&, PrintStream&) const;
    310351
     352    // The specific value of VarArgs does not matter, but the value of the others is assumed to match their meaning.
     353    enum NumChildren : uint8_t { Zero = 0, One = 1, Two = 2, Three = 3, VarArgs = 4};
     354
     355    char* childrenAlloc() { return bitwise_cast<char*>(this) + adjacencyListOffset(); }
     356    const char* childrenAlloc() const { return bitwise_cast<const char*>(this) + adjacencyListOffset(); }
     357    Vector<Value*, 3>& childrenVector()
     358    {
     359        ASSERT(m_numChildren == VarArgs);
     360        return *bitwise_cast<Vector<Value*, 3>*>(childrenAlloc());
     361    }
     362    const Vector<Value*, 3>& childrenVector() const
     363    {
     364        ASSERT(m_numChildren == VarArgs);
     365        return *bitwise_cast<Vector<Value*, 3> const*>(childrenAlloc());
     366    }
     367    Value** childrenArray()
     368    {
     369        ASSERT(m_numChildren != VarArgs);
     370        return bitwise_cast<Value**>(childrenAlloc());
     371    }
     372    Value* const* childrenArray() const
     373    {
     374        ASSERT(m_numChildren != VarArgs);
     375        return bitwise_cast<Value* const*>(childrenAlloc());
     376    }
     377
     378    template<typename... Arguments>
     379    static Opcode opcodeFromConstructor(Kind kind, Arguments...) { return kind.opcode(); }
     380    ALWAYS_INLINE static size_t adjacencyListSpace(Kind kind)
     381    {
     382        switch (kind.opcode()) {
     383        case FramePointer:
     384        case Nop:
     385        case Phi:
     386        case Jump:
     387        case Oops:
     388        case EntrySwitch:
     389        case ArgumentReg:
     390        case Const32:
     391        case Const64:
     392        case ConstFloat:
     393        case ConstDouble:
     394        case Fence:
     395        case SlotBase:
     396        case Get:
     397            return 0;
     398        case Return:
     399        case Identity:
     400        case Opaque:
     401        case Neg:
     402        case Clz:
     403        case Abs:
     404        case Ceil:
     405        case Floor:
     406        case Sqrt:
     407        case SExt8:
     408        case SExt16:
     409        case Trunc:
     410        case SExt32:
     411        case ZExt32:
     412        case FloatToDouble:
     413        case IToD:
     414        case DoubleToFloat:
     415        case IToF:
     416        case BitwiseCast:
     417        case Branch:
     418        case Depend:
     419        case Load8Z:
     420        case Load8S:
     421        case Load16Z:
     422        case Load16S:
     423        case Load:
     424        case Switch:
     425        case Upsilon:
     426        case Set:
     427        case WasmAddress:
     428        case WasmBoundsCheck:
     429            return sizeof(Value*);
     430        case Add:
     431        case Sub:
     432        case Mul:
     433        case Div:
     434        case UDiv:
     435        case Mod:
     436        case UMod:
     437        case BitAnd:
     438        case BitOr:
     439        case BitXor:
     440        case Shl:
     441        case SShr:
     442        case ZShr:
     443        case RotR:
     444        case RotL:
     445        case Equal:
     446        case NotEqual:
     447        case LessThan:
     448        case GreaterThan:
     449        case LessEqual:
     450        case GreaterEqual:
     451        case Above:
     452        case Below:
     453        case AboveEqual:
     454        case BelowEqual:
     455        case EqualOrUnordered:
     456        case AtomicXchgAdd:
     457        case AtomicXchgAnd:
     458        case AtomicXchgOr:
     459        case AtomicXchgSub:
     460        case AtomicXchgXor:
     461        case AtomicXchg:
     462        case Store8:
     463        case Store16:
     464        case Store:
     465            return 2 * sizeof(Value*);
     466        case Select:
     467        case AtomicWeakCAS:
     468        case AtomicStrongCAS:
     469            return 3 * sizeof(Value*);
     470        case CCall:
     471        case Check:
     472        case CheckAdd:
     473        case CheckSub:
     474        case CheckMul:
     475        case Patchpoint:
     476            return sizeof(Vector<Value*, 3>);
     477        default:
     478            break;
     479        }
     480        RELEASE_ASSERT_NOT_REACHED();
     481        return 0;
     482    }
     483
    311484private:
     485    static char* allocateSpace(Opcode opcode, size_t size)
     486    {
     487        size_t adjacencyListSpace = Value::adjacencyListSpace(opcode);
     488        // We must allocate enough space that replaceWithIdentity can work without buffer overflow.
     489        size_t allocIdentitySize = sizeof(Value) + sizeof(Value*);
     490        size_t allocSize = std::max(size + adjacencyListSpace, allocIdentitySize);
     491        return static_cast<char*>(WTF::fastMalloc(allocSize));
     492    }
     493
     494protected:
     495    template<typename ValueType, typename... Arguments>
     496    static ValueType* allocate(Arguments... arguments)
     497    {
     498        char* alloc = allocateSpace(ValueType::opcodeFromConstructor(arguments...), sizeof(ValueType));
     499        return new (alloc) ValueType(arguments...);
     500    }
     501    template<typename ValueType>
     502    static ValueType* allocate(const ValueType& valueToClone)
     503    {
     504        char* alloc = allocateSpace(valueToClone.opcode(), sizeof(ValueType));
     505        ValueType* result = new (alloc) ValueType(valueToClone);
     506        result->buildAdjacencyList(sizeof(ValueType), valueToClone);
     507        return result;
     508    }
     509
     510    // Protected so it will only be called from allocate above, possibly through the subclasses'copy constructors
     511    Value(const Value&) = default;
     512
     513    Value(Value&&) = delete;
     514    Value& operator=(const Value&) = delete;
     515    Value& operator=(Value&&) = delete;
     516   
     517    size_t adjacencyListOffset() const;
     518
    312519    friend class Procedure;
    313520    friend class SparseCollection<Value>;
    314521
     522private:
     523    template<typename... Arguments>
     524    void buildAdjacencyList(NumChildren numChildren, Arguments... arguments)
     525    {
     526        if (numChildren == VarArgs) {
     527            new (childrenAlloc()) Vector<Value*, 3> { arguments... };
     528            return;
     529        }
     530        ASSERT(numChildren == sizeof...(arguments));
     531        new (childrenAlloc()) Value*[sizeof...(arguments)] { arguments... };
     532    }
     533    void buildAdjacencyList(size_t offset, const Value& valueToClone)
     534    {
     535        switch (valueToClone.m_numChildren) {
     536        case VarArgs:
     537            new (bitwise_cast<char*>(this) + offset) Vector<Value*, 3> (valueToClone.childrenVector());
     538            break;
     539        case Three:
     540            bitwise_cast<Value**>(bitwise_cast<char*>(this) + offset)[2] = valueToClone.childrenArray()[2];
     541            FALLTHROUGH;
     542        case Two:
     543            bitwise_cast<Value**>(bitwise_cast<char*>(this) + offset)[1] = valueToClone.childrenArray()[1];
     544            FALLTHROUGH;
     545        case One:
     546            bitwise_cast<Value**>(bitwise_cast<char*>(this) + offset)[0] = valueToClone.childrenArray()[0];
     547            break;
     548        case Zero:
     549            break;
     550        }
     551    }
     552   
    315553    // Checks that this kind is valid for use with B3::Value.
    316     ALWAYS_INLINE static void checkKind(Kind kind, unsigned numArgs)
     554    ALWAYS_INLINE static NumChildren numChildrenForKind(Kind kind, unsigned numArgs)
    317555    {
    318556        switch (kind.opcode()) {
     
    325563            if (UNLIKELY(numArgs))
    326564                badKind(kind, numArgs);
    327             break;
     565            return Zero;
    328566        case Return:
    329567            if (UNLIKELY(numArgs > 1))
    330568                badKind(kind, numArgs);
    331             break;
     569            return numArgs ? One : Zero;
    332570        case Identity:
    333571        case Opaque:
     
    352590            if (UNLIKELY(numArgs != 1))
    353591                badKind(kind, numArgs);
    354             break;
     592            return One;
    355593        case Add:
    356594        case Sub:
     
    381619            if (UNLIKELY(numArgs != 2))
    382620                badKind(kind, numArgs);
    383             break;
     621            return Two;
    384622        case Select:
    385623            if (UNLIKELY(numArgs != 3))
    386624                badKind(kind, numArgs);
    387             break;
     625            return Three;
    388626        default:
    389627            badKind(kind, numArgs);
    390628            break;
    391629        }
     630        return VarArgs;
    392631    }
    393632
    394633protected:
    395634    enum CheckedOpcodeTag { CheckedOpcode };
    396 
    397     Value(const Value&) = default;
    398     Value& operator=(const Value&) = default;
    399635   
    400636    // Instantiate values via Procedure.
    401637    // This form requires specifying the type explicitly:
    402638    template<typename... Arguments>
    403     explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Value* firstChild, Arguments... arguments)
     639    explicit Value(CheckedOpcodeTag, Kind kind, Type type, NumChildren numChildren, Origin origin, Value* firstChild, Arguments... arguments)
    404640        : m_kind(kind)
    405641        , m_type(type)
     642        , m_numChildren(numChildren)
    406643        , m_origin(origin)
    407         , m_children{ firstChild, arguments... }
    408     {
     644    {
     645        buildAdjacencyList(numChildren, firstChild, arguments...);
    409646    }
    410647    // This form is for specifying the type explicitly when the opcode has no children:
    411     explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin)
     648    explicit Value(CheckedOpcodeTag, Kind kind, Type type, NumChildren numChildren, Origin origin)
    412649        : m_kind(kind)
    413650        , m_type(type)
     651        , m_numChildren(numChildren)
    414652        , m_origin(origin)
    415653    {
     654        buildAdjacencyList(numChildren);
     655    }
     656    // This form is for those opcodes that can infer their type from the opcode alone, and that don't
     657    // take any arguments:
     658    explicit Value(CheckedOpcodeTag, Kind kind, NumChildren numChildren, Origin origin)
     659        : m_kind(kind)
     660        , m_type(typeFor(kind, nullptr))
     661        , m_numChildren(numChildren)
     662        , m_origin(origin)
     663    {
     664        buildAdjacencyList(numChildren);
    416665    }
    417666    // This form is for those opcodes that can infer their type from the opcode and first child:
    418     template<typename... Arguments>
    419     explicit Value(CheckedOpcodeTag, Kind kind, Origin origin, Value* firstChild)
     667    explicit Value(CheckedOpcodeTag, Kind kind, NumChildren numChildren, Origin origin, Value* firstChild)
    420668        : m_kind(kind)
    421669        , m_type(typeFor(kind, firstChild))
     670        , m_numChildren(numChildren)
    422671        , m_origin(origin)
    423         , m_children{ firstChild }
    424     {
     672    {
     673        buildAdjacencyList(numChildren, firstChild);
    425674    }
    426675    // This form is for those opcodes that can infer their type from the opcode and first and second child:
    427676    template<typename... Arguments>
    428     explicit Value(CheckedOpcodeTag, Kind kind, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
     677    explicit Value(CheckedOpcodeTag, Kind kind, NumChildren numChildren, Origin origin, Value* firstChild, Value* secondChild, Arguments... arguments)
    429678        : m_kind(kind)
    430679        , m_type(typeFor(kind, firstChild, secondChild))
     680        , m_numChildren(numChildren)
    431681        , m_origin(origin)
    432         , m_children{ firstChild, secondChild, arguments... }
    433     {
    434     }
    435     // This form is for those opcodes that can infer their type from the opcode alone, and that don't
    436     // take any arguments:
    437     explicit Value(CheckedOpcodeTag, Kind kind, Origin origin)
    438         : m_kind(kind)
    439         , m_type(typeFor(kind, nullptr))
    440         , m_origin(origin)
    441     {
    442     }
    443     // Use this form for varargs.
    444     explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, const AdjacencyList& children)
    445         : m_kind(kind)
    446         , m_type(type)
    447         , m_origin(origin)
    448         , m_children(children)
    449     {
    450     }
    451     explicit Value(CheckedOpcodeTag, Kind kind, Type type, Origin origin, AdjacencyList&& children)
    452         : m_kind(kind)
    453         , m_type(type)
    454         , m_origin(origin)
    455         , m_children(WTFMove(children))
    456     {
     682    {
     683        buildAdjacencyList(numChildren, firstChild, secondChild, arguments...);
    457684    }
    458685
    459686    // This is the constructor you end up actually calling, if you're instantiating Value
    460687    // directly.
     688    explicit Value(Kind kind, Type type, Origin origin)
     689        : Value(CheckedOpcode, kind, type, Zero, origin)
     690    {
     691        RELEASE_ASSERT(numChildrenForKind(kind, 0) == Zero);
     692    }
     693    // We explicitly convert the extra arguments to Value* (they may be pointers to some subclasses of Value) to limit template explosion
    461694    template<typename... Arguments>
    462         explicit Value(Kind kind, Type type, Origin origin)
    463         : Value(CheckedOpcode, kind, type, origin)
    464     {
    465         checkKind(kind, 0);
     695    explicit Value(Kind kind, Origin origin, Arguments... arguments)
     696        : Value(CheckedOpcode, kind, numChildrenForKind(kind, sizeof...(arguments)), origin, static_cast<Value*>(arguments)...)
     697    {
    466698    }
    467699    template<typename... Arguments>
    468         explicit Value(Kind kind, Type type, Origin origin, Value* firstChild, Arguments&&... arguments)
    469         : Value(CheckedOpcode, kind, type, origin, firstChild, std::forward<Arguments>(arguments)...)
    470     {
    471         checkKind(kind, 1 + sizeof...(arguments));
    472     }
    473     template<typename... Arguments>
    474         explicit Value(Kind kind, Type type, Origin origin, const AdjacencyList& children)
    475         : Value(CheckedOpcode, kind, type, origin, children)
    476     {
    477         checkKind(kind, children.size());
    478     }
    479     template<typename... Arguments>
    480         explicit Value(Kind kind, Type type, Origin origin, AdjacencyList&& children)
    481         : Value(CheckedOpcode, kind, type, origin, WTFMove(children))
    482     {
    483         checkKind(kind, m_children.size());
    484     }
    485     template<typename... Arguments>
    486         explicit Value(Kind kind, Origin origin, Arguments&&... arguments)
    487         : Value(CheckedOpcode, kind, origin, std::forward<Arguments>(arguments)...)
    488     {
    489         checkKind(kind, sizeof...(arguments));
     700    explicit Value(Kind kind, Type type, Origin origin, Value* firstChild, Arguments... arguments)
     701        : Value(CheckedOpcode, kind, type, numChildrenForKind(kind, 1 + sizeof...(arguments)), origin, firstChild, static_cast<Value*>(arguments)...)
     702    {
    490703    }
    491704
    492705private:
    493706    friend class CheckValue; // CheckValue::convertToAdd() modifies m_kind.
    494    
     707
    495708    static Type typeFor(Kind, Value* firstChild, Value* secondChild = nullptr);
    496709
    497     // This group of fields is arranged to fit in 64 bits.
     710    // m_index to m_numChildren are arranged to fit in 64 bits.
    498711protected:
    499712    unsigned m_index { UINT_MAX };
     
    501714    Kind m_kind;
    502715    Type m_type;
    503    
     716protected:
     717    NumChildren m_numChildren;
     718private:
    504719    Origin m_origin;
    505     AdjacencyList m_children;
    506720
    507721    NO_RETURN_DUE_TO_CRASH static void badKind(Kind, unsigned);
     
    519733    }
    520734
    521     void dump(PrintStream& out) const
    522     {
    523         if (m_value)
    524             m_value->deepDump(m_proc, out);
    525         else
    526             out.print("<null>");
    527     }
     735    void dump(PrintStream& out) const;
    528736
    529737private:
     
    541749}
    542750
     751// The following macros are designed for subclasses of B3::Value to use.
     752// They are never required for correctness, but can improve the performance of child/lastChild/numChildren/children methods,
     753// for users that already know the specific subclass of Value they are manipulating.
     754// 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:
     755// - B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN: always 0 children (e.g. Const32Value)
     756// - B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(n): always n children, with n in {1, 2, 3} (e.g. UpsilonValue, with n = 1)
     757// - 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)
     758// - B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN: always a varargs (e.g. CCallValue)
     759// The second set is only to be used by classes that we know are not further subclassed by anyone adding fields,
     760// as they hardcode the offset of the children array/vector (which is equal to the size of the object).
     761// - B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     762// - B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN
     763#define B3_SPECIALIZE_VALUE_FOR_NO_CHILDREN \
     764    unsigned numChildren() const { return 0; } \
     765    WTF::IteratorRange<Value**> children() { return {nullptr, nullptr}; } \
     766    WTF::IteratorRange<Value* const*> children() const { return { nullptr, nullptr}; }
     767
     768#define B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(n) \
     769public: \
     770    unsigned numChildren() const { return n; } \
     771    Value*& child(unsigned index) \
     772    { \
     773        ASSERT(index <= n); \
     774        return childrenArray()[index]; \
     775    } \
     776    Value* child(unsigned index) const \
     777    { \
     778        ASSERT(index <= n); \
     779        return childrenArray()[index]; \
     780    } \
     781    Value*& lastChild() \
     782    { \
     783        return childrenArray()[n - 1]; \
     784    } \
     785    Value* lastChild() const \
     786    { \
     787        return childrenArray()[n - 1]; \
     788    } \
     789    WTF::IteratorRange<Value**> children() \
     790    { \
     791        Value** buffer = childrenArray(); \
     792        return {buffer, buffer + n }; \
     793    } \
     794    WTF::IteratorRange<Value* const*> children() const \
     795    { \
     796        Value* const* buffer = childrenArray(); \
     797        return {buffer, buffer + n }; \
     798    } \
     799
     800#define B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN \
     801public: \
     802    unsigned numChildren() const { return m_numChildren; } \
     803    Value*& child(unsigned index) { return childrenArray()[index]; } \
     804    Value* child(unsigned index) const { return childrenArray()[index]; } \
     805    Value*& lastChild() { return childrenArray()[numChildren() - 1]; } \
     806    Value* lastChild() const { return childrenArray()[numChildren() - 1]; } \
     807    WTF::IteratorRange<Value**> children() \
     808    { \
     809        Value** buffer = childrenArray(); \
     810        return {buffer, buffer + numChildren() }; \
     811    } \
     812    WTF::IteratorRange<Value* const*> children() const \
     813    { \
     814        Value* const* buffer = childrenArray(); \
     815        return {buffer, buffer + numChildren() }; \
     816    } \
     817
     818#define B3_SPECIALIZE_VALUE_FOR_VARARGS_CHILDREN \
     819public: \
     820    unsigned numChildren() const { return childrenVector().size(); } \
     821    Value*& child(unsigned index) { return childrenVector()[index]; } \
     822    Value* child(unsigned index) const { return childrenVector()[index]; } \
     823    Value*& lastChild() { return childrenVector().last(); } \
     824    Value* lastChild() const { return childrenVector().last(); } \
     825    WTF::IteratorRange<Value**> children() \
     826    { \
     827        Vector<Value*, 3>& vec = childrenVector(); \
     828        return WTF::makeIteratorRange(&*vec.begin(), &*vec.end()); \
     829    } \
     830    WTF::IteratorRange<Value* const*> children() const \
     831    { \
     832        const Vector<Value*, 3>& vec = childrenVector(); \
     833        return WTF::makeIteratorRange(&*vec.begin(), &*vec.end()); \
     834    } \
     835
     836// Only use this for classes with no subclass that add new fields (as it uses sizeof(*this))
     837// Also there is no point in applying this to classes with no children, as they don't have a children array to access.
     838#define B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN \
     839private: \
     840    Value** childrenArray() \
     841    { \
     842        return bitwise_cast<Value**>(bitwise_cast<char*>(this) + sizeof(*this)); \
     843    } \
     844    Value* const* childrenArray() const \
     845    { \
     846        return bitwise_cast<Value* const*>(bitwise_cast<char const*>(this) + sizeof(*this)); \
     847    }
     848
     849// Only use this for classes with no subclass that add new fields (as it uses sizeof(*this))
     850#define B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_VARARGS_CHILDREN \
     851private: \
     852    Vector<Value*, 3>& childrenVector() \
     853    { \
     854        return *bitwise_cast<Vector<Value*, 3>*>(bitwise_cast<char*>(this) + sizeof(*this)); \
     855    } \
     856    const Vector<Value*, 3>& childrenVector() const \
     857    { \
     858        return *bitwise_cast<Vector<Value*, 3> const*>(bitwise_cast<char const*>(this) + sizeof(*this)); \
     859    } \
     860
    543861} } // namespace JSC::B3
    544862
  • trunk/Source/JavaScriptCore/b3/B3ValueInlines.h

    r207039 r244309  
    2828#if ENABLE(B3_JIT)
    2929
     30#include "B3ArgumentRegValue.h"
     31#include "B3AtomicValue.h"
     32#include "B3CCallValue.h"
    3033#include "B3CheckValue.h"
    3134#include "B3Const32Value.h"
     
    3336#include "B3ConstDoubleValue.h"
    3437#include "B3ConstFloatValue.h"
     38#include "B3FenceValue.h"
     39#include "B3MemoryValue.h"
    3540#include "B3PatchpointValue.h"
    3641#include "B3PhiChildren.h"
    3742#include "B3Procedure.h"
     43#include "B3SlotBaseValue.h"
     44#include "B3SwitchValue.h"
     45#include "B3UpsilonValue.h"
    3846#include "B3Value.h"
     47#include "B3VariableValue.h"
     48#include "B3WasmAddressValue.h"
     49#include "B3WasmBoundsCheckValue.h"
    3950#include <wtf/GraphNodeWorklist.h>
    4051
    4152namespace JSC { namespace B3 {
     53
     54#define DISPATCH_ON_KIND(MACRO) \
     55    switch (kind().opcode()) { \
     56    case FramePointer: \
     57    case Nop: \
     58    case Phi: \
     59    case Jump: \
     60    case Oops: \
     61    case EntrySwitch: \
     62    case Return: \
     63    case Identity: \
     64    case Opaque: \
     65    case Neg: \
     66    case Clz: \
     67    case Abs: \
     68    case Ceil: \
     69    case Floor: \
     70    case Sqrt: \
     71    case SExt8: \
     72    case SExt16: \
     73    case Trunc: \
     74    case SExt32: \
     75    case ZExt32: \
     76    case FloatToDouble: \
     77    case IToD: \
     78    case DoubleToFloat: \
     79    case IToF: \
     80    case BitwiseCast: \
     81    case Branch: \
     82    case Depend: \
     83    case Add: \
     84    case Sub: \
     85    case Mul: \
     86    case Div: \
     87    case UDiv: \
     88    case Mod: \
     89    case UMod: \
     90    case BitAnd: \
     91    case BitOr: \
     92    case BitXor: \
     93    case Shl: \
     94    case SShr: \
     95    case ZShr: \
     96    case RotR: \
     97    case RotL: \
     98    case Equal: \
     99    case NotEqual: \
     100    case LessThan: \
     101    case GreaterThan: \
     102    case LessEqual: \
     103    case GreaterEqual: \
     104    case Above: \
     105    case Below: \
     106    case AboveEqual: \
     107    case BelowEqual: \
     108    case EqualOrUnordered: \
     109    case Select: \
     110        return MACRO(Value); \
     111    case ArgumentReg: \
     112        return MACRO(ArgumentRegValue); \
     113    case Const32: \
     114        return MACRO(Const32Value); \
     115    case Const64: \
     116        return MACRO(Const64Value); \
     117    case ConstFloat: \
     118        return MACRO(ConstFloatValue); \
     119    case ConstDouble: \
     120        return MACRO(ConstDoubleValue); \
     121    case Fence: \
     122        return MACRO(FenceValue); \
     123    case SlotBase: \
     124        return MACRO(SlotBaseValue); \
     125    case Get: \
     126    case Set: \
     127        return MACRO(VariableValue); \
     128    case Load8Z: \
     129    case Load8S: \
     130    case Load16Z: \
     131    case Load16S: \
     132    case Load: \
     133    case Store8: \
     134    case Store16: \
     135    case Store: \
     136        return MACRO(MemoryValue); \
     137    case Switch: \
     138        return MACRO(SwitchValue); \
     139    case Upsilon: \
     140        return MACRO(UpsilonValue); \
     141    case WasmAddress: \
     142        return MACRO(WasmAddressValue); \
     143    case WasmBoundsCheck: \
     144        return MACRO(WasmBoundsCheckValue); \
     145    case AtomicXchgAdd: \
     146    case AtomicXchgAnd: \
     147    case AtomicXchgOr: \
     148    case AtomicXchgSub: \
     149    case AtomicXchgXor: \
     150    case AtomicXchg: \
     151    case AtomicWeakCAS: \
     152    case AtomicStrongCAS: \
     153        return MACRO(AtomicValue); \
     154    case CCall: \
     155        return MACRO(CCallValue); \
     156    case Check: \
     157    case CheckAdd: \
     158    case CheckSub: \
     159    case CheckMul: \
     160        return MACRO(CheckValue); \
     161    case Patchpoint: \
     162        return MACRO(PatchpointValue); \
     163    default: \
     164        RELEASE_ASSERT_NOT_REACHED(); \
     165    }
     166
     167ALWAYS_INLINE size_t Value::adjacencyListOffset() const
     168{
     169#define VALUE_TYPE_SIZE(ValueType) sizeof(ValueType)
     170    DISPATCH_ON_KIND(VALUE_TYPE_SIZE);
     171#undef VALUE_TYPE_SIZE
     172}
     173
     174ALWAYS_INLINE Value* Value::cloneImpl() const
     175{
     176#define VALUE_TYPE_CLONE(ValueType) allocate<ValueType>(*static_cast<const ValueType*>(this))
     177    DISPATCH_ON_KIND(VALUE_TYPE_CLONE);
     178#undef VALUE_TYPE_CLONE
     179}
    42180
    43181template<typename BottomProvider>
  • trunk/Source/JavaScriptCore/b3/B3VariableValue.cpp

    r206595 r244309  
    4242}
    4343
    44 Value* VariableValue::cloneImpl() const
    45 {
    46     return new VariableValue(*this);
    47 }
    48 
    4944VariableValue::VariableValue(Kind kind, Origin origin, Variable* variable, Value* value)
    50     : Value(CheckedOpcode, kind, Void, origin, value)
     45    : Value(CheckedOpcode, kind, Void, One, origin, value)
    5146    , m_variable(variable)
    5247{
     
    5550
    5651VariableValue::VariableValue(Kind kind, Origin origin, Variable* variable)
    57     : Value(CheckedOpcode, kind, variable->type(), origin)
     52    : Value(CheckedOpcode, kind, variable->type(), Zero, origin)
    5853    , m_variable(variable)
    5954{
  • trunk/Source/JavaScriptCore/b3/B3VariableValue.h

    r206595 r244309  
    4242    Variable* variable() const { return m_variable; }
    4343
     44    B3_SPECIALIZE_VALUE_FOR_NON_VARARGS_CHILDREN
     45    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     46
    4447protected:
    4548    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    4649
    47     Value* cloneImpl() const override;
    48 
    4950private:
    5051    friend class Procedure;
     52    friend class Value;
    5153
    5254    // Use this for Set.
  • trunk/Source/JavaScriptCore/b3/B3WasmAddressValue.cpp

    r207360 r244309  
    4040}
    4141
    42 Value* WasmAddressValue::cloneImpl() const
    43 {
    44     return new WasmAddressValue(*this);
    45 }
    46 
    4742WasmAddressValue::WasmAddressValue(Origin origin, Value* value, GPRReg pinnedGPR)
    48     : Value(CheckedOpcode, WasmAddress, Int64, origin, value)
     43    : Value(CheckedOpcode, WasmAddress, Int64, One, origin, value)
    4944    , m_pinnedGPR(pinnedGPR)
    5045{
  • trunk/Source/JavaScriptCore/b3/B3WasmAddressValue.h

    r212970 r244309  
    4141    GPRReg pinnedGPR() const { return m_pinnedGPR; }
    4242
     43    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
     44    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     45
    4346protected:
    4447    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    4548
    46     Value* cloneImpl() const override;
    47 
    4849private:
    4950    friend class Procedure;
     51    friend class Value;
    5052
     53    static Opcode opcodeFromConstructor(Origin, Value*, GPRReg) { return WasmAddress; }
    5154    WasmAddressValue(Origin, Value*, GPRReg);
    5255
  • trunk/Source/JavaScriptCore/b3/B3WasmBoundsCheckValue.cpp

    r230144 r244309  
    3737
    3838WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, GPRReg pinnedSize, Value* ptr, unsigned offset)
    39     : Value(CheckedOpcode, WasmBoundsCheck, origin, ptr)
     39    : Value(CheckedOpcode, WasmBoundsCheck, One, origin, ptr)
    4040    , m_offset(offset)
    4141    , m_boundsType(Type::Pinned)
     
    4545
    4646WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, Value* ptr, unsigned offset, size_t maximum)
    47     : Value(CheckedOpcode, WasmBoundsCheck, origin, ptr)
     47    : Value(CheckedOpcode, WasmBoundsCheck, One, origin, ptr)
    4848    , m_offset(offset)
    4949    , m_boundsType(Type::Maximum)
     
    5454#endif
    5555    m_bounds.maximum = maximum;
    56 }
    57 
    58 Value* WasmBoundsCheckValue::cloneImpl() const
    59 {
    60     return new WasmBoundsCheckValue(*this);
    6156}
    6257
  • trunk/Source/JavaScriptCore/b3/B3WasmBoundsCheckValue.h

    r230144 r244309  
    3535class WasmBoundsCheckValue : public Value {
    3636public:
    37     static bool accepts(Kind kind)
    38     {
    39         switch (kind.opcode()) {
    40         case WasmBoundsCheck:
    41             return true;
    42         default:
    43             return false;
    44         }
    45     }
     37    static bool accepts(Kind kind) { return kind == WasmBoundsCheck; }
    4638   
    4739    ~WasmBoundsCheckValue();
     
    6153    Bounds bounds() const { return m_bounds; }
    6254
     55    B3_SPECIALIZE_VALUE_FOR_FIXED_CHILDREN(1)
     56    B3_SPECIALIZE_VALUE_FOR_FINAL_SIZE_FIXED_CHILDREN
     57
    6358protected:
    6459    void dumpMeta(CommaPrinter&, PrintStream&) const override;
    6560
    66     Value* cloneImpl() const override;
    67 
    6861private:
    6962    friend class Procedure;
     63    friend class Value;
    7064
     65    static Opcode opcodeFromConstructor(Origin, GPRReg, Value*, unsigned) { return WasmBoundsCheck; }
    7166    JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, GPRReg pinnedGPR, Value* ptr, unsigned offset);
     67
     68    static Opcode opcodeFromConstructor(Origin, Value*, unsigned, size_t) { return WasmBoundsCheck; }
    7269    JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, Value* ptr, unsigned offset, size_t maximum);
    7370
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r243851 r244309  
    1096110961        proc, Int32, Origin(),
    1096210962        root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaArguments, B3CCallPtrTag)));
    10963     call->children().appendVector(args);
     10963    call->appendArgs(args);
    1096410964   
    1096510965    root->appendNewControlValue(proc, Return, Origin(), call);
     
    1098710987        proc, Int64, Origin(),
    1098810988        root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaArguments2, B3CCallPtrTag)));
    10989     call->children().appendVector(args);
     10989    call->appendArgs(args);
    1099010990   
    1099110991    root->appendNewControlValue(proc, Return, Origin(), call);
     
    1100911009        proc, Int32, Origin(),
    1101011010        root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaArguments3, B3CCallPtrTag)));
    11011     call->children().appendVector(args);
     11011    call->appendArgs(args);
    1101211012   
    1101311013    root->appendNewControlValue(proc, Return, Origin(), call);
     
    1110911109        proc, Double, Origin(),
    1111011110        root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaDoubleArguments, B3CCallPtrTag)));
    11111     call->children().appendVector(args);
     11111    call->appendArgs(args);
    1111211112   
    1111311113    root->appendNewControlValue(proc, Return, Origin(), call);
     
    1113311133        proc, Float, Origin(),
    1113411134        root->appendNew<ConstPtrValue>(proc, Origin(), tagCFunctionPtr<void*>(functionWithHellaFloatArguments, B3CCallPtrTag)));
    11135     call->children().appendVector(args);
     11135    call->appendArgs(args);
    1113611136   
    1113711137    root->appendNewControlValue(proc, Return, Origin(), call);
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.h

    r242123 r244309  
    381381    {
    382382        B3::CCallValue* result = m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function);
    383         result->children().appendVector(vector);
     383        result->appendArgs(vector);
    384384        return result;
    385385    }
Note: See TracChangeset for help on using the changeset viewer.