]>
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 StringLiteral < NoChildren
586 def initialize(codeOrigin, value)
588 @value = value[1..-2]
589 raise "Bad string literal
#{value.inspect} at
#{codeOriginString}" unless value.is_a? String
597 other.is_a? StringLiteral and other.value == @value
612 def immediateOperand?
621 class RegisterID < NoChildren
624 def initialize(codeOrigin, name)
631 def self.forName(codeOrigin, name)
632 unless @@mapping[name]
633 @@mapping[name] = RegisterID.new(codeOrigin, name)
659 class FPRegisterID < NoChildren
662 def initialize(codeOrigin, name)
669 def self.forName(codeOrigin, name)
670 unless @@mapping[name]
671 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
692 def immediateOperand?
701 class SpecialRegister < NoChildren
718 def immediateOperand?
727 class Variable < NoChildren
730 def initialize(codeOrigin, name)
737 def self.forName(codeOrigin, name)
738 unless @@mapping[name]
739 @@mapping[name] = Variable.new(codeOrigin, name)
749 "<variable
#{name} at
#{codeOriginString}>"
754 attr_reader :base, :offset
756 def initialize(codeOrigin, base, offset)
760 raise "Bad base
for address
#{base.inspect} at
#{codeOriginString}" unless base.is_a? Variable or base.register?
761 raise "Bad offset
for address
#{offset.inspect} at
#{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
764 def withOffset(extraOffset)
765 Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset
))
773 Address
.new(codeOrigin
, (yield @base), (yield @offset))
777 "#{offset.dump}[#{base.dump}]"
792 def immediateOperand
?
801 class BaseIndex
< Node
802 attr_reader
:base, :index, :scale, :offset
804 def initialize(codeOrigin
, base
, index
, scale
, offset
)
809 raise unless [1, 2, 4, 8].member
? @scale
824 raise "Bad scale at #{codeOriginString}"
828 def withOffset(extraOffset
)
829 BaseIndex
.new(codeOrigin
, @base, @index, @scale, Immediate
.new(codeOrigin
, @offset.value + extraOffset
))
833 [@base, @index, @offset]
837 BaseIndex
.new(codeOrigin
, (yield @base), (yield @index), @scale, (yield @offset))
841 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
856 def immediateOperand
?
865 class AbsoluteAddress
< NoChildren
868 def initialize(codeOrigin
, address
)
873 def withOffset(extraOffset
)
874 AbsoluteAddress
.new(codeOrigin
, Immediate
.new(codeOrigin
, @address.value + extraOffset
))
893 def immediateOperand
?
902 class Instruction
< Node
903 attr_reader
:opcode, :operands, :annotation
905 def initialize(codeOrigin
, opcode
, operands
, annotation
=nil)
909 @annotation = annotation
916 def mapChildren(&proc
)
917 Instruction
.new(codeOrigin
, @opcode, @operands.map(&proc
), @annotation)
921 "\t" + opcode
.to_s +
" " + operands
.collect
{|v
| v
.dump
}.join(", ")
926 when "localAnnotation"
927 $asm.putLocalAnnotation
928 when "globalAnnotation"
929 $asm.putGlobalAnnotation
931 $asm.puts
"#{operands[0].dump}"
933 raise "Unhandled opcode #{opcode} at #{codeOriginString}"
938 class Error
< NoChildren
939 def initialize(codeOrigin
)
948 class ConstDecl
< Node
949 attr_reader
:variable, :value
951 def initialize(codeOrigin
, variable
, value
)
962 ConstDecl
.new(codeOrigin
, (yield @variable), (yield @value))
966 "const #{@variable.dump} = #{@value.dump}"
971 $referencedExternLabels = Array
.new
973 class Label
< NoChildren
976 def initialize(codeOrigin
, name
)
983 def self.forName(codeOrigin
, name
, definedInFile
= false)
984 if $labelMapping[name
]
985 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? Label
987 $labelMapping[name
] = Label
.new(codeOrigin
, name
)
990 $labelMapping[name
].clearExtern()
995 def self.setAsGlobal(codeOrigin
, name
)
996 if $labelMapping[name
]
997 label
= $labelMapping[name
]
998 raise "Label: #{name} declared global multiple times" unless not label
.global
?
1001 newLabel
= Label
.new(codeOrigin
, name
)
1002 newLabel
.setGlobal()
1003 $labelMapping[name
] = newLabel
1007 def self.resetReferenced
1008 $referencedExternLabels = Array
.new
1011 def self.forReferencedExtern()
1012 $referencedExternLabels.each
{
1014 yield "#{label.name}"
1039 class LocalLabel
< NoChildren
1042 def initialize(codeOrigin
, name
)
1047 @
@uniqueNameCounter = 0
1049 def self.forName(codeOrigin
, name
)
1050 if $labelMapping[name
]
1051 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? LocalLabel
1053 $labelMapping[name
] = LocalLabel
.new(codeOrigin
, name
)
1058 def self.unique(comment
)
1059 newName
= "_#{comment}"
1060 if $labelMapping[newName
]
1061 while $labelMapping[newName
= "_#{@@uniqueNameCounter}_#{comment}"]
1062 @
@uniqueNameCounter +
= 1
1065 forName(nil, newName
)
1081 class LabelReference
< Node
1084 def initialize(codeOrigin
, label
)
1094 LabelReference
.new(codeOrigin
, (yield @label))
1102 $labelMapping[name
].is_a
? Label
and $labelMapping[name
].extern
?
1106 if !
$referencedExternLabels.include?(@label) and extern
?
1107 $referencedExternLabels.push(@label)
1131 def immediateOperand
?
1136 class LocalLabelReference
< NoChildren
1139 def initialize(codeOrigin
, label
)
1149 LocalLabelReference
.new(codeOrigin
, (yield @label))
1176 def immediateOperand
?
1181 class Sequence
< Node
1184 def initialize(codeOrigin
, list
)
1193 def mapChildren(&proc
)
1194 Sequence
.new(codeOrigin
, @list.map(&proc
))
1198 list
.collect
{|v
| v
.dump
}.join("\n")
1202 class True
< NoChildren
1207 @
@instance = True
.new
1222 class False
< NoChildren
1227 @
@instance = False
.new
1254 class Setting
< NoChildren
1257 def initialize(codeOrigin
, name
)
1264 def self.forName(codeOrigin
, name
)
1265 unless @
@mapping[name
]
1266 @
@mapping[name
] = Setting
.new(codeOrigin
, name
)
1277 attr_reader
:left, :right
1279 def initialize(codeOrigin
, left
, right
)
1290 And
.new(codeOrigin
, (yield @left), (yield @right))
1294 "(#{left.dump} and #{right.dump})"
1299 attr_reader
:left, :right
1301 def initialize(codeOrigin
, left
, right
)
1312 Or
.new(codeOrigin
, (yield @left), (yield @right))
1316 "(#{left.dump} or #{right.dump})"
1323 def initialize(codeOrigin
, child
)
1333 Not
.new(codeOrigin
, (yield @child))
1337 "(not #{child.dump})"
1341 class Skip
< NoChildren
1342 def initialize(codeOrigin
)
1351 class IfThenElse
< Node
1352 attr_reader
:predicate, :thenCase
1353 attr_accessor
:elseCase
1355 def initialize(codeOrigin
, predicate
, thenCase
)
1357 @predicate = predicate
1358 @thenCase = thenCase
1359 @elseCase = Skip
.new(codeOrigin
)
1364 [@predicate, @thenCase, @elseCase]
1366 [@predicate, @thenCase]
1371 IfThenElse
.new(codeOrigin
, (yield @predicate), (yield @thenCase), (yield @elseCase))
1375 "if #{predicate.dump}\n" + thenCase
.dump +
"\nelse\n" + elseCase
.dump +
"\nend"
1380 attr_reader
:name, :variables, :body
1382 def initialize(codeOrigin
, name
, variables
, body
)
1385 @variables = variables
1390 @variables +
[@body]
1394 Macro
.new(codeOrigin
, @name, @variables.map
{|v
| yield v
}, (yield @body))
1398 "macro #{name}(" + variables
.collect
{|v
| v
.dump
}.join(", ") +
")\n" + body
.dump +
"\nend"
1402 class MacroCall
< Node
1403 attr_reader
:name, :operands, :annotation
1405 def initialize(codeOrigin
, name
, operands
, annotation
)
1408 @operands = operands
1409 raise unless @operands
1410 @operands.each
{|v
| raise unless v
}
1411 @annotation = annotation
1418 def mapChildren(&proc
)
1419 MacroCall
.new(codeOrigin
, @name, @operands.map(&proc
), @annotation)
1423 "\t#{name}(" + operands
.collect
{|v
| v
.dump
}.join(", ") +
")"