Changeset 215407 in webkit


Ignore:
Timestamp:
Apr 17, 2017 1:24:48 AM (7 years ago)
Author:
jfbastien@apple.com
Message:

B3: don't allow unsigned offsets in Value
https://bugs.webkit.org/show_bug.cgi?id=170692

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

MemoryValue and similar B3 opcode classes always expects a signed
offset. Giving it an out-of-bounds unsigned offset causes
implementation-defined behavior, which can cause badness as I just
fixed in WebAssembly. This patch makes it impossible to create a
Value opcodes with an unsigned value, or with an overly-large
value.

  • b3/B3AtomicValue.cpp:

(JSC::B3::AtomicValue::AtomicValue):

  • b3/B3AtomicValue.h:
  • b3/B3Common.h:

(JSC::B3::isRepresentableAs):

  • b3/B3EliminateCommonSubexpressions.cpp:
  • b3/B3LowerToAir.cpp:

(JSC::B3::Air::LowerToAir::scaleForShl):
(JSC::B3::Air::LowerToAir::effectiveAddr):
(JSC::B3::Air::LowerToAir::addr):
(JSC::B3::Air::LowerToAir::tryAppendLea):

  • b3/B3MemoryValue.cpp:

(JSC::B3::MemoryValue::isLegalOffsetImpl):
(JSC::B3::MemoryValue::MemoryValue):

  • b3/B3MemoryValue.h:
  • b3/B3MemoryValueInlines.h:

(JSC::B3::MemoryValue::isLegalOffsetImpl):

  • b3/B3MoveConstants.cpp:
  • b3/B3ReduceStrength.cpp:
  • b3/B3StackmapSpecial.cpp:

(JSC::B3::StackmapSpecial::repForArg):

  • b3/B3Value.h:
  • b3/air/AirArg.cpp:

(JSC::B3::Air::Arg::stackAddrImpl):

  • b3/air/AirArg.h:

(JSC::B3::Air::Arg::addr):
(JSC::B3::Air::Arg::stack):
(JSC::B3::Air::Arg::callArg):
(JSC::B3::Air::Arg::stackAddr):
(JSC::B3::Air::Arg::index):
(JSC::B3::Air::Arg::offset):
(JSC::B3::Air::Arg::isValidAddrForm):
(JSC::B3::Air::Arg::isValidIndexForm):
(JSC::B3::Air::Arg::asTrustedImm32):
(JSC::B3::Air::Arg::asAddress):
(JSC::B3::Air::Arg::asBaseIndex):

  • b3/air/AirLowerStackArgs.cpp:

(JSC::B3::Air::lowerStackArgs):

  • b3/testb3.cpp:

(JSC::B3::testMulArgStore):
(JSC::B3::testStore32):
(JSC::B3::testStoreConstant):
(JSC::B3::testStoreConstantPtr):
(JSC::B3::testStoreAddLoad32):
(JSC::B3::testStoreAddLoadImm32):
(JSC::B3::testStoreAddLoad8):
(JSC::B3::testStoreAddLoadImm8):
(JSC::B3::testStoreAddLoad16):
(JSC::B3::testStoreAddLoadImm16):
(JSC::B3::testStoreAddLoad64):
(JSC::B3::testStoreAddLoadImm64):
(JSC::B3::testStoreAddLoad32Index):
(JSC::B3::testStoreAddLoadImm32Index):
(JSC::B3::testStoreAddLoad64Index):
(JSC::B3::testStoreAddLoadImm64Index):
(JSC::B3::testStoreSubLoad):
(JSC::B3::testStoreAddLoadInterference):
(JSC::B3::testStoreAddAndLoad):
(JSC::B3::testStoreNegLoad32):
(JSC::B3::testStoreNegLoadPtr):
(JSC::B3::testLoadOffset):
(JSC::B3::testLoadOffsetNotConstant):
(JSC::B3::testLoadOffsetUsingAdd):
(JSC::B3::testLoadOffsetUsingAddInterference):
(JSC::B3::testLoadOffsetUsingAddNotConstant):
(JSC::B3::testStoreLoadStackSlot):
(JSC::B3::testLoad):
(JSC::B3::testInterpreter):
(JSC::B3::testTrappingStore):
(JSC::B3::testTrappingLoadAddStore):
(JSC::B3::testWasmAddress):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::fixupPointerPlusOffset):
(JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::B3IRGenerator::emitLoadOp):
(JSC::Wasm::B3IRGenerator::emitStoreOp):

Source/WTF:

Add C++17's std::conjunction type trait, except for Microsoft VS
2015 update 2 and later because it adds the logical operator type
traits, event when C++ is pre-2017:
https://blogs.msdn.microsoft.com/vcblog/2016/01/22/vs-2015-update-2s-stl-is-c17-so-far-feature-complete/

  • wtf/StdLibExtras.h:
