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