Title: [226145] branches/safari-604.5.100-branch/Source
Revision
226145
Author
[email protected]
Date
2017-12-19 15:01:00 -0800 (Tue, 19 Dec 2017)

Log Message

Apply patch. rdar://problem/36112003

Modified Paths


Diff

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/ChangeLog (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/ChangeLog	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/ChangeLog	2017-12-19 23:01:00 UTC (rev 226145)
@@ -1,5 +1,77 @@
 2017-12-18  Jason Marcell  <[email protected]>
 
+        Apply patch. rdar://problem/36112003
+
+    2017-12-17  Keith Miller  <[email protected]>
+
+            Use index masking for TypedArrays and and Wasm.
+            https://bugs.webkit.org/show_bug.cgi?id=180920
+
+            Reviewed by Filip Pizlo.
+
+            We should have index masking for our TypedArray code in the
+            DFG/FTL and for Wasm when doing bounds checking. Index masking for
+            Wasm is added to the WasmBoundsCheckValue. Since we don't CSE any
+            WasmBoundsCheckValues we don't need to worry about combining a
+            bounds check for a load and a store. I went with fusing the
+            pointer masking in the WasmBoundsCheckValue since it should reduce
+            additional compiler overhead.
+
+            * b3/B3LowerToAir.cpp:
+            * b3/B3Validate.cpp:
+            * b3/B3WasmBoundsCheckValue.cpp:
+            (JSC::B3::WasmBoundsCheckValue::WasmBoundsCheckValue):
+            (JSC::B3::WasmBoundsCheckValue::dumpMeta const):
+            * b3/B3WasmBoundsCheckValue.h:
+            (JSC::B3::WasmBoundsCheckValue::pinnedIndexingMask const):
+            * b3/air/AirCustom.h:
+            (JSC::B3::Air::WasmBoundsCheckCustom::generate):
+            * b3/testb3.cpp:
+            (JSC::B3::testWasmBoundsCheck):
+            * dfg/DFGSpeculativeJIT.cpp:
+            (JSC::DFG::SpeculativeJIT::loadFromIntTypedArray):
+            (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
+            (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray):
+            (JSC::DFG::SpeculativeJIT::compileNewTypedArray):
+            * dfg/DFGSpeculativeJIT.h:
+            * dfg/DFGSpeculativeJIT64.cpp:
+            (JSC::DFG::SpeculativeJIT::compile):
+            * ftl/FTLAbstractHeapRepository.h:
+            * ftl/FTLLowerDFGToB3.cpp:
+            (JSC::FTL::DFG::LowerDFGToB3::compileAtomicsReadModifyWrite):
+            (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
+            (JSC::FTL::DFG::LowerDFGToB3::compileNewTypedArray):
+            (JSC::FTL::DFG::LowerDFGToB3::pointerIntoTypedArray):
+            * jit/AssemblyHelpers.h:
+            (JSC::AssemblyHelpers::emitComputeButterflyIndexingMask):
+            * runtime/Butterfly.h:
+            * runtime/JSArrayBufferView.cpp:
+            (JSC::JSArrayBufferView::JSArrayBufferView):
+            * runtime/JSArrayBufferView.h:
+            (JSC::JSArrayBufferView::offsetOfIndexingMask):
+            * wasm/WasmB3IRGenerator.cpp:
+            (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+            (JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
+            (JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
+            (JSC::Wasm::B3IRGenerator::load):
+            (JSC::Wasm::B3IRGenerator::store):
+            (JSC::Wasm::B3IRGenerator::addCallIndirect):
+            * wasm/WasmBinding.cpp:
+            (JSC::Wasm::wasmToWasm):
+            * wasm/WasmMemory.cpp:
+            (JSC::Wasm::Memory::Memory):
+            * wasm/WasmMemory.h:
+            (JSC::Wasm::Memory::offsetOfIndexingMask):
+            * wasm/WasmMemoryInformation.cpp:
+            (JSC::Wasm::PinnedRegisterInfo::get):
+            (JSC::Wasm::PinnedRegisterInfo::PinnedRegisterInfo):
+            * wasm/WasmMemoryInformation.h:
+            (JSC::Wasm::PinnedRegisterInfo::toSave const):
+            * wasm/js/JSToWasm.cpp:
+            (JSC::Wasm::createJSToWasmWrapper):
+
+2017-12-18  Jason Marcell  <[email protected]>
+
         Cherry-pick r226068. rdar://problem/36112028
 
     2017-12-16  Filip Pizlo  <[email protected]>

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3LowerToAir.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3LowerToAir.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3LowerToAir.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -3210,9 +3210,10 @@
             WasmBoundsCheckValue* value = m_value->as<WasmBoundsCheckValue>();
 
             Value* ptr = value->child(0);
+            Tmp pointer = tmp(ptr);
 
             Arg ptrPlusImm = m_code.newTmp(GP);
-            append(Inst(Move32, value, tmp(ptr), ptrPlusImm));
+            append(Inst(Move32, value, pointer, ptrPlusImm));
             if (value->offset()) {
                 if (imm(value->offset()))
                     append(Add64, imm(value->offset()), ptrPlusImm);
@@ -3226,7 +3227,7 @@
             Arg limit;
             switch (value->boundsType()) {
             case WasmBoundsCheckValue::Type::Pinned:
-                limit = Arg(value->bounds().pinned);
+                limit = Arg(value->bounds().pinnedSize);
                 break;
 
             case WasmBoundsCheckValue::Type::Maximum:
@@ -3239,6 +3240,10 @@
             }
 
             append(Inst(Air::WasmBoundsCheck, value, ptrPlusImm, limit));
+            // Hypothetically, this could write to the pointer value. Which we didn't claim we did but since we assume the indexing mask
+            // should not actually change the value of the pointer we should be OK.
+            if (value->pinnedIndexingMask() != InvalidGPRReg)
+                append(And32, Arg(value->pinnedIndexingMask()), pointer, pointer);
             return;
         }
 

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3Validate.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3Validate.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3Validate.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -472,11 +472,14 @@
                 VALIDATE(value->child(0)->type() == Int32, ("At ", *value));
                 switch (value->as<WasmBoundsCheckValue>()->boundsType()) {
                 case WasmBoundsCheckValue::Type::Pinned:
-                    VALIDATE(m_procedure.code().isPinned(value->as<WasmBoundsCheckValue>()->bounds().pinned), ("At ", *value));
+                    VALIDATE(m_procedure.code().isPinned(value->as<WasmBoundsCheckValue>()->bounds().pinnedSize), ("At ", *value));
+
                     break;
                 case WasmBoundsCheckValue::Type::Maximum:
                     break;
                 }
+                if (value->as<WasmBoundsCheckValue>()->pinnedIndexingMask() != InvalidGPRReg)
+                    VALIDATE(m_procedure.code().isPinned(value->as<WasmBoundsCheckValue>()->pinnedIndexingMask()), ("At ", *value));
                 VALIDATE(m_procedure.code().wasmBoundsCheckGenerator(), ("At ", *value));
                 break;
             case Upsilon:

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -35,12 +35,13 @@
 {
 }
 
-WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, GPRReg pinnedGPR, Value* ptr, unsigned offset)
+WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, GPRReg pinnedSize, GPRReg pinnedIndexingMask, Value* ptr, unsigned offset)
     : Value(CheckedOpcode, WasmBoundsCheck, origin, ptr)
     , m_offset(offset)
     , m_boundsType(Type::Pinned)
+    , m_pinnedIndexingMask(pinnedIndexingMask)
 {
-    m_bounds.pinned = pinnedGPR;
+    m_bounds.pinnedSize = pinnedSize;
 }
 
 WasmBoundsCheckValue::WasmBoundsCheckValue(Origin origin, Value* ptr, unsigned offset, size_t maximum)
@@ -64,10 +65,10 @@
 {
     switch (m_boundsType) {
     case Type::Pinned:
-        out.print(comma, "offset = ", m_offset, ", pinned = ", m_bounds.pinned);
+        out.print(comma, "offset = ", m_offset, comma, "pinnedSize = ", m_bounds.pinnedSize, comma, "pinnedMask", m_pinnedIndexingMask);
         break;
     case Type::Maximum:
-        out.print(comma, "offset = ", m_offset, ", maximum = ", m_bounds.maximum);
+        out.print(comma, "offset = ", m_offset, comma, "maximum = ", m_bounds.maximum);
         break;
     }
 }

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/b3/B3WasmBoundsCheckValue.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -52,7 +52,7 @@
     };
 
     union Bounds {
-        GPRReg pinned;
+        GPRReg pinnedSize;
         size_t maximum;
     };
 
@@ -59,6 +59,7 @@
     unsigned offset() const { return m_offset; }
     Type boundsType() const { return m_boundsType; }
     Bounds bounds() const { return m_bounds; }
+    GPRReg pinnedIndexingMask() const { return m_pinnedIndexingMask; };
 
 protected:
     void dumpMeta(CommaPrinter&, PrintStream&) const override;
@@ -68,12 +69,14 @@
 private:
     friend class Procedure;
 
-    JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, GPRReg pinnedGPR, Value* ptr, unsigned offset);
+    JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, GPRReg pinnedGPR, GPRReg pinnedIndexingMask, Value* ptr, unsigned offset);
     JS_EXPORT_PRIVATE WasmBoundsCheckValue(Origin, Value* ptr, unsigned offset, size_t maximum);
 
     unsigned m_offset;
     Type m_boundsType;
     Bounds m_bounds;
+    GPRReg m_pinnedIndexingMask { InvalidGPRReg };
+
 };
 
 } } // namespace JSC::B3

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/b3/air/AirCustom.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/b3/air/AirCustom.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/b3/air/AirCustom.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -343,7 +343,7 @@
                 outOfBounds.link(&jit);
                 switch (value->boundsType()) {
                 case WasmBoundsCheckValue::Type::Pinned:
-                    context.code->wasmBoundsCheckGenerator()->run(jit, value->bounds().pinned);
+                    context.code->wasmBoundsCheckGenerator()->run(jit, value->bounds().pinnedSize);
                     break;
 
                 case WasmBoundsCheckValue::Type::Maximum:

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/b3/testb3.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/b3/testb3.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/b3/testb3.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -15326,7 +15326,7 @@
     Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
     if (pointerType() != Int32)
         left = root->appendNew<Value>(proc, Trunc, Origin(), left);
-    root->appendNew<WasmBoundsCheckValue>(proc, Origin(), pinned, left, offset);
+    root->appendNew<WasmBoundsCheckValue>(proc, Origin(), pinned, InvalidGPRReg, left, offset);
     Value* result = root->appendNew<Const32Value>(proc, Origin(), 0x42);
     root->appendNewControlValue(proc, Return, Origin(), result);
 

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -2727,8 +2727,9 @@
     return done;
 }
 
