]> git.saurik.com Git - apple/javascriptcore.git/blame - offlineasm/asm.rb
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / offlineasm / asm.rb
CommitLineData
6fe7ccc8
A
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
93a37866 28require "config"
6fe7ccc8
A
29require "backends"
30require "digest/sha1"
31require "offsets"
32require "parser"
33require "self_hash"
34require "settings"
35require "transform"
36
37class Assembler
38 def initialize(outp)
39 @outp = outp
40 @state = :cpp
41 @commentState = :none
42 @comment = nil
93a37866
A
43 @internalComment = nil
44 @annotation = nil
45 @codeOrigin = nil
46 @numLocalLabels = 0
47 @numGlobalLabels = 0
48
49 @newlineSpacerState = :none
81345200 50 @lastlabel = ""
6fe7ccc8 51 end
81345200 52
6fe7ccc8 53 def enterAsm
81345200 54 @outp.puts "OFFLINE_ASM_BEGIN" if !$emitWinAsm
6fe7ccc8
A
55 @state = :asm
56 end
57
58 def leaveAsm
81345200 59 putsProcEndIfNeeded if $emitWinAsm
6fe7ccc8 60 putsLastComment
81345200 61 @outp.puts "OFFLINE_ASM_END" if !$emitWinAsm
6fe7ccc8
A
62 @state = :cpp
63 end
64
65 def inAsm
66 enterAsm
67 yield
68 leaveAsm
69 end
70
93a37866 71 # Concatenates all the various components of the comment to dump.
6fe7ccc8 72 def lastComment
93a37866
A
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 != ""
81345200 89 result = $commentPrefix + " " + result
6fe7ccc8 90 end
93a37866
A
91
92 # Reset all the components that we've just sent to be dumped.
6fe7ccc8
A
93 @commentState = :none
94 @comment = nil
93a37866
A
95 @annotation = nil
96 @codeOrigin = nil
97 @internalComment = nil
6fe7ccc8
A
98 result
99 end
100
93a37866
A
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
6fe7ccc8
A
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
81345200
A
142 if !$emitWinAsm
143 @outp.puts(formatDump(" \"\\t" + line.join('') + "\\n\"", lastComment))
144 else
145 @outp.puts(formatDump(" " + line.join(''), lastComment))
146 end
6fe7ccc8
A
147 end
148
149 def print(line)
150 raise unless @state == :asm
151 @outp.print("\"" + line + "\"")
152 end
153
93a37866
A
154 def putsNewlineSpacerIfAppropriate(state)
155 if @newlineSpacerState != state
156 @outp.puts("\n")
157 @newlineSpacerState = state
158 end
159 end
160
81345200
A
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)
6fe7ccc8 176 raise unless @state == :asm
93a37866 177 @numGlobalLabels += 1
81345200 178 putsProcEndIfNeeded if $emitWinAsm and isGlobal
93a37866
A
179 putsNewlineSpacerIfAppropriate(:global)
180 @internalComment = $enableLabelCountComments ? "Global Label #{@numGlobalLabels}" : nil
81345200
A
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
93a37866 194 else
81345200
A
195 if !$emitWinAsm
196 @outp.puts(formatDump("OFFLINE_ASM_GLUE_LABEL(#{labelName})", lastComment))
197 else
198 @outp.puts(formatDump(" _#{labelName}:", lastComment))
199 end
93a37866
A
200 end
201 @newlineSpacerState = :none # After a global label, we can use another spacer.
6fe7ccc8
A
202 end
203
204 def putsLocalLabel(labelName)
205 raise unless @state == :asm
93a37866
A
206 @numLocalLabels += 1
207 @outp.puts("\n")
208 @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
81345200
A
209 if !$emitWinAsm
210 @outp.puts(formatDump(" OFFLINE_ASM_LOCAL_LABEL(#{labelName})", lastComment))
211 else
212 @outp.puts(formatDump(" #{labelName}:", lastComment))
213 end
6fe7ccc8 214 end
81345200
A
215
216 def self.externLabelReference(labelName)
217 if !$emitWinAsm
218 "\" LOCAL_REFERENCE(#{labelName}) \""
219 else
220 "#{labelName}"
221 end
222 end
223
6fe7ccc8 224 def self.labelReference(labelName)
81345200
A
225 if !$emitWinAsm
226 "\" LOCAL_LABEL_STRING(#{labelName}) \""
227 else
228 "_#{labelName}"
229 end
6fe7ccc8
A
230 end
231
232 def self.localLabelReference(labelName)
81345200
A
233 if !$emitWinAsm
234 "\" LOCAL_LABEL_STRING(#{labelName}) \""
235 else
236 "#{labelName}"
237 end
6fe7ccc8
A
238 end
239
93a37866
A
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)
6fe7ccc8
A
253 case @commentState
254 when :none
93a37866 255 @codeOrigin = text
6fe7ccc8
A
256 @commentState = :one
257 when :one
93a37866 258 if $enableCodeOriginComments
81345200
A
259 @outp.puts " " + $commentPrefix + " #{@codeOrigin}"
260 @outp.puts " " + $commentPrefix + " #{text}"
93a37866
A
261 end
262 @codeOrigin = nil
6fe7ccc8
A
263 @commentState = :many
264 when :many
81345200 265 @outp.puts $commentPrefix + " #{text}" if $enableCodeOriginComments
6fe7ccc8
A
266 else
267 raise
268 end
269 end
93a37866
A
270
271 def comment(text)
272 @comment = text
273 end
274 def annotation(text)
275 @annotation = text
276 end
6fe7ccc8
A
277end
278
81345200
A
279IncludeFile.processIncludeOptions()
280
6fe7ccc8
A
281asmFile = ARGV.shift
282offsetsFile = ARGV.shift
283outputFlnm = ARGV.shift
284
285$stderr.puts "offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}."
286
287begin
288 configurationList = offsetsAndConfigurationIndex(offsetsFile)
289rescue MissingMagicValuesException
93a37866 290 $stderr.puts "offlineasm: No magic values found. Skipping assembly file generation."
6fe7ccc8
A
291 exit 0
292end
293
81345200
A
294$emitWinAsm = isMSVC ? outputFlnm.index(".asm") != nil : false
295$commentPrefix = $emitWinAsm ? ";" : "//"
296
6fe7ccc8 297inputHash =
81345200 298 $commentPrefix + " offlineasm input hash: " + parseHash(asmFile) +
6fe7ccc8
A
299 " " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) +
300 " " + selfHash
301
302if 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 }
311end
312
313File.open(outputFlnm, "w") {
314 | outp |
315 $output = outp
316 $output.puts inputHash
81345200 317
6fe7ccc8
A
318 $asm = Assembler.new($output)
319
320 ast = parse(asmFile)
81345200 321
6fe7ccc8
A
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