]> git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/asm.rb
JavaScriptCore-7600.1.4.17.5.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 @lastlabel = ""
51 end
52
53 def enterAsm
54 @outp.puts "OFFLINE_ASM_BEGIN" if !$emitWinAsm
55 @state = :asm
56 end
57
58 def leaveAsm
59 putsProcEndIfNeeded if $emitWinAsm
60 putsLastComment
61 @outp.puts "OFFLINE_ASM_END" if !$emitWinAsm
62 @state = :cpp
63 end
64
65 def inAsm
66 enterAsm
67 yield
68 leaveAsm
69 end
70
71 # Concatenates all the various components of the comment to dump.
72 def lastComment
73 separator = " "
74 result = ""
75 result = "#{@comment}" if @comment
76 if @annotation and $enableInstrAnnotations
77 result += separator if result != ""
78 result += "#{@annotation}"
79 end
80 if @internalComment
81 result += separator if result != ""
82 result += "#{@internalComment}"
83 end
84 if @codeOrigin and $enableCodeOriginComments
85 result += separator if result != ""
86 result += "#{@codeOrigin}"
87 end
88 if result != ""
89 result = $commentPrefix + " " + result
90 end
91
92 # Reset all the components that we've just sent to be dumped.
93 @commentState = :none
94 @comment = nil
95 @annotation = nil
96 @codeOrigin = nil
97 @internalComment = nil
98 result
99 end
100
101 # Puts a C Statement in the output stream.
102 def putc(*line)
103 raise unless @state == :asm
104 @outp.puts(formatDump(" " + line.join(''), lastComment))
105 end
106
107 def formatDump(dumpStr, comment, commentColumns=$preferredCommentStartColumn)
108 if comment.length > 0
109 "%-#{commentColumns}s %s" % [dumpStr, comment]
110 else
111 dumpStr
112 end
113 end
114
115 # private method for internal use only.
116 def putAnnotation(text)
117 raise unless @state == :asm
118 if $enableInstrAnnotations
119 @outp.puts text
120 @annotation = nil
121 end
122 end
123
124 def putLocalAnnotation()
125 putAnnotation " // #{@annotation}" if @annotation
126 end
127
128 def putGlobalAnnotation()
129 putsNewlineSpacerIfAppropriate(:annotation)
130 putAnnotation "// #{@annotation}" if @annotation
131 end
132
133 def putsLastComment
134 comment = lastComment
135 unless comment.empty?
136 @outp.puts comment
137 end
138 end
139
140 def puts(*line)
141 raise unless @state == :asm
142 if !$emitWinAsm
143 @outp.puts(formatDump(" \"\\t" + line.join('') + "\\n\"", lastComment))
144 else
145 @outp.puts(formatDump(" " + line.join(''), lastComment))
146 end
147 end
148
149 def print(line)
150 raise unless @state == :asm
151 @outp.print("\"" + line + "\"")
152 end
153
154 def putsNewlineSpacerIfAppropriate(state)
155 if @newlineSpacerState != state
156 @outp.puts("\n")
157 @newlineSpacerState = state
158 end
159 end
160
161 def putsProc(label, comment)
162 raise unless $emitWinAsm
163 @outp.puts(formatDump("#{label} PROC PUBLIC", comment))
164 @lastlabel = label
165 end
166
167 def putsProcEndIfNeeded
168 raise unless $emitWinAsm
169 if @lastlabel != ""
170 @outp.puts("#{@lastlabel} ENDP")
171 end
172 @lastlabel = ""
173 end
174
175 def putsLabel(labelName, isGlobal)
176 raise unless @state == :asm
177 @numGlobalLabels += 1
178 putsProcEndIfNeeded if $emitWinAsm and isGlobal
179 putsNewlineSpacerIfAppropriate(:global)
180 @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil
181 if isGlobal
182 if !$emitWinAsm
183 @outp.puts(formatDump("OFFLINE_ASM_GLOBAL_LABEL(#{labelName})", lastComment))
184 else
185 putsProc(labelName, lastComment)
186 end
187 elsif /\Allint_op_/.match(labelName)
188 if !$emitWinAsm
189 @outp.puts(formatDump("OFFLINE_ASM_OPCODE_LABEL(op_#{$~.post_match})", lastComment))
190 else
191 label = "llint_" + "op_#{$~.post_match}"
192 @outp.puts(formatDump(" _#{label}:", lastComment))
193 end
194 else
195 if !$emitWinAsm
196 @outp.puts(formatDump("OFFLINE_ASM_GLUE_LABEL(#{labelName})", lastComment))
197 else
198 @outp.puts(formatDump(" _#{labelName}:", lastComment))
199 end
200 end
201 @newlineSpacerState = :none # After a global label, we can use another spacer.
202 end
203
204 def putsLocalLabel(labelName)
205 raise unless @state == :asm
206 @numLocalLabels += 1
207 @outp.puts("\n")
208 @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
209 if !$emitWinAsm
210 @outp.puts(formatDump(" OFFLINE_ASM_LOCAL_LABEL(#{labelName})", lastComment))
211 else
212 @outp.puts(formatDump(" #{labelName}:", lastComment))
213 end
214 end
215
216 def self.externLabelReference(labelName)
217 if !$emitWinAsm
218 "\" LOCAL_REFERENCE(#{labelName}) \""
219 else
220 "#{labelName}"
221 end
222 end
223
224 def self.labelReference(labelName)
225 if !$emitWinAsm
226 "\" LOCAL_LABEL_STRING(#{labelName}) \""
227 else
228 "_#{labelName}"
229 end
230 end
231
232 def self.localLabelReference(labelName)
233 if !$emitWinAsm
234 "\" LOCAL_LABEL_STRING(#{labelName}) \""
235 else
236 "#{labelName}"
237 end
238 end
239
240 def self.cLabelReference(labelName)
241 if /\Allint_op_/.match(labelName)
242 "op_#{$~.post_match}" # strip opcodes of their llint_ prefix.
243 else
244 "#{labelName}"
245 end
246 end
247
248 def self.cLocalLabelReference(labelName)
249 "#{labelName}"
250 end
251
252 def codeOrigin(text)
253 case @commentState
254 when :none
255 @codeOrigin = text
256 @commentState = :one
257 when :one
258 if $enableCodeOriginComments
259 @outp.puts " " + $commentPrefix + " #{@codeOrigin}"
260 @outp.puts " " + $commentPrefix + " #{text}"
261 end
262 @codeOrigin = nil
263 @commentState = :many
264 when :many
265 @outp.puts $commentPrefix + " #{text}" if $enableCodeOriginComments
266 else
267 raise
268 end
269 end
270
271 def comment(text)
272 @comment = text
273 end
274 def annotation(text)
275 @annotation = text
276 end
277 end
278
279 IncludeFile.processIncludeOptions()
280
281 asmFile = ARGV.shift
282 offsetsFile = ARGV.shift
283 outputFlnm = ARGV.shift
284
285 $stderr.puts "offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}."
286
287 begin
288 configurationList = offsetsAndConfigurationIndex(offsetsFile)
289 rescue MissingMagicValuesException
290 $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation."
291 exit 0
292 end
293
294 $emitWinAsm = isMSVC ? outputFlnm.index(".asm") != nil : false
295 $commentPrefix = $emitWinAsm ? ";" : "//"
296
297 inputHash =
298 $commentPrefix + " offlineasm input hash: " + parseHash(asmFile) +
299 " " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) +
300 " " + selfHash
301
302 if FileTest.exist? outputFlnm
303 File.open(outputFlnm, "r") {
304 | inp |
305 firstLine = inp.gets
306 if firstLine and firstLine.chomp == inputHash
307 $stderr.puts "offlineasm: Nothing changed."
308 exit 0
309 end
310 }
311 end
312
313 File.open(outputFlnm, "w") {
314 | outp |
315 $output = outp
316 $output.puts inputHash
317
318 $asm = Assembler.new($output)
319
320 ast = parse(asmFile)
321
322 configurationList.each {
323 | configuration |
324 offsetsList = configuration[0]
325 configIndex = configuration[1]
326 forSettings(computeSettingsCombinations(ast)[configIndex], ast) {
327 | concreteSettings, lowLevelAST, backend |
328 lowLevelAST = lowLevelAST.resolve(*buildOffsetsMap(lowLevelAST, offsetsList))
329 lowLevelAST.validate
330 emitCodeInConfiguration(concreteSettings, lowLevelAST, backend) {
331 $asm.inAsm {
332 lowLevelAST.lower(backend)
333 }
334 }
335 }
336 }
337 }
338
339 $stderr.puts "offlineasm: Assembly file #{outputFlnm} successfully generated."
340