Title: [215407] trunk/Source
Revision
215407
Author
jfbast...@apple.com
Date
2017-04-17 01:24:48 -0700 (Mon, 17 Apr 2017)

Log Message

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

Reviewed by Filip Pizlo.

Source/_javascript_Core:

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:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (215406 => 215407)


--- trunk/Source/_javascript_Core/ChangeLog	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-04-17 08:24:48 UTC (rev 215407)
@@ -1,3 +1,94 @@
+2017-04-17  JF Bastien  <jfbast...@apple.com>
+
+        B3: don't allow unsigned offsets in Value
+        https://bugs.webkit.org/show_bug.cgi?id=170692
+
+        Reviewed by Filip Pizlo.
+
+        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):
+
 2017-04-16  Joseph Pecoraro  <pecor...@apple.com>
 
         test262: test262/test/built-ins/Object/prototype/toLocaleString/primitive_this_value.js

Modified: trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3AtomicValue.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -46,7 +46,7 @@
     return new AtomicValue(*this);
 }
 
-AtomicValue::AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+AtomicValue::AtomicValue(AtomicValue::AtomicValueRMW, Kind kind, Origin origin, Width width, Value* operand, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
     : MemoryValue(CheckedOpcode, kind, operand->type(), origin, offset, range, fenceRange, operand, pointer)
     , m_width(width)
 {
@@ -65,7 +65,7 @@
     }
 }
 
