Title: [160800] trunk/Source
Revision
160800
Author
benja...@webkit.org
Date
2013-12-18 15:23:53 -0800 (Wed, 18 Dec 2013)

Log Message

Add a simple stack abstraction for x86_64
https://bugs.webkit.org/show_bug.cgi?id=125908

Reviewed by Geoffrey Garen.

Source/_javascript_Core: 

* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::addPtrNoFlags):
Add an explicit abstraction for the "lea" instruction. This is needed
by the experimental JIT to have add and substract without changing the flags.

This is useful for function calls to test the return value, restore the registers,
then branch on the flags from the return value.

Source/WebCore: 

StackAllocator provides an abstraction to make it hard to make mistakes and protects from obvious
issues at runtime.

The key roles of StackAllocators are:
-Provide the necessary stack alignment for function calls (only x86_64 stack for now).
-Provide ways to save registers on the stack, restore or discard them as needed.
-Crash at runtime if an operation would obviously cause a stack inconsistency.

The way simple inconsistencies are detected is through the StackReference object
returned whenever something is added on the stack.
The object keeps a reference to the offset of what has been pushed. When the StackReference
is used to recover the register, if the offset is different, there is a missmatch between
push() and pop() after the object was pushed.

* cssjit/StackAllocator.h: Added.
(WebCore::StackAllocator::StackReference::StackReference):
(WebCore::StackAllocator::StackReference::operator unsigned):
(WebCore::StackAllocator::StackAllocator):
(WebCore::StackAllocator::~StackAllocator):
(WebCore::StackAllocator::push):
(WebCore::StackAllocator::pop):

(WebCore::StackAllocator::alignStackPreFunctionCall):
(WebCore::StackAllocator::unalignStackPostFunctionCall):
Those helpers provide a simple way to have a valid stack prior to a function call.
Since StackAllocator knows the offset and the platform rules, it can adjust the stack
if needed for x86_64.

(WebCore::StackAllocator::discard): Discard a single register or the full stack.

(WebCore::StackAllocator::combine): combining stacks is the way to solve branches
where the stack is used differently in each case.
To do that, the stack is first copied to A and B. Each branch works on its own
StackAllocator copy, then the two copies are linked together to the original stack.

The copies ensure the local consistency in each branch, linking the copies ensure global
consistencies and that both branches end in the same stack state.

(WebCore::StackAllocator::offsetToStackReference): Helper function to access the stack by address
through its StackReference.

(WebCore::StackAllocator::reset):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (160799 => 160800)


--- trunk/Source/_javascript_Core/ChangeLog	2013-12-18 23:12:02 UTC (rev 160799)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-12-18 23:23:53 UTC (rev 160800)
@@ -1,3 +1,18 @@
+2013-12-18  Benjamin Poulain  <benja...@webkit.org>
+
+        Add a simple stack abstraction for x86_64
+        https://bugs.webkit.org/show_bug.cgi?id=125908
+
+        Reviewed by Geoffrey Garen.
+
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::addPtrNoFlags):
+        Add an explicit abstraction for the "lea" instruction. This is needed
+        by the experimental JIT to have add and substract without changing the flags.
+
+        This is useful for function calls to test the return value, restore the registers,
+        then branch on the flags from the return value.
+
 2013-12-18  Mark Hahnenberg  <mhahnenb...@apple.com>
 
         DFG should have a separate StoreBarrier node

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (160799 => 160800)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2013-12-18 23:12:02 UTC (rev 160799)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2013-12-18 23:23:53 UTC (rev 160800)
@@ -228,6 +228,11 @@
         add64(imm, Address(scratchRegister));
     }
 
