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

Side by Side Diff: src/array.js

Issue 519061: Improve performance of Array.prototype.join and String.prototype.substring... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | src/macros.py » ('j') | test/mjsunit/fuzz-natives.js » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 } 63 }
64 } 64 }
65 keys.sort(function(a, b) { return a - b; }); 65 keys.sort(function(a, b) { return a - b; });
66 return keys; 66 return keys;
67 } 67 }
68 68
69 69
70 // Optimized for sparse arrays if separator is ''. 70 // Optimized for sparse arrays if separator is ''.
71 function SparseJoin(array, len, convert) { 71 function SparseJoin(array, len, convert) {
72 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); 72 var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
73 var builder = new StringBuilder();
74 var last_key = -1; 73 var last_key = -1;
75 var keys_length = keys.length; 74 var keys_length = keys.length;
75
76 var elements = new $Array(keys_length);
77 var elements_length = 0;
78
76 for (var i = 0; i < keys_length; i++) { 79 for (var i = 0; i < keys_length; i++) {
77 var key = keys[i]; 80 var key = keys[i];
78 if (key != last_key) { 81 if (key != last_key) {
79 var e = array[key]; 82 var e = array[key];
80 if (typeof(e) !== 'string') e = convert(e); 83 if (!IS_STRING(e)) e = convert(e);
81 builder.add(e); 84 elements[elements_length++] = e;
82 last_key = key; 85 last_key = key;
83 } 86 }
84 } 87 }
85 return builder.generate(); 88 return %StringBuilderConcat(elements, elements_length, '');
86 } 89 }
87 90
88 91
89 function UseSparseVariant(object, length, is_array) { 92 function UseSparseVariant(object, length, is_array) {
90 return is_array && 93 return is_array &&
91 length > 1000 && 94 length > 1000 &&
92 (!%_IsSmi(length) || 95 (!%_IsSmi(length) ||
93 %EstimateNumberOfElements(object) < (length >> 2)); 96 %EstimateNumberOfElements(object) < (length >> 2));
94 } 97 }
95 98
96 99
97 function Join(array, length, separator, convert) { 100 function Join(array, length, separator, convert) {
98 if (length == 0) return ''; 101 if (length == 0) return '';
99 102
100 var is_array = IS_ARRAY(array); 103 var is_array = IS_ARRAY(array);
101 104
102 if (is_array) { 105 if (is_array) {
103 // If the array is cyclic, return the empty string for already 106 // If the array is cyclic, return the empty string for already
104 // visited arrays. 107 // visited arrays.
105 if (!%PushIfAbsent(visited_arrays, array)) return ''; 108 if (!%PushIfAbsent(visited_arrays, array)) return '';
106 } 109 }
107 110
108 // Attempt to convert the elements. 111 // Attempt to convert the elements.
109 try { 112 try {
110 if (UseSparseVariant(array, length, is_array) && separator === '') { 113 if (UseSparseVariant(array, length, is_array) && (separator.length == 0)) {
Erik Corry 2010/01/06 14:03:57 I don't think the extra () around separator.length
111 return SparseJoin(array, length, convert); 114 return SparseJoin(array, length, convert);
112 } 115 }
113 116
114 // Fast case for one-element arrays. 117 // Fast case for one-element arrays.
115 if (length == 1) { 118 if (length == 1) {
116 var e = array[0]; 119 var e = array[0];
117 if (!IS_UNDEFINED(e) || (0 in array)) { 120 if (!IS_UNDEFINED(e) || (0 in array)) {
118 if (typeof(e) === 'string') return e; 121 if (IS_STRING(e)) return e;
119 return convert(e); 122 return convert(e);
120 } 123 }
121 } 124 }
122 125
123 var builder = new StringBuilder(); 126 // Construct an array for the elements.
127 var elements;
128 var elements_length = 0;
124 129
125 // We pull the empty separator check outside the loop for speed! 130 // We pull the empty separator check outside the loop for speed!
126 if (separator.length == 0) { 131 if (separator.length == 0) {
132 elements = new $Array(length);
127 for (var i = 0; i < length; i++) { 133 for (var i = 0; i < length; i++) {
128 var e = array[i]; 134 var e = array[i];
129 if (!IS_UNDEFINED(e) || (i in array)) { 135 if (!IS_UNDEFINED(e) || (i in array)) {
130 if (typeof(e) !== 'string') e = convert(e); 136 if (!IS_STRING(e)) e = convert(e);
131 if (e.length > 0) { 137 elements[elements_length++] = e;
132 var elements = builder.elements;
133 elements[elements.length] = e;
134 }
135 } 138 }
136 } 139 }
137 } else { 140 } else {
141 elements = new $Array(length << 1);
138 for (var i = 0; i < length; i++) { 142 for (var i = 0; i < length; i++) {
139 var e = array[i]; 143 var e = array[i];
140 if (i != 0) builder.add(separator); 144 if (i != 0) elements[elements_length++] = separator;
141 if (!IS_UNDEFINED(e) || (i in array)) { 145 if (!IS_UNDEFINED(e) || (i in array)) {
142 if (typeof(e) !== 'string') e = convert(e); 146 if (!IS_STRING(e)) e = convert(e);
143 if (e.length > 0) { 147 elements[elements_length++] = e;
144 var elements = builder.elements;
145 elements[elements.length] = e;
146 }
147 } 148 }
148 } 149 }
149 } 150 }
150 return builder.generate(); 151 return %StringBuilderConcat(elements, elements_length, '');
151 } finally { 152 } finally {
152 // Make sure to pop the visited array no matter what happens. 153 // Make sure to pop the visited array no matter what happens.
153 if (is_array) visited_arrays.pop(); 154 if (is_array) visited_arrays.pop();
154 } 155 }
155 } 156 }
156 157
157 158
158 function ConvertToString(e) { 159 function ConvertToString(e) {
159 if (typeof(e) === 'string') return e;
160 if (e == null) return ''; 160 if (e == null) return '';
161 else return ToString(e); 161 else return ToString(e);
162 } 162 }
163 163
164 164
165 function ConvertToLocaleString(e) { 165 function ConvertToLocaleString(e) {
166 if (typeof(e) === 'string') return e; 166 if (e == null) {
167 if (e == null) return ''; 167 return '';
168 else { 168 } else {
169 // e_obj's toLocaleString might be overwritten, check if it is a function. 169 // e_obj's toLocaleString might be overwritten, check if it is a function.
170 // Call ToString if toLocaleString is not a function. 170 // Call ToString if toLocaleString is not a function.
171 // See issue 877615. 171 // See issue 877615.
172 var e_obj = ToObject(e); 172 var e_obj = ToObject(e);
173 if (IS_FUNCTION(e_obj.toLocaleString)) 173 if (IS_FUNCTION(e_obj.toLocaleString))
174 return ToString(e_obj.toLocaleString()); 174 return ToString(e_obj.toLocaleString());
175 else 175 else
176 return ToString(e); 176 return ToString(e);
177 } 177 }
178 } 178 }
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 352
353 function ArrayToLocaleString() { 353 function ArrayToLocaleString() {
354 if (!IS_ARRAY(this)) { 354 if (!IS_ARRAY(this)) {
355 throw new $TypeError('Array.prototype.toString is not generic'); 355 throw new $TypeError('Array.prototype.toString is not generic');
356 } 356 }
357 return Join(this, this.length, ',', ConvertToLocaleString); 357 return Join(this, this.length, ',', ConvertToLocaleString);
358 } 358 }
359 359
360 360
361 function ArrayJoin(separator) { 361 function ArrayJoin(separator) {
362 if (IS_UNDEFINED(separator)) separator = ','; 362 if (IS_UNDEFINED(separator)) {
363 else separator = ToString(separator); 363 separator = ',';
364 return Join(this, ToUint32(this.length), separator, ConvertToString); 364 } else if (!IS_STRING(separator)) {
365 separator = ToString(separator);
366 }
367 var length = TO_UINT32(this.length);
368 return Join(this, length, separator, ConvertToString);
365 } 369 }
366 370
367 371
368 // Removes the last element from the array and returns it. See 372 // Removes the last element from the array and returns it. See
369 // ECMA-262, section 15.4.4.6. 373 // ECMA-262, section 15.4.4.6.
370 function ArrayPop() { 374 function ArrayPop() {
371 var n = ToUint32(this.length); 375 var n = TO_UINT32(this.length);
372 if (n == 0) { 376 if (n == 0) {
373 this.length = n; 377 this.length = n;
374 return; 378 return;
375 } 379 }
376 n--; 380 n--;
377 var value = this[n]; 381 var value = this[n];
378 this.length = n; 382 this.length = n;
379 delete this[n]; 383 delete this[n];
380 return value; 384 return value;
381 } 385 }
382 386
383 387
384 // Appends the arguments to the end of the array and returns the new 388 // Appends the arguments to the end of the array and returns the new
385 // length of the array. See ECMA-262, section 15.4.4.7. 389 // length of the array. See ECMA-262, section 15.4.4.7.
386 function ArrayPush() { 390 function ArrayPush() {
387 var n = ToUint32(this.length); 391 var n = TO_UINT32(this.length);
388 var m = %_ArgumentsLength(); 392 var m = %_ArgumentsLength();
389 for (var i = 0; i < m; i++) { 393 for (var i = 0; i < m; i++) {
390 this[i+n] = %_Arguments(i); 394 this[i+n] = %_Arguments(i);
391 } 395 }
392 this.length = n + m; 396 this.length = n + m;
393 return this.length; 397 return this.length;
394 } 398 }
395 399
396 400
397 function ArrayConcat(arg1) { // length == 1 401 function ArrayConcat(arg1) { // length == 1
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 if (!IS_UNDEFINED(current_j) || high in array) { 449 if (!IS_UNDEFINED(current_j) || high in array) {
446 array[low] = current_j; 450 array[low] = current_j;
447 delete array[high]; 451 delete array[high];
448 } 452 }
449 } 453 }
450 } 454 }
451 } 455 }
452 456
453 457
454 function ArrayReverse() { 458 function ArrayReverse() {
455 var j = ToUint32(this.length) - 1; 459 var j = TO_UINT32(this.length) - 1;
456 460
457 if (UseSparseVariant(this, j, IS_ARRAY(this))) { 461 if (UseSparseVariant(this, j, IS_ARRAY(this))) {
458 SparseReverse(this, j+1); 462 SparseReverse(this, j+1);
459 return this; 463 return this;
460 } 464 }
461 465
462 for (var i = 0; i < j; i++, j--) { 466 for (var i = 0; i < j; i++, j--) {
463 var current_i = this[i]; 467 var current_i = this[i];
464 if (!IS_UNDEFINED(current_i) || i in this) { 468 if (!IS_UNDEFINED(current_i) || i in this) {
465 var current_j = this[j]; 469 var current_j = this[j];
(...skipping 10 matching lines...) Expand all
476 this[i] = current_j; 480 this[i] = current_j;
477 delete this[j]; 481 delete this[j];
478 } 482 }
479 } 483 }
480 } 484 }
481 return this; 485 return this;
482 } 486 }
483 487
484 488
485 function ArrayShift() { 489 function ArrayShift() {
486 var len = ToUint32(this.length); 490 var len = TO_UINT32(this.length);
487 491
488 if (len === 0) { 492 if (len === 0) {
489 this.length = 0; 493 this.length = 0;
490 return; 494 return;
491 } 495 }
492 496
493 var first = this[0]; 497 var first = this[0];
494 498
495 if (IS_ARRAY(this)) 499 if (IS_ARRAY(this))
496 SmartMove(this, 0, 1, len, 0); 500 SmartMove(this, 0, 1, len, 0);
497 else 501 else
498 SimpleMove(this, 0, 1, len, 0); 502 SimpleMove(this, 0, 1, len, 0);
499 503
500 this.length = len - 1; 504 this.length = len - 1;
501 505
502 return first; 506 return first;
503 } 507 }
504 508
505 509
506 function ArrayUnshift(arg1) { // length == 1 510 function ArrayUnshift(arg1) { // length == 1
507 var len = ToUint32(this.length); 511 var len = TO_UINT32(this.length);
508 var num_arguments = %_ArgumentsLength(); 512 var num_arguments = %_ArgumentsLength();
509 513
510 if (IS_ARRAY(this)) 514 if (IS_ARRAY(this))
511 SmartMove(this, 0, 0, len, num_arguments); 515 SmartMove(this, 0, 0, len, num_arguments);
512 else 516 else
513 SimpleMove(this, 0, 0, len, num_arguments); 517 SimpleMove(this, 0, 0, len, num_arguments);
514 518
515 for (var i = 0; i < num_arguments; i++) { 519 for (var i = 0; i < num_arguments; i++) {
516 this[i] = %_Arguments(i); 520 this[i] = %_Arguments(i);
517 } 521 }
518 522
519 this.length = len + num_arguments; 523 this.length = len + num_arguments;
520 524
521 return len + num_arguments; 525 return len + num_arguments;
522 } 526 }
523 527
524 528
525 function ArraySlice(start, end) { 529 function ArraySlice(start, end) {
526 var len = ToUint32(this.length); 530 var len = TO_UINT32(this.length);
527 var start_i = TO_INTEGER(start); 531 var start_i = TO_INTEGER(start);
528 var end_i = len; 532 var end_i = len;
529 533
530 if (end !== void 0) end_i = TO_INTEGER(end); 534 if (end !== void 0) end_i = TO_INTEGER(end);
531 535
532 if (start_i < 0) { 536 if (start_i < 0) {
533 start_i += len; 537 start_i += len;
534 if (start_i < 0) start_i = 0; 538 if (start_i < 0) start_i = 0;
535 } else { 539 } else {
536 if (start_i > len) start_i = len; 540 if (start_i > len) start_i = len;
(...skipping 24 matching lines...) Expand all
561 565
562 function ArraySplice(start, delete_count) { 566 function ArraySplice(start, delete_count) {
563 var num_arguments = %_ArgumentsLength(); 567 var num_arguments = %_ArgumentsLength();
564 568
565 // SpiderMonkey and KJS return undefined in the case where no 569 // SpiderMonkey and KJS return undefined in the case where no
566 // arguments are given instead of using the implicit undefined 570 // arguments are given instead of using the implicit undefined
567 // arguments. This does not follow ECMA-262, but we do the same for 571 // arguments. This does not follow ECMA-262, but we do the same for
568 // compatibility. 572 // compatibility.
569 if (num_arguments == 0) return; 573 if (num_arguments == 0) return;
570 574
571 var len = ToUint32(this.length); 575 var len = TO_UINT32(this.length);
572 var start_i = TO_INTEGER(start); 576 var start_i = TO_INTEGER(start);
573 577
574 if (start_i < 0) { 578 if (start_i < 0) {
575 start_i += len; 579 start_i += len;
576 if (start_i < 0) start_i = 0; 580 if (start_i < 0) start_i = 0;
577 } else { 581 } else {
578 if (start_i > len) start_i = len; 582 if (start_i > len) start_i = len;
579 } 583 }
580 584
581 // SpiderMonkey and KJS treat the case where no delete count is 585 // SpiderMonkey and KJS treat the case where no delete count is
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 obj[i] = void 0; 847 obj[i] = void 0;
844 } else { 848 } else {
845 delete obj[i]; 849 delete obj[i];
846 } 850 }
847 } 851 }
848 852
849 // Return the number of defined elements. 853 // Return the number of defined elements.
850 return first_undefined; 854 return first_undefined;
851 } 855 }
852 856
853 length = ToUint32(this.length); 857 length = TO_UINT32(this.length);
854 if (length < 2) return this; 858 if (length < 2) return this;
855 859
856 var is_array = IS_ARRAY(this); 860 var is_array = IS_ARRAY(this);
857 var max_prototype_element; 861 var max_prototype_element;
858 if (!is_array) { 862 if (!is_array) {
859 // For compatibility with JSC, we also sort elements inherited from 863 // For compatibility with JSC, we also sort elements inherited from
860 // the prototype chain on non-Array objects. 864 // the prototype chain on non-Array objects.
861 // We do this by copying them to this object and sorting only 865 // We do this by copying them to this object and sorting only
862 // local elements. This is not very efficient, but sorting with 866 // local elements. This is not very efficient, but sorting with
863 // inherited elements happens very, very rarely, if at all. 867 // inherited elements happens very, very rarely, if at all.
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
1143 ArrayIndexOf: 1, 1147 ArrayIndexOf: 1,
1144 ArrayLastIndexOf: 1, 1148 ArrayLastIndexOf: 1,
1145 ArrayPush: 1, 1149 ArrayPush: 1,
1146 ArrayReduce: 1, 1150 ArrayReduce: 1,
1147 ArrayReduceRight: 1 1151 ArrayReduceRight: 1
1148 }); 1152 });
1149 } 1153 }
1150 1154
1151 1155
1152 SetupArray(); 1156 SetupArray();
OLDNEW
« no previous file with comments | « no previous file | src/macros.py » ('j') | test/mjsunit/fuzz-natives.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698