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 InterceptorEmitter extends CodeEmitterHelper { | |
8 final Set<String> interceptorInvocationNames = new Set<String>(); | |
9 | |
10 void recordMangledNameOfMemberMethod(FunctionElement member, String name) { | |
11 if (backend.isInterceptedMethod(member)) { | |
12 interceptorInvocationNames.add(name); | |
13 } | |
14 } | |
15 | |
16 void emitGetInterceptorMethod(CodeBuffer buffer, | |
17 String key, | |
18 Set<ClassElement> classes) { | |
19 InterceptorStubGenerator stubGenerator = | |
20 new InterceptorStubGenerator(compiler, namer, backend); | |
21 jsAst.Expression function = | |
22 stubGenerator.generateGetInterceptorMethod(classes); | |
23 | |
24 buffer.write(jsAst.prettyPrint( | |
25 js('${namer.globalObjectFor(backend.interceptorsLibrary)}.# = #', | |
26 [key, function]), | |
27 compiler)); | |
28 buffer.write(N); | |
29 } | |
30 | |
31 /** | |
32 * Emit all versions of the [:getInterceptor:] method. | |
33 */ | |
34 void emitGetInterceptorMethods(CodeBuffer buffer) { | |
35 emitter.addComment('getInterceptor methods', buffer); | |
36 Map<String, Set<ClassElement>> specializedGetInterceptors = | |
37 backend.specializedGetInterceptors; | |
38 for (String name in specializedGetInterceptors.keys.toList()..sort()) { | |
39 Set<ClassElement> classes = specializedGetInterceptors[name]; | |
40 emitGetInterceptorMethod(buffer, name, classes); | |
41 } | |
42 } | |
43 | |
44 void emitOneShotInterceptors(CodeBuffer buffer) { | |
45 List<String> names = backend.oneShotInterceptors.keys.toList(); | |
46 names.sort(); | |
47 | |
48 InterceptorStubGenerator stubGenerator = | |
49 new InterceptorStubGenerator(compiler, namer, backend); | |
50 String globalObject = namer.globalObjectFor(backend.interceptorsLibrary); | |
51 for (String name in names) { | |
52 jsAst.Expression function = | |
53 stubGenerator.generateOneShotInterceptor(name); | |
54 jsAst.Expression assignment = | |
55 js('${globalObject}.# = #', [name, function]); | |
56 | |
57 buffer.write(jsAst.prettyPrint(assignment, compiler)); | |
58 buffer.write(N); | |
59 } | |
60 } | |
61 | |
62 /** | |
63 * If [JSInvocationMirror._invokeOn] has been compiled, emit all the | |
64 * possible selector names that are intercepted into the | |
65 * [interceptedNames] top-level variable. The implementation of | |
66 * [_invokeOn] will use it to determine whether it should call the | |
67 * method with an extra parameter. | |
68 */ | |
69 void emitInterceptedNames(CodeBuffer buffer) { | |
70 // TODO(ahe): We should not generate the list of intercepted names at | |
71 // compile time, it can be generated automatically at runtime given | |
72 // subclasses of Interceptor (which can easily be identified). | |
73 if (!compiler.enabledInvokeOn) return; | |
74 | |
75 // TODO(ahe): We should roll this into | |
76 // [emitStaticNonFinalFieldInitializations]. | |
77 String name = backend.namer.getNameOfGlobalField(backend.interceptedNames); | |
78 | |
79 int index = 0; | |
80 var invocationNames = interceptorInvocationNames.toList()..sort(); | |
81 List<jsAst.ArrayElement> elements = invocationNames.map( | |
82 (String invocationName) { | |
83 jsAst.Literal str = js.string(invocationName); | |
84 return new jsAst.ArrayElement(index++, str); | |
85 }).toList(); | |
86 jsAst.ArrayInitializer array = | |
87 new jsAst.ArrayInitializer(invocationNames.length, elements); | |
88 | |
89 jsAst.Expression assignment = | |
90 js('${emitter.isolateProperties}.# = #', [name, array]); | |
91 | |
92 buffer.write(jsAst.prettyPrint(assignment, compiler)); | |
93 buffer.write(N); | |
94 } | |
95 | |
96 /** | |
97 * Emit initializer for [mapTypeToInterceptor] data structure used by | |
98 * [findInterceptorForType]. See declaration of [mapTypeToInterceptor] in | |
99 * `interceptors.dart`. | |
100 */ | |
101 void emitMapTypeToInterceptor(CodeBuffer buffer) { | |
102 // TODO(sra): Perhaps inject a constant instead? | |
103 CustomElementsAnalysis analysis = backend.customElementsAnalysis; | |
104 if (!analysis.needsTable) return; | |
105 | |
106 List<jsAst.Expression> elements = <jsAst.Expression>[]; | |
107 JavaScriptConstantCompiler handler = backend.constants; | |
108 List<ConstantValue> constants = | |
109 handler.getConstantsForEmission(emitter.compareConstants); | |
110 for (ConstantValue constant in constants) { | |
111 if (constant is TypeConstantValue) { | |
112 TypeConstantValue typeConstant = constant; | |
113 Element element = typeConstant.representedType.element; | |
114 if (element is ClassElement) { | |
115 ClassElement classElement = element; | |
116 if (!analysis.needsClass(classElement)) continue; | |
117 | |
118 elements.add(emitter.constantReference(constant)); | |
119 elements.add(namer.elementAccess(classElement)); | |
120 | |
121 // Create JavaScript Object map for by-name lookup of generative | |
122 // constructors. For example, the class A has three generative | |
123 // constructors | |
124 // | |
125 // class A { | |
126 // A() {} | |
127 // A.foo() {} | |
128 // A.bar() {} | |
129 // } | |
130 // | |
131 // Which are described by the map | |
132 // | |
133 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} | |
134 // | |
135 // We expect most of the time the map will be a singleton. | |
136 var properties = []; | |
137 for (Element member in analysis.constructors(classElement)) { | |
138 properties.add( | |
139 new jsAst.Property( | |
140 js.string(member.name), | |
141 backend.namer.elementAccess(member))); | |
142 } | |
143 | |
144 var map = new jsAst.ObjectInitializer(properties); | |
145 elements.add(map); | |
146 } | |
147 } | |
148 } | |
149 | |
150 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements); | |
151 String name = | |
152 backend.namer.getNameOfGlobalField(backend.mapTypeToInterceptor); | |
153 jsAst.Expression assignment = | |
154 js('${emitter.isolateProperties}.# = #', [name, array]); | |
155 | |
156 buffer.write(jsAst.prettyPrint(assignment, compiler)); | |
157 buffer.write(N); | |
158 } | |
159 } | |
OLD | NEW |