Index: pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
index 7d4b2a5f2cd35c09472530a194466914243db05a..a61c38d963c24e7d86c09e87ce503b199713ef84 100644 |
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
+++ b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart |
@@ -160,13 +160,21 @@ class ModelEmitter { |
return totalSize; |
} |
- js.LiteralString unparse(Compiler compiler, js.Node value) { |
+ /// Unparses the given [value]. |
+ /// |
+ /// Pretty-prints the given [value] and, if [protectForEval] is |
+ /// true, wraps the resulting string in parenthesis. The result is escaped |
+ /// and returned. |
+ js.LiteralString unparse(Compiler compiler, js.Node value, |
+ {bool protectForEval: true}) { |
String text = js.prettyPrint(value, compiler).getText(); |
- if (value is js.Fun) text = '($text)'; |
- if (value is js.LiteralExpression && |
- (value.template.startsWith("function ") || |
- value.template.startsWith("{"))) { |
- text = '($text)'; |
+ if (protectForEval) { |
+ if (value is js.Fun) text = '($text)'; |
+ if (value is js.LiteralExpression && |
+ (value.template.startsWith("function ") || |
+ value.template.startsWith("{"))) { |
+ text = '($text)'; |
+ } |
} |
return js.js.escapedString(text); |
} |
@@ -201,6 +209,7 @@ class ModelEmitter { |
backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
'outputContainsConstantList': program.outputContainsConstantList, |
'embeddedGlobals': emitEmbeddedGlobals(program), |
+ 'readMetadataTypeFunction': readMetadataTypeFunction, |
'staticNonFinals': |
emitStaticNonFinalFields(fragment.staticNonFinalFields), |
'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
@@ -421,6 +430,28 @@ class ModelEmitter { |
return new js.Property(js.string(GET_TYPE_FROM_NAME), function); |
} |
+ static final String readMetadataTypeName = "readMetadataType"; |
+ |
+ js.Statement get readMetadataTypeFunction { |
+ // Types are non-evaluated and must be compiled at first use. |
+ // Compiled strings are guaranteed not to be strings, and it's thus safe |
+ // to use a type-test to determine if a type has already been compiled. |
+ return js.js.statement('''function $readMetadataTypeName(index) { |
+ var type = #typesAccess[index]; |
+ if (typeof type == 'string') { |
+ type = expressionCompile(type); |
+ #typesAccess[index] = type; |
+ } |
+ return type; |
+ }''', {"typesAccess": generateEmbeddedGlobalAccess(TYPES)}); |
+ } |
+ |
+ js.Template get templateForReadType { |
+ // TODO(floitsch): make sure that no local variable shadows the access to |
+ // the readMetadataType function. |
+ return js.js.expressionTemplateFor('$readMetadataTypeName(#)'); |
+ } |
+ |
List<js.Property> emitMetadata(Program program) { |
List<js.Property> metadataGlobals = <js.Property>[]; |
metadataGlobals.add(new js.Property( |
@@ -428,9 +459,11 @@ class ModelEmitter { |
List<js.Expression> types = |
program.metadataTypes[program.fragments.first.outputUnit]; |
if (types == null) types = <js.Expression>[]; |
- metadataGlobals.add(new js.Property( |
- js.string(TYPES), new js.ArrayInitializer(types))); |
- |
+ List<js.LiteralString> unparsedTypes = types |
+ .map((type) => unparse(compiler, type, protectForEval: false)) |
+ .toList(); |
+ js.ArrayInitializer typesArray = new js.ArrayInitializer(unparsedTypes); |
+ metadataGlobals.add(new js.Property(js.string(TYPES), typesArray)); |
return metadataGlobals; |
} |
@@ -458,7 +491,7 @@ class ModelEmitter { |
js.LiteralString immediateString = unparse(compiler, immediateCode); |
- js.Expression deferredTypes = types == null |
+ js.Expression deferredTypes = (types == null) |
? js.string("[]") |
: unparse(compiler, new js.ArrayInitializer(types)); |
@@ -1156,6 +1189,13 @@ function parseFunctionDescriptor(proto, name, descriptor, typesOffset) { |
// Initialize globals. |
#embeddedGlobals; |
+ function expressionCompile(__s__) { |
+ 'use strict'; |
+ return eval('(' + __s__ + ')'); |
+ } |
+ |
+ #readMetadataTypeFunction; |
+ |
// TODO(floitsch): this order means that native classes may not be |
// referenced from constants. I'm mostly afraid of things like using them as |
// generic arguments (which should be fine, but maybe there are other |