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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart

Issue 237583014: JS templates (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cleanup Created 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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 /// This class should morph into something that makes it easy to build 7 /// This class should morph into something that makes it easy to build
8 /// JavaScript representations of libraries, class-sides, and instance-sides. 8 /// JavaScript representations of libraries, class-sides, and instance-sides.
9 /// Initially, it is just a placeholder for code that is moved from 9 /// Initially, it is just a placeholder for code that is moved from
10 /// [CodeEmitterTask]. 10 /// [CodeEmitterTask].
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount); 64 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount);
65 // The arguments that will be passed to the real method. 65 // The arguments that will be passed to the real method.
66 List<jsAst.Expression> argumentsBuffer = 66 List<jsAst.Expression> argumentsBuffer =
67 new List<jsAst.Expression>( 67 new List<jsAst.Expression>(
68 parameters.parameterCount + extraArgumentCount); 68 parameters.parameterCount + extraArgumentCount);
69 69
70 int count = 0; 70 int count = 0;
71 if (isInterceptedMethod) { 71 if (isInterceptedMethod) {
72 count++; 72 count++;
73 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName); 73 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
74 argumentsBuffer[0] = js(receiverArgumentName); 74 argumentsBuffer[0] = js('#', receiverArgumentName);
75 task.interceptorEmitter.interceptorInvocationNames.add(invocationName); 75 task.interceptorEmitter.interceptorInvocationNames.add(invocationName);
76 } 76 }
77 77
78 int optionalParameterStart = positionalArgumentCount + extraArgumentCount; 78 int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
79 // Includes extra receiver argument when using interceptor convention 79 // Includes extra receiver argument when using interceptor convention
80 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1; 80 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1;
81 81
82 TreeElements elements = 82 TreeElements elements =
83 compiler.enqueuer.resolution.getCachedElements(member); 83 compiler.enqueuer.resolution.getCachedElements(member);
84 84
85 int parameterIndex = 0; 85 int parameterIndex = 0;
86 parameters.orderedForEachParameter((Element element) { 86 parameters.orderedForEachParameter((Element element) {
87 String jsName = backend.namer.safeName(element.name); 87 String jsName = backend.namer.safeName(element.name);
88 assert(jsName != receiverArgumentName); 88 assert(jsName != receiverArgumentName);
89 if (count < optionalParameterStart) { 89 if (count < optionalParameterStart) {
90 parametersBuffer[count] = new jsAst.Parameter(jsName); 90 parametersBuffer[count] = new jsAst.Parameter(jsName);
91 argumentsBuffer[count] = js(jsName); 91 argumentsBuffer[count] = js('#', jsName);
92 } else { 92 } else {
93 int index = names.indexOf(element.name); 93 int index = names.indexOf(element.name);
94 if (index != -1) { 94 if (index != -1) {
95 indexOfLastOptionalArgumentInParameters = count; 95 indexOfLastOptionalArgumentInParameters = count;
96 // The order of the named arguments is not the same as the 96 // The order of the named arguments is not the same as the
97 // one in the real method (which is in Dart source order). 97 // one in the real method (which is in Dart source order).
98 argumentsBuffer[count] = js(jsName); 98 argumentsBuffer[count] = js('#', jsName);
99 parametersBuffer[optionalParameterStart + index] = 99 parametersBuffer[optionalParameterStart + index] =
100 new jsAst.Parameter(jsName); 100 new jsAst.Parameter(jsName);
101 } else { 101 } else {
102 Constant value = handler.getConstantForVariable(element); 102 Constant value = handler.getConstantForVariable(element);
103 if (value == null) { 103 if (value == null) {
104 argumentsBuffer[count] = task.constantReference(new NullConstant()); 104 argumentsBuffer[count] = task.constantReference(new NullConstant());
105 } else { 105 } else {
106 if (!value.isNull) { 106 if (!value.isNull) {
107 // If the value is the null constant, we should not pass it 107 // If the value is the null constant, we should not pass it
108 // down to the native method. 108 // down to the native method.
109 indexOfLastOptionalArgumentInParameters = count; 109 indexOfLastOptionalArgumentInParameters = count;
110 } 110 }
111 argumentsBuffer[count] = task.constantReference(value); 111 argumentsBuffer[count] = task.constantReference(value);
112 } 112 }
113 } 113 }
114 } 114 }
115 count++; 115 count++;
116 }); 116 });
117 117
118 List body; 118 var body; // List or jsAst.Statement.
119 if (member.hasFixedBackendName()) { 119 if (member.hasFixedBackendName()) {
120 body = task.nativeEmitter.generateParameterStubStatements( 120 body = task.nativeEmitter.generateParameterStubStatements(
121 member, isInterceptedMethod, invocationName, 121 member, isInterceptedMethod, invocationName,
122 parametersBuffer, argumentsBuffer, 122 parametersBuffer, argumentsBuffer,
123 indexOfLastOptionalArgumentInParameters); 123 indexOfLastOptionalArgumentInParameters);
124 } else if (member.isInstanceMember()) { 124 } else if (member.isInstanceMember()) {
125 if (needsSuperGetter(member)) { 125 if (needsSuperGetter(member)) {
126 ClassElement superClass = member.getEnclosingClass(); 126 ClassElement superClass = member.getEnclosingClass();
127 String methodName = namer.getNameOfInstanceMember(member); 127 String methodName = namer.getNameOfInstanceMember(member);
128 // When redirecting, we must ensure that we don't end up in a subclass. 128 // When redirecting, we must ensure that we don't end up in a subclass.
129 // We thus can't just invoke `this.foo$1.call(filledInArguments)`. 129 // We thus can't just invoke `this.foo$1.call(filledInArguments)`.
130 // Instead we need to call the statically resolved target. 130 // Instead we need to call the statically resolved target.
131 // `<class>.prototype.bar$1.call(this, argument0, ...)`. 131 // `<class>.prototype.bar$1.call(this, argument0, ...)`.
132 body = [js.return_( 132 body = js.statement(
133 backend.namer.elementAccess(superClass)['prototype'][methodName] 133 'return #.prototype.#.call(this, #);',
134 ["call"](["this"]..addAll(argumentsBuffer)))]; 134 [backend.namer.elementAccess(superClass), methodName,
135 argumentsBuffer]);
135 } else { 136 } else {
136 body = [js.return_( 137 body = js.statement(
137 js('this') 138 'return this.#(#);',
138 [namer.getNameOfInstanceMember(member)](argumentsBuffer))]; 139 [namer.getNameOfInstanceMember(member), argumentsBuffer]);
139 } 140 }
140 } else { 141 } else {
141 body = [js.return_(namer.elementAccess(member)(argumentsBuffer))]; 142 body = js.statement('return #(#)',
143 [namer.elementAccess(member), argumentsBuffer]);
142 } 144 }
143 145
144 jsAst.Fun function = js.fun(parametersBuffer, body); 146 jsAst.Fun function = js('function(#) { #; }', [parametersBuffer, body]);
145 147
146 addStub(selector, function); 148 addStub(selector, function);
147 } 149 }
148 150
149 void addParameterStubs(FunctionElement member, AddStubFunction defineStub, 151 void addParameterStubs(FunctionElement member, AddStubFunction defineStub,
150 [bool canTearOff = false]) { 152 [bool canTearOff = false]) {
151 if (member.enclosingElement.isClosure()) { 153 if (member.enclosingElement.isClosure()) {
152 ClosureClassElement cls = member.enclosingElement; 154 ClosureClassElement cls = member.enclosingElement;
153 if (cls.supertype.element == compiler.boundClosureClass) { 155 if (cls.supertype.element == compiler.boundClosureClass) {
154 compiler.internalError(cls.methodElement, 'Bound closure1.'); 156 compiler.internalError(cls.methodElement, 'Bound closure1.');
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 backend.isInterceptorClass(member.getEnclosingClass()); 262 backend.isInterceptorClass(member.getEnclosingClass());
261 263
262 const String receiverArgumentName = r'$receiver'; 264 const String receiverArgumentName = r'$receiver';
263 265
264 jsAst.Expression buildGetter() { 266 jsAst.Expression buildGetter() {
265 jsAst.Expression receiver = 267 jsAst.Expression receiver =
266 js(isInterceptorClass ? receiverArgumentName : 'this'); 268 js(isInterceptorClass ? receiverArgumentName : 'this');
267 if (member.isGetter()) { 269 if (member.isGetter()) {
268 String getterName = namer.getterName(member); 270 String getterName = namer.getterName(member);
269 if (isInterceptedMethod) { 271 if (isInterceptedMethod) {
270 return js('this')[getterName](<jsAst.Expression>[receiver]); 272 //return js('this')[getterName](<jsAst.Expression>[receiver]);
floitsch 2014/04/22 16:11:18 dead code.
sra1 2014/04/23 02:33:50 Done.
273 return js('this.#(#)', [getterName, receiver]);
271 } 274 }
272 return receiver[getterName](<jsAst.Expression>[]); 275 //return receiver[getterName](<jsAst.Expression>[]);
floitsch 2014/04/22 16:11:18 ditto.
sra1 2014/04/23 02:33:50 Done.
276 return js('#.#()', [receiver, getterName]);
273 } else { 277 } else {
274 String fieldName = namer.instanceFieldPropertyName(member); 278 String fieldName = namer.instanceFieldPropertyName(member);
275 return receiver[fieldName]; 279 return js('#.#', [receiver, fieldName]);
276 } 280 }
277 } 281 }
278 282
279 // Two selectors may match but differ only in type. To avoid generating 283 // Two selectors may match but differ only in type. To avoid generating
280 // identical stubs for each we track untyped selectors which already have 284 // identical stubs for each we track untyped selectors which already have
281 // stubs. 285 // stubs.
282 Set<Selector> generatedSelectors = new Set<Selector>(); 286 Set<Selector> generatedSelectors = new Set<Selector>();
283 for (Selector selector in selectors) { 287 for (Selector selector in selectors) {
284 if (selector.applies(member, compiler)) { 288 if (selector.applies(member, compiler)) {
285 selector = selector.asUntyped; 289 selector = selector.asUntyped;
286 if (generatedSelectors.contains(selector)) continue; 290 if (generatedSelectors.contains(selector)) continue;
287 generatedSelectors.add(selector); 291 generatedSelectors.add(selector);
288 292
289 String invocationName = namer.invocationName(selector); 293 String invocationName = namer.invocationName(selector);
290 Selector callSelector = new Selector.callClosureFrom(selector); 294 Selector callSelector = new Selector.callClosureFrom(selector);
291 String closureCallName = namer.invocationName(callSelector); 295 String closureCallName = namer.invocationName(callSelector);
292 296
293 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 297 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
294 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 298 List<jsAst.Expression> arguments = <jsAst.Expression>[];
295 if (isInterceptedMethod) { 299 if (isInterceptedMethod) {
296 parameters.add(new jsAst.Parameter(receiverArgumentName)); 300 parameters.add(new jsAst.Parameter(receiverArgumentName));
297 } 301 }
298 302
299 for (int i = 0; i < selector.argumentCount; i++) { 303 for (int i = 0; i < selector.argumentCount; i++) {
300 String name = 'arg$i'; 304 String name = 'arg$i';
301 parameters.add(new jsAst.Parameter(name)); 305 parameters.add(new jsAst.Parameter(name));
302 arguments.add(js(name)); 306 arguments.add(js('#', name));
303 } 307 }
304 308
305 jsAst.Fun function = js.fun( 309 jsAst.Fun function = js(
306 parameters, 310 'function(#) { return #.#(#); }',
307 js.return_(buildGetter()[closureCallName](arguments))); 311 [ parameters, buildGetter(), closureCallName, arguments]);
308 312
309 addProperty(invocationName, function); 313 addProperty(invocationName, function);
310 } 314 }
311 } 315 }
312 } 316 }
313 317
314 /** 318 /**
315 * Documentation wanted -- johnniwinther 319 * Documentation wanted -- johnniwinther
316 * 320 *
317 * Invariant: [member] must be a declaration element. 321 * Invariant: [member] must be a declaration element.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 // N+4. First default argument. 421 // N+4. First default argument.
418 // ... 422 // ...
419 // O. First parameter name (if needed for reflection or Function.apply). 423 // O. First parameter name (if needed for reflection or Function.apply).
420 // ... 424 // ...
421 // P. Unmangled name (if reflectable). 425 // P. Unmangled name (if reflectable).
422 // P+1. First metadata (if reflectable). 426 // P+1. First metadata (if reflectable).
423 // ... 427 // ...
424 // TODO(ahe): Consider one of the parameter counts can be replaced by the 428 // TODO(ahe): Consider one of the parameter counts can be replaced by the
425 // length property of the JavaScript function object. 429 // length property of the JavaScript function object.
426 430
427 List expressions = []; 431 List<jsAst.Expression> expressions = <jsAst.Expression>[];
428 432
429 String callSelectorString = 'null'; 433 String callSelectorString = 'null';
430 if (member.isFunction()) { 434 if (member.isFunction()) {
431 Selector callSelector = 435 Selector callSelector =
432 new Selector.fromElement(member, compiler).toCallSelector(); 436 new Selector.fromElement(member, compiler).toCallSelector();
433 callSelectorString = '"${namer.invocationName(callSelector)}"'; 437 callSelectorString = '"${namer.invocationName(callSelector)}"';
434 } 438 }
435 439
436 // On [requiredParameterCount], the lower bit is set if this method can be 440 // On [requiredParameterCount], the lower bit is set if this method can be
437 // called reflectively. 441 // called reflectively.
438 int requiredParameterCount = parameters.requiredParameterCount << 1; 442 int requiredParameterCount = parameters.requiredParameterCount << 1;
439 if (member.isAccessor()) requiredParameterCount++; 443 if (member.isAccessor()) requiredParameterCount++;
440 444
441 int optionalParameterCount = parameters.optionalParameterCount << 1; 445 int optionalParameterCount = parameters.optionalParameterCount << 1;
442 if (parameters.optionalParametersAreNamed) optionalParameterCount++; 446 if (parameters.optionalParametersAreNamed) optionalParameterCount++;
443 447
444 expressions.add(code); 448 expressions.add(code);
445 449
450 // TODO(sra): Don't use LiteralString for non-strings.
446 List tearOffInfo = [new jsAst.LiteralString(callSelectorString)]; 451 List tearOffInfo = [new jsAst.LiteralString(callSelectorString)];
447 452
448 if (needsStubs || canTearOff) { 453 if (needsStubs || canTearOff) {
449 addParameterStubs(member, (Selector selector, jsAst.Fun function) { 454 addParameterStubs(member, (Selector selector, jsAst.Fun function) {
450 expressions.add(function); 455 expressions.add(function);
451 if (member.isInstanceMember()) { 456 if (member.isInstanceMember()) {
452 Set invokedSelectors = 457 Set invokedSelectors =
453 compiler.codegenWorld.invokedNames[member.name]; 458 compiler.codegenWorld.invokedNames[member.name];
454 expressions.add(js.string(namer.invocationName(selector))); 459 expressions.add(js.string(namer.invocationName(selector)));
455 } else { 460 } else {
456 expressions.add("null"); 461 expressions.add(js('null'));
457 // TOOD(ahe): Since we know when reading static data versus instance 462 // TOOD(ahe): Since we know when reading static data versus instance
458 // data, we can eliminate this element. 463 // data, we can eliminate this element.
459 } 464 }
460 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[ 465 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
461 namer.closureInvocationSelectorName]; 466 namer.closureInvocationSelectorName];
462 Selector callSelector = selector.toCallSelector(); 467 Selector callSelector = selector.toCallSelector();
463 String callSelectorString = 'null'; 468 String callSelectorString = 'null';
464 if (canTearOff && callSelectors != null && 469 if (canTearOff && callSelectors != null &&
465 callSelectors.contains(callSelector)) { 470 callSelectors.contains(callSelector)) {
466 callSelectorString = '"${namer.invocationName(callSelector)}"'; 471 callSelectorString = '"${namer.invocationName(callSelector)}"';
(...skipping 10 matching lines...) Expand all
477 memberType = body.constructor.type; 482 memberType = body.constructor.type;
478 } else { 483 } else {
479 memberType = member.type; 484 memberType = member.type;
480 } 485 }
481 if (memberType.containsTypeVariables) { 486 if (memberType.containsTypeVariables) {
482 jsAst.Expression thisAccess = js(r'this.$receiver'); 487 jsAst.Expression thisAccess = js(r'this.$receiver');
483 memberTypeExpression = 488 memberTypeExpression =
484 backend.rti.getSignatureEncoding(memberType, thisAccess); 489 backend.rti.getSignatureEncoding(memberType, thisAccess);
485 } else { 490 } else {
486 memberTypeExpression = 491 memberTypeExpression =
487 js.toExpression(task.metadataEmitter.reifyType(memberType)); 492 js.number(task.metadataEmitter.reifyType(memberType));
488 } 493 }
489 } else { 494 } else {
490 memberTypeExpression = js('null'); 495 memberTypeExpression = js('null');
491 } 496 }
492 497
493 expressions 498 expressions
494 ..addAll(tearOffInfo) 499 ..addAll(tearOffInfo)
495 ..add((tearOffName == null || member.isAccessor()) 500 ..add((tearOffName == null || member.isAccessor())
496 ? js("null") : js.string(tearOffName)) 501 ? js("null") : js.string(tearOffName))
497 ..add(requiredParameterCount) 502 ..add(js.number(requiredParameterCount))
498 ..add(optionalParameterCount) 503 ..add(js.number(optionalParameterCount))
499 ..add(memberTypeExpression) 504 ..add(memberTypeExpression)
500 ..addAll(task.metadataEmitter.reifyDefaultArguments(member)); 505 ..addAll(
506 task.metadataEmitter.reifyDefaultArguments(member).map(js.number));
501 507
502 if (canBeReflected || canBeApplied) { 508 if (canBeReflected || canBeApplied) {
503 parameters.forEachParameter((Element parameter) { 509 parameters.forEachParameter((Element parameter) {
504 expressions.add(task.metadataEmitter.reifyName(parameter.name)); 510 expressions.add(
511 js.number(task.metadataEmitter.reifyName(parameter.name)));
505 if (backend.mustRetainMetadata) { 512 if (backend.mustRetainMetadata) {
506 List<MetadataAnnotation> annotations = parameter.metadata.toList(); 513 List<MetadataAnnotation> annotations = parameter.metadata.toList();
507 Iterable<int> metadataIndices = 514 Iterable<int> metadataIndices =
508 annotations.map((MetadataAnnotation annotation) { 515 annotations.map((MetadataAnnotation annotation) {
509 Constant constant = 516 Constant constant =
510 backend.constants.getConstantForMetadata(annotation); 517 backend.constants.getConstantForMetadata(annotation);
511 backend.constants.addCompileTimeConstantForEmission(constant); 518 backend.constants.addCompileTimeConstantForEmission(constant);
512 return task.metadataEmitter.reifyMetadata(annotation); 519 return task.metadataEmitter.reifyMetadata(annotation);
513 }); 520 });
514 expressions.add(metadataIndices.isNotEmpty ? metadataIndices.toList() 521 expressions.add(
515 : js('[]')); 522 new jsAst.ArrayInitializer.from(metadataIndices.map(js.number)));
516 } 523 }
517 }); 524 });
518 } 525 }
519 if (canBeReflected) { 526 if (canBeReflected) {
520 jsAst.LiteralString reflectionName; 527 jsAst.LiteralString reflectionName;
521 if (member.isConstructor()) { 528 if (member.isConstructor()) {
522 String reflectionNameString = task.getReflectionName(member, name); 529 String reflectionNameString = task.getReflectionName(member, name);
523 reflectionName = 530 reflectionName =
524 new jsAst.LiteralString( 531 new jsAst.LiteralString(
525 '"new ${Elements.reconstructConstructorName(member)}"'); 532 '"new ${Elements.reconstructConstructorName(member)}"');
526 } else { 533 } else {
527 reflectionName = js.string(member.name); 534 reflectionName = js.string(member.name);
528 } 535 }
529 expressions 536 expressions
530 ..add(reflectionName) 537 ..add(reflectionName)
531 ..addAll(task.metadataEmitter.computeMetadata(member)); 538 ..addAll(task.metadataEmitter.computeMetadata(member).map(js.number));
532 } else if (isClosure && canBeApplied) { 539 } else if (isClosure && canBeApplied) {
533 expressions.add(js.string(member.name)); 540 expressions.add(js.string(member.name));
534 } 541 }
535 542 builder.addProperty(name, new jsAst.ArrayInitializer.from(expressions));
536 builder.addProperty(name, js.toExpression(expressions));
537 } 543 }
538 544
539 void addMemberField(VariableElement member, ClassBuilder builder) { 545 void addMemberField(VariableElement member, ClassBuilder builder) {
540 // For now, do nothing. 546 // For now, do nothing.
541 } 547 }
542 } 548 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698