Title: [171763] branches/ftlopt/Source/_javascript_Core
Revision
171763
Author
mhahnenb...@apple.com
Date
2014-07-29 14:03:06 -0700 (Tue, 29 Jul 2014)

Log Message

Support for-in in the FTL
https://bugs.webkit.org/show_bug.cgi?id=134140

Reviewed by Filip Pizlo.

* dfg/DFGSSALoweringPhase.cpp:
(JSC::DFG::SSALoweringPhase::handleNode):
* ftl/FTLAbstractHeapRepository.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileHasIndexedProperty):
(JSC::FTL::LowerDFGToLLVM::compileHasGenericProperty):
(JSC::FTL::LowerDFGToLLVM::compileHasStructureProperty):
(JSC::FTL::LowerDFGToLLVM::compileGetDirectPname):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength):
(JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator):
(JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname):
(JSC::FTL::LowerDFGToLLVM::compileToIndexString):

Modified Paths

Diff

Modified: branches/ftlopt/Source/_javascript_Core/ChangeLog (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/ChangeLog	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/ChangeLog	2014-07-29 21:03:06 UTC (rev 171763)
@@ -1,3 +1,29 @@
+2014-07-28  Mark Hahnenberg  <mhahnenb...@apple.com>
+
+        Support for-in in the FTL
+        https://bugs.webkit.org/show_bug.cgi?id=134140
+
+        Reviewed by Filip Pizlo.
+
+        * dfg/DFGSSALoweringPhase.cpp:
+        (JSC::DFG::SSALoweringPhase::handleNode):
+        * ftl/FTLAbstractHeapRepository.cpp:
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLIntrinsicRepository.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileHasIndexedProperty):
+        (JSC::FTL::LowerDFGToLLVM::compileHasGenericProperty):
+        (JSC::FTL::LowerDFGToLLVM::compileHasStructureProperty):
+        (JSC::FTL::LowerDFGToLLVM::compileGetDirectPname):
+        (JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength):
+        (JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator):
+        (JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator):
+        (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname):
+        (JSC::FTL::LowerDFGToLLVM::compileToIndexString):
+
 2014-07-25  Mark Hahnenberg  <mhahnenb...@apple.com>
 
         Remove JSPropertyNameIterator