Location:
trunk/Source
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r215405 r215407  
     12017-04-17  JF Bastien  <jfbastien@apple.com>
     2
     3        B3: don't allow unsigned offsets in Value
     4        https://bugs.webkit.org/show_bug.cgi?id=170692
     5
     6        Reviewed by Filip Pizlo.
     7
     8        MemoryValue and similar B3 opcode classes always expects a signed
     9        offset. Giving it an out-of-bounds unsigned offset causes
     10        implementation-defined behavior, which can cause badness as I just
     11        fixed in WebAssembly.  This patch makes it impossible to create a
     12        Value opcodes with an unsigned value, or with an overly-large
     13        value.
     14
     15        * b3/B3AtomicValue.cpp:
     16        (JSC::B3::AtomicValue::AtomicValue):
     17        * b3/B3AtomicValue.h:
     18        * b3/B3Common.h:
     19        (JSC::B3::isRepresentableAs):
     20        * b3/B3EliminateCommonSubexpressions.cpp:
     21        * b3/B3LowerToAir.cpp:
     22        (JSC::B3::Air::LowerToAir::scaleForShl):
     23        (JSC::B3::Air::LowerToAir::effectiveAddr):
     24        (JSC::B3::Air::LowerToAir::addr):
     25        (JSC::B3::Air::LowerToAir::tryAppendLea):
     26        * b3/B3MemoryValue.cpp:
     27        (JSC::B3::MemoryValue::isLegalOffsetImpl):
     28        (JSC::B3::MemoryValue::MemoryValue):
     29        * b3/B3MemoryValue.h:
     30        * b3/B3MemoryValueInlines.h:
     31        (JSC::B3::MemoryValue::isLegalOffsetImpl):
     32        * b3/B3MoveConstants.cpp:
     33        * b3/B3ReduceStrength.cpp:
     34        * b3/B3StackmapSpecial.cpp:
     35        (JSC::B3::StackmapSpecial::repForArg):
     36        * b3/B3Value.h:
     37        * b3/air/AirArg.cpp:
     38        (JSC::B3::Air::Arg::stackAddrImpl):
     39        * b3/air/AirArg.h:
     40        (JSC::B3::Air::Arg::addr):
     41        (JSC::B3::Air::Arg::stack):
     42        (JSC::B3::Air::Arg::callArg):
     43        (JSC::B3::Air::Arg::stackAddr):
     44        (JSC::B3::Air::Arg::index):
     45        (JSC::B3::Air::Arg::offset):
     46        (JSC::B3::Air::Arg::isValidAddrForm):
     47        (JSC::B3::Air::Arg::isValidIndexForm):
     48        (JSC::B3::Air::Arg::asTrustedImm32):
     49        (JSC::B3::Air::Arg::asAddress):
     50        (JSC::B3::Air::Arg::asBaseIndex):
     51        * b3/air/AirLowerStackArgs.cpp:
     52        (JSC::B3::Air::lowerStackArgs):
     53        * b3/testb3.cpp:
     54        (JSC::B3::testMulArgStore):
     55        (JSC::B3::testStore32):
     56        (JSC::B3::testStoreConstant):
     57        (JSC::B3::testStoreConstantPtr):
     58        (JSC::B3::testStoreAddLoad32):
     59        (JSC::B3::testStoreAddLoadImm32):
     60        (JSC::B3::testStoreAddLoad8):
     61        (JSC::B3::testStoreAddLoadImm8):
     62        (JSC::B3::testStoreAddLoad16):
     63        (JSC::B3::testStoreAddLoadImm16):
     64        (JSC::B3::testStoreAddLoad64):
     65        (JSC::B3::testStoreAddLoadImm64):
     66        (JSC::B3::testStoreAddLoad32Index):
     67        (JSC::B3::testStoreAddLoadImm32Index):
     68        (JSC::B3::testStoreAddLoad64Index):
     69        (JSC::B3::testStoreAddLoadImm64Index):
     70        (JSC::B3::testStoreSubLoad):
     71        (JSC::B3::testStoreAddLoadInterference):
     72        (JSC::B3::testStoreAddAndLoad):
     73        (JSC::B3::testStoreNegLoad32):
     74        (JSC::B3::testStoreNegLoadPtr):
     75        (JSC::B3::testLoadOffset):
     76        (JSC::B3::testLoadOffsetNotConstant):
     77        (JSC::B3::testLoadOffsetUsingAdd):
     78        (JSC::B3::testLoadOffsetUsingAddInterference):
     79        (JSC::B3::testLoadOffsetUsingAddNotConstant):
     80        (JSC::B3::testStoreLoadStackSlot):
     81        (JSC::B3::testLoad):
     82        (JSC::B3::testInterpreter):
     83        (JSC::B3::testTrappingStore):
     84        (JSC::B3::testTrappingLoadAddStore):
     85        (JSC::B3::testWasmAddress):
     86        * wasm/WasmB3IRGenerator.cpp:
     87        (JSC::Wasm::B3IRGenerator::fixupPointerPlusOffset):
     88        (JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
     89        (JSC::Wasm::B3IRGenerator::emitLoadOp):
     90        (JSC::Wasm::B3IRGenerator::emitStoreOp):
     91
    1922017-04-16  Joseph Pecoraro  <pecoraro@apple.com>
    293
  • trunk/Source/JavaScriptCore/b3/B3AtomicValue.cpp

    r213714 r215407  
    4747}
    4848
    49 AtomicValue::AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
     49AtomicValue::AtomicValue(AtomicValue::AtomicValueRMW, Kind kind, Origin origin, Width width, Value* operand, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    5050    : MemoryValue(CheckedOpcode, kind, operand->type(), origin, offset, range, fenceRange, operand, pointer)
    5151    , m_width(width)
     
    6666}
    6767
    68 AtomicValue::AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
     68AtomicValue::AtomicValue(AtomicValue::AtomicValueCAS, Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    6969    : MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), origin, offset, range, fenceRange, expectedValue, newValue, pointer)
    7070    , m_width(width)
  • trunk/Source/JavaScriptCore/b3/B3AtomicValue.h

    r213714 r215407  
    5353private:
    5454    friend class Procedure;
    55    
    56     AtomicValue(Kind, Origin, Width, Value* operand, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
    57    
    58     AtomicValue(Kind, Origin, Width, Value* expectedValue, Value* newValue, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
    59    
     55
     56    enum AtomicValueRMW { AtomicValueRMWTag };
     57    enum AtomicValueCAS { AtomicValueCASTag };
     58
     59    AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer)
     60        : AtomicValue(kind, origin, width, operand, pointer, 0)
     61    {
     62    }
     63    template<typename Int,
     64        typename = typename std::enable_if<std::is_integral<Int>::value>::type,
     65        typename = typename std::enable_if<std::is_signed<Int>::value>::type,
     66        typename = typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
     67    >
     68    AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top())
     69        : AtomicValue(AtomicValueRMWTag, kind, origin, width, operand, pointer, offset, range, fenceRange)
     70    {
     71    }
     72
     73    AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer)
     74        : AtomicValue(kind, origin, width, expectedValue, newValue, pointer, 0)
     75    {
     76    }
     77    template<typename Int,
     78        typename = typename std::enable_if<std::is_integral<Int>::value>::type,
     79        typename = typename std::enable_if<std::is_signed<Int>::value>::type,
     80        typename = typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
     81    >
     82    AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top())
     83        : AtomicValue(AtomicValueCASTag, kind, origin, width, expectedValue, newValue, pointer, offset, range, fenceRange)
     84    {
     85    }
     86
     87    // The above templates forward to these implementations.
     88    AtomicValue(AtomicValueRMW, Kind, Origin, Width, Value* operand, Value* pointer, OffsetType, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
     89    AtomicValue(AtomicValueCAS, Kind, Origin, Width, Value* expectedValue, Value* newValue, Value* pointer, OffsetType, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
     90
    6091    Width m_width;
    6192};
     
    6495
    6596#endif // ENABLE(B3_JIT)
    66 
  • trunk/Source/JavaScriptCore/b3/B3Common.h

    r214636 r215407  
    103103
    104104template<typename ResultType>
     105inline bool isRepresentableAs(size_t value)
     106{
     107    return isRepresentableAsImpl<ResultType, size_t, size_t>(value);
     108}
     109
     110template<typename ResultType>
    105111inline bool isRepresentableAs(double value)
    106112{
  • trunk/Source/JavaScriptCore/b3/B3EliminateCommonSubexpressions.cpp

    r214636 r215407  
    258258        Value* ptr = memory->lastChild();
    259259        HeapRange range = memory->range();
    260         int32_t offset = memory->offset();
     260        Value::OffsetType offset = memory->offset();
    261261
    262262        switch (memory->opcode()) {
     
    306306        Value* ptr = memory->lastChild();
    307307        HeapRange range = memory->range();
    308         int32_t offset = memory->offset();
     308        Value::OffsetType offset = memory->offset();
    309309        Type type = memory->type();
    310310
  • trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp

    r215340 r215407  
    440440        return true;
    441441    }
    442    
    443     std::optional<unsigned> scaleForShl(Value* shl, int32_t offset, std::optional<Width> width = std::nullopt)
     442
     443    template<typename Int, typename = Value::IsLegalOffset<Int>>
     444    std::optional<unsigned> scaleForShl(Value* shl, Int offset, std::optional<Width> width = std::nullopt)
    444445    {
    445446        if (shl->opcode() != Shl)
     
    464465   
    465466    // This turns the given operand into an address.
    466     Arg effectiveAddr(Value* address, int32_t offset, Width width)
     467    template<typename Int, typename = Value::IsLegalOffset<Int>>
     468    Arg effectiveAddr(Value* address, Int offset, Width width)
    467469    {
    468470        ASSERT(Arg::isValidAddrForm(offset, width));
     
    553555            return Arg::simpleAddr(tmp(value->lastChild()));
    554556
    555         int32_t offset = value->offset();
     557        Value::OffsetType offset = value->offset();
    556558        Width width = value->accessWidth();
    557559
     
    20242026        // Add(@x, Shl(@y, $c))
    20252027        // Add(@x, @y) (only if offset != 0)
    2026         int32_t offset = 0;
    2027         if (value->child(1)->isRepresentableAs<int32_t>()
     2028        Value::OffsetType offset = 0;
     2029        if (value->child(1)->isRepresentableAs<Value::OffsetType>()
    20282030            && canBeInternal(value->child(0))
    20292031            && value->child(0)->opcode() == Add) {
    20302032            innerAdd = value->child(0);
    2031             offset = static_cast<int32_t>(value->child(1)->asInt());
     2033            offset = static_cast<Value::OffsetType>(value->child(1)->asInt());
    20322034            value = value->child(0);
    20332035        }
  • trunk/Source/JavaScriptCore/b3/B3MemoryValue.cpp

    r213714 r215407  
    3939}
    4040
    41 bool MemoryValue::isLegalOffset(int64_t offset) const
     41bool MemoryValue::isLegalOffsetImpl(int64_t offset) const
    4242{
    43     return B3::isRepresentableAs<int32_t>(offset) && isLegalOffset(static_cast<int32_t>(offset));
     43    return B3::isRepresentableAs<OffsetType>(offset) && isLegalOffset(static_cast<OffsetType>(offset));
    4444}
    4545
     
    8181// Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
    8282// describes the returned type).
    83 MemoryValue::MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
     83MemoryValue::MemoryValue(MemoryValue::MemoryValueLoad, Kind kind, Type type, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    8484    : Value(CheckedOpcode, kind, type, origin, pointer)
    8585    , m_offset(offset)
     
    109109
    110110// Use this form for loads where the return type is implied.
    111 MemoryValue::MemoryValue(Kind kind, Origin origin, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
     111MemoryValue::MemoryValue(MemoryValue::MemoryValueLoadImplied, Kind kind, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    112112    : MemoryValue(kind, Int32, origin, pointer, offset, range, fenceRange)
    113113{
     
    126126
    127127// Use this form for stores.
    128 MemoryValue::MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
     128MemoryValue::MemoryValue(MemoryValue::MemoryValueStore, Kind kind, Origin origin, Value* value, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
    129129    : Value(CheckedOpcode, kind, Void, origin, value, pointer)
    130130    , m_offset(offset)
  • trunk/Source/JavaScriptCore/b3/B3MemoryValue.h

    r213714 r215407  
    3232#include "B3HeapRange.h"
    3333#include "B3Value.h"
     34#include <type_traits>
    3435
    3536namespace JSC { namespace B3 {
     
    4445    ~MemoryValue();
    4546
    46     int32_t offset() const { return m_offset; }
    47     void setOffset(int32_t offset) { m_offset = offset; }
    48    
     47    OffsetType offset() const { return m_offset; }
     48    template<typename Int, typename = IsLegalOffset<Int>>
     49    void setOffset(Int offset) { m_offset = offset; }
     50
    4951    // You don't have to worry about using legal offsets unless you've entered quirks mode.
    50     bool isLegalOffset(int32_t offset) const;
    51     bool isLegalOffset(int64_t offset) const;
    52    
     52    template<typename Int,
     53        typename = typename std::enable_if<std::is_integral<Int>::value>::type,
     54        typename = typename std::enable_if<std::is_signed<Int>::value>::type
     55    >
     56    bool isLegalOffset(Int offset) const { return isLegalOffsetImpl(offset); }
     57
    5358    // A necessary consequence of MemoryValue having an offset is that it participates in instruction
    5459    // selection. This tells you if this will get lowered to something that requires an offsetless
     
    8590    Value* cloneImpl() const override;
    8691
    87     template<typename... Arguments>
    88     MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, int32_t offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
     92    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)
    8994        : Value(CheckedOpcode, kind, type, origin, arguments...)
    9095        , m_offset(offset)
     
    96101private:
    97102    friend class Procedure;
    98    
     103
     104    bool isLegalOffsetImpl(int32_t offset) const;
     105    bool isLegalOffsetImpl(int64_t offset) const;
     106
     107    enum MemoryValueLoad { MemoryValueLoadTag };
     108    enum MemoryValueLoadImplied { MemoryValueLoadImpliedTag };
     109    enum MemoryValueStore { MemoryValueStoreTag };
     110
    99111    // Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
    100112    // describes the returned type).
    101     MemoryValue(Kind, Type, Origin, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
     113    MemoryValue(Kind kind, Type type, Origin origin, Value* pointer)
     114        : MemoryValue(MemoryValueLoadTag, kind, type, origin, pointer)
     115    {
     116    }
     117    template<typename Int, typename = IsLegalOffset<Int>>
     118    MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
     119        : MemoryValue(MemoryValueLoadTag, kind, type, origin, pointer, offset, range, fenceRange)
     120    {
     121    }
    102122
    103123    // Use this form for loads where the return type is implied.
    104     MemoryValue(Kind, Origin, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
     124    MemoryValue(Kind kind, Origin origin, Value* pointer)
     125        : MemoryValue(MemoryValueLoadImpliedTag, kind, origin, pointer)
     126    {
     127    }
     128    template<typename Int, typename = IsLegalOffset<Int>>
     129    MemoryValue(Kind kind, Origin origin, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
     130        : MemoryValue(MemoryValueLoadImpliedTag, kind, origin, pointer, offset, range, fenceRange)
     131    {
     132    }
    105133
    106134    // Use this form for stores.
    107     MemoryValue(Kind, Origin, Value* value, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
    108    
    109     int32_t m_offset { 0 };
     135    MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer)
     136        : MemoryValue(MemoryValueStoreTag, kind, origin, value, pointer)
     137    {
     138    }
     139    template<typename Int, typename = IsLegalOffset<Int>>
     140    MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
     141        : MemoryValue(MemoryValueStoreTag, kind, origin, value, pointer, offset, range, fenceRange)
     142    {
     143    }
     144
     145    // The above templates forward to these implementations.
     146    MemoryValue(MemoryValueLoad, Kind, Type, Origin, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
     147    MemoryValue(MemoryValueLoadImplied, Kind, Origin, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
     148    MemoryValue(MemoryValueStore, Kind, Origin, Value*, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
     149
     150    OffsetType m_offset { 0 };
    110151    HeapRange m_range { HeapRange::top() };
    111152    HeapRange m_fenceRange { HeapRange() };
  • trunk/Source/JavaScriptCore/b3/B3MemoryValueInlines.h

    r213714 r215407  
    3333namespace JSC { namespace B3 {
    3434
    35 inline bool MemoryValue::isLegalOffset(int32_t offset) const
     35inline bool MemoryValue::isLegalOffsetImpl(int32_t offset) const
    3636{
    3737    // NOTE: This is inline because it constant-folds to true on x86!
  • trunk/Source/JavaScriptCore/b3/B3MoveConstants.cpp

    r214636 r215407  
    210210                        if (bestPointer) {
    211211                            memoryValue->lastChild() = bestPointer;
    212                             memoryValue->setOffset(desiredOffset(bestPointer));
     212                            memoryValue->setOffset(static_cast<int32_t>(desiredOffset(bestPointer)));
    213213                        }
    214214                    }
     
    309309                    continue;
    310310
     311                auto offset = sizeof(int64_t) * m_constTable.get(key);
     312                if (!isRepresentableAs<Value::OffsetType>(offset))
     313                    continue;
     314
    311315                Value* tableBase = m_insertionSet.insertIntConstant(
    312316                    valueIndex, value->origin(), pointerType(),
     
    314318                Value* result = m_insertionSet.insert<MemoryValue>(
    315319                    valueIndex, Load, value->type(), value->origin(), tableBase,
    316                     sizeof(int64_t) * m_constTable.get(key));
     320                    static_cast<Value::OffsetType>(offset));
    317321                value->replaceWithIdentity(result);
    318322            }
  • trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp

    r215057 r215407  
    15561556                if (!sumOverflows<intptr_t>(offset, memory->offset())) {
    15571557                    offset += memory->offset();
    1558                     int32_t smallOffset = static_cast<int32_t>(offset);
     1558                    Value::OffsetType smallOffset = static_cast<Value::OffsetType>(offset);
    15591559                    if (smallOffset == offset) {
    15601560                        address = address->child(0);
  • trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp

    r212970 r215407  
    271271            return ValueRep::stack(arg.offset());
    272272        ASSERT(arg.base() == Tmp(MacroAssembler::stackPointerRegister));
    273         return ValueRep::stack(arg.offset() - static_cast<int32_t>(code.frameSize()));
     273        return ValueRep::stack(arg.offset() - safeCast<Value::OffsetType>(code.frameSize()));
    274274    default:
    275275        ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/b3/B3Value.h

    r213714 r215407  
    4040#include <wtf/FastMalloc.h>
    4141#include <wtf/Noncopyable.h>
     42#include <wtf/StdLibExtras.h>
    4243#include <wtf/TriState.h>
    4344
     
    283284    template<typename Functor>
    284285    void walk(const Functor& functor, PhiChildren* = nullptr);
     286
     287    // B3 purposefully only represents signed 32-bit offsets because that's what x86 can encode, and
     288    // ARM64 cannot encode anything bigger. The IsLegalOffset type trait is then used on B3 Value
     289    // methods to prevent implicit conversions by C++ from invalid offset types: these cause compilation
     290    // to fail, instead of causing implementation-defined behavior (which often turns to exploit).
     291    // OffsetType isn't sufficient to determine offset validity! Each Value opcode further has an
     292    // isLegalOffset runtime method used to determine value legality at runtime. This is exposed to users
     293    // of B3 to force them to reason about the target's offset.
     294    typedef int32_t OffsetType;
     295    template<typename Int>
     296    struct IsLegalOffset : std::conjunction<
     297        typename std::enable_if<std::is_integral<Int>::value>::type,
     298        typename std::enable_if<std::is_signed<Int>::value>::type,
     299        typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
     300    > { };
     301
    285302
    286303protected:
  • trunk/Source/JavaScriptCore/b3/air/AirArg.cpp

    r215292 r215407  
    4242namespace JSC { namespace B3 { namespace Air {
    4343
    44 Arg Arg::stackAddr(int32_t offsetFromFP, unsigned frameSize, Width width)
     44Arg Arg::stackAddrImpl(int32_t offsetFromFP, unsigned frameSize, Width width)
    4545{
    4646    Arg result = Arg::addr(Air::Tmp(GPRInfo::callFrameRegister), offsetFromFP);
  • trunk/Source/JavaScriptCore/b3/air/AirArg.h

    r215292 r215407  
    3232#include "B3Common.h"
    3333#include "B3Type.h"
     34#include "B3Value.h"
    3435#include "B3Width.h"
    3536#include <wtf/Optional.h>
     
    535536    }
    536537
    537     static Arg addr(Air::Tmp base, int32_t offset = 0)
     538    template<typename Int, typename = Value::IsLegalOffset<Int>>
     539    static Arg addr(Air::Tmp base, Int offset)
    538540    {
    539541        ASSERT(base.isGP());
     
    545547    }
    546548
    547     static Arg stack(StackSlot* value, int32_t offset = 0)
     549    static Arg addr(Air::Tmp base)
     550    {
     551        return addr(base, 0);
     552    }
     553
     554    template<typename Int, typename = Value::IsLegalOffset<Int>>
     555    static Arg stack(StackSlot* value, Int offset)
    548556    {
    549557        Arg result;
     
    554562    }
    555563
    556     static Arg callArg(int32_t offset)
     564    static Arg stack(StackSlot* value)
     565    {
     566        return stack(value, 0);
     567    }
     568
     569    template<typename Int, typename = Value::IsLegalOffset<Int>>
     570    static Arg callArg(Int offset)
    557571    {
    558572        Arg result;
     
    561575        return result;
    562576    }
    563    
    564     static Arg stackAddr(int32_t offsetFromFP, unsigned frameSize, Width);
     577
     578    template<typename Int, typename = Value::IsLegalOffset<Int>>
     579    static Arg stackAddr(Int offsetFromFP, unsigned frameSize, Width width)
     580    {
     581        return stackAddrImpl(offsetFromFP, frameSize, width);
     582    }
    565583
    566584    // If you don't pass a Width, this optimistically assumes that you're using the right width.
     
    605623    }
    606624
    607     static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1, int32_t offset = 0)
     625    template<typename Int, typename = Value::IsLegalOffset<Int>>
     626    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale, Int offset)
    608627    {
    609628        ASSERT(base.isGP());
     
    617636        result.m_offset = offset;
    618637        return result;
     638    }
     639
     640    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1)
     641    {
     642        return Arg::index(base, index, scale, 0);
    619643    }
    620644
     
    926950    bool hasOffset() const { return isMemory(); }
    927951   
    928     int32_t offset() const
     952    Value::OffsetType offset() const
    929953    {
    930954        if (kind() == Stack)
    931             return static_cast<int32_t>(m_scale);
     955            return static_cast<Value::OffsetType>(m_scale);
    932956        ASSERT(kind() == Addr || kind() == CallArg || kind() == Index);
    933         return static_cast<int32_t>(m_offset);
     957        return static_cast<Value::OffsetType>(m_offset);
    934958    }
    935959
     
    11421166    }
    11431167
    1144     static bool isValidAddrForm(int32_t offset, std::optional<Width> width = std::nullopt)
     1168    template<typename Int, typename = Value::IsLegalOffset<Int>>
     1169    static bool isValidAddrForm(Int offset, std::optional<Width> width = std::nullopt)
    11451170    {
    11461171        if (isX86())
     
    11671192    }
    11681193
    1169     static bool isValidIndexForm(unsigned scale, int32_t offset, std::optional<Width> width = std::nullopt)
     1194    template<typename Int, typename = Value::IsLegalOffset<Int>>
     1195    static bool isValidIndexForm(unsigned scale, Int offset, std::optional<Width> width = std::nullopt)
    11701196    {
    11711197        if (!isValidScale(scale, width))
     
    12771303    {
    12781304        ASSERT(isImm() || isBitImm());
    1279         return MacroAssembler::TrustedImm32(static_cast<int32_t>(m_offset));
     1305        return MacroAssembler::TrustedImm32(static_cast<Value::OffsetType>(m_offset));
    12801306    }
    12811307
     
    13021328            return MacroAssembler::Address(m_base.gpr());
    13031329        ASSERT(isAddr());
    1304         return MacroAssembler::Address(m_base.gpr(), static_cast<int32_t>(m_offset));
     1330        return MacroAssembler::Address(m_base.gpr(), static_cast<Value::OffsetType>(m_offset));
    13051331    }
    13061332
     
    13101336        return MacroAssembler::BaseIndex(
    13111337            m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
    1312             static_cast<int32_t>(m_offset));
     1338            static_cast<Value::OffsetType>(m_offset));
    13131339    }
    13141340
     
    14131439
    14141440private:
     1441    static Arg stackAddrImpl(int32_t, unsigned, Width);
     1442
    14151443    int64_t m_offset { 0 };
    14161444    Kind m_kind { Invalid };
  • trunk/Source/JavaScriptCore/b3/air/AirLowerStackArgs.cpp

    r215292 r215407  
    7575            inst.forEachArg(
    7676                [&] (Arg& arg, Arg::Role role, Bank, Width width) {
    77                     auto stackAddr = [&] (int32_t offset) -> Arg {
     77                    auto stackAddr = [&] (Value::OffsetType offset) -> Arg {
    7878                        Arg result = Arg::stackAddr(offset, code.frameSize(), width);
    7979                        if (!result) {
  • trunk/Source/JavaScriptCore/b3/testb3.cpp

    r215340 r215407  
    880880    root->appendNew<MemoryValue>(
    881881        proc, Store, Origin(), value,
    882         root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot));
     882        root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot), 0);
    883883    root->appendNew<MemoryValue>(
    884884        proc, Store, Origin(), mul,
    885         root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot));
     885        root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot), 0);
    886886
    887887    root->appendNewControlValue(
     
    54225422            proc, Trunc, Origin(),
    54235423            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
    5424         root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     5424        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
    54255425    root->appendNewControlValue(
    54265426        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
     
    54385438        proc, Store, Origin(),
    54395439        root->appendNew<Const32Value>(proc, Origin(), value),
    5440         root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     5440        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
    54415441    root->appendNewControlValue(
    54425442        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
     
    54585458        proc, Store, Origin(),
    54595459        root->appendNew<ConstPtrValue>(proc, Origin(), value),
    5460         root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
     5460        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
    54615461    root->appendNewControlValue(
    54625462        proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
     
    57605760                proc, Trunc, Origin(),
    57615761                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
    5762         slotPtr);
     5762        slotPtr, 0);
    57635763    root->appendNewControlValue(
    57645764        proc, Return, Origin(),
     
    58105810            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
    58115811            root->appendNew<Const32Value>(proc, Origin(), amount)),
    5812         slotPtr);
     5812        slotPtr, 0);
    58135813    root->appendNewControlValue(
    58145814        proc, Return, Origin(),
     
    58335833                proc, Trunc, Origin(),
    58345834                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
    5835         slotPtr);
     5835        slotPtr, 0);
    58365836    root->appendNewControlValue(
    58375837        proc, Return, Origin(),
     
    59225922            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
    59235923            root->appendNew<Const32Value>(proc, Origin(), amount)),
    5924         slotPtr);
     5924        slotPtr, 0);
    59255925    root->appendNewControlValue(
    59265926        proc, Return, Origin(),
     
    59455945                proc, Trunc, Origin(),
    59465946                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
    5947         slotPtr);
     5947        slotPtr, 0);
    59485948    root->appendNewControlValue(
    59495949        proc, Return, Origin(),
     
    59955995            root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
    59965996            root->appendNew<Const32Value>(proc, Origin(), amount)),
    5997         slotPtr);
     5997        slotPtr, 0);
    59985998    root->appendNewControlValue(
    59995999        proc, Return, Origin(),
     
    60166016            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
    60176017            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
    6018         slotPtr);
     6018        slotPtr, 0);
    60196019    root->appendNewControlValue(
    60206020        proc, Return, Origin(),
     
    60646064            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
    60656065            root->appendNew<Const64Value>(proc, Origin(), amount)),
    6066         slotPtr);
     6066        slotPtr, 0);
    60676067    root->appendNewControlValue(
    60686068        proc, Return, Origin(),
     
    60966096                proc, Trunc, Origin(),
    60976097                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
    6098         slotPtr);
     6098        slotPtr, 0);
    60996099    root->appendNewControlValue(
    61006100        proc, Return, Origin(),
     
    61266126            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
    61276127            root->appendNew<Const32Value>(proc, Origin(), amount)),
    6128         slotPtr);
     6128        slotPtr, 0);
    61296129    root->appendNewControlValue(
    61306130        proc, Return, Origin(),
     
    62806280            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
    62816281            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
    6282         slotPtr);
     6282        slotPtr, 0);
    62836283    root->appendNewControlValue(
    62846284        proc, Return, Origin(),
     
    63106310            root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
    63116311            root->appendNew<Const64Value>(proc, Origin(), amount)),
    6312         slotPtr);
     6312        slotPtr, 0);
    63136313    root->appendNewControlValue(
    63146314        proc, Return, Origin(),
     
    63346334                proc, Trunc, Origin(),
    63356335                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
    6336         slotPtr);
     6336        slotPtr, 0);
    63376337    root->appendNewControlValue(
    63386338        proc, Return, Origin(),
     
    63556355        proc, Store, Origin(),
    63566356        root->appendNew<Const32Value>(proc, Origin(), 666),
    6357         otherSlotPtr);
     6357        otherSlotPtr, 0);
    63586358    root->appendNew<MemoryValue>(
    63596359        proc, Store, Origin(),
     
    63616361            proc, Add, Origin(),
    63626362            load, root->appendNew<Const32Value>(proc, Origin(), amount)),
    6363         slotPtr);
     6363        slotPtr, 0);
    63646364    root->appendNewControlValue(
    63656365        proc, Return, Origin(),
     
    63856385                root->appendNew<Const32Value>(proc, Origin(), amount)),
    63866386            root->appendNew<Const32Value>(proc, Origin(), mask)),
    6387         slotPtr);
     6387        slotPtr, 0);
    63886388    root->appendNewControlValue(
    63896389        proc, Return, Origin(),
     
    64096409            root->appendNew<Const32Value>(proc, Origin(), 0),
    64106410            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)),
    6411         slotPtr);
     6411        slotPtr, 0);
    64126412   
    64136413    root->appendNewControlValue(
     
    64336433            root->appendNew<ConstPtrValue>(proc, Origin(), 0),
    64346434            root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)),
    6435         slotPtr);
     6435        slotPtr, 0);
    64366436   
    64376437    root->appendNewControlValue(
     
    64696469            proc, Add, Origin(),
    64706470            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
    6471             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
     6471            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, static_cast<int32_t>(sizeof(int)))));
    64726472
    64736473    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
     
    64856485            proc, Add, Origin(),
    64866486            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
    6487             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
     6487            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, static_cast<int32_t>(sizeof(int)))));
    64886488
    64896489    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
     
    65096509                root->appendNew<Value>(
    65106510                    proc, Add, Origin(), arrayPtr,
    6511                     root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
     6511                    root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))))));
    65126512   
    65136513    CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
     
    65326532        root->appendNew<Value>(
    65336533            proc, Add, Origin(), arrayPtr,
    6534             root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))));
     6534            root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))));
    65356535    root->appendNew<MemoryValue>(
    65366536        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0);
    65376537    root->appendNew<MemoryValue>(
    6538         proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int));
     6538        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, static_cast<int32_t>(sizeof(int)));
    65396539    root->appendNewControlValue(
    65406540        proc, Return, Origin(),
     
    65666566                root->appendNew<Value>(
    65676567                    proc, Add, Origin(), arrayPtr,
    6568                     root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
     6568                    root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))))));
    65696569   
    65706570    CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
     
    66916691            proc, Trunc, Origin(),
    66926692            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
    6693         stack);
     6693        stack, 0);
    66946694   
    66956695    root->appendNewControlValue(
     
    67616761                proc, opcode, type, Origin(),
    67626762                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
    6763                 sizeof(InputType)));
     6763                static_cast<int32_t>(sizeof(InputType))));
    67646764
    67656765        CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value)));
     
    1290312903                proc, Mul, Origin(),
    1290412904                addToDataPointer->appendNew<MemoryValue>(
    12905                     proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t)),
     12905                    proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t))),
    1290612906                addToDataPointer->appendIntConstant(
    1290712907                    proc, Origin(), pointerType(), sizeof(intptr_t)))));
     
    1293212932                proc, Mul, Origin(),
    1293312933                addToCodePointerTaken->appendNew<MemoryValue>(
    12934                     proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t)),
     12934                    proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t))),
    1293512935                addToCodePointerTaken->appendIntConstant(
    1293612936                    proc, Origin(), pointerType(), sizeof(intptr_t)))));
     
    1295512955                proc, Load, pointerType(), Origin(), dataPointerValue),
    1295612956            addToData->appendNew<MemoryValue>(
    12957                 proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t))),
     12957                proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t)))),
    1295812958        dataPointerValue);
    1295912959    addToData->appendNew<VariableValue>(
     
    1387613876        proc, trapping(Store), Origin(),
    1387713877        root->appendNew<Const32Value>(proc, Origin(), 111),
    13878         root->appendNew<ConstPtrValue>(proc, Origin(), &x));
     13878        root->appendNew<ConstPtrValue>(proc, Origin(), &x), 0);
    1387913879    Effects expectedEffects;
    1388013880    expectedEffects.exitsSideways = true;
     
    1391313913            root->appendNew<MemoryValue>(proc, trapping(Load), Int32, Origin(), ptr),
    1391413914            root->appendNew<Const32Value>(proc, Origin(), 3)),
    13915         ptr);
     13915        ptr, 0);
    1391613916    root->appendNew<Value>(proc, Return, Origin());
    1391713917    compileAndRun<int>(proc);
     
    1522915229    pointer = body->appendNew<Value>(proc, ZExt32, Origin(), pointer);
    1523015230    body->appendNew<MemoryValue>(proc, Store, Origin(), valueToStore,
    15231         body->appendNew<WasmAddressValue>(proc, Origin(), pointer, pinnedGPR));
     15231        body->appendNew<WasmAddressValue>(proc, Origin(), pointer, pinnedGPR), 0);
    1523215232    UpsilonValue* incUpsilon = body->appendNew<UpsilonValue>(proc, Origin(),
    1523315233        body->appendNew<Value>(proc, Add, Origin(), indexPhi,
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r215379 r215407  
    6161#include "WasmThunks.h"
    6262#include <wtf/Optional.h>
     63#include <wtf/StdLibExtras.h>
    6364
    6465void dumpProcedure(void* ptr)
     
    238239    void emitChecksForModOrDiv(B3::Opcode, ExpressionType left, ExpressionType right);
    239240
    240     void fixupPointerPlusOffset(ExpressionType&, uint32_t&);
     241    int32_t WARN_UNUSED_RETURN fixupPointerPlusOffset(ExpressionType&, uint32_t);
    241242
    242243    Value* materializeWasmContext(Procedure&, BasicBlock*);
     
    262263
    263264// Memory accesses in WebAssembly have unsigned 32-bit offsets, whereas they have signed 32-bit offsets in B3.
    264 void B3IRGenerator::fixupPointerPlusOffset(ExpressionType& ptr, uint32_t& offset)
     265int32_t B3IRGenerator::fixupPointerPlusOffset(ExpressionType& ptr, uint32_t offset)
    265266{
    266267    if (static_cast<uint64_t>(offset) > static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
    267268        ptr = m_currentBlock->appendNew<Value>(m_proc, Add, origin(), ptr, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), offset));
    268         offset = 0;
    269     }
     269        return 0;
     270    }
     271    return offset;
    270272}
    271273
     
    508510auto B3IRGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
    509511{
    510     Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfMemory());
     512    Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfMemory()));
    511513
    512514    static_assert(sizeof(decltype(static_cast<JSWebAssemblyInstance*>(nullptr)->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
    513     Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, JSWebAssemblyMemory::offsetOfSize());
     515    Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, safeCast<int32_t>(JSWebAssemblyMemory::offsetOfSize()));
    514516   
    515517    constexpr uint32_t shiftValue = 16;
     
    532534auto B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult
    533535{
    534     Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
    535     result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), origin(), globalsArray, index * sizeof(Register));
     536    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfGlobals()));
     537    result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), origin(), globalsArray, safeCast<int32_t>(index * sizeof(Register)));
    536538    return { };
    537539}
     
    540542{
    541543    ASSERT(toB3Type(m_info.globals[index].type) == value->type());
    542     Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
    543     m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, index * sizeof(Register));
     544    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfGlobals()));
     545    m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, safeCast<int32_t>(index * sizeof(Register)));
    544546    return { };
    545547}
     
    556558        break;
    557559    case MemoryMode::Signaling:
    558         // We've virtually mapped 4GiB+redzone fo this memory. Only the user-allocated pages are addressable, contiguously in range [0, current], and everything above is mapped PROT_NONE. We don't need to perform any explicit bounds check in the 4GiB range because WebAssembly register memory accesses are 32-bit. However WebAssembly register+immediate accesses perform the addition in 64-bit which can push an access above the 32-bit limit. The redzone will catch most small immediates, and we'll explicitly bounds check any register + large immediate access.
     560        // We've virtually mapped 4GiB+redzone for this memory. Only the user-allocated pages are addressable, contiguously in range [0, current], and everything above is mapped PROT_NONE. We don't need to perform any explicit bounds check in the 4GiB range because WebAssembly register memory accesses are 32-bit. However WebAssembly register+immediate accesses perform the addition in 64-bit which can push an access above the 32-bit limit. The redzone will catch most small immediates, and we'll explicitly bounds check any register + large immediate access.
    559561        if (offset >= Memory::fastMappedRedzoneBytes())
    560562            m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), pointer, InvalidGPRReg, sizeOfOperation + offset - 1, m_info.memory.maximum());
     
    599601}
    600602
    601 inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, ExpressionType pointer, uint32_t offset)
    602 {
    603     fixupPointerPlusOffset(pointer, offset);
     603inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, ExpressionType pointer, uint32_t uoffset)
     604{
     605    int32_t offset = fixupPointerPlusOffset(pointer, uoffset);
    604606
    605607    switch (op) {
     
    738740
    739741
    740 inline void B3IRGenerator::emitStoreOp(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
    741 {
    742     fixupPointerPlusOffset(pointer, offset);
     742inline void B3IRGenerator::emitStoreOp(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t uoffset)
     743{
     744    int32_t offset = fixupPointerPlusOffset(pointer, uoffset);
    743745
    744746    switch (op) {
     
    941943    if (m_info.isImportedFunctionFromFunctionIndexSpace(functionIndex)) {
    942944        // FIXME imports can be linked here, instead of generating a patchpoint, because all import stubs are generated before B3 compilation starts. https://bugs.webkit.org/show_bug.cgi?id=166462
    943         Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfImportFunction(functionIndex));
    944         Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, JSCell::typeInfoTypeOffset());
     945        Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfImportFunction(functionIndex)));
     946        Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, safeCast<int32_t>(JSCell::typeInfoTypeOffset()));
    945947        Value* isWasmCall = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), jsTypeOfImport, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), WebAssemblyFunctionType));
    946948
     
    972974        // https://bugs.webkit.org/show_bug.cgi?id=170375
    973975        Value* codeBlock = isJSBlock->appendNew<MemoryValue>(m_proc,
    974             Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfCodeBlock());
     976            Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfCodeBlock()));
    975977        Value* jumpDestination = isJSBlock->appendNew<MemoryValue>(m_proc,
    976             Load, pointerType(), origin(), codeBlock, JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex));
     978            Load, pointerType(), origin(), codeBlock, safeCast<int32_t>(JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex)));
    977979        Value* jsCallResult = wasmCallingConvention().setupCall(m_proc, isJSBlock, origin(), args, toB3Type(returnType),
    978980            [&] (PatchpointValue* patchpoint) {
     
    10301032    {
    10311033        ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
    1032             m_instanceValue, JSWebAssemblyInstance::offsetOfTable());
     1034            m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfTable()));
    10331035        callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
    1034             table, JSWebAssemblyTable::offsetOfFunctions());
     1036            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfFunctions()));
    10351037        callableFunctionBufferSize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(),
    1036             table, JSWebAssemblyTable::offsetOfSize());
     1038            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfSize()));
    10371039    }
    10381040
     
    10551057    // Check that the CallableFunction is initialized. We trap if it isn't. An "invalid" SignatureIndex indicates it's not initialized.
    10561058    static_assert(sizeof(CallableFunction::signatureIndex) == sizeof(uint32_t), "Load codegen assumes i32");
    1057     ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signatureIndex));
     1059    ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, signatureIndex)));
    10581060    {
    10591061        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
     
    10781080    }
    10791081
    1080     ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, code));
     1082    ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, code)));
    10811083
    10821084    Type returnType = signature.returnType();
  • trunk/Source/WTF/ChangeLog

    r215386 r215407  
     12017-04-17  JF Bastien  <jfbastien@apple.com>
     2
     3        B3: don't allow unsigned offsets in Value
     4        https://bugs.webkit.org/show_bug.cgi?id=170692
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Add C++17's std::conjunction type trait, except for Microsoft VS
     9        2015 update 2 and later because it adds the logical operator type
     10        traits, event when C++ is pre-2017:
     11        https://blogs.msdn.microsoft.com/vcblog/2016/01/22/vs-2015-update-2s-stl-is-c17-so-far-feature-complete/
     12
     13        * wtf/StdLibExtras.h:
     14
    1152017-04-14  Mark Lam  <mark.lam@apple.com>
    216
  • trunk/Source/WTF/wtf/StdLibExtras.h

    r214409 r215407  
    3131#include <cstring>
    3232#include <memory>
     33#include <type_traits>
    3334#include <wtf/Assertions.h>
    3435#include <wtf/CheckedArithmetic.h>
     
    511512}
    512513
     514#if __cplusplus < 201703L && (!defined(_MSC_FULL_VER) || _MSC_FULL_VER < 190023918)
     515template<class...> struct wtf_conjunction_impl;
     516template<> struct wtf_conjunction_impl<> : true_type { };
     517template<class B0> struct wtf_conjunction_impl<B0> : B0 { };
     518template<class B0, class B1> struct wtf_conjunction_impl<B0, B1> : conditional<B0::value, B1, B0>::type { };
     519template<class B0, class B1, class B2, class... Bn> struct wtf_conjunction_impl<B0, B1, B2, Bn...> : conditional<B0::value, wtf_conjunction_impl<B1, B2, Bn...>, B0>::type { };
     520template<class... _Args> struct conjunction : wtf_conjunction_impl<_Args...> { };
     521#endif
     522
    513523} // namespace std
    514524
Note: See TracChangeset for help on using the changeset viewer.