Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: pkg/compiler/lib/src/js_emitter/class_stub_generator.dart

Issue 1198293002: dart2js: Use an abstract Name class for names in the generated JavaScript ast. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: fix tests Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart2js.js_emitter; 5 part of dart2js.js_emitter;
6 6
7 class ClassStubGenerator { 7 class ClassStubGenerator {
8 final Namer namer; 8 final Namer namer;
9 final Compiler compiler; 9 final Compiler compiler;
10 final JavaScriptBackend backend; 10 final JavaScriptBackend backend;
11 11
12 ClassStubGenerator(this.compiler, this.namer, this.backend); 12 ClassStubGenerator(this.compiler, this.namer, this.backend);
13 13
14 jsAst.Expression generateClassConstructor(ClassElement classElement, 14 jsAst.Expression generateClassConstructor(ClassElement classElement,
15 Iterable<String> fields) { 15 Iterable<String> fields) {
16 // TODO(sra): Implement placeholders in VariableDeclaration position: 16 // TODO(sra): Implement placeholders in VariableDeclaration position:
17 // 17 //
18 // String constructorName = namer.getNameOfClass(classElement); 18 // String constructorName = namer.getNameOfClass(classElement);
19 // return js.statement('function #(#) { #; }', 19 // return js.statement('function #(#) { #; }',
20 // [ constructorName, fields, 20 // [ constructorName, fields,
21 // fields.map( 21 // fields.map(
22 // (name) => js('this.# = #', [name, name]))])); 22 // (name) => js('this.# = #', [name, name]))]));
23 return js('function(#) { #; this.#();}', 23 return js('function(#) { #; this.#();}',
24 [fields, 24 [fields,
25 fields.map((name) => js('this.# = #', [name, name])), 25 fields.map((name) => js('this.# = #', [name, name])),
26 namer.deferredAction]); 26 namer.deferredAction]);
27 } 27 }
28 28
29 jsAst.Expression generateGetter(Element member, String fieldName) { 29 jsAst.Expression generateGetter(Element member, jsAst.Name fieldName) {
30 ClassElement cls = member.enclosingClass; 30 ClassElement cls = member.enclosingClass;
31 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; 31 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
32 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; 32 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
33 return js('function(#) { return #.# }', [args, receiver, fieldName]); 33 return js('function(#) { return #.# }', [args, receiver, fieldName]);
34 } 34 }
35 35
36 jsAst.Expression generateSetter(Element member, String fieldName) { 36 jsAst.Expression generateSetter(Element member, jsAst.Name fieldName) {
37 ClassElement cls = member.enclosingClass; 37 ClassElement cls = member.enclosingClass;
38 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; 38 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
39 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; 39 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
40 // TODO(floitsch): remove 'return'? 40 // TODO(floitsch): remove 'return'?
41 return js('function(#, v) { return #.# = v; }', 41 return js('function(#, v) { return #.# = v; }',
42 [args, receiver, fieldName]); 42 [args, receiver, fieldName]);
43 } 43 }
44 44
45 /** 45 /**
46 * Documentation wanted -- johnniwinther 46 * Documentation wanted -- johnniwinther
47 * 47 *
48 * Invariant: [member] must be a declaration element. 48 * Invariant: [member] must be a declaration element.
49 */ 49 */
50 Map<String, jsAst.Expression> generateCallStubsForGetter( 50 Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter(
51 Element member, Set<Selector> selectors) { 51 Element member, Set<Selector> selectors) {
52 assert(invariant(member, member.isDeclaration)); 52 assert(invariant(member, member.isDeclaration));
53 53
54 // If the method is intercepted, the stub gets the 54 // If the method is intercepted, the stub gets the
55 // receiver explicitely and we need to pass it to the getter call. 55 // receiver explicitely and we need to pass it to the getter call.
56 bool isInterceptedMethod = backend.isInterceptedMethod(member); 56 bool isInterceptedMethod = backend.isInterceptedMethod(member);
57 bool isInterceptorClass = 57 bool isInterceptorClass =
58 backend.isInterceptorClass(member.enclosingClass); 58 backend.isInterceptorClass(member.enclosingClass);
59 59
60 const String receiverArgumentName = r'$receiver'; 60 const String receiverArgumentName = r'$receiver';
61 61
62 jsAst.Expression buildGetter() { 62 jsAst.Expression buildGetter() {
63 jsAst.Expression receiver = 63 jsAst.Expression receiver =
64 js(isInterceptorClass ? receiverArgumentName : 'this'); 64 js(isInterceptorClass ? receiverArgumentName : 'this');
65 if (member.isGetter) { 65 if (member.isGetter) {
66 String getterName = namer.getterForElement(member); 66 jsAst.Name getterName = namer.getterForElement(member);
67 if (isInterceptedMethod) { 67 if (isInterceptedMethod) {
68 return js('this.#(#)', [getterName, receiver]); 68 return js('this.#(#)', [getterName, receiver]);
69 } 69 }
70 return js('#.#()', [receiver, getterName]); 70 return js('#.#()', [receiver, getterName]);
71 } else { 71 } else {
72 String fieldName = namer.instanceFieldPropertyName(member); 72 jsAst.Name fieldName = namer.instanceFieldPropertyName(member);
73 return js('#.#', [receiver, fieldName]); 73 return js('#.#', [receiver, fieldName]);
74 } 74 }
75 } 75 }
76 76
77 Map<String, jsAst.Expression> generatedStubs = <String, jsAst.Expression>{}; 77 Map<jsAst.Name, jsAst.Expression> generatedStubs =
78 <jsAst.Name, jsAst.Expression>{};
78 79
79 // Two selectors may match but differ only in type. To avoid generating 80 // Two selectors may match but differ only in type. To avoid generating
80 // identical stubs for each we track untyped selectors which already have 81 // identical stubs for each we track untyped selectors which already have
81 // stubs. 82 // stubs.
82 Set<Selector> generatedSelectors = new Set<Selector>(); 83 Set<Selector> generatedSelectors = new Set<Selector>();
83 for (Selector selector in selectors) { 84 for (Selector selector in selectors) {
84 if (selector.applies(member, compiler.world)) { 85 if (selector.applies(member, compiler.world)) {
85 selector = selector.asUntyped; 86 selector = selector.asUntyped;
86 if (generatedSelectors.contains(selector)) continue; 87 if (generatedSelectors.contains(selector)) continue;
87 generatedSelectors.add(selector); 88 generatedSelectors.add(selector);
88 89
89 String invocationName = namer.invocationName(selector); 90 jsAst.Name invocationName = namer.invocationName(selector);
90 Selector callSelector = new Selector.callClosureFrom(selector); 91 Selector callSelector = new Selector.callClosureFrom(selector);
91 String closureCallName = namer.invocationName(callSelector); 92 jsAst.Name closureCallName = namer.invocationName(callSelector);
92 93
93 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 94 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
94 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 95 List<jsAst.Expression> arguments = <jsAst.Expression>[];
95 if (isInterceptedMethod) { 96 if (isInterceptedMethod) {
96 parameters.add(new jsAst.Parameter(receiverArgumentName)); 97 parameters.add(new jsAst.Parameter(receiverArgumentName));
97 } 98 }
98 99
99 for (int i = 0; i < selector.argumentCount; i++) { 100 for (int i = 0; i < selector.argumentCount; i++) {
100 String name = 'arg$i'; 101 String name = 'arg$i';
101 parameters.add(new jsAst.Parameter(name)); 102 parameters.add(new jsAst.Parameter(name));
102 arguments.add(js('#', name)); 103 arguments.add(js('#', name));
103 } 104 }
104 105
105 jsAst.Fun function = js( 106 jsAst.Fun function = js(
106 'function(#) { return #.#(#); }', 107 'function(#) { return #.#(#); }',
107 [ parameters, buildGetter(), closureCallName, arguments]); 108 [ parameters, buildGetter(), closureCallName, arguments]);
108 109
109 generatedStubs[invocationName] = function; 110 generatedStubs[invocationName] = function;
110 } 111 }
111 } 112 }
112 113
113 return generatedStubs; 114 return generatedStubs;
114 } 115 }
115 116
116 Map<String, Selector> computeSelectorsForNsmHandlers() { 117 Map<jsAst.Name, Selector> computeSelectorsForNsmHandlers() {
117 118
118 Map<String, Selector> jsNames = <String, Selector>{}; 119 Map<jsAst.Name, Selector> jsNames = <jsAst.Name, Selector>{};
119 120
120 // Do not generate no such method handlers if there is no class. 121 // Do not generate no such method handlers if there is no class.
121 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) { 122 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) {
122 return jsNames; 123 return jsNames;
123 } 124 }
124 125
125 void addNoSuchMethodHandlers(String ignore, Set<Selector> selectors) { 126 void addNoSuchMethodHandlers(String ignore, Set<Selector> selectors) {
126 TypeMask objectSubclassTypeMask = 127 TypeMask objectSubclassTypeMask =
127 new TypeMask.subclass(compiler.objectClass, compiler.world); 128 new TypeMask.subclass(compiler.objectClass, compiler.world);
128 129
129 for (Selector selector in selectors) { 130 for (Selector selector in selectors) {
130 TypeMask mask = selector.mask; 131 TypeMask mask = selector.mask;
131 if (mask == null) mask = objectSubclassTypeMask; 132 if (mask == null) mask = objectSubclassTypeMask;
132 133
133 if (!mask.needsNoSuchMethodHandling(selector, compiler.world)) { 134 if (!mask.needsNoSuchMethodHandling(selector, compiler.world)) {
134 continue; 135 continue;
135 } 136 }
136 String jsName = namer.invocationMirrorInternalName(selector); 137 jsAst.Name jsName = namer.invocationMirrorInternalName(selector);
137 jsNames[jsName] = selector; 138 jsNames[jsName] = selector;
138 } 139 }
139 } 140 }
140 141
141 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); 142 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
142 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); 143 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
143 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); 144 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers);
144 return jsNames; 145 return jsNames;
145 } 146 }
146 147
147 StubMethod generateStubForNoSuchMethod(String name, Selector selector) { 148 StubMethod generateStubForNoSuchMethod(jsAst.Name name,
149 Selector selector) {
148 // Values match JSInvocationMirror in js-helper library. 150 // Values match JSInvocationMirror in js-helper library.
149 int type = selector.invocationMirrorKind; 151 int type = selector.invocationMirrorKind;
150 List<String> parameterNames = 152 List<String> parameterNames =
151 new List.generate(selector.argumentCount, (i) => '\$$i'); 153 new List.generate(selector.argumentCount, (i) => '\$$i');
152 154
153 List<jsAst.Expression> argNames = 155 List<jsAst.Expression> argNames =
154 selector.callStructure.getOrderedNamedArguments().map((String name) => 156 selector.callStructure.getOrderedNamedArguments().map((String name) =>
155 js.string(name)).toList(); 157 js.string(name)).toList();
156 158
157 String methodName = selector.invocationMirrorMemberName; 159 jsAst.Name methodName = namer.asName(selector.invocationMirrorMemberName);
158 String internalName = namer.invocationMirrorInternalName(selector); 160 jsAst.Name internalName = namer.invocationMirrorInternalName(selector);
159 161
160 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD)); 162 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
161 bool isIntercepted = backend.isInterceptedName(selector.name); 163 bool isIntercepted = backend.isInterceptedName(selector.name);
162 jsAst.Expression expression = 164 jsAst.Expression expression =
163 js('''this.#noSuchMethodName(#receiver, 165 js('''this.#noSuchMethodName(#receiver,
164 #createInvocationMirror(#methodName, 166 #createInvocationMirror(#methodName,
165 #internalName, 167 #internalName,
166 #type, 168 #type,
167 #arguments, 169 #arguments,
168 #namedArguments))''', 170 #namedArguments))''',
169 {'receiver': isIntercepted ? r'$receiver' : 'this', 171 {'receiver': isIntercepted ? r'$receiver' : 'this',
170 'noSuchMethodName': namer.noSuchMethodName, 172 'noSuchMethodName': namer.noSuchMethodName,
171 'createInvocationMirror': 173 'createInvocationMirror':
172 backend.emitter.staticFunctionAccess( 174 backend.emitter.staticFunctionAccess(
173 backend.getCreateInvocationMirror()), 175 backend.getCreateInvocationMirror()),
174 'methodName': 176 'methodName':
175 js.string(compiler.enableMinification 177 js.quoteName(compiler.enableMinification
176 ? internalName : methodName), 178 ? internalName : methodName),
177 'internalName': js.string(internalName), 179 'internalName': js.quoteName(internalName),
178 'type': js.number(type), 180 'type': js.number(type),
179 'arguments': 181 'arguments':
180 new jsAst.ArrayInitializer(parameterNames.map(js).toList()), 182 new jsAst.ArrayInitializer(parameterNames.map(js).toList()),
181 'namedArguments': new jsAst.ArrayInitializer(argNames)}); 183 'namedArguments': new jsAst.ArrayInitializer(argNames)});
182 184
183 jsAst.Expression function; 185 jsAst.Expression function;
184 if (isIntercepted) { 186 if (isIntercepted) {
185 function = js(r'function($receiver, #) { return # }', 187 function = js(r'function($receiver, #) { return # }',
186 [parameterNames, expression]); 188 [parameterNames, expression]);
187 } else { 189 } else {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 ? function() { 283 ? function() {
282 if (cache === void 0) cache = #tearOff( 284 if (cache === void 0) cache = #tearOff(
283 this, funcs, reflectionInfo, true, [], name).prototype; 285 this, funcs, reflectionInfo, true, [], name).prototype;
284 return cache; 286 return cache;
285 } 287 }
286 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted); 288 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
287 }''', {'tearOff': tearOffAccessExpression}); 289 }''', {'tearOff': tearOffAccessExpression});
288 290
289 return <jsAst.Statement>[tearOffGetter, tearOff]; 291 return <jsAst.Statement>[tearOffGetter, tearOff];
290 } 292 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698