-AtomicValue::AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+AtomicValue::AtomicValue(AtomicValue::AtomicValueCAS, Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
     : MemoryValue(CheckedOpcode, kind, kind.opcode() == AtomicWeakCAS ? Int32 : expectedValue->type(), origin, offset, range, fenceRange, expectedValue, newValue, pointer)
     , m_width(width)
 {

Modified: trunk/Source/_javascript_Core/b3/B3AtomicValue.h (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3AtomicValue.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3AtomicValue.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -52,11 +52,42 @@
     
 private:
     friend class Procedure;
-    
-    AtomicValue(Kind, Origin, Width, Value* operand, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
-    
-    AtomicValue(Kind, Origin, Width, Value* expectedValue, Value* newValue, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
-    
+
+    enum AtomicValueRMW { AtomicValueRMWTag };
+    enum AtomicValueCAS { AtomicValueCASTag };
+
+    AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer)
+        : AtomicValue(kind, origin, width, operand, pointer, 0)
+    {
+    }
+    template<typename Int,
+        typename = typename std::enable_if<std::is_integral<Int>::value>::type,
+        typename = typename std::enable_if<std::is_signed<Int>::value>::type,
+        typename = typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
+    >
+    AtomicValue(Kind kind, Origin origin, Width width, Value* operand, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top())
+        : AtomicValue(AtomicValueRMWTag, kind, origin, width, operand, pointer, offset, range, fenceRange)
+    {
+    }
+
+    AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer)
+        : AtomicValue(kind, origin, width, expectedValue, newValue, pointer, 0)
+    {
+    }
+    template<typename Int,
+        typename = typename std::enable_if<std::is_integral<Int>::value>::type,
+        typename = typename std::enable_if<std::is_signed<Int>::value>::type,
+        typename = typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
+    >
+    AtomicValue(Kind kind, Origin origin, Width width, Value* expectedValue, Value* newValue, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange::top())
+        : AtomicValue(AtomicValueCASTag, kind, origin, width, expectedValue, newValue, pointer, offset, range, fenceRange)
+    {
+    }
+
+    // The above templates forward to these implementations.
+    AtomicValue(AtomicValueRMW, Kind, Origin, Width, Value* operand, Value* pointer, OffsetType, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
+    AtomicValue(AtomicValueCAS, Kind, Origin, Width, Value* expectedValue, Value* newValue, Value* pointer, OffsetType, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange::top());
+
     Width m_width;
 };
 
@@ -63,4 +94,3 @@
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)
-

Modified: trunk/Source/_javascript_Core/b3/B3Common.h (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3Common.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3Common.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -102,6 +102,12 @@
 }
 
 template<typename ResultType>
+inline bool isRepresentableAs(size_t value)
+{
+    return isRepresentableAsImpl<ResultType, size_t, size_t>(value);
+}
+
+template<typename ResultType>
 inline bool isRepresentableAs(double value)
 {
     return isRepresentableAsImpl<ResultType, double, int64_t>(value);

Modified: trunk/Source/_javascript_Core/b3/B3EliminateCommonSubexpressions.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3EliminateCommonSubexpressions.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3EliminateCommonSubexpressions.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -257,7 +257,7 @@
         Value* value = memory->child(0);
         Value* ptr = memory->lastChild();
         HeapRange range = memory->range();
-        int32_t offset = memory->offset();
+        Value::OffsetType offset = memory->offset();
 
         switch (memory->opcode()) {
         case Store8:
@@ -305,7 +305,7 @@
     {
         Value* ptr = memory->lastChild();
         HeapRange range = memory->range();
-        int32_t offset = memory->offset();
+        Value::OffsetType offset = memory->offset();
         Type type = memory->type();
 
         // FIXME: Empower this to insert more casts and shifts. For example, a Load8 could match a

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -439,8 +439,9 @@
         ASSERT_NOT_REACHED();
         return true;
     }
-    
-    std::optional<unsigned> scaleForShl(Value* shl, int32_t offset, std::optional<Width> width = std::nullopt)
+
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    std::optional<unsigned> scaleForShl(Value* shl, Int offset, std::optional<Width> width = std::nullopt)
     {
         if (shl->opcode() != Shl)
             return std::nullopt;
@@ -463,7 +464,8 @@
     }
     
     // This turns the given operand into an address.
-    Arg effectiveAddr(Value* address, int32_t offset, Width width)
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    Arg effectiveAddr(Value* address, Int offset, Width width)
     {
         ASSERT(Arg::isValidAddrForm(offset, width));
         
@@ -552,7 +554,7 @@
         if (value->requiresSimpleAddr())
             return Arg::simpleAddr(tmp(value->lastChild()));
 
-        int32_t offset = value->offset();
+        Value::OffsetType offset = value->offset();
         Width width = value->accessWidth();
 
         Arg result = effectiveAddr(value->lastChild(), offset, width);
@@ -2023,12 +2025,12 @@
         // Add(Shl(@x, $c), @y)
         // Add(@x, Shl(@y, $c))
         // Add(@x, @y) (only if offset != 0)
-        int32_t offset = 0;
-        if (value->child(1)->isRepresentableAs<int32_t>()
+        Value::OffsetType offset = 0;
+        if (value->child(1)->isRepresentableAs<Value::OffsetType>()
             && canBeInternal(value->child(0))
             && value->child(0)->opcode() == Add) {
             innerAdd = value->child(0);
-            offset = static_cast<int32_t>(value->child(1)->asInt());
+            offset = static_cast<Value::OffsetType>(value->child(1)->asInt());
             value = value->child(0);
         }
         

Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -38,9 +38,9 @@
 {
 }
 
-bool MemoryValue::isLegalOffset(int64_t offset) const
+bool MemoryValue::isLegalOffsetImpl(int64_t offset) const
 {
-    return B3::isRepresentableAs<int32_t>(offset) && isLegalOffset(static_cast<int32_t>(offset));
+    return B3::isRepresentableAs<OffsetType>(offset) && isLegalOffset(static_cast<OffsetType>(offset));
 }
 
 Type MemoryValue::accessType() const
@@ -80,7 +80,7 @@
 
 // Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
 // describes the returned type).
-MemoryValue::MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+MemoryValue::MemoryValue(MemoryValue::MemoryValueLoad, Kind kind, Type type, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
     : Value(CheckedOpcode, kind, type, origin, pointer)
     , m_offset(offset)
     , m_range(range)
@@ -108,7 +108,7 @@
 }
 
 // Use this form for loads where the return type is implied.
-MemoryValue::MemoryValue(Kind kind, Origin origin, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+MemoryValue::MemoryValue(MemoryValue::MemoryValueLoadImplied, Kind kind, Origin origin, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
     : MemoryValue(kind, Int32, origin, pointer, offset, range, fenceRange)
 {
     if (!ASSERT_DISABLED) {
@@ -125,7 +125,7 @@
 }
 
 // Use this form for stores.
-MemoryValue::MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, int32_t offset, HeapRange range, HeapRange fenceRange)
+MemoryValue::MemoryValue(MemoryValue::MemoryValueStore, Kind kind, Origin origin, Value* value, Value* pointer, MemoryValue::OffsetType offset, HeapRange range, HeapRange fenceRange)
     : Value(CheckedOpcode, kind, Void, origin, value, pointer)
     , m_offset(offset)
     , m_range(range)

Modified: trunk/Source/_javascript_Core/b3/B3MemoryValue.h (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3MemoryValue.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValue.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -31,6 +31,7 @@
 #include "B3Bank.h"
 #include "B3HeapRange.h"
 #include "B3Value.h"
+#include <type_traits>
 
 namespace JSC { namespace B3 {
 
@@ -43,13 +44,17 @@
 
     ~MemoryValue();
 
-    int32_t offset() const { return m_offset; }
-    void setOffset(int32_t offset) { m_offset = offset; }
-    
+    OffsetType offset() const { return m_offset; }
+    template<typename Int, typename = IsLegalOffset<Int>>
+    void setOffset(Int offset) { m_offset = offset; }
+
     // You don't have to worry about using legal offsets unless you've entered quirks mode.
-    bool isLegalOffset(int32_t offset) const;
-    bool isLegalOffset(int64_t offset) const;
-    
+    template<typename Int,
+        typename = typename std::enable_if<std::is_integral<Int>::value>::type,
+        typename = typename std::enable_if<std::is_signed<Int>::value>::type
+    >
+    bool isLegalOffset(Int offset) const { return isLegalOffsetImpl(offset); }
+
     // A necessary consequence of MemoryValue having an offset is that it participates in instruction
     // selection. This tells you if this will get lowered to something that requires an offsetless
     // address.
@@ -84,8 +89,8 @@
 
     Value* cloneImpl() const override;
 
-    template<typename... Arguments>
-    MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, int32_t offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
+    template<typename Int, typename = IsLegalOffset<Int>, typename... Arguments>
+    MemoryValue(CheckedOpcodeTag, Kind kind, Type type, Origin origin, Int offset, HeapRange range, HeapRange fenceRange, Arguments... arguments)
         : Value(CheckedOpcode, kind, type, origin, arguments...)
         , m_offset(offset)
         , m_range(range)
@@ -95,18 +100,54 @@
     
 private:
     friend class Procedure;
-    
+
+    bool isLegalOffsetImpl(int32_t offset) const;
+    bool isLegalOffsetImpl(int64_t offset) const;
+
+    enum MemoryValueLoad { MemoryValueLoadTag };
+    enum MemoryValueLoadImplied { MemoryValueLoadImpliedTag };
+    enum MemoryValueStore { MemoryValueStoreTag };
+
     // Use this form for Load (but not Load8Z, Load8S, or any of the Loads that have a suffix that
     // describes the returned type).
-    MemoryValue(Kind, Type, Origin, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
+    MemoryValue(Kind kind, Type type, Origin origin, Value* pointer)
+        : MemoryValue(MemoryValueLoadTag, kind, type, origin, pointer)
+    {
+    }
+    template<typename Int, typename = IsLegalOffset<Int>>
+    MemoryValue(Kind kind, Type type, Origin origin, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
+        : MemoryValue(MemoryValueLoadTag, kind, type, origin, pointer, offset, range, fenceRange)
+    {
+    }
 
     // Use this form for loads where the return type is implied.
-    MemoryValue(Kind, Origin, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
+    MemoryValue(Kind kind, Origin origin, Value* pointer)
+        : MemoryValue(MemoryValueLoadImpliedTag, kind, origin, pointer)
+    {
+    }
+    template<typename Int, typename = IsLegalOffset<Int>>
+    MemoryValue(Kind kind, Origin origin, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
+        : MemoryValue(MemoryValueLoadImpliedTag, kind, origin, pointer, offset, range, fenceRange)
+    {
+    }
 
     // Use this form for stores.
-    MemoryValue(Kind, Origin, Value* value, Value* pointer, int32_t offset = 0, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange());
-    
-    int32_t m_offset { 0 };
+    MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer)
+        : MemoryValue(MemoryValueStoreTag, kind, origin, value, pointer)
+    {
+    }
+    template<typename Int, typename = IsLegalOffset<Int>>
+    MemoryValue(Kind kind, Origin origin, Value* value, Value* pointer, Int offset, HeapRange range = HeapRange::top(), HeapRange fenceRange = HeapRange())
+        : MemoryValue(MemoryValueStoreTag, kind, origin, value, pointer, offset, range, fenceRange)
+    {
+    }
+
+    // The above templates forward to these implementations.
+    MemoryValue(MemoryValueLoad, Kind, Type, Origin, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
+    MemoryValue(MemoryValueLoadImplied, Kind, Origin, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
+    MemoryValue(MemoryValueStore, Kind, Origin, Value*, Value* pointer, OffsetType = 0, HeapRange = HeapRange::top(), HeapRange fenceRange = HeapRange());
+
+    OffsetType m_offset { 0 };
     HeapRange m_range { HeapRange::top() };
     HeapRange m_fenceRange { HeapRange() };
 };

Modified: trunk/Source/_javascript_Core/b3/B3MemoryValueInlines.h (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3MemoryValueInlines.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MemoryValueInlines.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -32,7 +32,7 @@
 
 namespace JSC { namespace B3 {
 
-inline bool MemoryValue::isLegalOffset(int32_t offset) const
+inline bool MemoryValue::isLegalOffsetImpl(int32_t offset) const
 {
     // NOTE: This is inline because it constant-folds to true on x86!
     

Modified: trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3MoveConstants.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -209,7 +209,7 @@
                         
                         if (bestPointer) {
                             memoryValue->lastChild() = bestPointer;
-                            memoryValue->setOffset(desiredOffset(bestPointer));
+                            memoryValue->setOffset(static_cast<int32_t>(desiredOffset(bestPointer)));
                         }
                     }
                 } else {
@@ -308,12 +308,16 @@
                 if (offLimits.contains(value))
                     continue;
 
+                auto offset = sizeof(int64_t) * m_constTable.get(key);
+                if (!isRepresentableAs<Value::OffsetType>(offset))
+                    continue;
+
                 Value* tableBase = m_insertionSet.insertIntConstant(
                     valueIndex, value->origin(), pointerType(),
                     bitwise_cast<intptr_t>(m_dataSection));
                 Value* result = m_insertionSet.insert<MemoryValue>(
                     valueIndex, Load, value->type(), value->origin(), tableBase,
-                    sizeof(int64_t) * m_constTable.get(key));
+                    static_cast<Value::OffsetType>(offset));
                 value->replaceWithIdentity(result);
             }
 

Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -1555,7 +1555,7 @@
                 intptr_t offset = address->child(1)->asIntPtr();
                 if (!sumOverflows<intptr_t>(offset, memory->offset())) {
                     offset += memory->offset();
-                    int32_t smallOffset = static_cast<int32_t>(offset);
+                    Value::OffsetType smallOffset = static_cast<Value::OffsetType>(offset);
                     if (smallOffset == offset) {
                         address = address->child(0);
                         memory->lastChild() = address;

Modified: trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3StackmapSpecial.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -270,7 +270,7 @@
         if (arg.base() == Tmp(GPRInfo::callFrameRegister))
             return ValueRep::stack(arg.offset());
         ASSERT(arg.base() == Tmp(MacroAssembler::stackPointerRegister));
-        return ValueRep::stack(arg.offset() - static_cast<int32_t>(code.frameSize()));
+        return ValueRep::stack(arg.offset() - safeCast<Value::OffsetType>(code.frameSize()));
     default:
         ASSERT_NOT_REACHED();
         return ValueRep();

Modified: trunk/Source/_javascript_Core/b3/B3Value.h (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/B3Value.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/B3Value.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -39,6 +39,7 @@
 #include <wtf/CommaPrinter.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/StdLibExtras.h>
 #include <wtf/TriState.h>
 
 namespace JSC { namespace B3 {
@@ -283,6 +284,22 @@
     template<typename Functor>
     void walk(const Functor& functor, PhiChildren* = nullptr);
 
+    // B3 purposefully only represents signed 32-bit offsets because that's what x86 can encode, and
+    // ARM64 cannot encode anything bigger. The IsLegalOffset type trait is then used on B3 Value
+    // methods to prevent implicit conversions by C++ from invalid offset types: these cause compilation
+    // to fail, instead of causing implementation-defined behavior (which often turns to exploit).
+    // OffsetType isn't sufficient to determine offset validity! Each Value opcode further has an
+    // isLegalOffset runtime method used to determine value legality at runtime. This is exposed to users
+    // of B3 to force them to reason about the target's offset.
+    typedef int32_t OffsetType;
+    template<typename Int>
+    struct IsLegalOffset : std::conjunction<
+        typename std::enable_if<std::is_integral<Int>::value>::type,
+        typename std::enable_if<std::is_signed<Int>::value>::type,
+        typename std::enable_if<sizeof(Int) <= sizeof(OffsetType)>::type
+    > { };
+
+
 protected:
     virtual Value* cloneImpl() const;
     

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/air/AirArg.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -41,7 +41,7 @@
 
 namespace JSC { namespace B3 { namespace Air {
 
-Arg Arg::stackAddr(int32_t offsetFromFP, unsigned frameSize, Width width)
+Arg Arg::stackAddrImpl(int32_t offsetFromFP, unsigned frameSize, Width width)
 {
     Arg result = Arg::addr(Air::Tmp(GPRInfo::callFrameRegister), offsetFromFP);
     if (!result.isValidForm(width)) {

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/air/AirArg.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -31,6 +31,7 @@
 #include "B3Bank.h"
 #include "B3Common.h"
 #include "B3Type.h"
+#include "B3Value.h"
 #include "B3Width.h"
 #include <wtf/Optional.h>
 
@@ -534,7 +535,8 @@
         return result;
     }
 
-    static Arg addr(Air::Tmp base, int32_t offset = 0)
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static Arg addr(Air::Tmp base, Int offset)
     {
         ASSERT(base.isGP());
         Arg result;
@@ -544,8 +546,14 @@
         return result;
     }
 
-    static Arg stack(StackSlot* value, int32_t offset = 0)
+    static Arg addr(Air::Tmp base)
     {
+        return addr(base, 0);
+    }
+
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static Arg stack(StackSlot* value, Int offset)
+    {
         Arg result;
         result.m_kind = Stack;
         result.m_offset = bitwise_cast<intptr_t>(value);
@@ -553,16 +561,26 @@
         return result;
     }
 
-    static Arg callArg(int32_t offset)
+    static Arg stack(StackSlot* value)
     {
+        return stack(value, 0);
+    }
+
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static Arg callArg(Int offset)
+    {
         Arg result;
         result.m_kind = CallArg;
         result.m_offset = offset;
         return result;
     }
-    
-    static Arg stackAddr(int32_t offsetFromFP, unsigned frameSize, Width);
 
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static Arg stackAddr(Int offsetFromFP, unsigned frameSize, Width width)
+    {
+        return stackAddrImpl(offsetFromFP, frameSize, width);
+    }
+
     // If you don't pass a Width, this optimistically assumes that you're using the right width.
     static bool isValidScale(unsigned scale, std::optional<Width> width = std::nullopt)
     {
@@ -604,7 +622,8 @@
         }
     }
 
-    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1, int32_t offset = 0)
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale, Int offset)
     {
         ASSERT(base.isGP());
         ASSERT(index.isGP());
@@ -618,6 +637,11 @@
         return result;
     }
 
+    static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1)
+    {
+        return Arg::index(base, index, scale, 0);
+    }
+
     static Arg relCond(MacroAssembler::RelationalCondition condition)
     {
         Arg result;
@@ -925,12 +949,12 @@
 
     bool hasOffset() const { return isMemory(); }
     
-    int32_t offset() const
+    Value::OffsetType offset() const
     {
         if (kind() == Stack)
-            return static_cast<int32_t>(m_scale);
+            return static_cast<Value::OffsetType>(m_scale);
         ASSERT(kind() == Addr || kind() == CallArg || kind() == Index);
-        return static_cast<int32_t>(m_offset);
+        return static_cast<Value::OffsetType>(m_offset);
     }
 
     StackSlot* stackSlot() const
@@ -1141,7 +1165,8 @@
         return false;
     }
 
-    static bool isValidAddrForm(int32_t offset, std::optional<Width> width = std::nullopt)
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static bool isValidAddrForm(Int offset, std::optional<Width> width = std::nullopt)
     {
         if (isX86())
             return true;
@@ -1166,7 +1191,8 @@
         return false;
     }
 
-    static bool isValidIndexForm(unsigned scale, int32_t offset, std::optional<Width> width = std::nullopt)
+    template<typename Int, typename = Value::IsLegalOffset<Int>>
+    static bool isValidIndexForm(unsigned scale, Int offset, std::optional<Width> width = std::nullopt)
     {
         if (!isValidScale(scale, width))
             return false;
@@ -1276,7 +1302,7 @@
     MacroAssembler::TrustedImm32 asTrustedImm32() const
     {
         ASSERT(isImm() || isBitImm());
-        return MacroAssembler::TrustedImm32(static_cast<int32_t>(m_offset));
+        return MacroAssembler::TrustedImm32(static_cast<Value::OffsetType>(m_offset));
     }
 
 #if USE(JSVALUE64)
@@ -1301,7 +1327,7 @@
         if (isSimpleAddr())
             return MacroAssembler::Address(m_base.gpr());
         ASSERT(isAddr());
-        return MacroAssembler::Address(m_base.gpr(), static_cast<int32_t>(m_offset));
+        return MacroAssembler::Address(m_base.gpr(), static_cast<Value::OffsetType>(m_offset));
     }
 
     MacroAssembler::BaseIndex asBaseIndex() const
@@ -1309,7 +1335,7 @@
         ASSERT(isIndex());
         return MacroAssembler::BaseIndex(
             m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
-            static_cast<int32_t>(m_offset));
+            static_cast<Value::OffsetType>(m_offset));
     }
 
     MacroAssembler::RelationalCondition asRelationalCondition() const
@@ -1412,6 +1438,8 @@
     }
 
 private:
+    static Arg stackAddrImpl(int32_t, unsigned, Width);
+
     int64_t m_offset { 0 };
     Kind m_kind { Invalid };
     int32_t m_scale { 1 };

Modified: trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/air/AirLowerStackArgs.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -74,7 +74,7 @@
             Inst& inst = block->at(instIndex);
             inst.forEachArg(
                 [&] (Arg& arg, Arg::Role role, Bank, Width width) {
-                    auto stackAddr = [&] (int32_t offset) -> Arg {
+                    auto stackAddr = [&] (Value::OffsetType offset) -> Arg {
                         Arg result = Arg::stackAddr(offset, code.frameSize(), width);
                         if (!result) {
                             dataLog("FATAL: Could not create stack reference for offset = ", offset, " and width = ", width, "\n");

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -879,10 +879,10 @@
 
     root->appendNew<MemoryValue>(
         proc, Store, Origin(), value,
-        root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot));
+        root->appendNew<ConstPtrValue>(proc, Origin(), &valueSlot), 0);
     root->appendNew<MemoryValue>(
         proc, Store, Origin(), mul,
-        root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot));
+        root->appendNew<ConstPtrValue>(proc, Origin(), &mulSlot), 0);
 
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5421,7 +5421,7 @@
         root->appendNew<Value>(
             proc, Trunc, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
@@ -5437,7 +5437,7 @@
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), value),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
@@ -5457,7 +5457,7 @@
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<ConstPtrValue>(proc, Origin(), value),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &slot));
+        root->appendNew<ConstPtrValue>(proc, Origin(), &slot), 0);
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
 
@@ -5759,7 +5759,7 @@
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5809,7 +5809,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
             root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5832,7 +5832,7 @@
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5921,7 +5921,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
             root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5944,7 +5944,7 @@
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -5994,7 +5994,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, loadOpcode, Origin(), slotPtr),
             root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6015,7 +6015,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6063,7 +6063,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
             root->appendNew<Const64Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6095,7 +6095,7 @@
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6125,7 +6125,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
             root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6279,7 +6279,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6309,7 +6309,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), slotPtr),
             root->appendNew<Const64Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6333,7 +6333,7 @@
             root->appendNew<Value>(
                 proc, Trunc, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6354,13 +6354,13 @@
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 666),
-        otherSlotPtr);
+        otherSlotPtr, 0);
     root->appendNew<MemoryValue>(
         proc, Store, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(),
             load, root->appendNew<Const32Value>(proc, Origin(), amount)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6384,7 +6384,7 @@
                 root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr),
                 root->appendNew<Const32Value>(proc, Origin(), amount)),
             root->appendNew<Const32Value>(proc, Origin(), mask)),
-        slotPtr);
+        slotPtr, 0);
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6408,7 +6408,7 @@
             proc, Sub, Origin(),
             root->appendNew<Const32Value>(proc, Origin(), 0),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), slotPtr)),
-        slotPtr);
+        slotPtr, 0);
     
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6432,7 +6432,7 @@
             proc, Sub, Origin(),
             root->appendNew<ConstPtrValue>(proc, Origin(), 0),
             root->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), slotPtr)),
