3 # Copyright (C) 2011 Apple Inc. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
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.
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.
26 $
: << File
.dirname(__FILE__
)
43 @internalComment = nil
49 @newlineSpacerState = :none
54 @outp.puts
"OFFLINE_ASM_BEGIN" if !
$emitWinAsm
59 putsProcEndIfNeeded
if $emitWinAsm
61 @outp.puts
"OFFLINE_ASM_END" if !
$emitWinAsm
71 # Concatenates all the various components of the comment to dump.
75 result
= "#{@comment}" if @comment
76 if @annotation and $enableInstrAnnotations
77 result +
= separator
if result !
= ""
78 result +
= "#{@annotation}"
81 result +
= separator
if result !
= ""
82 result +
= "#{@internalComment}"
84 if @codeOrigin and $enableCodeOriginComments
85 result +
= separator
if result !
= ""
86 result +
= "#{@codeOrigin}"
89 result
= $commentPrefix +
" " + result
92 # Reset all the components that we've just sent to be dumped.
97 @internalComment = nil
101 # Puts a C Statement in the output stream.
103 raise unless @state == :asm
104 @outp.puts(formatDump(" " + line
.join(''), lastComment
))
107 def formatDump(dumpStr
, comment
, commentColumns
=$preferredCommentStartColumn)
108 if comment
.length
> 0
109 "%-#{commentColumns}s %s" % [dumpStr
, comment
]
115 # private method for internal use only.
116 def putAnnotation(text
)
117 raise unless @state == :asm
118 if $enableInstrAnnotations
124 def putLocalAnnotation()
125 putAnnotation
" // #{@annotation}" if @annotation
128 def putGlobalAnnotation()
129 putsNewlineSpacerIfAppropriate(:annotation)
130 putAnnotation
"// #{@annotation}" if @annotation
134 comment
= lastComment
135 unless comment
.empty
?
141 raise unless @state == :asm
143 @outp.puts(formatDump(" \"\\t" + line
.join('') +
"\\n\"", lastComment
))
145 @outp.puts(formatDump(" " + line
.join(''), lastComment
))
150 raise unless @state == :asm
151 @outp.print("\"" + line +
"\"")
154 def putsNewlineSpacerIfAppropriate(state
)
155 if @newlineSpacerState !
= state
157 @newlineSpacerState = state
161 def putsProc(label
, comment
)
162 raise unless $emitWinAsm
163 @outp.puts(formatDump("#{label} PROC PUBLIC", comment
))
167 def putsProcEndIfNeeded
168 raise unless $emitWinAsm
170 @outp.puts("#{@lastlabel} ENDP")
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
183 @outp.puts(formatDump("OFFLINE_ASM_GLOBAL_LABEL(#{labelName})", lastComment
))
185 putsProc(labelName
, lastComment
)
187 elsif /\Allint_op_/.match(labelName
)
189 @outp.puts(formatDump("OFFLINE_ASM_OPCODE_LABEL(op_#{$~.post_match})", lastComment
))
191 label
= "llint_" +
"op_#{$~.post_match}"
192 @outp.puts(formatDump(" _#{label}:", lastComment
))
196 @outp.puts(formatDump("OFFLINE_ASM_GLUE_LABEL(#{labelName})", lastComment
))
198 @outp.puts(formatDump(" _#{labelName}:", lastComment
))
201 @newlineSpacerState = :none # After a global label, we can use another spacer.
204 def putsLocalLabel(labelName
)
205 raise unless @state == :asm
208 @internalComment = $enableLabelCountComments ? "Local Label #{@numLocalLabels}" : nil
210 @outp.puts(formatDump(" OFFLINE_ASM_LOCAL_LABEL(#{labelName})", lastComment
))
212 @outp.puts(formatDump(" #{labelName}:", lastComment
))
216 def self.externLabelReference(labelName
)
218 "\" LOCAL_REFERENCE(#{labelName}) \""
224 def self.labelReference(labelName
)
226 "\" LOCAL_LABEL_STRING(#{labelName}) \""
232 def self.localLabelReference(labelName
)
234 "\" LOCAL_LABEL_STRING(#{labelName}) \""
240 def self.cLabelReference(labelName
)
241 if /\Allint_op_/.match(labelName
)
242 "op_#{$~.post_match}" # strip opcodes of their llint_ prefix.
248 def self.cLocalLabelReference(labelName
)
258 if $enableCodeOriginComments
259 @outp.puts
" " +
$commentPrefix +
" #{@codeOrigin}"
260 @outp.puts
" " +
$commentPrefix +
" #{text}"
263 @commentState = :many
265 @outp.puts
$commentPrefix +
" #{text}" if $enableCodeOriginComments
279 IncludeFile
.processIncludeOptions()
282 offsetsFile
= ARGV.shift
283 outputFlnm
= ARGV.shift
285 $stderr.puts
"offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}."
288 configurationList
= offsetsAndConfigurationIndex(offsetsFile
)
289 rescue MissingMagicValuesException
290 $stderr.puts
"offlineasm: No magic values found. Skipping assembly file generation."
294 $emitWinAsm = isMSVC
? outputFlnm
.index(".asm") !
= nil : false
295 $commentPrefix = $emitWinAsm ? ";" : "//"
298 $commentPrefix +
" offlineasm input hash: " +
parseHash(asmFile
) +
299 " " + Digest
::SHA1.hexdigest(configurationList
.map
{|v
| (v
[0] +
[v
[1]]).join(' ')}.join(' ')) +
302 if FileTest
.exist
? outputFlnm
303 File
.open(outputFlnm
, "r") {
306 if firstLine
and firstLine
.chomp
== inputHash
307 $stderr.puts
"offlineasm: Nothing changed."
313 File
.open(outputFlnm
, "w") {
316 $output.puts inputHash
318 $asm = Assembler
.new($output)
322 configurationList
.each
{
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
))
330 emitCodeInConfiguration(concreteSettings
, lowLevelAST
, backend
) {
332 lowLevelAST
.lower(backend
)
339 $stderr.puts
"offlineasm: Assembly file #{outputFlnm} successfully generated."