]> git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/asm.rb
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / offlineasm / asm.rb
1 #!/usr/bin/env ruby
2
3 # Copyright (C) 2011 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 # THE POSSIBILITY OF SUCH DAMAGE.
25
26 $: << File.dirname(__FILE__)
27
28 require "config"
29 require "backends"
30 require "digest/sha1"
31 require "offsets"
32 require "parser"
33 require "self_hash"
34 require "settings"
35 require "transform"
36
37 class Assembler
38 def initialize(outp)
39 @outp = outp
40 @state = :cpp
41 @commentState = :none
42 @comment = nil
43 @internalComment = nil
44 @annotation = nil
45 @codeOrigin = nil
46 @numLocalLabels = 0
47 @numGlobalLabels = 0
48
49 @newlineSpacerState = :none
50 end
51
52 def enterAsm
53 @outp.puts "OFFLINE_ASM_BEGIN"
54 @state = :asm
55 end
56
57 def leaveAsm
58 putsLastComment
59 @outp.puts "OFFLINE_ASM_END"
60 @state = :cpp
61 end
62
63 def inAsm
64 enterAsm
65 yield
66 leaveAsm
67 end
68
69 # Concatenates all the various components of the comment to dump.
70 def lastComment
71 separator = " "
72 result = ""
73 result = "#{@comment}" if @comment
74 if @annotation and $enableInstrAnnotations
75 result += separator if result != ""
76 result += "#{@annotation}"
77 end
78 if @internalComment
79 result += separator if result != ""
80 result += "#{@internalComment}"
81 end
82 if @codeOrigin and $enableCodeOriginComments
83 result += separator if result != ""
84 result += "#{@codeOrigin}"
85 end
86 if result != ""
87 result = "// " + result
88 end
89
90 # Reset all the components that we've just sent to be dumped.
91 @commentState = :none
92 @comment = nil
93 @annotation = nil
94 @codeOrigin = nil
95 @internalComment = nil
96 result
97 end
98
99 # Puts a C Statement in the output stream.
100 def putc(*line)
101 raise unless @state == :asm
102 @outp.puts(formatDump(" " + line.join(''), lastComment))
103 end
104
105 def formatDump(dumpStr, comment, commentColumns=$preferredCommentStartColumn)
106 if comment.length > 0
107 "%-#{commentColumns}s %s" % [dumpStr, comment]
108 else
109 dumpStr
110 end
111 end
112
113 # private method for internal use only.
114 def putAnnotation(text)
115 raise unless @state == :asm
116 if $enableInstrAnnotations
117 @outp.puts text
118 @annotation = nil
119 end
120 end
121
122 def putLocalAnnotation()
123 putAnnotation " // #{@annotation}" if @annotation
124 end
125
126 def putGlobalAnnotation()
127 putsNewlineSpacerIfAppropriate(:annotation)
128 putAnnotation "// #{@annotation}" if @annotation
129 end
130
131 def putsLastComment
132 comment = lastComment
133 unless comment.empty?
134 @outp.puts comment
135 end
136 end
137
138 def puts(*line)
139 raise unless @state == :asm
140 @outp.puts(formatDump(" \"\\t" + line.join('') + "\\n\"", lastComment))
141 end
142
143 def print(line)
144 raise unless @state == :asm
145 @outp.print("\"" + line + "\"")
146 end
147
148 def putsNewlineSpacerIfAppropriate(state)
149 if @newlineSpacerState != state
150 @outp.puts("\n")
151 @newlineSpacerState = state
152 end
153 end
154
155 def putsLabel(labelName)
156 raise unless @state == :asm
157 @numGlobalLabels += 1
158 putsNewlineSpacerIfAppropriate(:global)
159 @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil
160 if /\Allint_op_/.match(labelName)
161 @outp.puts(formatDump("OFFLINE_ASM_OPCODE_LABEL(op_#{$~.post_match})", lastComment))
162 else
163 @outp.puts(formatDump("OFFLINE_ASM_GLUE_LABEL(#{labelName})", lastComment))
164 end
165 @newlineSpacerState = :none # After a global label, we can use another spacer.
166 end
167
168 def putsLocalLabel(labelName)
169 raise unless @state == :asm
170 @numLocalLabels += 1
171 @outp.puts("\n")
172 @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
173 @outp.puts(formatDump(" OFFLINE_ASM_LOCAL_LABEL(#{labelName})", lastComment))
174 end
175
176 def self.labelReference(labelName)
177 "\" LOCAL_REFERENCE(#{labelName}) \""
178 end
179
180 def self.localLabelReference(labelName)
181 "\" LOCAL_LABEL_STRING(#{labelName}) \""
182 end
183
184 def self.cLabelReference(labelName)
185 if /\Allint_op_/.match(labelName)
186 "op_#{$~.post_match}" # strip opcodes of their llint_ prefix.
187 else
188 "#{labelName}"
189 end
190 end
191
192 def self.cLocalLabelReference(labelName)
193 "#{labelName}"
194 end
195
196 def codeOrigin(text)
197 case @commentState
198 when :none
199 @codeOrigin = text
200 @commentState = :one
201 when :one
202 if $enableCodeOriginComments
203 @outp.puts " // #{@codeOrigin}"
204 @outp.puts " // #{text}"
205 end
206 @codeOrigin = nil
207 @commentState = :many
208 when :many
209 @outp.puts "// #{text}" if $enableCodeOriginComments
210 else
211 raise
212 end
213 end
214
215 def comment(text)
216 @comment = text
217 end
218 def annotation(text)
219 @annotation = text
220 end
221 end
222
223 asmFile = ARGV.shift
224 offsetsFile = ARGV.shift
225 outputFlnm = ARGV.shift
226
227 $stderr.puts "offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}."
228
229 begin
230 configurationList = offsetsAndConfigurationIndex(offsetsFile)
231 rescue MissingMagicValuesException
232 $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation."
233 exit 0
234 end
235
236 inputHash =
237 "// offlineasm input hash: " + parseHash(asmFile) +
238 " " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) +
239 " " + selfHash
240
241 if FileTest.exist? outputFlnm
242 File.open(outputFlnm, "r") {
243 | inp |
244 firstLine = inp.gets
245 if firstLine and firstLine.chomp == inputHash
246 $stderr.puts "offlineasm: Nothing changed."
247 exit 0
248 end
249 }
250 end
251
252 File.open(outputFlnm, "w") {
253 | outp |
254 $output = outp
255 $output.puts inputHash
256
257 $asm = Assembler.new($output)
258
259 ast = parse(asmFile)
260
261 configurationList.each {
262 | configuration |
263 offsetsList = configuration[0]
264 configIndex = configuration[1]
265 forSettings(computeSettingsCombinations(ast)[configIndex], ast) {
266 | concreteSettings, lowLevelAST, backend |
267 lowLevelAST = lowLevelAST.resolve(*buildOffsetsMap(lowLevelAST, offsetsList))
268 lowLevelAST.validate
269 emitCodeInConfiguration(concreteSettings, lowLevelAST, backend) {
270 $asm.inAsm {
271 lowLevelAST.lower(backend)
272 }
273 }
274 }
275 }
276 }
277
278 $stderr.puts "offlineasm: Assembly file #{outputFlnm} successfully generated."
279