-        slotPtr);
+        slotPtr, 0);
     
     root->appendNewControlValue(
         proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
@@ -6468,7 +6468,7 @@
         root->appendNew<Value>(
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, static_cast<int32_t>(sizeof(int)))));
 
     CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
 }
@@ -6484,7 +6484,7 @@
         root->appendNew<Value>(
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, 0),
-            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, sizeof(int))));
+            root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), arrayPtr, static_cast<int32_t>(sizeof(int)))));
 
     CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
 }
@@ -6508,7 +6508,7 @@
                 proc, Load, Int32, Origin(),
                 root->appendNew<Value>(
                     proc, Add, Origin(), arrayPtr,
-                    root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
+                    root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))))));
     
     CHECK(compileAndRun<int>(proc) == array[0] + array[1]);
 }
@@ -6531,11 +6531,11 @@
         proc, Load, Int32, Origin(),
         root->appendNew<Value>(
             proc, Add, Origin(), arrayPtr,
-            root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))));
+            root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))));
     root->appendNew<MemoryValue>(
         proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, 0);
     root->appendNew<MemoryValue>(
-        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, sizeof(int));
+        proc, Store, Origin(), theNumberOfTheBeast, otherArrayPtr, static_cast<int32_t>(sizeof(int)));
     root->appendNewControlValue(
         proc, Return, Origin(),
         root->appendNew<Value>(
@@ -6565,7 +6565,7 @@
                 proc, Load, Int32, Origin(),
                 root->appendNew<Value>(
                     proc, Add, Origin(), arrayPtr,
-                    root->appendNew<ConstPtrValue>(proc, Origin(), sizeof(int))))));
+                    root->appendNew<ConstPtrValue>(proc, Origin(), static_cast<int32_t>(sizeof(int)))))));
     
     CHECK(compileAndRun<int>(proc, &array[0]) == array[0] + array[1]);
 }
