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

Side by Side Diff: lib/runtime/_classes.js

Issue 1413683006: Move runtime js files down to lib/runtime/dart (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 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
« no previous file with comments | « no previous file | lib/runtime/_errors.js » ('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) 2015, 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 /* This library defines the operations that define and manipulate Dart
6 * classes. Included in this are:
7 * - Generics
8 * - Class metadata
9 * - Extension methods
10 */
11
12 // TODO(leafp): Consider splitting some of this out.
13 dart_library.library('dart_runtime/_classes', null, /* Imports */[
14 ], /* Lazy Imports */[
15 'dart/core',
16 'dart/_interceptors',
17 'dart_runtime/_types',
18 'dart_runtime/_rtti',
19 ], function(exports, core, _interceptors, types, rtti) {
20 'use strict';
21
22 const assert = dart_utils.assert;
23 const copyProperties = dart_utils.copyProperties;
24 const copyTheseProperties = dart_utils.copyTheseProperties;
25 const defineMemoizedGetter = dart_utils.defineMemoizedGetter;
26 const safeGetOwnProperty = dart_utils.safeGetOwnProperty;
27 const throwInternalError = dart_utils.throwInternalError;
28
29 const defineProperty = Object.defineProperty;
30 const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
31 const getOwnPropertySymbols = Object.getOwnPropertySymbols;
32
33 const slice = [].slice;
34
35 /** The Symbol for storing type arguments on a specialized generic type. */
36 const _mixins = Symbol('mixins');
37 const _implements = Symbol('implements');
38 exports.implements = _implements;
39 const _metadata = Symbol('metadata');
40 exports.metadata = _metadata;
41
42 /**
43 * Returns a new type that mixes members from base and all mixins.
44 *
45 * Each mixin applies in sequence, with further to the right ones overriding
46 * previous entries.
47 *
48 * For each mixin, we only take its own properties, not anything from its
49 * superclass (prototype).
50 */
51 function mixin(base/*, ...mixins*/) {
52 // Create an initializer for the mixin, so when derived constructor calls
53 // super, we can correctly initialize base and mixins.
54 let mixins = slice.call(arguments, 1);
55
56 // Create a class that will hold all of the mixin methods.
57 class Mixin extends base {
58 // Initializer method: run mixin initializers, then the base.
59 [base.name](/*...args*/) {
60 // Run mixin initializers. They cannot have arguments.
61 // Run them backwards so most-derived mixin is initialized first.
62 for (let i = mixins.length - 1; i >= 0; i--) {
63 let mixin = mixins[i];
64 let init = mixin.prototype[mixin.name];
65 if (init) init.call(this);
66 }
67 // Run base initializer.
68 let init = base.prototype[base.name];
69 if (init) init.apply(this, arguments);
70 }
71 }
72 // Copy each mixin's methods, with later ones overwriting earlier entries.
73 for (let m of mixins) {
74 copyProperties(Mixin.prototype, m.prototype);
75 }
76
77 // Set the signature of the Mixin class to be the composition
78 // of the signatures of the mixins.
79 setSignature(Mixin, {
80 methods: () => {
81 let s = {};
82 for (let m of mixins) {
83 copyProperties(s, m[_methodSig]);
84 }
85 return s;
86 }
87 });
88
89 // Save mixins for reflection
90 Mixin[_mixins] = mixins;
91 return Mixin;
92 }
93 exports.mixin = mixin;
94
95 function getMixins (clazz) {
96 return clazz[_mixins];
97 }
98 exports.getMixins = getMixins;
99
100 function getImplements (clazz) {
101 return clazz[_implements];
102 }
103 exports.getImplements = getImplements;
104
105 /** The Symbol for storing type arguments on a specialized generic type. */
106 let _typeArguments = Symbol('typeArguments');
107 let _originalDeclaration = Symbol('originalDeclaration');
108
109 /** Memoize a generic type constructor function. */
110 function generic(typeConstructor) {
111 let length = typeConstructor.length;
112 if (length < 1) {
113 throwInternalError('must have at least one generic type argument');
114 }
115 let resultMap = new Map();
116 function makeGenericType(/*...arguments*/) {
117 if (arguments.length != length && arguments.length != 0) {
118 throwInternalError('requires ' + length + ' or 0 type arguments');
119 }
120 let args = slice.call(arguments);
121 while (args.length < length) args.push(types.dynamic);
122
123 let value = resultMap;
124 for (let i = 0; i < length; i++) {
125 let arg = args[i];
126 if (arg == null) {
127 throwInternalError('type arguments should not be null: '
128 + typeConstructor);
129 }
130 let map = value;
131 value = map.get(arg);
132 if (value === void 0) {
133 if (i + 1 == length) {
134 value = typeConstructor.apply(null, args);
135 // Save the type constructor and arguments for reflection.
136 if (value) {
137 value[_typeArguments] = args;
138 value[_originalDeclaration] = makeGenericType;
139 }
140 } else {
141 value = new Map();
142 }
143 map.set(arg, value);
144 }
145 }
146 return value;
147 }
148 return makeGenericType;
149 }
150 exports.generic = generic;
151
152 function getGenericClass(type) {
153 return safeGetOwnProperty(type, _originalDeclaration);
154 };
155 exports.getGenericClass = getGenericClass;
156
157 function getGenericArgs(type) {
158 return safeGetOwnProperty(type, _typeArguments);
159 };
160 exports.getGenericArgs = getGenericArgs;
161
162 let _constructorSig = Symbol('sigCtor');
163 let _methodSig = Symbol("sig");
164 let _staticSig = Symbol("sigStatic");
165
166 /// Get the type of a method using the stored signature
167 function _getMethodType(obj, name) {
168 if (obj === void 0) return void 0;
169 if (obj == null) return void 0;
170 let sigObj = obj.__proto__.constructor[_methodSig];
171 if (sigObj === void 0) return void 0;
172 let parts = sigObj[name];
173 if (parts === void 0) return void 0;
174 return types.definiteFunctionType.apply(null, parts);
175 }
176
177 /// Get the type of a constructor from a class using the stored signature
178 /// If name is undefined, returns the type of the default constructor
179 /// Returns undefined if the constructor is not found.
180 function _getConstructorType(cls, name) {
181 if(!name) name = cls.name;
182 if (cls === void 0) return void 0;
183 if (cls == null) return void 0;
184 let sigCtor = cls[_constructorSig];
185 if (sigCtor === void 0) return void 0;
186 let parts = sigCtor[name];
187 if (parts === void 0) return void 0;
188 return types.definiteFunctionType.apply(null, parts);
189 }
190 exports.classGetConstructorType = _getConstructorType;
191
192 /// Given an object and a method name, tear off the method.
193 /// Sets the runtime type of the torn off method appropriately,
194 /// and also binds the object.
195 ///
196 /// If the optional `f` argument is passed in, it will be used as the method.
197 /// This supports cases like `super.foo` where we need to tear off the method
198 /// from the superclass, not from the `obj` directly.
199 /// TODO(leafp): Consider caching the tearoff on the object?
200 function bind(obj, name, f) {
201 if (f === void 0) f = obj[name];
202 f = f.bind(obj);
203 // TODO(jmesserly): track the function's signature on the function, instead
204 // of having to go back to the class?
205 let sig = _getMethodType(obj, name);
206 assert(sig);
207 rtti.tag(f, sig);
208 return f;
209 }
210 exports.bind = bind;
211
212 // Set up the method signature field on the constructor
213 function _setMethodSignature(f, sigF) {
214 defineMemoizedGetter(f, _methodSig, () => {
215 let sigObj = sigF();
216 sigObj.__proto__ = f.__proto__[_methodSig];
217 return sigObj;
218 });
219 }
220
221 // Set up the constructor signature field on the constructor
222 function _setConstructorSignature(f, sigF) {
223 defineMemoizedGetter(f, _constructorSig, sigF);
224 }
225
226 // Set up the static signature field on the constructor
227 function _setStaticSignature(f, sigF) {
228 defineMemoizedGetter(f, _staticSig, sigF);
229 }
230
231 // Set the lazily computed runtime type field on static methods
232 function _setStaticTypes(f, names) {
233 for (let name of names) {
234 rtti.tagMemoized(f[name], function() {
235 let parts = f[_staticSig][name];
236 return types.definiteFunctionType.apply(null, parts);
237 })
238 }
239 }
240
241 /// Set up the type signature of a class (constructor object)
242 /// f is a constructor object
243 /// signature is an object containing optional properties as follows:
244 /// methods: A function returning an object mapping method names
245 /// to method types. The function is evaluated lazily and cached.
246 /// statics: A function returning an object mapping static method
247 /// names to types. The function is evalutated lazily and cached.
248 /// names: An array of the names of the static methods. Used to
249 /// permit eagerly setting the runtimeType field on the methods
250 /// while still lazily computing the type descriptor object.
251 function setSignature(f, signature) {
252 let constructors =
253 ('constructors' in signature) ? signature.constructors : () => ({});
254 let methods =
255 ('methods' in signature) ? signature.methods : () => ({});
256 let statics =
257 ('statics' in signature) ? signature.statics : () => ({});
258 let names =
259 ('names' in signature) ? signature.names : [];
260 _setConstructorSignature(f, constructors);
261 _setMethodSignature(f, methods);
262 _setStaticSignature(f, statics);
263 _setStaticTypes(f, names);
264 rtti.tagMemoized(f, () => core.Type);
265 }
266 exports.setSignature = setSignature;
267
268 function hasMethod(obj, name) {
269 return _getMethodType(obj, name) !== void 0;
270 }
271 exports.hasMethod = hasMethod;
272
273 exports.getMethodType = _getMethodType;
274
275 /**
276 * This is called whenever a derived class needs to introduce a new field,
277 * shadowing a field or getter/setter pair on its parent.
278 *
279 * This is important because otherwise, trying to read or write the field
280 * would end up calling the getter or setter, and one of those might not even
281 * exist, resulting in a runtime error. Even if they did exist, that's the
282 * wrong behavior if a new field was declared.
283 */
284 function virtualField(subclass, fieldName) {
285 // If the field is already overridden, do nothing.
286 let prop = getOwnPropertyDescriptor(subclass.prototype, fieldName);
287 if (prop) return;
288
289 let symbol = Symbol(subclass.name + '.' + fieldName);
290 defineProperty(subclass.prototype, fieldName, {
291 get: function() { return this[symbol]; },
292 set: function(x) { this[symbol] = x; }
293 });
294 }
295 exports.virtualField = virtualField;
296
297 /**
298 * Given a class and an initializer method name, creates a constructor
299 * function with the same name. For example `new SomeClass.name(args)`.
300 */
301 function defineNamedConstructor(clazz, name) {
302 let proto = clazz.prototype;
303 let initMethod = proto[name];
304 let ctor = function() { return initMethod.apply(this, arguments); };
305 ctor.prototype = proto;
306 // Use defineProperty so we don't hit a property defined on Function,
307 // like `caller` and `arguments`.
308 defineProperty(clazz, name, { value: ctor, configurable: true });
309 }
310 exports.defineNamedConstructor = defineNamedConstructor;
311
312 let _extensionType = Symbol('extensionType');
313
314 let dartx = {};
315 exports.dartx = dartx;
316
317 function getExtensionSymbol(name) {
318 let sym = dartx[name];
319 if (!sym) dartx[name] = sym = Symbol('dartx.' + name);
320 return sym;
321 }
322
323 function defineExtensionNames(names) {
324 names.forEach(getExtensionSymbol);
325 }
326 exports.defineExtensionNames = defineExtensionNames;
327
328 /**
329 * Copy symbols from the prototype of the source to destination.
330 * These are the only properties safe to copy onto an existing public
331 * JavaScript class.
332 */
333 function registerExtension(jsType, dartExtType) {
334 let extProto = dartExtType.prototype;
335 let jsProto = jsType.prototype;
336
337 // Mark the JS type's instances so we can easily check for extensions.
338 assert(jsProto[_extensionType] === void 0);
339 jsProto[_extensionType] = extProto;
340
341 let dartObjProto = core.Object.prototype;
342 while (extProto !== dartObjProto && extProto !== jsProto) {
343 copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto));
344 extProto = extProto.__proto__;
345 }
346 let originalSigFn = getOwnPropertyDescriptor(dartExtType, _methodSig).get;
347 assert(originalSigFn);
348 defineMemoizedGetter(jsType, _methodSig, originalSigFn);
349 }
350 exports.registerExtension = registerExtension;
351
352 /**
353 * Mark a concrete type as implementing extension methods.
354 * For example: `class MyIter implements Iterable`.
355 *
356 * This takes a list of names, which are the extension methods implemented.
357 * It will add a forwarder, so the extension method name redirects to the
358 * normal Dart method name. For example:
359 *
360 * defineExtensionMembers(MyType, ['add', 'remove']);
361 *
362 * Results in:
363 *
364 * MyType.prototype[dartx.add] = MyType.prototype.add;
365 * MyType.prototype[dartx.remove] = MyType.prototype.remove;
366 */
367 // TODO(jmesserly): essentially this gives two names to the same method.
368 // This benefit is roughly equivalent call performance either way, but the
369 // cost is we need to call defineExtensionMembers any time a subclass
370 // overrides one of these methods.
371 function defineExtensionMembers(type, methodNames) {
372 let proto = type.prototype;
373 for (let name of methodNames) {
374 let method = getOwnPropertyDescriptor(proto, name);
375 defineProperty(proto, getExtensionSymbol(name), method);
376 }
377 // Ensure the signature is available too.
378 // TODO(jmesserly): not sure if we can do this in a cleaner way. Essentially
379 // we need to copy the signature (and in the future, other data like
380 // annotations) any time we copy a method as part of our metaprogramming.
381 // It might be more friendly to JS metaprogramming if we include this info
382 // on the function.
383 let originalSigFn = getOwnPropertyDescriptor(type, _methodSig).get;
384 defineMemoizedGetter(type, _methodSig, function() {
385 let sig = originalSigFn();
386 for (let name of methodNames) {
387 sig[getExtensionSymbol(name)] = sig[name];
388 }
389 return sig;
390 });
391 }
392 exports.defineExtensionMembers = defineExtensionMembers;
393
394 function canonicalMember(obj, name) {
395 if (obj != null && obj[_extensionType]) return dartx[name];
396 // Check for certain names that we can't use in JS
397 if (name == 'constructor' || name == 'prototype') {
398 name = '+' + name;
399 }
400 return name;
401 }
402 exports.canonicalMember = canonicalMember;
403
404 /** Sets the type of `obj` to be `type` */
405 function setType(obj, type) {
406 obj.__proto__ = type.prototype;
407 return obj;
408 }
409
410 /** Sets the element type of a list literal. */
411 function list(obj, elementType) {
412 return setType(obj, _interceptors.JSArray$(elementType));
413 }
414 exports.list = list;
415
416 function setBaseClass(derived, base) {
417 // Link the extension to the type it's extending as a base class.
418 derived.prototype.__proto__ = base.prototype;
419 }
420 exports.setBaseClass = setBaseClass;
421
422 });
OLDNEW
« no previous file with comments | « no previous file | lib/runtime/_errors.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698