-void SpeculativeJIT::loadFromIntTypedArray(GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType type)
+void SpeculativeJIT::loadFromIntTypedArray(GPRReg baseReg, GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType type)
 {
+    m_jit.and32(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfIndexingMask()), propertyReg);
     switch (elementSize(type)) {
     case 1:
         if (isSigned(type))
@@ -2798,7 +2799,7 @@
     ASSERT(node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1())));
 
     emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
-    loadFromIntTypedArray(storageReg, propertyReg, resultReg, type);
+    loadFromIntTypedArray(baseReg, storageReg, propertyReg, resultReg, type);
     bool canSpeculate = true;
     setIntTypedArrayLoadResult(node, resultReg, type, canSpeculate);
 }
@@ -3030,6 +3031,7 @@
     FPRTemporary result(this);
     FPRReg resultReg = result.fpr();
     emitTypedArrayBoundsCheck(node, baseReg, propertyReg);
+    m_jit.and32(MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfIndexingMask()), propertyReg);
     switch (elementSize(type)) {
     case 4:
         m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
@@ -8509,7 +8511,8 @@
     emitAllocateJSObject<JSArrayBufferView>(
         resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR, scratchGPR2,
         slowCases);
-    
+
+    m_jit.emitComputeButterflyIndexingMask(sizeGPR, scratchGPR, scratchGPR2);
     m_jit.storePtr(
         storageGPR,
         MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfVector()));
