]>
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
237 class AddImmediates
< Node
238 attr_reader
:left, :right
240 def initialize(codeOrigin
, left
, right
)
251 AddImmediates
.new(codeOrigin
, (yield @left), (yield @right))
255 "(#{left.dump} + #{right.dump})"
275 class SubImmediates < Node
276 attr_reader :left, :right
278 def initialize(codeOrigin, left, right)
289 SubImmediates.new(codeOrigin, (yield @left), (yield @right))
293 "(#{left.dump} - #{right.dump})"
313 class MulImmediates < Node
314 attr_reader :left, :right
316 def initialize(codeOrigin, left, right)
327 MulImmediates.new(codeOrigin, (yield @left), (yield @right))
331 "(#{left.dump} * #{right.dump})"
351 class NegImmediate < Node
354 def initialize(codeOrigin, child)
364 NegImmediate.new(codeOrigin, (yield @child))
388 class OrImmediates < Node
389 attr_reader :left, :right
391 def initialize(codeOrigin, left, right)
402 OrImmediates.new(codeOrigin, (yield @left), (yield @right))
406 "(#{left.dump} | #{right.dump})"
426 class AndImmediates < Node
427 attr_reader :left, :right
429 def initialize(codeOrigin, left, right)
440 AndImmediates.new(codeOrigin, (yield @left), (yield @right))
444 "(#{left.dump} & #{right.dump})"
464 class XorImmediates < Node
465 attr_reader :left, :right
467 def initialize(codeOrigin, left, right)
478 XorImmediates.new(codeOrigin, (yield @left), (yield @right))
482 "(#{left.dump} ^
#{right.dump})"
502 class BitnotImmediate < Node
505 def initialize(codeOrigin, child)
515 BitnotImmediate.new(codeOrigin, (yield @child))
539 class RegisterID < NoChildren
542 def initialize(codeOrigin, name)
549 def self.forName(codeOrigin, name)
550 unless @@mapping[name]
551 @@mapping[name] = RegisterID.new(codeOrigin, name)
577 class FPRegisterID < NoChildren
580 def initialize(codeOrigin, name)
587 def self.forName(codeOrigin, name)
588 unless @@mapping[name]
589 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
615 class SpecialRegister < NoChildren
637 class Variable < NoChildren
640 def initialize(codeOrigin, name)
647 def self.forName(codeOrigin, name)
648 unless @@mapping[name]
649 @@mapping[name] = Variable.new(codeOrigin, name)
659 "<variable
#{name} at
#{codeOriginString}>"
664 attr_reader :base, :offset
666 def initialize(codeOrigin, base, offset)
670 raise "Bad base
for address
#{base.inspect} at
#{codeOriginString}" unless base.is_a? Variable or base.register?
671 raise "Bad offset
for address
#{offset.inspect} at
#{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
674 def withOffset(extraOffset)
675 Address.new(codeOrigin, @base, Immediate.new(codeOrigin, @offset.value + extraOffset
))
683 Address
.new(codeOrigin
, (yield @base), (yield @offset))
687 "#{offset.dump}[#{base.dump}]"
707 class BaseIndex
< Node
708 attr_reader
:base, :index, :scale, :offset
710 def initialize(codeOrigin
, base
, index
, scale
, offset
)
715 raise unless [1, 2, 4, 8].member
? @scale
730 raise "Bad scale at #{codeOriginString}"
734 def withOffset(extraOffset
)
735 BaseIndex
.new(codeOrigin
, @base, @index, @scale, Immediate
.new(codeOrigin
, @offset.value + extraOffset
))
739 [@base, @index, @offset]
743 BaseIndex
.new(codeOrigin
, (yield @base), (yield @index), @scale, (yield @offset))
747 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
767 class AbsoluteAddress
< NoChildren
770 def initialize(codeOrigin
, address
)
775 def withOffset(extraOffset
)
776 AbsoluteAddress
.new(codeOrigin
, Immediate
.new(codeOrigin
, @address.value + extraOffset
))
800 class Instruction
< Node
801 attr_reader
:opcode, :operands, :annotation
803 def initialize(codeOrigin
, opcode
, operands
, annotation
=nil)
807 @annotation = annotation
814 def mapChildren(&proc
)
815 Instruction
.new(codeOrigin
, @opcode, @operands.map(&proc
), @annotation)
819 "\t" + opcode
.to_s +
" " + operands
.collect
{|v
| v
.dump
}.join(", ")
824 when "localAnnotation"
825 $asm.putLocalAnnotation
826 when "globalAnnotation"
827 $asm.putGlobalAnnotation
829 raise "Unhandled opcode #{opcode} at #{codeOriginString}"
834 class Error
< NoChildren
835 def initialize(codeOrigin
)
844 class ConstDecl
< Node
845 attr_reader
:variable, :value
847 def initialize(codeOrigin
, variable
, value
)
858 ConstDecl
.new(codeOrigin
, (yield @variable), (yield @value))
862 "const #{@variable.dump} = #{@value.dump}"
868 class Label
< NoChildren
871 def initialize(codeOrigin
, name
)
876 def self.forName(codeOrigin
, name
)
877 if $labelMapping[name
]
878 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? Label
880 $labelMapping[name
] = Label
.new(codeOrigin
, name
)
890 class LocalLabel
< NoChildren
893 def initialize(codeOrigin
, name
)
898 @
@uniqueNameCounter = 0
900 def self.forName(codeOrigin
, name
)
901 if $labelMapping[name
]
902 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? LocalLabel
904 $labelMapping[name
] = LocalLabel
.new(codeOrigin
, name
)
909 def self.unique(comment
)
910 newName
= "_#{comment}"
911 if $labelMapping[newName
]
912 while $labelMapping[newName
= "_#{@@uniqueNameCounter}_#{comment}"]
913 @
@uniqueNameCounter +
= 1
916 forName(nil, newName
)
932 class LabelReference
< Node
935 def initialize(codeOrigin
, label
)
945 LabelReference
.new(codeOrigin
, (yield @label))
969 class LocalLabelReference
< NoChildren
972 def initialize(codeOrigin
, label
)
982 LocalLabelReference
.new(codeOrigin
, (yield @label))
1006 class Sequence
< Node
1009 def initialize(codeOrigin
, list
)
1018 def mapChildren(&proc
)
1019 Sequence
.new(codeOrigin
, @list.map(&proc
))
1023 list
.collect
{|v
| v
.dump
}.join("\n")
1027 class True
< NoChildren
1032 @
@instance = True
.new
1047 class False
< NoChildren
1052 @
@instance = False
.new
1079 class Setting
< NoChildren
1082 def initialize(codeOrigin
, name
)
1089 def self.forName(codeOrigin
, name
)
1090 unless @
@mapping[name
]
1091 @
@mapping[name
] = Setting
.new(codeOrigin
, name
)
1102 attr_reader
:left, :right
1104 def initialize(codeOrigin
, left
, right
)
1115 And
.new(codeOrigin
, (yield @left), (yield @right))
1119 "(#{left.dump} and #{right.dump})"
1124 attr_reader
:left, :right
1126 def initialize(codeOrigin
, left
, right
)
1137 Or
.new(codeOrigin
, (yield @left), (yield @right))
1141 "(#{left.dump} or #{right.dump})"
1148 def initialize(codeOrigin
, child
)
1158 Not
.new(codeOrigin
, (yield @child))
1162 "(not #{child.dump})"
1166 class Skip
< NoChildren
1167 def initialize(codeOrigin
)
1176 class IfThenElse
< Node
1177 attr_reader
:predicate, :thenCase
1178 attr_accessor
:elseCase
1180 def initialize(codeOrigin
, predicate
, thenCase
)
1182 @predicate = predicate
1183 @thenCase = thenCase
1184 @elseCase = Skip
.new(codeOrigin
)
1189 [@predicate, @thenCase, @elseCase]
1191 [@predicate, @thenCase]
1196 IfThenElse
.new(codeOrigin
, (yield @predicate), (yield @thenCase), (yield @elseCase))
1200 "if #{predicate.dump}\n" + thenCase
.dump +
"\nelse\n" + elseCase
.dump +
"\nend"
1205 attr_reader
:name, :variables, :body
1207 def initialize(codeOrigin
, name
, variables
, body
)
1210 @variables = variables
1215 @variables +
[@body]
1219 Macro
.new(codeOrigin
, @name, @variables.map
{|v
| yield v
}, (yield @body))
1223 "macro #{name}(" + variables
.collect
{|v
| v
.dump
}.join(", ") +
")\n" + body
.dump +
"\nend"
1227 class MacroCall
< Node
1228 attr_reader
:name, :operands, :annotation
1230 def initialize(codeOrigin
, name
, operands
, annotation
)
1233 @operands = operands
1234 raise unless @operands
1235 @operands.each
{|v
| raise unless v
}
1236 @annotation = annotation
1243 def mapChildren(&proc
)
1244 MacroCall
.new(codeOrigin
, @name, @operands.map(&proc
), @annotation)
1248 "\t#{name}(" + operands
.collect
{|v
| v
.dump
}.join(", ") +
")"