Upgrade V8 to 5.1.281.57 DO NOT MERGE
FPIIM-449
Change-Id: Id981b686b4d587ac31697662eb98bb34be42ad90
(cherry picked from commit 3b9bc31999c9787eb726ecdbfd5796bfdec32a18)
diff --git a/src/js/array-iterator.js b/src/js/array-iterator.js
index 2609ebd..b3e25e9 100644
--- a/src/js/array-iterator.js
+++ b/src/js/array-iterator.js
@@ -109,6 +109,24 @@
return CreateArrayIterator(this, ITERATOR_KIND_KEYS);
}
+// TODO(littledan): Check for detached TypedArray in these three methods
+function TypedArrayEntries() {
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
+ return %_Call(ArrayEntries, this);
+}
+
+
+function TypedArrayValues() {
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
+ return %_Call(ArrayValues, this);
+}
+
+
+function TypedArrayKeys() {
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
+ return %_Call(ArrayKeys, this);
+}
+
%FunctionSetPrototype(ArrayIterator, {__proto__: IteratorPrototype});
%FunctionSetInstanceClassName(ArrayIterator, 'Array Iterator');
@@ -117,8 +135,6 @@
'next', ArrayIteratorNext
]);
utils.SetFunctionName(ArrayIteratorIterator, iteratorSymbol);
-%AddNamedProperty(ArrayIterator.prototype, iteratorSymbol,
- ArrayIteratorIterator, DONT_ENUM);
%AddNamedProperty(ArrayIterator.prototype, toStringTagSymbol,
"Array Iterator", READ_ONLY | DONT_ENUM);
@@ -135,12 +151,13 @@
%AddNamedProperty(GlobalArray.prototype, iteratorSymbol, ArrayValues,
DONT_ENUM);
+utils.InstallFunctions(GlobalTypedArray.prototype, DONT_ENUM, [
+ 'entries', TypedArrayEntries,
+ 'keys', TypedArrayKeys,
+ 'values', TypedArrayValues
+]);
%AddNamedProperty(GlobalTypedArray.prototype,
- 'entries', ArrayEntries, DONT_ENUM);
-%AddNamedProperty(GlobalTypedArray.prototype, 'values', ArrayValues, DONT_ENUM);
-%AddNamedProperty(GlobalTypedArray.prototype, 'keys', ArrayKeys, DONT_ENUM);
-%AddNamedProperty(GlobalTypedArray.prototype,
- iteratorSymbol, ArrayValues, DONT_ENUM);
+ iteratorSymbol, TypedArrayValues, DONT_ENUM);
// -------------------------------------------------------------------
// Exports
diff --git a/src/js/array.js b/src/js/array.js
index 0a5e283..1406df3 100644
--- a/src/js/array.js
+++ b/src/js/array.js
@@ -73,17 +73,13 @@
}
}
+function KeySortCompare(a, b) {
+ return a - b;
+}
-// Global list of arrays visited during toString, toLocaleString and
-// join invocations.
-var visited_arrays = new InternalArray();
-
-
-// Gets a sorted array of array keys. Useful for operations on sparse
-// arrays. Dupes have not been removed.
function GetSortedArrayKeys(array, indices) {
- var keys = new InternalArray();
if (IS_NUMBER(indices)) {
+ var keys = new InternalArray();
// It's an interval
var limit = indices;
for (var i = 0; i < limit; ++i) {
@@ -92,61 +88,34 @@
keys.push(i);
}
}
- } else {
- var length = indices.length;
- for (var k = 0; k < length; ++k) {
- var key = indices[k];
- if (!IS_UNDEFINED(key)) {
- var e = array[key];
- if (!IS_UNDEFINED(e) || key in array) {
- keys.push(key);
- }
- }
- }
- keys.sort(function(a, b) { return a - b; });
+ return keys;
}
- return keys;
+ return InnerArraySort(indices, indices.length, KeySortCompare);
}
-function SparseJoinWithSeparatorJS(array, len, convert, separator) {
- var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
- var totalLength = 0;
- var elements = new InternalArray(keys.length * 2);
- var previousKey = -1;
- for (var i = 0; i < keys.length; i++) {
+function SparseJoinWithSeparatorJS(array, keys, length, convert, separator) {
+ var keys_length = keys.length;
+ var elements = new InternalArray(keys_length * 2);
+ for (var i = 0; i < keys_length; i++) {
var key = keys[i];
- if (key != previousKey) { // keys may contain duplicates.
- var e = array[key];
- if (!IS_STRING(e)) e = convert(e);
- elements[i * 2] = key;
- elements[i * 2 + 1] = e;
- previousKey = key;
- }
+ var e = array[key];
+ elements[i * 2] = key;
+ elements[i * 2 + 1] = IS_STRING(e) ? e : convert(e);
}
- return %SparseJoinWithSeparator(elements, len, separator);
+ return %SparseJoinWithSeparator(elements, length, separator);
}
// Optimized for sparse arrays if separator is ''.
-function SparseJoin(array, len, convert) {
- var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
- var last_key = -1;
+function SparseJoin(array, keys, convert) {
var keys_length = keys.length;
-
var elements = new InternalArray(keys_length);
- var elements_length = 0;
-
for (var i = 0; i < keys_length; i++) {
- var key = keys[i];
- if (key != last_key) {
- var e = array[key];
- if (!IS_STRING(e)) e = convert(e);
- elements[elements_length++] = e;
- last_key = key;
- }
+ var e = array[keys[i]];
+ elements[i] = IS_STRING(e) ? e : convert(e);
}
- return %StringBuilderConcat(elements, elements_length, '');
+ return %StringBuilderConcat(elements, keys_length, '');
}
@@ -167,94 +136,122 @@
(touched > estimated_elements * 4);
}
+function Stack() {
+ this.length = 0;
+ this.values = new InternalArray();
+}
+
+// Predeclare the instance variables on the prototype. Otherwise setting them in
+// the constructor will leak the instance through settings on Object.prototype.
+Stack.prototype.length = null;
+Stack.prototype.values = null;
+
+function StackPush(stack, value) {
+ stack.values[stack.length++] = value;
+}
+
+function StackPop(stack) {
+ stack.values[--stack.length] = null
+}
+
+function StackHas(stack, v) {
+ var length = stack.length;
+ var values = stack.values;
+ for (var i = 0; i < length; i++) {
+ if (values[i] === v) return true;
+ }
+ return false;
+}
+
+// Global list of arrays visited during toString, toLocaleString and
+// join invocations.
+var visited_arrays = new Stack();
+
+function DoJoin(array, length, is_array, separator, convert) {
+ if (UseSparseVariant(array, length, is_array, length)) {
+ %NormalizeElements(array);
+ var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length));
+ if (separator === '') {
+ if (keys.length === 0) return '';
+ return SparseJoin(array, keys, convert);
+ } else {
+ return SparseJoinWithSeparatorJS(array, keys, length, convert, separator);
+ }
+ }
+
+ // Fast case for one-element arrays.
+ if (length === 1) {
+ var e = array[0];
+ return IS_STRING(e) ? e : convert(e);
+ }
+
+ // Construct an array for the elements.
+ var elements = new InternalArray(length);
+
+ // We pull the empty separator check outside the loop for speed!
+ if (separator === '') {
+ for (var i = 0; i < length; i++) {
+ var e = array[i];
+ elements[i] = IS_STRING(e) ? e : convert(e);
+ }
+ return %StringBuilderConcat(elements, length, '');
+ }
+ // Non-empty separator case.
+ // If the first element is a number then use the heuristic that the
+ // remaining elements are also likely to be numbers.
+ var e = array[0];
+ if (IS_NUMBER(e)) {
+ elements[0] = %_NumberToString(e);
+ for (var i = 1; i < length; i++) {
+ e = array[i];
+ if (IS_NUMBER(e)) {
+ elements[i] = %_NumberToString(e);
+ } else {
+ elements[i] = IS_STRING(e) ? e : convert(e);
+ }
+ }
+ } else {
+ elements[0] = IS_STRING(e) ? e : convert(e);
+ for (var i = 1; i < length; i++) {
+ e = array[i];
+ elements[i] = IS_STRING(e) ? e : convert(e);
+ }
+ }
+ return %StringBuilderJoin(elements, length, separator);
+}
function Join(array, length, separator, convert) {
- if (length == 0) return '';
+ if (length === 0) return '';
var is_array = IS_ARRAY(array);
if (is_array) {
// If the array is cyclic, return the empty string for already
// visited arrays.
- if (!%PushIfAbsent(visited_arrays, array)) return '';
+ if (StackHas(visited_arrays, array)) return '';
+ StackPush(visited_arrays, array);
}
// Attempt to convert the elements.
try {
- if (UseSparseVariant(array, length, is_array, length)) {
- %NormalizeElements(array);
- if (separator.length == 0) {
- return SparseJoin(array, length, convert);
- } else {
- return SparseJoinWithSeparatorJS(array, length, convert, separator);
- }
- }
-
- // Fast case for one-element arrays.
- if (length == 1) {
- var e = array[0];
- if (IS_STRING(e)) return e;
- return convert(e);
- }
-
- // Construct an array for the elements.
- var elements = new InternalArray(length);
-
- // We pull the empty separator check outside the loop for speed!
- if (separator.length == 0) {
- var elements_length = 0;
- for (var i = 0; i < length; i++) {
- var e = array[i];
- if (!IS_STRING(e)) e = convert(e);
- elements[elements_length++] = e;
- }
- elements.length = elements_length;
- return %StringBuilderConcat(elements, elements_length, '');
- }
- // Non-empty separator case.
- // If the first element is a number then use the heuristic that the
- // remaining elements are also likely to be numbers.
- if (!IS_NUMBER(array[0])) {
- for (var i = 0; i < length; i++) {
- var e = array[i];
- if (!IS_STRING(e)) e = convert(e);
- elements[i] = e;
- }
- } else {
- for (var i = 0; i < length; i++) {
- var e = array[i];
- if (IS_NUMBER(e)) {
- e = %_NumberToString(e);
- } else if (!IS_STRING(e)) {
- e = convert(e);
- }
- elements[i] = e;
- }
- }
- return %StringBuilderJoin(elements, length, separator);
+ return DoJoin(array, length, is_array, separator, convert);
} finally {
// Make sure to remove the last element of the visited array no
// matter what happens.
- if (is_array) visited_arrays.length = visited_arrays.length - 1;
+ if (is_array) StackPop(visited_arrays);
}
}
function ConvertToString(x) {
- if (IS_NULL_OR_UNDEFINED(x)) {
- return '';
- } else {
- return TO_STRING(x);
- }
+ if (IS_NULL_OR_UNDEFINED(x)) return '';
+ return TO_STRING(x);
}
function ConvertToLocaleString(e) {
- if (IS_NULL_OR_UNDEFINED(e)) {
- return '';
- } else {
- return TO_STRING(e.toLocaleString());
- }
+ if (IS_NULL_OR_UNDEFINED(e)) return '';
+ return TO_STRING(e.toLocaleString());
}
@@ -275,12 +272,10 @@
var length = indices.length;
for (var k = 0; k < length; ++k) {
var key = indices[k];
- if (!IS_UNDEFINED(key)) {
- if (key >= start_i) {
- var current = array[key];
- if (!IS_UNDEFINED(current) || key in array) {
- DefineIndexedProperty(deleted_elements, key - start_i, current);
- }
+ if (key >= start_i) {
+ var current = array[key];
+ if (!IS_UNDEFINED(current) || key in array) {
+ DefineIndexedProperty(deleted_elements, key - start_i, current);
}
}
}
@@ -317,21 +312,19 @@
var length = indices.length;
for (var k = 0; k < length; ++k) {
var key = indices[k];
- if (!IS_UNDEFINED(key)) {
- if (key < start_i) {
- var current = array[key];
- if (!IS_UNDEFINED(current) || key in array) {
- new_array[key] = current;
- }
- } else if (key >= start_i + del_count) {
- var current = array[key];
- if (!IS_UNDEFINED(current) || key in array) {
- var new_key = key - del_count + num_additional_args;
- new_array[new_key] = current;
- if (new_key > 0xfffffffe) {
- big_indices = big_indices || new InternalArray();
- big_indices.push(new_key);
- }
+ if (key < start_i) {
+ var current = array[key];
+ if (!IS_UNDEFINED(current) || key in array) {
+ new_array[key] = current;
+ }
+ } else if (key >= start_i + del_count) {
+ var current = array[key];
+ if (!IS_UNDEFINED(current) || key in array) {
+ var new_key = key - del_count + num_additional_args;
+ new_array[new_key] = current;
+ if (new_key > 0xfffffffe) {
+ big_indices = big_indices || new InternalArray();
+ big_indices.push(new_key);
}
}
}
@@ -1069,8 +1062,7 @@
} else {
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
- if (!IS_UNDEFINED(index) && !HAS_OWN_PROPERTY(obj, index)
- && HAS_OWN_PROPERTY(proto, index)) {
+ if (!HAS_OWN_PROPERTY(obj, index) && HAS_OWN_PROPERTY(proto, index)) {
obj[index] = proto[index];
if (index >= max) { max = index + 1; }
}
@@ -1097,8 +1089,7 @@
} else {
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
- if (!IS_UNDEFINED(index) && from <= index &&
- HAS_OWN_PROPERTY(proto, index)) {
+ if (from <= index && HAS_OWN_PROPERTY(proto, index)) {
obj[index] = UNDEFINED;
}
}
@@ -1247,10 +1238,19 @@
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var is_array = IS_ARRAY(array);
- for (var i = 0; i < length; i++) {
- if (HAS_INDEX(array, i, is_array)) {
- var element = array[i];
- %_Call(f, receiver, element, i, array);
+ if (IS_UNDEFINED(receiver)) {
+ for (var i = 0; i < length; i++) {
+ if (HAS_INDEX(array, i, is_array)) {
+ var element = array[i];
+ f(element, i, array);
+ }
+ }
+ } else {
+ for (var i = 0; i < length; i++) {
+ if (HAS_INDEX(array, i, is_array)) {
+ var element = array[i];
+ %_Call(f, receiver, element, i, array);
+ }
}
}
}
@@ -1347,7 +1347,7 @@
if (IS_UNDEFINED(index)) {
index = 0;
} else {
- index = TO_INTEGER(index);
+ index = TO_INTEGER(index) + 0; // Add 0 to convert -0 to 0
// If index is negative, index from the end of the array.
if (index < 0) {
index = length + index;
@@ -1373,7 +1373,7 @@
while (i < n && sortedKeys[i] < index) i++;
while (i < n) {
var key = sortedKeys[i];
- if (!IS_UNDEFINED(key) && array[key] === element) return key;
+ if (array[key] === element) return key;
i++;
}
return -1;
@@ -1409,7 +1409,7 @@
if (argumentsLength < 2) {
index = length - 1;
} else {
- index = TO_INTEGER(index);
+ index = TO_INTEGER(index) + 0; // Add 0 to convert -0 to 0
// If index is negative, index from end of the array.
if (index < 0) index += length;
// If index is still negative, do not search the array.
@@ -1432,7 +1432,7 @@
var i = sortedKeys.length - 1;
while (i >= 0) {
var key = sortedKeys[i];
- if (!IS_UNDEFINED(key) && array[key] === element) return key;
+ if (array[key] === element) return key;
i--;
}
return -1;
@@ -1946,6 +1946,10 @@
to.InnerArraySort = InnerArraySort;
to.InnerArrayToLocaleString = InnerArrayToLocaleString;
to.PackedArrayReverse = PackedArrayReverse;
+ to.Stack = Stack;
+ to.StackHas = StackHas;
+ to.StackPush = StackPush;
+ to.StackPop = StackPop;
});
%InstallToContext([
diff --git a/src/js/harmony-atomics.js b/src/js/harmony-atomics.js
index b861a2a..9f80227 100644
--- a/src/js/harmony-atomics.js
+++ b/src/js/harmony-atomics.js
@@ -12,12 +12,14 @@
// Imports
var GlobalObject = global.Object;
+var MakeRangeError;
var MakeTypeError;
var MaxSimple;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) {
MakeTypeError = from.MakeTypeError;
+ MakeRangeError = from.MakeRangeError;
MaxSimple = from.MaxSimple;
});
@@ -37,14 +39,24 @@
}
}
+// https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess
+function ValidateIndex(index, length) {
+ var numberIndex = TO_NUMBER(index);
+ var accessIndex = TO_INTEGER(numberIndex);
+ if (numberIndex !== accessIndex) {
+ throw MakeRangeError(kInvalidAtomicAccessIndex);
+ }
+ if (accessIndex < 0 || accessIndex >= length) {
+ throw MakeRangeError(kInvalidAtomicAccessIndex);
+ }
+ return accessIndex;
+}
+
//-------------------------------------------------------------------
function AtomicsCompareExchangeJS(sta, index, oldValue, newValue) {
CheckSharedIntegerTypedArray(sta);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(sta)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(sta));
oldValue = TO_NUMBER(oldValue);
newValue = TO_NUMBER(newValue);
return %_AtomicsCompareExchange(sta, index, oldValue, newValue);
@@ -52,79 +64,55 @@
function AtomicsLoadJS(sta, index) {
CheckSharedIntegerTypedArray(sta);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(sta)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(sta));
return %_AtomicsLoad(sta, index);
}
function AtomicsStoreJS(sta, index, value) {
CheckSharedIntegerTypedArray(sta);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(sta)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(sta));
value = TO_NUMBER(value);
return %_AtomicsStore(sta, index, value);
}
function AtomicsAddJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsAdd(ia, index, value);
}
function AtomicsSubJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsSub(ia, index, value);
}
function AtomicsAndJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsAnd(ia, index, value);
}
function AtomicsOrJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsOr(ia, index, value);
}
function AtomicsXorJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsXor(ia, index, value);
}
function AtomicsExchangeJS(ia, index, value) {
CheckSharedIntegerTypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
value = TO_NUMBER(value);
return %_AtomicsExchange(ia, index, value);
}
@@ -137,10 +125,7 @@
function AtomicsFutexWaitJS(ia, index, value, timeout) {
CheckSharedInteger32TypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
if (IS_UNDEFINED(timeout)) {
timeout = INFINITY;
} else {
@@ -156,20 +141,17 @@
function AtomicsFutexWakeJS(ia, index, count) {
CheckSharedInteger32TypedArray(ia);
- index = TO_INTEGER(index);
- if (index < 0 || index >= %_TypedArrayGetLength(ia)) {
- return UNDEFINED;
- }
+ index = ValidateIndex(index, %_TypedArrayGetLength(ia));
count = MaxSimple(0, TO_INTEGER(count));
return %AtomicsFutexWake(ia, index, count);
}
function AtomicsFutexWakeOrRequeueJS(ia, index1, count, value, index2) {
CheckSharedInteger32TypedArray(ia);
- index1 = TO_INTEGER(index1);
+ index1 = ValidateIndex(index1, %_TypedArrayGetLength(ia));
count = MaxSimple(0, TO_INTEGER(count));
value = TO_INT32(value);
- index2 = TO_INTEGER(index2);
+ index2 = ValidateIndex(index2, %_TypedArrayGetLength(ia));
if (index1 < 0 || index1 >= %_TypedArrayGetLength(ia) ||
index2 < 0 || index2 >= %_TypedArrayGetLength(ia)) {
return UNDEFINED;
diff --git a/src/js/harmony-regexp-exec.js b/src/js/harmony-regexp-exec.js
new file mode 100644
index 0000000..e2eece9
--- /dev/null
+++ b/src/js/harmony-regexp-exec.js
@@ -0,0 +1,37 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function(global, utils) {
+
+%CheckIsBootstrapping();
+
+// -------------------------------------------------------------------
+// Imports
+
+var GlobalRegExp = global.RegExp;
+var RegExpSubclassExecJS = utils.ImportNow("RegExpSubclassExecJS");
+var RegExpSubclassMatch = utils.ImportNow("RegExpSubclassMatch");
+var RegExpSubclassReplace = utils.ImportNow("RegExpSubclassReplace");
+var RegExpSubclassSearch = utils.ImportNow("RegExpSubclassSearch");
+var RegExpSubclassSplit = utils.ImportNow("RegExpSubclassSplit");
+var RegExpSubclassTest = utils.ImportNow("RegExpSubclassTest");
+var matchSymbol = utils.ImportNow("match_symbol");
+var replaceSymbol = utils.ImportNow("replace_symbol");
+var searchSymbol = utils.ImportNow("search_symbol");
+var splitSymbol = utils.ImportNow("split_symbol");
+
+utils.OverrideFunction(GlobalRegExp.prototype, "exec",
+ RegExpSubclassExecJS, true);
+utils.OverrideFunction(GlobalRegExp.prototype, matchSymbol,
+ RegExpSubclassMatch, true);
+utils.OverrideFunction(GlobalRegExp.prototype, replaceSymbol,
+ RegExpSubclassReplace, true);
+utils.OverrideFunction(GlobalRegExp.prototype, searchSymbol,
+ RegExpSubclassSearch, true);
+utils.OverrideFunction(GlobalRegExp.prototype, splitSymbol,
+ RegExpSubclassSplit, true);
+utils.OverrideFunction(GlobalRegExp.prototype, "test",
+ RegExpSubclassTest, true);
+
+})
diff --git a/src/js/harmony-regexp.js b/src/js/harmony-regexp.js
deleted file mode 100644
index f76ef86..0000000
--- a/src/js/harmony-regexp.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(function(global, utils) {
-
-'use strict';
-
-%CheckIsBootstrapping();
-
-// -------------------------------------------------------------------
-// Imports
-
-var GlobalRegExp = global.RegExp;
-var GlobalRegExpPrototype = GlobalRegExp.prototype;
-var MakeTypeError;
-var regExpFlagsSymbol = utils.ImportNow("regexp_flags_symbol");
-
-utils.Import(function(from) {
- MakeTypeError = from.MakeTypeError;
-});
-
-// -------------------------------------------------------------------
-
-// ES6 draft 12-06-13, section 21.2.5.3
-// + https://bugs.ecmascript.org/show_bug.cgi?id=3423
-function RegExpGetFlags() {
- if (!IS_RECEIVER(this)) {
- throw MakeTypeError(
- kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this));
- }
- var result = '';
- if (this.global) result += 'g';
- if (this.ignoreCase) result += 'i';
- if (this.multiline) result += 'm';
- if (this.unicode) result += 'u';
- if (this.sticky) result += 'y';
- return result;
-}
-
-// ES6 21.2.5.12.
-function RegExpGetSticky() {
- if (!IS_REGEXP(this)) {
- // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
- // TODO(littledan): Remove this workaround or standardize it
- if (this === GlobalRegExpPrototype) {
- %IncrementUseCounter(kRegExpPrototypeStickyGetter);
- return UNDEFINED;
- }
- throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky");
- }
- return !!REGEXP_STICKY(this);
-}
-%FunctionSetName(RegExpGetSticky, "RegExp.prototype.sticky");
-%SetNativeFlag(RegExpGetSticky);
-
-utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags);
-utils.InstallGetter(GlobalRegExp.prototype, 'sticky', RegExpGetSticky);
-
-})
diff --git a/src/js/harmony-string-padding.js b/src/js/harmony-string-padding.js
new file mode 100644
index 0000000..a6c6c47
--- /dev/null
+++ b/src/js/harmony-string-padding.js
@@ -0,0 +1,77 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function(global, utils) {
+
+%CheckIsBootstrapping();
+
+// -------------------------------------------------------------------
+// Imports
+
+var GlobalString = global.String;
+var MakeTypeError;
+
+utils.Import(function(from) {
+ MakeTypeError = from.MakeTypeError;
+});
+
+// -------------------------------------------------------------------
+// http://tc39.github.io/proposal-string-pad-start-end/
+
+function StringPad(thisString, maxLength, fillString) {
+ maxLength = TO_LENGTH(maxLength);
+ var stringLength = thisString.length;
+
+ if (maxLength <= stringLength) return "";
+
+ if (IS_UNDEFINED(fillString)) {
+ fillString = " ";
+ } else {
+ fillString = TO_STRING(fillString);
+ if (fillString === "") {
+ fillString = " ";
+ }
+ }
+
+ var fillLength = maxLength - stringLength;
+ var repetitions = (fillLength / fillString.length) | 0;
+ var remainingChars = (fillLength - fillString.length * repetitions) | 0;
+
+ var filler = "";
+ while (true) {
+ if (repetitions & 1) filler += fillString;
+ repetitions >>= 1;
+ if (repetitions === 0) break;
+ fillString += fillString;
+ }
+
+ if (remainingChars) {
+ filler += %_SubString(fillString, 0, remainingChars);
+ }
+
+ return filler;
+}
+
+function StringPadStart(maxLength, fillString) {
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.padStart")
+ var thisString = TO_STRING(this);
+
+ return StringPad(thisString, maxLength, fillString) + thisString;
+}
+%FunctionSetLength(StringPadStart, 1);
+
+function StringPadEnd(maxLength, fillString) {
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.padEnd")
+ var thisString = TO_STRING(this);
+
+ return thisString + StringPad(thisString, maxLength, fillString);
+}
+%FunctionSetLength(StringPadEnd, 1);
+
+utils.InstallFunctions(GlobalString.prototype, DONT_ENUM, [
+ "padStart", StringPadStart,
+ "padEnd", StringPadEnd
+]);
+
+});
diff --git a/src/js/harmony-unicode-regexps.js b/src/js/harmony-unicode-regexps.js
index b24bbdf..16d06ba 100644
--- a/src/js/harmony-unicode-regexps.js
+++ b/src/js/harmony-unicode-regexps.js
@@ -31,10 +31,9 @@
}
throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.unicode");
}
- return !!REGEXP_UNICODE(this);
+ return TO_BOOLEAN(REGEXP_UNICODE(this));
}
-%FunctionSetName(RegExpGetUnicode, "RegExp.prototype.unicode");
-%SetNativeFlag(RegExpGetUnicode);
+%SetForceInlineFlag(RegExpGetUnicode);
utils.InstallGetter(GlobalRegExp.prototype, 'unicode', RegExpGetUnicode);
diff --git a/src/js/i18n.js b/src/js/i18n.js
index 7b2f5a1..845289a 100644
--- a/src/js/i18n.js
+++ b/src/js/i18n.js
@@ -20,26 +20,30 @@
var ArrayIndexOf;
var ArrayJoin;
var ArrayPush;
-var IsFinite;
-var IsNaN;
var GlobalBoolean = global.Boolean;
var GlobalDate = global.Date;
var GlobalNumber = global.Number;
var GlobalRegExp = global.RegExp;
var GlobalString = global.String;
+var InstallFunctions = utils.InstallFunctions;
+var InstallGetter = utils.InstallGetter;
+var InternalPackedArray = utils.InternalPackedArray;
+var InternalRegExpMatch;
+var InternalRegExpReplace
+var IsFinite;
+var IsNaN;
var MakeError;
var MakeRangeError;
var MakeTypeError;
-var MathFloor;
var ObjectDefineProperties = utils.ImportNow("ObjectDefineProperties");
var ObjectDefineProperty = utils.ImportNow("ObjectDefineProperty");
+var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
+var OverrideFunction = utils.OverrideFunction;
var patternSymbol = utils.ImportNow("intl_pattern_symbol");
-var RegExpTest;
var resolvedSymbol = utils.ImportNow("intl_resolved_symbol");
+var SetFunctionName = utils.SetFunctionName;
var StringIndexOf;
var StringLastIndexOf;
-var StringMatch;
-var StringReplace;
var StringSplit;
var StringSubstr;
var StringSubstring;
@@ -53,17 +57,72 @@
MakeError = from.MakeError;
MakeRangeError = from.MakeRangeError;
MakeTypeError = from.MakeTypeError;
- MathFloor = from.MathFloor;
- RegExpTest = from.RegExpTest;
+ InternalRegExpMatch = from.InternalRegExpMatch;
+ InternalRegExpReplace = from.InternalRegExpReplace;
StringIndexOf = from.StringIndexOf;
StringLastIndexOf = from.StringLastIndexOf;
- StringMatch = from.StringMatch;
- StringReplace = from.StringReplace;
StringSplit = from.StringSplit;
StringSubstr = from.StringSubstr;
StringSubstring = from.StringSubstring;
});
+// Utilities for definitions
+
+function InstallFunction(object, name, func) {
+ InstallFunctions(object, DONT_ENUM, [name, func]);
+}
+
+
+function InstallConstructor(object, name, func) {
+ %CheckIsBootstrapping();
+ SetFunctionName(func, name);
+ %AddNamedProperty(object, name, func, DONT_ENUM);
+ %SetNativeFlag(func);
+ %ToFastProperties(object);
+}
+
+/**
+ * Adds bound method to the prototype of the given object.
+ */
+function AddBoundMethod(obj, methodName, implementation, length) {
+ %CheckIsBootstrapping();
+ var internalName = %CreatePrivateSymbol(methodName);
+ var getter = function() {
+ if (!%IsInitializedIntlObject(this)) {
+ throw MakeTypeError(kMethodCalledOnWrongObject, methodName);
+ }
+ if (IS_UNDEFINED(this[internalName])) {
+ var boundMethod;
+ if (IS_UNDEFINED(length) || length === 2) {
+ boundMethod = (x, y) => implementation(this, x, y);
+ } else if (length === 1) {
+ boundMethod = x => implementation(this, x);
+ } else {
+ boundMethod = (...args) => {
+ // DateTimeFormat.format needs to be 0 arg method, but can stil
+ // receive optional dateValue param. If one was provided, pass it
+ // along.
+ if (args.length > 0) {
+ return implementation(this, args[0]);
+ } else {
+ return implementation(this);
+ }
+ }
+ }
+ // TODO(littledan): Once function name reform is shipped, remove the
+ // following line and wrap the boundMethod definition in an anonymous
+ // function macro.
+ %FunctionSetName(boundMethod, '__bound' + methodName + '__');
+ %FunctionRemovePrototype(boundMethod);
+ %SetNativeFlag(boundMethod);
+ this[internalName] = boundMethod;
+ }
+ return this[internalName];
+ };
+
+ InstallGetter(obj.prototype, methodName, getter, DONT_ENUM);
+}
+
// -------------------------------------------------------------------
var Intl = {};
@@ -197,74 +256,13 @@
return TIMEZONE_NAME_LOCATION_PART_RE;
}
-/**
- * Adds bound method to the prototype of the given object.
- */
-function addBoundMethod(obj, methodName, implementation, length) {
- %CheckIsBootstrapping();
- function getter() {
- if (!%IsInitializedIntlObject(this)) {
- throw MakeTypeError(kMethodCalledOnWrongObject, methodName);
- }
- var internalName = '__bound' + methodName + '__';
- if (IS_UNDEFINED(this[internalName])) {
- var that = this;
- var boundMethod;
- if (IS_UNDEFINED(length) || length === 2) {
- boundMethod = function(x, y) {
- if (!IS_UNDEFINED(new.target)) {
- throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
- }
- return implementation(that, x, y);
- }
- } else if (length === 1) {
- boundMethod = function(x) {
- if (!IS_UNDEFINED(new.target)) {
- throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
- }
- return implementation(that, x);
- }
- } else {
- boundMethod = function() {
- if (!IS_UNDEFINED(new.target)) {
- throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
- }
- // DateTimeFormat.format needs to be 0 arg method, but can stil
- // receive optional dateValue param. If one was provided, pass it
- // along.
- if (arguments.length > 0) {
- return implementation(that, arguments[0]);
- } else {
- return implementation(that);
- }
- }
- }
- %FunctionSetName(boundMethod, internalName);
- %FunctionRemovePrototype(boundMethod);
- %SetNativeFlag(boundMethod);
- this[internalName] = boundMethod;
- }
- return this[internalName];
- }
-
- %FunctionSetName(getter, methodName);
- %FunctionRemovePrototype(getter);
- %SetNativeFlag(getter);
-
- ObjectDefineProperty(obj.prototype, methodName, {
- get: getter,
- enumerable: false,
- configurable: true
- });
-}
-
/**
* Returns an intersection of locales and service supported locales.
* Parameter locales is treated as a priority list.
*/
function supportedLocalesOf(service, locales, options) {
- if (IS_NULL(%_Call(StringMatch, service, GetServiceRE()))) {
+ if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) {
throw MakeError(kWrongServiceType, service);
}
@@ -312,10 +310,8 @@
var matchedLocales = [];
for (var i = 0; i < requestedLocales.length; ++i) {
// Remove -u- extension.
- var locale = %_Call(StringReplace,
- requestedLocales[i],
- GetUnicodeExtensionRE(),
- '');
+ var locale = InternalRegExpReplace(
+ GetUnicodeExtensionRE(), requestedLocales[i], '');
do {
if (!IS_UNDEFINED(availableLocales[locale])) {
// Push requested locale not the resolved one.
@@ -421,7 +417,7 @@
* lookup algorithm.
*/
function lookupMatcher(service, requestedLocales) {
- if (IS_NULL(%_Call(StringMatch, service, GetServiceRE()))) {
+ if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) {
throw MakeError(kWrongServiceType, service);
}
@@ -432,13 +428,13 @@
for (var i = 0; i < requestedLocales.length; ++i) {
// Remove all extensions.
- var locale = %_Call(StringReplace, requestedLocales[i],
- GetAnyExtensionRE(), '');
+ var locale = InternalRegExpReplace(
+ GetAnyExtensionRE(), requestedLocales[i], '');
do {
if (!IS_UNDEFINED(AVAILABLE_LOCALES[service][locale])) {
// Return the resolved locale and extension.
- var extensionMatch =
- %_Call(StringMatch, requestedLocales[i], GetUnicodeExtensionRE());
+ var extensionMatch = InternalRegExpMatch(
+ GetUnicodeExtensionRE(), requestedLocales[i]);
var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0];
return {'locale': locale, 'extension': extension, 'position': i};
}
@@ -535,7 +531,7 @@
}
for (var key in keyValues) {
- if (%HasOwnProperty(keyValues, key)) {
+ if (HAS_OWN_PROPERTY(keyValues, key)) {
var value = UNDEFINED;
var map = keyValues[key];
if (!IS_UNDEFINED(map.property)) {
@@ -551,7 +547,7 @@
// User options didn't have it, check Unicode extension.
// Here we want to convert strings 'true', 'false' into proper Boolean
// values (not a user error).
- if (%HasOwnProperty(extensionMap, key)) {
+ if (HAS_OWN_PROPERTY(extensionMap, key)) {
value = extensionMap[key];
if (!IS_UNDEFINED(value)) {
updateProperty(map.property, map.type, value);
@@ -612,8 +608,8 @@
}
// Preserve extensions of resolved locale, but swap base tags with original.
- var resolvedBase = new GlobalRegExp('^' + locales[1].base);
- return %_Call(StringReplace, resolved, resolvedBase, locales[0].base);
+ var resolvedBase = new GlobalRegExp('^' + locales[1].base, 'g');
+ return InternalRegExpReplace(resolvedBase, resolved, locales[0].base);
}
@@ -627,10 +623,10 @@
var available = %AvailableLocalesOf(service);
for (var i in available) {
- if (%HasOwnProperty(available, i)) {
- var parts =
- %_Call(StringMatch, i, /^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/);
- if (parts !== null) {
+ if (HAS_OWN_PROPERTY(available, i)) {
+ var parts = InternalRegExpMatch(
+ /^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/, i);
+ if (!IS_NULL(parts)) {
// Build xx-ZZ. We don't care about the actual value,
// as long it's not undefined.
available[parts[1] + '-' + parts[3]] = null;
@@ -700,7 +696,7 @@
* 'of', 'au' and 'es' are special-cased and lowercased.
*/
function toTitleCaseTimezoneLocation(location) {
- var match = %_Call(StringMatch, location, GetTimezoneNameLocationPartRE());
+ var match = InternalRegExpMatch(GetTimezoneNameLocationPartRE(), location)
if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, location);
var result = toTitleCaseWord(match[1]);
@@ -797,7 +793,7 @@
*/
function isValidLanguageTag(locale) {
// Check if it's well-formed, including grandfadered tags.
- if (!%_Call(RegExpTest, GetLanguageTagRE(), locale)) {
+ if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) {
return false;
}
@@ -809,17 +805,17 @@
// Check if there are any duplicate variants or singletons (extensions).
// Remove private use section.
- locale = %_Call(StringSplit, locale, /-x-/)[0];
+ locale = %_Call(StringSplit, locale, '-x-')[0];
// Skip language since it can match variant regex, so we start from 1.
// We are matching i-klingon here, but that's ok, since i-klingon-klingon
// is not valid and would fail LANGUAGE_TAG_RE test.
var variants = [];
var extensions = [];
- var parts = %_Call(StringSplit, locale, /-/);
+ var parts = %_Call(StringSplit, locale, '-');
for (var i = 1; i < parts.length; i++) {
var value = parts[i];
- if (%_Call(RegExpTest, GetLanguageVariantRE(), value) &&
+ if (!IS_NULL(InternalRegExpMatch(GetLanguageVariantRE(), value)) &&
extensions.length === 0) {
if (%_Call(ArrayIndexOf, variants, value) === -1) {
%_Call(ArrayPush, variants, value);
@@ -828,7 +824,7 @@
}
}
- if (%_Call(RegExpTest, GetLanguageSingletonRE(), value)) {
+ if (!IS_NULL(InternalRegExpMatch(GetLanguageSingletonRE(), value))) {
if (%_Call(ArrayIndexOf, extensions, value) === -1) {
%_Call(ArrayPush, extensions, value);
} else {
@@ -943,7 +939,7 @@
var collation = 'default';
var extension = '';
- if (%HasOwnProperty(extensionMap, 'co') && internalOptions.usage === 'sort') {
+ if (HAS_OWN_PROPERTY(extensionMap, 'co') && internalOptions.usage === 'sort') {
/**
* Allowed -u-co- values. List taken from:
@@ -1001,7 +997,7 @@
*
* @constructor
*/
-%AddNamedProperty(Intl, 'Collator', function() {
+InstallConstructor(Intl, 'Collator', function() {
var locales = arguments[0];
var options = arguments[1];
@@ -1011,15 +1007,14 @@
}
return initializeCollator(TO_OBJECT(this), locales, options);
- },
- DONT_ENUM
+ }
);
/**
* Collator resolvedOptions method.
*/
-%AddNamedProperty(Intl.Collator.prototype, 'resolvedOptions', function() {
+InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
@@ -1041,12 +1036,8 @@
caseFirst: coll[resolvedSymbol].caseFirst,
collation: coll[resolvedSymbol].collation
};
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.Collator.prototype.resolvedOptions, 'resolvedOptions');
-%FunctionRemovePrototype(Intl.Collator.prototype.resolvedOptions);
-%SetNativeFlag(Intl.Collator.prototype.resolvedOptions);
/**
@@ -1055,18 +1046,14 @@
* order in the returned list as in the input list.
* Options are optional parameter.
*/
-%AddNamedProperty(Intl.Collator, 'supportedLocalesOf', function(locales) {
+InstallFunction(Intl.Collator, 'supportedLocalesOf', function(locales) {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
return supportedLocalesOf('collator', locales, arguments[1]);
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.Collator.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.Collator.supportedLocalesOf);
-%SetNativeFlag(Intl.Collator.supportedLocalesOf);
/**
@@ -1085,7 +1072,7 @@
};
-addBoundMethod(Intl.Collator, 'compare', compare, 2);
+AddBoundMethod(Intl.Collator, 'compare', compare, 2);
/**
* Verifies that the input is a well-formed ISO 4217 currency code.
@@ -1093,9 +1080,8 @@
* For example \u00DFP (Eszett+P) becomes SSP.
*/
function isWellFormedCurrencyCode(currency) {
- return typeof currency == "string" &&
- currency.length == 3 &&
- %_Call(StringMatch, currency, /[^A-Za-z]/) == null;
+ return typeof currency == "string" && currency.length == 3 &&
+ IS_NULL(InternalRegExpMatch(/[^A-Za-z]/, currency));
}
@@ -1110,7 +1096,7 @@
if (IsNaN(value) || value < min || value > max) {
throw MakeRangeError(kPropertyValueOutOfRange, property);
}
- return MathFloor(value);
+ return %math_floor(value);
}
return fallback;
@@ -1225,10 +1211,10 @@
style: {value: internalOptions.style, writable: true},
useGrouping: {writable: true}
});
- if (%HasOwnProperty(internalOptions, 'minimumSignificantDigits')) {
+ if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) {
defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED);
}
- if (%HasOwnProperty(internalOptions, 'maximumSignificantDigits')) {
+ if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) {
defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED);
}
var formatter = %CreateNumberFormat(requestedLocale,
@@ -1254,7 +1240,7 @@
*
* @constructor
*/
-%AddNamedProperty(Intl, 'NumberFormat', function() {
+InstallConstructor(Intl, 'NumberFormat', function() {
var locales = arguments[0];
var options = arguments[1];
@@ -1264,15 +1250,14 @@
}
return initializeNumberFormat(TO_OBJECT(this), locales, options);
- },
- DONT_ENUM
+ }
);
/**
* NumberFormat resolvedOptions method.
*/
-%AddNamedProperty(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
+InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
@@ -1301,24 +1286,19 @@
format[resolvedSymbol].currencyDisplay);
}
- if (%HasOwnProperty(format[resolvedSymbol], 'minimumSignificantDigits')) {
+ if (HAS_OWN_PROPERTY(format[resolvedSymbol], 'minimumSignificantDigits')) {
defineWECProperty(result, 'minimumSignificantDigits',
format[resolvedSymbol].minimumSignificantDigits);
}
- if (%HasOwnProperty(format[resolvedSymbol], 'maximumSignificantDigits')) {
+ if (HAS_OWN_PROPERTY(format[resolvedSymbol], 'maximumSignificantDigits')) {
defineWECProperty(result, 'maximumSignificantDigits',
format[resolvedSymbol].maximumSignificantDigits);
}
return result;
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.NumberFormat.prototype.resolvedOptions,
- 'resolvedOptions');
-%FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions);
-%SetNativeFlag(Intl.NumberFormat.prototype.resolvedOptions);
/**
@@ -1327,18 +1307,14 @@
* order in the returned list as in the input list.
* Options are optional parameter.
*/
-%AddNamedProperty(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
+InstallFunction(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
return supportedLocalesOf('numberformat', locales, arguments[1]);
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.NumberFormat.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.NumberFormat.supportedLocalesOf);
-%SetNativeFlag(Intl.NumberFormat.supportedLocalesOf);
/**
@@ -1364,8 +1340,8 @@
}
-addBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
-addBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
+AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
+AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
/**
* Returns a string that matches LDML representation of the options object.
@@ -1435,57 +1411,57 @@
*/
function fromLDMLString(ldmlString) {
// First remove '' quoted text, so we lose 'Uhr' strings.
- ldmlString = %_Call(StringReplace, ldmlString, GetQuotedStringRE(), '');
+ ldmlString = InternalRegExpReplace(GetQuotedStringRE(), ldmlString, '');
var options = {};
- var match = %_Call(StringMatch, ldmlString, /E{3,5}/g);
+ var match = InternalRegExpMatch(/E{3,5}/, ldmlString);
options = appendToDateTimeObject(
options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'});
- match = %_Call(StringMatch, ldmlString, /G{3,5}/g);
+ match = InternalRegExpMatch(/G{3,5}/, ldmlString);
options = appendToDateTimeObject(
options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'});
- match = %_Call(StringMatch, ldmlString, /y{1,2}/g);
+ match = InternalRegExpMatch(/y{1,2}/, ldmlString);
options = appendToDateTimeObject(
options, 'year', match, {y: 'numeric', yy: '2-digit'});
- match = %_Call(StringMatch, ldmlString, /M{1,5}/g);
+ match = InternalRegExpMatch(/M{1,5}/, ldmlString);
options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit',
M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'});
// Sometimes we get L instead of M for month - standalone name.
- match = %_Call(StringMatch, ldmlString, /L{1,5}/g);
+ match = InternalRegExpMatch(/L{1,5}/, ldmlString);
options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit',
L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'});
- match = %_Call(StringMatch, ldmlString, /d{1,2}/g);
+ match = InternalRegExpMatch(/d{1,2}/, ldmlString);
options = appendToDateTimeObject(
options, 'day', match, {d: 'numeric', dd: '2-digit'});
- match = %_Call(StringMatch, ldmlString, /h{1,2}/g);
+ match = InternalRegExpMatch(/h{1,2}/, ldmlString);
if (match !== null) {
options['hour12'] = true;
}
options = appendToDateTimeObject(
options, 'hour', match, {h: 'numeric', hh: '2-digit'});
- match = %_Call(StringMatch, ldmlString, /H{1,2}/g);
+ match = InternalRegExpMatch(/H{1,2}/, ldmlString);
if (match !== null) {
options['hour12'] = false;
}
options = appendToDateTimeObject(
options, 'hour', match, {H: 'numeric', HH: '2-digit'});
- match = %_Call(StringMatch, ldmlString, /m{1,2}/g);
+ match = InternalRegExpMatch(/m{1,2}/, ldmlString);
options = appendToDateTimeObject(
options, 'minute', match, {m: 'numeric', mm: '2-digit'});
- match = %_Call(StringMatch, ldmlString, /s{1,2}/g);
+ match = InternalRegExpMatch(/s{1,2}/, ldmlString);
options = appendToDateTimeObject(
options, 'second', match, {s: 'numeric', ss: '2-digit'});
- match = %_Call(StringMatch, ldmlString, /z|zzzz/g);
+ match = InternalRegExpMatch(/z|zzzz/, ldmlString);
options = appendToDateTimeObject(
options, 'timeZoneName', match, {z: 'short', zzzz: 'long'});
@@ -1495,7 +1471,7 @@
function appendToDateTimeObject(options, option, match, pairs) {
if (IS_NULL(match)) {
- if (!%HasOwnProperty(options, option)) {
+ if (!HAS_OWN_PROPERTY(options, option)) {
defineWEProperty(options, option, UNDEFINED);
}
return options;
@@ -1658,7 +1634,7 @@
*
* @constructor
*/
-%AddNamedProperty(Intl, 'DateTimeFormat', function() {
+InstallConstructor(Intl, 'DateTimeFormat', function() {
var locales = arguments[0];
var options = arguments[1];
@@ -1668,15 +1644,14 @@
}
return initializeDateTimeFormat(TO_OBJECT(this), locales, options);
- },
- DONT_ENUM
+ }
);
/**
* DateTimeFormat resolvedOptions method.
*/
-%AddNamedProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
+InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
@@ -1735,13 +1710,8 @@
addWECPropertyIfDefined(result, 'second', fromPattern.second);
return result;
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.DateTimeFormat.prototype.resolvedOptions,
- 'resolvedOptions');
-%FunctionRemovePrototype(Intl.DateTimeFormat.prototype.resolvedOptions);
-%SetNativeFlag(Intl.DateTimeFormat.prototype.resolvedOptions);
/**
@@ -1750,18 +1720,14 @@
* order in the returned list as in the input list.
* Options are optional parameter.
*/
-%AddNamedProperty(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) {
+InstallFunction(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
return supportedLocalesOf('dateformat', locales, arguments[1]);
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.DateTimeFormat.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.DateTimeFormat.supportedLocalesOf);
-%SetNativeFlag(Intl.DateTimeFormat.supportedLocalesOf);
/**
@@ -1797,8 +1763,8 @@
// 0 because date is optional argument.
-addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
-addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
+AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
+AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
/**
@@ -1822,7 +1788,7 @@
// We expect only _, '-' and / beside ASCII letters.
// All inputs should conform to Area/Location(/Location)* from now on.
- var match = %_Call(StringMatch, tzID, GetTimezoneNameCheckRE());
+ var match = InternalRegExpMatch(GetTimezoneNameCheckRE(), tzID);
if (IS_NULL(match)) throw MakeRangeError(kExpectedTimezoneID, tzID);
var result = toTitleCaseTimezoneLocation(match[1]) + '/' +
@@ -1885,7 +1851,7 @@
*
* @constructor
*/
-%AddNamedProperty(Intl, 'v8BreakIterator', function() {
+InstallConstructor(Intl, 'v8BreakIterator', function() {
var locales = arguments[0];
var options = arguments[1];
@@ -1895,15 +1861,14 @@
}
return initializeBreakIterator(TO_OBJECT(this), locales, options);
- },
- DONT_ENUM
+ }
);
/**
* BreakIterator resolvedOptions method.
*/
-%AddNamedProperty(Intl.v8BreakIterator.prototype, 'resolvedOptions',
+InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions',
function() {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
@@ -1922,13 +1887,8 @@
locale: locale,
type: segmenter[resolvedSymbol].type
};
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.v8BreakIterator.prototype.resolvedOptions,
- 'resolvedOptions');
-%FunctionRemovePrototype(Intl.v8BreakIterator.prototype.resolvedOptions);
-%SetNativeFlag(Intl.v8BreakIterator.prototype.resolvedOptions);
/**
@@ -1937,19 +1897,15 @@
* order in the returned list as in the input list.
* Options are optional parameter.
*/
-%AddNamedProperty(Intl.v8BreakIterator, 'supportedLocalesOf',
+InstallFunction(Intl.v8BreakIterator, 'supportedLocalesOf',
function(locales) {
if (!IS_UNDEFINED(new.target)) {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
return supportedLocalesOf('breakiterator', locales, arguments[1]);
- },
- DONT_ENUM
+ }
);
-%FunctionSetName(Intl.v8BreakIterator.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.v8BreakIterator.supportedLocalesOf);
-%SetNativeFlag(Intl.v8BreakIterator.supportedLocalesOf);
/**
@@ -1994,11 +1950,11 @@
}
-addBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
-addBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
-addBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
-addBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
-addBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
+AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
+AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
+AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
+AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
+AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
// Save references to Intl objects and methods we use, for added security.
var savedObjects = {
@@ -2036,18 +1992,6 @@
return new savedObjects[service](locales, useOptions);
}
-
-function OverrideFunction(object, name, f) {
- %CheckIsBootstrapping();
- ObjectDefineProperty(object, name, { value: f,
- writeable: true,
- configurable: true,
- enumerable: false });
- %FunctionSetName(f, name);
- %FunctionRemovePrototype(f);
- %SetNativeFlag(f);
-}
-
/**
* Compares this and that, and returns less than 0, 0 or greater than 0 value.
* Overrides the built-in method.
diff --git a/src/js/json.js b/src/js/json.js
index 73d7802..c6dbed9 100644
--- a/src/js/json.js
+++ b/src/js/json.js
@@ -19,6 +19,10 @@
var MaxSimple;
var MinSimple;
var ObjectHasOwnProperty;
+var Stack;
+var StackHas;
+var StackPop;
+var StackPush;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) {
@@ -26,6 +30,10 @@
MaxSimple = from.MaxSimple;
MinSimple = from.MinSimple;
ObjectHasOwnProperty = from.ObjectHasOwnProperty;
+ Stack = from.Stack;
+ StackHas = from.StackHas;
+ StackPop = from.StackPop;
+ StackPush = from.StackPush;
});
// -------------------------------------------------------------------
@@ -51,7 +59,9 @@
}
}
} else {
- for (var p of %object_keys(val)) {
+ var keys = %object_keys(val);
+ for (var i = 0; i < keys.length; i++) {
+ var p = keys[i];
var newElement = InternalizeJSONProperty(val, p, reviver);
if (IS_UNDEFINED(newElement)) {
%reflect_delete_property(val, p);
@@ -76,7 +86,8 @@
function SerializeArray(value, replacer, stack, indent, gap) {
- if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure);
+ if (StackHas(stack, value)) throw MakeTypeError(kCircularStructure);
+ StackPush(stack, value);
var stepback = indent;
indent += gap;
var partial = new InternalArray();
@@ -99,13 +110,14 @@
} else {
final = "[]";
}
- stack.pop();
+ StackPop(stack);
return final;
}
function SerializeObject(value, replacer, stack, indent, gap) {
- if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure);
+ if (StackHas(stack, value)) throw MakeTypeError(kCircularStructure);
+ StackPush(stack, value);
var stepback = indent;
indent += gap;
var partial = new InternalArray();
@@ -122,7 +134,9 @@
}
}
} else {
- for (var p of %object_keys(value)) {
+ var keys = %object_keys(value);
+ for (var i = 0; i < keys.length; i++) {
+ var p = keys[i];
var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
if (!IS_UNDEFINED(strP)) {
var member = %QuoteJSONString(p) + ":";
@@ -142,7 +156,7 @@
} else {
final = "{}";
}
- stack.pop();
+ StackPop(stack);
return final;
}
@@ -237,7 +251,7 @@
if (!IS_CALLABLE(replacer) && !property_list && !gap && !IS_PROXY(value)) {
return %BasicJSONStringify(value);
}
- return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
+ return JSONSerialize('', {'': value}, replacer, new Stack(), "", gap);
}
// -------------------------------------------------------------------
@@ -275,7 +289,7 @@
var holder = {};
holder[key] = object;
// No need to pass the actual holder since there is no replacer function.
- return JSONSerialize(key, holder, UNDEFINED, new InternalArray(), "", "");
+ return JSONSerialize(key, holder, UNDEFINED, new Stack(), "", "");
}
%InstallToContext(["json_serialize_adapter", JsonSerializeAdapter]);
diff --git a/src/js/macros.py b/src/js/macros.py
index b2a7856..a4c7f53 100644
--- a/src/js/macros.py
+++ b/src/js/macros.py
@@ -88,9 +88,9 @@
macro IS_SIMD_VALUE(arg) = (%IsSimdValue(arg));
macro IS_STRING(arg) = (typeof(arg) === 'string');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
-macro IS_STRONG(arg) = (%IsStrong(arg));
macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol');
macro IS_SYMBOL_WRAPPER(arg) = (%_ClassOf(arg) === 'Symbol');
+macro IS_TYPEDARRAY(arg) = (%_IsTypedArray(arg));
macro IS_UNDEFINED(arg) = (arg === (void 0));
macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap');
macro IS_WEAKSET(arg) = (%_ClassOf(arg) === 'WeakSet');
@@ -122,12 +122,12 @@
macro TO_PRIMITIVE_STRING(arg) = (%_ToPrimitive_String(arg));
macro TO_NAME(arg) = (%_ToName(arg));
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
-macro HAS_OWN_PROPERTY(arg, index) = (%_Call(ObjectHasOwnProperty, arg, index));
-macro HAS_INDEX(array, index, is_array) = ((is_array && %_HasFastPackedElements(%IS_VAR(array))) ? (index < array.length) : (index in array));
+macro HAS_OWN_PROPERTY(obj, key) = (%_Call(ObjectHasOwnProperty, obj, key));
+macro HAS_INDEX(array, index, is_array) = ((is_array && %_HasFastPackedElements(%IS_VAR(array)) && (index < array.length)) || (index in array));
# Private names.
macro IS_PRIVATE(sym) = (%SymbolIsPrivate(sym));
-macro HAS_PRIVATE(obj, sym) = (%HasOwnProperty(obj, sym));
+macro HAS_PRIVATE(obj, key) = HAS_OWN_PROPERTY(obj, key);
macro HAS_DEFINED_PRIVATE(obj, sym) = (!IS_UNDEFINED(obj[sym]));
macro GET_PRIVATE(obj, sym) = (obj[sym]);
macro SET_PRIVATE(obj, sym, val) = (obj[sym] = val);
@@ -255,7 +255,6 @@
define kForcedGC = 7;
define kSloppyMode = 8;
define kStrictMode = 9;
-define kStrongMode = 10;
define kRegExpPrototypeStickyGetter = 11;
define kRegExpPrototypeToString = 12;
define kRegExpPrototypeUnicodeGetter = 13;
@@ -265,3 +264,15 @@
define kPromiseChain = 17;
define kPromiseAccept = 18;
define kPromiseDefer = 19;
+define kHtmlCommentInExternalScript = 20;
+define kHtmlComment = 21;
+define kSloppyModeBlockScopedFunctionRedefinition = 22;
+define kForInInitializer = 23;
+define kArrayProtectorDirtied = 24;
+define kArraySpeciesModified = 25;
+define kArrayPrototypeConstructorModified = 26;
+define kArrayInstanceProtoModified = 27;
+define kArrayInstanceConstructorModified = 28;
+define kLegacyFunctionDeclaration = 29;
+define kRegExpPrototypeSourceGetter = 30;
+define kRegExpPrototypeOldFlagGetter = 31;
diff --git a/src/js/math.js b/src/js/math.js
index a698fd4..f8ad6b1 100644
--- a/src/js/math.js
+++ b/src/js/math.js
@@ -10,7 +10,6 @@
// -------------------------------------------------------------------
// Imports
-define kRandomBatchSize = 64;
// The first two slots are reserved to persist PRNG state.
define kRandomNumberStart = 2;
@@ -19,7 +18,7 @@
var GlobalObject = global.Object;
var InternalArray = utils.InternalArray;
var NaN = %GetRootNaN();
-var nextRandomIndex = kRandomBatchSize;
+var nextRandomIndex = 0;
var randomNumbers = UNDEFINED;
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
@@ -31,33 +30,13 @@
return (x > 0) ? x : 0 - x;
}
-// ECMA 262 - 15.8.2.2
-function MathAcosJS(x) {
- return %_MathAcos(+x);
-}
-
-// ECMA 262 - 15.8.2.3
-function MathAsinJS(x) {
- return %_MathAsin(+x);
-}
-
-// ECMA 262 - 15.8.2.4
-function MathAtanJS(x) {
- return %_MathAtan(+x);
-}
-
// ECMA 262 - 15.8.2.5
// The naming of y and x matches the spec, as does the order in which
// ToNumber (valueOf) is called.
function MathAtan2JS(y, x) {
y = +y;
x = +x;
- return %_MathAtan2(y, x);
-}
-
-// ECMA 262 - 15.8.2.6
-function MathCeil(x) {
- return -%_MathFloor(-x);
+ return %MathAtan2(y, x);
}
// ECMA 262 - 15.8.2.8
@@ -65,11 +44,6 @@
return %MathExpRT(TO_NUMBER(x));
}
-// ECMA 262 - 15.8.2.9
-function MathFloorJS(x) {
- return %_MathFloor(+x);
-}
-
// ECMA 262 - 15.8.2.10
function MathLog(x) {
return %_MathLogRT(TO_NUMBER(x));
@@ -82,34 +56,24 @@
// ECMA 262 - 15.8.2.14
function MathRandom() {
- if (nextRandomIndex >= kRandomBatchSize) {
+ // While creating a startup snapshot, %GenerateRandomNumbers returns a
+ // normal array containing a single random number, and has to be called for
+ // every new random number.
+ // Otherwise, it returns a pre-populated typed array of random numbers. The
+ // first two elements are reserved for the PRNG state.
+ if (nextRandomIndex <= kRandomNumberStart) {
randomNumbers = %GenerateRandomNumbers(randomNumbers);
- nextRandomIndex = kRandomNumberStart;
+ nextRandomIndex = randomNumbers.length;
}
- return randomNumbers[nextRandomIndex++];
+ return randomNumbers[--nextRandomIndex];
}
function MathRandomRaw() {
- if (nextRandomIndex >= kRandomBatchSize) {
+ if (nextRandomIndex <= kRandomNumberStart) {
randomNumbers = %GenerateRandomNumbers(randomNumbers);
- nextRandomIndex = kRandomNumberStart;
+ nextRandomIndex = randomNumbers.length;
}
- return %_DoubleLo(randomNumbers[nextRandomIndex++]) & 0x3FFFFFFF;
-}
-
-// ECMA 262 - 15.8.2.15
-function MathRound(x) {
- return %RoundNumber(TO_NUMBER(x));
-}
-
-// ECMA 262 - 15.8.2.17
-function MathSqrtJS(x) {
- return %_MathSqrt(+x);
-}
-
-// Non-standard extension.
-function MathImul(x, y) {
- return %NumberImul(TO_NUMBER(x), TO_NUMBER(y));
+ return %_DoubleLo(randomNumbers[--nextRandomIndex]) & 0x3FFFFFFF;
}
// ES6 draft 09-27-13, section 20.2.2.28.
@@ -121,23 +85,14 @@
return x;
}
-// ES6 draft 09-27-13, section 20.2.2.34.
-function MathTrunc(x) {
- x = +x;
- if (x > 0) return %_MathFloor(x);
- if (x < 0) return -%_MathFloor(-x);
- // -0, 0 or NaN.
- return x;
-}
-
// ES6 draft 09-27-13, section 20.2.2.5.
function MathAsinh(x) {
x = TO_NUMBER(x);
// Idempotent for NaN, +/-0 and +/-Infinity.
if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
- if (x > 0) return MathLog(x + %_MathSqrt(x * x + 1));
+ if (x > 0) return MathLog(x + %math_sqrt(x * x + 1));
// This is to prevent numerical errors caused by large negative x.
- return -MathLog(-x + %_MathSqrt(x * x + 1));
+ return -MathLog(-x + %math_sqrt(x * x + 1));
}
// ES6 draft 09-27-13, section 20.2.2.3.
@@ -146,7 +101,7 @@
if (x < 1) return NaN;
// Idempotent for NaN and +Infinity.
if (!NUMBER_IS_FINITE(x)) return x;
- return MathLog(x + %_MathSqrt(x + 1) * %_MathSqrt(x - 1));
+ return MathLog(x + %math_sqrt(x + 1) * %math_sqrt(x - 1));
}
// ES6 draft 09-27-13, section 20.2.2.7.
@@ -185,17 +140,7 @@
compensation = (preliminary - sum) - summand;
sum = preliminary;
}
- return %_MathSqrt(sum) * max;
-}
-
-// ES6 draft 09-27-13, section 20.2.2.16.
-function MathFroundJS(x) {
- return %MathFround(TO_NUMBER(x));
-}
-
-// ES6 draft 07-18-14, section 20.2.2.11
-function MathClz32JS(x) {
- return %_MathClz32(x >>> 0);
+ return %math_sqrt(sum) * max;
}
// ES6 draft 09-27-13, section 20.2.2.9.
@@ -213,7 +158,7 @@
endmacro
function CubeRoot(x) {
- var approx_hi = MathFloorJS(%_DoubleHi(x) / 3) + 0x2A9F7893;
+ var approx_hi = %math_floor(%_DoubleHi(x) / 3) + 0x2A9F7893;
var approx = %_ConstructDouble(approx_hi | 0, 0);
approx = NEWTON_ITERATION_CBRT(x, approx);
approx = NEWTON_ITERATION_CBRT(x, approx);
@@ -223,6 +168,10 @@
// -------------------------------------------------------------------
+%InstallToContext([
+ "math_pow", MathPowJS,
+]);
+
%AddNamedProperty(GlobalMath, toStringTagSymbol, "Math", READ_ONLY | DONT_ENUM);
// Set up math constants.
@@ -246,41 +195,22 @@
utils.InstallFunctions(GlobalMath, DONT_ENUM, [
"random", MathRandom,
"abs", MathAbs,
- "acos", MathAcosJS,
- "asin", MathAsinJS,
- "atan", MathAtanJS,
- "ceil", MathCeil,
"exp", MathExp,
- "floor", MathFloorJS,
"log", MathLog,
- "round", MathRound,
- "sqrt", MathSqrtJS,
"atan2", MathAtan2JS,
"pow", MathPowJS,
- "imul", MathImul,
"sign", MathSign,
- "trunc", MathTrunc,
"asinh", MathAsinh,
"acosh", MathAcosh,
"atanh", MathAtanh,
"hypot", MathHypot,
- "fround", MathFroundJS,
- "clz32", MathClz32JS,
"cbrt", MathCbrt
]);
%SetForceInlineFlag(MathAbs);
-%SetForceInlineFlag(MathAcosJS);
-%SetForceInlineFlag(MathAsinJS);
-%SetForceInlineFlag(MathAtanJS);
%SetForceInlineFlag(MathAtan2JS);
-%SetForceInlineFlag(MathCeil);
-%SetForceInlineFlag(MathClz32JS);
-%SetForceInlineFlag(MathFloorJS);
%SetForceInlineFlag(MathRandom);
%SetForceInlineFlag(MathSign);
-%SetForceInlineFlag(MathSqrtJS);
-%SetForceInlineFlag(MathTrunc);
// -------------------------------------------------------------------
// Exports
@@ -288,7 +218,6 @@
utils.Export(function(to) {
to.MathAbs = MathAbs;
to.MathExp = MathExp;
- to.MathFloor = MathFloorJS;
to.IntRandom = MathRandomRaw;
});
diff --git a/src/js/messages.js b/src/js/messages.js
index feb14d3..f8cb967 100644
--- a/src/js/messages.js
+++ b/src/js/messages.js
@@ -23,7 +23,6 @@
utils.ImportNow("call_site_position_symbol");
var callSiteStrictSymbol =
utils.ImportNow("call_site_strict_symbol");
-var FLAG_harmony_tostring;
var Float32x4ToString;
var formattedStackTraceSymbol =
utils.ImportNow("formatted_stack_trace_symbol");
@@ -34,6 +33,7 @@
var InternalArray = utils.InternalArray;
var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
var ObjectDefineProperty;
+var ObjectHasOwnProperty;
var ObjectToString = utils.ImportNow("object_to_string");
var Script = utils.ImportNow("Script");
var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
@@ -56,6 +56,7 @@
Int32x4ToString = from.Int32x4ToString;
Int8x16ToString = from.Int8x16ToString;
ObjectDefineProperty = from.ObjectDefineProperty;
+ ObjectHasOwnProperty = from.ObjectHasOwnProperty;
StringCharAt = from.StringCharAt;
StringIndexOf = from.StringIndexOf;
StringSubstring = from.StringSubstring;
@@ -65,10 +66,6 @@
Uint8x16ToString = from.Uint8x16ToString;
});
-utils.ImportFromExperimental(function(from) {
- FLAG_harmony_tostring = from.FLAG_harmony_tostring;
-});
-
// -------------------------------------------------------------------
var GlobalError;
@@ -85,13 +82,8 @@
if (IS_NULL(this)) return "[object Null]";
var O = TO_OBJECT(this);
var builtinTag = %_ClassOf(O);
- var tag;
- if (FLAG_harmony_tostring) {
- tag = %GetDataProperty(O, toStringTagSymbol);
- if (!IS_STRING(tag)) {
- tag = builtinTag;
- }
- } else {
+ var tag = %GetDataProperty(O, toStringTagSymbol);
+ if (!IS_STRING(tag)) {
tag = builtinTag;
}
return `[object ${tag}]`;
@@ -578,69 +570,90 @@
SET_PRIVATE(this, callSiteStrictSymbol, TO_BOOLEAN(strict_mode));
}
+function CheckCallSite(obj, name) {
+ if (!IS_RECEIVER(obj) || !HAS_PRIVATE(obj, callSiteFunctionSymbol)) {
+ throw MakeTypeError(kCallSiteMethod, name);
+ }
+}
+
function CallSiteGetThis() {
+ CheckCallSite(this, "getThis");
return GET_PRIVATE(this, callSiteStrictSymbol)
? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol);
}
function CallSiteGetFunction() {
+ CheckCallSite(this, "getFunction");
return GET_PRIVATE(this, callSiteStrictSymbol)
? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol);
}
function CallSiteGetPosition() {
+ CheckCallSite(this, "getPosition");
return GET_PRIVATE(this, callSitePositionSymbol);
}
function CallSiteGetTypeName() {
+ CheckCallSite(this, "getTypeName");
return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false);
}
function CallSiteIsToplevel() {
+ CheckCallSite(this, "isTopLevel");
return %CallSiteIsToplevelRT(this);
}
function CallSiteIsEval() {
+ CheckCallSite(this, "isEval");
return %CallSiteIsEvalRT(this);
}
function CallSiteGetEvalOrigin() {
+ CheckCallSite(this, "getEvalOrigin");
var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol));
return FormatEvalOrigin(script);
}
function CallSiteGetScriptNameOrSourceURL() {
+ CheckCallSite(this, "getScriptNameOrSourceURL");
return %CallSiteGetScriptNameOrSourceUrlRT(this);
}
function CallSiteGetFunctionName() {
// See if the function knows its own name
+ CheckCallSite(this, "getFunctionName");
return %CallSiteGetFunctionNameRT(this);
}
function CallSiteGetMethodName() {
// See if we can find a unique property on the receiver that holds
// this function.
+ CheckCallSite(this, "getMethodName");
return %CallSiteGetMethodNameRT(this);
}
function CallSiteGetFileName() {
+ CheckCallSite(this, "getFileName");
return %CallSiteGetFileNameRT(this);
}
function CallSiteGetLineNumber() {
+ CheckCallSite(this, "getLineNumber");
return %CallSiteGetLineNumberRT(this);
}
function CallSiteGetColumnNumber() {
+ CheckCallSite(this, "getColumnNumber");
return %CallSiteGetColumnNumberRT(this);
}
function CallSiteIsNative() {
+ CheckCallSite(this, "isNative");
return %CallSiteIsNativeRT(this);
}
function CallSiteIsConstructor() {
+ CheckCallSite(this, "isConstructor");
return %CallSiteIsConstructorRT(this);
}
diff --git a/src/js/prologue.js b/src/js/prologue.js
index 24225a0..f9589a5 100644
--- a/src/js/prologue.js
+++ b/src/js/prologue.js
@@ -126,6 +126,18 @@
}
+function OverrideFunction(object, name, f, afterInitialBootstrap) {
+ %CheckIsBootstrapping();
+ %ObjectDefineProperty(object, name, { value: f,
+ writeable: true,
+ configurable: true,
+ enumerable: false });
+ SetFunctionName(f, name);
+ if (!afterInitialBootstrap) %FunctionRemovePrototype(f);
+ %SetNativeFlag(f);
+}
+
+
// Prevents changes to the prototype of a built-in function.
// The "prototype" property of the function object is made non-configurable,
// and the prototype object is made non-extensible. The latter prevents
@@ -175,18 +187,26 @@
"GetMethod",
"IsNaN",
"MakeError",
+ "MakeRangeError",
"MakeTypeError",
"MapEntries",
"MapIterator",
"MapIteratorNext",
"MaxSimple",
"MinSimple",
+ "NumberIsInteger",
"ObjectDefineProperty",
"ObserveArrayMethods",
"ObserveObjectMethods",
"PromiseChain",
"PromiseDeferred",
"PromiseResolved",
+ "RegExpSubclassExecJS",
+ "RegExpSubclassMatch",
+ "RegExpSubclassReplace",
+ "RegExpSubclassSearch",
+ "RegExpSubclassSplit",
+ "RegExpSubclassTest",
"SetIterator",
"SetIteratorNext",
"SetValues",
@@ -206,6 +226,10 @@
"to_string_tag_symbol",
"object_to_string",
"species_symbol",
+ "match_symbol",
+ "replace_symbol",
+ "search_symbol",
+ "split_symbol",
];
var filtered_exports = {};
@@ -284,6 +308,7 @@
utils.InstallFunctions = InstallFunctions;
utils.InstallGetter = InstallGetter;
utils.InstallGetterSetter = InstallGetterSetter;
+utils.OverrideFunction = OverrideFunction;
utils.SetUpLockedPrototype = SetUpLockedPrototype;
utils.PostNatives = PostNatives;
utils.PostExperimentals = PostExperimentals;
@@ -323,14 +348,14 @@
// indirection and slowness given how un-optimized bind is.
extrasUtils.simpleBind = function simpleBind(func, thisArg) {
- return function() {
- return %Apply(func, thisArg, arguments, 0, arguments.length);
+ return function(...args) {
+ return %reflect_apply(func, thisArg, args);
};
};
extrasUtils.uncurryThis = function uncurryThis(func) {
- return function(thisArg) {
- return %Apply(func, thisArg, arguments, 1, arguments.length - 1);
+ return function(thisArg, ...args) {
+ return %reflect_apply(func, thisArg, args);
};
};
diff --git a/src/js/promise.js b/src/js/promise.js
index 8cf6a36..bcf826a 100644
--- a/src/js/promise.js
+++ b/src/js/promise.js
@@ -61,13 +61,13 @@
var GlobalPromise = function Promise(resolver) {
if (resolver === promiseRawSymbol) {
- return %NewObject(GlobalPromise, new.target);
+ return %_NewObject(GlobalPromise, new.target);
}
if (IS_UNDEFINED(new.target)) throw MakeTypeError(kNotAPromise, this);
if (!IS_CALLABLE(resolver))
throw MakeTypeError(kResolverNotAFunction, resolver);
- var promise = PromiseInit(%NewObject(GlobalPromise, new.target));
+ var promise = PromiseInit(%_NewObject(GlobalPromise, new.target));
var callbacks = CreateResolvingFunctions(promise);
try {
@@ -89,9 +89,6 @@
SET_PRIVATE(promise, promiseValueSymbol, value);
SET_PRIVATE(promise, promiseOnResolveSymbol, onResolve);
SET_PRIVATE(promise, promiseOnRejectSymbol, onReject);
- if (DEBUG_IS_ACTIVE) {
- %DebugPromiseEvent({ promise: promise, status: status, value: value });
- }
return promise;
}
@@ -217,8 +214,6 @@
PromiseDone(promise, -1, r, promiseOnRejectSymbol)
}
-// Convenience.
-
function NewPromiseCapability(C) {
if (C === GlobalPromise) {
// Optimized case, avoid extra closure.
@@ -239,6 +234,9 @@
result.reject = reject;
});
+ if (!IS_CALLABLE(result.resolve) || !IS_CALLABLE(result.reject))
+ throw MakeTypeError(kPromiseNonCallable);
+
return result;
}
@@ -305,9 +303,6 @@
}
// Mark this promise as having handler.
SET_PRIVATE(this, promiseHasHandlerSymbol, true);
- if (DEBUG_IS_ACTIVE) {
- %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
- }
return deferred.promise;
}
diff --git a/src/js/regexp.js b/src/js/regexp.js
index e80d019..cc8cb41 100644
--- a/src/js/regexp.js
+++ b/src/js/regexp.js
@@ -4,26 +4,37 @@
(function(global, utils) {
+'use strict';
+
%CheckIsBootstrapping();
// -------------------------------------------------------------------
// Imports
+var AddIndexedProperty;
var ExpandReplacement;
+var GlobalArray = global.Array;
var GlobalObject = global.Object;
var GlobalRegExp = global.RegExp;
var GlobalRegExpPrototype;
var InternalArray = utils.InternalArray;
var InternalPackedArray = utils.InternalPackedArray;
var MakeTypeError;
+var MaxSimple;
+var MinSimple;
var matchSymbol = utils.ImportNow("match_symbol");
var replaceSymbol = utils.ImportNow("replace_symbol");
var searchSymbol = utils.ImportNow("search_symbol");
var splitSymbol = utils.ImportNow("split_symbol");
+var SpeciesConstructor;
utils.Import(function(from) {
+ AddIndexedProperty = from.AddIndexedProperty;
ExpandReplacement = from.ExpandReplacement;
MakeTypeError = from.MakeTypeError;
+ MaxSimple = from.MaxSimple;
+ MinSimple = from.MinSimple;
+ SpeciesConstructor = from.SpeciesConstructor;
});
// -------------------------------------------------------------------
@@ -44,6 +55,7 @@
// -------------------------------------------------------------------
+// ES#sec-isregexp IsRegExp ( argument )
function IsRegExp(o) {
if (!IS_RECEIVER(o)) return false;
var is_regexp = o[matchSymbol];
@@ -52,7 +64,8 @@
}
-// ES6 section 21.2.3.2.2
+// ES#sec-regexpinitialize
+// Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
function RegExpInitialize(object, pattern, flags) {
pattern = IS_UNDEFINED(pattern) ? '' : TO_STRING(pattern);
flags = IS_UNDEFINED(flags) ? '' : TO_STRING(flags);
@@ -70,6 +83,8 @@
}
+// ES#sec-regexp-pattern-flags
+// RegExp ( pattern, flags )
function RegExpConstructor(pattern, flags) {
var newtarget = new.target;
var pattern_is_regexp = IsRegExp(pattern);
@@ -94,11 +109,12 @@
if (IS_UNDEFINED(flags)) flags = input_pattern.flags;
}
- var object = %NewObject(GlobalRegExp, newtarget);
+ var object = %_NewObject(GlobalRegExp, newtarget);
return RegExpInitialize(object, pattern, flags);
}
+// ES#sec-regexp.prototype.compile RegExp.prototype.compile (pattern, flags)
function RegExpCompileJS(pattern, flags) {
if (!IS_REGEXP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
@@ -163,6 +179,54 @@
}
+// ES#sec-regexp.prototype.exec
+// RegExp.prototype.exec ( string )
+function RegExpSubclassExecJS(string) {
+ if (!IS_REGEXP(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ 'RegExp.prototype.exec', this);
+ }
+
+ string = TO_STRING(string);
+ var lastIndex = this.lastIndex;
+
+ // Conversion is required by the ES2015 specification (RegExpBuiltinExec
+ // algorithm, step 4) even if the value is discarded for non-global RegExps.
+ var i = TO_LENGTH(lastIndex);
+
+ var global = TO_BOOLEAN(REGEXP_GLOBAL(this));
+ var sticky = TO_BOOLEAN(REGEXP_STICKY(this));
+ var updateLastIndex = global || sticky;
+ if (updateLastIndex) {
+ if (i > string.length) {
+ this.lastIndex = 0;
+ return null;
+ }
+ } else {
+ i = 0;
+ }
+
+ // matchIndices is either null or the RegExpLastMatchInfo array.
+ // TODO(littledan): Whether a RegExp is sticky is compiled into the RegExp
+ // itself, but ES2015 allows monkey-patching this property to differ from
+ // the internal flags. If it differs, recompile a different RegExp?
+ var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo);
+
+ if (IS_NULL(matchIndices)) {
+ this.lastIndex = 0;
+ return null;
+ }
+
+ // Successful match.
+ if (updateLastIndex) {
+ this.lastIndex = RegExpLastMatchInfo[CAPTURE1];
+ }
+ RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string);
+}
+%FunctionRemovePrototype(RegExpSubclassExecJS);
+
+
+// Legacy implementation of RegExp.prototype.exec
function RegExpExecJS(string) {
if (!IS_REGEXP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
@@ -202,10 +266,30 @@
}
+// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
+// Also takes an optional exec method in case our caller
+// has already fetched exec.
+function RegExpSubclassExec(regexp, string, exec) {
+ if (IS_UNDEFINED(exec)) {
+ exec = regexp.exec;
+ }
+ if (IS_CALLABLE(exec)) {
+ var result = %_Call(exec, regexp, string);
+ if (!IS_RECEIVER(result) && !IS_NULL(result)) {
+ throw MakeTypeError(kInvalidRegExpExecResult);
+ }
+ return result;
+ }
+ return %_Call(RegExpExecJS, regexp, string);
+}
+%SetForceInlineFlag(RegExpSubclassExec);
+
+
// One-element cache for the simplified test regexp.
var regexp_key;
var regexp_val;
+// Legacy implementation of RegExp.prototype.test
// Section 15.10.6.3 doesn't actually make sense, but the intention seems to be
// that test is defined in terms of String.prototype.exec. However, it probably
// means the original value of String.prototype.exec, which is what everybody
@@ -259,6 +343,19 @@
}
}
+
+// ES#sec-regexp.prototype.test RegExp.prototype.test ( S )
+function RegExpSubclassTest(string) {
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ 'RegExp.prototype.test', this);
+ }
+ string = TO_STRING(string);
+ var match = RegExpSubclassExec(this, string);
+ return !IS_NULL(match);
+}
+%FunctionRemovePrototype(RegExpSubclassTest);
+
function TrimRegExp(regexp) {
if (regexp_key !== regexp) {
regexp_key = regexp;
@@ -273,27 +370,14 @@
function RegExpToString() {
- if (!IS_REGEXP(this)) {
- // RegExp.prototype.toString() returns '/(?:)/' as a compatibility fix;
- // a UseCounter is incremented to track it.
- // TODO(littledan): Remove this workaround or standardize it
- if (this === GlobalRegExpPrototype) {
- %IncrementUseCounter(kRegExpPrototypeToString);
- return '/(?:)/';
- }
- if (!IS_RECEIVER(this)) {
- throw MakeTypeError(
- kIncompatibleMethodReceiver, 'RegExp.prototype.toString', this);
- }
- return '/' + TO_STRING(this.source) + '/' + TO_STRING(this.flags);
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(
+ kIncompatibleMethodReceiver, 'RegExp.prototype.toString', this);
}
- var result = '/' + REGEXP_SOURCE(this) + '/';
- if (REGEXP_GLOBAL(this)) result += 'g';
- if (REGEXP_IGNORE_CASE(this)) result += 'i';
- if (REGEXP_MULTILINE(this)) result += 'm';
- if (REGEXP_UNICODE(this)) result += 'u';
- if (REGEXP_STICKY(this)) result += 'y';
- return result;
+ if (this === GlobalRegExpPrototype) {
+ %IncrementUseCounter(kRegExpPrototypeToString);
+ }
+ return '/' + TO_STRING(this.source) + '/' + TO_STRING(this.flags);
}
@@ -306,7 +390,8 @@
}
-// ES6 21.2.5.11.
+// Legacy implementation of RegExp.prototype[Symbol.split] which
+// doesn't properly call the underlying exec, @@species methods
function RegExpSplit(string, limit) {
// TODO(yangguo): allow non-regexp receivers.
if (!IS_REGEXP(this)) {
@@ -380,9 +465,85 @@
}
-// ES6 21.2.5.6.
+// ES#sec-regexp.prototype-@@split
+// RegExp.prototype [ @@split ] ( string, limit )
+function RegExpSubclassSplit(string, limit) {
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "RegExp.prototype.@@split", this);
+ }
+ string = TO_STRING(string);
+ var constructor = SpeciesConstructor(this, GlobalRegExp);
+ var flags = TO_STRING(this.flags);
+
+ // TODO(adamk): this fast path is wrong with respect to this.global
+ // and this.sticky, but hopefully the spec will remove those gets
+ // and thus make the assumption of 'exec' having no side-effects
+ // more correct. Also, we doesn't ensure that 'exec' is actually
+ // a data property on RegExp.prototype.
+ var exec;
+ if (IS_REGEXP(this) && constructor === GlobalRegExp) {
+ exec = this.exec;
+ if (exec === RegExpSubclassExecJS) {
+ return %_Call(RegExpSplit, this, string, limit);
+ }
+ }
+
+ var unicode = %StringIndexOf(flags, 'u', 0) >= 0;
+ var sticky = %StringIndexOf(flags, 'y', 0) >= 0;
+ var newFlags = sticky ? flags : flags + "y";
+ var splitter = new constructor(this, newFlags);
+ var array = new GlobalArray();
+ var arrayIndex = 0;
+ var lim = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
+ var size = string.length;
+ var prevStringIndex = 0;
+ if (lim === 0) return array;
+ var result;
+ if (size === 0) {
+ result = RegExpSubclassExec(splitter, string);
+ if (IS_NULL(result)) AddIndexedProperty(array, 0, string);
+ return array;
+ }
+ var stringIndex = prevStringIndex;
+ while (stringIndex < size) {
+ splitter.lastIndex = stringIndex;
+ result = RegExpSubclassExec(splitter, string, exec);
+ // Ensure exec will be read again on the next loop through.
+ exec = UNDEFINED;
+ if (IS_NULL(result)) {
+ stringIndex += AdvanceStringIndex(string, stringIndex, unicode);
+ } else {
+ var end = MinSimple(TO_LENGTH(splitter.lastIndex), size);
+ if (end === stringIndex) {
+ stringIndex += AdvanceStringIndex(string, stringIndex, unicode);
+ } else {
+ AddIndexedProperty(
+ array, arrayIndex,
+ %_SubString(string, prevStringIndex, stringIndex));
+ arrayIndex++;
+ if (arrayIndex === lim) return array;
+ prevStringIndex = end;
+ var numberOfCaptures = MaxSimple(TO_LENGTH(result.length), 0);
+ for (var i = 1; i < numberOfCaptures; i++) {
+ AddIndexedProperty(array, arrayIndex, result[i]);
+ arrayIndex++;
+ if (arrayIndex === lim) return array;
+ }
+ stringIndex = prevStringIndex;
+ }
+ }
+ }
+ AddIndexedProperty(array, arrayIndex,
+ %_SubString(string, prevStringIndex, size));
+ return array;
+}
+%FunctionRemovePrototype(RegExpSubclassSplit);
+
+
+// Legacy implementation of RegExp.prototype[Symbol.match] which
+// doesn't properly call the underlying exec method
function RegExpMatch(string) {
- // TODO(yangguo): allow non-regexp receivers.
if (!IS_REGEXP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"RegExp.prototype.@@match", this);
@@ -396,7 +557,41 @@
}
-// ES6 21.2.5.8.
+// ES#sec-regexp.prototype-@@match
+// RegExp.prototype [ @@match ] ( string )
+function RegExpSubclassMatch(string) {
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "RegExp.prototype.@@match", this);
+ }
+ string = TO_STRING(string);
+ var global = this.global;
+ if (!global) return RegExpSubclassExec(this, string);
+ var unicode = this.unicode;
+ this.lastIndex = 0;
+ var array = new InternalArray();
+ var n = 0;
+ var result;
+ while (true) {
+ result = RegExpSubclassExec(this, string);
+ if (IS_NULL(result)) {
+ if (n === 0) return null;
+ break;
+ }
+ var matchStr = TO_STRING(result[0]);
+ array[n] = matchStr;
+ if (matchStr === "") SetAdvancedStringIndex(this, string, unicode);
+ n++;
+ }
+ var resultArray = [];
+ %MoveArrayContents(array, resultArray);
+ return resultArray;
+}
+%FunctionRemovePrototype(RegExpSubclassMatch);
+
+
+// Legacy implementation of RegExp.prototype[Symbol.replace] which
+// doesn't properly call the underlying exec method.
// TODO(lrn): This array will survive indefinitely if replace is never
// called again. However, it will be empty, since the contents are cleared
@@ -458,7 +653,7 @@
if (!%_IsSmi(elem)) {
// elem must be an Array.
// Use the apply argument as backing for global RegExp properties.
- var func_result = %Apply(replace, UNDEFINED, elem, 0, elem.length);
+ var func_result = %reflect_apply(replace, UNDEFINED, elem);
// Overwrite the i'th element in the results with the string we got
// back from the callback function.
res[i] = TO_STRING(func_result);
@@ -512,7 +707,7 @@
parameters[j] = index;
parameters[j + 1] = subject;
- replacement = %Apply(replace, UNDEFINED, parameters, 0, j + 2);
+ replacement = %reflect_apply(replace, UNDEFINED, parameters);
}
result += replacement; // The add method converts to string if necessary.
@@ -523,7 +718,6 @@
function RegExpReplace(string, replace) {
- // TODO(littledan): allow non-regexp receivers.
if (!IS_REGEXP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"RegExp.prototype.@@replace", this);
@@ -565,9 +759,206 @@
}
-// ES6 21.2.5.9.
+// ES#sec-getsubstitution
+// GetSubstitution(matched, str, position, captures, replacement)
+// Expand the $-expressions in the string and return a new string with
+// the result.
+// TODO(littledan): Call this function from String.prototype.replace instead
+// of the very similar ExpandReplacement in src/js/string.js
+function GetSubstitution(matched, string, position, captures, replacement) {
+ var matchLength = matched.length;
+ var stringLength = string.length;
+ var capturesLength = captures.length;
+ var tailPos = position + matchLength;
+ var result = "";
+ var pos, expansion, peek, next, scaledIndex, advance, newScaledIndex;
+
+ var next = %StringIndexOf(replacement, '$', 0);
+ if (next < 0) {
+ result += replacement;
+ return result;
+ }
+
+ if (next > 0) result += %_SubString(replacement, 0, next);
+
+ while (true) {
+ expansion = '$';
+ pos = next + 1;
+ if (pos < replacement.length) {
+ peek = %_StringCharCodeAt(replacement, pos);
+ if (peek == 36) { // $$
+ ++pos;
+ result += '$';
+ } else if (peek == 38) { // $& - match
+ ++pos;
+ result += matched;
+ } else if (peek == 96) { // $` - prefix
+ ++pos;
+ result += %_SubString(string, 0, position);
+ } else if (peek == 39) { // $' - suffix
+ ++pos;
+ result += %_SubString(string, tailPos, stringLength);
+ } else if (peek >= 48 && peek <= 57) {
+ // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
+ scaledIndex = (peek - 48);
+ advance = 1;
+ if (pos + 1 < replacement.length) {
+ next = %_StringCharCodeAt(replacement, pos + 1);
+ if (next >= 48 && next <= 57) {
+ newScaledIndex = scaledIndex * 10 + ((next - 48));
+ if (newScaledIndex < capturesLength) {
+ scaledIndex = newScaledIndex;
+ advance = 2;
+ }
+ }
+ }
+ if (scaledIndex != 0 && scaledIndex < capturesLength) {
+ var capture = captures[scaledIndex];
+ if (!IS_UNDEFINED(capture)) result += capture;
+ pos += advance;
+ } else {
+ result += '$';
+ }
+ } else {
+ result += '$';
+ }
+ } else {
+ result += '$';
+ }
+
+ // Go the the next $ in the replacement.
+ next = %StringIndexOf(replacement, '$', pos);
+
+ // Return if there are no more $ characters in the replacement. If we
+ // haven't reached the end, we need to append the suffix.
+ if (next < 0) {
+ if (pos < replacement.length) {
+ result += %_SubString(replacement, pos, replacement.length);
+ }
+ return result;
+ }
+
+ // Append substring between the previous and the next $ character.
+ if (next > pos) {
+ result += %_SubString(replacement, pos, next);
+ }
+ }
+ return result;
+}
+
+
+// ES#sec-advancestringindex
+// AdvanceStringIndex ( S, index, unicode )
+function AdvanceStringIndex(string, index, unicode) {
+ var increment = 1;
+ if (unicode) {
+ var first = %_StringCharCodeAt(string, index);
+ if (first >= 0xD800 && first <= 0xDBFF && string.length > index + 1) {
+ var second = %_StringCharCodeAt(string, index + 1);
+ if (second >= 0xDC00 && second <= 0xDFFF) {
+ increment = 2;
+ }
+ }
+ }
+ return increment;
+}
+
+
+function SetAdvancedStringIndex(regexp, string, unicode) {
+ var lastIndex = regexp.lastIndex;
+ regexp.lastIndex = lastIndex +
+ AdvanceStringIndex(string, lastIndex, unicode);
+}
+
+
+// ES#sec-regexp.prototype-@@replace
+// RegExp.prototype [ @@replace ] ( string, replaceValue )
+function RegExpSubclassReplace(string, replace) {
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "RegExp.prototype.@@replace", this);
+ }
+ string = TO_STRING(string);
+ var length = string.length;
+ var functionalReplace = IS_CALLABLE(replace);
+ if (!functionalReplace) replace = TO_STRING(replace);
+ var global = TO_BOOLEAN(this.global);
+ if (global) {
+ var unicode = TO_BOOLEAN(this.unicode);
+ this.lastIndex = 0;
+ }
+
+ // TODO(adamk): this fast path is wrong with respect to this.global
+ // and this.sticky, but hopefully the spec will remove those gets
+ // and thus make the assumption of 'exec' having no side-effects
+ // more correct. Also, we doesn't ensure that 'exec' is actually
+ // a data property on RegExp.prototype, nor does the fast path
+ // correctly handle lastIndex setting.
+ var exec;
+ if (IS_REGEXP(this)) {
+ exec = this.exec;
+ if (exec === RegExpSubclassExecJS) {
+ return %_Call(RegExpReplace, this, string, replace);
+ }
+ }
+
+ var results = new InternalArray();
+ var result, replacement;
+ while (true) {
+ result = RegExpSubclassExec(this, string, exec);
+ // Ensure exec will be read again on the next loop through.
+ exec = UNDEFINED;
+ if (IS_NULL(result)) {
+ break;
+ } else {
+ results.push(result);
+ if (!global) break;
+ var matchStr = TO_STRING(result[0]);
+ if (matchStr === "") SetAdvancedStringIndex(this, string, unicode);
+ }
+ }
+ var accumulatedResult = "";
+ var nextSourcePosition = 0;
+ for (var i = 0; i < results.length; i++) {
+ result = results[i];
+ var capturesLength = MaxSimple(TO_LENGTH(result.length), 0);
+ var matched = TO_STRING(result[0]);
+ var matchedLength = matched.length;
+ var position = MaxSimple(MinSimple(TO_INTEGER(result.index), length), 0);
+ var captures = new InternalArray();
+ for (var n = 0; n < capturesLength; n++) {
+ var capture = result[n];
+ if (!IS_UNDEFINED(capture)) capture = TO_STRING(capture);
+ captures[n] = capture;
+ }
+ if (functionalReplace) {
+ var parameters = new InternalArray(capturesLength + 2);
+ for (var j = 0; j < capturesLength; j++) {
+ parameters[j] = captures[j];
+ }
+ parameters[j] = position;
+ parameters[j + 1] = string;
+ replacement = %reflect_apply(replace, UNDEFINED, parameters, 0,
+ parameters.length);
+ } else {
+ replacement = GetSubstitution(matched, string, position, captures,
+ replace);
+ }
+ if (position >= nextSourcePosition) {
+ accumulatedResult +=
+ %_SubString(string, nextSourcePosition, position) + replacement;
+ nextSourcePosition = position + matchedLength;
+ }
+ }
+ if (nextSourcePosition >= length) return accumulatedResult;
+ return accumulatedResult + %_SubString(string, nextSourcePosition, length);
+}
+%FunctionRemovePrototype(RegExpSubclassReplace);
+
+
+// Legacy implementation of RegExp.prototype[Symbol.search] which
+// doesn't properly use the overridden exec method
function RegExpSearch(string) {
- // TODO(yangguo): allow non-regexp receivers.
if (!IS_REGEXP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"RegExp.prototype.@@search", this);
@@ -578,6 +969,24 @@
}
+// ES#sec-regexp.prototype-@@search
+// RegExp.prototype [ @@search ] ( string )
+function RegExpSubclassSearch(string) {
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(kIncompatibleMethodReceiver,
+ "RegExp.prototype.@@search", this);
+ }
+ string = TO_STRING(string);
+ var previousLastIndex = this.lastIndex;
+ this.lastIndex = 0;
+ var result = RegExpSubclassExec(this, string);
+ this.lastIndex = previousLastIndex;
+ if (IS_NULL(result)) return -1;
+ return result.index;
+}
+%FunctionRemovePrototype(RegExpSubclassSearch);
+
+
// Getters for the static properties lastMatch, lastParen, leftContext, and
// rightContext of the RegExp constructor. The properties are computed based
// on the captures array of the last successful match and the subject string
@@ -639,19 +1048,35 @@
}
+// ES6 21.2.5.3.
+function RegExpGetFlags() {
+ if (!IS_RECEIVER(this)) {
+ throw MakeTypeError(
+ kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this));
+ }
+ var result = '';
+ if (this.global) result += 'g';
+ if (this.ignoreCase) result += 'i';
+ if (this.multiline) result += 'm';
+ if (this.unicode) result += 'u';
+ if (this.sticky) result += 'y';
+ return result;
+}
+
+
// ES6 21.2.5.4.
function RegExpGetGlobal() {
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
+ %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
return UNDEFINED;
}
throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global");
}
- return !!REGEXP_GLOBAL(this);
+ return TO_BOOLEAN(REGEXP_GLOBAL(this));
}
-%FunctionSetName(RegExpGetGlobal, "RegExp.prototype.global");
-%SetNativeFlag(RegExpGetGlobal);
+%SetForceInlineFlag(RegExpGetGlobal);
// ES6 21.2.5.5.
@@ -659,14 +1084,13 @@
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
+ %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
return UNDEFINED;
}
throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase");
}
- return !!REGEXP_IGNORE_CASE(this);
+ return TO_BOOLEAN(REGEXP_IGNORE_CASE(this));
}
-%FunctionSetName(RegExpGetIgnoreCase, "RegExp.prototype.ignoreCase");
-%SetNativeFlag(RegExpGetIgnoreCase);
// ES6 21.2.5.7.
@@ -674,14 +1098,13 @@
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
+ %IncrementUseCounter(kRegExpPrototypeOldFlagGetter);
return UNDEFINED;
}
throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline");
}
- return !!REGEXP_MULTILINE(this);
+ return TO_BOOLEAN(REGEXP_MULTILINE(this));
}
-%FunctionSetName(RegExpGetMultiline, "RegExp.prototype.multiline");
-%SetNativeFlag(RegExpGetMultiline);
// ES6 21.2.5.10.
@@ -689,14 +1112,29 @@
if (!IS_REGEXP(this)) {
// TODO(littledan): Remove this RegExp compat workaround
if (this === GlobalRegExpPrototype) {
- return UNDEFINED;
+ %IncrementUseCounter(kRegExpPrototypeSourceGetter);
+ return "(?:)";
}
throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source");
}
return REGEXP_SOURCE(this);
}
-%FunctionSetName(RegExpGetSource, "RegExp.prototype.source");
-%SetNativeFlag(RegExpGetSource);
+
+
+// ES6 21.2.5.12.
+function RegExpGetSticky() {
+ if (!IS_REGEXP(this)) {
+ // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it
+ // TODO(littledan): Remove this workaround or standardize it
+ if (this === GlobalRegExpPrototype) {
+ %IncrementUseCounter(kRegExpPrototypeStickyGetter);
+ return UNDEFINED;
+ }
+ throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky");
+ }
+ return TO_BOOLEAN(REGEXP_STICKY(this));
+}
+%SetForceInlineFlag(RegExpGetSticky);
// -------------------------------------------------------------------
@@ -718,10 +1156,12 @@
splitSymbol, RegExpSplit,
]);
+utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags);
utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal);
utils.InstallGetter(GlobalRegExp.prototype, 'ignoreCase', RegExpGetIgnoreCase);
utils.InstallGetter(GlobalRegExp.prototype, 'multiline', RegExpGetMultiline);
utils.InstallGetter(GlobalRegExp.prototype, 'source', RegExpGetSource);
+utils.InstallGetter(GlobalRegExp.prototype, 'sticky', RegExpGetSticky);
// The properties `input` and `$_` are aliases for each other. When this
// value is set the value it is set to is coerced to a string.
@@ -769,12 +1209,39 @@
%ToFastProperties(GlobalRegExp);
// -------------------------------------------------------------------
+// Internal
+
+var InternalRegExpMatchInfo = new InternalPackedArray(2, "", UNDEFINED, 0, 0);
+
+function InternalRegExpMatch(regexp, subject) {
+ var matchInfo = %_RegExpExec(regexp, subject, 0, InternalRegExpMatchInfo);
+ if (!IS_NULL(matchInfo)) {
+ RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, subject);
+ }
+ return null;
+}
+
+function InternalRegExpReplace(regexp, subject, replacement) {
+ return %StringReplaceGlobalRegExpWithString(
+ subject, regexp, replacement, InternalRegExpMatchInfo);
+}
+
+// -------------------------------------------------------------------
// Exports
utils.Export(function(to) {
+ to.InternalRegExpMatch = InternalRegExpMatch;
+ to.InternalRegExpReplace = InternalRegExpReplace;
+ to.IsRegExp = IsRegExp;
to.RegExpExec = DoRegExpExec;
- to.RegExpExecNoTests = RegExpExecNoTests;
+ to.RegExpInitialize = RegExpInitialize;
to.RegExpLastMatchInfo = RegExpLastMatchInfo;
+ to.RegExpSubclassExecJS = RegExpSubclassExecJS;
+ to.RegExpSubclassMatch = RegExpSubclassMatch;
+ to.RegExpSubclassReplace = RegExpSubclassReplace;
+ to.RegExpSubclassSearch = RegExpSubclassSearch;
+ to.RegExpSubclassSplit = RegExpSubclassSplit;
+ to.RegExpSubclassTest = RegExpSubclassTest;
to.RegExpTest = RegExpTest;
});
diff --git a/src/js/runtime.js b/src/js/runtime.js
index 7a61094..8e4f283 100644
--- a/src/js/runtime.js
+++ b/src/js/runtime.js
@@ -42,14 +42,6 @@
---------------------------------
*/
-function ConcatIterableToArray(target, iterable) {
- var index = target.length;
- for (var element of iterable) {
- AddIndexedProperty(target, index++, element);
- }
- return target;
-}
-
// This function should be called rather than %AddElement in contexts where the
// argument might not be less than 2**32-1. ES2015 ToLength semantics mean that
@@ -137,8 +129,4 @@
to.SpeciesConstructor = SpeciesConstructor;
});
-%InstallToContext([
- "concat_iterable_to_array", ConcatIterableToArray,
-]);
-
})
diff --git a/src/js/string-iterator.js b/src/js/string-iterator.js
index 3c331dd..af9af31 100644
--- a/src/js/string-iterator.js
+++ b/src/js/string-iterator.js
@@ -32,6 +32,7 @@
// 21.1.5.1 CreateStringIterator Abstract Operation
function CreateStringIterator(string) {
+ CHECK_OBJECT_COERCIBLE(string, 'String.prototype[Symbol.iterator]');
var s = TO_STRING(string);
var iterator = new StringIterator;
SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol, s);
diff --git a/src/js/string.js b/src/js/string.js
index a401978..0eb394e 100644
--- a/src/js/string.js
+++ b/src/js/string.js
@@ -15,12 +15,13 @@
var GlobalString = global.String;
var InternalArray = utils.InternalArray;
var InternalPackedArray = utils.InternalPackedArray;
+var IsRegExp;
var MakeRangeError;
var MakeTypeError;
var MaxSimple;
var MinSimple;
+var RegExpInitialize;
var matchSymbol = utils.ImportNow("match_symbol");
-var RegExpExecNoTests;
var replaceSymbol = utils.ImportNow("replace_symbol");
var searchSymbol = utils.ImportNow("search_symbol");
var splitSymbol = utils.ImportNow("split_symbol");
@@ -28,11 +29,12 @@
utils.Import(function(from) {
ArrayIndexOf = from.ArrayIndexOf;
ArrayJoin = from.ArrayJoin;
+ IsRegExp = from.IsRegExp;
MakeRangeError = from.MakeRangeError;
MakeTypeError = from.MakeTypeError;
MaxSimple = from.MaxSimple;
MinSimple = from.MinSimple;
- RegExpExecNoTests = from.RegExpExecNoTests;
+ RegExpInitialize = from.RegExpInitialize;
});
//-------------------------------------------------------------------
@@ -159,9 +161,10 @@
var subject = TO_STRING(this);
- // Non-regexp argument.
- var regexp = new GlobalRegExp(pattern);
- return RegExpExecNoTests(regexp, subject, 0);
+ // Equivalent to RegExpCreate (ES#sec-regexpcreate)
+ var regexp = %_NewObject(GlobalRegExp, GlobalRegExp);
+ RegExpInitialize(regexp, pattern);
+ return regexp[matchSymbol](subject);
}
@@ -355,7 +358,10 @@
}
var subject = TO_STRING(this);
- var regexp = new GlobalRegExp(pattern);
+
+ // Equivalent to RegExpCreate (ES#sec-regexpcreate)
+ var regexp = %_NewObject(GlobalRegExp, GlobalRegExp);
+ RegExpInitialize(regexp, pattern);
return %_Call(regexp[searchSymbol], regexp, subject);
}
@@ -558,18 +564,6 @@
}
-// ECMA-262, section 15.5.3.2
-function StringFromCharCode(_) { // length == 1
- "use strict";
- var s = "";
- var n = arguments.length;
- for (var i = 0; i < n; ++i) {
- s += %_StringCharFromCode(arguments[i] & 0xffff);
- }
- return s;
-}
-
-
// ES6 draft, revision 26 (2014-07-18), section B.2.3.2.1
function HtmlEscape(str) {
return %_Call(StringReplace, TO_STRING(str), /"/g, """);
@@ -701,7 +695,7 @@
var s = TO_STRING(this);
- if (IS_REGEXP(searchString)) {
+ if (IsRegExp(searchString)) {
throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.startsWith");
}
@@ -727,7 +721,7 @@
var s = TO_STRING(this);
- if (IS_REGEXP(searchString)) {
+ if (IsRegExp(searchString)) {
throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.endsWith");
}
@@ -754,7 +748,7 @@
var string = TO_STRING(this);
- if (IS_REGEXP(searchString)) {
+ if (IsRegExp(searchString)) {
throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.includes");
}
@@ -860,7 +854,6 @@
// Set up the non-enumerable functions on the String object.
utils.InstallFunctions(GlobalString, DONT_ENUM, [
- "fromCharCode", StringFromCharCode,
"fromCodePoint", StringFromCodePoint,
"raw", StringRaw
]);
diff --git a/src/js/symbol.js b/src/js/symbol.js
index ae54369..7365655 100644
--- a/src/js/symbol.js
+++ b/src/js/symbol.js
@@ -84,9 +84,7 @@
// "search", searchSymbol,
// "split, splitSymbol,
"toPrimitive", toPrimitiveSymbol,
- // TODO(dslomov, caitp): Currently defined in harmony-tostring.js ---
- // Move here when shipping
- // "toStringTag", toStringTagSymbol,
+ "toStringTag", toStringTagSymbol,
"unscopables", unscopablesSymbol,
]);
diff --git a/src/js/typedarray.js b/src/js/typedarray.js
index 3d500a3..4fb174b 100644
--- a/src/js/typedarray.js
+++ b/src/js/typedarray.js
@@ -11,11 +11,15 @@
// -------------------------------------------------------------------
// Imports
-var ArrayFrom;
-var ArrayToString;
+var AddIndexedProperty;
+// array.js has to come before typedarray.js for this to work
+var ArrayToString = utils.ImportNow("ArrayToString");
var ArrayValues;
+var GetIterator;
+var GetMethod;
var GlobalArray = global.Array;
var GlobalArrayBuffer = global.ArrayBuffer;
+var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype;
var GlobalDataView = global.DataView;
var GlobalObject = global.Object;
var InternalArray = utils.InternalArray;
@@ -67,9 +71,10 @@
TYPED_ARRAYS(DECLARE_GLOBALS)
utils.Import(function(from) {
- ArrayFrom = from.ArrayFrom;
- ArrayToString = from.ArrayToString;
+ AddIndexedProperty = from.AddIndexedProperty;
ArrayValues = from.ArrayValues;
+ GetIterator = from.GetIterator;
+ GetMethod = from.GetMethod;
InnerArrayCopyWithin = from.InnerArrayCopyWithin;
InnerArrayEvery = from.InnerArrayEvery;
InnerArrayFill = from.InnerArrayFill;
@@ -118,7 +123,7 @@
} else {
var newTypedArray = new constructor(arg0, arg1, arg2);
}
- if (!%_IsTypedArray(newTypedArray)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(newTypedArray)) throw MakeTypeError(kNotTypedArray);
// TODO(littledan): Check for being detached, here and elsewhere
// All callers where the first argument is a Number have no additional
// arguments.
@@ -195,8 +200,7 @@
}
}
-function NAMEConstructByArrayLike(obj, arrayLike) {
- var length = arrayLike.length;
+function NAMEConstructByArrayLike(obj, arrayLike, length) {
var l = ToPositiveInteger(length, kInvalidTypedArrayLength);
if (l > %_MaxSmi()) {
@@ -236,7 +240,23 @@
for (var value of newIterable) {
list.push(value);
}
- NAMEConstructByArrayLike(obj, list);
+ NAMEConstructByArrayLike(obj, list, list.length);
+}
+
+// ES#sec-typedarray-typedarray TypedArray ( typedArray )
+function NAMEConstructByTypedArray(obj, typedArray) {
+ // TODO(littledan): Throw on detached typedArray
+ var srcData = %TypedArrayGetBuffer(typedArray);
+ var length = %_TypedArrayGetLength(typedArray);
+ var byteLength = %_ArrayBufferViewGetByteLength(typedArray);
+ var newByteLength = length * ELEMENT_SIZE;
+ NAMEConstructByArrayLike(obj, typedArray, length);
+ var bufferConstructor = SpeciesConstructor(srcData, GlobalArrayBuffer);
+ var prototype = bufferConstructor.prototype;
+ // TODO(littledan): Use the right prototype based on bufferConstructor's realm
+ if (IS_RECEIVER(prototype) && prototype !== GlobalArrayBufferPrototype) {
+ %InternalSetPrototype(%TypedArrayGetBuffer(obj), prototype);
+ }
}
function NAMEConstructor(arg1, arg2, arg3) {
@@ -246,14 +266,12 @@
} else if (IS_NUMBER(arg1) || IS_STRING(arg1) ||
IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) {
NAMEConstructByLength(this, arg1);
+ } else if (IS_TYPEDARRAY(arg1)) {
+ NAMEConstructByTypedArray(this, arg1);
} else {
- // TODO(littledan): If arg1 is a TypedArray, follow the constructor
- // path in ES2015 22.2.4.3, and call SpeciesConstructor, in a
- // path that seems to be an optimized version of what's below, but
- // in an observably different way.
var iteratorFn = arg1[iteratorSymbol];
if (IS_UNDEFINED(iteratorFn) || iteratorFn === ArrayValues) {
- NAMEConstructByArrayLike(this, arg1);
+ NAMEConstructByArrayLike(this, arg1, arg1.length);
} else {
NAMEConstructByIterable(this, arg1, iteratorFn);
}
@@ -263,14 +281,6 @@
}
}
-// TODO(littledan): Remove this performance workaround BUG(chromium:579905)
-function NAME_GetLength() {
- if (!(%_ClassOf(this) === 'NAME')) {
- throw MakeTypeError(kIncompatibleMethodReceiver, "NAME.length", this);
- }
- return %_TypedArrayGetLength(this);
-}
-
function NAMESubArray(begin, end) {
var beginInt = TO_INTEGER(begin);
if (!IS_UNDEFINED(end)) {
@@ -323,7 +333,7 @@
%SetForceInlineFlag(TypedArraySubArray);
function TypedArrayGetBuffer() {
- if (!%_IsTypedArray(this)) {
+ if (!IS_TYPEDARRAY(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"get TypedArray.prototype.buffer", this);
}
@@ -332,7 +342,7 @@
%SetForceInlineFlag(TypedArrayGetBuffer);
function TypedArrayGetByteLength() {
- if (!%_IsTypedArray(this)) {
+ if (!IS_TYPEDARRAY(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"get TypedArray.prototype.byteLength", this);
}
@@ -341,7 +351,7 @@
%SetForceInlineFlag(TypedArrayGetByteLength);
function TypedArrayGetByteOffset() {
- if (!%_IsTypedArray(this)) {
+ if (!IS_TYPEDARRAY(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"get TypedArray.prototype.byteOffset", this);
}
@@ -350,7 +360,7 @@
%SetForceInlineFlag(TypedArrayGetByteOffset);
function TypedArrayGetLength() {
- if (!%_IsTypedArray(this)) {
+ if (!IS_TYPEDARRAY(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"get TypedArray.prototype.length", this);
}
@@ -465,7 +475,7 @@
%FunctionSetLength(TypedArraySet, 1);
function TypedArrayGetToStringTag() {
- if (!%_IsTypedArray(this)) return;
+ if (!IS_TYPEDARRAY(this)) return;
var name = %_ClassOf(this);
if (IS_UNDEFINED(name)) return;
return name;
@@ -473,7 +483,7 @@
function TypedArrayCopyWithin(target, start, end) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -485,7 +495,7 @@
// ES6 draft 05-05-15, section 22.2.3.7
function TypedArrayEvery(f, receiver) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -496,7 +506,7 @@
// ES6 draft 08-24-14, section 22.2.3.12
function TypedArrayForEach(f, receiver) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -507,7 +517,7 @@
// ES6 draft 04-05-14 section 22.2.3.8
function TypedArrayFill(value, start, end) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -518,7 +528,7 @@
// ES6 draft 07-15-13, section 22.2.3.9
function TypedArrayFilter(f, thisArg) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
@@ -536,7 +546,7 @@
// ES6 draft 07-15-13, section 22.2.3.10
function TypedArrayFind(predicate, thisArg) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -547,7 +557,7 @@
// ES6 draft 07-15-13, section 22.2.3.11
function TypedArrayFindIndex(predicate, thisArg) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -558,7 +568,7 @@
// ES6 draft 05-18-15, section 22.2.3.21
function TypedArrayReverse() {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -586,7 +596,7 @@
// ES6 draft 05-18-15, section 22.2.3.25
function TypedArraySort(comparefn) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -600,7 +610,7 @@
// ES6 section 22.2.3.13
function TypedArrayIndexOf(element, index) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
return InnerArrayIndexOf(this, element, index, length);
@@ -610,7 +620,7 @@
// ES6 section 22.2.3.16
function TypedArrayLastIndexOf(element, index) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -622,7 +632,7 @@
// ES6 draft 07-15-13, section 22.2.3.18
function TypedArrayMap(f, thisArg) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
var result = TypedArraySpeciesCreate(this, length);
@@ -638,7 +648,7 @@
// ES6 draft 05-05-15, section 22.2.3.24
function TypedArraySome(f, receiver) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -649,7 +659,7 @@
// ES6 section 22.2.3.27
function TypedArrayToLocaleString() {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -657,15 +667,9 @@
}
-// ES6 section 22.2.3.28
-function TypedArrayToString() {
- return %_Call(ArrayToString, this);
-}
-
-
// ES6 section 22.2.3.14
function TypedArrayJoin(separator) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -675,7 +679,7 @@
// ES6 draft 07-15-13, section 22.2.3.19
function TypedArrayReduce(callback, current) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
return InnerArrayReduce(callback, current, this, length,
@@ -686,7 +690,7 @@
// ES6 draft 07-15-13, section 22.2.3.19
function TypedArrayReduceRight(callback, current) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
return InnerArrayReduceRight(callback, current, this, length,
@@ -696,7 +700,7 @@
function TypedArraySlice(start, end) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var len = %_TypedArrayGetLength(this);
var relativeStart = TO_INTEGER(start);
@@ -740,7 +744,7 @@
// ES2016 draft, section 22.2.3.14
function TypedArrayIncludes(searchElement, fromIndex) {
- if (!%_IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+ if (!IS_TYPEDARRAY(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
@@ -760,14 +764,50 @@
}
+// ES#sec-iterabletoarraylike Runtime Semantics: IterableToArrayLike( items )
+function IterableToArrayLike(items) {
+ var iterable = GetMethod(items, iteratorSymbol);
+ if (!IS_UNDEFINED(iterable)) {
+ var internal_array = new InternalArray();
+ var i = 0;
+ for (var value of
+ { [iteratorSymbol]() { return GetIterator(items, iterable) } }) {
+ internal_array[i] = value;
+ i++;
+ }
+ var array = [];
+ %MoveArrayContents(internal_array, array);
+ return array;
+ }
+ return TO_OBJECT(items);
+}
+
+
+// ES#sec-%typedarray%.from
+// %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] )
function TypedArrayFrom(source, mapfn, thisArg) {
- // TODO(littledan): Investigate if there is a receiver which could be
- // faster to accumulate on than Array, e.g., a TypedVector.
- // TODO(littledan): Rewrite this code to ensure that things happen
- // in the right order, e.g., the constructor needs to be called before
- // the mapping function on array-likes.
- var array = %_Call(ArrayFrom, GlobalArray, source, mapfn, thisArg);
- return TypedArrayCreate(this, array);
+ if (!%IsConstructor(this)) throw MakeTypeError(kNotConstructor, this);
+ var mapping;
+ if (!IS_UNDEFINED(mapfn)) {
+ if (!IS_CALLABLE(mapfn)) throw MakeTypeError(kCalledNonCallable, this);
+ mapping = true;
+ } else {
+ mapping = false;
+ }
+ var arrayLike = IterableToArrayLike(source);
+ var length = TO_LENGTH(arrayLike.length);
+ var targetObject = TypedArrayCreate(this, length);
+ var value, mappedValue;
+ for (var i = 0; i < length; i++) {
+ value = arrayLike[i];
+ if (mapping) {
+ mappedValue = %_Call(mapfn, thisArg, value, i);
+ } else {
+ mappedValue = value;
+ }
+ targetObject[i] = mappedValue;
+ }
+ return targetObject;
}
%FunctionSetLength(TypedArrayFrom, 1);
@@ -785,7 +825,7 @@
%FunctionSetPrototype(TypedArray, new GlobalObject());
%AddNamedProperty(TypedArray.prototype,
"constructor", TypedArray, DONT_ENUM);
-utils.InstallFunctions(TypedArray, DONT_ENUM | DONT_DELETE | READ_ONLY, [
+utils.InstallFunctions(TypedArray, DONT_ENUM, [
"from", TypedArrayFrom,
"of", TypedArrayOf
]);
@@ -819,10 +859,12 @@
"slice", TypedArraySlice,
"some", TypedArraySome,
"sort", TypedArraySort,
- "toString", TypedArrayToString,
"toLocaleString", TypedArrayToLocaleString
]);
+%AddNamedProperty(TypedArray.prototype, "toString", ArrayToString,
+ DONT_ENUM);
+
macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
%SetCode(GlobalNAME, NAMEConstructor);
@@ -838,9 +880,6 @@
%AddNamedProperty(GlobalNAME.prototype,
"BYTES_PER_ELEMENT", ELEMENT_SIZE,
READ_ONLY | DONT_ENUM | DONT_DELETE);
- // TODO(littledan): Remove this performance workaround BUG(chromium:579905)
- utils.InstallGetter(GlobalNAME.prototype, "length", NAME_GetLength,
- DONT_ENUM | DONT_DELETE);
endmacro
TYPED_ARRAYS(SETUP_TYPED_ARRAY)
diff --git a/src/js/uri.js b/src/js/uri.js
index 712d7e6..dca83c9 100644
--- a/src/js/uri.js
+++ b/src/js/uri.js
@@ -15,7 +15,6 @@
// Imports
var GlobalObject = global.Object;
-var GlobalArray = global.Array;
var InternalArray = utils.InternalArray;
var MakeURIError;
@@ -76,7 +75,7 @@
var x = (cc >> 12) & 0xF;
var y = (cc >> 6) & 63;
var z = cc & 63;
- var octets = new GlobalArray(3);
+ var octets = new InternalArray(3);
if (cc <= 0x007F) {
octets[0] = cc;
} else if (cc <= 0x07FF) {
@@ -96,7 +95,7 @@
var x = cc1 & 3;
var y = (cc2 >> 6) & 0xF;
var z = cc2 & 63;
- var octets = new GlobalArray(4);
+ var octets = new InternalArray(4);
octets[0] = (u >> 2) + 240;
octets[1] = (((u & 3) << 4) | w) + 128;
octets[2] = ((x << 4) | y) + 128;
@@ -248,7 +247,7 @@
var n = 0;
while (((cc << ++n) & 0x80) != 0) { }
if (n == 1 || n > 4) throw MakeURIError();
- var octets = new GlobalArray(n);
+ var octets = new InternalArray(n);
octets[0] = cc;
if (k + 3 * (n - 1) >= uriLength) throw MakeURIError();
for (var i = 1; i < n; i++) {
diff --git a/src/js/v8natives.js b/src/js/v8natives.js
index 5e1a825..5185c62 100644
--- a/src/js/v8natives.js
+++ b/src/js/v8natives.js
@@ -134,14 +134,6 @@
}
-// ES6 7.3.11
-function ObjectHasOwnProperty(value) {
- var name = TO_NAME(value);
- var object = TO_OBJECT(this);
- return %HasOwnProperty(object, name);
-}
-
-
// ES6 19.1.3.3 Object.prototype.isPrototypeOf(V)
function ObjectIsPrototypeOf(V) {
if (!IS_RECEIVER(V)) return false;
@@ -581,11 +573,9 @@
if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
var currentIsWritable = current.isWritable();
if (currentIsWritable != desc.isWritable()) {
- if (!currentIsWritable || IS_STRONG(obj)) {
+ if (!currentIsWritable) {
if (should_throw) {
- throw currentIsWritable
- ? MakeTypeError(kStrongRedefineDisallowed, obj, p)
- : MakeTypeError(kRedefineDisallowed, p);
+ throw MakeTypeError(kRedefineDisallowed, p);
} else {
return false;
}
@@ -850,7 +840,6 @@
"toString", ObjectToString,
"toLocaleString", ObjectToLocaleString,
"valueOf", ObjectValueOf,
- "hasOwnProperty", ObjectHasOwnProperty,
"isPrototypeOf", ObjectIsPrototypeOf,
"propertyIsEnumerable", ObjectPropertyIsEnumerable,
"__defineGetter__", ObjectDefineGetter,
@@ -1106,9 +1095,10 @@
to.IsFinite = GlobalIsFinite;
to.IsNaN = GlobalIsNaN;
to.NumberIsNaN = NumberIsNaN;
+ to.NumberIsInteger = NumberIsInteger;
to.ObjectDefineProperties = ObjectDefineProperties;
to.ObjectDefineProperty = ObjectDefineProperty;
- to.ObjectHasOwnProperty = ObjectHasOwnProperty;
+ to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty;
});
%InstallToContext([