@@ -6690,7 +6690,7 @@
         root->appendNew<Value>(
             proc, Trunc, Origin(),
             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
-        stack);
+        stack, 0);
     
     root->appendNewControlValue(
         proc, Return, Origin(),
@@ -6760,7 +6760,7 @@
             root->appendNew<MemoryValue>(
                 proc, opcode, type, Origin(),
                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
-                sizeof(InputType)));
+                static_cast<int32_t>(sizeof(InputType))));
 
         CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value)));
     }
@@ -12902,7 +12902,7 @@
             addToDataPointer->appendNew<Value>(
                 proc, Mul, Origin(),
                 addToDataPointer->appendNew<MemoryValue>(
-                    proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t)),
+                    proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t))),
                 addToDataPointer->appendIntConstant(
                     proc, Origin(), pointerType(), sizeof(intptr_t)))));
     addToDataPointer->appendNew<VariableValue>(
@@ -12931,7 +12931,7 @@
             addToCodePointerTaken->appendNew<Value>(
                 proc, Mul, Origin(),
                 addToCodePointerTaken->appendNew<MemoryValue>(
-                    proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t)),
+                    proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t))),
                 addToCodePointerTaken->appendIntConstant(
                     proc, Origin(), pointerType(), sizeof(intptr_t)))));
     addToCodePointerTaken->appendNewControlValue(proc, Jump, Origin(), FrequentedBlock(dispatch));
