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

Side by Side Diff: tool/input_sdk_patch/interceptors.dart

Issue 955513008: cleans up sdk patching so we no longer have unresolved names (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 months 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
« no previous file with comments | « tool/input_sdk_patch/foreign_helper.dart ('k') | tool/input_sdk_patch/isolate_helper.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library _interceptors;
6
7 import 'dart:_js_embedded_names' show
8 DISPATCH_PROPERTY_NAME,
9 MAP_TYPE_TO_INTERCEPTOR;
10
11 import 'dart:collection';
12 import 'dart:_internal' hide Symbol;
13 import "dart:_internal" as _symbol_dev show Symbol;
14 import 'dart:_js_helper' show allMatchesInStringUnchecked,
15 Null,
16 JSSyntaxRegExp,
17 Primitives,
18 checkInt,
19 checkNull,
20 checkNum,
21 checkString,
22 defineProperty,
23 getRuntimeType,
24 initNativeDispatch,
25 initNativeDispatchFlag,
26 regExpGetNative,
27 regExpCaptureCount,
28 stringContainsUnchecked,
29 stringLastIndexOfUnchecked,
30 stringReplaceAllFuncUnchecked,
31 stringReplaceAllUnchecked,
32 stringReplaceFirstUnchecked,
33 lookupAndCacheInterceptor,
34 lookupDispatchRecord,
35 StringMatch,
36 firstMatchAfter,
37 NoInline;
38 import 'dart:_foreign_helper' show
39 JS,
40 JS_EFFECT,
41 JS_EMBEDDED_GLOBAL,
42 JS_INTERCEPTOR_CONSTANT,
43 JS_STRING_CONCAT;
44 import 'dart:math' show Random;
45
46 part 'js_array.dart';
47 part 'js_number.dart';
48 part 'js_string.dart';
49
50 String _symbolToString(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
51
52 _symbolMapToStringMap(Map<Symbol, dynamic> map) {
53 if (map == null) return null;
54 var result = new Map<String, dynamic>();
55 map.forEach((Symbol key, value) {
56 result[_symbolToString(key)] = value;
57 });
58 return result;
59 }
60
61 /**
62 * Get the interceptor for [object]. Called by the compiler when it needs
63 * to emit a call to an intercepted method, that is a method that is
64 * defined in an interceptor class.
65 */
66 getInterceptor(object) {
67 // This is a magic method: the compiler does specialization of it
68 // depending on the uses of intercepted methods and instantiated
69 // primitive types.
70
71 // The [JS] call prevents the type analyzer from making assumptions about the
72 // return type.
73 return JS('', 'void 0');
74 }
75
76 getDispatchProperty(object) {
77 return JS('', '#[#]',
78 object, JS_EMBEDDED_GLOBAL('String', DISPATCH_PROPERTY_NAME));
79 }
80
81 setDispatchProperty(object, value) {
82 defineProperty(object,
83 JS_EMBEDDED_GLOBAL('String', DISPATCH_PROPERTY_NAME),
84 value);
85 }
86
87 // Avoid inlining this method because inlining gives us multiple allocation
88 // points for records which is bad because it leads to polymorphic access.
89 @NoInline()
90 makeDispatchRecord(interceptor, proto, extension, indexability) {
91 // Dispatch records are stored in the prototype chain, and in some cases, on
92 // instances.
93 //
94 // The record layout and field usage is designed to minimize the number of
95 // operations on the common paths.
96 //
97 // [interceptor] is the interceptor - a holder of methods for the object,
98 // i.e. the prototype of the interceptor class.
99 //
100 // [proto] is usually the prototype, used to check that the dispatch record
101 // matches the object and is not the dispatch record of a superclass. Other
102 // values:
103 // - `false` for leaf classes that need no check.
104 // - `true` for Dart classes where the object is its own interceptor (unused)
105 // - a function used to continue matching.
106 //
107 // [extension] is used for irregular cases.
108 //
109 // [indexability] is used to cache whether or not the object
110 // implements JavaScriptIndexingBehavior.
111 //
112 // proto interceptor extension action
113 // ----- ----------- --------- ------
114 // false I use interceptor I
115 // true - use object
116 // P I if object's prototype is P, use I
117 // F - P if object's prototype is P, call F
118
119 return JS('', '{i: #, p: #, e: #, x: #}',
120 interceptor, proto, extension, indexability);
121 }
122
123 dispatchRecordInterceptor(record) => JS('', '#.i', record);
124 dispatchRecordProto(record) => JS('', '#.p', record);
125 dispatchRecordExtension(record) => JS('', '#.e', record);
126 dispatchRecordIndexability(record) => JS('bool|Null', '#.x', record);
127
128 /**
129 * Returns the interceptor for a native class instance. Used by
130 * [getInterceptor].
131 */
132 getNativeInterceptor(object) {
133 var record = getDispatchProperty(object);
134
135 if (record == null) {
136 if (initNativeDispatchFlag == null) {
137 initNativeDispatch();
138 record = getDispatchProperty(object);
139 }
140 }
141
142 if (record != null) {
143 var proto = dispatchRecordProto(record);
144 if (false == proto) return dispatchRecordInterceptor(record);
145 if (true == proto) return object;
146 var objectProto = JS('', 'Object.getPrototypeOf(#)', object);
147 if (JS('bool', '# === #', proto, objectProto)) {
148 return dispatchRecordInterceptor(record);
149 }
150
151 var extension = dispatchRecordExtension(record);
152 if (JS('bool', '# === #', extension, objectProto)) {
153 // TODO(sra): The discriminator returns a tag. The tag is an uncached or
154 // instance-cached tag, defaulting to instance-cached if caching
155 // unspecified.
156 var discriminatedTag = JS('', '(#)(#, #)', proto, object, record);
157 throw new UnimplementedError('Return interceptor for $discriminatedTag');
158 }
159 }
160
161 var interceptor = lookupAndCacheInterceptor(object);
162 if (interceptor == null) {
163 // JavaScript Objects created via object literals and `Object.create(null)`
164 // are 'plain' Objects. This test could be simplified and the dispatch path
165 // be faster if Object.prototype was pre-patched with a non-leaf dispatch
166 // record.
167 var proto = JS('', 'Object.getPrototypeOf(#)', object);
168 if (JS('bool', '# == null || # === Object.prototype', proto, proto)) {
169 return JS_INTERCEPTOR_CONSTANT(PlainJavaScriptObject);
170 } else {
171 return JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject);
172 }
173 }
174
175 return interceptor;
176 }
177
178 /**
179 * Data structure used to map a [Type] to the [Interceptor] and constructors for
180 * that type. It is JavaScript array of 3N entries of adjacent slots containing
181 * a [Type], followed by an [Interceptor] class for the type, followed by a
182 * JavaScript object map for the constructors.
183 *
184 * The value of this variable is set by the compiler and contains only types
185 * that are user extensions of native classes where the type occurs as a
186 * constant in the program.
187 *
188 * The compiler, in CustomElementsAnalysis, assumes that [mapTypeToInterceptor]
189 * is accessed only by code that also calls [findIndexForWebComponentType]. If
190 * this assumption is invalidated, the compiler will have to be updated.
191 */
192 get mapTypeToInterceptor {
193 return JS_EMBEDDED_GLOBAL('', MAP_TYPE_TO_INTERCEPTOR);
194 }
195
196 int findIndexForNativeSubclassType(Type type) {
197 if (JS('bool', '# == null', mapTypeToInterceptor)) return null;
198 List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
199 for (int i = 0; i + 1 < map.length; i += 3) {
200 if (type == map[i]) {
201 return i;
202 }
203 }
204 return null;
205 }
206
207 findInterceptorConstructorForType(Type type) {
208 var index = findIndexForNativeSubclassType(type);
209 if (index == null) return null;
210 List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
211 return map[index + 1];
212 }
213
214 /**
215 * Returns a JavaScript function that runs the constructor on its argument, or
216 * `null` if there is no such constructor.
217 *
218 * The returned function takes one argument, the web component object.
219 */
220 findConstructorForNativeSubclassType(Type type, String name) {
221 var index = findIndexForNativeSubclassType(type);
222 if (index == null) return null;
223 List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
224 var constructorMap = map[index + 2];
225 var constructorFn = JS('', '#[#]', constructorMap, name);
226 return constructorFn;
227 }
228
229 findInterceptorForType(Type type) {
230 var constructor = findInterceptorConstructorForType(type);
231 if (constructor == null) return null;
232 return JS('', '#.prototype', constructor);
233 }
234
235 /**
236 * The base interceptor class.
237 *
238 * The code `r.foo(a)` is compiled to `getInterceptor(r).foo$1(r, a)`. The
239 * value returned by [getInterceptor] holds the methods separately from the
240 * state of the instance. The compiler converts the methods on an interceptor
241 * to take the Dart `this` argument as an explicit `receiver` argument. The
242 * JavaScript `this` parameter is bound to the interceptor.
243 *
244 * In order to have uniform call sites, if a method is defined on an
245 * interceptor, methods of that name on plain unintercepted classes also use the
246 * interceptor calling convention. The plain classes are _self-interceptors_,
247 * and for them, `getInterceptor(r)` returns `r`. Methods on plain
248 * unintercepted classes have a redundant `receiver` argument and should ignore
249 * it in favour of `this`.
250 *
251 * In the case of mixins, a method may be placed on both an intercepted class
252 * and an unintercepted class. In this case, the method must use the `receiver`
253 * parameter.
254 *
255 *
256 * There are various optimizations of the general call pattern.
257 *
258 * When the interceptor can be statically determined, it can be used directly:
259 *
260 * CONSTANT_INTERCEPTOR.foo$1(r, a)
261 *
262 * If there are only a few classes, [getInterceptor] can be specialized with a
263 * more efficient dispatch:
264 *
265 * getInterceptor$specialized(r).foo$1(r, a)
266 *
267 * If it can be determined that the receiver is an unintercepted class, it can
268 * be called directly:
269 *
270 * r.foo$1(r, a)
271 *
272 * If, further, it is known that the call site cannot call a foo that is
273 * mixed-in to a native class, then it is known that the explicit receiver is
274 * ignored, and space-saving dummy value can be passed instead:
275 *
276 * r.foo$1(0, a)
277 *
278 * This class defines implementations of *all* methods on [Object] so no
279 * interceptor inherits an implementation from [Object]. This enables the
280 * implementations on Object to ignore the explicit receiver argument, which
281 * allows dummy receiver optimization.
282 */
283 abstract class Interceptor {
284 const Interceptor();
285
286 bool operator ==(other) => identical(this, other);
287
288 int get hashCode => Primitives.objectHashCode(this);
289
290 String toString() => Primitives.objectToString(this);
291
292 dynamic noSuchMethod(Invocation invocation) {
293 throw new NoSuchMethodError(
294 this,
295 invocation.memberName,
296 invocation.positionalArguments,
297 invocation.namedArguments);
298 }
299
300 Type get runtimeType => getRuntimeType(this);
301 }
302
303 /**
304 * The interceptor class for [bool].
305 */
306 class JSBool extends Interceptor implements bool {
307 const JSBool();
308
309 // Note: if you change this, also change the function [S].
310 String toString() => JS('String', r'String(#)', this);
311
312 // The values here are SMIs, co-prime and differ about half of the bit
313 // positions, including the low bit, so they are different mod 2^k.
314 int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
315
316 Type get runtimeType => bool;
317 }
318
319 /**
320 * The interceptor class for [Null].
321 *
322 * This class defines implementations for *all* methods on [Object] since
323 * the methods on Object assume the receiver is non-null. This means that
324 * JSNull will always be in the interceptor set for methods defined on Object.
325 */
326 class JSNull extends Interceptor implements Null {
327 const JSNull();
328
329 bool operator ==(other) => identical(null, other);
330
331 // Note: if you change this, also change the function [S].
332 String toString() => 'null';
333
334 int get hashCode => 0;
335
336 // The spec guarantees that `null` is the singleton instance of the `Null`
337 // class. In the mirrors library we also have to patch the `type` getter to
338 // special case `null`.
339 Type get runtimeType => Null;
340
341 dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
342 }
343
344 /**
345 * The supertype for JSString and JSArray. Used by the backend as to
346 * have a type mask that contains the objects that we can use the
347 * native JS [] operator and length on.
348 */
349 abstract class JSIndexable {
350 int get length;
351 operator[](int index);
352 }
353
354 /**
355 * The supertype for JSMutableArray and
356 * JavaScriptIndexingBehavior. Used by the backend to have a type mask
357 * that contains the objects we can use the JS []= operator on.
358 */
359 abstract class JSMutableIndexable extends JSIndexable {
360 operator[]=(int index, var value);
361 }
362
363 /**
364 * The interface implemented by JavaScript objects. These are methods in
365 * addition to the regular Dart Object methods like [Object.hashCode].
366 *
367 * This is the type that should be exported by a JavaScript interop library.
368 */
369 abstract class JSObject {
370 }
371
372
373 /**
374 * Interceptor base class for JavaScript objects not recognized as some more
375 * specific native type.
376 */
377 abstract class JavaScriptObject extends Interceptor implements JSObject {
378 const JavaScriptObject();
379
380 // It would be impolite to stash a property on the object.
381 int get hashCode => 0;
382
383 Type get runtimeType => JSObject;
384 }
385
386
387 /**
388 * Interceptor for plain JavaScript objects created as JavaScript object
389 * literals or `new Object()`.
390 */
391 class PlainJavaScriptObject extends JavaScriptObject {
392 const PlainJavaScriptObject();
393 }
394
395
396 /**
397 * Interceptor for unclassified JavaScript objects, typically objects with a
398 * non-trivial prototype chain.
399 *
400 * This class also serves as a fallback for unknown JavaScript exceptions.
401 */
402 class UnknownJavaScriptObject extends JavaScriptObject {
403 const UnknownJavaScriptObject();
404
405 String toString() => JS('String', 'String(#)', this);
406 }
OLDNEW
« no previous file with comments | « tool/input_sdk_patch/foreign_helper.dart ('k') | tool/input_sdk_patch/isolate_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698