@@ -8517,6 +8520,9 @@
         sizeGPR,
         MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfLength()));
     m_jit.store32(
+        scratchGPR2,
+        MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfIndexingMask()));
+    m_jit.store32(
         TrustedImm32(FastTypedArray),
         MacroAssembler::Address(resultGPR, JSArrayBufferView::offsetOfMode()));
     

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -2826,7 +2826,7 @@
         GPRTemporary& valueTag,
 #endif
         Edge valueUse, JITCompiler::JumpList& slowPathCases, bool isClamped = false);
-    void loadFromIntTypedArray(GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType);
+    void loadFromIntTypedArray(GPRReg baseReg, GPRReg storageReg, GPRReg propertyReg, GPRReg resultReg, TypedArrayType);
     void setIntTypedArrayLoadResult(Node*, GPRReg resultReg, TypedArrayType, bool canSpeculate = false);
     template <typename ClassType> void compileNewFunctionCommon(GPRReg, RegisteredStructure, GPRReg, GPRReg, GPRReg, MacroAssembler::JumpList&, size_t, FunctionExecutable*, ptrdiff_t, ptrdiff_t, ptrdiff_t);
     void compileNewFunction(Node*);

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -3284,7 +3284,7 @@
         
         JITCompiler::Label loop = m_jit.label();
         