@@ -12954,7 +12954,7 @@
             addToData->appendNew<MemoryValue>(
                 proc, Load, pointerType(), Origin(), dataPointerValue),
             addToData->appendNew<MemoryValue>(
-                proc, Load, pointerType(), Origin(), codePointerValue, sizeof(intptr_t))),
+                proc, Load, pointerType(), Origin(), codePointerValue, static_cast<int32_t>(sizeof(intptr_t)))),
         dataPointerValue);
     addToData->appendNew<VariableValue>(
         proc, Set, Origin(), codePointer,
@@ -13875,7 +13875,7 @@
     MemoryValue* value = root->appendNew<MemoryValue>(
         proc, trapping(Store), Origin(),
         root->appendNew<Const32Value>(proc, Origin(), 111),
-        root->appendNew<ConstPtrValue>(proc, Origin(), &x));
+        root->appendNew<ConstPtrValue>(proc, Origin(), &x), 0);
     Effects expectedEffects;
     expectedEffects.exitsSideways = true;
     expectedEffects.controlDependent= true;
@@ -13912,7 +13912,7 @@
             proc, Add, Origin(),
             root->appendNew<MemoryValue>(proc, trapping(Load), Int32, Origin(), ptr),
             root->appendNew<Const32Value>(proc, Origin(), 3)),
