Title: [227874] trunk/Source
Revision
227874
Author
[email protected]
Date
2018-01-30 21:23:52 -0800 (Tue, 30 Jan 2018)

Log Message

Apply poisoning to TypedArray vector pointers.
https://bugs.webkit.org/show_bug.cgi?id=182155
<rdar://problem/36286266>

Reviewed by JF Bastien.

Source/_javascript_Core:

The TypeArray's vector pointer is now poisoned.  The poison value is chosen based
on a TypeArray's jsType.  The JSType must be between FirstTypedArrayType and
LastTypedArrayType.  At runtime, we enforce that the index is well-behaved by
masking it against TypedArrayPoisonIndexMask.  TypedArrayPoisonIndexMask (16) is
the number of TypedArray types (10) rounded up to the next power of 2.
Accordingly, we reserve an array of TypedArrayPoisonIndexMask poisons so that we
can use index masking on the index, and be guaranteed that the masked index will
be within bounds of the poisons array.

1. Fixed both DFG and FTL versions of compileGetTypedArrayByteOffset() to not
   do any unnecessary work if the TypedArray vector is null.

   FTL's cagedMayBeNull() is no longer needed because it is only used by
   compileGetTypedArrayByteOffset(), and we need to enhance it to handle unpoisoning
   in a TypedArray specific way.  So, might as well do the work inline in
   compileGetTypedArrayByteOffset() instead.

2. Removed an unnecessary null-check in DFGSpeculativeJIT's compileNewTypedArrayWithSize()
   because there's already a null check above it that ensures that sizeGPR is
   never null.

3. In LLInt's _llint_op_get_by_val, move the TypedArray length check before the
   loading of the vector for unpoisoning and uncaging.  We don't need the vector
   if the length is 0.

Implementation notes on the need to null check the TypeArray vector:

1. DFG::SpeculativeJIT::jumpForTypedArrayIsNeuteredIfOutOfBounds() does not need a
   m_poisonedVector null check because the function is a null check.

2. DFG::SpeculativeJIT::compileGetIndexedPropertyStorage() does not need a
   m_poisonedVector null check because it is followed by a call to
   cageTypedArrayStorage() which assumes that storageReg cannot be null.

3. DFG::SpeculativeJIT::compileGetTypedArrayByteOffset() already has a
   m_poisonedVector null check.

4. DFG::SpeculativeJIT::compileNewTypedArrayWithSize() does not need a vector null
   check because the poisoning code is preceded by a sizeGPR null check, which
   ensures that the storageGPR (vector to be poisoned) is not null.

5. FTL's compileGetIndexedPropertyStorage() does not need a m_poisonedVector null
   check because it is followed by a call to caged() which assumes that the
   vector cannot be null.

6. FTL's compileGetTypedArrayByteOffset() already has a m_poisonedVector null check.

7. FTL's compileNewTypedArray() does not need a vector null check because the
   poisoning code is preceded by a size null check, which ensures that the
   storage (vector to be poisoned) is not null.

8. FTL's speculateTypedArrayIsNotNeutered() does not need a
   m_poisonedVector null check because the function is a null check.

9. IntrinsicGetterAccessCase::emitIntrinsicGetter()'s TypedArrayByteOffsetIntrinsic
   case needs a null check so that it does not try to unpoison a null vector.

10. JIT::emitIntTypedArrayGetByVal() does not need a vector null check because
    we already do a length check even before loading the vector.

11. JIT::emitFloatTypedArrayGetByVal() does not need a vector null check because
    we already do a length check even before loading the vector.

12. JIT::emitIntTypedArrayPutByVal() does not need a vector null check because
    we already do a length check even before loading the vector.

13. JIT::emitFloatTypedArrayPutByVal() does not need a vector null check because
    we already do a length check even before loading the vector.

14. LLInt's loadTypedArrayCaged() does not need a vector null check because its
    client will do a TypedArray length check before calling it.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::checkArray):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasArrayMode):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::jumpForTypedArrayIsNeuteredIfOutOfBounds):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
(JSC::DFG::SpeculativeJIT::compileGetTypedArrayByteOffset):
(JSC::DFG::SpeculativeJIT::compileNewTypedArrayWithSize):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetIndexedPropertyStorage):
(JSC::FTL::DFG::LowerDFGToB3::compileGetTypedArrayByteOffset):
(JSC::FTL::DFG::LowerDFGToB3::compileNewTypedArray):
(JSC::FTL::DFG::LowerDFGToB3::speculateTypedArrayIsNotNeutered):
(JSC::FTL::DFG::LowerDFGToB3::cagedMayBeNull): Deleted.
* jit/IntrinsicEmitter.cpp:
(JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitIntTypedArrayGetByVal):
(JSC::JIT::emitFloatTypedArrayGetByVal):
(JSC::JIT::emitIntTypedArrayPutByVal):
(JSC::JIT::emitFloatTypedArrayPutByVal):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/arm64.rb:
* offlineasm/x86.rb:
* runtime/CagedBarrierPtr.h:
* runtime/JSArrayBufferView.cpp:
(JSC::JSArrayBufferView::JSArrayBufferView):
(JSC::JSArrayBufferView::finalize):
(JSC::JSArrayBufferView::neuter):
* runtime/JSArrayBufferView.h:
(JSC::JSArrayBufferView::vector const):
(JSC::JSArrayBufferView::offsetOfPoisonedVector):
(JSC::JSArrayBufferView::poisonFor):
(JSC::JSArrayBufferView::Poison::key):
(JSC::JSArrayBufferView::offsetOfVector): Deleted.
* runtime/JSCPoison.cpp:
(JSC::initializePoison):
* runtime/JSCPoison.h:
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::estimatedSize):
(JSC::JSGenericTypedArrayView<Adaptor>::visitChildren):
(JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory):
* runtime/JSObject.h:

Source/WTF:

1. Added the ability to poison a CagedPtr.

2. Prevent CagedPtr from being implicitly instantiated, and add operator= methods
   instead.  This is because implicitly instantiated CagedPtrs with a poisoned
   trait may silently use a wrong poison value.

* wtf/CagedPtr.h:
(WTF::CagedPtr::CagedPtr):
(WTF::CagedPtr::get const):
(WTF::CagedPtr::operator=):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (227873 => 227874)


