| 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 |