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

Side by Side Diff: frog/leg/emitter.dart

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 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
« no previous file with comments | « frog/leg/elements/elements.dart ('k') | frog/leg/enqueue.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 /**
6 * A function element that represents a closure call. The signature is copied
7 * from the given element.
8 */
9 class ClosureInvocationElement extends FunctionElement {
10 ClosureInvocationElement(SourceString name,
11 FunctionElement other)
12 : super.from(name, other, other.enclosingElement);
13
14 isInstanceMember() => true;
15 }
16
17 /**
18 * Generates the code for all used classes in the program. Static fields (even
19 * in classes) are ignored, since they can be treated as non-class elements.
20 *
21 * The code for the containing (used) methods must exist in the [:universe:].
22 */
23 class CodeEmitterTask extends CompilerTask {
24 static final String INHERIT_FUNCTION = '''
25 function(child, parent) {
26 if (child.prototype.__proto__) {
27 child.prototype.__proto__ = parent.prototype;
28 } else {
29 function tmp() {};
30 tmp.prototype = parent.prototype;
31 child.prototype = new tmp();
32 child.prototype.constructor = child;
33 }
34 }''';
35
36 bool addedInheritFunction = false;
37 final Namer namer;
38 final NativeEmitter nativeEmitter;
39 Set<ClassElement> generatedClasses;
40 StringBuffer mainBuffer;
41
42 CodeEmitterTask(Compiler compiler)
43 : namer = compiler.namer,
44 nativeEmitter = new NativeEmitter(compiler),
45 generatedClasses = new Set<ClassElement>(),
46 mainBuffer = new StringBuffer(),
47 super(compiler);
48
49 String get name() => 'CodeEmitter';
50
51 String get inheritsName() => '${namer.ISOLATE}.\$inherits';
52
53 String get objectClassName() {
54 ClassElement objectClass =
55 compiler.coreLibrary.find(const SourceString('Object'));
56 return namer.isolatePropertyAccess(objectClass);
57 }
58
59 void addInheritFunctionIfNecessary() {
60 if (addedInheritFunction) return;
61 addedInheritFunction = true;
62 mainBuffer.add('$inheritsName = ');
63 mainBuffer.add(INHERIT_FUNCTION);
64 mainBuffer.add(';\n');
65 }
66
67 void addParameterStub(FunctionElement member,
68 String attachTo(String invocationName),
69 StringBuffer buffer,
70 Selector selector,
71 bool isNative) {
72 FunctionParameters parameters = member.computeParameters(compiler);
73 int positionalArgumentCount = selector.positionalArgumentCount;
74 if (positionalArgumentCount == parameters.parameterCount) {
75 assert(selector.namedArgumentCount == 0);
76 return;
77 }
78 ConstantHandler handler = compiler.constantHandler;
79 List<SourceString> names = selector.getOrderedNamedArguments();
80
81 String invocationName =
82 namer.instanceMethodInvocationName(member.getLibrary(), member.name,
83 selector);
84 buffer.add('${attachTo(invocationName)} = function(');
85
86 // The parameters that this stub takes.
87 List<String> parametersBuffer = new List<String>(selector.argumentCount);
88 // The arguments that will be passed to the real method.
89 List<String> argumentsBuffer = new List<String>(parameters.parameterCount);
90
91 // We fill the lists depending on the selector. For example,
92 // take method foo:
93 // foo(a, b, [c, d]);
94 //
95 // We may have multiple ways of calling foo:
96 // (1) foo(1, 2, 3, 4)
97 // (2) foo(1, 2);
98 // (3) foo(1, 2, 3);
99 // (4) foo(1, 2, c: 3);
100 // (5) foo(1, 2, d: 4);
101 // (6) foo(1, 2, c: 3, d: 4);
102 // (7) foo(1, 2, d: 4, c: 3);
103 //
104 // What we generate at the call sites are:
105 // (1) foo$4(1, 2, 3, 4)
106 // (2) foo$2(1, 2);
107 // (3) foo$3(1, 2, 3);
108 // (4) foo$3$c(1, 2, 3);
109 // (5) foo$3$d(1, 2, 4);
110 // (6) foo$4$c$d(1, 2, 3, 4);
111 // (7) foo$4$c$d(1, 2, 3, 4);
112 //
113 // The stubs we generate are (expressed in Dart):
114 // (1) No stub generated, call is direct.
115 // (2) foo$2(a, b) => foo$4(a, b, null, null)
116 // (3) foo$3(a, b, c) => foo$4(a, b, c, null)
117 // (4) foo$3$c(a, b, c) => foo$4(a, b, c, null);
118 // (5) foo$3$d(a, b, d) => foo$4(a, b, null, d);
119 // (6) foo$4$c$d(a, b, c, d) => foo$4(a, b, c, d);
120 // (7) Same as (5).
121 //
122 // We need to generate a stub for (5) because the order of the
123 // stub arguments and the real method may be different.
124
125 int count = 0;
126 int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1;
127 parameters.forEachParameter((Element element) {
128 String jsName = JsNames.getValid(element.name.slowToString());
129 if (count < positionalArgumentCount) {
130 parametersBuffer[count] = jsName;
131 argumentsBuffer[count] = jsName;
132 } else {
133 int index = names.indexOf(element.name);
134 if (index != -1) {
135 indexOfLastOptionalArgumentInParameters = count;
136 // The order of the named arguments is not the same as the
137 // one in the real method (which is in Dart source order).
138 argumentsBuffer[count] = jsName;
139 parametersBuffer[selector.positionalArgumentCount + index] = jsName;
140 } else {
141 Constant value = handler.initialVariableValues[element];
142 if (value == null) {
143 argumentsBuffer[count] = '(void 0)';
144 } else {
145 if (!value.isNull()) {
146 // If the value is the null constant, we should not pass it
147 // down to the native method.
148 indexOfLastOptionalArgumentInParameters = count;
149 }
150 argumentsBuffer[count] =
151 handler.writeJsCode(new StringBuffer(), value).toString();
152 }
153 }
154 }
155 count++;
156 });
157 String parametersString = Strings.join(parametersBuffer, ",");
158 buffer.add('$parametersString) {\n');
159
160 if (isNative) {
161 nativeEmitter.emitParameterStub(
162 member, invocationName, parametersString, argumentsBuffer,
163 indexOfLastOptionalArgumentInParameters);
164 } else {
165 String arguments = Strings.join(argumentsBuffer, ",");
166 buffer.add(' return this.${namer.getName(member)}($arguments)');
167 }
168 buffer.add('\n};\n');
169 }
170
171 void addParameterStubs(FunctionElement member,
172 String attachTo(String invocationName),
173 StringBuffer buffer,
174 [bool isNative = false]) {
175 Set<Selector> selectors = compiler.universe.invokedNames[member.name];
176 if (selectors == null) return;
177 FunctionParameters parameters = member.computeParameters(compiler);
178 for (Selector selector in selectors) {
179 if (!selector.applies(parameters)) continue;
180 addParameterStub(member, attachTo, buffer, selector, isNative);
181 }
182 }
183
184 void addInstanceMember(Element member,
185 String attachTo(String name),
186 StringBuffer buffer,
187 [bool isNative = false]) {
188 // TODO(floitsch): we don't need to deal with members of
189 // uninstantiated classes, that have been overwritten by subclasses.
190
191 if (member.kind === ElementKind.FUNCTION
192 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY
193 || member.kind === ElementKind.GETTER
194 || member.kind === ElementKind.SETTER) {
195 if (member.modifiers !== null && member.modifiers.isAbstract()) return;
196 String codeBlock = compiler.universe.generatedCode[member];
197 if (codeBlock == null) return;
198 buffer.add('${attachTo(namer.getName(member))} = $codeBlock;\n');
199 codeBlock = compiler.universe.generatedBailoutCode[member];
200 if (codeBlock !== null) {
201 String name = compiler.namer.getBailoutName(member);
202 buffer.add('${attachTo(name)} = $codeBlock;\n');
203 }
204 FunctionElement function = member;
205 FunctionParameters parameters = function.computeParameters(compiler);
206 if (!parameters.optionalParameters.isEmpty()) {
207 addParameterStubs(member, attachTo, buffer, isNative: isNative);
208 }
209 } else if (member.kind === ElementKind.FIELD) {
210 // TODO(ngeoffray): Have another class generate the code for the
211 // fields.
212 if ((member.modifiers === null || !member.modifiers.isFinal()) &&
213 compiler.universe.invokedSetters.contains(member.name)) {
214 String setterName = namer.setterName(member.getLibrary(), member.name);
215 String name =
216 isNative ? member.name.slowToString() : namer.getName(member);
217 buffer.add('${attachTo(setterName)} = function(v){\n');
218 buffer.add(' this.$name = v;\n};\n');
219 }
220 if (compiler.universe.invokedGetters.contains(member.name)) {
221 String getterName = namer.getterName(member.getLibrary(), member.name);
222 String name =
223 isNative ? member.name.slowToString() : namer.getName(member);
224 buffer.add('${attachTo(getterName)} = function(){\n');
225 buffer.add(' return this.$name;\n};\n');
226 }
227 } else {
228 compiler.internalError('unexpected kind: "${member.kind}"',
229 element: member);
230 }
231 emitExtraAccessors(member, attachTo, buffer);
232 }
233
234 bool generateFieldInits(ClassElement classElement,
235 StringBuffer argumentsBuffer,
236 StringBuffer bodyBuffer) {
237 bool isFirst = true;
238 do {
239 // TODO(floitsch): make sure there are no name clashes.
240 String className = namer.getName(classElement);
241
242 void generateFieldInit(Element member) {
243 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
244 if (!isFirst) argumentsBuffer.add(', ');
245 isFirst = false;
246 String memberName = namer.instanceFieldName(member.getLibrary(),
247 member.name);
248 argumentsBuffer.add('${className}_$memberName');
249 bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n');
250 }
251 }
252
253 for (Element element in classElement.members) {
254 generateFieldInit(element);
255 }
256 for (Element element in classElement.backendMembers) {
257 generateFieldInit(element);
258 }
259
260 classElement = classElement.superclass;
261 } while(classElement !== null);
262 }
263
264 void emitInherits(ClassElement cls, StringBuffer buffer) {
265 ClassElement superclass = cls.superclass;
266 if (superclass !== null) {
267 addInheritFunctionIfNecessary();
268 String className = namer.isolatePropertyAccess(cls);
269 String superName = namer.isolatePropertyAccess(superclass);
270 buffer.add('${inheritsName}($className, $superName);\n');
271 }
272 }
273
274 void ensureGenerated(ClassElement classElement, StringBuffer buffer) {
275 if (classElement == null) return;
276 if (generatedClasses.contains(classElement)) return;
277 generatedClasses.add(classElement);
278 generateClass(classElement, buffer);
279 }
280
281 void generateClass(ClassElement classElement, StringBuffer buffer) {
282 ensureGenerated(classElement.superclass, buffer);
283
284 if (classElement.isNative()) {
285 nativeEmitter.generateNativeClass(classElement);
286 return;
287 } else {
288 // TODO(ngeoffray): Instead of switching between buffer, we
289 // should create code sections, and decide where to emit them at
290 // the end.
291 buffer = mainBuffer;
292 }
293
294 String className = namer.isolatePropertyAccess(classElement);
295 String constructorName = namer.safeName(classElement.name.slowToString());
296 buffer.add('$className = function $constructorName(');
297 StringBuffer bodyBuffer = new StringBuffer();
298 // If the class is never instantiated we still need to set it up for
299 // inheritance purposes, but we can leave its JavaScript constructor empty.
300 if (compiler.universe.instantiatedClasses.contains(classElement)) {
301 generateFieldInits(classElement, buffer, bodyBuffer);
302 }
303 buffer.add(') {\n');
304 buffer.add(bodyBuffer);
305 buffer.add('};\n');
306
307 emitInherits(classElement, buffer);
308
309 String attachTo(String name) => '$className.prototype.$name';
310 for (Element member in classElement.members) {
311 if (member.isInstanceMember()) {
312 addInstanceMember(member, attachTo, buffer);
313 }
314 }
315 for (Element member in classElement.backendMembers) {
316 if (member.isInstanceMember()) {
317 addInstanceMember(member, attachTo, buffer);
318 }
319 }
320 generateTypeTests(classElement, (Element other) {
321 buffer.add('${attachTo(namer.operatorIs(other))} = ');
322 if (nativeEmitter.requiresNativeIsCheck(other)) {
323 buffer.add('function() { return true; }');
324 } else {
325 buffer.add('true');
326 }
327 buffer.add(';\n');
328 });
329
330 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) {
331 // Emit the noSuchMethods on the Object prototype now, so that
332 // the code in the dynamicMethod can find them. Note that the
333 // code in dynamicMethod is invoked before analyzing the full JS
334 // script.
335 emitNoSuchMethodCalls(buffer);
336 }
337 }
338
339 void generateTypeTests(ClassElement cls,
340 void generateTypeTest(ClassElement element)) {
341 if (compiler.universe.isChecks.contains(cls)) {
342 generateTypeTest(cls);
343 }
344 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>());
345 }
346
347 void generateInterfacesIsTests(ClassElement cls,
348 void generateTypeTest(ClassElement element),
349 Set<Element> alreadyGenerated) {
350 for (Type interfaceType in cls.interfaces) {
351 Element element = interfaceType.element;
352 if (!alreadyGenerated.contains(element) &&
353 compiler.universe.isChecks.contains(element)) {
354 alreadyGenerated.add(element);
355 generateTypeTest(element);
356 }
357 generateInterfacesIsTests(element, generateTypeTest, alreadyGenerated);
358 }
359 }
360
361 void emitClasses(StringBuffer buffer) {
362 for (ClassElement element in compiler.universe.instantiatedClasses) {
363 ensureGenerated(element, buffer);
364 }
365 }
366
367 void emitStaticFunctionsWithNamer(StringBuffer buffer,
368 Map<Element, String> generatedCode,
369 String functionNamer(Element element)) {
370 generatedCode.forEach((Element element, String codeBlock) {
371 if (!element.isInstanceMember()) {
372 buffer.add('${functionNamer(element)} = ');
373 buffer.add(codeBlock);
374 buffer.add(';\n\n');
375 }
376 });
377 }
378
379 void emitStaticFunctions(StringBuffer buffer) {
380 emitStaticFunctionsWithNamer(buffer,
381 compiler.universe.generatedCode,
382 namer.isolatePropertyAccess);
383 emitStaticFunctionsWithNamer(buffer,
384 compiler.universe.generatedBailoutCode,
385 namer.isolateBailoutPropertyAccess);
386 }
387
388 void emitStaticFunctionGetters(StringBuffer buffer) {
389 Set<FunctionElement> functionsNeedingGetter =
390 compiler.universe.staticFunctionsNeedingGetter;
391 for (FunctionElement element in functionsNeedingGetter) {
392 // The static function does not have the correct name. Since
393 // [addParameterStubs] use the name to create its stubs we simply
394 // create a fake element with the correct name.
395 // Note: the callElement will not have any enclosingElement.
396 FunctionElement callElement =
397 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element);
398 String staticName = namer.isolatePropertyAccess(element);
399 int parameterCount = element.parameterCount(compiler);
400 String invocationName =
401 namer.instanceMethodName(element.getLibrary(), callElement.name,
402 parameterCount);
403 buffer.add("$staticName.$invocationName = $staticName;\n");
404 addParameterStubs(callElement, (name) => '$staticName.$name', buffer);
405 }
406 }
407
408 void emitDynamicFunctionGetter(StringBuffer buffer,
409 String attachTo(String invocationName),
410 FunctionElement member) {
411 // For every method that has the same name as a property-get we create a
412 // getter that returns a bound closure. Say we have a class 'A' with method
413 // 'foo' and somewhere in the code there is a dynamic property get of
414 // 'foo'. Then we generate the following code (in pseudo Dart):
415 //
416 // class A {
417 // foo(x, y, z) { ... } // Original function.
418 // get foo() { return new BoundClosure499(this); }
419 // }
420 // class BoundClosure499 extends Closure {
421 // var self;
422 // BoundClosure499(this.self);
423 // $call3(x, y, z) { return self.foo(x, y, z); }
424 // }
425
426 // TODO(floitsch): share the closure classes with other classes
427 // if they share methods with the same signature.
428
429 // The closure class.
430 SourceString name = const SourceString("BoundClosure");
431 ClassElement closureClassElement =
432 new ClosureClassElement(compiler, member.getCompilationUnit());
433 String isolateAccess = namer.isolatePropertyAccess(closureClassElement);
434 ensureGenerated(closureClassElement.superclass, buffer);
435
436 // Define the constructor with a name so that Object.toString can
437 // find the class name of the closure class.
438 buffer.add("$isolateAccess = function $name(self) ");
439 buffer.add("{ this.self = self; };\n");
440 emitInherits(closureClassElement, buffer);
441
442 String prototype = "$isolateAccess.prototype";
443
444 // Now add the methods on the closure class. The instance method does not
445 // have the correct name. Since [addParameterStubs] use the name to create
446 // its stubs we simply create a fake element with the correct name.
447 // Note: the callElement will not have any enclosingElement.
448 FunctionElement callElement =
449 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
450
451 int parameterCount = member.parameterCount(compiler);
452 String invocationName =
453 namer.instanceMethodName(member.getLibrary(),
454 callElement.name, parameterCount);
455 String targetName = namer.instanceMethodName(member.getLibrary(),
456 member.name, parameterCount);
457 List<String> arguments = new List<String>(parameterCount);
458 for (int i = 0; i < parameterCount; i++) {
459 arguments[i] = "arg$i";
460 }
461 String joinedArgs = Strings.join(arguments, ", ");
462 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n");
463 buffer.add(" return this.self.$targetName($joinedArgs);\n");
464 buffer.add("};\n");
465 addParameterStubs(callElement,
466 (invocationName) => '$prototype.$invocationName',
467 buffer);
468
469 // And finally the getter.
470 String getterName = namer.getterName(member.getLibrary(), member.name);
471 String closureClass = namer.isolateAccess(closureClassElement);
472 buffer.add("${attachTo(getterName)} = function() {\n");
473 buffer.add(" return new $closureClass(this);\n");
474 buffer.add("};\n");
475 }
476
477 void emitCallStubForGetter(StringBuffer buffer,
478 String attachTo(String name),
479 Element member,
480 Set<Selector> selectors) {
481 String getter;
482 if (member.kind == ElementKind.GETTER) {
483 getter = "this.${namer.getterName(member.getLibrary(), member.name)}()";
484 } else {
485 getter =
486 "this.${namer.instanceFieldName(member.getLibrary(), member.name)}";
487 }
488 for (Selector selector in selectors) {
489 String invocationName =
490 namer.instanceMethodInvocationName(member.getLibrary(), member.name,
491 selector);
492 SourceString callName = Namer.CLOSURE_INVOCATION_NAME;
493 String closureCallName =
494 namer.instanceMethodInvocationName(member.getLibrary(), callName,
495 selector);
496 List<String> arguments = <String>[];
497 for (int i = 0; i < selector.argumentCount; i++) {
498 arguments.add("arg$i");
499 }
500 String joined = Strings.join(arguments, ", ");
501 buffer.add("${attachTo(invocationName)} = function($joined) {\n");
502 buffer.add(" return $getter.$closureCallName($joined);\n");
503 buffer.add("};\n");
504 }
505 }
506
507 void emitStaticNonFinalFieldInitializations(StringBuffer buffer) {
508 // Adds initializations inside the Isolate constructor.
509 // Example:
510 // function Isolate() {
511 // this.staticNonFinal = Isolate.prototype.someVal;
512 // ...
513 // }
514 ConstantHandler handler = compiler.constantHandler;
515 List<VariableElement> staticNonFinalFields =
516 handler.getStaticNonFinalFieldsForEmission();
517 if (!staticNonFinalFields.isEmpty()) buffer.add('\n');
518 for (Element element in staticNonFinalFields) {
519 buffer.add(' this.${namer.getName(element)} = ');
520 compiler.withCurrentElement(element, () {
521 handler.writeJsCodeForVariable(buffer, element);
522 });
523 buffer.add(';\n');
524 }
525 }
526
527 void emitCompileTimeConstants(StringBuffer buffer) {
528 ConstantHandler handler = compiler.constantHandler;
529 List<Constant> constants = handler.getConstantsForEmission();
530 String prototype = "${namer.ISOLATE}.prototype";
531 bool addedMakeConstantList = false;
532 for (Constant constant in constants) {
533 if (!addedMakeConstantList && constant.isList()) {
534 addedMakeConstantList = true;
535 emitMakeConstantList(prototype, buffer);
536 }
537 String name = handler.getNameForConstant(constant);
538 buffer.add('$prototype.$name = ');
539 handler.writeJsCode(buffer, constant);
540 buffer.add(';\n');
541 }
542 }
543
544 void emitMakeConstantList(String prototype, StringBuffer buffer) {
545 buffer.add(prototype);
546 buffer.add(@'''.makeConstantList = function(list) {
547 list.immutable$list = true;
548 list.fixed$length = true;
549 return list;
550 };
551 ''');
552 }
553
554 void emitStaticFinalFieldInitializations(StringBuffer buffer) {
555 ConstantHandler handler = compiler.constantHandler;
556 List<VariableElement> staticFinalFields =
557 handler.getStaticFinalFieldsForEmission();
558 for (VariableElement element in staticFinalFields) {
559 buffer.add('${namer.isolatePropertyAccess(element)} = ');
560 compiler.withCurrentElement(element, () {
561 handler.writeJsCodeForVariable(buffer, element);
562 });
563 buffer.add(';\n');
564 }
565 }
566
567 void emitExtraAccessors(Element member,
568 String attachTo(String name),
569 StringBuffer buffer) {
570 if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) {
571 Set<Selector> selectors = compiler.universe.invokedNames[member.name];
572 if (selectors !== null && !selectors.isEmpty()) {
573 compiler.emitter.emitCallStubForGetter(
574 buffer, attachTo, member, selectors);
575 }
576 } else if (member.kind == ElementKind.FUNCTION) {
577 if (compiler.universe.invokedGetters.contains(member.name)) {
578 compiler.emitter.emitDynamicFunctionGetter(
579 buffer, attachTo, member);
580 }
581 }
582 }
583
584 void emitNoSuchMethodCalls(StringBuffer buffer) {
585 // Do not generate no such method calls if there is no class.
586 if (compiler.universe.instantiatedClasses.isEmpty()) return;
587
588 ClassElement objectClass =
589 compiler.coreLibrary.find(const SourceString('Object'));
590 String className = namer.isolatePropertyAccess(objectClass);
591 String prototype = '$className.prototype';
592 String noSuchMethodName =
593 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2);
594 Collection<LibraryElement> libraries =
595 compiler.universe.libraries.getValues();
596
597 void generateMethod(String methodName, String jsName, Selector selector) {
598 buffer.add('$prototype.$jsName = function');
599 StringBuffer args = new StringBuffer();
600 for (int i = 0; i < selector.argumentCount; i++) {
601 if (i != 0) args.add(', ');
602 args.add('arg$i');
603 }
604 // We need to check if the object has a noSuchMethod. If not, it
605 // means the object is a native object, and we can just call our
606 // generic noSuchMethod. Note that when calling this method, the
607 // 'this' object is not a Dart object.
608 buffer.add(' ($args) {\n');
609 buffer.add(' return this.$noSuchMethodName\n');
610 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n");
611 buffer.add(" : $objectClassName.prototype.$noSuchMethodName.call(");
612 buffer.add("this, '$methodName', [$args])\n");
613 buffer.add('}\n');
614 }
615
616 compiler.universe.invokedNames.forEach((SourceString methodName,
617 Set<Selector> selectors) {
618 if (objectClass.lookupLocalMember(methodName) === null
619 && methodName != Namer.OPERATOR_EQUALS) {
620 for (Selector selector in selectors) {
621 if (methodName.isPrivate()) {
622 for (LibraryElement lib in libraries) {
623 String jsName =
624 namer.instanceMethodInvocationName(lib, methodName, selector);
625 generateMethod(methodName.slowToString(), jsName, selector);
626 }
627 } else {
628 String jsName =
629 namer.instanceMethodInvocationName(null, methodName, selector);
630 generateMethod(methodName.slowToString(), jsName, selector);
631 }
632 }
633 }
634 });
635
636 compiler.universe.invokedGetters.forEach((SourceString getterName) {
637 if (getterName.isPrivate()) {
638 for (LibraryElement lib in libraries) {
639 String jsName = namer.getterName(lib, getterName);
640 generateMethod('get ${getterName.slowToString()}', jsName,
641 Selector.GETTER);
642 }
643 } else {
644 String jsName = namer.getterName(null, getterName);
645 generateMethod('get ${getterName.slowToString()}', jsName,
646 Selector.GETTER);
647 }
648 });
649
650 compiler.universe.invokedSetters.forEach((SourceString setterName) {
651 if (setterName.isPrivate()) {
652 for (LibraryElement lib in libraries) {
653 String jsName = namer.setterName(lib, setterName);
654 generateMethod('set ${setterName.slowToString()}', jsName,
655 Selector.SETTER);
656 }
657 } else {
658 String jsName = namer.setterName(null, setterName);
659 generateMethod('set ${setterName.slowToString()}', jsName,
660 Selector.SETTER);
661 }
662 });
663 }
664
665 String buildIsolateSetup(Element appMain, Element isolateMain) {
666 String mainAccess = "${namer.isolateAccess(appMain)}";
667 String currentIsolate = "${namer.CURRENT_ISOLATE}";
668 String mainEnsureGetter = '';
669 // Since we pass the closurized version of the main method to
670 // the isolate method, we must make sure that it exists.
671 if (!compiler.universe.staticFunctionsNeedingGetter.contains(appMain)) {
672 String invocationName =
673 "${namer.closureInvocationName(Selector.INVOCATION_0)}";
674 mainEnsureGetter = "$mainAccess.$invocationName = $mainAccess";
675 }
676
677 // TODO(ngeoffray): These globals are currently required by the isolate
678 // library, but since leg already generates code on an Isolate object, they
679 // are not really needed. We should remove them once Leg replaces Frog.
680 return """
681 var \$globalThis = $currentIsolate;
682 var \$globalState;
683 var \$globals;
684 function \$static_init(){};
685
686 function \$initGlobals(context) {
687 context.isolateStatics = new ${namer.ISOLATE}();
688 }
689 function \$setGlobals(context) {
690 $currentIsolate = context.isolateStatics;
691 \$globalThis = $currentIsolate;
692 }
693 $mainEnsureGetter
694 ${namer.isolateAccess(isolateMain)}($mainAccess);""";
695 }
696
697 emitMain(StringBuffer buffer) {
698 if (compiler.isMockCompilation) return;
699 Element main = compiler.mainApp.find(Compiler.MAIN);
700 if (compiler.isolateLibrary != null) {
701 Element isolateMain =
702 compiler.isolateLibrary.find(Compiler.START_ROOT_ISOLATE);
703 buffer.add(buildIsolateSetup(main, isolateMain));
704 } else {
705 buffer.add('${namer.isolateAccess(main)}();\n');
706 }
707 }
708
709 String assembleProgram() {
710 measure(() {
711 mainBuffer.add('function ${namer.ISOLATE}() {');
712 emitStaticNonFinalFieldInitializations(mainBuffer);
713 mainBuffer.add('}\n\n');
714 emitClasses(mainBuffer);
715 emitStaticFunctions(mainBuffer);
716 emitStaticFunctionGetters(mainBuffer);
717 emitCompileTimeConstants(mainBuffer);
718 emitStaticFinalFieldInitializations(mainBuffer);
719 nativeEmitter.emitDynamicDispatchMetadata();
720 mainBuffer.add(
721 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n');
722 nativeEmitter.assembleCode(mainBuffer);
723 emitMain(mainBuffer);
724 compiler.assembledCode = mainBuffer.toString();
725 });
726 return compiler.assembledCode;
727 }
728 }
OLDNEW
« no previous file with comments | « frog/leg/elements/elements.dart ('k') | frog/leg/enqueue.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698