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

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

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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(
15 Iterable<jsAst.Name> fields) { 15 ClassElement classElement, Iterable<jsAst.Name> 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
29 jsAst.Expression generateGetter(Element member, jsAst.Name fieldName) { 30 jsAst.Expression generateGetter(Element member, jsAst.Name fieldName) {
30 ClassElement cls = member.enclosingClass; 31 ClassElement cls = member.enclosingClass;
31 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; 32 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
32 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; 33 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
33 return js('function(#) { return #.# }', [args, receiver, fieldName]); 34 return js('function(#) { return #.# }', [args, receiver, fieldName]);
34 } 35 }
35 36
36 jsAst.Expression generateSetter(Element member, jsAst.Name fieldName) { 37 jsAst.Expression generateSetter(Element member, jsAst.Name fieldName) {
37 ClassElement cls = member.enclosingClass; 38 ClassElement cls = member.enclosingClass;
38 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; 39 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
39 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; 40 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
40 // TODO(floitsch): remove 'return'? 41 // TODO(floitsch): remove 'return'?
41 return js('function(#, v) { return #.# = v; }', 42 return js(
42 [args, receiver, fieldName]); 43 'function(#, v) { return #.# = v; }', [args, receiver, fieldName]);
43 } 44 }
44 45
45 /** 46 /**
46 * Documentation wanted -- johnniwinther 47 * Documentation wanted -- johnniwinther
47 * 48 *
48 * Invariant: [member] must be a declaration element. 49 * Invariant: [member] must be a declaration element.
49 */ 50 */
50 Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter( 51 Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter(
51 Element member, Map<Selector, SelectorConstraints> selectors) { 52 Element member, Map<Selector, SelectorConstraints> selectors) {
52 assert(invariant(member, member.isDeclaration)); 53 assert(invariant(member, member.isDeclaration));
53 54
54 // If the method is intercepted, the stub gets the 55 // If the method is intercepted, the stub gets the
55 // receiver explicitely and we need to pass it to the getter call. 56 // receiver explicitely and we need to pass it to the getter call.
56 bool isInterceptedMethod = backend.isInterceptedMethod(member); 57 bool isInterceptedMethod = backend.isInterceptedMethod(member);
57 bool isInterceptorClass = 58 bool isInterceptorClass = 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 jsAst.Name 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 jsAst.Name 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<jsAst.Name, jsAst.Expression> generatedStubs = 77 Map<jsAst.Name, jsAst.Expression> generatedStubs =
78 <jsAst.Name, jsAst.Expression>{}; 78 <jsAst.Name, jsAst.Expression>{};
79 79
80 // 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
81 // identical stubs for each we track untyped selectors which already have 81 // identical stubs for each we track untyped selectors which already have
82 // stubs. 82 // stubs.
83 Set<Selector> generatedSelectors = new Set<Selector>(); 83 Set<Selector> generatedSelectors = new Set<Selector>();
84 for (Selector selector in selectors.keys) { 84 for (Selector selector in selectors.keys) {
85 if (generatedSelectors.contains(selector)) continue; 85 if (generatedSelectors.contains(selector)) continue;
86 if (!selector.appliesUnnamed(member, compiler.world)) continue; 86 if (!selector.appliesUnnamed(member, compiler.world)) continue;
87 if (selectors[selector].applies(member, selector, compiler.world)) { 87 if (selectors[selector].applies(member, selector, compiler.world)) {
88 generatedSelectors.add(selector); 88 generatedSelectors.add(selector);
89 89
90 jsAst.Name invocationName = namer.invocationName(selector); 90 jsAst.Name invocationName = namer.invocationName(selector);
91 Selector callSelector = new Selector.callClosureFrom(selector); 91 Selector callSelector = new Selector.callClosureFrom(selector);
92 jsAst.Name closureCallName = namer.invocationName(callSelector); 92 jsAst.Name closureCallName = namer.invocationName(callSelector);
93 93
94 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 94 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
95 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 95 List<jsAst.Expression> arguments = <jsAst.Expression>[];
96 if (isInterceptedMethod) { 96 if (isInterceptedMethod) {
97 parameters.add(new jsAst.Parameter(receiverArgumentName)); 97 parameters.add(new jsAst.Parameter(receiverArgumentName));
98 } 98 }
99 99
100 for (int i = 0; i < selector.argumentCount; i++) { 100 for (int i = 0; i < selector.argumentCount; i++) {
101 String name = 'arg$i'; 101 String name = 'arg$i';
102 parameters.add(new jsAst.Parameter(name)); 102 parameters.add(new jsAst.Parameter(name));
103 arguments.add(js('#', name)); 103 arguments.add(js('#', name));
104 } 104 }
105 105
106 jsAst.Fun function = js( 106 jsAst.Fun function = js('function(#) { return #.#(#); }',
107 'function(#) { return #.#(#); }', 107 [parameters, buildGetter(), closureCallName, arguments]);
108 [ parameters, buildGetter(), closureCallName, arguments]);
109 108
110 generatedStubs[invocationName] = function; 109 generatedStubs[invocationName] = function;
111 } 110 }
112 } 111 }
113 112
114 return generatedStubs; 113 return generatedStubs;
115 } 114 }
116 115
117 Map<jsAst.Name, Selector> computeSelectorsForNsmHandlers() { 116 Map<jsAst.Name, Selector> computeSelectorsForNsmHandlers() {
118
119 Map<jsAst.Name, Selector> jsNames = <jsAst.Name, Selector>{}; 117 Map<jsAst.Name, Selector> jsNames = <jsAst.Name, Selector>{};
120 118
121 // Do not generate no such method handlers if there is no class. 119 // Do not generate no such method handlers if there is no class.
122 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) { 120 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) {
123 return jsNames; 121 return jsNames;
124 } 122 }
125 123
126 void addNoSuchMethodHandlers(String ignore, 124 void addNoSuchMethodHandlers(
127 Map<Selector, SelectorConstraints> selectors) { 125 String ignore, Map<Selector, SelectorConstraints> selectors) {
128 for (Selector selector in selectors.keys) { 126 for (Selector selector in selectors.keys) {
129 SelectorConstraints maskSet = selectors[selector]; 127 SelectorConstraints maskSet = selectors[selector];
130 if (maskSet.needsNoSuchMethodHandling(selector, compiler.world)) { 128 if (maskSet.needsNoSuchMethodHandling(selector, compiler.world)) {
131 jsAst.Name jsName = namer.invocationMirrorInternalName(selector); 129 jsAst.Name jsName = namer.invocationMirrorInternalName(selector);
132 jsNames[jsName] = selector; 130 jsNames[jsName] = selector;
133 } 131 }
134 } 132 }
135 } 133 }
136 134
137 compiler.codegenWorld.forEachInvokedName(addNoSuchMethodHandlers); 135 compiler.codegenWorld.forEachInvokedName(addNoSuchMethodHandlers);
138 compiler.codegenWorld.forEachInvokedGetter(addNoSuchMethodHandlers); 136 compiler.codegenWorld.forEachInvokedGetter(addNoSuchMethodHandlers);
139 compiler.codegenWorld.forEachInvokedSetter(addNoSuchMethodHandlers); 137 compiler.codegenWorld.forEachInvokedSetter(addNoSuchMethodHandlers);
140 return jsNames; 138 return jsNames;
141 } 139 }
142 140
143 StubMethod generateStubForNoSuchMethod(jsAst.Name name, 141 StubMethod generateStubForNoSuchMethod(jsAst.Name name, Selector selector) {
144 Selector selector) {
145 // Values match JSInvocationMirror in js-helper library. 142 // Values match JSInvocationMirror in js-helper library.
146 int type = selector.invocationMirrorKind; 143 int type = selector.invocationMirrorKind;
147 List<String> parameterNames = 144 List<String> parameterNames =
148 new List.generate(selector.argumentCount, (i) => '\$$i'); 145 new List.generate(selector.argumentCount, (i) => '\$$i');
149 146
150 List<jsAst.Expression> argNames = 147 List<jsAst.Expression> argNames = selector.callStructure
151 selector.callStructure.getOrderedNamedArguments().map((String name) => 148 .getOrderedNamedArguments()
152 js.string(name)).toList(); 149 .map((String name) => js.string(name))
150 .toList();
153 151
154 jsAst.Name methodName = namer.asName(selector.invocationMirrorMemberName); 152 jsAst.Name methodName = namer.asName(selector.invocationMirrorMemberName);
155 jsAst.Name internalName = namer.invocationMirrorInternalName(selector); 153 jsAst.Name internalName = namer.invocationMirrorInternalName(selector);
156 154
157 assert(backend.isInterceptedName(Identifiers.noSuchMethod_)); 155 assert(backend.isInterceptedName(Identifiers.noSuchMethod_));
158 bool isIntercepted = backend.isInterceptedName(selector.name); 156 bool isIntercepted = backend.isInterceptedName(selector.name);
159 jsAst.Expression expression = 157 jsAst.Expression expression = js(
160 js('''this.#noSuchMethodName(#receiver, 158 '''this.#noSuchMethodName(#receiver,
161 #createInvocationMirror(#methodName, 159 #createInvocationMirror(#methodName,
162 #internalName, 160 #internalName,
163 #type, 161 #type,
164 #arguments, 162 #arguments,
165 #namedArguments))''', 163 #namedArguments))''',
166 {'receiver': isIntercepted ? r'$receiver' : 'this', 164 {
167 'noSuchMethodName': namer.noSuchMethodName, 165 'receiver': isIntercepted ? r'$receiver' : 'this',
168 'createInvocationMirror': 166 'noSuchMethodName': namer.noSuchMethodName,
169 backend.emitter.staticFunctionAccess( 167 'createInvocationMirror': backend.emitter
170 backend.helpers.createInvocationMirror), 168 .staticFunctionAccess(backend.helpers.createInvocationMirror),
171 'methodName': 169 'methodName': js.quoteName(
172 js.quoteName(compiler.options.enableMinification 170 compiler.options.enableMinification ? internalName : methodName),
173 ? internalName : methodName), 171 'internalName': js.quoteName(internalName),
174 'internalName': js.quoteName(internalName), 172 'type': js.number(type),
175 'type': js.number(type), 173 'arguments':
176 'arguments': 174 new jsAst.ArrayInitializer(parameterNames.map(js).toList()),
177 new jsAst.ArrayInitializer(parameterNames.map(js).toList()), 175 'namedArguments': new jsAst.ArrayInitializer(argNames)
178 'namedArguments': new jsAst.ArrayInitializer(argNames)}); 176 });
179 177
180 jsAst.Expression function; 178 jsAst.Expression function;
181 if (isIntercepted) { 179 if (isIntercepted) {
182 function = js(r'function($receiver, #) { return # }', 180 function = js(
183 [parameterNames, expression]); 181 r'function($receiver, #) { return # }', [parameterNames, expression]);
184 } else { 182 } else {
185 function = js(r'function(#) { return # }', [parameterNames, expression]); 183 function = js(r'function(#) { return # }', [parameterNames, expression]);
186 } 184 }
187 return new StubMethod(name, function); 185 return new StubMethod(name, function);
188 } 186 }
189 } 187 }
190 188
191 /// Creates two JavaScript functions: `tearOffGetter` and `tearOff`. 189 /// Creates two JavaScript functions: `tearOffGetter` and `tearOff`.
192 /// 190 ///
193 /// `tearOffGetter` is internal and only used by `tearOff`. 191 /// `tearOffGetter` is internal and only used by `tearOff`.
(...skipping 18 matching lines...) Expand all
212 jsAst.Expression tearOffGlobalObject; 210 jsAst.Expression tearOffGlobalObject;
213 if (closureFromTearOff != null) { 211 if (closureFromTearOff != null) {
214 tearOffAccessExpression = 212 tearOffAccessExpression =
215 backend.emitter.staticFunctionAccess(closureFromTearOff); 213 backend.emitter.staticFunctionAccess(closureFromTearOff);
216 tearOffGlobalObject = 214 tearOffGlobalObject =
217 js.stringPart(namer.globalObjectFor(closureFromTearOff)); 215 js.stringPart(namer.globalObjectFor(closureFromTearOff));
218 tearOffGlobalObjectString = 216 tearOffGlobalObjectString =
219 js.string(namer.globalObjectFor(closureFromTearOff)); 217 js.string(namer.globalObjectFor(closureFromTearOff));
220 } else { 218 } else {
221 // Default values for mocked-up test libraries. 219 // Default values for mocked-up test libraries.
222 tearOffAccessExpression = js( 220 tearOffAccessExpression =
223 r'''function() { throw "Helper 'closureFromTearOff' missing." }'''); 221 js(r'''function() { throw "Helper 'closureFromTearOff' missing." }''');
224 tearOffGlobalObjectString = js.string('MissingHelperFunction'); 222 tearOffGlobalObjectString = js.string('MissingHelperFunction');
225 tearOffGlobalObject = js( 223 tearOffGlobalObject = js(
226 r'''(function() { throw "Helper 'closureFromTearOff' missing." })()'''); 224 r'''(function() { throw "Helper 'closureFromTearOff' missing." })()''');
227 } 225 }
228 226
229 jsAst.Statement tearOffGetter; 227 jsAst.Statement tearOffGetter;
230 if (!compiler.options.useContentSecurityPolicy) { 228 if (!compiler.options.useContentSecurityPolicy) {
231 jsAst.Expression tearOffAccessText = 229 jsAst.Expression tearOffAccessText =
232 new jsAst.UnparsedNode(tearOffAccessExpression, compiler, false); 230 new jsAst.UnparsedNode(tearOffAccessExpression, compiler, false);
233 tearOffGetter = js.statement(''' 231 tearOffGetter = js.statement(
232 '''
234 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) { 233 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
235 return isIntercepted 234 return isIntercepted
236 ? new Function("funcs", "reflectionInfo", "name", 235 ? new Function("funcs", "reflectionInfo", "name",
237 #tearOffGlobalObjectString, "c", 236 #tearOffGlobalObjectString, "c",
238 "return function tearOff_" + name + (functionCounter++) + "(x) {" + 237 "return function tearOff_" + name + (functionCounter++) + "(x) {" +
239 "if (c === null) c = " + #tearOffAccessText + "(" + 238 "if (c === null) c = " + #tearOffAccessText + "(" +
240 "this, funcs, reflectionInfo, false, [x], name);" + 239 "this, funcs, reflectionInfo, false, [x], name);" +
241 "return new c(this, funcs[0], x, name);" + 240 "return new c(this, funcs[0], x, name);" +
242 "}")(funcs, reflectionInfo, name, #tearOffGlobalObject, null) 241 "}")(funcs, reflectionInfo, name, #tearOffGlobalObject, null)
243 : new Function("funcs", "reflectionInfo", "name", 242 : new Function("funcs", "reflectionInfo", "name",
244 #tearOffGlobalObjectString, "c", 243 #tearOffGlobalObjectString, "c",
245 "return function tearOff_" + name + (functionCounter++)+ "() {" + 244 "return function tearOff_" + name + (functionCounter++)+ "() {" +
246 "if (c === null) c = " + #tearOffAccessText + "(" + 245 "if (c === null) c = " + #tearOffAccessText + "(" +
247 "this, funcs, reflectionInfo, false, [], name);" + 246 "this, funcs, reflectionInfo, false, [], name);" +
248 "return new c(this, funcs[0], null, name);" + 247 "return new c(this, funcs[0], null, name);" +
249 "}")(funcs, reflectionInfo, name, #tearOffGlobalObject, null); 248 "}")(funcs, reflectionInfo, name, #tearOffGlobalObject, null);
250 }''', {'tearOffAccessText': tearOffAccessText, 249 }''',
251 'tearOffGlobalObject': tearOffGlobalObject, 250 {
252 'tearOffGlobalObjectString': tearOffGlobalObjectString}); 251 'tearOffAccessText': tearOffAccessText,
252 'tearOffGlobalObject': tearOffGlobalObject,
253 'tearOffGlobalObjectString': tearOffGlobalObjectString
254 });
253 } else { 255 } else {
254 tearOffGetter = js.statement(''' 256 tearOffGetter = js.statement(
257 '''
255 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) { 258 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
256 var cache = null; 259 var cache = null;
257 return isIntercepted 260 return isIntercepted
258 ? function(x) { 261 ? function(x) {
259 if (cache === null) cache = #( 262 if (cache === null) cache = #(
260 this, funcs, reflectionInfo, false, [x], name); 263 this, funcs, reflectionInfo, false, [x], name);
261 return new cache(this, funcs[0], x, name); 264 return new cache(this, funcs[0], x, name);
262 } 265 }
263 : function() { 266 : function() {
264 if (cache === null) cache = #( 267 if (cache === null) cache = #(
265 this, funcs, reflectionInfo, false, [], name); 268 this, funcs, reflectionInfo, false, [], name);
266 return new cache(this, funcs[0], null, name); 269 return new cache(this, funcs[0], null, name);
267 }; 270 };
268 }''', [tearOffAccessExpression, tearOffAccessExpression]); 271 }''',
272 [tearOffAccessExpression, tearOffAccessExpression]);
269 } 273 }
270 274
271 jsAst.Statement tearOff = js.statement(''' 275 jsAst.Statement tearOff = js.statement(
276 '''
272 function tearOff(funcs, reflectionInfo, isStatic, name, isIntercepted) { 277 function tearOff(funcs, reflectionInfo, isStatic, name, isIntercepted) {
273 var cache; 278 var cache;
274 return isStatic 279 return isStatic
275 ? function() { 280 ? function() {
276 if (cache === void 0) cache = #tearOff( 281 if (cache === void 0) cache = #tearOff(
277 this, funcs, reflectionInfo, true, [], name).prototype; 282 this, funcs, reflectionInfo, true, [], name).prototype;
278 return cache; 283 return cache;
279 } 284 }
280 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted); 285 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
281 }''', {'tearOff': tearOffAccessExpression}); 286 }''',
287 {'tearOff': tearOffAccessExpression});
282 288
283 return <jsAst.Statement>[tearOffGetter, tearOff]; 289 return <jsAst.Statement>[tearOffGetter, tearOff];
284 } 290 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/type_variable_handler.dart ('k') | pkg/compiler/lib/src/js_emitter/code_emitter_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698