--- trunk/Source/_javascript_Core/ChangeLog	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,3 +1,130 @@
+2018-01-30  Mark Lam  <[email protected]>
+
+        Apply poisoning to TypedArray vector pointers.
+        https://bugs.webkit.org/show_bug.cgi?id=182155
+        <rdar://problem/36286266>
+
+        Reviewed by JF Bastien.
+
+        The TypeArray's vector pointer is now poisoned.  The poison value is chosen based
+        on a TypeArray's jsType.  The JSType must be between FirstTypedArrayType and
+        LastTypedArrayType.  At runtime, we enforce that the index is well-behaved by
+        masking it against TypedArrayPoisonIndexMask.  TypedArrayPoisonIndexMask (16) is
+        the number of TypedArray types (10) rounded up to the next power of 2.
+        Accordingly, we reserve an array of TypedArrayPoisonIndexMask poisons so that we
+        can use index masking on the index, and be guaranteed that the masked index will
+        be within bounds of the poisons array.
+
+        1. Fixed both DFG and FTL versions of compileGetTypedArrayByteOffset() to not
+           do any unnecessary work if the TypedArray vector is null.
+
+           FTL's cagedMayBeNull() is no longer needed because it is only used by
+           compileGetTypedArrayByteOffset(), and we need to enhance it to handle unpoisoning
+           in a TypedArray specific way.  So, might as well do the work inline in
+           compileGetTypedArrayByteOffset() instead.
+
+        2. Removed an unnecessary null-check in DFGSpeculativeJIT's compileNewTypedArrayWithSize()
+           because there's already a null check above it that ensures that sizeGPR is
+           never null.
+
+        3. In LLInt's _llint_op_get_by_val, move the TypedArray length check before the
+           loading of the vector for unpoisoning and uncaging.  We don't need the vector
+           if the length is 0.
+
+        Implementation notes on the need to null check the TypeArray vector:
+
+        1. DFG::SpeculativeJIT::jumpForTypedArrayIsNeuteredIfOutOfBounds() does not need a
+           m_poisonedVector null check because the function is a null check.
+
+        2. DFG::SpeculativeJIT::compileGetIndexedPropertyStorage() does not need a
+           m_poisonedVector null check because it is followed by a call to
+           cageTypedArrayStorage() which assumes that storageReg cannot be null.
+
+        3. DFG::SpeculativeJIT::compileGetTypedArrayByteOffset() already has a
+           m_poisonedVector null check.
+
+        4. DFG::SpeculativeJIT::compileNewTypedArrayWithSize() does not need a vector null
+           check because the poisoning code is preceded by a sizeGPR null check, which
+           ensures that the storageGPR (vector to be poisoned) is not null.
+
+        5. FTL's compileGetIndexedPropertyStorage() does not need a m_poisonedVector null
+           check because it is followed by a call to caged() which assumes that the
+           vector cannot be null.
+
+        6. FTL's compileGetTypedArrayByteOffset() already has a m_poisonedVector null check.
+
+        7. FTL's compileNewTypedArray() does not need a vector null check because the
+           poisoning code is preceded by a size null check, which ensures that the
+           storage (vector to be poisoned) is not null.
+
+        8. FTL's speculateTypedArrayIsNotNeutered() does not need a
+           m_poisonedVector null check because the function is a null check.
+
+        9. IntrinsicGetterAccessCase::emitIntrinsicGetter()'s TypedArrayByteOffsetIntrinsic
+           case needs a null check so that it does not try to unpoison a null vector.
+
+        10. JIT::emitIntTypedArrayGetByVal() does not need a vector null check because
+            we already do a length check even before loading the vector.
+
+        11. JIT::emitFloatTypedArrayGetByVal() does not need a vector null check because
+            we already do a length check even before loading the vector.
+
+        12. JIT::emitIntTypedArrayPutByVal() does not need a vector null check because
+            we already do a length check even before loading the vector.
+
+        13. JIT::emitFloatTypedArrayPutByVal() does not need a vector null check because
+            we already do a length check even before loading the vector.
+
+        14. LLInt's loadTypedArrayCaged() does not need a vector null check because its
+            client will do a TypedArray length check before calling it.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::checkArray):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasArrayMode):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::jumpForTypedArrayIsNeuteredIfOutOfBounds):
+        (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
+        (JSC::DFG::SpeculativeJIT::compileGetTypedArrayByteOffset):
+        (JSC::DFG::SpeculativeJIT::compileNewTypedArrayWithSize):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetIndexedPropertyStorage):
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetTypedArrayByteOffset):
+        (JSC::FTL::DFG::LowerDFGToB3::compileNewTypedArray):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateTypedArrayIsNotNeutered):
+        (JSC::FTL::DFG::LowerDFGToB3::cagedMayBeNull): Deleted.
+        * jit/IntrinsicEmitter.cpp:
+        (JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emitIntTypedArrayGetByVal):
+        (JSC::JIT::emitFloatTypedArrayGetByVal):
+        (JSC::JIT::emitIntTypedArrayPutByVal):
+        (JSC::JIT::emitFloatTypedArrayPutByVal):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * offlineasm/arm64.rb:
+        * offlineasm/x86.rb:
+        * runtime/CagedBarrierPtr.h:
+        * runtime/JSArrayBufferView.cpp:
+        (JSC::JSArrayBufferView::JSArrayBufferView):
+        (JSC::JSArrayBufferView::finalize):
+        (JSC::JSArrayBufferView::neuter):
+        * runtime/JSArrayBufferView.h:
+        (JSC::JSArrayBufferView::vector const):
+        (JSC::JSArrayBufferView::offsetOfPoisonedVector):
+        (JSC::JSArrayBufferView::poisonFor):
+        (JSC::JSArrayBufferView::Poison::key):
+        (JSC::JSArrayBufferView::offsetOfVector): Deleted.
+        * runtime/JSCPoison.cpp:
+        (JSC::initializePoison):
+        * runtime/JSCPoison.h:
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::estimatedSize):
+        (JSC::JSGenericTypedArrayView<Adaptor>::visitChildren):
+        (JSC::JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory):
+        * runtime/JSObject.h:
+
 2018-01-30  Fujii Hironori  <[email protected]>
 
         [Win] Warning fix.

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -2870,6 +2870,7 @@
                 m_indexInBlock, SpecNone, GetButterfly, origin, Edge(array, CellUse));
         }
         
+        ASSERT(arrayMode.type() == Array::String || arrayMode.typedArrayType() != NotTypedArray);
         return m_insertionSet.insertNode(
             m_indexInBlock, SpecNone, GetIndexedPropertyStorage, origin,
             OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -2845,7 +2845,7 @@
 
             JITCompiler::Jump hasNullVector = m_jit.branchTestPtr(
                 MacroAssembler::Zero,
-                MacroAssembler::Address(base, JSArrayBufferView::offsetOfVector()));
+                MacroAssembler::Address(base, JSArrayBufferView::offsetOfPoisonedVector()));
             speculationCheck(Uncountable, JSValueSource(), node, hasNullVector);
             notWasteful.link(&m_jit);
         }
@@ -6354,9 +6354,13 @@
         break;
         
     default:
-        ASSERT(isTypedView(node->arrayMode().typedArrayType()));
+        auto typedArrayType = node->arrayMode().typedArrayType();
+        ASSERT_UNUSED(typedArrayType, isTypedView(typedArrayType));
 
-        m_jit.loadPtr(JITCompiler::Address(baseReg, JSArrayBufferView::offsetOfVector()), storageReg);
+        m_jit.loadPtr(JITCompiler::Address(baseReg, JSArrayBufferView::offsetOfPoisonedVector()), storageReg);
+#if ENABLE(POISON)
+        m_jit.xorPtr(JITCompiler::TrustedImmPtr(JSArrayBufferView::poisonFor(typedArrayType)), storageReg);
+#endif
         cageTypedArrayStorage(storageReg);
         break;
     }
