Ignore:
Timestamp:
Apr 15, 2019, 4:53:23 PM (6 years ago)
Author:
[email protected]
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):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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:
Note: See TracChangeset for help on using the changeset viewer.