OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 part of dart2js.js_emitter; | |
6 | |
7 class MetadataEmitter extends CodeEmitterHelper { | |
8 /// A list of JS expressions that represent metadata, parameter names and | |
9 /// type, and return types. | |
10 final List<String> globalMetadata = []; | |
11 | |
12 /// A map used to canonicalize the entries of globalMetadata. | |
13 final Map<String, int> globalMetadataMap = <String, int>{}; | |
14 | |
15 bool mustEmitMetadataFor(Element element) { | |
16 return backend.mustRetainMetadata && | |
17 backend.referencedFromMirrorSystem(element); | |
18 } | |
19 | |
20 /// The metadata function returns the metadata associated with | |
21 /// [element] in generated code. The metadata needs to be wrapped | |
22 /// in a function as it refers to constants that may not have been | |
23 /// constructed yet. For example, a class is allowed to be | |
24 /// annotated with itself. The metadata function is used by | |
25 /// mirrors_patch to implement DeclarationMirror.metadata. | |
26 jsAst.Fun buildMetadataFunction(Element element) { | |
27 if (!mustEmitMetadataFor(element)) return null; | |
28 return compiler.withCurrentElement(element, () { | |
29 var metadata = []; | |
30 Link link = element.metadata; | |
31 // TODO(ahe): Why is metadata sometimes null? | |
32 if (link != null) { | |
33 for (; !link.isEmpty; link = link.tail) { | |
34 MetadataAnnotation annotation = link.head; | |
35 ConstantExpression constant = | |
36 backend.constants.getConstantForMetadata(annotation); | |
37 if (constant == null) { | |
38 compiler.internalError(annotation, 'Annotation value is null.'); | |
39 } else { | |
40 metadata.add(emitter.constantReference(constant.value)); | |
41 } | |
42 } | |
43 } | |
44 if (metadata.isEmpty) return null; | |
45 return js('function() { return # }', | |
46 new jsAst.ArrayInitializer.from(metadata)); | |
47 }); | |
48 } | |
49 | |
50 List<int> reifyDefaultArguments(FunctionElement function) { | |
51 FunctionSignature signature = function.functionSignature; | |
52 if (signature.optionalParameterCount == 0) return const []; | |
53 List<int> defaultValues = <int>[]; | |
54 for (ParameterElement element in signature.optionalParameters) { | |
55 ConstantExpression constant = | |
56 backend.constants.getConstantForVariable(element); | |
57 String stringRepresentation = (constant == null) | |
58 ? "null" | |
59 : jsAst.prettyPrint( | |
60 emitter.constantReference(constant.value), compiler).getText(); | |
61 defaultValues.add(addGlobalMetadata(stringRepresentation)); | |
62 } | |
63 return defaultValues; | |
64 } | |
65 | |
66 int reifyMetadata(MetadataAnnotation annotation) { | |
67 ConstantExpression constant = | |
68 backend.constants.getConstantForMetadata(annotation); | |
69 if (constant == null) { | |
70 compiler.internalError(annotation, 'Annotation value is null.'); | |
71 return -1; | |
72 } | |
73 return addGlobalMetadata( | |
74 jsAst.prettyPrint( | |
75 emitter.constantReference(constant.value), compiler).getText()); | |
76 } | |
77 | |
78 int reifyType(DartType type) { | |
79 jsAst.Expression representation = | |
80 backend.rti.getTypeRepresentation( | |
81 type, | |
82 (variable) { | |
83 return js.number( | |
84 emitter.typeVariableHandler.reifyTypeVariable( | |
85 variable.element)); | |
86 }, | |
87 (TypedefType typedef) { | |
88 return backend.isAccessibleByReflection(typedef.element); | |
89 }); | |
90 | |
91 return addGlobalMetadata( | |
92 jsAst.prettyPrint(representation, compiler).getText()); | |
93 } | |
94 | |
95 int reifyName(String name) { | |
96 return addGlobalMetadata('"$name"'); | |
97 } | |
98 | |
99 int addGlobalMetadata(String string) { | |
100 return globalMetadataMap.putIfAbsent(string, () { | |
101 globalMetadata.add(string); | |
102 return globalMetadata.length - 1; | |
103 }); | |
104 } | |
105 | |
106 void emitMetadata(CodeBuffer buffer) { | |
107 String metadataAccess = emitter.generateEmbeddedGlobalAccessString( | |
108 embeddedNames.METADATA); | |
109 buffer.write('$metadataAccess$_=$_['); | |
110 for (String metadata in globalMetadata) { | |
111 if (metadata is String) { | |
112 if (metadata != 'null') { | |
113 buffer.write(metadata); | |
114 } | |
115 } else { | |
116 throw 'Unexpected value in metadata: ${Error.safeToString(metadata)}'; | |
117 } | |
118 buffer.write(',$n'); | |
119 } | |
120 buffer.write('];$n'); | |
121 } | |
122 | |
123 List<int> computeMetadata(FunctionElement element) { | |
124 return compiler.withCurrentElement(element, () { | |
125 if (!mustEmitMetadataFor(element)) return const <int>[]; | |
126 List<int> metadata = <int>[]; | |
127 Link link = element.metadata; | |
128 // TODO(ahe): Why is metadata sometimes null? | |
129 if (link != null) { | |
130 for (; !link.isEmpty; link = link.tail) { | |
131 metadata.add(reifyMetadata(link.head)); | |
132 } | |
133 } | |
134 return metadata; | |
135 }); | |
136 } | |
137 } | |
OLD | NEW |