-        loadFromIntTypedArray(storageGPR, indexGPR, oldValueGPR, type);
+        loadFromIntTypedArray(baseGPR, storageGPR, indexGPR, oldValueGPR, type);
         m_jit.move(oldValueGPR, newValueGPR);
         m_jit.move(oldValueGPR, resultGPR);
         

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -57,6 +57,7 @@
     macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \
     macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \
     macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \
+    macro(JSArrayBufferView_indexingMask, JSArrayBufferView::offsetOfIndexingMask()) \
     macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \
     macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \
     macro(JSCell_cellState, JSCell::cellStateOffset()) \

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -3022,9 +3022,10 @@
         LValue args[2];
         for (unsigned i = numExtraArgs; i--;)
             args[i] = getIntTypedArrayStoreOperand(argEdges[i]);
+        LValue base = lowCell(baseEdge);
         LValue storage = lowStorage(storageEdge);
-        
-        TypedPointer pointer = pointerIntoTypedArray(storage, index, type);
+
+        TypedPointer pointer = pointerIntoTypedArray(base, storage, index, type);
         Width width = widthForBytes(elementSize(type));
         
         LValue atomicValue;
@@ -3658,6 +3659,7 @@
         }
             
         default: {
+            LValue base = lowCell(m_node->child1());
             LValue index = lowInt32(m_node->child2());
             LValue storage = lowStorage(m_node->child3());
             
@@ -3664,7 +3666,7 @@
             TypedArrayType type = m_node->arrayMode().typedArrayType();
             
             if (isTypedView(type)) {
-                TypedPointer pointer = pointerIntoTypedArray(storage, index, type);
+                TypedPointer pointer = pointerIntoTypedArray(base, storage, index, type);
                 
                 if (isInt(type)) {
                     LValue result = loadFromIntTypedArray(pointer, type);
@@ -5091,8 +5093,10 @@
             LValue fastResultValue =
                 allocateObject<JSArrayBufferView>(structure, m_out.intPtrZero, slowCase);
 
+            LValue indexingMask = m_out.castToInt32(m_out.lShr(m_out.zeroExt(m_out.constInt32(-1), Int64), m_out.ctlz32(size)));
             m_out.storePtr(storage, fastResultValue, m_heaps.JSArrayBufferView_vector);
             m_out.store32(size, fastResultValue, m_heaps.JSArrayBufferView_length);
+            m_out.store32(indexingMask, fastResultValue, m_heaps.JSArrayBufferView_indexingMask);
             m_out.store32(m_out.constInt32(FastTypedArray), fastResultValue, m_heaps.JSArrayBufferView_mode);
             
             mutatorFence();
@@ -12098,14 +12102,15 @@
         functor(TypeofType::Undefined);
     }
     
-    TypedPointer pointerIntoTypedArray(LValue storage, LValue index, TypedArrayType type)
+    TypedPointer pointerIntoTypedArray(LValue base, LValue storage, LValue index, TypedArrayType type)
     {
+        LValue mask = m_out.load32(base, m_heaps.JSArrayBufferView_indexingMask);
         return TypedPointer(
             m_heaps.typedArrayProperties,
             m_out.add(
                 storage,
                 m_out.shl(
-                    m_out.zeroExtPtr(index),
+                    m_out.zeroExtPtr(m_out.bitAnd(index, mask)),
                     m_out.constIntPtr(logElementSize(type)))));
     }
     

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/jit/AssemblyHelpers.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/jit/AssemblyHelpers.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/jit/AssemblyHelpers.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -1440,6 +1440,14 @@
     void emitRandomThunk(VM&, GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, FPRReg result);
 #endif
 
+    void emitComputeButterflyIndexingMask(GPRReg vectorLengthGPR, GPRReg scratchGPR, GPRReg resultGPR)
+    {
+        // If vectorLength == 0 then clz will return 32 on both ARM and x86. On 64-bit systems, we can then do a 64-bit right shift on a 32-bit -1 to get a 0 mask for zero vectorLength. On 32-bit ARM, shift masks with 0xff, which means it will still create a 0 mask.
+        countLeadingZeros32(vectorLengthGPR, scratchGPR);
+        move(TrustedImm32(-1), resultGPR);
+        urshift64(scratchGPR, resultGPR);
+    }
+
     // Call this if you know that the value held in allocatorGPR is non-null. This DOES NOT mean
     // that allocator is non-null; allocator can be null as a signal that we don't know what the
     // value of allocatorGPR is.

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/Butterfly.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/Butterfly.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/Butterfly.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -123,7 +123,7 @@
     uint32_t vectorLength() { return indexingHeader()->vectorLength(); }
     void setPublicLength(uint32_t value) { indexingHeader()->setPublicLength(value); }
     void setVectorLength(uint32_t value) { indexingHeader()->setVectorLength(value); }
-    
+
     template<typename T>
     T* indexingPayload() { return reinterpret_cast_ptr<T*>(this); }
     ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); }

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/JSArrayBufferView.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/JSArrayBufferView.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/JSArrayBufferView.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -129,6 +129,7 @@
 JSArrayBufferView::JSArrayBufferView(VM& vm, ConstructionContext& context)
     : Base(vm, context.structure(), context.butterfly())
     , m_length(context.length())