+    void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
+    {
+        m_assembler.leaq_mr(imm.m_value, srcDest, srcDest);
+    }
+
     void and64(RegisterID src, RegisterID dest)
     {
         m_assembler.andq_rr(src, dest);

Modified: trunk/Source/WebCore/ChangeLog (160799 => 160800)


--- trunk/Source/WebCore/ChangeLog	2013-12-18 23:12:02 UTC (rev 160799)
+++ trunk/Source/WebCore/ChangeLog	2013-12-18 23:23:53 UTC (rev 160800)
@@ -1,3 +1,53 @@
+2013-12-18  Benjamin Poulain  <benja...@webkit.org>
+
+        Add a simple stack abstraction for x86_64
+        https://bugs.webkit.org/show_bug.cgi?id=125908
+
+        Reviewed by Geoffrey Garen.
+
+        StackAllocator provides an abstraction to make it hard to make mistakes and protects from obvious
+        issues at runtime.
+
+        The key roles of StackAllocators are:
+        -Provide the necessary stack alignment for function calls (only x86_64 stack for now).
+        -Provide ways to save registers on the stack, restore or discard them as needed.
+        -Crash at runtime if an operation would obviously cause a stack inconsistency.
+
+        The way simple inconsistencies are detected is through the StackReference object
+        returned whenever something is added on the stack.
+        The object keeps a reference to the offset of what has been pushed. When the StackReference
+        is used to recover the register, if the offset is different, there is a missmatch between
+        push() and pop() after the object was pushed.
+
+        * cssjit/StackAllocator.h: Added.
+        (WebCore::StackAllocator::StackReference::StackReference):
+        (WebCore::StackAllocator::StackReference::operator unsigned):
+        (WebCore::StackAllocator::StackAllocator):
+        (WebCore::StackAllocator::~StackAllocator):
+        (WebCore::StackAllocator::push):
+        (WebCore::StackAllocator::pop):
+
+        (WebCore::StackAllocator::alignStackPreFunctionCall):
+        (WebCore::StackAllocator::unalignStackPostFunctionCall):
+        Those helpers provide a simple way to have a valid stack prior to a function call.
+        Since StackAllocator knows the offset and the platform rules, it can adjust the stack
+        if needed for x86_64.
+
+        (WebCore::StackAllocator::discard): Discard a single register or the full stack.
+
+        (WebCore::StackAllocator::combine): combining stacks is the way to solve branches
+        where the stack is used differently in each case.
+        To do that, the stack is first copied to A and B. Each branch works on its own
+        StackAllocator copy, then the two copies are linked together to the original stack.
+
+        The copies ensure the local consistency in each branch, linking the copies ensure global
+        consistencies and that both branches end in the same stack state.
+
+        (WebCore::StackAllocator::offsetToStackReference): Helper function to access the stack by address
+        through its StackReference.
+
+        (WebCore::StackAllocator::reset):
+
 2013-12-18  Alex Christensen  <achristen...@webkit.org>
 
         [WinCairo] Preparation for GStreamer on Windows.

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (160799 => 160800)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-12-18 23:12:02 UTC (rev 160799)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-12-18 23:23:53 UTC (rev 160800)
@@ -910,6 +910,7 @@
 		265541521489B233000DFC5D /* CursorIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2655414B1489AA2B000DFC5D /* CursorIOS.cpp */; };
 		269239961505E1AA009E57FC /* JSIDBVersionChangeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 269239921505E1AA009E57FC /* JSIDBVersionChangeEvent.h */; };
 		26B9998F1803AE7200D01121 /* RegisterAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 26B9998E1803AE7200D01121 /* RegisterAllocator.h */; };
+		26B999911803B3C900D01121 /* StackAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 26B999901803B3C900D01121 /* StackAllocator.h */; };
 		26C15CF61857E15D00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C15CF41857E15D00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.cpp */; };
 		26C15CF71857E15E00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 26C15CF51857E15D00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.h */; };
 		26C17A3E1491D2D400D12BA2 /* FileSystemIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 26C17A3C1491D2D400D12BA2 /* FileSystemIOS.h */; };
@@ -7563,6 +7564,7 @@
 		269239911505E1AA009E57FC /* JSIDBVersionChangeEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIDBVersionChangeEvent.cpp; sourceTree = "<group>"; };
 		269239921505E1AA009E57FC /* JSIDBVersionChangeEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIDBVersionChangeEvent.h; sourceTree = "<group>"; };
 		26B9998E1803AE7200D01121 /* RegisterAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterAllocator.h; path = cssjit/RegisterAllocator.h; sourceTree = "<group>"; };
+		26B999901803B3C900D01121 /* StackAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackAllocator.h; path = cssjit/StackAllocator.h; sourceTree = "<group>"; };
 		26C15CF41857E15D00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceHandleCFURLConnectionDelegateWithOperationQueue.cpp; sourceTree = "<group>"; };
 		26C15CF51857E15D00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceHandleCFURLConnectionDelegateWithOperationQueue.h; sourceTree = "<group>"; };
 		26C17A3C1491D2D400D12BA2 /* FileSystemIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileSystemIOS.h; path = ios/FileSystemIOS.h; sourceTree = "<group>"; };
@@ -14648,6 +14650,7 @@
 			isa = PBXGroup;
 			children = (
 				26B9998E1803AE7200D01121 /* RegisterAllocator.h */,
+				26B999901803B3C900D01121 /* StackAllocator.h */,
 			);
 			name = cssjit;
 			sourceTree = "<group>";
@@ -24722,6 +24725,7 @@
 				97BC6A5D1505F081001B74AC /* SQLTransactionSyncCallback.h in Headers */,
 				1A2E6E5A0CC55213004A2062 /* SQLValue.h in Headers */,
 				93F1996308245E59001E9ABC /* SSLKeyGenerator.h in Headers */,
