]> git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/settings.rb
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / offlineasm / settings.rb
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 require "config"
25 require "ast"
26 require "backends"
27 require "parser"
28 require "transform"
29
30 #
31 # computeSettingsCombinations(ast) -> settingsCombiations
32 #
33 # Computes an array of settings maps, where a settings map constitutes
34 # a configuration for the assembly code being generated. The map
35 # contains key value pairs where keys are settings names (strings) and
36 # the values are booleans (true for enabled, false for disabled).
37 #
38
39 def computeSettingsCombinations(ast)
40 settingsCombinations = []
41
42 def settingsCombinator(settingsCombinations, mapSoFar, remaining)
43 if remaining.empty?
44 settingsCombinations << mapSoFar
45 return
46 end
47
48 newMap = mapSoFar.dup
49 newMap[remaining[0]] = true
50 settingsCombinator(settingsCombinations, newMap, remaining[1..-1])
51
52 newMap = mapSoFar.dup
53 newMap[remaining[0]] = false
54 settingsCombinator(settingsCombinations, newMap, remaining[1..-1])
55 end
56
57 nonBackendSettings = ast.filter(Setting).uniq.collect{ |v| v.name }
58 nonBackendSettings.delete_if {
59 | setting |
60 isBackend? setting
61 }
62
63 allBackendsFalse = {}
64 BACKENDS.each {
65 | backend |
66 allBackendsFalse[backend] = false
67 }
68
69 # This will create entries for invalid backends. That's fine. It's necessary
70 # because it ensures that generate_offsets_extractor (which knows about valid
71 # backends) has settings indices that are compatible with what asm will see
72 # (asm doesn't know about valid backends).
73 BACKENDS.each {
74 | backend |
75 map = allBackendsFalse.clone
76 map[backend] = true
77 settingsCombinator(settingsCombinations, map, nonBackendSettings)
78 }
79
80 settingsCombinations
81 end
82
83 #
84 # forSettings(concreteSettings, ast) {
85 # | concreteSettings, lowLevelAST, backend | ... }
86 #
87 # Determines if the settings combination is valid, and if so, calls
88 # the block with the information you need to generate code.
89 #
90
91 def forSettings(concreteSettings, ast)
92 # Check which architectures this combinator claims to support.
93 numClaimedBackends = 0
94 selectedBackend = nil
95 BACKENDS.each {
96 | backend |
97 if concreteSettings[backend]
98 raise if selectedBackend
99 selectedBackend = backend
100 end
101 }
102
103 return unless isValidBackend? selectedBackend
104
105 # Resolve the AST down to a low-level form (no macros or conditionals).
106 lowLevelAST = ast.resolveSettings(concreteSettings)
107
108 yield concreteSettings, lowLevelAST, selectedBackend
109 end
110
111 #
112 # forEachValidSettingsCombination(ast) {
113 # | concreteSettings, ast, backend, index | ... }
114 #
115 # forEachValidSettingsCombination(ast, settingsCombinations) {
116 # | concreteSettings, ast, backend, index | ... }
117 #
118 # Executes the given block for each valid settings combination in the
119 # settings map. The ast passed into the block is resolved
120 # (ast.resolve) against the settings.
121 #
122 # The first form will call computeSettingsCombinations(ast) for you.
123 #
124
125 def forEachValidSettingsCombination(ast, *optionalSettingsCombinations)
126 raise if optionalSettingsCombinations.size > 1
127
128 if optionalSettingsCombinations.empty?
129 settingsCombinations = computeSettingsCombinations(ast)
130 else
131 settingsCombinations = optionalSettingsCombiations[0]
132 end
133
134 settingsCombinations.each_with_index {
135 | concreteSettings, index |
136 forSettings(concreteSettings, ast) {
137 | concreteSettings_, lowLevelAST, backend |
138 yield concreteSettings, lowLevelAST, backend, index
139 }
140 }
141 end
142
143 #
144 # cppSettingsTest(concreteSettings)
145 #
146 # Returns the C++ code used to test if we are in a configuration that
147 # corresponds to the given concrete settings.
148 #
149
150 def cppSettingsTest(concreteSettings)
151 "#if " + concreteSettings.to_a.collect{
152 | pair |
153 (if pair[1]
154 ""
155 else
156 "!"
157 end) + "OFFLINE_ASM_" + pair[0]
158 }.join(" && ")
159 end
160
161 #
162 # isASTErroneous(ast)
163 #
164 # Tests to see if the AST claims that there is an error - i.e. if the
165 # user's code, after settings resolution, has Error nodes.
166 #
167
168 def isASTErroneous(ast)
169 not ast.filter(Error).empty?
170 end
171
172 #
173 # assertConfiguration(concreteSettings)
174 #
175 # Emits a check that asserts that we're using the given configuration.
176 #
177
178 def assertConfiguration(concreteSettings)
179 $output.puts cppSettingsTest(concreteSettings)
180 $output.puts "#else"
181 $output.puts "#error \"Configuration mismatch.\""
182 $output.puts "#endif"
183 end
184
185 #
186 # emitCodeInConfiguration(concreteSettings, ast, backend) {
187 # | concreteSettings, ast, backend | ... }
188 #
189 # Emits all relevant guards to see if the configuration holds and
190 # calls the block if the configuration is not erroneous.
191 #
192
193 def emitCodeInConfiguration(concreteSettings, ast, backend)
194 Label.resetReferenced
195
196 if !$emitWinAsm
197 $output.puts cppSettingsTest(concreteSettings)
198 else
199 if backend == "X86_WIN"
200 $output.puts ".MODEL FLAT, C"
201 end
202 $output.puts "INCLUDE #{File.basename($output.path)}.sym"
203 $output.puts "_TEXT SEGMENT"
204 end
205
206 if isASTErroneous(ast)
207 $output.puts "#error \"Invalid configuration.\""
208 elsif not WORKING_BACKENDS.include? backend
209 $output.puts "#error \"This backend is not supported yet.\""
210 else
211 yield concreteSettings, ast, backend
212 end
213
214 if !$emitWinAsm
215 $output.puts "#endif"
216 else
217 $output.puts "_TEXT ENDS"
218 $output.puts "END"
219
220 # Write symbols needed by MASM
221 File.open("#{File.basename($output.path)}.sym", "w") {
222 | outp |
223 Label.forReferencedExtern {
224 | name |
225 outp.puts "EXTERN #{name[1..-1]} : near"
226 }
227 }
228 end
229 end
230
231 #
232 # emitCodeInAllConfigurations(ast) {
233 # | concreteSettings, ast, backend, index | ... }
234 #
235 # Emits guard codes for all valid configurations, and calls the block
236 # for those configurations that are valid and not erroneous.
237 #
238
239 def emitCodeInAllConfigurations(ast)
240 forEachValidSettingsCombination(ast) {
241 | concreteSettings, lowLevelAST, backend, index |
242 $output.puts cppSettingsTest(concreteSettings)
243 yield concreteSettings, lowLevelAST, backend, index
244 $output.puts "#endif"
245 }
246 end
247
248
249