| 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 // IrNodes are kept in a separate library to have precise control over their | 5 // IrNodes are kept in a separate library to have precise control over their |
| 6 // dependencies on other parts of the system. | 6 // dependencies on other parts of the system. |
| 7 library dart2js.ir_nodes; | 7 library dart2js.ir_nodes; |
| 8 | 8 |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart' as values show ConstantValue; | 10 import '../constants/values.dart' as values show ConstantValue; |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 InvokeStatic(this.target, this.selector, Continuation cont, | 213 InvokeStatic(this.target, this.selector, Continuation cont, |
| 214 List<Primitive> args) | 214 List<Primitive> args) |
| 215 : continuation = new Reference<Continuation>(cont), | 215 : continuation = new Reference<Continuation>(cont), |
| 216 arguments = _referenceList(args) { | 216 arguments = _referenceList(args) { |
| 217 assert(target is ErroneousElement || selector.name == target.name); | 217 assert(target is ErroneousElement || selector.name == target.name); |
| 218 } | 218 } |
| 219 | 219 |
| 220 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 220 accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
| 221 } | 221 } |
| 222 | 222 |
| 223 /// A [CallingConvention] codifies how arguments are matched to parameters when |
| 224 /// emitting code for a function call. |
| 225 class CallingConvention { |
| 226 final String name; |
| 227 const CallingConvention(this.name); |
| 228 /// The normal way of calling a Dart function: Positional arguments are |
| 229 /// matched with (mandatory and optional) positionals parameters from left to |
| 230 /// right and named arguments are matched by name. |
| 231 static const CallingConvention DART = const CallingConvention("Dart call"); |
| 232 /// Intercepted calls have an additional first argument that is the actual |
| 233 /// receiver of the call. See the documentation of [Interceptor] for more |
| 234 /// information. |
| 235 static const CallingConvention JS_INTERCEPTED = |
| 236 const CallingConvention("intercepted JavaScript call"); |
| 237 } |
| 238 |
| 223 /// Invoke a method, operator, getter, setter, or index getter/setter. | 239 /// Invoke a method, operator, getter, setter, or index getter/setter. |
| 224 /// Converting a method to a function object is treated as a getter invocation. | 240 /// Converting a method to a function object is treated as a getter invocation. |
| 225 class InvokeMethod extends Expression implements Invoke { | 241 class InvokeMethod extends Expression implements Invoke { |
| 226 Reference<Primitive> receiver; | 242 Reference<Primitive> receiver; |
| 227 final Selector selector; | 243 Selector selector; |
| 244 CallingConvention callingConvention; |
| 228 final Reference<Continuation> continuation; | 245 final Reference<Continuation> continuation; |
| 229 final List<Reference<Primitive>> arguments; | 246 final List<Reference<Primitive>> arguments; |
| 230 | 247 |
| 231 InvokeMethod(Primitive receiver, | 248 InvokeMethod(Primitive receiver, |
| 232 Selector selector, | 249 Selector selector, |
| 233 Continuation cont, | 250 Continuation continuation, |
| 234 List<Primitive> args) | 251 List<Primitive> arguments) |
| 235 : this.internal(new Reference<Primitive>(receiver), | 252 : this.internal(new Reference<Primitive>(receiver), |
| 236 selector, | 253 selector, |
| 237 new Reference<Continuation>(cont), | 254 new Reference<Continuation>(continuation), |
| 238 _referenceList(args)); | 255 _referenceList(arguments)); |
| 239 | 256 |
| 240 InvokeMethod.internal(this.receiver, | 257 InvokeMethod.internal(this.receiver, |
| 241 this.selector, | 258 this.selector, |
| 242 this.continuation, | 259 this.continuation, |
| 243 this.arguments) { | 260 this.arguments, |
| 244 assert(selector != null); | 261 [this.callingConvention = CallingConvention.DART]) { |
| 245 assert(selector.kind == SelectorKind.CALL || | 262 assert(isValid); |
| 246 selector.kind == SelectorKind.OPERATOR || | |
| 247 (selector.kind == SelectorKind.GETTER && arguments.isEmpty) || | |
| 248 (selector.kind == SelectorKind.SETTER && arguments.length == 1) || | |
| 249 (selector.kind == SelectorKind.INDEX && arguments.length == 1) || | |
| 250 (selector.kind == SelectorKind.INDEX && arguments.length == 2)); | |
| 251 } | 263 } |
| 252 | 264 |
| 253 bool get isIntercepted => receiver.definition is Interceptor; | 265 /// Returns whether the arguments match the selector under the given calling |
| 266 /// convention. |
| 267 /// |
| 268 /// This check is designed to be used in an assert, as it also checks that the |
| 269 /// selector, arguments, and calling convention have meaningful values. |
| 270 bool get isValid { |
| 271 if (selector == null || callingConvention == null) return false; |
| 272 if (callingConvention != CallingConvention.DART && |
| 273 callingConvention != CallingConvention.JS_INTERCEPTED) { |
| 274 return false; |
| 275 } |
| 276 int numberOfArguments = |
| 277 callingConvention == CallingConvention.JS_INTERCEPTED |
| 278 ? arguments.length - 1 |
| 279 : arguments.length; |
| 280 return selector.kind == SelectorKind.CALL || |
| 281 selector.kind == SelectorKind.OPERATOR || |
| 282 (selector.kind == SelectorKind.GETTER && numberOfArguments == 0) || |
| 283 (selector.kind == SelectorKind.SETTER && numberOfArguments == 1) || |
| 284 (selector.kind == SelectorKind.INDEX && numberOfArguments == 1) || |
| 285 (selector.kind == SelectorKind.INDEX && numberOfArguments == 2); |
| 286 } |
| 254 | 287 |
| 255 accept(Visitor visitor) => visitor.visitInvokeMethod(this); | 288 accept(Visitor visitor) => visitor.visitInvokeMethod(this); |
| 256 } | 289 } |
| 257 | 290 |
| 258 /// Invoke [target] on [receiver], bypassing dispatch and override semantics. | 291 /// Invoke [target] on [receiver], bypassing dispatch and override semantics. |
| 259 /// | 292 /// |
| 260 /// That is, if [receiver] is an instance of a class that overrides [target] | 293 /// That is, if [receiver] is an instance of a class that overrides [target] |
| 261 /// with a different implementation, the overriding implementation is bypassed | 294 /// with a different implementation, the overriding implementation is bypassed |
| 262 /// and [target]'s implementation is invoked. | 295 /// and [target]'s implementation is invoked. |
| 263 /// | 296 /// |
| (...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1358 | 1391 |
| 1359 void visitIdentical(Identical node) { | 1392 void visitIdentical(Identical node) { |
| 1360 visitReference(node.left); | 1393 visitReference(node.left); |
| 1361 visitReference(node.right); | 1394 visitReference(node.right); |
| 1362 } | 1395 } |
| 1363 | 1396 |
| 1364 void visitInterceptor(Interceptor node) { | 1397 void visitInterceptor(Interceptor node) { |
| 1365 visitReference(node.input); | 1398 visitReference(node.input); |
| 1366 } | 1399 } |
| 1367 } | 1400 } |
| OLD | NEW |