]>
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.
25 # Base utility types for the AST.
28 # Valid methods for Node:
30 # node.children -> Returns an array of immediate children.
32 # node.descendents -> Returns an array of all strict descendants (children
33 # and children of children, transitively).
35 # node.flatten -> Returns an array containing the strict descendants and
38 # node.filter(type) -> Returns an array containing those elements in
39 # node.flatten that are of the given type (is_a? type returns true).
41 # node.mapChildren{|v| ...} -> Returns a new node with all children
42 # replaced according to the given block.
46 # node.filter(Setting).uniq -> Returns all of the settings that the AST's
47 # IfThenElse blocks depend on.
49 # node.filter(StructOffset).uniq -> Returns all of the structure offsets
50 # that the AST depends on.
53 attr_reader
:codeOrigin
55 def initialize(codeOrigin
)
56 @codeOrigin = codeOrigin
64 children
.collect
{|v
| v
.flatten
}.flatten
72 flatten
.select
{|v
| v
.is_a
? type
}
76 class NoChildren
< Node
77 def initialize(codeOrigin
)
91 attr_reader
:struct, :field
93 def initialize(struct
, field
)
99 @struct.hash +
@field.hash
* 3
103 @struct == other
.struct
and @field == other
.field
111 class StructOffset
< NoChildren
112 attr_reader
:struct, :field
114 def initialize(codeOrigin
, struct
, field
)
122 def self.forField(codeOrigin
, struct
, field
)
123 key
= StructOffsetKey
.new(struct
, field
)
125 unless @
@mapping[key
]
126 @
@mapping[key
] = StructOffset
.new(codeOrigin
, struct
, field
)
132 "#{struct}::#{field}"
136 if @struct !
= other
.struct
137 return @struct <=> other
.struct
139 @field <=> other
.field
159 class Sizeof
< NoChildren
162 def initialize(codeOrigin
, struct
)
169 def self.forName(codeOrigin
, struct
)
170 unless @
@mapping[struct
]
171 @
@mapping[struct
] = Sizeof
.new(codeOrigin
, struct
)
181 @struct <=> other
.struct
201 class Immediate
< NoChildren
204 def initialize(codeOrigin
, value
)
207 raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value
.is_a
? Integer
215 other
.is_a
? Immediate
and other
.value
== @value
235 class AddImmediates
< Node
236 attr_reader
:left, :right
238 def initialize(codeOrigin
, left
, right
)
249 AddImmediates
.new(codeOrigin
, (yield @left), (yield @right))
253 "(#{left.dump} + #{right.dump})"
273 class SubImmediates < Node
274 attr_reader :left, :right
276 def initialize(codeOrigin, left, right)
287 SubImmediates.new(codeOrigin, (yield @left), (yield @right))
291 "(#{left.dump} - #{right.dump})"
311 class MulImmediates < Node
312 attr_reader :left, :right
314 def initialize(codeOrigin, left, right)
325 MulImmediates.new(codeOrigin, (yield @left), (yield @right))
329 "(#{left.dump} * #{right.dump})"
349 class NegImmediate < Node
352 def initialize(codeOrigin, child)
362 NegImmediate.new(codeOrigin, (yield @child))
386 class OrImmediates < Node
387 attr_reader :left, :right
389 def initialize(codeOrigin, left, right)
400 OrImmediates.new(codeOrigin, (yield @left), (yield @right))
404 "(#{left.dump} | #{right.dump})"
424 class AndImmediates < Node
425 attr_reader :left, :right
427 def initialize(codeOrigin, left, right)
438 AndImmediates.new(codeOrigin, (yield @left), (yield @right))
442 "(#{left.dump} & #{right.dump})"
462 class XorImmediates < Node
463 attr_reader :left, :right
465 def initialize(codeOrigin, left, right)
476 XorImmediates.new(codeOrigin, (yield @left), (yield @right))
480 "(#{left.dump} ^
#{right.dump})"
500 class BitnotImmediate < Node
503 def initialize(codeOrigin, child)
513 BitnotImmediate.new(codeOrigin, (yield @child))
537 class RegisterID < NoChildren
540 def initialize(codeOrigin, name)
547 def self.forName(codeOrigin, name)
548 unless @@mapping[name]
549 @@mapping[name] = RegisterID.new(codeOrigin, name)
575 class FPRegisterID < NoChildren
578 def initialize(codeOrigin, name)
585 def self.forName(codeOrigin, name)
586 unless @@mapping[name]
587 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
613 class SpecialRegister < NoChildren
635 class Variable < NoChildren
638 def initialize(codeOrigin, name)
645 def self.forName(codeOrigin, name)
646 unless @@mapping[name]
647 @@mapping[name] = Variable.new(codeOrigin, name)
657 "<variable
#{name} at
#{codeOriginString}>"
662 attr_reader :base, :offset
664 def initialize(codeOrigin, base, offset)
668 raise "Bad base
for address
#{base.inspect} at
#{codeOriginString}" unless base.is_a? Variable or base.register?
669 raise "Bad offset
for address
#{offset.inspect} at
#{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
677 Address.new(codeOrigin, (yield @base), (yield @offset))
681 "#{offset.dump}[#{base.dump}]"
701 class BaseIndex < Node
702 attr_reader :base, :index, :scale, :offset
704 def initialize(codeOrigin, base, index, scale, offset)
709 raise unless [1, 2, 4, 8].member? @scale
724 raise "Bad scale at
#{codeOriginString}"
729 [@base, @index, @offset]
733 BaseIndex.new(codeOrigin, (yield @base), (yield @index), @scale, (yield @offset))
737 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
757 class AbsoluteAddress < NoChildren
760 def initialize(codeOrigin, address)
786 class Instruction < Node
787 attr_reader :opcode, :operands
789 def initialize(codeOrigin, opcode, operands)
799 def mapChildren(&proc)
800 Instruction.new(codeOrigin, @opcode, @operands.map(&proc))
804 "\t" + opcode
.to_s +
" " + operands
.collect
{|v
| v
.dump
}.join(", ")
808 class Error
< NoChildren
809 def initialize(codeOrigin
)
818 class ConstDecl
< Node
819 attr_reader
:variable, :value
821 def initialize(codeOrigin
, variable
, value
)
832 ConstDecl
.new(codeOrigin
, (yield @variable), (yield @value))
836 "const #{@variable.dump} = #{@value.dump}"
842 class Label
< NoChildren
845 def initialize(codeOrigin
, name
)
850 def self.forName(codeOrigin
, name
)
851 if $labelMapping[name
]
852 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? Label
854 $labelMapping[name
] = Label
.new(codeOrigin
, name
)
864 class LocalLabel
< NoChildren
867 def initialize(codeOrigin
, name
)
872 @
@uniqueNameCounter = 0
874 def self.forName(codeOrigin
, name
)
875 if $labelMapping[name
]
876 raise "Label name collision: #{name}" unless $labelMapping[name
].is_a
? LocalLabel
878 $labelMapping[name
] = LocalLabel
.new(codeOrigin
, name
)
883 def self.unique(comment
)
884 newName
= "_#{comment}"
885 if $labelMapping[newName
]
886 while $labelMapping[newName
= "_#{@@uniqueNameCounter}_#{comment}"]
887 @
@uniqueNameCounter +
= 1
890 forName(nil, newName
)
906 class LabelReference
< Node
909 def initialize(codeOrigin
, label
)
919 LabelReference
.new(codeOrigin
, (yield @label))
943 class LocalLabelReference
< NoChildren
946 def initialize(codeOrigin
, label
)
956 LocalLabelReference
.new(codeOrigin
, (yield @label))
980 class Sequence
< Node
983 def initialize(codeOrigin
, list
)
992 def mapChildren(&proc
)
993 Sequence
.new(codeOrigin
, @list.map(&proc
))
997 list
.collect
{|v
| v
.dump
}.join("\n")
1001 class True
< NoChildren
1006 @
@instance = True
.new
1021 class False
< NoChildren
1026 @
@instance = False
.new
1053 class Setting
< NoChildren
1056 def initialize(codeOrigin
, name
)
1063 def self.forName(codeOrigin
, name
)
1064 unless @
@mapping[name
]
1065 @
@mapping[name
] = Setting
.new(codeOrigin
, name
)
1076 attr_reader
:left, :right
1078 def initialize(codeOrigin
, left
, right
)
1089 And
.new(codeOrigin
, (yield @left), (yield @right))
1093 "(#{left.dump} and #{right.dump})"
1098 attr_reader
:left, :right
1100 def initialize(codeOrigin
, left
, right
)
1111 Or
.new(codeOrigin
, (yield @left), (yield @right))
1115 "(#{left.dump} or #{right.dump})"
1122 def initialize(codeOrigin
, child
)
1132 Not
.new(codeOrigin
, (yield @child))
1136 "(not #{child.dump})"
1140 class Skip
< NoChildren
1141 def initialize(codeOrigin
)
1150 class IfThenElse
< Node
1151 attr_reader
:predicate, :thenCase
1152 attr_accessor
:elseCase
1154 def initialize(codeOrigin
, predicate
, thenCase
)
1156 @predicate = predicate
1157 @thenCase = thenCase
1158 @elseCase = Skip
.new(codeOrigin
)
1163 [@predicate, @thenCase, @elseCase]
1165 [@predicate, @thenCase]
1170 IfThenElse
.new(codeOrigin
, (yield @predicate), (yield @thenCase), (yield @elseCase))
1174 "if #{predicate.dump}\n" + thenCase
.dump +
"\nelse\n" + elseCase
.dump +
"\nend"
1179 attr_reader
:name, :variables, :body
1181 def initialize(codeOrigin
, name
, variables
, body
)
1184 @variables = variables
1189 @variables +
[@body]
1193 Macro
.new(codeOrigin
, @name, @variables.map
{|v
| yield v
}, (yield @body))
1197 "macro #{name}(" + variables
.collect
{|v
| v
.dump
}.join(", ") +
")\n" + body
.dump +
"\nend"
1201 class MacroCall
< Node
1202 attr_reader
:name, :operands
1204 def initialize(codeOrigin
, name
, operands
)
1207 @operands = operands
1208 raise unless @operands
1209 @operands.each
{|v
| raise unless v
}
1216 def mapChildren(&proc
)
1217 MacroCall
.new(codeOrigin
, @name, @operands.map(&proc
))
1221 "\t#{name}(" + operands
.collect
{|v
| v
.dump
}.join(", ") +
")"