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(DefineStubFunction defineStub) { | 21 void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) { |
22 // Do not generate no such method handlers if there is no class. | 22 // Do not generate no such method handlers if there is no class. |
23 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; | 23 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; |
24 | 24 |
25 String noSuchMethodName = namer.publicInstanceMethodNameByArity( | 25 String noSuchMethodName = namer.publicInstanceMethodNameByArity( |
26 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); | 26 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); |
27 | 27 |
28 // Keep track of the JavaScript names we've already added so we | 28 // Keep track of the JavaScript names we've already added so we |
29 // do not introduce duplicates (bad for code size). | 29 // do not introduce duplicates (bad for code size). |
30 Map<String, Selector> addedJsNames = new Map<String, Selector>(); | 30 Map<String, Selector> addedJsNames = new Map<String, Selector>(); |
31 | 31 |
(...skipping 16 matching lines...) Expand all Loading... |
48 task.mangledFieldNames[jsName] = reflectionName; | 48 task.mangledFieldNames[jsName] = reflectionName; |
49 } | 49 } |
50 } | 50 } |
51 } | 51 } |
52 | 52 |
53 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); | 53 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); |
54 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); | 54 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); |
55 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); | 55 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); |
56 | 56 |
57 // Set flag used by generateMethod helper below. If we have very few | 57 // Set flag used by generateMethod helper below. If we have very few |
58 // handlers we use defineStub for them all, rather than try to generate them | 58 // handlers we use addProperty for them all, rather than try to generate |
59 // at runtime. | 59 // them at runtime. |
60 bool haveVeryFewNoSuchMemberHandlers = | 60 bool haveVeryFewNoSuchMemberHandlers = |
61 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS); | 61 (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS); |
62 | 62 |
63 jsAst.Expression generateMethod(String jsName, Selector selector) { | 63 jsAst.Expression generateMethod(String jsName, Selector selector) { |
64 // Values match JSInvocationMirror in js-helper library. | 64 // Values match JSInvocationMirror in js-helper library. |
65 int type = selector.invocationMirrorKind; | 65 int type = selector.invocationMirrorKind; |
66 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; | 66 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; |
67 CodeBuffer args = new CodeBuffer(); | 67 CodeBuffer args = new CodeBuffer(); |
68 for (int i = 0; i < selector.argumentCount; i++) { | 68 for (int i = 0; i < selector.argumentCount; i++) { |
69 parameters.add(new jsAst.Parameter('\$$i')); | 69 parameters.add(new jsAst.Parameter('\$$i')); |
(...skipping 27 matching lines...) Expand all Loading... |
97 parameters = backend.isInterceptedName(selector.name) | 97 parameters = backend.isInterceptedName(selector.name) |
98 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters)) | 98 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters)) |
99 : parameters; | 99 : parameters; |
100 return js.fun(parameters, js.return_(expression)); | 100 return js.fun(parameters, js.return_(expression)); |
101 } | 101 } |
102 | 102 |
103 for (String jsName in addedJsNames.keys.toList()..sort()) { | 103 for (String jsName in addedJsNames.keys.toList()..sort()) { |
104 Selector selector = addedJsNames[jsName]; | 104 Selector selector = addedJsNames[jsName]; |
105 jsAst.Expression method = generateMethod(jsName, selector); | 105 jsAst.Expression method = generateMethod(jsName, selector); |
106 if (method != null) { | 106 if (method != null) { |
107 defineStub(jsName, method); | 107 addProperty(jsName, method); |
108 String reflectionName = task.getReflectionName(selector, jsName); | 108 String reflectionName = task.getReflectionName(selector, jsName); |
109 if (reflectionName != null) { | 109 if (reflectionName != null) { |
110 bool accessible = compiler.world.allFunctions.filter(selector).any( | 110 bool accessible = compiler.world.allFunctions.filter(selector).any( |
111 (Element e) => backend.isAccessibleByReflection(e)); | 111 (Element e) => backend.isAccessibleByReflection(e)); |
112 defineStub('+$reflectionName', js(accessible ? '1' : '0')); | 112 addProperty('+$reflectionName', js(accessible ? '1' : '0')); |
113 } | 113 } |
114 } | 114 } |
115 } | 115 } |
116 } | 116 } |
117 | 117 |
118 // Identify the noSuchMethod handlers that are so simple that we can | 118 // Identify the noSuchMethod handlers that are so simple that we can |
119 // generate them programatically. | 119 // generate them programatically. |
120 bool isTrivialNsmHandler( | 120 bool isTrivialNsmHandler( |
121 int type, List argNames, Selector selector, String internalName) { | 121 int type, List argNames, Selector selector, String internalName) { |
122 if (!generateTrivialNsmHandlers) return false; | 122 if (!generateTrivialNsmHandlers) return false; |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 [js.return_(js( | 356 [js.return_(js( |
357 'this.$noSuchMethodName(' | 357 'this.$noSuchMethodName(' |
358 'this, ' | 358 'this, ' |
359 '$createInvocationMirror(' | 359 '$createInvocationMirror(' |
360 'name, short, type, ' | 360 'name, short, type, ' |
361 '$slice(arguments$sliceOffsetParam), []))'))]))])) | 361 '$slice(arguments$sliceOffsetParam), []))'))]))])) |
362 ]) | 362 ]) |
363 ]); | 363 ]); |
364 } | 364 } |
365 } | 365 } |
OLD | NEW |