]>
git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/ast.rb
1 # Copyright (C) 2011 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22 # THE POSSIBILITY OF SUCH DAMAGE.
27 # Base utility types for the AST.
30 # Valid methods for Node:
32 # node.children -> Returns an array of immediate children.
34 # node.descendents -> Returns an array of all strict descendants (children
35 # and children of children, transitively).
37 # node.flatten -> Returns an array containing the strict descendants and
40 # node.filter(type) -> Returns an array containing those elements in
41 # node.flatten that are of the given type (is_a? type returns true).
43 # node.mapChildren{|v| ...} -> Returns a new node with all children
44 # replaced according to the given block.
48 # node.filter(Setting).uniq -> Returns all of the settings that the AST's
49 # IfThenElse blocks depend on.
51 # node.filter(StructOffset).uniq -> Returns all of the structure offsets
52 # that the AST depends on.
55 attr_reader
:codeOrigin
57 def initialize(codeOrigin
)
58 @codeOrigin = codeOrigin
66 children
.collect
{|v
| v
.flatten
}.flatten
74 flatten
.select
{|v
| v
.is_a
? type
}
78 class NoChildren
< Node
79 def initialize(codeOrigin
)
93 attr_reader
:struct, :field
95 def initialize(struct
, field
)
101 @struct.hash +
@field.hash
* 3
105 @struct == other
.struct
and @field == other
.field
113 class StructOffset
< NoChildren
114 attr_reader
:struct, :field
116 def initialize(codeOrigin
, struct
, field
)
124 def self.forField(codeOrigin
, struct
, field
)
125 key
= StructOffsetKey
.new(struct
, field
)
127 unless @
@mapping[key
]
128 @
@mapping[key
] = StructOffset
.new(codeOrigin
, struct
, field
)
134 "#{struct}::#{field}"
138 if @struct !
= other
.struct
139 return @struct <=> other
.struct
141 @field <=> other
.field
161 class Sizeof
< NoChildren
164 def initialize(codeOrigin
, struct
)
171 def self.forName(codeOrigin
, struct
)
172 unless @
@mapping[struct
]
173 @
@mapping[struct
] = Sizeof
.new(codeOrigin
, struct
)
183 @struct <=> other
.struct
203 class Immediate
< NoChildren
206 def initialize(codeOrigin
, value
)
209 raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value
.is_a
? Integer
217 other
.is_a
? Immediate
and other
.value
== @value
232 def immediateOperand
?
241 class AddImmediates
< Node
242 attr_reader
:left, :right
244 def initialize(codeOrigin
, left
, right
)
255 AddImmediates
.new(codeOrigin
, (yield @left), (yield @right))
259 "(#{left.dump} + #{right.dump})"
263 "#{left.value} +
#{right.value}"
278 def immediateOperand?
287 class SubImmediates < Node
288 attr_reader :left, :right
290 def initialize(codeOrigin, left, right)
301 SubImmediates.new(codeOrigin, (yield @left), (yield @right))
305 "(#{left.dump} - #{right.dump})"
309 "#{left.value} - #{right.value}"
324 def immediateOperand?
333 class MulImmediates < Node
334 attr_reader :left, :right
336 def initialize(codeOrigin, left, right)
347 MulImmediates.new(codeOrigin, (yield @left), (yield @right))
351 "(#{left.dump} * #{right.dump})"
366 def immediateOperand?
375 class NegImmediate < Node
378 def initialize(codeOrigin, child)
388 NegImmediate.new(codeOrigin, (yield @child))
407 def immediateOperand?
416 class OrImmediates < Node
417 attr_reader :left, :right
419 def initialize(codeOrigin, left, right)
430 OrImmediates.new(codeOrigin, (yield @left), (yield @right))
434 "(#{left.dump} | #{right.dump})"
449 def immediateOperand?
458 class AndImmediates < Node
459 attr_reader :left, :right
461 def initialize(codeOrigin, left, right)
472 AndImmediates.new(codeOrigin, (yield @left), (yield @right))
476 "(#{left.dump} & #{right.dump})"
491 def immediateOperand?
500 class XorImmediates < Node
501 attr_reader :left, :right
503 def initialize(codeOrigin, left, right)
514 XorImmediates.new(codeOrigin, (yield @left), (yield @right))
518 "(#{left.dump} ^
#{right.dump})"
533 def immediateOperand?
542 class BitnotImmediate < Node
545 def initialize(codeOrigin, child)
555 BitnotImmediate.new(codeOrigin, (yield @child))
574 def immediateOperand?
583 class RegisterID < NoChildren
586 def initialize(codeOrigin, name)
593 def self.forName(codeOrigin, name)
594 unless @@mapping[name]
595 @@mapping[name] = RegisterID.new(codeOrigin, name)
621 class FPRegisterID < NoChildren
624 def initialize(codeOrigin, name)
631 def self.forName(codeOrigin, name)
632 unless @@mapping[name]
633 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
654 def immediateOperand?
663 class SpecialRegister < NoChildren
680 def immediateOperand?
689 class Variable < NoChildren
692 def initialize(codeOrigin, name)
699 def self.forName(codeOrigin, name)
700 unless @@mapping[name]
701 @@mapping[name] = Variable.new(codeOrigin, name)
711 "<variable
#{name} at
#{codeOriginString}>"
716 attr_reader :base, :offset
718 def initialize(codeOrigin, base, offset)
722 raise "Bad base
for address
#{base.inspect} at
#{codeOriginString}" unless base.is_a? Variable or base.register?
723 raise "Bad offset
for address
#{offset.inspect} at
#{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
726 def withOffset(extraOffset)
727 Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset
))
735 Address
.new(codeOrigin
, (yield @base), (yield @offset))
739 "#{offset.dump}[#{base.dump}]"
754 def immediateOperand
?
763 class BaseIndex
< Node
764 attr_reader
:base, :index, :scale, :offset
766 def initialize(codeOrigin
, base
, index
, scale
, offset
)
771 raise unless [1, 2, 4, 8].member
? @scale
786 raise "Bad scale at #{codeOriginString}"
790 def withOffset(extraOffset
)
791 BaseIndex
.new(codeOrigin
, @base, @index, @scale, Immediate
.new(codeOrigin
, @offset.value + extraOffset
))
795 [@base, @index, @offset]
799 BaseIndex
.new(codeOrigin
, (yield @base), (yield @index), @scale, (yield @offset))
803 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
818 def immediateOperand
?
827 class AbsoluteAddress
< NoChildren
830 def initialize(codeOrigin
, address
)
835 def withOffset(extraOffset
)
836 AbsoluteAddress
.new(codeOrigin
, Immediate
.new(codeOrigin
, @address.value + extraOffset
))
855 def immediateOperand
?
864 class Instruction
< Node
865 attr_reader
:opcode, :operands, :annotation
867 def initialize(codeOrigin
, opcode
, operands
, annotation
=nil)
871 @annotation = annotation
878 def mapChildren(&proc
)
879 Instruction
.new(codeOrigin
, @opcode, @operands.map(&proc
), @annotation)
883 "\t" + opcode
.to_s +
" " + operands
.collect
{|v
| v
.dump
}.join(", ")
888 when "localAnnotation"
889 $asm.putLocalAnnotation
890 when "globalAnnotation"
891 $asm.putGlobalAnnotation
893 raise "Unhandled opcode #{opcode} at #{codeOriginString}"
898 class Error
< NoChildren
899 def initialize(codeOrigin
)
908 class ConstDecl
< Node
909 attr_reader
:variable, :value
911 def initialize(codeOrigin
, variable
, value
)
922 ConstDecl
.new(codeOrigin
, (yield @variable), (yield @value))
926 "const #{@variable.dump} = #{@value.dump}"
931 $referencedExternLabels = Array
.new
933 class Label
< NoChildren
936 def initialize(codeOrigin
, name
)
943 def self.forName(codeOrigin
, name
, definedInFile
= false)
944 if $labelMapping[name
]
945 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? Label
947 $labelMapping[name
] = Label
.new(codeOrigin
, name
)
950 $labelMapping[name
].clearExtern()
955 def self.setAsGlobal(codeOrigin
, name
)
956 if $labelMapping[name
]
957 label
= $labelMapping[name
]
958 raise "Label: #{name} declared global multiple times" unless not label
.global
?
961 newLabel
= Label
.new(codeOrigin
, name
)
963 $labelMapping[name
] = newLabel
967 def self.resetReferenced
968 $referencedExternLabels = Array
.new
971 def self.forReferencedExtern()
972 $referencedExternLabels.each
{
974 yield "#{label.name}"
999 class LocalLabel
< NoChildren
1002 def initialize(codeOrigin
, name
)
1007 @
@uniqueNameCounter = 0
1009 def self.forName(codeOrigin
, name
)
1010 if $labelMapping[name
]
1011 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? LocalLabel
1013 $labelMapping[name
] = LocalLabel
.new(codeOrigin
, name
)
1018 def self.unique(comment
)
1019 newName
= "_#{comment}"
1020 if $labelMapping[newName
]
1021 while $labelMapping[newName
= "_#{@@uniqueNameCounter}_#{comment}"]
1022 @
@uniqueNameCounter +
= 1
1025 forName(nil, newName
)
1041 class LabelReference
< Node
1044 def initialize(codeOrigin
, label
)
1054 LabelReference
.new(codeOrigin
, (yield @label))
1062 $labelMapping[name
].is_a
? Label
and $labelMapping[name
].extern
?
1066 if !
$referencedExternLabels.include?(@label) and extern
?
1067 $referencedExternLabels.push(@label)
1091 def immediateOperand
?
1096 class LocalLabelReference
< NoChildren
1099 def initialize(codeOrigin
, label
)
1109 LocalLabelReference
.new(codeOrigin
, (yield @label))
1136 def immediateOperand
?
1141 class Sequence
< Node
1144 def initialize(codeOrigin
, list
)
1153 def mapChildren(&proc
)
1154 Sequence
.new(codeOrigin
, @list.map(&proc
))
1158 list
.collect
{|v
| v
.dump
}.join("\n")
1162 class True
< NoChildren
1167 @
@instance = True
.new
1182 class False
< NoChildren
1187 @
@instance = False
.new
1214 class Setting
< NoChildren
1217 def initialize(codeOrigin
, name
)
1224 def self.forName(codeOrigin
, name
)
1225 unless @
@mapping[name
]
1226 @
@mapping[name
] = Setting
.new(codeOrigin
, name
)
1237 attr_reader
:left, :right
1239 def initialize(codeOrigin
, left
, right
)
1250 And
.new(codeOrigin
, (yield @left), (yield @right))
1254 "(#{left.dump} and #{right.dump})"
1259 attr_reader
:left, :right
1261 def initialize(codeOrigin
, left
, right
)
1272 Or
.new(codeOrigin
, (yield @left), (yield @right))
1276 "(#{left.dump} or #{right.dump})"
1283 def initialize(codeOrigin
, child
)
1293 Not
.new(codeOrigin
, (yield @child))
1297 "(not #{child.dump})"
1301 class Skip
< NoChildren
1302 def initialize(codeOrigin
)
1311 class IfThenElse
< Node
1312 attr_reader
:predicate, :thenCase
1313 attr_accessor
:elseCase
1315 def initialize(codeOrigin
, predicate
, thenCase
)
1317 @predicate = predicate
1318 @thenCase = thenCase
1319 @elseCase = Skip
.new(codeOrigin
)
1324 [@predicate, @thenCase, @elseCase]
1326 [@predicate, @thenCase]
1331 IfThenElse
.new(codeOrigin
, (yield @predicate), (yield @thenCase), (yield @elseCase))
1335 "if #{predicate.dump}\n" + thenCase
.dump +
"\nelse\n" + elseCase
.dump +
"\nend"
1340 attr_reader
:name, :variables, :body
1342 def initialize(codeOrigin
, name
, variables
, body
)
1345 @variables = variables
1350 @variables +
[@body]
1354 Macro
.new(codeOrigin
, @name, @variables.map
{|v
| yield v
}, (yield @body))
1358 "macro #{name}(" + variables
.collect
{|v
| v
.dump
}.join(", ") +
")\n" + body
.dump +
"\nend"
1362 class MacroCall
< Node
1363 attr_reader
:name, :operands, :annotation
1365 def initialize(codeOrigin
, name
, operands
, annotation
)
1368 @operands = operands
1369 raise unless @operands
1370 @operands.each
{|v
| raise unless v
}
1371 @annotation = annotation
1378 def mapChildren(&proc
)
1379 MacroCall
.new(codeOrigin
, @name, @operands.map(&proc
), @annotation)
1383 "\t#{name}(" + operands
.collect
{|v
| v
.dump
}.join(", ") +
")"