Modified: branches/ftlopt/Source/_javascript_Core/dfg/DFGSSALoweringPhase.cpp (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/dfg/DFGSSALoweringPhase.cpp	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/dfg/DFGSSALoweringPhase.cpp	2014-07-29 21:03:06 UTC (rev 171763)
@@ -69,6 +69,7 @@
     {
         switch (m_node->op()) {
         case GetByVal:
+        case HasIndexedProperty:
             lowerBoundsCheck(m_node->child1(), m_node->child2(), m_node->child3());
             break;
             

Modified: branches/ftlopt/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.cpp (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.cpp	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.cpp	2014-07-29 21:03:06 UTC (rev 171763)
@@ -29,6 +29,7 @@
 #if ENABLE(FTL_JIT)
 
 #include "GetterSetter.h"
+#include "JSPropertyNameEnumerator.h"
 #include "JSScope.h"
 #include "JSVariableObject.h"
 #include "JSCInlines.h"

Modified: branches/ftlopt/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2014-07-29 21:03:06 UTC (rev 171763)
@@ -59,6 +59,10 @@
     macro(JSFunction_executable, JSFunction::offsetOfExecutable()) \
     macro(JSFunction_scope, JSFunction::offsetOfScopeChain()) \
     macro(JSObject_butterfly, JSObject::butterflyOffset()) \
+    macro(JSPropertyNameEnumerator_cachedInlineCapacity, JSPropertyNameEnumerator::cachedInlineCapacityOffset()) \
+    macro(JSPropertyNameEnumerator_cachedPropertyNamesLength, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()) \
+    macro(JSPropertyNameEnumerator_cachedPropertyNamesVector, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()) \
+    macro(JSPropertyNameEnumerator_cachedStructureID, JSPropertyNameEnumerator::cachedStructureIDOffset()) \
     macro(JSScope_next, JSScope::offsetOfNext()) \
     macro(JSString_flags, JSString::offsetOfFlags()) \
     macro(JSString_length, JSString::offsetOfLength()) \

Modified: branches/ftlopt/Source/_javascript_Core/ftl/FTLCapabilities.cpp (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2014-07-29 21:03:06 UTC (rev 171763)
@@ -157,6 +157,14 @@
     case Int52Rep:
     case DoubleConstant:
     case Int52Constant:
+    case HasGenericProperty:
+    case HasStructureProperty:
+    case GetDirectPname:
+    case GetEnumerableLength:
+    case GetStructurePropertyEnumerator:
+    case GetGenericPropertyEnumerator:
+    case GetEnumeratorPname:
+    case ToIndexString:
         // These are OK.
         break;
     case Identity:
@@ -205,6 +213,17 @@
             return CannotCompile;
         }
         break;
+    case HasIndexedProperty:
+        switch (node->arrayMode().type()) {
+        case Array::ForceExit:
+        case Array::Int32:
+        case Array::Double:
+        case Array::Contiguous:
+            break;
+        default:
+            return CannotCompile;
+        }
+        break;
     case GetByVal:
         switch (node->arrayMode().type()) {
         case Array::ForceExit:

Modified: branches/ftlopt/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2014-07-29 21:03:06 UTC (rev 171763)
@@ -54,19 +54,24 @@
 
 #define FOR_EACH_FUNCTION_TYPE(macro) \
     macro(C_JITOperation_EC, functionType(intPtr, intPtr, intPtr)) \
+    macro(C_JITOperation_ECZ, functionType(intPtr, intPtr, intPtr, int32)) \
+    macro(C_JITOperation_ECZC, functionType(intPtr, intPtr, intPtr, int32, intPtr)) \
     macro(C_JITOperation_EJ, functionType(intPtr, intPtr, int64)) \
     macro(C_JITOperation_EJssJss, functionType(intPtr, intPtr, intPtr, intPtr)) \
     macro(C_JITOperation_EJssJssJss, functionType(intPtr, intPtr, intPtr, intPtr, intPtr)) \
     macro(C_JITOperation_ESt, functionType(intPtr, intPtr, intPtr)) \
+    macro(C_JITOperation_EZ, functionType(intPtr, intPtr, int32)) \
     macro(D_JITOperation_D, functionType(doubleType, doubleType)) \
     macro(I_JITOperation_EJss, functionType(intPtr, intPtr, intPtr)) \
     macro(J_JITOperation_E, functionType(int64, intPtr)) \
     macro(J_JITOperation_EA, functionType(int64, intPtr, intPtr)) \
     macro(J_JITOperation_EAZ, functionType(int64, intPtr, intPtr, int32)) \
     macro(J_JITOperation_ECJ, functionType(int64, intPtr, intPtr, int64)) \
+    macro(J_JITOperation_ECZ, functionType(int64, intPtr, intPtr, int32)) \
     macro(J_JITOperation_EDA, functionType(int64, intPtr, doubleType, intPtr)) \
     macro(J_JITOperation_EJ, functionType(int64, intPtr, int64)) \
     macro(J_JITOperation_EJA, functionType(int64, intPtr, int64, intPtr)) \
+    macro(J_JITOperation_EJC, functionType(int64, intPtr, int64, intPtr)) \
     macro(J_JITOperation_EJJ, functionType(int64, intPtr, int64, int64)) \
     macro(J_JITOperation_EJssZ, functionType(int64, intPtr, intPtr, int32)) \
     macro(J_JITOperation_ESsiJI, functionType(int64, intPtr, intPtr, int64, intPtr)) \
@@ -92,8 +97,9 @@
     macro(V_JITOperation_EVwsJ, functionType(voidType, intPtr, intPtr, int64)) \
     macro(V_JITOperation_J, functionType(voidType, int64)) \
     macro(V_JITOperation_Z, functionType(voidType, int32)) \
-    macro(Z_JITOperation_D, functionType(int32, doubleType))
-
+    macro(Z_JITOperation_D, functionType(int32, doubleType)) \
+    macro(Z_JITOperation_EC, functionType(int32, intPtr, intPtr))
+    
 class IntrinsicRepository : public CommonValues {
 public:
     IntrinsicRepository(LContext);

Modified: branches/ftlopt/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (171762 => 171763)


--- branches/ftlopt/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2014-07-29 21:00:51 UTC (rev 171762)
+++ branches/ftlopt/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2014-07-29 21:03:06 UTC (rev 171763)
@@ -692,6 +692,34 @@
         case StoreBarrierWithNullCheck:
             compileStoreBarrierWithNullCheck();
             break;
+        case HasIndexedProperty:
+            compileHasIndexedProperty();
+            break;
+        case HasGenericProperty:
+            compileHasGenericProperty();
+            break;
+        case HasStructureProperty:
+            compileHasStructureProperty();
+            break;
+        case GetDirectPname:
+            compileGetDirectPname();
+            break;
+        case GetEnumerableLength:
+            compileGetEnumerableLength();
+            break;
+        case GetStructurePropertyEnumerator:
+            compileGetStructurePropertyEnumerator();
+            break;
+        case GetGenericPropertyEnumerator:
+            compileGetGenericPropertyEnumerator();
+            break;
+        case GetEnumeratorPname:
+            compileGetEnumeratorPname();
+            break;
+        case ToIndexString:
+            compileToIndexString();
+            break;
+
         case PhantomLocal:
         case SetArgument:
         case LoopHint:
@@ -4055,6 +4083,225 @@
 #endif
     }
     
+    void compileHasIndexedProperty()
+    {
+        switch (m_node->arrayMode().type()) {
+        case Array::Int32:
+        case Array::Contiguous: {
+            LValue base = lowCell(m_node->child1());
+            LValue index = lowInt32(m_node->child2());
+            LValue storage = lowStorage(m_node->child3());
+
+            IndexedAbstractHeap& heap = m_node->arrayMode().type() == Array::Int32 ?
+                m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
+
+            LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous check hole"));
+            LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous slow case"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty int/contiguous continuation"));
+
+            if (!m_node->arrayMode().isInBounds()) {
+                m_out.branch(
+                    m_out.aboveOrEqual(
+                        index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
+                    rarely(slowCase), usually(checkHole));
+            } else
+                m_out.jump(checkHole);
+
+            LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase); 
+            ValueFromBlock checkHoleResult = m_out.anchor(
+                m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_node->child2()))));
+            m_out.branch(checkHoleResult.value(), usually(continuation), rarely(slowCase));
+
+            m_out.appendTo(slowCase, continuation);
+            ValueFromBlock slowResult = m_out.anchor(m_out.equal(
+                m_out.constInt64(JSValue::encode(jsBoolean(true))), 
+                vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index)));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult));
+            return;
+        }
+        case Array::Double: {
+            LValue base = lowCell(m_node->child1());
+            LValue index = lowInt32(m_node->child2());
+            LValue storage = lowStorage(m_node->child3());
+            
+            IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
+            
+            LBasicBlock checkHole = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double check hole"));
+            LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double slow case"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasIndexedProperty double continuation"));
+            
+            if (!m_node->arrayMode().isInBounds()) {
+                m_out.branch(
+                    m_out.aboveOrEqual(
+                        index, m_out.load32NonNegative(storage, m_heaps.Butterfly_publicLength)),
+                    rarely(slowCase), usually(checkHole));
+            } else
+                m_out.jump(checkHole);
+
+            LBasicBlock lastNext = m_out.appendTo(checkHole, slowCase);
+            LValue doubleValue = m_out.loadDouble(baseIndex(heap, storage, index, m_node->child2()));
+            ValueFromBlock checkHoleResult = m_out.anchor(
+                m_out.doubleNotEqualOrUnordered(doubleValue, doubleValue));
+            m_out.branch(checkHoleResult.value(), rarely(slowCase), usually(continuation));
+            
+            m_out.appendTo(slowCase, continuation);
+            ValueFromBlock slowResult = m_out.anchor(m_out.equal(
+                m_out.constInt64(JSValue::encode(jsBoolean(true))), 
+                vmCall(m_out.operation(operationHasIndexedProperty), m_callFrame, base, index)));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(continuation, lastNext);
+            setBoolean(m_out.phi(m_out.boolean, checkHoleResult, slowResult));
+            return;
+        }
+            
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+    }
+
+    void compileHasGenericProperty()
+    {
+        LValue base = lowJSValue(m_node->child1());
+        LValue property = lowCell(m_node->child2());
+        setJSValue(vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property));
+    }
+
+    void compileHasStructureProperty()
+    {
+        LValue base = lowJSValue(m_node->child1());
+        LValue property = lowString(m_node->child2());
+        LValue enumerator = lowCell(m_node->child3());
+
+        LBasicBlock correctStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty correct structure"));
+        LBasicBlock wrongStructure = FTL_NEW_BLOCK(m_out, ("HasStructureProperty wrong structure"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("HasStructureProperty continuation"));
+
+        m_out.branch(m_out.notEqual(
+            m_out.load32(base, m_heaps.JSCell_structureID),
+            m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
+            rarely(wrongStructure), usually(correctStructure));
+
+        LBasicBlock lastNext = m_out.appendTo(correctStructure, wrongStructure);
+        ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue);
+        m_out.jump(continuation);
+
+        m_out.appendTo(wrongStructure, continuation);
+        ValueFromBlock wrongStructureResult = m_out.anchor(
+            m_out.equal(
+                m_out.constInt64(JSValue::encode(jsBoolean(true))), 
+                vmCall(m_out.operation(operationHasGenericProperty), m_callFrame, base, property)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setBoolean(m_out.phi(m_out.boolean, correctStructureResult, wrongStructureResult));
+    }
+
+    void compileGetDirectPname()
+    {
+        LValue base = lowCell(m_graph.varArgChild(m_node, 0));
+        LValue property = lowCell(m_graph.varArgChild(m_node, 1));
+        LValue index = lowInt32(m_graph.varArgChild(m_node, 2));
+        LValue enumerator = lowCell(m_graph.varArgChild(m_node, 3));
+
+        LBasicBlock checkOffset = FTL_NEW_BLOCK(m_out, ("GetDirectPname check offset"));
+        LBasicBlock inlineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname inline load"));
+        LBasicBlock outOfLineLoad = FTL_NEW_BLOCK(m_out, ("GetDirectPname out-of-line load"));
+        LBasicBlock slowCase = FTL_NEW_BLOCK(m_out, ("GetDirectPname slow case"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetDirectPname continuation"));
+
+        m_out.branch(m_out.notEqual(
+            m_out.load32(base, m_heaps.JSCell_structureID),
+            m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
+            rarely(slowCase), usually(checkOffset));
+
+        LBasicBlock lastNext = m_out.appendTo(checkOffset, inlineLoad);
+        m_out.branch(m_out.aboveOrEqual(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity)),
+            unsure(outOfLineLoad), unsure(inlineLoad));
+
+        m_out.appendTo(inlineLoad, outOfLineLoad);
+        ValueFromBlock inlineResult = m_out.anchor(
+            m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), 
+                base, m_out.zeroExt(index, m_out.int64), ScaleEight, JSObject::offsetOfInlineStorage())));
+        m_out.jump(continuation);
+
+        m_out.appendTo(outOfLineLoad, slowCase);
+        LValue storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
+        LValue realIndex = m_out.signExt(
+            m_out.neg(m_out.sub(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedInlineCapacity))), 
+            m_out.int64);
+        int32_t offsetOfFirstProperty = static_cast<int32_t>(offsetInButterfly(firstOutOfLineOffset)) * sizeof(EncodedJSValue);
+        ValueFromBlock outOfLineResult = m_out.anchor(
+            m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), storage, realIndex, ScaleEight, offsetOfFirstProperty)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(slowCase, continuation);
+        ValueFromBlock slowCaseResult = m_out.anchor(
+            vmCall(m_out.operation(operationGetByVal), m_callFrame, base, property));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(m_out.int64, inlineResult, outOfLineResult, slowCaseResult));
+    }
+
+    void compileGetEnumerableLength()
+    {
+        LValue base = lowCell(m_node->child1());
+        setInt32(vmCall(m_out.operation(operationGetEnumerableLength), m_callFrame, base));
+    }
+
+    void compileGetStructurePropertyEnumerator()
+    {
+        LValue base = lowCell(m_node->child1());
+        LValue length = lowInt32(m_node->child2());
+        setJSValue(vmCall(m_out.operation(operationGetStructurePropertyEnumerator), m_callFrame, base, length));
+    }
+
+    void compileGetGenericPropertyEnumerator()
+    {
+        LValue base = lowCell(m_node->child1());
+        LValue length = lowInt32(m_node->child2());
+        LValue enumerator = lowCell(m_node->child3());
+        setJSValue(vmCall(m_out.operation(operationGetGenericPropertyEnumerator), m_callFrame, base, length, enumerator));
+    }
+
+    void compileGetEnumeratorPname()
+    {
+        LValue enumerator = lowCell(m_node->child1());
+        LValue index = lowInt32(m_node->child2());
+
+        LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname in bounds"));
+        LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname out of bounds"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname continuation"));
+
+        m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesLength)),
+            usually(inBounds), rarely(outOfBounds));
+
+        LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
+        LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
+        ValueFromBlock inBoundsResult = m_out.anchor(
+            m_out.load64(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector, 
+                storage, m_out.signExt(index, m_out.int64), ScaleEight)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(outOfBounds, continuation);
+        ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull));
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult));
+    }
+
+    void compileToIndexString()
+    {
+        LValue index = lowInt32(m_node->child1());
+        setJSValue(vmCall(m_out.operation(operationToIndexString), m_callFrame, index));
+    }
+
     LValue getFunctionBySymbol(const CString symbol)
     {
         if (!m_ftlState.symbolTable.contains(symbol)) 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to