OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * The [ConstantHandler] keeps track of compile-time constants, | 6 * The [ConstantHandler] keeps track of compile-time constants, |
7 * initializations of global and static fields, and default values of | 7 * initializations of global and static fields, and default values of |
8 * optional parameters. | 8 * optional parameters. |
9 */ | 9 */ |
10 class ConstantHandler extends CompilerTask { | 10 class ConstantHandler extends CompilerTask { |
11 final ConstantSystem constantSystem; | 11 final ConstantSystem constantSystem; |
12 | 12 |
13 /** | 13 /** |
14 * Contains the initial value of fields. Must contain all static and global | 14 * Contains the initial value of fields. Must contain all static and global |
15 * initializations of const fields. May contain eagerly compiled values for | 15 * initializations of const fields. May contain eagerly compiled values for |
16 * statics and instance fields. | 16 * statics and instance fields. |
17 */ | 17 */ |
18 final Map<VariableElement, Constant> initialVariableValues; | 18 final Map<VariableElement, Constant> initialVariableValues; |
19 | 19 |
20 /** Set of all registered compiled constants. */ | 20 /** Map from compile-time constants to their JS name. */ |
21 final Set<Constant> compiledConstants; | 21 final Map<Constant, String> compiledConstants; |
22 | 22 |
23 /** The set of variable elements that are in the process of being computed. */ | 23 /** The set of variable elements that are in the process of being computed. */ |
24 final Set<VariableElement> pendingVariables; | 24 final Set<VariableElement> pendingVariables; |
25 | 25 |
26 /** Caches the statics where the initial value cannot be eagerly compiled. */ | 26 /** Caches the statics where the initial value cannot be eagerly compiled. */ |
27 final Set<VariableElement> lazyStatics; | 27 final Set<VariableElement> lazyStatics; |
28 | 28 |
29 | 29 |
30 ConstantHandler(Compiler compiler, this.constantSystem) | 30 ConstantHandler(Compiler compiler, this.constantSystem) |
31 : initialVariableValues = new Map<VariableElement, Dynamic>(), | 31 : initialVariableValues = new Map<VariableElement, Dynamic>(), |
32 compiledConstants = new Set<Constant>(), | 32 compiledConstants = new Map<Constant, String>(), |
33 pendingVariables = new Set<VariableElement>(), | 33 pendingVariables = new Set<VariableElement>(), |
34 lazyStatics = new Set<VariableElement>(), | 34 lazyStatics = new Set<VariableElement>(), |
35 super(compiler); | 35 super(compiler); |
36 String get name => 'ConstantHandler'; | 36 String get name => 'ConstantHandler'; |
37 | 37 |
38 void registerCompileTimeConstant(Constant constant) { | 38 void registerCompileTimeConstant(Constant constant) { |
39 compiledConstants.add(constant); | 39 Function ifAbsentThunk = (() { |
| 40 return constant.isFunction() |
| 41 ? null : compiler.namer.getFreshGlobalName("CTC"); |
| 42 }); |
| 43 compiledConstants.putIfAbsent(constant, ifAbsentThunk); |
40 } | 44 } |
41 | 45 |
42 /** | 46 /** |
43 * Compiles the initial value of the given field and stores it in an internal | 47 * Compiles the initial value of the given field and stores it in an internal |
44 * map. Returns the initial value (a constant) if it can be computed | 48 * map. Returns the initial value (a constant) if it can be computed |
45 * statically. Returns [:null:] if the variable must be initialized lazily. | 49 * statically. Returns [:null:] if the variable must be initialized lazily. |
46 * | 50 * |
47 * [WorkItem] must contain a [VariableElement] refering to a global or | 51 * [WorkItem] must contain a [VariableElement] refering to a global or |
48 * static field. | 52 * static field. |
49 */ | 53 */ |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 | 205 |
202 void addConstant(Constant constant) { | 206 void addConstant(Constant constant) { |
203 if (!seenConstants.contains(constant)) { | 207 if (!seenConstants.contains(constant)) { |
204 constant.getDependencies().forEach(addConstant); | 208 constant.getDependencies().forEach(addConstant); |
205 assert(!seenConstants.contains(constant)); | 209 assert(!seenConstants.contains(constant)); |
206 result.add(constant); | 210 result.add(constant); |
207 seenConstants.add(constant); | 211 seenConstants.add(constant); |
208 } | 212 } |
209 } | 213 } |
210 | 214 |
211 compiledConstants.forEach(addConstant); | 215 compiledConstants.forEach((Constant key, ignored) => addConstant(key)); |
212 return result; | 216 return result; |
213 } | 217 } |
214 | 218 |
215 Constant getInitialValueFor(VariableElement element) { | 219 String getNameForConstant(Constant constant) { |
216 Constant initialValue = initialVariableValues[element]; | 220 return compiledConstants[constant]; |
217 if (initialValue === null) { | 221 } |
| 222 |
| 223 /** This function writes the constant in non-canonicalized form. */ |
| 224 CodeBuffer writeJsCode(CodeBuffer buffer, Constant value) { |
| 225 value._writeJsCode(buffer, this); |
| 226 return buffer; |
| 227 } |
| 228 |
| 229 CodeBuffer writeConstant(CodeBuffer buffer, Constant value) { |
| 230 value._writeCanonicalizedJsCode(buffer, this); |
| 231 return buffer; |
| 232 } |
| 233 |
| 234 CodeBuffer writeJsCodeForVariable(CodeBuffer buffer, |
| 235 VariableElement element) { |
| 236 if (!initialVariableValues.containsKey(element)) { |
218 compiler.internalError("No initial value for given element", | 237 compiler.internalError("No initial value for given element", |
219 element: element); | 238 element: element); |
220 } | 239 } |
221 return initialValue; | 240 Constant constant = initialVariableValues[element]; |
| 241 writeConstant(buffer, constant); |
| 242 return buffer; |
| 243 } |
| 244 |
| 245 /** |
| 246 * Write the contents of the quoted string to a [CodeBuffer] in |
| 247 * a form that is valid as JavaScript string literal content. |
| 248 * The string is assumed quoted by single quote characters. |
| 249 */ |
| 250 static void writeEscapedString(DartString string, |
| 251 CodeBuffer buffer, |
| 252 void cancel(String reason)) { |
| 253 Iterator<int> iterator = string.iterator(); |
| 254 while (iterator.hasNext()) { |
| 255 int code = iterator.next(); |
| 256 if (code === $SQ) { |
| 257 buffer.add(@"\'"); |
| 258 } else if (code === $LF) { |
| 259 buffer.add(@'\n'); |
| 260 } else if (code === $CR) { |
| 261 buffer.add(@'\r'); |
| 262 } else if (code === $LS) { |
| 263 // This Unicode line terminator and $PS are invalid in JS string |
| 264 // literals. |
| 265 buffer.add(@'\u2028'); |
| 266 } else if (code === $PS) { |
| 267 buffer.add(@'\u2029'); |
| 268 } else if (code === $BACKSLASH) { |
| 269 buffer.add(@'\\'); |
| 270 } else { |
| 271 if (code > 0xffff) { |
| 272 cancel('Unhandled non-BMP character: U+${code.toRadixString(16)}'); |
| 273 } |
| 274 // TODO(lrn): Consider whether all codes above 0x7f really need to |
| 275 // be escaped. We build a Dart string here, so it should be a literal |
| 276 // stage that converts it to, e.g., UTF-8 for a JS interpreter. |
| 277 if (code < 0x20) { |
| 278 buffer.add(@'\x'); |
| 279 if (code < 0x10) buffer.add('0'); |
| 280 buffer.add(code.toRadixString(16)); |
| 281 } else if (code >= 0x80) { |
| 282 if (code < 0x100) { |
| 283 buffer.add(@'\x'); |
| 284 } else { |
| 285 buffer.add(@'\u'); |
| 286 if (code < 0x1000) { |
| 287 buffer.add('0'); |
| 288 } |
| 289 } |
| 290 buffer.add(code.toRadixString(16)); |
| 291 } else { |
| 292 buffer.addCharCode(code); |
| 293 } |
| 294 } |
| 295 } |
| 296 } |
| 297 |
| 298 String getJsConstructor(ClassElement element) { |
| 299 return compiler.namer.isolatePropertiesAccess(element); |
222 } | 300 } |
223 } | 301 } |
224 | 302 |
225 class CompileTimeConstantEvaluator extends AbstractVisitor { | 303 class CompileTimeConstantEvaluator extends AbstractVisitor { |
226 bool isEvaluatingConstant; | 304 bool isEvaluatingConstant; |
227 final ConstantSystem constantSystem; | 305 final ConstantSystem constantSystem; |
228 final TreeElements elements; | 306 final TreeElements elements; |
229 final Compiler compiler; | 307 final Compiler compiler; |
230 | 308 |
231 CompileTimeConstantEvaluator(this.constantSystem, | 309 CompileTimeConstantEvaluator(this.constantSystem, |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; | 374 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL; |
297 compiler.reportError(entry.key, new ResolutionError(kind, const [])); | 375 compiler.reportError(entry.key, new ResolutionError(kind, const [])); |
298 } | 376 } |
299 StringConstant keyConstant = key; | 377 StringConstant keyConstant = key; |
300 if (!map.containsKey(key)) keys.add(key); | 378 if (!map.containsKey(key)) keys.add(key); |
301 map[key] = evaluateConstant(entry.value); | 379 map[key] = evaluateConstant(entry.value); |
302 } | 380 } |
303 List<Constant> values = <Constant>[]; | 381 List<Constant> values = <Constant>[]; |
304 Constant protoValue = null; | 382 Constant protoValue = null; |
305 for (StringConstant key in keys) { | 383 for (StringConstant key in keys) { |
306 if (key.value == MapConstant.PROTO_PROPERTY) { | 384 if (key.value == const LiteralDartString(MapConstant.PROTO_PROPERTY)) { |
307 protoValue = map[key]; | 385 protoValue = map[key]; |
308 } else { | 386 } else { |
309 values.add(map[key]); | 387 values.add(map[key]); |
310 } | 388 } |
311 } | 389 } |
312 bool hasProtoKey = (protoValue !== null); | 390 bool hasProtoKey = (protoValue !== null); |
313 // TODO(floitsch): this should be a List<String> type. | 391 // TODO(floitsch): this should be a List<String> type. |
314 DartType keysType = null; | 392 DartType keysType = null; |
315 ListConstant keysList = new ListConstant(keysType, keys); | 393 ListConstant keysList = new ListConstant(keysType, keys); |
316 compiler.constantHandler.registerCompileTimeConstant(keysList); | 394 compiler.constantHandler.registerCompileTimeConstant(keysList); |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 Constant fieldValue = fieldValues[field]; | 815 Constant fieldValue = fieldValues[field]; |
738 if (fieldValue === null) { | 816 if (fieldValue === null) { |
739 // Use the default value. | 817 // Use the default value. |
740 fieldValue = compiler.compileConstant(field); | 818 fieldValue = compiler.compileConstant(field); |
741 } | 819 } |
742 jsNewArguments.add(fieldValue); | 820 jsNewArguments.add(fieldValue); |
743 }); | 821 }); |
744 return jsNewArguments; | 822 return jsNewArguments; |
745 } | 823 } |
746 } | 824 } |
OLD | NEW |