+    , m_indexingMask(WTF::computeIndexingMask(context.length()))
     , m_mode(context.mode())
 {
     m_vector.setWithoutBarrier(context.vector());

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/JSArrayBufferView.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/JSArrayBufferView.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/runtime/JSArrayBufferView.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -176,6 +176,7 @@
     
     static ptrdiff_t offsetOfVector() { return OBJECT_OFFSETOF(JSArrayBufferView, m_vector); }
     static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSArrayBufferView, m_length); }
+    static ptrdiff_t offsetOfIndexingMask() { return OBJECT_OFFSETOF(JSArrayBufferView, m_indexingMask); }
     static ptrdiff_t offsetOfMode() { return OBJECT_OFFSETOF(JSArrayBufferView, m_mode); }
     
     static RefPtr<ArrayBufferView> toWrapped(VM&, JSValue);
@@ -192,6 +193,7 @@
 
     AuxiliaryBarrier<void*> m_vector;
     uint32_t m_length;
+    uint32_t m_indexingMask;
     TypedArrayMode m_mode;
 };
 

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -233,7 +233,8 @@
 
     void emitTierUpCheck(uint32_t decrementCount, Origin);
 
-    ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
+    enum class ShouldMask { Yes, No };
+    ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp, ShouldMask);
     B3::Kind memoryKind(B3::Opcode memoryOp);
     ExpressionType emitLoadOp(LoadOpType, ExpressionType pointer, uint32_t offset);
     void emitStoreOp(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
@@ -266,6 +267,7 @@
     InsertionSet m_constantInsertionValues;
     GPRReg m_memoryBaseGPR;
     GPRReg m_memorySizeGPR { InvalidGPRReg };
+    GPRReg m_indexingMaskGPR { InvalidGPRReg };
     GPRReg m_wasmContextGPR;
     Value* m_instanceValue; // FIXME: make this lazy https://bugs.webkit.org/show_bug.cgi?id=169792
     bool m_makesCalls { false };
@@ -360,6 +362,8 @@
 
     if (mode != MemoryMode::Signaling) {
         ASSERT(!pinnedRegs.sizeRegisters[0].sizeOffset);
+        m_indexingMaskGPR = pinnedRegs.indexingMask;
+        m_proc.pinRegister(pinnedRegs.indexingMask);
         m_memorySizeGPR = pinnedRegs.sizeRegisters[0].sizeRegister;
         for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters)
             m_proc.pinRegister(regInfo.sizeRegister);
@@ -444,6 +448,7 @@
         const PinnedRegisterInfo* pinnedRegs = &PinnedRegisterInfo::get();
         RegisterSet clobbers;
         clobbers.set(pinnedRegs->baseMemoryPointer);
+        clobbers.set(pinnedRegs->indexingMask);
         for (auto info : pinnedRegs->sizeRegisters)
             clobbers.set(info.sizeRegister);
 
@@ -463,6 +468,7 @@
             ASSERT(sizeRegs.size() >= 1);
             ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
             jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister);
