OLD | NEW |
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 _interceptors; | 5 library _interceptors; |
6 | 6 |
7 import 'dart:_js_embedded_names' show | 7 import 'dart:_js_embedded_names' show |
8 DISPATCH_PROPERTY_NAME, | 8 DISPATCH_PROPERTY_NAME, |
9 TYPE_TO_INTERCEPTOR_MAP; | 9 TYPE_TO_INTERCEPTOR_MAP; |
10 | 10 |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 * The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`. The | 243 * The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`. The |
244 * value returned by [getInterceptor] holds the methods separately from the | 244 * value returned by [getInterceptor] holds the methods separately from the |
245 * state of the instance. The compiler converts the methods on an interceptor | 245 * state of the instance. The compiler converts the methods on an interceptor |
246 * to take the Dart `this` argument as an explicit `receiver` argument. The | 246 * to take the Dart `this` argument as an explicit `receiver` argument. The |
247 * JavaScript `this` parameter is bound to the interceptor. | 247 * JavaScript `this` parameter is bound to the interceptor. |
248 * | 248 * |
249 * In order to have uniform call sites, if a method is defined on an | 249 * In order to have uniform call sites, if a method is defined on an |
250 * interceptor, methods of that name on plain unintercepted classes also use the | 250 * interceptor, methods of that name on plain unintercepted classes also use the |
251 * interceptor calling convention. The plain classes are _self-interceptors_, | 251 * interceptor calling convention. The plain classes are _self-interceptors_, |
252 * and for them, `getInterceptor(r)` returns `r`. Methods on plain | 252 * and for them, `getInterceptor(r)` returns `r`. Methods on plain |
253 * unintercepted classes have a redundant `receiver` argument and should ignore | 253 * unintercepted classes have a redundant `receiver` argument and, to enable |
254 * it in favour of `this`. | 254 * some optimizations, must ignore `receiver` in favour of `this`. |
255 * | 255 * |
256 * In the case of mixins, a method may be placed on both an intercepted class | 256 * In the case of mixins, a method may be placed on both an intercepted class |
257 * and an unintercepted class. In this case, the method must use the `receiver` | 257 * and an unintercepted class. In this case, the method must use the `receiver` |
258 * parameter. | 258 * parameter. |
259 * | 259 * |
260 * | 260 * |
261 * There are various optimizations of the general call pattern. | 261 * There are various optimizations of the general call pattern. |
262 * | 262 * |
263 * When the interceptor can be statically determined, it can be used directly: | 263 * When the interceptor can be statically determined, it can be used directly: |
264 * | 264 * |
(...skipping 22 matching lines...) Expand all Loading... |
287 */ | 287 */ |
288 abstract class Interceptor { | 288 abstract class Interceptor { |
289 const Interceptor(); | 289 const Interceptor(); |
290 | 290 |
291 bool operator ==(other) => identical(this, other); | 291 bool operator ==(other) => identical(this, other); |
292 | 292 |
293 int get hashCode => Primitives.objectHashCode(this); | 293 int get hashCode => Primitives.objectHashCode(this); |
294 | 294 |
295 String toString() => Primitives.objectToHumanReadableString(this); | 295 String toString() => Primitives.objectToHumanReadableString(this); |
296 | 296 |
| 297 // [Interceptor.noSuchMethod] is identical to [Object.noSuchMethod]. However, |
| 298 // each copy is compiled differently. The presence of the method on an |
| 299 // Interceptor class forces [noSuchMethod] to use interceptor calling |
| 300 // convention. In the [Interceptor] version, `this` is the explicit receiver |
| 301 // argument. In the [Object] version, as Object is not an intercepted class, |
| 302 // `this` is the JavaScript receiver, and the explicit receiver is ignored. |
| 303 // The noSuchMethod stubs for selectors that use the interceptor calling |
| 304 // convention do not know the calling convention and forward `this` and |
| 305 // `receiver` to one of these noSuchMethod implementations which selects the |
| 306 // correct Dart receiver. |
| 307 // |
| 308 // We don't allow [noSuchMethod] on intercepted classes (that would force all |
| 309 // calls to use interceptor calling convention). If we did allow it, the |
| 310 // interceptor context would select the correct `this`. |
297 dynamic noSuchMethod(Invocation invocation) { | 311 dynamic noSuchMethod(Invocation invocation) { |
298 throw new NoSuchMethodError( | 312 throw new NoSuchMethodError( |
299 this, | 313 this, |
300 invocation.memberName, | 314 invocation.memberName, |
301 invocation.positionalArguments, | 315 invocation.positionalArguments, |
302 invocation.namedArguments); | 316 invocation.namedArguments); |
303 } | 317 } |
304 | 318 |
305 Type get runtimeType => getRuntimeType(this); | 319 Type get runtimeType => getRuntimeType(this); |
306 } | 320 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 * Interceptor for unclassified JavaScript objects, typically objects with a | 416 * Interceptor for unclassified JavaScript objects, typically objects with a |
403 * non-trivial prototype chain. | 417 * non-trivial prototype chain. |
404 * | 418 * |
405 * This class also serves as a fallback for unknown JavaScript exceptions. | 419 * This class also serves as a fallback for unknown JavaScript exceptions. |
406 */ | 420 */ |
407 class UnknownJavaScriptObject extends JavaScriptObject { | 421 class UnknownJavaScriptObject extends JavaScriptObject { |
408 const UnknownJavaScriptObject(); | 422 const UnknownJavaScriptObject(); |
409 | 423 |
410 String toString() => JS('String', 'String(#)', this); | 424 String toString() => JS('String', 'String(#)', this); |
411 } | 425 } |
OLD | NEW |