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

Side by Side Diff: src/js/typedarray.js

Issue 1574903004: TypedArray and ArrayBuffer support for @@species (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Upload tests and make some code more clear Created 4 years, 11 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 | « src/js/runtime.js ('k') | src/messages.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 (function(global, utils) { 5 (function(global, utils) {
6 6
7 "use strict"; 7 "use strict";
8 8
9 %CheckIsBootstrapping(); 9 %CheckIsBootstrapping();
10 10
11 // ------------------------------------------------------------------- 11 // -------------------------------------------------------------------
12 // Imports 12 // Imports
13 13
14 var ArrayFrom; 14 var ArrayFrom;
15 var ArrayToString; 15 var ArrayToString;
16 var ArrayValues; 16 var ArrayValues;
17 var GlobalArray = global.Array; 17 var GlobalArray = global.Array;
18 var GlobalArrayBuffer = global.ArrayBuffer; 18 var GlobalArrayBuffer = global.ArrayBuffer;
19 var GlobalDataView = global.DataView; 19 var GlobalDataView = global.DataView;
20 var GlobalObject = global.Object; 20 var GlobalObject = global.Object;
21 var InternalArray = utils.InternalArray;
21 var InnerArrayCopyWithin; 22 var InnerArrayCopyWithin;
22 var InnerArrayEvery; 23 var InnerArrayEvery;
23 var InnerArrayFill; 24 var InnerArrayFill;
24 var InnerArrayFilter; 25 var InnerArrayFilter;
25 var InnerArrayFind; 26 var InnerArrayFind;
26 var InnerArrayFindIndex; 27 var InnerArrayFindIndex;
27 var InnerArrayForEach; 28 var InnerArrayForEach;
28 var InnerArrayIncludes; 29 var InnerArrayIncludes;
29 var InnerArrayIndexOf; 30 var InnerArrayIndexOf;
30 var InnerArrayJoin; 31 var InnerArrayJoin;
31 var InnerArrayLastIndexOf; 32 var InnerArrayLastIndexOf;
32 var InnerArrayReduce; 33 var InnerArrayReduce;
33 var InnerArrayReduceRight; 34 var InnerArrayReduceRight;
34 var InnerArraySome; 35 var InnerArraySome;
35 var InnerArraySort; 36 var InnerArraySort;
36 var InnerArrayToLocaleString; 37 var InnerArrayToLocaleString;
37 var InternalArray = utils.InternalArray; 38 var InternalArray = utils.InternalArray;
38 var IsNaN; 39 var IsNaN;
39 var MakeRangeError; 40 var MakeRangeError;
40 var MakeTypeError; 41 var MakeTypeError;
41 var MaxSimple; 42 var MaxSimple;
42 var MinSimple; 43 var MinSimple;
43 var PackedArrayReverse; 44 var PackedArrayReverse;
45 var SpeciesConstructor;
44 var ToPositiveInteger; 46 var ToPositiveInteger;
45 var iteratorSymbol = utils.ImportNow("iterator_symbol"); 47 var iteratorSymbol = utils.ImportNow("iterator_symbol");
46 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 48 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
47 49
48 macro TYPED_ARRAYS(FUNCTION) 50 macro TYPED_ARRAYS(FUNCTION)
49 // arrayIds below should be synchronized with Runtime_TypedArrayInitialize. 51 // arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
50 FUNCTION(1, Uint8Array, 1) 52 FUNCTION(1, Uint8Array, 1)
51 FUNCTION(2, Int8Array, 1) 53 FUNCTION(2, Int8Array, 1)
52 FUNCTION(3, Uint16Array, 2) 54 FUNCTION(3, Uint16Array, 2)
53 FUNCTION(4, Int16Array, 2) 55 FUNCTION(4, Int16Array, 2)
(...skipping 26 matching lines...) Expand all
80 InnerArrayJoin = from.InnerArrayJoin; 82 InnerArrayJoin = from.InnerArrayJoin;
81 InnerArrayLastIndexOf = from.InnerArrayLastIndexOf; 83 InnerArrayLastIndexOf = from.InnerArrayLastIndexOf;
82 InnerArrayReduce = from.InnerArrayReduce; 84 InnerArrayReduce = from.InnerArrayReduce;
83 InnerArrayReduceRight = from.InnerArrayReduceRight; 85 InnerArrayReduceRight = from.InnerArrayReduceRight;
84 InnerArraySome = from.InnerArraySome; 86 InnerArraySome = from.InnerArraySome;
85 InnerArraySort = from.InnerArraySort; 87 InnerArraySort = from.InnerArraySort;
86 InnerArrayToLocaleString = from.InnerArrayToLocaleString; 88 InnerArrayToLocaleString = from.InnerArrayToLocaleString;
87 IsNaN = from.IsNaN; 89 IsNaN = from.IsNaN;
88 MakeRangeError = from.MakeRangeError; 90 MakeRangeError = from.MakeRangeError;
89 MakeTypeError = from.MakeTypeError; 91 MakeTypeError = from.MakeTypeError;
90 MakeTypeError = from.MakeTypeError;
91 MaxSimple = from.MaxSimple;
92 MaxSimple = from.MaxSimple; 92 MaxSimple = from.MaxSimple;
93 MinSimple = from.MinSimple; 93 MinSimple = from.MinSimple;
94 MinSimple = from.MinSimple;
95 PackedArrayReverse = from.PackedArrayReverse; 94 PackedArrayReverse = from.PackedArrayReverse;
95 SpeciesConstructor = from.SpeciesConstructor;
96 ToPositiveInteger = from.ToPositiveInteger; 96 ToPositiveInteger = from.ToPositiveInteger;
97 }); 97 });
98 98
99 // --------------- Typed Arrays --------------------- 99 // --------------- Typed Arrays ---------------------
100 100
101 function TypedArrayDefaultConstructor(typedArray) {
102 switch (%_ClassOf(typedArray)) {
103 macro TYPED_ARRAY_CONSTRUCTOR_CASE(ARRAY_ID, NAME, ELEMENT_SIZE)
104 case "NAME":
105 return GlobalNAME;
106 endmacro
107 TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR_CASE)
108 }
109 // The TypeError should not be generated since all callers should
110 // have already called ValidateTypedArray.
111 throw MakeTypeError(kIncompatibleMethodReceiver,
112 "TypedArrayDefaultConstructor", this);
113 }
114
115 function TypedArrayCreate(constructor, arg0, arg1, arg2) {
116 if (IS_UNDEFINED(arg1)) {
117 var newTypedArray = new constructor(arg0);
118 } else {
119 var newTypedArray = new constructor(arg0, arg1, arg2);
120 }
121 if (!%_IsTypedArray(newTypedArray)) throw MakeTypeError(kNotTypedArray);
122 // TODO(littledan): Check for being detached, here and elsewhere
123 // All callers where the first argument is a Number have no additional
124 // arguments.
125 if (IS_NUMBER(arg0) && %_TypedArrayGetLength(newTypedArray) < arg0) {
126 throw MakeTypeError(kTypedArrayTooShort);
127 }
128 return newTypedArray;
129 }
130
131 function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2) {
132 var defaultConstructor = TypedArrayDefaultConstructor(exemplar);
133 var constructor = SpeciesConstructor(exemplar, defaultConstructor);
134 return TypedArrayCreate(constructor, arg0, arg1, arg2);
135 }
136
101 macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE) 137 macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
102 function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) { 138 function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) {
103 if (!IS_UNDEFINED(byteOffset)) { 139 if (!IS_UNDEFINED(byteOffset)) {
104 byteOffset = ToPositiveInteger(byteOffset, kInvalidTypedArrayLength); 140 byteOffset = ToPositiveInteger(byteOffset, kInvalidTypedArrayLength);
105 } 141 }
106 if (!IS_UNDEFINED(length)) { 142 if (!IS_UNDEFINED(length)) {
107 length = ToPositiveInteger(length, kInvalidTypedArrayLength); 143 length = ToPositiveInteger(length, kInvalidTypedArrayLength);
108 } 144 }
109 145
110 var bufferByteLength = %_ArrayBufferGetByteLength(buffer); 146 var bufferByteLength = %_ArrayBufferGetByteLength(buffer);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 } 239 }
204 240
205 function NAMEConstructor(arg1, arg2, arg3) { 241 function NAMEConstructor(arg1, arg2, arg3) {
206 if (!IS_UNDEFINED(new.target)) { 242 if (!IS_UNDEFINED(new.target)) {
207 if (IS_ARRAYBUFFER(arg1) || IS_SHAREDARRAYBUFFER(arg1)) { 243 if (IS_ARRAYBUFFER(arg1) || IS_SHAREDARRAYBUFFER(arg1)) {
208 NAMEConstructByArrayBuffer(this, arg1, arg2, arg3); 244 NAMEConstructByArrayBuffer(this, arg1, arg2, arg3);
209 } else if (IS_NUMBER(arg1) || IS_STRING(arg1) || 245 } else if (IS_NUMBER(arg1) || IS_STRING(arg1) ||
210 IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) { 246 IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) {
211 NAMEConstructByLength(this, arg1); 247 NAMEConstructByLength(this, arg1);
212 } else { 248 } else {
249 // TODO(littledan): If arg1 is a TypedArray, follow the constructor
250 // path in ES2015 22.2.4.3, and call SpeciesConstructor, in a
251 // path that seems to be an optimized version of what's below, but
252 // in an observably different way.
213 var iteratorFn = arg1[iteratorSymbol]; 253 var iteratorFn = arg1[iteratorSymbol];
214 if (IS_UNDEFINED(iteratorFn) || iteratorFn === ArrayValues) { 254 if (IS_UNDEFINED(iteratorFn) || iteratorFn === ArrayValues) {
215 NAMEConstructByArrayLike(this, arg1); 255 NAMEConstructByArrayLike(this, arg1);
216 } else { 256 } else {
217 NAMEConstructByIterable(this, arg1, iteratorFn); 257 NAMEConstructByIterable(this, arg1, iteratorFn);
218 } 258 }
219 } 259 }
220 } else { 260 } else {
221 throw MakeTypeError(kConstructorNotFunction, "NAME") 261 throw MakeTypeError(kConstructorNotFunction, "NAME")
222 } 262 }
(...skipping 21 matching lines...) Expand all
244 endInt = MinSimple(endInt, srcLength); 284 endInt = MinSimple(endInt, srcLength);
245 } 285 }
246 286
247 if (endInt < beginInt) { 287 if (endInt < beginInt) {
248 endInt = beginInt; 288 endInt = beginInt;
249 } 289 }
250 290
251 var newLength = endInt - beginInt; 291 var newLength = endInt - beginInt;
252 var beginByteOffset = 292 var beginByteOffset =
253 %_ArrayBufferViewGetByteOffset(this) + beginInt * ELEMENT_SIZE; 293 %_ArrayBufferViewGetByteOffset(this) + beginInt * ELEMENT_SIZE;
254 return new GlobalNAME(%TypedArrayGetBuffer(this), 294 return TypedArraySpeciesCreate(this, %TypedArrayGetBuffer(this),
255 beginByteOffset, newLength); 295 beginByteOffset, newLength);
256 } 296 }
257 endmacro 297 endmacro
258 298
259 TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR) 299 TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
260 300
261 function TypedArraySubArray(begin, end) { 301 function TypedArraySubArray(begin, end) {
262 switch (%_ClassOf(this)) { 302 switch (%_ClassOf(this)) {
263 macro TYPED_ARRAY_SUBARRAY_CASE(ARRAY_ID, NAME, ELEMENT_SIZE) 303 macro TYPED_ARRAY_SUBARRAY_CASE(ARRAY_ID, NAME, ELEMENT_SIZE)
264 case "NAME": 304 case "NAME":
265 return %_Call(NAMESubArray, this, begin, end); 305 return %_Call(NAMESubArray, this, begin, end);
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 } 453 }
414 454
415 function TypedArrayGetToStringTag() { 455 function TypedArrayGetToStringTag() {
416 if (!%_IsTypedArray(this)) return; 456 if (!%_IsTypedArray(this)) return;
417 var name = %_ClassOf(this); 457 var name = %_ClassOf(this);
418 if (IS_UNDEFINED(name)) return; 458 if (IS_UNDEFINED(name)) return;
419 return name; 459 return name;
420 } 460 }
421 461
422 462
423 function ConstructTypedArray(constructor, arg) {
424 // TODO(littledan): This is an approximation of the spec, which requires
425 // that only real TypedArray classes should be accepted (22.2.2.1.1)
426 if (!%IsConstructor(constructor) || IS_UNDEFINED(constructor.prototype) ||
427 !%HasOwnProperty(constructor.prototype, "BYTES_PER_ELEMENT")) {
428 throw MakeTypeError(kNotTypedArray);
429 }
430
431 // TODO(littledan): The spec requires that, rather than directly calling
432 // the constructor, a TypedArray is created with the proper proto and
433 // underlying size and element size, and elements are put in one by one.
434 // By contrast, this would allow subclasses to make a radically different
435 // constructor with different semantics.
436 return new constructor(arg);
437 }
438
439
440 function ConstructTypedArrayLike(typedArray, arg) {
441 // TODO(littledan): The spec requires that we actuallly use
442 // typedArray.constructor[Symbol.species] (bug v8:4093)
443 // Also, it should default to the default constructor from
444 // table 49 if typedArray.constructor doesn't exist.
445 return ConstructTypedArray(typedArray.constructor, arg);
446 }
447
448
449 function TypedArrayCopyWithin(target, start, end) { 463 function TypedArrayCopyWithin(target, start, end) {
450 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); 464 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
451 465
452 var length = %_TypedArrayGetLength(this); 466 var length = %_TypedArrayGetLength(this);
453 467
454 // TODO(littledan): Replace with a memcpy for better performance 468 // TODO(littledan): Replace with a memcpy for better performance
455 return InnerArrayCopyWithin(target, start, end, this, length); 469 return InnerArrayCopyWithin(target, start, end, this, length);
456 } 470 }
457 %FunctionSetLength(TypedArrayCopyWithin, 2); 471 %FunctionSetLength(TypedArrayCopyWithin, 2);
458 472
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 506
493 // ES6 draft 07-15-13, section 22.2.3.9 507 // ES6 draft 07-15-13, section 22.2.3.9
494 function TypedArrayFilter(f, thisArg) { 508 function TypedArrayFilter(f, thisArg) {
495 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); 509 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
496 510
497 var length = %_TypedArrayGetLength(this); 511 var length = %_TypedArrayGetLength(this);
498 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); 512 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
499 var result = new InternalArray(); 513 var result = new InternalArray();
500 InnerArrayFilter(f, thisArg, this, length, result); 514 InnerArrayFilter(f, thisArg, this, length, result);
501 var captured = result.length; 515 var captured = result.length;
502 var output = ConstructTypedArrayLike(this, captured); 516 var output = TypedArraySpeciesCreate(this, captured);
503 for (var i = 0; i < captured; i++) { 517 for (var i = 0; i < captured; i++) {
504 output[i] = result[i]; 518 output[i] = result[i];
505 } 519 }
506 return output; 520 return output;
507 } 521 }
508 %FunctionSetLength(TypedArrayFilter, 1); 522 %FunctionSetLength(TypedArrayFilter, 1);
509 523
510 524
511 // ES6 draft 07-15-13, section 22.2.3.10 525 // ES6 draft 07-15-13, section 22.2.3.10
512 function TypedArrayFind(predicate, thisArg) { 526 function TypedArrayFind(predicate, thisArg) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 %_ArgumentsLength()); 608 %_ArgumentsLength());
595 } 609 }
596 %FunctionSetLength(TypedArrayLastIndexOf, 1); 610 %FunctionSetLength(TypedArrayLastIndexOf, 1);
597 611
598 612
599 // ES6 draft 07-15-13, section 22.2.3.18 613 // ES6 draft 07-15-13, section 22.2.3.18
600 function TypedArrayMap(f, thisArg) { 614 function TypedArrayMap(f, thisArg) {
601 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); 615 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
602 616
603 var length = %_TypedArrayGetLength(this); 617 var length = %_TypedArrayGetLength(this);
604 var result = ConstructTypedArrayLike(this, length); 618 var result = TypedArraySpeciesCreate(this, length);
605 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f); 619 if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
606 for (var i = 0; i < length; i++) { 620 for (var i = 0; i < length; i++) {
607 var element = this[i]; 621 var element = this[i];
608 result[i] = %_Call(f, thisArg, element, i, this); 622 result[i] = %_Call(f, thisArg, element, i, this);
609 } 623 }
610 return result; 624 return result;
611 } 625 }
612 %FunctionSetLength(TypedArrayMap, 1); 626 %FunctionSetLength(TypedArrayMap, 1);
613 627
614 628
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 } 706 }
693 707
694 var final; 708 var final;
695 if (relativeEnd < 0) { 709 if (relativeEnd < 0) {
696 final = MaxSimple(len + relativeEnd, 0); 710 final = MaxSimple(len + relativeEnd, 0);
697 } else { 711 } else {
698 final = MinSimple(relativeEnd, len); 712 final = MinSimple(relativeEnd, len);
699 } 713 }
700 714
701 var count = MaxSimple(final - k, 0); 715 var count = MaxSimple(final - k, 0);
702 var array = ConstructTypedArrayLike(this, count); 716 var array = TypedArraySpeciesCreate(this, count);
703 // The code below is the 'then' branch; the 'else' branch species 717 // The code below is the 'then' branch; the 'else' branch species
704 // a memcpy. Because V8 doesn't canonicalize NaN, the difference is 718 // a memcpy. Because V8 doesn't canonicalize NaN, the difference is
705 // unobservable. 719 // unobservable.
706 var n = 0; 720 var n = 0;
707 while (k < final) { 721 while (k < final) {
708 var kValue = this[k]; 722 var kValue = this[k];
709 // TODO(littledan): The spec says to throw on an error in setting;
710 // does this throw?
711 array[n] = kValue; 723 array[n] = kValue;
712 k++; 724 k++;
713 n++; 725 n++;
714 } 726 }
715 return array; 727 return array;
716 } 728 }
717 729
718 730
719 // ES2016 draft, section 22.2.3.14 731 // ES2016 draft, section 22.2.3.14
720 function TypedArrayIncludes(searchElement, fromIndex) { 732 function TypedArrayIncludes(searchElement, fromIndex) {
721 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray); 733 if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
722 734
723 var length = %_TypedArrayGetLength(this); 735 var length = %_TypedArrayGetLength(this);
724 736
725 return InnerArrayIncludes(searchElement, fromIndex, this, length); 737 return InnerArrayIncludes(searchElement, fromIndex, this, length);
726 } 738 }
727 %FunctionSetLength(TypedArrayIncludes, 1); 739 %FunctionSetLength(TypedArrayIncludes, 1);
728 740
729 741
730 // ES6 draft 08-24-14, section 22.2.2.2 742 // ES6 draft 08-24-14, section 22.2.2.2
731 function TypedArrayOf() { 743 function TypedArrayOf() {
732 var length = %_ArgumentsLength(); 744 var length = %_ArgumentsLength();
733 var array = new this(length); 745 var array = TypedArrayCreate(this, length);
734 for (var i = 0; i < length; i++) { 746 for (var i = 0; i < length; i++) {
735 array[i] = %_Arguments(i); 747 array[i] = %_Arguments(i);
736 } 748 }
737 return array; 749 return array;
738 } 750 }
739 751
740 752
741 function TypedArrayFrom(source, mapfn, thisArg) { 753 function TypedArrayFrom(source, mapfn, thisArg) {
742 // TODO(littledan): Investigate if there is a receiver which could be 754 // TODO(littledan): Investigate if there is a receiver which could be
743 // faster to accumulate on than Array, e.g., a TypedVector. 755 // faster to accumulate on than Array, e.g., a TypedVector.
756 // TODO(littledan): Rewrite this code to ensure that things happen
757 // in the right order, e.g., the constructor needs to be called before
758 // the mapping function on array-likes.
744 var array = %_Call(ArrayFrom, GlobalArray, source, mapfn, thisArg); 759 var array = %_Call(ArrayFrom, GlobalArray, source, mapfn, thisArg);
745 return ConstructTypedArray(this, array); 760 return TypedArrayCreate(this, array);
746 } 761 }
747 %FunctionSetLength(TypedArrayFrom, 1); 762 %FunctionSetLength(TypedArrayFrom, 1);
748 763
749 function TypedArray() { 764 function TypedArray() {
750 if (IS_UNDEFINED(new.target)) { 765 if (IS_UNDEFINED(new.target)) {
751 throw MakeTypeError(kConstructorNonCallable, "TypedArray"); 766 throw MakeTypeError(kConstructorNonCallable, "TypedArray");
752 } 767 }
753 if (new.target === TypedArray) { 768 if (new.target === TypedArray) {
754 throw MakeTypeError(kConstructAbstractClass, "TypedArray"); 769 throw MakeTypeError(kConstructAbstractClass, "TypedArray");
755 } 770 }
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
944 "setUint32", DataViewSetUint32JS, 959 "setUint32", DataViewSetUint32JS,
945 960
946 "getFloat32", DataViewGetFloat32JS, 961 "getFloat32", DataViewGetFloat32JS,
947 "setFloat32", DataViewSetFloat32JS, 962 "setFloat32", DataViewSetFloat32JS,
948 963
949 "getFloat64", DataViewGetFloat64JS, 964 "getFloat64", DataViewGetFloat64JS,
950 "setFloat64", DataViewSetFloat64JS 965 "setFloat64", DataViewSetFloat64JS
951 ]); 966 ]);
952 967
953 }) 968 })
OLDNEW
« no previous file with comments | « src/js/runtime.js ('k') | src/messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698