+            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfIndexingMask()), pinnedRegs->indexingMask);
             jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory);
             for (unsigned i = 1; i < sizeRegs.size(); ++i)
                 jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister);
@@ -609,19 +615,21 @@
     return { };
 }
 
-inline Value* B3IRGenerator::emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOperation)
+inline Value* B3IRGenerator::emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOperation, ShouldMask shouldMask)
 {
     ASSERT(m_memoryBaseGPR);
 
     switch (m_mode) {
-    case MemoryMode::BoundsChecking:
+    case MemoryMode::BoundsChecking: {
         // We're not using signal handling at all, we must therefore check that no memory access exceeds the current memory size.
         ASSERT(m_memorySizeGPR);
         ASSERT(sizeOfOperation + offset > offset);
-        m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), m_memorySizeGPR, pointer, sizeOfOperation + offset - 1);
+        GPRReg indexingMask = shouldMask == ShouldMask::Yes ? m_indexingMaskGPR : InvalidGPRReg;
+        m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, origin(), m_memorySizeGPR, indexingMask, pointer, sizeOfOperation + offset - 1);
         break;
+    }
 
-    case MemoryMode::Signaling:
+    case MemoryMode::Signaling: {
         // 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 + offset accesses perform the addition in 64-bit which can push an access above
@@ -641,6 +649,8 @@
     case MemoryMode::NumberOfMemoryModes:
         RELEASE_ASSERT_NOT_REACHED();
     }
+    }
+
     pointer = m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin(), pointer);
     return m_currentBlock->appendNew<WasmAddressValue>(m_proc, origin(), pointer, m_memoryBaseGPR);
 }
@@ -790,7 +800,7 @@
         }
 
     } else
-        result = emitLoadOp(op, emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op)), offset);
+        result = emitLoadOp(op, emitCheckAndPreparePointer(pointer, offset, sizeOfLoadOp(op), ShouldMask::Yes), offset);
 
     return { };
 }
@@ -863,7 +873,7 @@
             this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsMemoryAccess);
         });
     } else
-        emitStoreOp(op, emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op)), value, offset);
+        emitStoreOp(op, emitCheckAndPreparePointer(pointer, offset, sizeOfStoreOp(op), ShouldMask::No), value, offset);
 
     return { };
 }
@@ -1264,6 +1274,7 @@
             ASSERT(sizeRegs[0].sizeRegister != baseMemory);
             ASSERT(sizeRegs[0].sizeRegister != newContext);
             ASSERT(!sizeRegs[0].sizeOffset);
+            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfIndexingMask()), pinnedRegs.indexingMask); // Indexing mask.
             jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
             jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory); // WasmMemory::void*.
         });

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmBinding.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmBinding.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmBinding.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -649,6 +649,7 @@
     // Set up the callee's baseMemory register as well as the memory size registers.
     jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory); // JSWebAssemblyMemory*.
     ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
+    jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfIndexingMask()), pinnedRegs.indexingMask); // Indexing mask.
     jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
     jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory); // WasmMemory::void*.
     for (unsigned i = 1; i < sizeRegs.size(); ++i) {

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemory.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemory.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemory.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -359,6 +359,7 @@
 Memory::Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, MemoryMode mode)
     : m_memory(memory)
     , m_size(initial.bytes())