+				26B999911803B3C900D01121 /* StackAllocator.h in Headers */,
 				BC7FA62D0D1F0EFF00DB22A9 /* StaticNodeList.h in Headers */,
 				CD8B5A43180D149A008B8E65 /* VideoTrackPrivateMediaSourceAVFObjC.h in Headers */,
 				A5AFB350115151A700B045CB /* StepRange.h in Headers */,

Added: trunk/Source/WebCore/cssjit/StackAllocator.h (0 => 160800)


--- trunk/Source/WebCore/cssjit/StackAllocator.h	                        (rev 0)
+++ trunk/Source/WebCore/cssjit/StackAllocator.h	2013-12-18 23:23:53 UTC (rev 160800)
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StackAllocator_h
+#define StackAllocator_h
+
+#if ENABLE(CSS_SELECTOR_JIT)
+
+#include <_javascript_Core/MacroAssembler.h>
+
+namespace WebCore {
+
+class StackAllocator {
+public:
+    class StackReference {
+    public:
+        StackReference()
+            : m_offsetFromTop(-1)
+        { }
+        explicit StackReference(unsigned offset)
+            : m_offsetFromTop(offset)
+        { }
+        operator unsigned() const { return m_offsetFromTop; }
+    private:
+        unsigned m_offsetFromTop;
+    };
+
+    StackAllocator(JSC::MacroAssembler& assembler)
+        : m_assembler(assembler)
+        , m_offsetFromTop(0)
+        , m_hasFunctionCallPadding(false)
+    {
+    }
+
+    ~StackAllocator()
+    {
+        RELEASE_ASSERT(!m_offsetFromTop);
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+    }
+
+    StackReference push(JSC::MacroAssembler::RegisterID registerID)
+    {
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        m_assembler.push(registerID);
+        m_offsetFromTop += 8;
+        return StackReference(m_offsetFromTop);
+    }
+
+    void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
+    {
+        RELEASE_ASSERT(stackReference == m_offsetFromTop);
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        ASSERT(m_offsetFromTop > 0);
+        m_offsetFromTop -= 8;
+        m_assembler.pop(registerID);
+    }
+
+    void popAndDiscard(StackReference stackReference)
+    {
+        RELEASE_ASSERT(stackReference == m_offsetFromTop);
+        m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(8), JSC::MacroAssembler::stackPointerRegister);
+        m_offsetFromTop -= 8;
+    }
+
+    void alignStackPreFunctionCall()
+    {
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        unsigned topAlignment = 8;
+        if ((topAlignment + m_offsetFromTop) % 16) {
+            m_hasFunctionCallPadding = true;
+            m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-8), JSC::MacroAssembler::stackPointerRegister);
+        }
+    }
+
+    void unalignStackPostFunctionCall()
+    {
+        if (m_hasFunctionCallPadding) {
+            m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(8), JSC::MacroAssembler::stackPointerRegister);
+            m_hasFunctionCallPadding = false;
+        }
+    }
+
+    void discard()
+    {
+        if (m_offsetFromTop)
+            m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(m_offsetFromTop), JSC::MacroAssembler::stackPointerRegister);
+        m_offsetFromTop = 0;
+    }
+
+    void merge(StackAllocator&& stackA, StackAllocator&& stackB)
+    {
+        RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop);
+        RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding);
+        ASSERT(&stackA.m_assembler == &stackB.m_assembler);
+        ASSERT(&m_assembler == &stackB.m_assembler);
+
+        m_offsetFromTop = stackA.m_offsetFromTop;
+        m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding;
+
+        stackA.reset();
+        stackB.reset();
+    }
+
+    void merge(StackAllocator&& stackA, StackAllocator&& stackB, StackAllocator&& stackC)
+    {
+        RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop);
+        RELEASE_ASSERT(stackA.m_offsetFromTop == stackC.m_offsetFromTop);
+        RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding);
+        RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackC.m_hasFunctionCallPadding);
+        ASSERT(&stackA.m_assembler == &stackB.m_assembler);
+        ASSERT(&stackA.m_assembler == &stackC.m_assembler);
+        ASSERT(&m_assembler == &stackB.m_assembler);
+
+        m_offsetFromTop = stackA.m_offsetFromTop;
+        m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding;
+
+        stackA.reset();
+        stackB.reset();
+        stackC.reset();
+    }
+
+    unsigned offsetToStackReference(StackReference stackReference)
+    {
+        RELEASE_ASSERT(m_offsetFromTop >= stackReference);
+        return m_offsetFromTop - stackReference;
+    }
+
+private:
+    void reset()
+    {
+        m_offsetFromTop = 0;
+        m_hasFunctionCallPadding = false;
+    }
+
+    JSC::MacroAssembler& m_assembler;
+    unsigned m_offsetFromTop;
+    bool m_hasFunctionCallPadding;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SELECTOR_JIT)
+
+#endif // StackAllocator_h
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to