-        ptr);
+        ptr, 0);
     root->appendNew<Value>(proc, Return, Origin());
     compileAndRun<int>(proc);
     CHECK_EQ(x, 45);
@@ -15228,7 +15228,7 @@
         body->appendNew<Const32Value>(proc, Origin(), sizeof(unsigned)));
     pointer = body->appendNew<Value>(proc, ZExt32, Origin(), pointer);
     body->appendNew<MemoryValue>(proc, Store, Origin(), valueToStore,
-        body->appendNew<WasmAddressValue>(proc, Origin(), pointer, pinnedGPR));
+        body->appendNew<WasmAddressValue>(proc, Origin(), pointer, pinnedGPR), 0);
     UpsilonValue* incUpsilon = body->appendNew<UpsilonValue>(proc, Origin(),
         body->appendNew<Value>(proc, Add, Origin(), indexPhi,
             body->appendNew<Const32Value>(proc, Origin(), 1)));

Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (215406 => 215407)


--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-04-17 08:24:48 UTC (rev 215407)
@@ -60,6 +60,7 @@
 #include "WasmOpcodeOrigin.h"
 #include "WasmThunks.h"
 #include <wtf/Optional.h>
+#include <wtf/StdLibExtras.h>
 
 void dumpProcedure(void* ptr)
 {
@@ -237,7 +238,7 @@
 
     void emitChecksForModOrDiv(B3::Opcode, ExpressionType left, ExpressionType right);
 
-    void fixupPointerPlusOffset(ExpressionType&, uint32_t&);
+    int32_t WARN_UNUSED_RETURN fixupPointerPlusOffset(ExpressionType&, uint32_t);
 
     Value* materializeWasmContext(Procedure&, BasicBlock*);
     void restoreWasmContext(Procedure&, BasicBlock*, Value*);
@@ -261,12 +262,13 @@
 };
 
 // Memory accesses in WebAssembly have unsigned 32-bit offsets, whereas they have signed 32-bit offsets in B3.