@@ -6373,22 +6377,45 @@
     GPRReg baseGPR = base.gpr();
     GPRReg vectorGPR = vector.gpr();
     GPRReg dataGPR = data.gpr();
-    
+    ASSERT(baseGPR != vectorGPR);
+    ASSERT(baseGPR != dataGPR);
+    ASSERT(vectorGPR != dataGPR);
+
+#if ENABLE(POISON)
+    GPRTemporary poison(this);
+    GPRTemporary index(this);
+    GPRReg poisonGPR = poison.gpr();
+    GPRReg indexGPR = index.gpr();
+    GPRReg arrayBufferGPR = poisonGPR;
+#else
+    GPRReg arrayBufferGPR = dataGPR;
+#endif
+
     JITCompiler::Jump emptyByteOffset = m_jit.branch32(
         MacroAssembler::NotEqual,
         MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()),
         TrustedImm32(WastefulTypedArray));
 
+    m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfPoisonedVector()), vectorGPR);
+    JITCompiler::Jump nullVector = m_jit.branchTestPtr(JITCompiler::Zero, vectorGPR);
+
     m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), dataGPR);
     m_jit.cage(Gigacage::JSValue, dataGPR);
-    m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), vectorGPR);
-    JITCompiler::Jump nullVector = m_jit.branchTestPtr(JITCompiler::Zero, vectorGPR);
+
+#if ENABLE(POISON)
+    m_jit.load8(JITCompiler::Address(baseGPR, JSCell::typeInfoTypeOffset()), indexGPR);
+    m_jit.move(JITCompiler::TrustedImmPtr(&g_typedArrayPoisons), poisonGPR);
+    m_jit.sub32(JITCompiler::TrustedImm32(FirstTypedArrayType), indexGPR);
+    m_jit.and32(JITCompiler::TrustedImm32(TypedArrayPoisonIndexMask), indexGPR);
+    m_jit.loadPtr(JITCompiler::BaseIndex(poisonGPR, indexGPR, JITCompiler::timesPtr()), poisonGPR);
+    m_jit.xorPtr(poisonGPR, vectorGPR);
+#endif
     cageTypedArrayStorage(vectorGPR);
 
-    m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), dataGPR);
+    m_jit.loadPtr(MacroAssembler::Address(dataGPR, Butterfly::offsetOfArrayBuffer()), arrayBufferGPR);
     // FIXME: This needs caging.
     // https://bugs.webkit.org/show_bug.cgi?id=175515
-    m_jit.loadPtr(MacroAssembler::Address(dataGPR, ArrayBuffer::offsetOfData()), dataGPR);
+    m_jit.loadPtr(MacroAssembler::Address(arrayBufferGPR, ArrayBuffer::offsetOfData()), dataGPR);
     m_jit.subPtr(dataGPR, vectorGPR);
     
     JITCompiler::Jump done = m_jit.jump();
@@ -9025,8 +9052,7 @@
     m_jit.emitAllocateVariableSized(
         storageGPR, m_jit.vm()->primitiveGigacageAuxiliarySpace, scratchGPR, scratchGPR,
         scratchGPR2, slowCases);
-    
-    MacroAssembler::Jump done = m_jit.branchTest32(MacroAssembler::Zero, sizeGPR);
+
     m_jit.move(sizeGPR, scratchGPR);
     if (elementSize(typedArrayType) != 4) {
         if (elementSize(typedArrayType) > 4)
@@ -9044,7 +9070,6 @@
         TrustedImm32(0),
         MacroAssembler::BaseIndex(storageGPR, scratchGPR, MacroAssembler::TimesFour));
     m_jit.branchTest32(MacroAssembler::NonZero, scratchGPR).linkTo(loop, &m_jit);
-    done.link(&m_jit);
 
     auto butterfly = TrustedImmPtr(nullptr);
     m_jit.emitComputeButterflyIndexingMask(sizeGPR, scratchGPR, indexingMaskGPR);
@@ -9052,9 +9077,17 @@
         resultGPR, TrustedImmPtr(structure), butterfly, indexingMaskGPR, scratchGPR, scratchGPR2,
         slowCases);
 
+#if ENABLE(POISON)
+    m_jit.move(storageGPR, scratchGPR);
+    m_jit.xorPtr(TrustedImmPtr(JSArrayBufferView::poisonFor(typedArrayType)), scratchGPR);
     m_jit.storePtr(
+        scratchGPR,
+        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfPoisonedVector()));
+#else
+    m_jit.storePtr(
         storageGPR,
-        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector()));
+        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfPoisonedVector()));
+#endif
     m_jit.store32(
         sizeGPR,
         MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength()));

Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (227873 => 227874)


--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -59,7 +59,7 @@
     macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \
     macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \
     macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \
-    macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \
+    macro(JSArrayBufferView_poisonedVector, JSArrayBufferView::offsetOfPoisonedVector()) \
     macro(JSCell_cellState, JSCell::cellStateOffset()) \
     macro(JSCell_header, 0) \
     macro(JSCell_indexingTypeAndMisc, JSCell::indexingTypeAndMiscOffset()) \
@@ -149,7 +149,8 @@
     macro(variables, 0, sizeof(Register)) \
     macro(HasOwnPropertyCache, 0, sizeof(HasOwnPropertyCache::Entry)) \
     macro(JSFixedArray_buffer, JSFixedArray::offsetOfData(), sizeof(EncodedJSValue)) \
-    
+    macro(TypedArrayPoisons, 0, sizeof(uintptr_t)) \
+
 #define FOR_EACH_NUMBERED_ABSTRACT_HEAP(macro) \
     macro(properties)
     

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -3473,7 +3473,14 @@
         }
 
         DFG_ASSERT(m_graph, m_node, isTypedView(m_node->arrayMode().typedArrayType()));
-        setStorage(caged(Gigacage::Primitive, m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector)));
+        LValue poisonedVector = m_out.loadPtr(cell, m_heaps.JSArrayBufferView_poisonedVector);
+#if ENABLE(POISON)
+        auto typedArrayType = m_node->arrayMode().typedArrayType();
+        LValue vector = m_out.bitXor(m_out.constIntPtr(JSArrayBufferView::poisonFor(typedArrayType)), poisonedVector);
+#else
+        LValue vector = poisonedVector;
+#endif
+        setStorage(caged(Gigacage::Primitive, vector));
     }
     
     void compileCheckArray()
@@ -3495,6 +3502,7 @@
 
         LBasicBlock simpleCase = m_out.newBlock();
         LBasicBlock wastefulCase = m_out.newBlock();
+        LBasicBlock notNull = m_out.newBlock();
         LBasicBlock continuation = m_out.newBlock();
         
         LValue mode = m_out.load32(basePtr, m_heaps.JSArrayBufferView_mode);
@@ -3508,13 +3516,27 @@
 
         m_out.jump(continuation);
 
-        m_out.appendTo(wastefulCase, continuation);
+        m_out.appendTo(wastefulCase, notNull);
 
