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

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

Issue 11304021: Add NativeEnqueuer to work with the Enqueuer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month 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) 2012, the Dart project authors. Please see the AUTHORS file 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 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 library native; 5 library native;
6 6
7 import 'dart:uri'; 7 import 'dart:uri';
8 import 'dart2jslib.dart' hide SourceString; 8 import 'dart2jslib.dart' hide SourceString;
9 import 'elements/elements.dart'; 9 import 'elements/elements.dart';
10 import 'js_backend/js_backend.dart'; 10 import 'js_backend/js_backend.dart';
11 import 'resolution/resolution.dart' show ResolverVisitor;
11 import 'scanner/scannerlib.dart'; 12 import 'scanner/scannerlib.dart';
12 import 'ssa/ssa.dart'; 13 import 'ssa/ssa.dart';
13 import 'tree/tree.dart'; 14 import 'tree/tree.dart';
14 import 'util/util.dart'; 15 import 'util/util.dart';
15 16
16 void processNativeClasses(Enqueuer world, 17
17 CodeEmitterTask emitter, 18 /// This class is a temporary work-around until we get a more powerful DartType.
18 Collection<LibraryElement> libraries) { 19 class SpecialType {
19 for (LibraryElement library in libraries) { 20 final String name;
20 processNativeClassesInLibrary(world, emitter, library); 21 const SpecialType._(this.name);
21 } 22
22 } 23 /// The type Object, but no subtypes:
23 24 static const JsObject = const SpecialType._('=Object');
24 void addSubtypes(ClassElement cls, 25
25 NativeEmitter emitter) { 26 /// The specific implementation of List that is JavaScript Array:
26 for (DartType type in cls.allSupertypes) { 27 static const JsArray = const SpecialType._('=List');
27 List<Element> subtypes = emitter.subtypes.putIfAbsent( 28 }
28 type.element, 29
30
31 /**
32 * This could be an abstract class but we use it as a stub for the dart_backend.
33 */
34 class NativeEnqueuer {
35 /// Initial entry point to native enqueuer.
36 void processNativeClasses(Collection<LibraryElement> libraries) {}
37
38 void registerElement(Element element) {}
39
40 /// Method is a member of a native class.
41 void registerMethod(Element method) {}
42
43 /// Compute types instantiated due to getting a native field.
44 void registerFieldLoad(Element field) {}
45
46 /// Compute types instantiated due to setting a native field.
47 void registerFieldStore(Element field) {}
48
49 /**
50 * Handles JS-calls, which can be an instantiation point for types.
51 *
52 * For example, the following code instantiates and returns native classes
53 * that are `_DOMWindowImpl` or a subtype.
54 *
55 * JS('_DOMWindowImpl', 'window')
56 *
57 */
58 // TODO(sra): The entry from codegen will not have a resolver.
59 void registerJsCall(Send node, ResolverVisitor resolver) {}
60
61 /// Emits a summary information using the [log] function.
62 void logSummary(log(message)) {}
63 }
64
65
66 class NativeEnqueuerBase implements NativeEnqueuer {
67
68 /**
69 * The set of all native classes. Each native class is in [nativeClasses] and
70 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses].
71 */
72 final Set<ClassElement> nativeClasses = new Set<ClassElement>();
73
74 final Set<ClassElement> registeredClasses = new Set<ClassElement>();
75 final Set<ClassElement> pendingClasses = new Set<ClassElement>();
76 final Set<ClassElement> unusedClasses = new Set<ClassElement>();
77
78 /**
79 * Records matched constraints ([SpecialType] or [DartType]). Once a type
80 * constraint has been matched, there is no need to match it again.
81 */
82 final Set matchedTypeConstraints = new Set();
83
84 /// Pending actions. Classes in [pendingClasses] have action thunks in
85 /// [queue] to register the class.
86 final queue = new Queue();
87 bool flushing = false;
88
89
90 final Enqueuer world;
91 final Compiler compiler;
92 final bool enableLiveTypeAnalysis;
93
94 ClassElement _annotationCreatesClass;
95 ClassElement _annotationReturnsClass;
96
97 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
98 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis);
99
100 void processNativeClasses(Collection<LibraryElement> libraries) {
101 libraries.forEach(processNativeClassesInLibrary);
102 if (!enableLiveTypeAnalysis) {
103 nativeClasses.forEach((c) => enqueueClass(c, 'forced'));
104 flushQueue();
105 }
106 }
107
108 void processNativeClassesInLibrary(LibraryElement library) {
109 // Use implementation to ensure the inclusion of injected members.
110 library.implementation.forEachLocalMember((Element element) {
111 if (element.kind == ElementKind.CLASS) {
112 ClassElement classElement = element;
113 if (classElement.isNative()) {
114 nativeClasses.add(classElement);
115 unusedClasses.add(classElement);
116
117 // Resolve class to ensure the class has valid inheritance info.
118 classElement.ensureResolved(compiler);
119 }
120 }
121 });
122 }
123
124 ClassElement get annotationCreatesClass {
125 if (_annotationCreatesClass == null) findAnnotationClasses();
126 return _annotationCreatesClass;
127 }
128
129 ClassElement get annotationReturnsClass {
130 if (_annotationReturnsClass == null) findAnnotationClasses();
131 return _annotationReturnsClass;
132 }
133
134 void findAnnotationClasses() {
135 ClassElement find(name) {
136 Element e = compiler.findHelper(name);
137 if (e == null || e is! ClassElement) {
138 compiler.cancel("Could not find implementation class '${name}'");
139 }
140 return e;
141 }
142 _annotationCreatesClass = find(const SourceString('Creates'));
143 _annotationReturnsClass = find(const SourceString('Returns'));
144 }
145
146
147 enqueueClass(ClassElement classElement, cause) {
148 assert(unusedClasses.contains(classElement));
149 unusedClasses.remove(classElement);
150 pendingClasses.add(classElement);
151 queue.add(() { processClass(classElement, cause); });
152 }
153
154 void flushQueue() {
155 if (flushing) return;
156 flushing = true;
157 while (!queue.isEmpty) {
158 (queue.removeFirst())();
159 }
160 flushing = false;
161 }
162
163 processClass(ClassElement classElement, cause) {
164 assert(!registeredClasses.contains(classElement));
165
166 bool firstTime = registeredClasses.isEmpty;
167 pendingClasses.remove(classElement);
168 registeredClasses.add(classElement);
169
170 world.registerInstantiatedClass(classElement);
171
172 // Also parse the node to know all its methods because otherwise it will
173 // only be parsed if there is a call to one of its constructors.
174 classElement.parseNode(compiler);
175
176 if (firstTime) {
177 queue.add(onFirstNativeClass);
178 }
179 }
180
181 registerElement(Element element) {
182 if (element.isFunction()) return registerMethod(element);
183 }
184
185 registerMethod(Element method) {
186 if (isNativeMethod(method)) {
187 processNativeBehavior(
188 NativeBehavior.ofMethod(method, compiler),
189 method);
190 flushQueue();
191 }
192 }
193
194 bool isNativeMethod(Element element) {
195 // Native method?
196 Node node = element.parseNode(compiler);
197 if (node is! FunctionExpression) return false;
198 node = node.body;
199 Token token = node.getBeginToken();
200 if (token.stringValue == 'native') return true;
201 return false;
202 }
203
204 void registerFieldLoad(Element field) {
205 processNativeBehavior(
206 NativeBehavior.ofFieldLoad(field, compiler),
207 field);
208 flushQueue();
209 }
210
211 void registerFieldStore(Element field) {
212 processNativeBehavior(
213 NativeBehavior.ofFieldStore(field, compiler),
214 field);
215 flushQueue();
216 }
217
218 void registerJsCall(Send node, ResolverVisitor resolver) {
219 processNativeBehavior(
220 NativeBehavior.ofJsCall(node, compiler, resolver),
221 node);
222 flushQueue();
223 }
224
225 processNativeBehavior(NativeBehavior behavior, cause) {
226 bool allUsedBefore = unusedClasses.isEmpty;
227 for (var type in behavior.typesInstantiated) {
ahe 2012/12/04 09:15:19 When I see code like this, I assume this is equiva
228 if (matchedTypeConstraints.contains(type)) continue;
229 matchedTypeConstraints.add(type);
230 if (type is SpecialType) {
231 // The two special types (=Object, =List) are always instantiated.
232 continue;
233 }
234 assert(type is DartType);
ahe 2012/12/04 09:15:19 There is a more natural way to express this in Dar
235 enqueueUnusedClassesMatching(
236 (nativeClass) => compiler.types.isSubtype(nativeClass.type, type),
237 cause,
238 'subtypeof($type)');
239 }
240
241 // Give an info so that library developers can compile with -v to find why
242 // all the native classes are included.
243 if (unusedClasses.isEmpty && !allUsedBefore) {
244 compiler.log('All native types marked as used due to $cause.');
245 }
246 }
247
248 enqueueUnusedClassesMatching(bool predicate(classElement),
249 cause,
250 [String reason]) {
251 Collection matches = unusedClasses.filter(predicate);
252 matches.forEach((c) => enqueueClass(c, cause));
253 }
254
255 onFirstNativeClass() {
256 staticUse(name) => world.registerStaticUse(compiler.findHelper(name));
257
258 staticUse(const SourceString('dynamicFunction'));
259 staticUse(const SourceString('dynamicSetMetadata'));
260 staticUse(const SourceString('defineProperty'));
261 staticUse(const SourceString('toStringForNativeObject'));
262 staticUse(const SourceString('hashCodeForNativeObject'));
263
264 addNativeExceptions();
265 }
266
267 addNativeExceptions() {
268 enqueueUnusedClassesMatching((classElement) {
269 // TODO(sra): Annotate exception classes in dart:html.
270 String name = classElement.name.slowToString();
271 if (name.contains('Exception')) return true;
272 if (name.contains('Error')) return true;
273 return false;
274 },
275 'native exception');
276 }
277 }
278
279
280 class NativeResolutionEnqueuer extends NativeEnqueuerBase {
281
282 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler)
283 : super(world, compiler, compiler.enableNativeLiveTypeAnalysis);
284
285 void logSummary(log(message)) {
286 log('Resolved ${registeredClasses.length} native elements used, '
287 '${unusedClasses.length} native elements dead.');
288 }
289 }
290
291
292 class NativeCodegenEnqueuer extends NativeEnqueuerBase {
293
294 final CodeEmitterTask emitter;
295
296 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter)
297 : super(world, compiler, compiler.enableNativeLiveTypeAnalysis);
298
299 void processNativeClasses(Collection<LibraryElement> libraries) {
300 super.processNativeClasses(libraries);
301
302 // HACK HACK - add all the resolved classes.
303 for (final classElement
304 in compiler.enqueuer.resolution.nativeEnqueuer.registeredClasses) {
305 if (unusedClasses.contains(classElement)) {
306 enqueueClass(classElement, 'was resolved');
307 }
308 }
309 flushQueue();
310 }
311
312 processClass(ClassElement classElement, cause) {
313 super.processClass(classElement, cause);
314 // Add the information that this class is a subtype of its supertypes. The
315 // code emitter and the ssa builder use that information.
316 addSubtypes(classElement, emitter.nativeEmitter);
317 }
318
319 void addSubtypes(ClassElement cls, NativeEmitter emitter) {
320 for (DartType type in cls.allSupertypes) {
321 List<Element> subtypes = emitter.subtypes.putIfAbsent(
322 type.element,
323 () => <ClassElement>[]);
324 subtypes.add(cls);
325 }
326
327 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent(
328 cls.superclass,
29 () => <ClassElement>[]); 329 () => <ClassElement>[]);
30 subtypes.add(cls); 330 directSubtypes.add(cls);
31 } 331 }
32 332
33 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( 333 void logSummary(log(message)) {
34 cls.superclass, 334 log('Compiled ${registeredClasses.length} native classes, '
35 () => <ClassElement>[]); 335 '${unusedClasses.length} native classes omitted.');
36 directSubtypes.add(cls); 336 }
37 } 337 }
38 338
39 void processNativeClassesInLibrary(Enqueuer world,
40 CodeEmitterTask emitter,
41 LibraryElement library) {
42 bool hasNativeClass = false;
43 final compiler = emitter.compiler;
44 // Use implementation to ensure the inclusion of injected members.
45 library.implementation.forEachLocalMember((Element element) {
46 if (element.kind == ElementKind.CLASS) {
47 ClassElement classElement = element;
48 if (classElement.isNative()) {
49 hasNativeClass = true;
50 world.registerInstantiatedClass(classElement);
51 // Also parse the node to know all its methods because
52 // otherwise it will only be parsed if there is a call to
53 // one of its constructor.
54 classElement.parseNode(compiler);
55 // Resolve to setup the inheritance.
56 classElement.ensureResolved(compiler);
57 // Add the information that this class is a subtype of
58 // its supertypes. The code emitter and the ssa builder use that
59 // information.
60 addSubtypes(classElement, emitter.nativeEmitter);
61 }
62 }
63 });
64 if (hasNativeClass) {
65 world.registerStaticUse(compiler.findHelper(
66 const SourceString('dynamicFunction')));
67 world.registerStaticUse(compiler.findHelper(
68 const SourceString('dynamicSetMetadata')));
69 world.registerStaticUse(compiler.findHelper(
70 const SourceString('defineProperty')));
71 world.registerStaticUse(compiler.findHelper(
72 const SourceString('toStringForNativeObject')));
73 world.registerStaticUse(compiler.findHelper(
74 const SourceString('hashCodeForNativeObject')));
75 }
76 }
77
78 void maybeEnableNative(Compiler compiler, 339 void maybeEnableNative(Compiler compiler,
79 LibraryElement library, 340 LibraryElement library,
80 Uri uri) { 341 Uri uri) {
81 String libraryName = uri.toString(); 342 String libraryName = uri.toString();
82 if (library.entryCompilationUnit.script.name.contains( 343 if (library.entryCompilationUnit.script.name.contains(
83 'dart/tests/compiler/dart2js_native') 344 'dart/tests/compiler/dart2js_native')
84 || libraryName == 'dart:isolate' 345 || libraryName == 'dart:isolate'
85 || libraryName == 'dart:html' 346 || libraryName == 'dart:html'
86 || libraryName == 'dart:svg') { 347 || libraryName == 'dart:svg') {
87 library.canUseNative = true; 348 library.canUseNative = true;
88 } 349 }
89 } 350 }
90 351
352 /**
353 * A summary of the behavior of a native element.
354 *
355 * Native code can return values of one type and cause native subtypes of
356 * another type to be instantiated. By default, we compute both from the
357 * declared type.
358 *
359 * A field might yield any native type that 'is' the field type.
360 *
361 * A method might create and return instances of native subclasses of its
362 * declared return type, and a callback argument may be called with instances of
363 * the callback parameter type (e.g. Event).
364 *
365 * If there is one or more @Creates annotations, the union of the named types
366 * replaces the inferred instantiated type, and the return type is ignored for
367 * the purpose of inferring instantiated types.
368 *
369 * @Creates(IDBCursor) // Created asynchronously.
370 * @Creates(IDBRequest) // Created synchronously (for return value).
371 * IDBRequest request = objectStore.openCursor();
372 *
373 * If there is one or more @Returns annotations, the union of the named types
374 * replaces the declared return type.
375 *
376 * @Returns(IDBRequest)
377 * IDBRequest request = objectStore.openCursor();
378 */
379 class NativeBehavior {
380
381 /// [DartType]s or [SpecialType]s returned or yielded by the native element.
382 final Collection typesReturned = [];
383
384 /// [DartType]s or [SpecialType]s instantiated by the native element.
385 final Collection typesInstantiated = [];
386
387 static final NativeBehavior NONE = new NativeBehavior();
388
389 //NativeBehavior();
390
391 static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
392 // The first argument of a JS-call is a string encoding various attributes
393 // of the code.
394 //
395 // 'Type1|Type2'. A union type.
396 // '=Object'. A JavaScript Object, no subtype.
397 // '=List'. A JavaScript Array, no subtype.
398
399 var argNodes = jsCall.arguments;
400 if (argNodes.isEmpty) {
401 compiler.cancel("JS expression has no type", node: jsCall);
402 }
403
404 var firstArg = argNodes.head;
405 LiteralString specLiteral = firstArg.asLiteralString();
406 if (specLiteral != null) {
407 String specString = specLiteral.dartString.slowToString();
408 // Various things that are not in fact types.
409 if (specString == 'void') return NativeBehavior.NONE;
410 if (specString == '' || specString == 'var') {
411 var behavior = new NativeBehavior();
412 behavior.typesReturned.add(compiler.objectClass.computeType(compiler));
413 return behavior;
414 }
415 var behavior = new NativeBehavior();
416 for (final typeString in specString.split('|')) {
417 var type = _parseType(typeString, compiler,
418 (name) => resolver.resolveTypeFromString(name),
419 jsCall);
420 behavior.typesInstantiated.add(type);
421 behavior.typesReturned.add(type);
422 }
423 return behavior;
424 }
425
426 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
427 // is not very satisfactory because it does not work for void, dynamic.
428
429 compiler.cancel("Unexpected JS first argument", node: firstArg);
430 }
431
432 static NativeBehavior ofMethod(Element method, Compiler compiler) {
433 DartType type = method.computeType(compiler);
434 var behavior = new NativeBehavior();
435 behavior.typesReturned.add(type.returnType);
436 behavior._capture(type, compiler);
437
438 // TODO(sra): Optional arguments are currently missing from the
439 // DartType. This should be fixed so the following work-around can be
440 // removed.
441 method.computeSignature(compiler).forEachOptionalParameter(
442 (Element parameter) {
443 behavior._escape(parameter.computeType(compiler), compiler);
444 });
445
446 behavior._overrideWithAnnotations(method, compiler);
447 return behavior;
448 }
449
450 static NativeBehavior ofFieldLoad(Element field, Compiler compiler) {
451 DartType type = field.computeType(compiler);
452 var behavior = new NativeBehavior();
453 behavior.typesReturned.add(type);
454 behavior._capture(type, compiler);
455 behavior._overrideWithAnnotations(field, compiler);
456 return behavior;
457 }
458
459 static NativeBehavior ofFieldStore(Element field, Compiler compiler) {
460 DartType type = field.computeType(compiler);
461 var behavior = new NativeBehavior();
462 behavior._escape(type, compiler);
463 // We don't override the default behaviour - the annotations apply to
464 // loading the field.
465 return behavior;
466 }
467
468 void _overrideWithAnnotations(Element element, Compiler compiler) {
469 if (element.metadata.isEmpty) return;
470
471 DartType lookup(String name) {
472 Element e = element.buildScope().lookup(new SourceString(name));
473 if (e == null) return null;
474 if (e is! ClassElement) return null;
475 e.ensureResolved(compiler);
476 return e.computeType(compiler);
477 }
478
479 var creates =
480 _collect(element, compiler,
481 compiler.enqueuer.resolution.nativeEnqueuer.annotationCreatesClass,
482 lookup);
483 var returns =
484 _collect(element, compiler,
485 compiler.enqueuer.resolution.nativeEnqueuer.annotationReturnsClass,
486 lookup);
487
488 if (creates != null) {
489 typesInstantiated..clear()..addAll(creates);
490 }
491 if (returns != null) {
492 typesReturned..clear()..addAll(returns);
493 }
494 }
495
496 /**
497 * Returns a list of type constraints from the annotations of
498 * [annotationClass].
499 * Returns `null` if no constraints.
500 */
501 static _collect(Element element, Compiler compiler, Element annotationClass,
502 lookup(str)) {
503 var types = null;
504 for (Link<MetadataAnnotation> link = element.metadata;
505 !link.isEmpty;
506 link = link.tail) {
507 MetadataAnnotation annotation = link.head.ensureResolved(compiler);
508 var value = annotation.value;
509 if (value is! ConstructedConstant) continue;
510 if (value.type is! InterfaceType) continue;
511 if (!identical(value.type.element, annotationClass)) continue;
512
513 var fields = value.fields;
514 // TODO(sra): Better validation of the constant.
515 if (fields.length != 1 || fields[0] is! StringConstant) {
516 compiler.cancel(
517 'Annotations needs one string: ${annotation.parseNode(compiler)}');
518 }
519 String specString = fields[0].toDartString().slowToString();
520 for (final typeString in specString.split('|')) {
521 var type = _parseType(typeString, compiler, lookup, annotation);
522 if (types == null) types = [];
523 types.add(type);
524 }
525 }
526 return types;
527 }
528
529 /// Models the behavior of having intances of [type] escape from Dart code
530 /// into native code.
531 void _escape(DartType type, Compiler compiler) {
532 type = type.unalias(compiler);
533 if (type is FunctionType) {
534 // A function might be called from native code, passing us novel
535 // parameters.
536 _escape(type.returnType, compiler);
537 for (Link<DartType> parameters = type.parameterTypes;
538 !parameters.isEmpty;
539 parameters = parameters.tail) {
540 _capture(parameters.head, compiler);
541 }
542 }
543 }
544
545 /// Models the behavior of Dart code receiving instances and methods of [type]
546 /// from native code. We usually start the analysis by capturing a native
547 /// method that has been used.
548 void _capture(DartType type, Compiler compiler) {
549 type = type.unalias(compiler);
550 if (type is FunctionType) {
551 _capture(type.returnType, compiler);
552 for (Link<DartType> parameters = type.parameterTypes;
553 !parameters.isEmpty;
554 parameters = parameters.tail) {
555 _escape(parameters.head, compiler);
556 }
557 } else {
558 typesInstantiated.add(type);
559 }
560 }
561
562 static _parseType(String typeString, Compiler compiler,
563 lookup(name), locationNodeOrElement) {
564 if (typeString == '=Object') return SpecialType.JsObject;
565 if (typeString == '=List') return SpecialType.JsArray;
566 if (typeString == 'dynamic') {
567 return compiler.dynamicClass.computeType(compiler);
568 }
569 DartType type = lookup(typeString);
570 if (type != null) return type;
571
572 int index = typeString.indexOf('<');
573 if (index < 1) {
574 compiler.cancel("Type '$typeString' not found",
575 node: _errorNode(locationNodeOrElement, compiler));
576 }
577 type = lookup(typeString.substring(0, index));
578 if (type != null) {
579 // TODO(sra): Parse type parameters.
580 return type;
581 }
582 compiler.cancel("Type '$typeString' not found",
583 node: _errorNode(locationNodeOrElement, compiler));
584 }
585
586 static _errorNode(locationNodeOrElement, compiler) {
587 if (locationNodeOrElement is Node) return locationNodeOrElement;
588 return locationNodeOrElement.parseNode(compiler);
589 }
590 }
591
91 void checkAllowedLibrary(ElementListener listener, Token token) { 592 void checkAllowedLibrary(ElementListener listener, Token token) {
92 LibraryElement currentLibrary = listener.compilationUnitElement.getLibrary(); 593 LibraryElement currentLibrary = listener.compilationUnitElement.getLibrary();
93 if (!currentLibrary.canUseNative) { 594 if (!currentLibrary.canUseNative) {
94 listener.recoverableError("Unexpected token", token: token); 595 listener.recoverableError("Unexpected token", token: token);
95 } 596 }
96 } 597 }
97 598
98 Token handleNativeBlockToSkip(Listener listener, Token token) { 599 Token handleNativeBlockToSkip(Listener listener, Token token) {
99 checkAllowedLibrary(listener, token); 600 checkAllowedLibrary(listener, token);
100 token = token.next; 601 token = token.next;
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 String parameters) { 834 String parameters) {
334 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty"); 835 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty");
335 buffer.add("('$methodName')) {\n"); 836 buffer.add("('$methodName')) {\n");
336 buffer.add(" $code"); 837 buffer.add(" $code");
337 buffer.add(" } else {\n"); 838 buffer.add(" } else {\n");
338 buffer.add(" return Object.prototype.$methodName.call(this"); 839 buffer.add(" return Object.prototype.$methodName.call(this");
339 buffer.add(parameters == '' ? '' : ', $parameters'); 840 buffer.add(parameters == '' ? '' : ', $parameters');
340 buffer.add(");\n"); 841 buffer.add(");\n");
341 buffer.add(" }\n"); 842 buffer.add(" }\n");
342 } 843 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698