-void B3IRGenerator::fixupPointerPlusOffset(ExpressionType& ptr, uint32_t& offset)
+int32_t B3IRGenerator::fixupPointerPlusOffset(ExpressionType& ptr, uint32_t offset)
 {
     if (static_cast<uint64_t>(offset) > static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
         ptr = m_currentBlock->appendNew<Value>(m_proc, Add, origin(), ptr, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), offset));
-        offset = 0;
+        return 0;
     }
+    return offset;
 }
 
 Value* B3IRGenerator::materializeWasmContext(Procedure& proc, BasicBlock* block)
@@ -507,10 +509,10 @@
 
 auto B3IRGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
 {
-    Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfMemory());
+    Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfMemory()));
 
     static_assert(sizeof(decltype(static_cast<JSWebAssemblyInstance*>(nullptr)->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
-    Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, JSWebAssemblyMemory::offsetOfSize());
+    Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, safeCast<int32_t>(JSWebAssemblyMemory::offsetOfSize()));
     
     constexpr uint32_t shiftValue = 16;
     static_assert(PageCount::pageSize == 1 << shiftValue, "This must hold for the code below to be correct.");
@@ -531,8 +533,8 @@
 
 auto B3IRGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult
 {
-    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
-    result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), origin(), globalsArray, index * sizeof(Register));
+    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfGlobals()));
+    result = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, toB3Type(m_info.globals[index].type), origin(), globalsArray, safeCast<int32_t>(index * sizeof(Register)));
     return { };
 }
 
@@ -539,8 +541,8 @@
 auto B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialResult
 {
     ASSERT(toB3Type(m_info.globals[index].type) == value->type());
-    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfGlobals());
-    m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, index * sizeof(Register));
+    Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfGlobals()));
+    m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, safeCast<int32_t>(index * sizeof(Register)));
     return { };
 }
 
@@ -555,7 +557,7 @@
         m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), pointer, m_memorySizeGPR, sizeOfOperation + offset - 1, m_info.memory.maximum());
         break;
     case MemoryMode::Signaling:
-        // 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.
+        // 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.
         if (offset >= Memory::fastMappedRedzoneBytes())
             m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), pointer, InvalidGPRReg, sizeOfOperation + offset - 1, m_info.memory.maximum());
         break;
@@ -598,9 +600,9 @@
     return memoryOp;
 }
 
-inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, ExpressionType pointer, uint32_t offset)
+inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, ExpressionType pointer, uint32_t uoffset)
 {
-    fixupPointerPlusOffset(pointer, offset);
+    int32_t offset = fixupPointerPlusOffset(pointer, uoffset);
 
     switch (op) {
     case LoadOpType::I32Load8S: {
@@ -737,9 +739,9 @@
 }
 
 
-inline void B3IRGenerator::emitStoreOp(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t offset)
+inline void B3IRGenerator::emitStoreOp(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t uoffset)
 {
-    fixupPointerPlusOffset(pointer, offset);
+    int32_t offset = fixupPointerPlusOffset(pointer, uoffset);
 
     switch (op) {
     case StoreOpType::I64Store8:
@@ -940,8 +942,8 @@
 
     if (m_info.isImportedFunctionFromFunctionIndexSpace(functionIndex)) {
         // 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
-        Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfImportFunction(functionIndex));
-        Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, JSCell::typeInfoTypeOffset());
+        Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfImportFunction(functionIndex)));
+        Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, safeCast<int32_t>(JSCell::typeInfoTypeOffset()));
         Value* isWasmCall = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), jsTypeOfImport, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), WebAssemblyFunctionType));
 
         BasicBlock* isWasmBlock = m_proc.addBlock();
@@ -971,9 +973,9 @@
         // implement the IC to be over Wasm::Context*.
         // https://bugs.webkit.org/show_bug.cgi?id=170375
         Value* codeBlock = isJSBlock->appendNew<MemoryValue>(m_proc,
-            Load, pointerType(), origin(), m_instanceValue, JSWebAssemblyInstance::offsetOfCodeBlock());
+            Load, pointerType(), origin(), m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfCodeBlock()));
         Value* jumpDestination = isJSBlock->appendNew<MemoryValue>(m_proc,
-            Load, pointerType(), origin(), codeBlock, JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex));
+            Load, pointerType(), origin(), codeBlock, safeCast<int32_t>(JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex)));
         Value* jsCallResult = wasmCallingConvention().setupCall(m_proc, isJSBlock, origin(), args, toB3Type(returnType),
             [&] (PatchpointValue* patchpoint) {
                 patchpoint->effects.writesPinned = true;
@@ -1029,11 +1031,11 @@
     ExpressionType callableFunctionBufferSize;
     {
         ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            m_instanceValue, JSWebAssemblyInstance::offsetOfTable());
+            m_instanceValue, safeCast<int32_t>(JSWebAssemblyInstance::offsetOfTable()));
         callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            table, JSWebAssemblyTable::offsetOfFunctions());
+            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfFunctions()));
         callableFunctionBufferSize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(),
-            table, JSWebAssemblyTable::offsetOfSize());
+            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfSize()));
     }
 
     // Check the index we are looking for is valid.
@@ -1054,7 +1056,7 @@
 
     // Check that the CallableFunction is initialized. We trap if it isn't. An "invalid" SignatureIndex indicates it's not initialized.
     static_assert(sizeof(CallableFunction::signatureIndex) == sizeof(uint32_t), "Load codegen assumes i32");
-    ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signatureIndex));
+    ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, signatureIndex)));
     {
         CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
             m_currentBlock->appendNew<Value>(m_proc, Equal, origin(),
@@ -1077,7 +1079,7 @@
         });
     }
 
-    ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, code));
+    ExpressionType calleeCode = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, code)));
 
     Type returnType = signature.returnType();
     result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, origin(), args, toB3Type(returnType),

Modified: trunk/Source/WTF/ChangeLog (215406 => 215407)


--- trunk/Source/WTF/ChangeLog	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/WTF/ChangeLog	2017-04-17 08:24:48 UTC (rev 215407)
@@ -1,3 +1,17 @@
+2017-04-17  JF Bastien  <jfbast...@apple.com>
+
+        B3: don't allow unsigned offsets in Value
+        https://bugs.webkit.org/show_bug.cgi?id=170692
+
+        Reviewed by Filip Pizlo.
+
+        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:
+
 2017-04-14  Mark Lam  <mark....@apple.com>
 
         Update architectures in xcconfig files.

Modified: trunk/Source/WTF/wtf/StdLibExtras.h (215406 => 215407)


--- trunk/Source/WTF/wtf/StdLibExtras.h	2017-04-17 06:02:33 UTC (rev 215406)
+++ trunk/Source/WTF/wtf/StdLibExtras.h	2017-04-17 08:24:48 UTC (rev 215407)
@@ -30,6 +30,7 @@
 #include <chrono>
 #include <cstring>
 #include <memory>
+#include <type_traits>
 #include <wtf/Assertions.h>
 #include <wtf/CheckedArithmetic.h>
 #include <wtf/Compiler.h>
@@ -510,6 +511,15 @@
     return move(forward<T>(value));
 }
 
+#if __cplusplus < 201703L && (!defined(_MSC_FULL_VER) || _MSC_FULL_VER < 190023918)
+template<class...> struct wtf_conjunction_impl;
+template<> struct wtf_conjunction_impl<> : true_type { };
+template<class B0> struct wtf_conjunction_impl<B0> : B0 { };
+template<class B0, class B1> struct wtf_conjunction_impl<B0, B1> : conditional<B0::value, B1, B0>::type { };
+template<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 { };
+template<class... _Args> struct conjunction : wtf_conjunction_impl<_Args...> { };
+#endif
+
 } // namespace std
 
 #define WTFMove(value) std::move<WTF::CheckMoveParameter>(value)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to