-        LValue vectorPtr = cagedMayBeNull(
-            Gigacage::Primitive,
-            m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_vector));
+        LValue poisonedVector = m_out.loadPtr(basePtr, m_heaps.JSArrayBufferView_poisonedVector);
+        ValueFromBlock nullVectorOut = m_out.anchor(poisonedVector);
+        m_out.branch(poisonedVector, unsure(notNull), unsure(continuation));
+
+        m_out.appendTo(notNull, continuation);
+
         LValue butterflyPtr = caged(Gigacage::JSValue, m_out.loadPtr(basePtr, m_heaps.JSObject_butterfly));
         LValue arrayBufferPtr = m_out.loadPtr(butterflyPtr, m_heaps.Butterfly_arrayBuffer);
+
+#if ENABLE(POISON)
+        LValue jsType = m_out.load8ZeroExt32(basePtr, m_heaps.JSCell_typeInfoType);
+        LValue typeIndex = m_out.sub(jsType, m_out.constInt32(FirstTypedArrayType));
+        LValue maskedTypeIndex = m_out.zeroExtPtr(m_out.bitAnd(typeIndex, m_out.constInt32(TypedArrayPoisonIndexMask)));
+        LValue poisonsBasePtr = m_out.constIntPtr(&g_typedArrayPoisons);
+        LValue poison = m_out.loadPtr(m_out.baseIndex(m_heaps.TypedArrayPoisons, poisonsBasePtr, maskedTypeIndex));
+        poisonedVector = m_out.bitXor(poisonedVector, poison);
+#endif
+        LValue vectorPtr = caged(Gigacage::Primitive, poisonedVector);
+
         // FIXME: This needs caging.
         // https://bugs.webkit.org/show_bug.cgi?id=175515
         LValue dataPtr = m_out.loadPtr(arrayBufferPtr, m_heaps.ArrayBuffer_data);
@@ -3524,7 +3546,7 @@
         m_out.jump(continuation);
         m_out.appendTo(continuation, lastNext);
 
-        setInt32(m_out.castToInt32(m_out.phi(pointerType(), simpleOut, wastefulOut)));
+        setInt32(m_out.castToInt32(m_out.phi(pointerType(), simpleOut, nullVectorOut, wastefulOut)));
     }
 
     void compileGetPrototypeOf()
@@ -5637,7 +5659,10 @@
             LValue fastResultValue =
                 allocateObject<JSArrayBufferView>(structure, m_out.intPtrZero, indexingMask, slowCase);
 
-            m_out.storePtr(storage, fastResultValue, m_heaps.JSArrayBufferView_vector);
+#if ENABLE(POISON)
+            storage = m_out.bitXor(m_out.constIntPtr(JSArrayBufferView::poisonFor(typedArrayType)), storage);
+#endif
+            m_out.storePtr(storage, fastResultValue, m_heaps.JSArrayBufferView_poisonedVector);
             m_out.store32(size, fastResultValue, m_heaps.JSArrayBufferView_length);
             m_out.store32(m_out.constInt32(FastTypedArray), fastResultValue, m_heaps.JSArrayBufferView_mode);
             
@@ -12796,24 +12821,6 @@
         return m_out.opaque(result);
     }
     
-    LValue cagedMayBeNull(Gigacage::Kind kind, LValue ptr)
-    {
-        LBasicBlock notNull = m_out.newBlock();
-        LBasicBlock continuation = m_out.newBlock();
-        
-        LBasicBlock lastNext = m_out.insertNewBlocksBefore(notNull);
-        
-        ValueFromBlock nullResult = m_out.anchor(ptr);
-        m_out.branch(ptr, unsure(notNull), unsure(continuation));
-        
-        m_out.appendTo(notNull, continuation);
-        ValueFromBlock notNullResult = m_out.anchor(caged(kind, ptr));
-        m_out.jump(continuation);
-        
-        m_out.appendTo(continuation, lastNext);
-        return m_out.phi(pointerType(), nullResult, notNullResult);
-    }
-    
     void buildSwitch(SwitchData* data, LType type, LValue switchValue)
     {
         ASSERT(type == pointerType() || type == Int32);
@@ -15015,7 +15022,7 @@
             unsure(isWasteful), unsure(continuation));
 
         LBasicBlock lastNext = m_out.appendTo(isWasteful, continuation);
-        LValue vector = m_out.loadPtr(base, m_heaps.JSArrayBufferView_vector);
+        LValue vector = m_out.loadPtr(base, m_heaps.JSArrayBufferView_poisonedVector);
         speculate(Uncountable, jsValueValue(vector), m_node, m_out.isZero64(vector));
         m_out.jump(continuation);
 

Modified: trunk/Source/_javascript_Core/jit/IntrinsicEmitter.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/jit/IntrinsicEmitter.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/jit/IntrinsicEmitter.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -107,22 +107,31 @@
     case TypedArrayByteOffsetIntrinsic: {
         GPRReg scratchGPR = state.scratchGPR;
 
-        CCallHelpers::Jump emptyByteOffset = jit.branch32(
-            MacroAssembler::NotEqual,
+        CCallHelpers::Jump notEmptyByteOffset = jit.branch32(
+            MacroAssembler::Equal,
             MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfMode()),
             TrustedImm32(WastefulTypedArray));
 
+        jit.move(TrustedImmPtr(0), valueGPR);
+        CCallHelpers::Jump done = jit.jump();
+
+        notEmptyByteOffset.link(&jit);
+
+        // We need to load the butterfly before the vector because baseGPR and valueGPR
+        // can be the same register.
         jit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
-        jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfVector()), valueGPR);
+        jit.loadPtr(MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfPoisonedVector()), valueGPR);
+        CCallHelpers::Jump nullVector = jit.branchTestPtr(MacroAssembler::Zero, valueGPR);
+
+#if ENABLE(POISON)
+        auto typedArrayType = structure()->classInfo()->typedArrayStorageType;
+        jit.xorPtr(TrustedImmPtr(JSArrayBufferView::poisonFor(typedArrayType)), valueGPR);
+#endif
         jit.loadPtr(MacroAssembler::Address(scratchGPR, Butterfly::offsetOfArrayBuffer()), scratchGPR);
         jit.loadPtr(MacroAssembler::Address(scratchGPR, ArrayBuffer::offsetOfData()), scratchGPR);
         jit.subPtr(scratchGPR, valueGPR);
 
-        CCallHelpers::Jump done = jit.jump();
-        
-        emptyByteOffset.link(&jit);
-        jit.move(TrustedImmPtr(0), valueGPR);
-        
+        nullVector.link(&jit);
         done.link(&jit);
         
         jit.boxInt32(valueGPR, valueRegs);

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1457,9 +1457,9 @@
     return slowCases;
 }
 
