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