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

Side by Side Diff: frog/value.dart

Issue 8334035: Reduces code generated by dynamic calls. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 9 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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** 5 /**
6 * Represents a meta-value for code generation. 6 * Represents a meta-value for code generation.
7 */ 7 */
8 class Value { 8 class Value {
9 /** The [Type] of the [Value]. */ 9 /** The [Type] of the [Value]. */
10 Type type; 10 Type type;
(...skipping 27 matching lines...) Expand all
38 } 38 }
39 // member.get_ returns null if no signatures match the given node. 39 // member.get_ returns null if no signatures match the given node.
40 if (member != null) { 40 if (member != null) {
41 return member; 41 return member;
42 } else { 42 } else {
43 return invokeNoSuchMethod(context, 'get:$name', node); 43 return invokeNoSuchMethod(context, 'get:$name', node);
44 } 44 }
45 } 45 }
46 46
47 set_(MethodGenerator context, String name, Node node, Value value, 47 set_(MethodGenerator context, String name, Node node, Value value,
48 [bool checked=true]) { 48 [bool isDynamic=false]) {
49 var member = _resolveMember(context, name, node); 49 var member = _resolveMember(context, name, node);
50 if (member != null) { 50 if (member != null) {
51 member = member.set_(context, node, this, value, checked); 51 member = member.set_(context, node, this, value, isDynamic);
52 } 52 }
53 // member.set_ returns null if no signatures match the given node. 53 // member.set_ returns null if no signatures match the given node.
54 if (member != null) { 54 if (member != null) {
55 return member; 55 return member;
56 } else { 56 } else {
57 return invokeNoSuchMethod(context, 'set:$name', node, 57 return invokeNoSuchMethod(context, 'set:$name', node,
58 new Arguments(null, [value])); 58 new Arguments(null, [value]));
59 } 59 }
60 } 60 }
61 61
62 invoke(MethodGenerator context, String name, Node node, Arguments args, 62 invoke(MethodGenerator context, String name, Node node, Arguments args,
63 [bool checked=true]) { 63 [bool isDynamic=false]) {
64 // TODO(jimhug): The != method is weird - understand it better. 64 // TODO(jimhug): The != method is weird - understand it better.
65 if (type.isVar && name == '\$ne') { 65 if (type.isVar && name == '\$ne') {
66 if (args.values.length != 1) { 66 if (args.values.length != 1) {
67 world.warning('wrong number of arguments for !=', node.span); 67 world.warning('wrong number of arguments for !=', node.span);
68 } 68 }
69 return new Value(null, '\$ne($code, ${args.values[0].code})'); 69 return new Value(null, '\$ne($code, ${args.values[0].code})');
70 } 70 }
71 71
72 // TODO(jmesserly): it'd be nice to remove these special cases 72 // TODO(jmesserly): it'd be nice to remove these special cases
73 // We could create a $call (and $ne) in world members, and have 73 // We could create a $call (and $ne) in world members, and have
(...skipping 10 matching lines...) Expand all
84 } 84 }
85 if (type.needsVarCall(args)) { 85 if (type.needsVarCall(args)) {
86 return _varCall(context, args); 86 return _varCall(context, args);
87 } 87 }
88 } 88 }
89 89
90 var member = _resolveMember(context, name, node); 90 var member = _resolveMember(context, name, node);
91 if (member == null) { 91 if (member == null) {
92 return invokeNoSuchMethod(context, name, node, args); 92 return invokeNoSuchMethod(context, name, node, args);
93 } else { 93 } else {
94 return member.invoke(context, node, this, args, checked); 94 return member.invoke(context, node, this, args, isDynamic);
95 } 95 }
96 } 96 }
97 97
98 bool canInvoke(MethodGenerator context, String name, Arguments args) { 98 bool canInvoke(MethodGenerator context, String name, Arguments args) {
99 // TODO(jimhug): The != method is weird - understand it better. 99 // TODO(jimhug): The != method is weird - understand it better.
100 if (type.isVar && name == '\$ne') { 100 if (type.isVar && name == '\$ne') {
101 return true; 101 return true;
102 } 102 }
103 103
104 if (type.isVarOrFunction && name == '\$call') { 104 if (type.isVarOrFunction && name == '\$call') {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 } 156 }
157 157
158 /** Generate a call to an unknown function type. */ 158 /** Generate a call to an unknown function type. */
159 Value _varCall(MethodGenerator context, Arguments args) { 159 Value _varCall(MethodGenerator context, Arguments args) {
160 var stub = world.functionType.getCallStub(args); 160 var stub = world.functionType.getCallStub(args);
161 return new Value(null, '$code.${stub.name}(${args.getCode()})'); 161 return new Value(null, '$code.${stub.name}(${args.getCode()})');
162 } 162 }
163 163
164 /** 164 /**
165 * Assign or convert this value to another type. 165 * Assign or convert this value to another type.
166 * Right now we use this for converting between function types. In the future 166 * This is used for converting between function types, and inserting type
167 * we can use this for other kinds of type checks. 167 * checks when --enable_type_checks is enabled.
168 */ 168 */
169 Value convertTo(MethodGenerator context, Type toType, Node node, 169 Value convertTo(MethodGenerator context, Type toType, Node node,
170 [bool checked=true]) { 170 [bool isDynamic=false]) {
171
172 // Check types if enabled, unless this is a dynamic operation
173 bool checked = options.enableTypeChecks && !isDynamic;
171 174
172 var callMethod = toType.getCallMethod(); 175 var callMethod = toType.getCallMethod();
173 if (callMethod != null) { 176 if (callMethod != null) {
174 if (checked && options.enableTypeChecks && !toType.isAssignable(type)) { 177 if (checked && !toType.isAssignable(type)) {
175 convertWarning(toType, node); 178 convertWarning(toType, node);
176 } 179 }
177 180
178 // TODO(jmesserly): better error if passing a non-function to something
179 // that expects a function.
180
181 int arity = callMethod.parameters.length; 181 int arity = callMethod.parameters.length;
182 var myCall = type.getCallMethod(); 182 var myCall = type.getCallMethod();
183 if (myCall == null || myCall.parameters.length != arity) { 183 if (myCall == null || myCall.parameters.length != arity) {
184 final stub = world.functionType.getCallStub(new Arguments.bare(arity)); 184 final stub = world.functionType.getCallStub(new Arguments.bare(arity));
185 return new Value(toType, 'to\$${stub.name}($code)'); 185 return new Value(toType, 'to\$${stub.name}($code)');
186 } 186 }
187 } 187 }
188 188
189 // Don't add runtime asserts unless we have type checks turned on.
189 if (!options.enableTypeChecks) { 190 if (!options.enableTypeChecks) {
190 return this; 191 return this;
191 } 192 }
192 193
193 if (type.isSubtypeOf(toType)) { 194 if (type.isSubtypeOf(toType)) {
194 return this; // widening conversion 195 return this; // widening conversion
195 } else if (checked && !toType.isSubtypeOf(type)) { 196 } else if (checked && !toType.isSubtypeOf(type)) {
196 // According to the static types, this conversion can't work. 197 // According to the static types, this conversion can't work.
197 convertWarning(toType, node); 198 convertWarning(toType, node);
198 } 199 }
199 200
200 // Add a runtime type check 201 return _typeAssert(context, toType, node);
202 }
201 203
204 /**
205 * Generates a run time type assertion for the given value. This works like
206 * [instanceOf], but it allows null since Dart types are nullable.
207 * Also it will throw a TypeError if it gets the wrong type.
208 */
209 // TODO(jmesserly): this generated code is too verbose.
210 Value _typeAssert(MethodGenerator context, Type toType, Node node) {
211 if (toType is ParameterType) {
212 ParameterType p = toType;
213 toType = p.extendsType;
214 }
215
216 // TODO(jmesserly): I don't like the duplication with instanceOf
202 var temp = context.getTemp(this); 217 var temp = context.getTemp(this);
203 var test = context.assignTemp(temp, this); 218 String testCode;
204 // TODO(jmesserly): this generates a second temp because of assignTemp 219 if (toType.library.isCore && toType.typeofName != null) {
205 // Also it generates an unecessary !!. 220 testCode = "typeof(${temp.code}) == '${toType.typeofName}'";
206 test = test.instanceOf(context, toType, node.span); 221 } else if (toType.isClass && toType is !ConcreteType) {
222 toType.markUsed();
223 testCode = '${temp.code} instanceof ${toType.jsname}';
224 } else {
225 toType.isTested = true;
226 testCode = '${temp.code}.is\$${toType.jsname}';
227 }
228 testCode = '(${context.assignTemp(temp, this).code} == null || $testCode)';
229 var test = new Value(world.boolType, testCode);
207 230
208 // TODO(jmesserly): this generated code is too verbose
209 var err = world.corelib.types['TypeError']; 231 var err = world.corelib.types['TypeError'];
210 world.gen.genMethod(err.members['toString']); 232 world.gen.genMethod(err.members['toString']);
211 var args = new Arguments(null, [temp, 233 var args = new Arguments(null, [temp,
212 new Value(world.stringType, '"${toType.name}"')]); 234 new Value(world.stringType, '"${toType.name}"')]);
213 var typeErr = err.getConstructor('').invoke(context, node, null, args); 235 var typeErr = err.getConstructor('').invoke(context, node, null, args);
214 236
215 var result = new Value(toType, '(${test.code} ? ${temp.code} : ' 237 var result = new Value(toType, '(${test.code} ? ${temp.code} : '
216 + '\$throw(${typeErr.code}))'); 238 + '\$throw(${typeErr.code}))');
217 if (temp != this) context.freeTemp(temp); 239 if (temp != this) context.freeTemp(temp);
218 return result; 240 return result;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 // The single ! here nicely converts undefined to false and function 291 // The single ! here nicely converts undefined to false and function
270 // to true. 292 // to true.
271 testCode = '!' + testCode; 293 testCode = '!' + testCode;
272 } 294 }
273 if (this != temp) context.freeTemp(temp); 295 if (this != temp) context.freeTemp(temp);
274 } 296 }
275 return new Value(world.boolType, testCode); 297 return new Value(world.boolType, testCode);
276 } 298 }
277 299
278 void convertWarning(Type toType, Node node) { 300 void convertWarning(Type toType, Node node) {
301 // TODO(jmesserly): better error messages for type conversion failures
279 world.warning('type "${type.name}" is not assignable to "${toType.name}"', 302 world.warning('type "${type.name}" is not assignable to "${toType.name}"',
280 node.span); 303 node.span);
281 } 304 }
282 305
283 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node, 306 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node,
284 [Arguments args]) { 307 [Arguments args]) {
285 var pos = ''; 308 var pos = '';
286 if (args != null) { 309 if (args != null) {
287 var argsCode = []; 310 var argsCode = [];
288 for (int i = 0; i < args.length; i++) { 311 for (int i = 0; i < args.length; i++) {
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 return 1; 517 return 1;
495 } else if (name != null && other.name == null) { 518 } else if (name != null && other.name == null) {
496 return -1; 519 return -1;
497 } else if (name != null) { 520 } else if (name != null) {
498 return name.compareTo(other.name); 521 return name.compareTo(other.name);
499 } else { 522 } else {
500 return field.name.compareTo(other.field.name); 523 return field.name.compareTo(other.field.name);
501 } 524 }
502 } 525 }
503 } 526 }
OLDNEW
« frog/gen.dart ('K') | « frog/type.dart ('k') | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698