-JIT::JumpList JIT::emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, TypedArrayType type)
+JIT::JumpList JIT::emitIntTypedArrayGetByVal(Instruction*, PatchableJump& badType, TypedArrayType typeArrayType)
 {
-    ASSERT(isInt(type));
+    ASSERT(isInt(typeArrayType));
     
     // The best way to test the array type is to use the classInfo. We need to do so without
     // clobbering the register that holds the indexing type, base, and property.
@@ -1480,22 +1480,26 @@
 #endif
     
     JumpList slowCases;
-    
+    JSType jsType = typeForTypedArrayType(typeArrayType);
+
     load8(Address(base, JSCell::typeInfoTypeOffset()), scratch);
-    badType = patchableBranch32(NotEqual, scratch, TrustedImm32(typeForTypedArrayType(type)));
+    badType = patchableBranch32(NotEqual, scratch, TrustedImm32(jsType));
     slowCases.append(branch32(AboveOrEqual, property, Address(base, JSArrayBufferView::offsetOfLength())));
-    loadPtr(Address(base, JSArrayBufferView::offsetOfVector()), scratch);
+    loadPtr(Address(base, JSArrayBufferView::offsetOfPoisonedVector()), scratch);
+#if ENABLE(POISON)
+    xorPtr(TrustedImmPtr(JSArrayBufferView::poisonFor(jsType)), scratch);
+#endif
     cageConditionally(Gigacage::Primitive, scratch, scratch2);
 
-    switch (elementSize(type)) {
+    switch (elementSize(typeArrayType)) {
     case 1:
-        if (JSC::isSigned(type))
+        if (JSC::isSigned(typeArrayType))
             load8SignedExtendTo32(BaseIndex(scratch, property, TimesOne), resultPayload);
         else
             load8(BaseIndex(scratch, property, TimesOne), resultPayload);
         break;
     case 2:
-        if (JSC::isSigned(type))
+        if (JSC::isSigned(typeArrayType))
             load16SignedExtendTo32(BaseIndex(scratch, property, TimesTwo), resultPayload);
         else
             load16(BaseIndex(scratch, property, TimesTwo), resultPayload);
@@ -1508,7 +1512,7 @@
     }
     
     Jump done;
-    if (type == TypeUint32) {
+    if (typeArrayType == TypeUint32) {
         Jump canBeInt = branch32(GreaterThanOrEqual, resultPayload, TrustedImm32(0));
         
         convertInt32ToDouble(resultPayload, fpRegT0);
@@ -1534,9 +1538,9 @@
     return slowCases;
 }
 
-JIT::JumpList JIT::emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, TypedArrayType type)
+JIT::JumpList JIT::emitFloatTypedArrayGetByVal(Instruction*, PatchableJump& badType, TypedArrayType typeArrayType)
 {
-    ASSERT(isFloat(type));
+    ASSERT(isFloat(typeArrayType));
     
 #if USE(JSVALUE64)
     RegisterID base = regT0;
@@ -1554,14 +1558,18 @@
 #endif
     
     JumpList slowCases;
+    JSType jsType = typeForTypedArrayType(typeArrayType);
 
     load8(Address(base, JSCell::typeInfoTypeOffset()), scratch);
-    badType = patchableBranch32(NotEqual, scratch, TrustedImm32(typeForTypedArrayType(type)));
+    badType = patchableBranch32(NotEqual, scratch, TrustedImm32(jsType));
     slowCases.append(branch32(AboveOrEqual, property, Address(base, JSArrayBufferView::offsetOfLength())));
-    loadPtr(Address(base, JSArrayBufferView::offsetOfVector()), scratch);
+    loadPtr(Address(base, JSArrayBufferView::offsetOfPoisonedVector()), scratch);
+#if ENABLE(POISON)
+    xorPtr(TrustedImmPtr(JSArrayBufferView::poisonFor(jsType)), scratch);
+#endif
     cageConditionally(Gigacage::Primitive, scratch, scratch2);
     
-    switch (elementSize(type)) {
+    switch (elementSize(typeArrayType)) {
     case 4:
         loadFloat(BaseIndex(scratch, property, TimesFour), fpRegT0);
         convertFloatToDouble(fpRegT0, fpRegT0);
@@ -1588,10 +1596,10 @@
     return slowCases;    
 }
 
-JIT::JumpList JIT::emitIntTypedArrayPutByVal(Instruction* currentInstruction, PatchableJump& badType, TypedArrayType type)
+JIT::JumpList JIT::emitIntTypedArrayPutByVal(Instruction* currentInstruction, PatchableJump& badType, TypedArrayType typeArrayType)
 {
     ArrayProfile* profile = ""
-    ASSERT(isInt(type));
+    ASSERT(isInt(typeArrayType));
     
     int value = currentInstruction[3].u.operand;
 
@@ -1610,9 +1618,10 @@
 #endif
     
     JumpList slowCases;
-    
+    JSType jsType = typeForTypedArrayType(typeArrayType);
+
     load8(Address(base, JSCell::typeInfoTypeOffset()), earlyScratch);
-    badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));
+    badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(jsType));
     Jump inBounds = branch32(Below, property, Address(base, JSArrayBufferView::offsetOfLength()));
     emitArrayProfileOutOfBoundsSpecialCase(profile);
     slowCases.append(jump());
@@ -1628,12 +1637,15 @@
     
     // We would be loading this into base as in get_by_val, except that the slow
     // path expects the base to be unclobbered.
-    loadPtr(Address(base, JSArrayBufferView::offsetOfVector()), lateScratch);
+    loadPtr(Address(base, JSArrayBufferView::offsetOfPoisonedVector()), lateScratch);
+#if ENABLE(POISON)
+    xorPtr(TrustedImmPtr(JSArrayBufferView::poisonFor(jsType)), lateScratch);
+#endif
     cageConditionally(Gigacage::Primitive, lateScratch, lateScratch2);
     
-    if (isClamped(type)) {
-        ASSERT(elementSize(type) == 1);
-        ASSERT(!JSC::isSigned(type));
+    if (isClamped(typeArrayType)) {
+        ASSERT(elementSize(typeArrayType) == 1);
+        ASSERT(!JSC::isSigned(typeArrayType));
         Jump inBounds = branch32(BelowOrEqual, earlyScratch, TrustedImm32(0xff));
         Jump tooBig = branch32(GreaterThan, earlyScratch, TrustedImm32(0xff));
         xor32(earlyScratch, earlyScratch);
@@ -1644,7 +1656,7 @@
         inBounds.link(this);
     }
     
-    switch (elementSize(type)) {
+    switch (elementSize(typeArrayType)) {
     case 1:
         store8(earlyScratch, BaseIndex(lateScratch, property, TimesOne));
         break;
@@ -1661,10 +1673,10 @@
     return slowCases;
 }
 
-JIT::JumpList JIT::emitFloatTypedArrayPutByVal(Instruction* currentInstruction, PatchableJump& badType, TypedArrayType type)
+JIT::JumpList JIT::emitFloatTypedArrayPutByVal(Instruction* currentInstruction, PatchableJump& badType, TypedArrayType typeArrayType)
 {
     ArrayProfile* profile = ""
-    ASSERT(isFloat(type));
+    ASSERT(isFloat(typeArrayType));
     
     int value = currentInstruction[3].u.operand;
 
@@ -1683,9 +1695,10 @@
 #endif
     
     JumpList slowCases;
-    
+    JSType jsType = typeForTypedArrayType(typeArrayType);
+
     load8(Address(base, JSCell::typeInfoTypeOffset()), earlyScratch);
-    badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));
+    badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(jsType));
     Jump inBounds = branch32(Below, property, Address(base, JSArrayBufferView::offsetOfLength()));
     emitArrayProfileOutOfBoundsSpecialCase(profile);
     slowCases.append(jump());
@@ -1714,10 +1727,13 @@
     
     // We would be loading this into base as in get_by_val, except that the slow
     // path expects the base to be unclobbered.
-    loadPtr(Address(base, JSArrayBufferView::offsetOfVector()), lateScratch);
+    loadPtr(Address(base, JSArrayBufferView::offsetOfPoisonedVector()), lateScratch);
+#if ENABLE(POISON)
+    xorPtr(TrustedImmPtr(JSArrayBufferView::poisonFor(jsType)), lateScratch);
+#endif
     cageConditionally(Gigacage::Primitive, lateScratch, lateScratch2);
     
-    switch (elementSize(type)) {
+    switch (elementSize(typeArrayType)) {
     case 4:
         convertDoubleToFloat(fpRegT0, fpRegT0);
         storeFloat(fpRegT0, BaseIndex(lateScratch, property, TimesFour));

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (227873 => 227874)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2018-01-31 05:23:52 UTC (rev 227874)
@@ -394,6 +394,7 @@
 
 const FirstArrayType = constexpr FirstTypedArrayType
 const NumberOfTypedArrayTypesExcludingDataView = constexpr NumberOfTypedArrayTypesExcludingDataView
+const TypedArrayPoisonIndexMask = constexpr TypedArrayPoisonIndexMask
 
 # Type flags constants.
 const MasqueradesAsUndefined = constexpr MasqueradesAsUndefined

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (227873 => 227874)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2018-01-31 05:23:52 UTC (rev 227874)
@@ -376,17 +376,34 @@
         end)
 end
 
-macro loadCaged(basePtr, mask, source, dest, scratch)
-    loadp source, dest
+macro uncage(basePtr, mask, ptr, scratch)
     if GIGACAGE_ENABLED and not C_LOOP
         loadp basePtr, scratch
         btpz scratch, .done
-        andp mask, dest
-        addp scratch, dest
+        andp mask, ptr
+        addp scratch, ptr
     .done:
     end
 end
 
+macro loadCaged(basePtr, mask, source, dest, scratch)
+    loadp source, dest
+    uncage(basePtr, mask, dest, scratch)
+end
+
+macro loadTypedArrayCaged(basePtr, mask, source, typeIndex, dest, scratch)
+    if POISON
+        andp TypedArrayPoisonIndexMask, typeIndex
+        leap _g_typedArrayPoisons, dest
+        loadp [dest, typeIndex, 8], dest
+        loadp source, scratch
+        xorp scratch, dest
+    else
+        loadp source, dest
+    end
+    uncage(basePtr, mask, dest, scratch)
+end
+
 macro loadVariable(operand, value)
     loadisFromInstruction(operand, value)
     loadq [cfr, value, 8], value
@@ -1541,9 +1558,9 @@
     biaeq t2, NumberOfTypedArrayTypesExcludingDataView, .opGetByValSlow
     
     # Sweet, now we know that we have a typed array. Do some basic things now.
-    loadCaged(_g_gigacageBasePtrs + Gigacage::BasePtrs::primitive, constexpr PRIMITIVE_GIGACAGE_MASK, JSArrayBufferView::m_vector[t0], t3, t5)
     biaeq t1, JSArrayBufferView::m_length[t0], .opGetByValSlow
-    
+    loadTypedArrayCaged(_g_gigacageBasePtrs + Gigacage::BasePtrs::primitive, constexpr PRIMITIVE_GIGACAGE_MASK, JSArrayBufferView::m_poisonedVector[t0], t2, t3, t5)
+
     # Now bisect through the various types:
     #    Int8ArrayType,
     #    Uint8ArrayType,

Modified: trunk/Source/_javascript_Core/offlineasm/arm64.rb (227873 => 227874)


--- trunk/Source/_javascript_Core/offlineasm/arm64.rb	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/offlineasm/arm64.rb	2018-01-31 05:23:52 UTC (rev 227874)
@@ -275,6 +275,13 @@
                 else
                     newList << node
                 end
+            when "leai", "leap", "leaq"
+                labelRef = node.operands[0]
+                if labelRef.is_a? LabelReference
+                    newList << Instruction.new(codeOrigin, "globaladdr", [LabelReference.new(node.codeOrigin, labelRef.label), node.operands[1]])
+                else
+                    newList << node
+                end
             else
                 newList << node
             end

Modified: trunk/Source/_javascript_Core/offlineasm/x86.rb (227873 => 227874)


--- trunk/Source/_javascript_Core/offlineasm/x86.rb	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/offlineasm/x86.rb	2018-01-31 05:23:52 UTC (rev 227874)
@@ -468,6 +468,11 @@
         $asm.puts "movq #{asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
         "#{offset}(#{dst.x86Operand(kind)})"
     end
+    def x86AddressOperand(addressKind)
+        # FIXME: Implement this on platforms that aren't Mach-O.
+        # https://bugs.webkit.org/show_bug.cgi?id=175104
+        "#{asmLabel}@GOTPCREL(%rip)"
+    end
 end
 
 class LocalLabelReference
@@ -582,6 +587,15 @@
         end
     end
 
+    def emitX86Lea(src, dst, kind)
+        if src.is_a? LabelReference
+            $asm.puts "movq #{src.asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
+            $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(dst.x86Operand(kind), dst.x86Operand(kind))}"
+        else
+            $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(src.x86AddressOperand(kind), dst.x86Operand(kind))}"
+        end
+    end
+
     def getImplicitOperandString
         isIntelSyntax ? "st(0), " : ""
     end
@@ -1542,9 +1556,9 @@
         when "bnz"
             $asm.puts "jnz #{operands[0].asmLabel}"
         when "leai"
-            $asm.puts "lea#{x86Suffix(:int)} #{orderOperands(operands[0].x86AddressOperand(:int), operands[1].x86Operand(:int))}"
+            emitX86Lea(operands[0], operands[1], :int)
         when "leap"
-            $asm.puts "lea#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86AddressOperand(:ptr), operands[1].x86Operand(:ptr))}"
+            emitX86Lea(operands[0], operands[1], :ptr)
         when "memfence"
             sp = RegisterID.new(nil, "sp")
             if isIntelSyntax

Modified: trunk/Source/_javascript_Core/runtime/CagedBarrierPtr.h (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/CagedBarrierPtr.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/CagedBarrierPtr.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,8 +26,15 @@
 #pragma once
 
 #include "AuxiliaryBarrier.h"
+#include <type_traits>
 #include <wtf/CagedPtr.h>
 
+namespace WTF {
+
+template<typename Poison, typename T> struct PoisonedPtrTraits;
+
+} // namespace WTF
+
 namespace JSC {
 
 class JSCell;
@@ -35,7 +42,7 @@
 
 // This is a convenient combo of AuxiliaryBarrier and CagedPtr.
 
-template<Gigacage::Kind passedKind, typename T>
+template<Gigacage::Kind passedKind, typename T, typename PtrTraits = WTF::DumbPtrTraits<T>>
 class CagedBarrierPtr {
 public:
     static constexpr Gigacage::Kind kind = passedKind;
@@ -85,11 +92,11 @@
     T& operator[](IndexType index) const { return get()[index]; }
     
 private:
-    AuxiliaryBarrier<CagedPtr<kind, T>> m_barrier;
+    AuxiliaryBarrier<CagedPtr<kind, T, PtrTraits>> m_barrier;
 };
 
-template<Gigacage::Kind passedKind>
-class CagedBarrierPtr<passedKind, void> {
+template<Gigacage::Kind passedKind, typename PtrTraits>
+class CagedBarrierPtr<passedKind, void, PtrTraits> {
 public:
     static constexpr Gigacage::Kind kind = passedKind;
     typedef void Type;
@@ -132,7 +139,10 @@
     void setWithoutBarrier(U&& value) { m_barrier.setWithoutBarrier(std::forward<U>(value)); }
     
 private:
-    AuxiliaryBarrier<CagedPtr<kind, void>> m_barrier;
+    AuxiliaryBarrier<CagedPtr<kind, void, PtrTraits>> m_barrier;
 };
 
+template<typename Poison, Gigacage::Kind passedKind, typename T>
+using PoisonedCagedBarrierPtr = CagedBarrierPtr<passedKind, T, WTF::PoisonedPtrTraits<Poison, T>>;
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSArrayBufferView.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/JSArrayBufferView.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/JSArrayBufferView.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -132,7 +132,7 @@
     , m_mode(context.mode())
 {
     setButterflyWithIndexingMask(vm, context.butterfly(), WTF::computeIndexingMask(length()));
-    m_vector.setWithoutBarrier(context.vector());
+    m_poisonedVector.setWithoutBarrier(context.vector());
 }
 
 void JSArrayBufferView::finishCreation(VM& vm)
@@ -193,7 +193,7 @@
     JSArrayBufferView* thisObject = static_cast<JSArrayBufferView*>(cell);
     ASSERT(thisObject->m_mode == OversizeTypedArray || thisObject->m_mode == WastefulTypedArray);
     if (thisObject->m_mode == OversizeTypedArray)
-        Gigacage::free(Gigacage::Primitive, thisObject->m_vector.get());
+        Gigacage::free(Gigacage::Primitive, thisObject->m_poisonedVector.get());
 }
 
 JSArrayBuffer* JSArrayBufferView::unsharedJSBuffer(ExecState* exec)
@@ -211,7 +211,7 @@
     RELEASE_ASSERT(hasArrayBuffer());
     RELEASE_ASSERT(!isShared());
     m_length = 0;
-    m_vector.clear();
+    m_poisonedVector.clear();
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSArrayBufferView.h (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/JSArrayBufferView.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/JSArrayBufferView.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,12 +26,22 @@
 #pragma once
 
 #include "AuxiliaryBarrier.h"
+#include "CagedBarrierPtr.h"
+#include "JSCPoison.h"
 #include "JSObject.h"
+#include "TypedArrayType.h"
+#include <wtf/MathExtras.h>
 
 namespace JSC {
 
 class LLIntOffsetsExtractor;
 
+// Since we'll be indexing into the g_typedArrayPoisons array based on the TypedArray type,
+// we'll index mask the index value and round up to the array size to the next power of 2 to
+// ensure that we'll never be able to access beyond the bounds of this array.
+static constexpr uint32_t NumberOfTypedArrayPoisons = WTF::roundUpToPowerOfTwo(NumberOfTypedArrayTypes);
+static constexpr uint32_t TypedArrayPoisonIndexMask = NumberOfTypedArrayPoisons - 1;
+
 // This class serves two purposes:
 //
 // 1) It provides those parts of JSGenericTypedArrayView that don't depend
@@ -167,7 +177,7 @@
     bool isNeutered() { return hasArrayBuffer() && !vector(); }
     void neuter();
     
-    void* vector() const { return m_vector.getMayBeNull(); }
+    void* vector() const { return m_poisonedVector.getMayBeNull(); }
     
     unsigned byteOffset();
     unsigned length() const { return m_length; }
@@ -174,12 +184,23 @@
 
     DECLARE_EXPORT_INFO;
     
-    static ptrdiff_t offsetOfVector() { return OBJECT_OFFSETOF(JSArrayBufferView, m_vector); }
+    static ptrdiff_t offsetOfPoisonedVector() { return OBJECT_OFFSETOF(JSArrayBufferView, m_poisonedVector); }
     static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSArrayBufferView, m_length); }
     static ptrdiff_t offsetOfMode() { return OBJECT_OFFSETOF(JSArrayBufferView, m_mode); }
     
     static RefPtr<ArrayBufferView> toWrapped(VM&, JSValue);
 
+    static uintptr_t poisonFor(JSType type)
+    {
+        return g_typedArrayPoisons[(type - FirstTypedArrayType) & TypedArrayPoisonIndexMask];
+    }
+
+    static uintptr_t poisonFor(TypedArrayType typedArrayType)
+    {
+        ASSERT(isTypedView(typedArrayType));
+        return poisonFor(typeForTypedArrayType(typedArrayType));
+    }
+
 private:
     static void finalize(JSCell*);
 
@@ -190,7 +211,19 @@
 
     static String toStringName(const JSObject*, ExecState*);
 
-    CagedBarrierPtr<Gigacage::Primitive, void> m_vector;
+    class Poison {
+    public:
+        template<typename PoisonedType>
+        inline static uintptr_t key(const PoisonedType* poisonedPtr)
+        {
+            uintptr_t poisonedVectorAddress = bitwise_cast<uintptr_t>(poisonedPtr);
+            uintptr_t baseAddress = poisonedVectorAddress - OBJECT_OFFSETOF(JSArrayBufferView, m_poisonedVector);
+            JSArrayBufferView* thisObject = bitwise_cast<JSArrayBufferView*>(baseAddress);
+            return poisonFor(thisObject->type());
+        }
+    };
+
+    PoisonedCagedBarrierPtr<Poison, Gigacage::Primitive, void> m_poisonedVector;
     uint32_t m_length;
     TypedArrayMode m_mode;
 };

Modified: trunk/Source/_javascript_Core/runtime/JSCPoison.cpp (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/JSCPoison.cpp	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/JSCPoison.cpp	2018-01-31 05:23:52 UTC (rev 227874)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "JSCPoison.h"
 
+#include "JSArrayBufferView.h"
 #include "Options.h"
 #include <mutex>
 #include <wtf/HashSet.h>
@@ -36,6 +37,8 @@
     uintptr_t POISON_KEY_NAME(poisonID);
 FOR_EACH_JSC_POISON(DEFINE_POISON)
 
+uintptr_t g_typedArrayPoisons[NumberOfTypedArrayPoisons];
+
 void initializePoison()
 {
     static std::once_flag initializeOnceFlag;
@@ -47,6 +50,9 @@
     POISON_KEY_NAME(poisonID) = makePoison();
 
         FOR_EACH_JSC_POISON(INITIALIZE_POISON)
+
+        for (uint32_t i = 0; i < NumberOfTypedArrayPoisons; ++i)
+            g_typedArrayPoisons[i] = makePoison();
     });
 }
 

Modified: trunk/Source/_javascript_Core/runtime/JSCPoison.h (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/JSCPoison.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/JSCPoison.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -64,6 +64,8 @@
 FOR_EACH_JSC_POISON(DECLARE_POISON)
 #undef DECLARE_POISON
 
+extern "C" JS_EXPORTDATA uintptr_t g_typedArrayPoisons[];
+
 struct ClassInfo;
 
 using PoisonedClassInfoPtr = Poisoned<GlobalDataPoison, const ClassInfo*>;

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -504,7 +504,7 @@
 
     if (thisObject->m_mode == OversizeTypedArray)
         return Base::estimatedSize(thisObject) + thisObject->byteSize();
-    if (thisObject->m_mode == FastTypedArray && thisObject->m_vector)
+    if (thisObject->m_mode == FastTypedArray && thisObject->m_poisonedVector)
         return Base::estimatedSize(thisObject) + thisObject->byteSize();
 
     return Base::estimatedSize(thisObject);
@@ -517,7 +517,7 @@
     
     switch (thisObject->m_mode) {
     case FastTypedArray: {
-        if (void* vector = thisObject->m_vector.getMayBeNull())
+        if (void* vector = thisObject->m_poisonedVector.getMayBeNull())
             visitor.markAuxiliary(vector);
         break;
     }
@@ -585,7 +585,7 @@
     }
 
     thisObject->butterfly()->indexingHeader()->setArrayBuffer(buffer.get());
-    thisObject->m_vector.setWithoutBarrier(buffer->data());
+    thisObject->m_poisonedVector.setWithoutBarrier(buffer->data());
     WTF::storeStoreFence();
     thisObject->m_mode = WastefulTypedArray;
     heap->addReference(thisObject, buffer.get());

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (227873 => 227874)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -24,9 +24,9 @@
 
 #include "ArrayConventions.h"
 #include "ArrayStorage.h"
+#include "AuxiliaryBarrier.h"
 #include "Butterfly.h"
 #include "CPU.h"
-#include "CagedBarrierPtr.h"
 #include "CallFrame.h"
 #include "ClassInfo.h"
 #include "CustomGetterSetter.h"

Modified: trunk/Source/WTF/ChangeLog (227873 => 227874)


--- trunk/Source/WTF/ChangeLog	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/WTF/ChangeLog	2018-01-31 05:23:52 UTC (rev 227874)
@@ -1,3 +1,22 @@
+2018-01-30  Mark Lam  <[email protected]>
+
+        Apply poisoning to TypedArray vector pointers.
+        https://bugs.webkit.org/show_bug.cgi?id=182155
+        <rdar://problem/36286266>
+
+        Reviewed by JF Bastien.
+
+        1. Added the ability to poison a CagedPtr.
+
+        2. Prevent CagedPtr from being implicitly instantiated, and add operator= methods
+           instead.  This is because implicitly instantiated CagedPtrs with a poisoned
+           trait may silently use a wrong poison value.
+
+        * wtf/CagedPtr.h:
+        (WTF::CagedPtr::CagedPtr):
+        (WTF::CagedPtr::get const):
+        (WTF::CagedPtr::operator=):
+
 2018-01-30  Fujii Hironori  <[email protected]>
 
         [Win] Warning fix.

Modified: trunk/Source/WTF/wtf/CagedPtr.h (227873 => 227874)


--- trunk/Source/WTF/wtf/CagedPtr.h	2018-01-31 05:15:59 UTC (rev 227873)
+++ trunk/Source/WTF/wtf/CagedPtr.h	2018-01-31 05:23:52 UTC (rev 227874)
@@ -25,16 +25,20 @@
 
 #pragma once
 
+#include <wtf/DumbPtrTraits.h>
 #include <wtf/Gigacage.h>
 
 namespace WTF {
 
-template<Gigacage::Kind passedKind, typename T>
+template<Gigacage::Kind passedKind, typename T, typename PtrTraits = DumbPtrTraits<T>>
 class CagedPtr {
 public:
     static constexpr Gigacage::Kind kind = passedKind;
-    
-    CagedPtr(T* ptr = nullptr)
+
+    CagedPtr() : CagedPtr(nullptr) { }
+    CagedPtr(std::nullptr_t) : m_ptr(nullptr) { }
+
+    explicit CagedPtr(T* ptr)
         : m_ptr(ptr)
     {
     }
@@ -42,7 +46,7 @@
     T* get() const
     {
         ASSERT(m_ptr);
-        return Gigacage::caged(kind, m_ptr);
+        return Gigacage::caged(kind, PtrTraits::unwrap(m_ptr));
     }
     
     T* getMayBeNull() const
@@ -51,7 +55,19 @@
             return nullptr;
         return get();
     }
-    
+
+    CagedPtr& operator=(T* ptr)
+    {
+        m_ptr = ptr;
+        return *this;
+    }
+
+    CagedPtr& operator=(T*&& ptr)
+    {
+        m_ptr = WTFMove(ptr);
+        return *this;
+    }
+
     bool operator==(const CagedPtr& other) const
     {
         return getMayBeNull() == other.getMayBeNull();
@@ -74,15 +90,18 @@
     T& operator[](IndexType index) const { return get()[index]; }
     
 protected:
-    T* m_ptr;
+    typename PtrTraits::StorageType m_ptr;
 };
 
-template<Gigacage::Kind passedKind>
-class CagedPtr<passedKind, void> {
+template<Gigacage::Kind passedKind, typename PtrTraits>
+class CagedPtr<passedKind, void, PtrTraits> {
 public:
     static constexpr Gigacage::Kind kind = passedKind;
-    
-    CagedPtr(void* ptr = nullptr)
+
+    CagedPtr() : CagedPtr(nullptr) { }
+    CagedPtr(std::nullptr_t) : m_ptr(nullptr) { }
+
+    explicit CagedPtr(void* ptr)
         : m_ptr(ptr)
     {
     }
@@ -90,7 +109,7 @@
     void* get() const
     {
         ASSERT(m_ptr);
-        return Gigacage::caged(kind, m_ptr);
+        return Gigacage::caged(kind, PtrTraits::unwrap(m_ptr));
     }
     
     void* getMayBeNull() const
@@ -99,7 +118,13 @@
             return nullptr;
         return get();
     }
-    
+
+    CagedPtr& operator=(void* ptr)
+    {
+        m_ptr = ptr;
+        return *this;
+    }
+
     bool operator==(const CagedPtr& other) const
     {
         return getMayBeNull() == other.getMayBeNull();
@@ -116,7 +141,7 @@
     }
     
 protected:
-    void* m_ptr;
+    typename PtrTraits::StorageType m_ptr;
 };
 
 } // namespace WTF
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to