]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - offlineasm/transform.rb
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / offlineasm / transform.rb
diff --git a/offlineasm/transform.rb b/offlineasm/transform.rb
new file mode 100644 (file)
index 0000000..86c72be
--- /dev/null
@@ -0,0 +1,474 @@
+# Copyright (C) 2011 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.
+
+require "ast"
+
+#
+# node.resolveSettings(settings)
+#
+# Construct a new AST that does not have any IfThenElse nodes by
+# substituting concrete boolean values for each Setting.
+#
+
+class Node
+    def resolveSettings(settings)
+        mapChildren {
+            | child |
+            child.resolveSettings(settings)
+        }
+    end
+end
+
+class True
+    def resolveSettings(settings)
+        self
+    end
+end
+
+class False
+    def resolveSettings(settings)
+        self
+    end
+end
+
+class Setting
+    def resolveSettings(settings)
+        settings[@name].asNode
+    end
+end
+
+class And
+    def resolveSettings(settings)
+        (@left.resolveSettings(settings).value and @right.resolveSettings(settings).value).asNode
+    end
+end
+
+class Or
+    def resolveSettings(settings)
+        (@left.resolveSettings(settings).value or @right.resolveSettings(settings).value).asNode
+    end
+end
+
+class Not
+    def resolveSettings(settings)
+        (not @child.resolveSettings(settings).value).asNode
+    end
+end
+
+class IfThenElse
+    def resolveSettings(settings)
+        if @predicate.resolveSettings(settings).value
+            @thenCase.resolveSettings(settings)
+        else
+            @elseCase.resolveSettings(settings)
+        end
+    end
+end
+
+class Sequence
+    def resolveSettings(settings)
+        newList = []
+        @list.each {
+            | item |
+            item = item.resolveSettings(settings)
+            if item.is_a? Sequence
+                newList += item.list
+            else
+                newList << item
+            end
+        }
+        Sequence.new(codeOrigin, newList)
+    end
+end
+
+#
+# node.demacroify(macros)
+# node.substitute(mapping)
+#
+# demacroify() constructs a new AST that does not have any Macro
+# nodes, while substitute() replaces Variable nodes with the given
+# nodes in the mapping.
+#
+
+class Node
+    def demacroify(macros)
+        mapChildren {
+            | child |
+            child.demacroify(macros)
+        }
+    end
+    
+    def substitute(mapping)
+        mapChildren {
+            | child |
+            child.substitute(mapping)
+        }
+    end
+    
+    def substituteLabels(mapping)
+        mapChildren {
+            | child |
+            child.substituteLabels(mapping)
+        }
+    end
+end
+
+class Macro
+    def substitute(mapping)
+        myMapping = {}
+        mapping.each_pair {
+            | key, value |
+            unless @variables.include? key
+                myMapping[key] = value
+            end
+        }
+        mapChildren {
+            | child |
+            child.substitute(myMapping)
+        }
+    end
+end
+
+class Variable
+    def substitute(mapping)
+        if mapping[self]
+            mapping[self]
+        else
+            self
+        end
+    end
+end
+
+class LocalLabel
+    def substituteLabels(mapping)
+        if mapping[self]
+            mapping[self]
+        else
+            self
+        end
+    end
+end
+
+class Sequence
+    def substitute(constants)
+        newList = []
+        myConstants = constants.dup
+        @list.each {
+            | item |
+            if item.is_a? ConstDecl
+                myConstants[item.variable] = item.value.substitute(myConstants)
+            else
+                newList << item.substitute(myConstants)
+            end
+        }
+        Sequence.new(codeOrigin, newList)
+    end
+    
+    def renameLabels(comment)
+        mapping = {}
+        
+        @list.each {
+            | item |
+            if item.is_a? LocalLabel
+                mapping[item] = LocalLabel.unique(if comment then comment + "_" else "" end + item.cleanName)
+            end
+        }
+        
+        substituteLabels(mapping)
+    end
+    
+    def demacroify(macros)
+        myMacros = macros.dup
+        @list.each {
+            | item |
+            if item.is_a? Macro
+                myMacros[item.name] = item
+            end
+        }
+        newList = []
+        @list.each {
+            | item |
+            if item.is_a? Macro
+                # Ignore.
+            elsif item.is_a? MacroCall
+                mapping = {}
+                myMyMacros = myMacros.dup
+                raise "Could not find macro #{item.name} at #{item.codeOriginString}" unless myMacros[item.name]
+                raise "Argument count mismatch for call to #{item.name} at #{item.codeOriginString}" unless item.operands.size == myMacros[item.name].variables.size
+                item.operands.size.times {
+                    | idx |
+                    if item.operands[idx].is_a? Variable and myMacros[item.operands[idx].name]
+                        myMyMacros[myMacros[item.name].variables[idx].name] = myMacros[item.operands[idx].name]
+                        mapping[myMacros[item.name].variables[idx].name] = nil
+                    elsif item.operands[idx].is_a? Macro
+                        myMyMacros[myMacros[item.name].variables[idx].name] = item.operands[idx]
+                        mapping[myMacros[item.name].variables[idx].name] = nil
+                    else
+                        myMyMacros[myMacros[item.name].variables[idx]] = nil
+                        mapping[myMacros[item.name].variables[idx]] = item.operands[idx]
+                    end
+                }
+                newList += myMacros[item.name].body.substitute(mapping).demacroify(myMyMacros).renameLabels(item.name).list
+            else
+                newList << item.demacroify(myMacros)
+            end
+        }
+        Sequence.new(codeOrigin, newList).substitute({})
+    end
+end
+
+#
+# node.resolveOffsets(offsets, sizes)
+#
+# Construct a new AST that has offset values instead of symbolic
+# offsets.
+#
+
+class Node
+    def resolveOffsets(offsets, sizes)
+        mapChildren {
+            | child |
+            child.resolveOffsets(offsets, sizes)
+        }
+    end
+end
+
+class StructOffset
+    def resolveOffsets(offsets, sizes)
+        if offsets[self]
+            Immediate.new(codeOrigin, offsets[self])
+        else
+            self
+        end
+    end
+end
+
+class Sizeof
+    def resolveOffsets(offsets, sizes)
+        if sizes[self]
+            Immediate.new(codeOrigin, sizes[self])
+        else
+            puts "Could not find #{self.inspect} in #{sizes.keys.inspect}"
+            puts "sizes = #{sizes.inspect}"
+            self
+        end
+    end
+end
+
+#
+# node.fold
+#
+# Resolve constant references and compute arithmetic expressions.
+#
+
+class Node
+    def fold
+        mapChildren {
+            | child |
+            child.fold
+        }
+    end
+end
+
+class AddImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value + @right.value)
+    end
+end
+
+class SubImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value - @right.value)
+    end
+end
+
+class MulImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value * @right.value)
+    end
+end
+
+class NegImmediate
+    def fold
+        @child = @child.fold
+        return self unless @child.is_a? Immediate
+        Immediate.new(codeOrigin, -@child.value)
+    end
+end
+
+class OrImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value | @right.value)
+    end
+end
+
+class AndImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value & @right.value)
+    end
+end
+
+class XorImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value ^ @right.value)
+    end
+end
+
+class BitnotImmediate
+    def fold
+        @child = @child.fold
+        return self unless @child.is_a? Immediate
+        Immediate.new(codeOrigin, ~@child.value)
+    end
+end
+
+#
+# node.resolveAfterSettings(offsets, sizes)
+#
+# Compile assembly against a set of offsets.
+#
+
+class Node
+    def resolve(offsets, sizes)
+        demacroify({}).resolveOffsets(offsets, sizes).fold
+    end
+end
+
+#
+# node.validate
+#
+# Checks that the node is ready for backend compilation.
+#
+
+class Node
+    def validate
+        raise "Unresolved #{dump} at #{codeOriginString}"
+    end
+    
+    def validateChildren
+        children.each {
+            | node |
+            node.validate
+        }
+    end
+end
+
+class Sequence
+    def validate
+        validateChildren
+    end
+end
+
+class Immediate
+    def validate
+    end
+end
+
+class RegisterID
+    def validate
+    end
+end
+
+class FPRegisterID
+    def validate
+    end
+end
+
+class Address
+    def validate
+        validateChildren
+    end
+end
+
+class BaseIndex
+    def validate
+        validateChildren
+    end
+end
+
+class AbsoluteAddress
+    def validate
+        validateChildren
+    end
+end
+
+class Instruction
+    def validate
+        validateChildren
+    end
+end
+
+class Error
+    def validate
+    end
+end
+
+class Label
+    def validate
+    end
+end
+
+class LocalLabel
+    def validate
+    end
+end
+
+class LabelReference
+    def validate
+    end
+end
+
+class LocalLabelReference
+    def validate
+    end
+end
+
+class Skip
+    def validate
+    end
+end
+