+    , m_indexingMask(WTF::computeIndexingMask(initial.bytes()))
     , m_initial(initial)
     , m_maximum(maximum)
     , m_mappedCapacity(mappedCapacity)

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemory.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemory.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemory.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -72,6 +72,7 @@
 
     void* memory() const { return m_memory; }
     size_t size() const { return m_size; }
+    size_t indexingMask() const { return m_indexingMask; }
     PageCount sizeInPages() const { return PageCount::fromBytes(m_size); }
 
     PageCount initial() const { return m_initial; }
@@ -84,6 +85,9 @@
     bool grow(PageCount);
 
     void check() {  ASSERT(!deletionHasBegun()); }
+
+    static ptrdiff_t offsetOfIndexingMask() { return OBJECT_OFFSETOF(Memory, m_indexingMask); }
+
 private:
     Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, MemoryMode);
     Memory(PageCount initial, PageCount maximum);
@@ -91,6 +95,7 @@
     // FIXME: we should move these to the instance to avoid a load on instance->instance calls.
     void* m_memory { nullptr };
     size_t m_size { 0 };
+    size_t m_indexingMask { 0 };
     PageCount m_initial;
     PageCount m_maximum;
     size_t m_mappedCapacity { 0 };

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemoryInformation.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemoryInformation.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemoryInformation.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -58,6 +58,7 @@
         Vector<PinnedSizeRegisterInfo> sizeRegisters;
         GPRReg baseMemoryPointer = InvalidGPRReg;
         GPRReg wasmContextPointer = InvalidGPRReg;
+        GPRReg indexingMask = InvalidGPRReg;
 
         // FIXME: We should support more than one memory size register, and we should allow different
         //        WebAssembly.Instance to have different pins. Right now we take a vector with only one entry.
@@ -64,12 +65,13 @@
         //        If we have more than one size register, we can have one for each load size class.
         //        see: https://bugs.webkit.org/show_bug.cgi?id=162952
         Vector<unsigned> pinnedSizes = { 0 };
-        unsigned numberOfPinnedRegisters = pinnedSizes.size() + 1;
+        unsigned numberOfPinnedRegisters = pinnedSizes.size() + 2;
         if (!useFastTLSForContext())
             ++numberOfPinnedRegisters;
         Vector<GPRReg> pinnedRegs = getPinnedRegisters(numberOfPinnedRegisters);
 
         baseMemoryPointer = pinnedRegs.takeLast();
+        indexingMask = pinnedRegs.takeLast();
         if (!useFastTLSForContext())
             wasmContextPointer = pinnedRegs.takeLast();
 
@@ -76,15 +78,16 @@
         ASSERT(pinnedSizes.size() == pinnedRegs.size());
         for (unsigned i = 0; i < pinnedSizes.size(); ++i)
             sizeRegisters.append({ pinnedRegs[i], pinnedSizes[i] });
-        staticPinnedRegisterInfo.construct(WTFMove(sizeRegisters), baseMemoryPointer, wasmContextPointer);
+        staticPinnedRegisterInfo.construct(WTFMove(sizeRegisters), baseMemoryPointer, indexingMask, wasmContextPointer);
     });
 
     return staticPinnedRegisterInfo.get();
 }
 
-PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegisters, GPRReg baseMemoryPointer, GPRReg wasmContextPointer)
+PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegisters, GPRReg baseMemoryPointer, GPRReg indexingMask, GPRReg wasmContextPointer)
     : sizeRegisters(WTFMove(sizeRegisters))
     , baseMemoryPointer(baseMemoryPointer)
+    , indexingMask(indexingMask)
     , wasmContextPointer(wasmContextPointer)
 {
 }

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemoryInformation.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemoryInformation.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/WasmMemoryInformation.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -44,9 +44,10 @@
 struct PinnedRegisterInfo {
     Vector<PinnedSizeRegisterInfo> sizeRegisters;
     GPRReg baseMemoryPointer;
+    GPRReg indexingMask;
     GPRReg wasmContextPointer;
     static const PinnedRegisterInfo& get();
-    PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg, GPRReg);
+    PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg, GPRReg, GPRReg);
 
     RegisterSet toSave(MemoryMode mode) const
     {
@@ -55,6 +56,7 @@
         if (wasmContextPointer != InvalidGPRReg)
             result.set(wasmContextPointer);
         if (mode != MemoryMode::Signaling) {
+            result.set(indexingMask);
             for (const auto& info : sizeRegisters)
                 result.set(info.sizeRegister);
         }

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.cpp (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.cpp	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.cpp	2017-12-19 23:01:00 UTC (rev 226145)
@@ -68,6 +68,7 @@
     ASSERT(m_memory->refCount() == 1);
     m_memoryBase = m_memory->memory();
     m_memorySize = m_memory->size();
+    m_indexingMask = m_memory->indexingMask();
 }
 
 JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)
