]> git.saurik.com Git - apple/javascriptcore.git/blame - offlineasm/ast.rb
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / offlineasm / ast.rb
CommitLineData
6fe7ccc8
A
1# Copyright (C) 2011 Apple Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
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.
11#
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.
23
24#
25# Base utility types for the AST.
26#
27
28# Valid methods for Node:
29#
30# node.children -> Returns an array of immediate children.
31#
32# node.descendents -> Returns an array of all strict descendants (children
33# and children of children, transitively).
34#
35# node.flatten -> Returns an array containing the strict descendants and
36# the node itself.
37#
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).
40#
41# node.mapChildren{|v| ...} -> Returns a new node with all children
42# replaced according to the given block.
43#
44# Examples:
45#
46# node.filter(Setting).uniq -> Returns all of the settings that the AST's
47# IfThenElse blocks depend on.
48#
49# node.filter(StructOffset).uniq -> Returns all of the structure offsets
50# that the AST depends on.
51
52class Node
53 attr_reader :codeOrigin
54
55 def initialize(codeOrigin)
56 @codeOrigin = codeOrigin
57 end
58
59 def codeOriginString
60 @codeOrigin.to_s
61 end
62
63 def descendants
64 children.collect{|v| v.flatten}.flatten
65 end
66
67 def flatten
68 [self] + descendants
69 end
70
71 def filter(type)
72 flatten.select{|v| v.is_a? type}
73 end
74end
75
76class NoChildren < Node
77 def initialize(codeOrigin)
78 super(codeOrigin)
79 end
80
81 def children
82 []
83 end
84
85 def mapChildren
86 self
87 end
88end
89
90class StructOffsetKey
91 attr_reader :struct, :field
92
93 def initialize(struct, field)
94 @struct = struct
95 @field = field
96 end
97
98 def hash
99 @struct.hash + @field.hash * 3
100 end
101
102 def eql?(other)
103 @struct == other.struct and @field == other.field
104 end
105end
106
107#
108# AST nodes.
109#
110
111class StructOffset < NoChildren
112 attr_reader :struct, :field
113
114 def initialize(codeOrigin, struct, field)
115 super(codeOrigin)
116 @struct = struct
117 @field = field
118 end
119
120 @@mapping = {}
121
122 def self.forField(codeOrigin, struct, field)
123 key = StructOffsetKey.new(struct, field)
124
125 unless @@mapping[key]
126 @@mapping[key] = StructOffset.new(codeOrigin, struct, field)
127 end
128 @@mapping[key]
129 end
130
131 def dump
132 "#{struct}::#{field}"
133 end
134
135 def <=>(other)
136 if @struct != other.struct
137 return @struct <=> other.struct
138 end
139 @field <=> other.field
140 end
141
142 def address?
143 false
144 end
145
146 def label?
147 false
148 end
149
150 def immediate?
151 true
152 end
153
154 def register?
155 false
156 end
157end
158
159class Sizeof < NoChildren
160 attr_reader :struct
161
162 def initialize(codeOrigin, struct)
163 super(codeOrigin)
164 @struct = struct
165 end
166
167 @@mapping = {}
168
169 def self.forName(codeOrigin, struct)
170 unless @@mapping[struct]
171 @@mapping[struct] = Sizeof.new(codeOrigin, struct)
172 end
173 @@mapping[struct]
174 end
175
176 def dump
177 "sizeof #{@struct}"
178 end
179
180 def <=>(other)
181 @struct <=> other.struct
182 end
183
184 def address?
185 false
186 end
187
188 def label?
189 false
190 end
191
192 def immediate?
193 true
194 end
195
196 def register?
197 false
198 end
199end
200
201class Immediate < NoChildren
202 attr_reader :value
203
204 def initialize(codeOrigin, value)
205 super(codeOrigin)
206 @value = value
207 raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value.is_a? Integer
208 end
209
210 def dump
211 "#{value}"
212 end
213
214 def ==(other)
215 other.is_a? Immediate and other.value == @value
216 end
217
218 def address?
219 false
220 end
221
222 def label?
223 false
224 end
225
226 def immediate?
227 true
228 end
229
230 def register?
231 false
232 end
233end
234
235class AddImmediates < Node
236 attr_reader :left, :right
237
238 def initialize(codeOrigin, left, right)
239 super(codeOrigin)
240 @left = left
241 @right = right
242 end
243
244 def children
245 [@left, @right]
246 end
247
248 def mapChildren
249 AddImmediates.new(codeOrigin, (yield @left), (yield @right))
250 end
251
252 def dump
253 "(#{left.dump} + #{right.dump})"
254 end
255
256 def address?
257 false
258 end
259
260 def label?
261 false
262 end
263
264 def immediate?
265 true
266 end
267
268 def register?
269 false
270 end
271end
272
273class SubImmediates < Node
274 attr_reader :left, :right
275
276 def initialize(codeOrigin, left, right)
277 super(codeOrigin)
278 @left = left
279 @right = right
280 end
281
282 def children
283 [@left, @right]
284 end
285
286 def mapChildren
287 SubImmediates.new(codeOrigin, (yield @left), (yield @right))
288 end
289
290 def dump
291 "(#{left.dump} - #{right.dump})"
292 end
293
294 def address?
295 false
296 end
297
298 def label?
299 false
300 end
301
302 def immediate?
303 true
304 end
305
306 def register?
307 false
308 end
309end
310
311class MulImmediates < Node
312 attr_reader :left, :right
313
314 def initialize(codeOrigin, left, right)
315 super(codeOrigin)
316 @left = left
317 @right = right
318 end
319
320 def children
321 [@left, @right]
322 end
323
324 def mapChildren
325 MulImmediates.new(codeOrigin, (yield @left), (yield @right))
326 end
327
328 def dump
329 "(#{left.dump} * #{right.dump})"
330 end
331
332 def address?
333 false
334 end
335
336 def label?
337 false
338 end
339
340 def immediate?
341 true
342 end
343
344 def register?
345 false
346 end
347end
348
349class NegImmediate < Node
350 attr_reader :child
351
352 def initialize(codeOrigin, child)
353 super(codeOrigin)
354 @child = child
355 end
356
357 def children
358 [@child]
359 end
360
361 def mapChildren
362 NegImmediate.new(codeOrigin, (yield @child))
363 end
364
365 def dump
366 "(-#{@child.dump})"
367 end
368
369 def address?
370 false
371 end
372
373 def label?
374 false
375 end
376
377 def immediate?
378 true
379 end
380
381 def register?
382 false
383 end
384end
385
386class OrImmediates < Node
387 attr_reader :left, :right
388
389 def initialize(codeOrigin, left, right)
390 super(codeOrigin)
391 @left = left
392 @right = right
393 end
394
395 def children
396 [@left, @right]
397 end
398
399 def mapChildren
400 OrImmediates.new(codeOrigin, (yield @left), (yield @right))
401 end
402
403 def dump
404 "(#{left.dump} | #{right.dump})"
405 end
406
407 def address?
408 false
409 end
410
411 def label?
412 false
413 end
414
415 def immediate?
416 true
417 end
418
419 def register?
420 false
421 end
422end
423
424class AndImmediates < Node
425 attr_reader :left, :right
426
427 def initialize(codeOrigin, left, right)
428 super(codeOrigin)
429 @left = left
430 @right = right
431 end
432
433 def children
434 [@left, @right]
435 end
436
437 def mapChildren
438 AndImmediates.new(codeOrigin, (yield @left), (yield @right))
439 end
440
441 def dump
442 "(#{left.dump} & #{right.dump})"
443 end
444
445 def address?
446 false
447 end
448
449 def label?
450 false
451 end
452
453 def immediate?
454 true
455 end
456
457 def register?
458 false
459 end
460end
461
462class XorImmediates < Node
463 attr_reader :left, :right
464
465 def initialize(codeOrigin, left, right)
466 super(codeOrigin)
467 @left = left
468 @right = right
469 end
470
471 def children
472 [@left, @right]
473 end
474
475 def mapChildren
476 XorImmediates.new(codeOrigin, (yield @left), (yield @right))
477 end
478
479 def dump
480 "(#{left.dump} ^ #{right.dump})"
481 end
482
483 def address?
484 false
485 end
486
487 def label?
488 false
489 end
490
491 def immediate?
492 true
493 end
494
495 def register?
496 false
497 end
498end
499
500class BitnotImmediate < Node
501 attr_reader :child
502
503 def initialize(codeOrigin, child)
504 super(codeOrigin)
505 @child = child
506 end
507
508 def children
509 [@child]
510 end
511
512 def mapChildren
513 BitnotImmediate.new(codeOrigin, (yield @child))
514 end
515
516 def dump
517 "(~#{@child.dump})"
518 end
519
520 def address?
521 false
522 end
523
524 def label?
525 false
526 end
527
528 def immediate?
529 true
530 end
531
532 def register?
533 false
534 end
535end
536
537class RegisterID < NoChildren
538 attr_reader :name
539
540 def initialize(codeOrigin, name)
541 super(codeOrigin)
542 @name = name
543 end
544
545 @@mapping = {}
546
547 def self.forName(codeOrigin, name)
548 unless @@mapping[name]
549 @@mapping[name] = RegisterID.new(codeOrigin, name)
550 end
551 @@mapping[name]
552 end
553
554 def dump
555 name
556 end
557
558 def address?
559 false
560 end
561
562 def label?
563 false
564 end
565
566 def immediate?
567 false
568 end
569
570 def register?
571 true
572 end
573end
574
575class FPRegisterID < NoChildren
576 attr_reader :name
577
578 def initialize(codeOrigin, name)
579 super(codeOrigin)
580 @name = name
581 end
582
583 @@mapping = {}
584
585 def self.forName(codeOrigin, name)
586 unless @@mapping[name]
587 @@mapping[name] = FPRegisterID.new(codeOrigin, name)
588 end
589 @@mapping[name]
590 end
591
592 def dump
593 name
594 end
595
596 def address?
597 false
598 end
599
600 def label?
601 false
602 end
603
604 def immediate?
605 false
606 end
607
608 def register?
609 true
610 end
611end
612
613class SpecialRegister < NoChildren
614 def initialize(name)
615 @name = name
616 end
617
618 def address?
619 false
620 end
621
622 def label?
623 false
624 end
625
626 def immediate?
627 false
628 end
629
630 def register?
631 true
632 end
633end
634
635class Variable < NoChildren
636 attr_reader :name
637
638 def initialize(codeOrigin, name)
639 super(codeOrigin)
640 @name = name
641 end
642
643 @@mapping = {}
644
645 def self.forName(codeOrigin, name)
646 unless @@mapping[name]
647 @@mapping[name] = Variable.new(codeOrigin, name)
648 end
649 @@mapping[name]
650 end
651
652 def dump
653 name
654 end
655
656 def inspect
657 "<variable #{name} at #{codeOriginString}>"
658 end
659end
660
661class Address < Node
662 attr_reader :base, :offset
663
664 def initialize(codeOrigin, base, offset)
665 super(codeOrigin)
666 @base = base
667 @offset = 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?
670 end
671
672 def children
673 [@base, @offset]
674 end
675
676 def mapChildren
677 Address.new(codeOrigin, (yield @base), (yield @offset))
678 end
679
680 def dump
681 "#{offset.dump}[#{base.dump}]"
682 end
683
684 def address?
685 true
686 end
687
688 def label?
689 false
690 end
691
692 def immediate?
693 false
694 end
695
696 def register?
697 false
698 end
699end
700
701class BaseIndex < Node
702 attr_reader :base, :index, :scale, :offset
703
704 def initialize(codeOrigin, base, index, scale, offset)
705 super(codeOrigin)
706 @base = base
707 @index = index
708 @scale = scale
709 raise unless [1, 2, 4, 8].member? @scale
710 @offset = offset
711 end
712
713 def scaleShift
714 case scale
715 when 1
716 0
717 when 2
718 1
719 when 4
720 2
721 when 8
722 3
723 else
724 raise "Bad scale at #{codeOriginString}"
725 end
726 end
727
728 def children
729 [@base, @index, @offset]
730 end
731
732 def mapChildren
733 BaseIndex.new(codeOrigin, (yield @base), (yield @index), @scale, (yield @offset))
734 end
735
736 def dump
737 "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
738 end
739
740 def address?
741 true
742 end
743
744 def label?
745 false
746 end
747
748 def immediate?
749 false
750 end
751
752 def register?
753 false
754 end
755end
756
757class AbsoluteAddress < NoChildren
758 attr_reader :address
759
760 def initialize(codeOrigin, address)
761 super(codeOrigin)
762 @address = address
763 end
764
765 def dump
766 "#{address.dump}[]"
767 end
768
769 def address?
770 true
771 end
772
773 def label?
774 false
775 end
776
777 def immediate?
778 false
779 end
780
781 def register?
782 false
783 end
784end
785
786class Instruction < Node
787 attr_reader :opcode, :operands
788
789 def initialize(codeOrigin, opcode, operands)
790 super(codeOrigin)
791 @opcode = opcode
792 @operands = operands
793 end
794
795 def children
796 operands
797 end
798
799 def mapChildren(&proc)
800 Instruction.new(codeOrigin, @opcode, @operands.map(&proc))
801 end
802
803 def dump
804 "\t" + opcode.to_s + " " + operands.collect{|v| v.dump}.join(", ")
805 end
806end
807
808class Error < NoChildren
809 def initialize(codeOrigin)
810 super(codeOrigin)
811 end
812
813 def dump
814 "\terror"
815 end
816end
817
818class ConstDecl < Node
819 attr_reader :variable, :value
820
821 def initialize(codeOrigin, variable, value)
822 super(codeOrigin)
823 @variable = variable
824 @value = value
825 end
826
827 def children
828 [@variable, @value]
829 end
830
831 def mapChildren
832 ConstDecl.new(codeOrigin, (yield @variable), (yield @value))
833 end
834
835 def dump
836 "const #{@variable.dump} = #{@value.dump}"
837 end
838end
839
840$labelMapping = {}
841
842class Label < NoChildren
843 attr_reader :name
844
845 def initialize(codeOrigin, name)
846 super(codeOrigin)
847 @name = name
848 end
849
850 def self.forName(codeOrigin, name)
851 if $labelMapping[name]
852 raise "Label name collision: #{name}" unless $labelMapping[name].is_a? Label
853 else
854 $labelMapping[name] = Label.new(codeOrigin, name)
855 end
856 $labelMapping[name]
857 end
858
859 def dump
860 "#{name}:"
861 end
862end
863
864class LocalLabel < NoChildren
865 attr_reader :name
866
867 def initialize(codeOrigin, name)
868 super(codeOrigin)
869 @name = name
870 end
871
872 @@uniqueNameCounter = 0
873
874 def self.forName(codeOrigin, name)
875 if $labelMapping[name]
876 raise "Label name collision: #{name}" unless $labelMapping[name].is_a? LocalLabel
877 else
878 $labelMapping[name] = LocalLabel.new(codeOrigin, name)
879 end
880 $labelMapping[name]
881 end
882
883 def self.unique(comment)
884 newName = "_#{comment}"
885 if $labelMapping[newName]
886 while $labelMapping[newName = "_#{@@uniqueNameCounter}_#{comment}"]
887 @@uniqueNameCounter += 1
888 end
889 end
890 forName(nil, newName)
891 end
892
893 def cleanName
894 if name =~ /^\./
895 "_" + name[1..-1]
896 else
897 name
898 end
899 end
900
901 def dump
902 "#{name}:"
903 end
904end
905
906class LabelReference < Node
907 attr_reader :label
908
909 def initialize(codeOrigin, label)
910 super(codeOrigin)
911 @label = label
912 end
913
914 def children
915 [@label]
916 end
917
918 def mapChildren
919 LabelReference.new(codeOrigin, (yield @label))
920 end
921
922 def name
923 label.name
924 end
925
926 def dump
927 label.name
928 end
929
930 def address?
931 false
932 end
933
934 def label?
935 true
936 end
937
938 def immediate?
939 false
940 end
941end
942
943class LocalLabelReference < NoChildren
944 attr_reader :label
945
946 def initialize(codeOrigin, label)
947 super(codeOrigin)
948 @label = label
949 end
950
951 def children
952 [@label]
953 end
954
955 def mapChildren
956 LocalLabelReference.new(codeOrigin, (yield @label))
957 end
958
959 def name
960 label.name
961 end
962
963 def dump
964 label.name
965 end
966
967 def address?
968 false
969 end
970
971 def label?
972 true
973 end
974
975 def immediate?
976 false
977 end
978end
979
980class Sequence < Node
981 attr_reader :list
982
983 def initialize(codeOrigin, list)
984 super(codeOrigin)
985 @list = list
986 end
987
988 def children
989 list
990 end
991
992 def mapChildren(&proc)
993 Sequence.new(codeOrigin, @list.map(&proc))
994 end
995
996 def dump
997 list.collect{|v| v.dump}.join("\n")
998 end
999end
1000
1001class True < NoChildren
1002 def initialize
1003 super(nil)
1004 end
1005
1006 @@instance = True.new
1007
1008 def self.instance
1009 @@instance
1010 end
1011
1012 def value
1013 true
1014 end
1015
1016 def dump
1017 "true"
1018 end
1019end
1020
1021class False < NoChildren
1022 def initialize
1023 super(nil)
1024 end
1025
1026 @@instance = False.new
1027
1028 def self.instance
1029 @@instance
1030 end
1031
1032 def value
1033 false
1034 end
1035
1036 def dump
1037 "false"
1038 end
1039end
1040
1041class TrueClass
1042 def asNode
1043 True.instance
1044 end
1045end
1046
1047class FalseClass
1048 def asNode
1049 False.instance
1050 end
1051end
1052
1053class Setting < NoChildren
1054 attr_reader :name
1055
1056 def initialize(codeOrigin, name)
1057 super(codeOrigin)
1058 @name = name
1059 end
1060
1061 @@mapping = {}
1062
1063 def self.forName(codeOrigin, name)
1064 unless @@mapping[name]
1065 @@mapping[name] = Setting.new(codeOrigin, name)
1066 end
1067 @@mapping[name]
1068 end
1069
1070 def dump
1071 name
1072 end
1073end
1074
1075class And < Node
1076 attr_reader :left, :right
1077
1078 def initialize(codeOrigin, left, right)
1079 super(codeOrigin)
1080 @left = left
1081 @right = right
1082 end
1083
1084 def children
1085 [@left, @right]
1086 end
1087
1088 def mapChildren
1089 And.new(codeOrigin, (yield @left), (yield @right))
1090 end
1091
1092 def dump
1093 "(#{left.dump} and #{right.dump})"
1094 end
1095end
1096
1097class Or < Node
1098 attr_reader :left, :right
1099
1100 def initialize(codeOrigin, left, right)
1101 super(codeOrigin)
1102 @left = left
1103 @right = right
1104 end
1105
1106 def children
1107 [@left, @right]
1108 end
1109
1110 def mapChildren
1111 Or.new(codeOrigin, (yield @left), (yield @right))
1112 end
1113
1114 def dump
1115 "(#{left.dump} or #{right.dump})"
1116 end
1117end
1118
1119class Not < Node
1120 attr_reader :child
1121
1122 def initialize(codeOrigin, child)
1123 super(codeOrigin)
1124 @child = child
1125 end
1126
1127 def children
1128 [@left, @right]
1129 end
1130
1131 def mapChildren
1132 Not.new(codeOrigin, (yield @child))
1133 end
1134
1135 def dump
1136 "(not #{child.dump})"
1137 end
1138end
1139
1140class Skip < NoChildren
1141 def initialize(codeOrigin)
1142 super(codeOrigin)
1143 end
1144
1145 def dump
1146 "\tskip"
1147 end
1148end
1149
1150class IfThenElse < Node
1151 attr_reader :predicate, :thenCase
1152 attr_accessor :elseCase
1153
1154 def initialize(codeOrigin, predicate, thenCase)
1155 super(codeOrigin)
1156 @predicate = predicate
1157 @thenCase = thenCase
1158 @elseCase = Skip.new(codeOrigin)
1159 end
1160
1161 def children
1162 if @elseCase
1163 [@predicate, @thenCase, @elseCase]
1164 else
1165 [@predicate, @thenCase]
1166 end
1167 end
1168
1169 def mapChildren
1170 IfThenElse.new(codeOrigin, (yield @predicate), (yield @thenCase), (yield @elseCase))
1171 end
1172
1173 def dump
1174 "if #{predicate.dump}\n" + thenCase.dump + "\nelse\n" + elseCase.dump + "\nend"
1175 end
1176end
1177
1178class Macro < Node
1179 attr_reader :name, :variables, :body
1180
1181 def initialize(codeOrigin, name, variables, body)
1182 super(codeOrigin)
1183 @name = name
1184 @variables = variables
1185 @body = body
1186 end
1187
1188 def children
1189 @variables + [@body]
1190 end
1191
1192 def mapChildren
1193 Macro.new(codeOrigin, @name, @variables.map{|v| yield v}, (yield @body))
1194 end
1195
1196 def dump
1197 "macro #{name}(" + variables.collect{|v| v.dump}.join(", ") + ")\n" + body.dump + "\nend"
1198 end
1199end
1200
1201class MacroCall < Node
1202 attr_reader :name, :operands
1203
1204 def initialize(codeOrigin, name, operands)
1205 super(codeOrigin)
1206 @name = name
1207 @operands = operands
1208 raise unless @operands
1209 @operands.each{|v| raise unless v}
1210 end
1211
1212 def children
1213 @operands
1214 end
1215
1216 def mapChildren(&proc)
1217 MacroCall.new(codeOrigin, @name, @operands.map(&proc))
1218 end
1219
1220 def dump
1221 "\t#{name}(" + operands.collect{|v| v.dump}.join(", ") + ")"
1222 end
1223end
1224