Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 class NsmEmitter extends CodeEmitterHelper { | 7 class NsmEmitter extends CodeEmitterHelper { |
| 8 final List<Selector> trivialNsmHandlers = <Selector>[]; | 8 final List<Selector> trivialNsmHandlers = <Selector>[]; |
| 9 | 9 |
| 10 /// If this is true then we can generate the noSuchMethod handlers at startup | 10 /// If this is true then we can generate the noSuchMethod handlers at startup |
| 11 /// time, instead of them being emitted as part of the Object class. | 11 /// time, instead of them being emitted as part of the Object class. |
| 12 bool get generateTrivialNsmHandlers => true; | 12 bool get generateTrivialNsmHandlers => true; |
| 13 | 13 |
| 14 // If we need fewer than this many noSuchMethod handlers we can save space by | 14 // If we need fewer than this many noSuchMethod handlers we can save space by |
| 15 // just emitting them in JS, rather than emitting the JS needed to generate | 15 // just emitting them in JS, rather than emitting the JS needed to generate |
| 16 // them at run time. | 16 // them at run time. |
| 17 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; | 17 static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10; |
| 18 | 18 |
| 19 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; | 19 static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4; |
| 20 | 20 |
| 21 void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) { | 21 void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) { |
| 22 | 22 |
| 23 void computeSelectorsForNsmHandlers(Map<String, Selector> jsNames) { | 23 ClassStubGenerator generator = |
| 24 | 24 new ClassStubGenerator(compiler, namer, backend); |
| 25 // Do not generate no such method handlers if there is no class. | |
| 26 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) return; | |
| 27 | |
| 28 void addNoSuchMethodHandlers(String ignore, Set<Selector> selectors) { | |
| 29 // Cache the object class and type. | |
| 30 ClassElement objectClass = compiler.objectClass; | |
| 31 DartType objectType = objectClass.rawType; | |
| 32 | |
| 33 for (Selector selector in selectors) { | |
| 34 TypeMask mask = selector.mask; | |
| 35 if (mask == null) { | |
| 36 mask = new TypeMask.subclass(compiler.objectClass, | |
| 37 compiler.world); | |
| 38 } | |
| 39 | |
| 40 if (!mask.needsNoSuchMethodHandling(selector, compiler.world)) { | |
| 41 continue; | |
| 42 } | |
| 43 String jsName = namer.invocationMirrorInternalName(selector); | |
| 44 jsNames[jsName] = selector; | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); | |
| 49 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); | |
| 50 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); | |
| 51 } | |
| 52 | |
| 53 jsAst.Expression generateMethod(Selector selector) { | |
| 54 // Values match JSInvocationMirror in js-helper library. | |
| 55 int type = selector.invocationMirrorKind; | |
| 56 List<String> parameterNames = | |
| 57 new List.generate(selector.argumentCount, (i) => '\$$i'); | |
| 58 | |
| 59 List<jsAst.Expression> argNames = | |
| 60 selector.getOrderedNamedArguments().map((String name) => | |
| 61 js.string(name)).toList(); | |
| 62 | |
| 63 String methodName = selector.invocationMirrorMemberName; | |
| 64 String internalName = namer.invocationMirrorInternalName(selector); | |
| 65 | |
| 66 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD)); | |
| 67 jsAst.Expression expression = | |
| 68 js('''this.#noSuchMethodName(this, | |
| 69 #createInvocationMirror(#methodName, | |
| 70 #internalName, | |
| 71 #type, | |
| 72 #arguments, | |
| 73 #namedArguments))''', | |
| 74 {'noSuchMethodName': namer.noSuchMethodName, | |
| 75 'createInvocationMirror': | |
| 76 backend.emitter.staticFunctionAccess( | |
| 77 backend.getCreateInvocationMirror()), | |
| 78 'methodName': | |
| 79 js.string(compiler.enableMinification | |
| 80 ? internalName : methodName), | |
| 81 'internalName': js.string(internalName), | |
| 82 'type': js.number(type), | |
| 83 'arguments': | |
| 84 new jsAst.ArrayInitializer(parameterNames.map(js).toList()), | |
| 85 'namedArguments': new jsAst.ArrayInitializer(argNames)}); | |
| 86 | |
| 87 if (backend.isInterceptedName(selector.name)) { | |
| 88 return js(r'function($receiver, #) { return # }', | |
| 89 [parameterNames, expression]); | |
| 90 } else { | |
| 91 return js(r'function(#) { return # }', [parameterNames, expression]); | |
| 92 } | |
| 93 } | |
| 94 | 25 |
| 95 // Keep track of the JavaScript names we've already added so we | 26 // Keep track of the JavaScript names we've already added so we |
| 96 // do not introduce duplicates (bad for code size). | 27 // do not introduce duplicates (bad for code size). |
| 97 Map<String, Selector> addedJsNames = new Map<String, Selector>(); | 28 Map<String, Selector> addedJsNames = new Map<String, Selector>(); |
| 98 computeSelectorsForNsmHandlers(addedJsNames); | 29 generator.computeSelectorsForNsmHandlers(addedJsNames); |
|
floitsch
2015/02/03 10:48:51
In the next CL return the map from the generator (
zarah
2015/02/03 11:55:18
Done.
| |
| 99 | 30 |
| 100 // Set flag used by generateMethod helper below. If we have very few | 31 // Set flag used by generateMethod helper below. If we have very few |
| 101 // handlers we use addProperty for them all, rather than try to generate | 32 // handlers we use addProperty for them all, rather than try to generate |
| 102 // them at runtime. | 33 // them at runtime. |
| 103 bool haveVeryFewNoSuchMemberHandlers = | 34 bool haveVeryFewNoSuchMemberHandlers = |
| 104 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS); | 35 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS); |
| 105 for (String jsName in addedJsNames.keys.toList()..sort()) { | 36 for (String jsName in addedJsNames.keys.toList()..sort()) { |
| 106 Selector selector = addedJsNames[jsName]; | 37 Selector selector = addedJsNames[jsName]; |
| 107 String reflectionName = emitter.getReflectionName(selector, jsName); | 38 String reflectionName = emitter.getReflectionName(selector, jsName); |
| 108 | 39 |
| 109 if (reflectionName != null) { | 40 if (reflectionName != null) { |
| 110 emitter.mangledFieldNames[jsName] = reflectionName; | 41 emitter.mangledFieldNames[jsName] = reflectionName; |
| 111 } | 42 } |
| 112 | 43 |
| 113 List<jsAst.Expression> argNames = | 44 List<jsAst.Expression> argNames = |
| 114 selector.getOrderedNamedArguments().map((String name) => | 45 selector.getOrderedNamedArguments().map((String name) => |
| 115 js.string(name)).toList(); | 46 js.string(name)).toList(); |
| 116 int type = selector.invocationMirrorKind; | 47 int type = selector.invocationMirrorKind; |
| 117 if (!haveVeryFewNoSuchMemberHandlers && | 48 if (!haveVeryFewNoSuchMemberHandlers && |
| 118 isTrivialNsmHandler(type, argNames, selector, jsName) && | 49 isTrivialNsmHandler(type, argNames, selector, jsName) && |
| 119 reflectionName == null) { | 50 reflectionName == null) { |
| 120 trivialNsmHandlers.add(selector); | 51 trivialNsmHandlers.add(selector); |
| 121 } | 52 } |
| 122 | 53 |
| 123 jsAst.Expression method = generateMethod(jsName, selector); | 54 jsAst.Expression method = generator.generateStubForNoSuchMethod(selector); |
| 124 if (method != null) { | 55 if (method != null) { |
| 125 addProperty(jsName, method); | 56 addProperty(jsName, method); |
| 126 if (reflectionName != null) { | 57 if (reflectionName != null) { |
| 127 bool accessible = compiler.world.allFunctions.filter(selector).any( | 58 bool accessible = compiler.world.allFunctions.filter(selector).any( |
| 128 (Element e) => backend.isAccessibleByReflection(e)); | 59 (Element e) => backend.isAccessibleByReflection(e)); |
| 129 addProperty('+$reflectionName', js(accessible ? '2' : '0')); | 60 addProperty('+$reflectionName', js(accessible ? '2' : '0')); |
| 130 } | 61 } |
| 131 } | 62 } |
| 132 } | 63 } |
| 133 } | 64 } |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 }''', { | 325 }''', { |
| 395 'sliceOffsetParams': sliceOffsetParams, | 326 'sliceOffsetParams': sliceOffsetParams, |
| 396 'noSuchMethodName': noSuchMethodName, | 327 'noSuchMethodName': noSuchMethodName, |
| 397 'createInvocationMirror': createInvocationMirror, | 328 'createInvocationMirror': createInvocationMirror, |
| 398 'names': minify ? 'shortNames' : 'longNames', | 329 'names': minify ? 'shortNames' : 'longNames', |
| 399 'sliceOffsetArguments': sliceOffsetArguments})); | 330 'sliceOffsetArguments': sliceOffsetArguments})); |
| 400 | 331 |
| 401 return statements; | 332 return statements; |
| 402 } | 333 } |
| 403 } | 334 } |
| OLD | NEW |