@@ -116,6 +117,7 @@
         }
         m_memoryBase = memory().memory();
         m_memorySize = memory().size();
+        m_memorySize = memory().indexingMask();
     }
 
     // We need to clear out the old array buffer because it might now be pointing

Modified: branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/_javascript_Core/wasm/js/JSWebAssemblyMemory.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -52,6 +52,7 @@
 
     static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memoryBase); }
     static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memorySize); }
+    static ptrdiff_t offsetOfIndexingMask() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_indexingMask); }
 
 private:
     JSWebAssemblyMemory(VM&, Structure*, Ref<Wasm::Memory>&&);
@@ -61,6 +62,7 @@
 
     void* m_memoryBase;
     size_t m_memorySize;
+    size_t m_indexingMask;
     Ref<Wasm::Memory> m_memory;
     WriteBarrier<JSArrayBuffer> m_bufferWrapper;
     RefPtr<ArrayBuffer> m_buffer;

Modified: branches/safari-604.5.100-branch/Source/WTF/ChangeLog (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/WTF/ChangeLog	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/WTF/ChangeLog	2017-12-19 23:01:00 UTC (rev 226145)
@@ -1,5 +1,23 @@
 2017-12-18  Jason Marcell  <[email protected]>
 
+        Apply patch. rdar://problem/36112003
+
+    2017-12-17  Keith Miller  <[email protected]>
+
+            Use index masking for TypedArrays and and Wasm.
+            https://bugs.webkit.org/show_bug.cgi?id=180920
+
+            Reviewed by Filip Pizlo.
+
+            Copy things from ToT that we will need for a branch.
+
+            * wtf/MathExtras.h:
+            (WTF::computeIndexingMask):
+            * wtf/StdLibExtras.h:
+            (std::clz):
+
+2017-12-18  Jason Marcell  <[email protected]>
+
         Cherry-pick r226068. rdar://problem/36112028
 
     2017-12-16  Filip Pizlo  <[email protected]>

Modified: branches/safari-604.5.100-branch/Source/WTF/wtf/MathExtras.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/WTF/wtf/MathExtras.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/WTF/wtf/MathExtras.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -495,6 +495,11 @@
     return nonEmptyRangesOverlap(leftMin, leftMax, rightMin, rightMax);
 }
 
+inline uint32_t computeIndexingMask(uint32_t size)
+{
+    return static_cast<uint64_t>(static_cast<uint32_t>(-1)) >> std::clz(size);
+}
+
 } // namespace WTF
 
 #endif // #ifndef WTF_MathExtras_h

Modified: branches/safari-604.5.100-branch/Source/WTF/wtf/StdLibExtras.h (226144 => 226145)


--- branches/safari-604.5.100-branch/Source/WTF/wtf/StdLibExtras.h	2017-12-19 23:00:51 UTC (rev 226144)
+++ branches/safari-604.5.100-branch/Source/WTF/wtf/StdLibExtras.h	2017-12-19 23:01:00 UTC (rev 226145)
@@ -519,6 +519,23 @@
 template<class... _Args> struct conjunction : wtf_conjunction_impl<_Args...> { };
 #endif
 
+enum class ZeroStatus {
+    MayBeZero,
+    NonZero
+};
+
+constexpr size_t clz(uint32_t value, ZeroStatus mightBeZero = ZeroStatus::MayBeZero)
+{
+    if (mightBeZero == ZeroStatus::MayBeZero && value) {
+#if COMPILER(MSVC)
+        return __lzcnt(value);
+#else
+        return __builtin_clz(value);
+#endif
+    }
+    return 32;
+}
+
 } // namespace std
 
 #define WTFMove(value) std::move<WTF::CheckMoveParameter>(value)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to