diff options
Diffstat (limited to 'Source/JavaScriptCore/builtins')
28 files changed, 3666 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/builtins/ArrayConstructor.js b/Source/JavaScriptCore/builtins/ArrayConstructor.js new file mode 100644 index 000000000..27efc1d95 --- /dev/null +++ b/Source/JavaScriptCore/builtins/ArrayConstructor.js @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function of(/* items... */) +{ + "use strict"; + + var length = arguments.length; + // TODO: Need isConstructor(this) instead of typeof "function" check. + var array = typeof this === 'function' ? new this(length) : new @Array(length); + for (var k = 0; k < length; ++k) + @putByValDirect(array, k, arguments[k]); + array.length = length; + return array; +} + +function from(items /*, mapFn, thisArg */) +{ + "use strict"; + + var thisObj = this; + + var mapFn = arguments.length > 1 ? arguments[1] : @undefined; + + var thisArg; + + if (mapFn !== @undefined) { + if (typeof mapFn !== "function") + throw new @TypeError("Array.from requires that the second argument, when provided, be a function"); + + if (arguments.length > 2) + thisArg = arguments[2]; + } + + if (items == null) + throw new @TypeError("Array.from requires an array-like object - not null or undefined"); + + var iteratorMethod = items[@symbolIterator]; + if (iteratorMethod != null) { + if (typeof iteratorMethod !== "function") + throw new @TypeError("Array.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function"); + + // TODO: Need isConstructor(thisObj) instead of typeof "function" check. + var result = (typeof thisObj === "function") ? @Object(new thisObj()) : []; + + var k = 0; + var iterator = iteratorMethod.@call(items); + + // Since for-of loop once more looks up the @@iterator property of a given iterable, + // it could be observable if the user defines a getter for @@iterator. + // To avoid this situation, we define a wrapper object that @@iterator just returns a given iterator. + var wrapper = { + [@symbolIterator]() { + return iterator; + } + }; + + for (var value of wrapper) { + if (mapFn) + @putByValDirect(result, k, thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k)); + else + @putByValDirect(result, k, value); + k += 1; + } + + result.length = k; + return result; + } + + var arrayLike = @Object(items); + var arrayLikeLength = @toLength(arrayLike.length); + + // TODO: Need isConstructor(thisObj) instead of typeof "function" check. + var result = (typeof thisObj === "function") ? @Object(new thisObj(arrayLikeLength)) : new @Array(arrayLikeLength); + + var k = 0; + while (k < arrayLikeLength) { + var value = arrayLike[k]; + if (mapFn) + @putByValDirect(result, k, thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k)); + else + @putByValDirect(result, k, value); + k += 1; + } + + result.length = arrayLikeLength; + return result; +} diff --git a/Source/JavaScriptCore/builtins/ArrayIteratorPrototype.js b/Source/JavaScriptCore/builtins/ArrayIteratorPrototype.js new file mode 100644 index 000000000..aa7886c6f --- /dev/null +++ b/Source/JavaScriptCore/builtins/ArrayIteratorPrototype.js @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function next() +{ + "use strict"; + + if (this == null) + throw new @TypeError("%ArrayIteratorPrototype%.next requires that |this| not be null or undefined"); + + var itemKind = this.@arrayIterationKind; + if (itemKind === @undefined) + throw new @TypeError("%ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance"); + + var done = true; + var value = @undefined; + + var array = this.@iteratedObject; + if (array !== @undefined) { + var index = this.@arrayIteratorNextIndex; + var length = array.length >>> 0; + if (index >= length) { + this.@iteratedObject = @undefined; + } else { + this.@arrayIteratorNextIndex = index + 1; + done = false; + if (itemKind === @arrayIterationKindKey) { + value = index; + } else if (itemKind === @arrayIterationKindValue) { + value = array[index]; + } else { + value = [ index, array[index] ]; + } + } + } + + return {done, value}; +} diff --git a/Source/JavaScriptCore/builtins/ArrayPrototype.js b/Source/JavaScriptCore/builtins/ArrayPrototype.js new file mode 100644 index 000000000..57c81d7c7 --- /dev/null +++ b/Source/JavaScriptCore/builtins/ArrayPrototype.js @@ -0,0 +1,663 @@ +/* + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function reduce(callback /*, initialValue */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.reduce requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.reduce requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.reduce callback must be a function"); + + if (length === 0 && arguments.length < 2) + throw new @TypeError("reduce of empty array with no initial value"); + + var accumulator, k = 0; + if (arguments.length > 1) + accumulator = arguments[1]; + else { + while (k < length && !(k in array)) + k += 1; + if (k >= length) + throw new @TypeError("reduce of empty array with no initial value"); + accumulator = array[k++]; + } + + while (k < length) { + if (k in array) + accumulator = callback.@call(@undefined, accumulator, array[k], k, array); + k += 1; + } + return accumulator; +} + +function reduceRight(callback /*, initialValue */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.reduceRight requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.reduceRight requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.reduceRight callback must be a function"); + + if (length === 0 && arguments.length < 2) + throw new @TypeError("reduceRight of empty array with no initial value"); + + var accumulator, k = length - 1; + if (arguments.length > 1) + accumulator = arguments[1]; + else { + while (k >= 0 && !(k in array)) + k -= 1; + if (k < 0) + throw new @TypeError("reduceRight of empty array with no initial value"); + accumulator = array[k--]; + } + + while (k >= 0) { + if (k in array) + accumulator = callback.@call(@undefined, accumulator, array[k], k, array); + k -= 1; + } + return accumulator; +} + +function every(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.every requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.every requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.every callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + for (var i = 0; i < length; i++) { + if (!(i in array)) + continue; + if (!callback.@call(thisArg, array[i], i, array)) + return false; + } + + return true; +} + +function forEach(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.forEach requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.forEach requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.forEach callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + for (var i = 0; i < length; i++) { + if (i in array) + callback.@call(thisArg, array[i], i, array); + } +} + +function filter(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.filter requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.filter requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.filter callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + var result = []; + var nextIndex = 0; + for (var i = 0; i < length; i++) { + if (!(i in array)) + continue; + var current = array[i] + if (callback.@call(thisArg, current, i, array)) { + @putByValDirect(result, nextIndex, current); + ++nextIndex; + } + } + return result; +} + +function map(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.map requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.map requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.map callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + var result = []; + result.length = length; + var nextIndex = 0; + for (var i = 0; i < length; i++) { + if (!(i in array)) + continue; + var mappedValue = callback.@call(thisArg, array[i], i, array); + @putByValDirect(result, i, mappedValue); + } + return result; +} + +function some(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.some requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.some requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.some callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + for (var i = 0; i < length; i++) { + if (!(i in array)) + continue; + if (callback.@call(thisArg, array[i], i, array)) + return true; + } + return false; +} + +function fill(value /* [, start [, end]] */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.fill requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.fill requires that |this| not be undefined"); + var O = @Object(this); + var len = @toLength(O.length); + var relativeStart = 0; + if (arguments.length > 1 && arguments[1] !== @undefined) + relativeStart = arguments[1] | 0; + var k = 0; + if (relativeStart < 0) { + k = len + relativeStart; + if (k < 0) + k = 0; + } else { + k = relativeStart; + if (k > len) + k = len; + } + var relativeEnd = len; + if (arguments.length > 2 && arguments[2] !== @undefined) + relativeEnd = arguments[2] | 0; + var final = 0; + if (relativeEnd < 0) { + final = len + relativeEnd; + if (final < 0) + final = 0; + } else { + final = relativeEnd; + if (final > len) + final = len; + } + for (; k < final; k++) + O[k] = value; + return O; +} + +function find(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.find requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.find requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.find callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + for (var i = 0; i < length; i++) { + var kValue = array[i]; + if (callback.@call(thisArg, kValue, i, array)) + return kValue; + } + return @undefined; +} + +function findIndex(callback /*, thisArg */) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.findIndex requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.findIndex requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (typeof callback !== "function") + throw new @TypeError("Array.prototype.findIndex callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + for (var i = 0; i < length; i++) { + if (callback.@call(thisArg, array[i], i, array)) + return i; + } + return -1; +} + +function includes(searchElement /*, fromIndex*/) +{ + "use strict"; + + if (this === null) + throw new @TypeError("Array.prototype.includes requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.includes requires that |this| not be undefined"); + + var array = @Object(this); + var length = @toLength(array.length); + + if (length === 0) + return false; + + var fromIndex = 0; + if (arguments.length > 1 && arguments[1] !== @undefined) + fromIndex = arguments[1] | 0; + + var index; + if (fromIndex >= 0) + index = fromIndex; + else + index = length + fromIndex; + + if (index < 0) + index = 0; + + var currentElement; + for (; index < length; ++index) { + currentElement = array[index]; + // Use SameValueZero comparison, rather than just StrictEquals. + if (searchElement === currentElement || (searchElement !== searchElement && currentElement !== currentElement)) + return true; + } + return false; +} + +function sort(comparator) +{ + "use strict"; + + function min(a, b) + { + return a < b ? a : b; + } + + function stringComparator(a, b) + { + var aString = a.string; + var bString = b.string; + + var aLength = aString.length; + var bLength = bString.length; + var length = min(aLength, bLength); + + for (var i = 0; i < length; ++i) { + var aCharCode = aString.@charCodeAt(i); + var bCharCode = bString.@charCodeAt(i); + + if (aCharCode == bCharCode) + continue; + + return aCharCode - bCharCode; + } + + return aLength - bLength; + } + + // Move undefineds and holes to the end of a sparse array. Result is [values..., undefineds..., holes...]. + function compactSparse(array, dst, src, length) + { + var values = [ ]; + var seen = { }; + var valueCount = 0; + var undefinedCount = 0; + + // Clean up after the in-progress non-sparse compaction that failed. + for (var i = dst; i < src; ++i) + delete array[i]; + + for (var object = array; object; object = @Object.@getPrototypeOf(object)) { + var propertyNames = @Object.@getOwnPropertyNames(object); + for (var i = 0; i < propertyNames.length; ++i) { + var index = propertyNames[i]; + if (index < length) { // Exclude non-numeric properties and properties past length. + if (seen[index]) // Exclude duplicates. + continue; + seen[index] = 1; + + var value = array[index]; + delete array[index]; + + if (value === @undefined) { + ++undefinedCount; + continue; + } + + array[valueCount++] = value; + } + } + } + + for (var i = valueCount; i < valueCount + undefinedCount; ++i) + array[i] = @undefined; + + return valueCount; + } + + function compactSlow(array, length) + { + var holeCount = 0; + + for (var dst = 0, src = 0; src < length; ++src) { + if (!(src in array)) { + ++holeCount; + if (holeCount < 256) + continue; + return compactSparse(array, dst, src, length); + } + + var value = array[src]; + if (value === @undefined) + continue; + + array[dst++] = value; + } + + var valueCount = dst; + var undefinedCount = length - valueCount - holeCount; + + for (var i = valueCount; i < valueCount + undefinedCount; ++i) + array[i] = @undefined; + + for (var i = valueCount + undefinedCount; i < length; ++i) + delete array[i]; + + return valueCount; + } + + // Move undefineds and holes to the end of an array. Result is [values..., undefineds..., holes...]. + function compact(array, length) + { + for (var i = 0; i < array.length; ++i) { + if (array[i] === @undefined) + return compactSlow(array, length); + } + + return length; + } + + function merge(dst, src, srcIndex, srcEnd, width, comparator) + { + var left = srcIndex; + var leftEnd = min(left + width, srcEnd); + var right = leftEnd; + var rightEnd = min(right + width, srcEnd); + + for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) { + if (right < rightEnd) { + if (left >= leftEnd || comparator(src[right], src[left]) < 0) { + dst[dstIndex] = src[right++]; + continue; + } + } + + dst[dstIndex] = src[left++]; + } + } + + function mergeSort(array, valueCount, comparator) + { + var buffer = [ ]; + buffer.length = valueCount; + + var dst = buffer; + var src = array; + for (var width = 1; width < valueCount; width *= 2) { + for (var srcIndex = 0; srcIndex < valueCount; srcIndex += 2 * width) + merge(dst, src, srcIndex, valueCount, width, comparator); + + var tmp = src; + src = dst; + dst = tmp; + } + + if (src != array) { + for(var i = 0; i < valueCount; i++) + array[i] = src[i]; + } + } + + function bucketSort(array, dst, bucket, depth) + { + if (bucket.length < 32 || depth > 32) { + mergeSort(bucket, bucket.length, stringComparator); + for (var i = 0; i < bucket.length; ++i) + array[dst++] = bucket[i].value; + return dst; + } + + var buckets = [ ]; + for (var i = 0; i < bucket.length; ++i) { + var entry = bucket[i]; + var string = entry.string; + if (string.length == depth) { + array[dst++] = entry.value; + continue; + } + + var c = string.@charCodeAt(depth); + if (!buckets[c]) + buckets[c] = [ ]; + buckets[c][buckets[c].length] = entry; + } + + for (var i = 0; i < buckets.length; ++i) { + if (!buckets[i]) + continue; + dst = bucketSort(array, dst, buckets[i], depth + 1); + } + + return dst; + } + + function comparatorSort(array, comparator) + { + var length = array.length >>> 0; + + // For compatibility with Firefox and Chrome, do nothing observable + // to the target array if it has 0 or 1 sortable properties. + if (length < 2) + return; + + var valueCount = compact(array, length); + mergeSort(array, valueCount, comparator); + } + + function stringSort(array) + { + var length = array.length >>> 0; + + // For compatibility with Firefox and Chrome, do nothing observable + // to the target array if it has 0 or 1 sortable properties. + if (length < 2) + return; + + var valueCount = compact(array, length); + + var strings = new @Array(valueCount); + for (var i = 0; i < valueCount; ++i) + strings[i] = { string: @toString(array[i]), value: array[i] }; + + bucketSort(array, 0, strings, 0); + } + + if (this === null) + throw new @TypeError("Array.prototype.sort requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("Array.prototype.sort requires that |this| not be undefined"); + + if (typeof this == "string") + throw new @TypeError("Attempted to assign to readonly property."); + + var array = @Object(this); + + if (typeof comparator == "function") + comparatorSort(array, comparator); + else + stringSort(array); + + return array; +} + +function copyWithin(target, start /*, end */) +{ + "use strict"; + + function maxWithPositives(a, b) + { + return (a < b) ? b : a; + } + + function minWithMaybeNegativeZeroAndPositive(maybeNegativeZero, positive) + { + return (maybeNegativeZero < positive) ? maybeNegativeZero : positive; + } + + if (this === null || this === @undefined) + throw new @TypeError("Array.copyWithin requires that |this| not be null or undefined"); + var thisObject = @Object(this); + + var length = @toLength(thisObject.length); + + var relativeTarget = @toInteger(target); + var to = (relativeTarget < 0) ? maxWithPositives(length + relativeTarget, 0) : minWithMaybeNegativeZeroAndPositive(relativeTarget, length); + + var relativeStart = @toInteger(start); + var from = (relativeStart < 0) ? maxWithPositives(length + relativeStart, 0) : minWithMaybeNegativeZeroAndPositive(relativeStart, length); + + var relativeEnd; + if (arguments.length >= 3) { + var end = arguments[2]; + if (end === @undefined) + relativeEnd = length; + else + relativeEnd = @toInteger(end); + } else + relativeEnd = length; + + var finalValue = (relativeEnd < 0) ? maxWithPositives(length + relativeEnd, 0) : minWithMaybeNegativeZeroAndPositive(relativeEnd, length); + + var count = minWithMaybeNegativeZeroAndPositive(finalValue - from, length - to); + + var direction = 1; + if (from < to && to < from + count) { + direction = -1; + from = from + count - 1; + to = to + count - 1; + } + + for (var i = 0; i < count; ++i, from += direction, to += direction) { + if (from in thisObject) + thisObject[to] = thisObject[from]; + else + delete thisObject[to]; + } + + return thisObject; +} diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp new file mode 100644 index 000000000..0d59afccc --- /dev/null +++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "BuiltinExecutables.h" + +#include "BuiltinNames.h" +#include "Executable.h" +#include "JSCInlines.h" +#include "Parser.h" +#include <wtf/NeverDestroyed.h> + +namespace JSC { + +static UnlinkedFunctionExecutable* createExecutableInternal(VM&, const SourceCode&, const Identifier&, ConstructorKind, ConstructAbility); + +BuiltinExecutables::BuiltinExecutables(VM& vm) + : m_vm(vm) +#define INITIALIZE_BUILTIN_SOURCE_MEMBERS(name, functionName, length) , m_##name##Source(makeSource(StringImpl::createFromLiteral(s_##name, length))) + JSC_FOREACH_BUILTIN_CODE(INITIALIZE_BUILTIN_SOURCE_MEMBERS) +#undef EXPOSE_BUILTIN_STRINGS +{ +} + +UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name) +{ + static NeverDestroyed<const String> baseConstructorCode(ASCIILiteral("(function () { })")); + static NeverDestroyed<const String> derivedConstructorCode(ASCIILiteral("(function () { super(...arguments); })")); + + switch (constructorKind) { + case ConstructorKind::None: + break; + case ConstructorKind::Base: + return createExecutableInternal(m_vm, makeSource(baseConstructorCode), name, constructorKind, ConstructAbility::CanConstruct); + case ConstructorKind::Derived: + return createExecutableInternal(m_vm, makeSource(derivedConstructorCode), name, constructorKind, ConstructAbility::CanConstruct); + } + ASSERT_NOT_REACHED(); + return nullptr; +} + +UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const SourceCode& code, const Identifier& name, ConstructAbility constructAbility) +{ + return createExecutableInternal(m_vm, code, name, ConstructorKind::None, constructAbility); +} + +UnlinkedFunctionExecutable* createBuiltinExecutable(VM& vm, const SourceCode& code, const Identifier& name, ConstructAbility constructAbility) +{ + return createExecutableInternal(vm, code, name, ConstructorKind::None, constructAbility); +} + +UnlinkedFunctionExecutable* createExecutableInternal(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility) +{ + JSTextPosition positionBeforeLastNewline; + ParserError error; + bool isParsingDefaultConstructor = constructorKind != ConstructorKind::None; + JSParserBuiltinMode builtinMode = isParsingDefaultConstructor ? JSParserBuiltinMode::NotBuiltin : JSParserBuiltinMode::Builtin; + UnlinkedFunctionKind kind = isParsingDefaultConstructor ? UnlinkedNormalFunction : UnlinkedBuiltinFunction; + RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr; + std::unique_ptr<ProgramNode> program = parse<ProgramNode>( + &vm, source, Identifier(), builtinMode, + JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error, + &positionBeforeLastNewline, constructorKind); + + if (!program) { + dataLog("Fatal error compiling builtin function '", name.string(), "': ", error.message()); + CRASH(); + } + + StatementNode* exprStatement = program->singleStatement(); + RELEASE_ASSERT(exprStatement); + RELEASE_ASSERT(exprStatement->isExprStatement()); + ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); + RELEASE_ASSERT(funcExpr); + RELEASE_ASSERT(funcExpr->isFuncExprNode()); + FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(funcExpr)->metadata(); + RELEASE_ASSERT(!program->hasCapturedVariables()); + + metadata->setEndPosition(positionBeforeLastNewline); + RELEASE_ASSERT(metadata); + RELEASE_ASSERT(metadata->ident().isNull()); + + // This function assumes an input string that would result in a single anonymous function expression. + metadata->setEndPosition(positionBeforeLastNewline); + RELEASE_ASSERT(metadata); + metadata->overrideName(name); + VariableEnvironment dummyTDZVariables; + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, dummyTDZVariables, DerivedContextType::None, WTFMove(sourceOverride)); + functionExecutable->setNameValue(vm, jsString(&vm, name.string())); + return functionExecutable; +} + +void BuiltinExecutables::finalize(Handle<Unknown>, void* context) +{ + static_cast<Weak<UnlinkedFunctionExecutable>*>(context)->clear(); +} + +#define DEFINE_BUILTIN_EXECUTABLES(name, functionName, length) \ +UnlinkedFunctionExecutable* BuiltinExecutables::name##Executable() \ +{\ + if (!m_##name##Executable)\ + m_##name##Executable = Weak<UnlinkedFunctionExecutable>(createBuiltinExecutable(m_##name##Source, m_vm.propertyNames->builtinNames().functionName##PublicName(), s_##name##ConstructAbility), this, &m_##name##Executable);\ + return m_##name##Executable.get();\ +} +JSC_FOREACH_BUILTIN_CODE(DEFINE_BUILTIN_EXECUTABLES) +#undef EXPOSE_BUILTIN_SOURCES + +} diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.h b/Source/JavaScriptCore/builtins/BuiltinExecutables.h new file mode 100644 index 000000000..ec8d57704 --- /dev/null +++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BuiltinExecutables_h +#define BuiltinExecutables_h + +#include "JSCBuiltins.h" +#include "ParserModes.h" +#include "SourceCode.h" +#include "Weak.h" +#include "WeakHandleOwner.h" + +namespace JSC { + +class UnlinkedFunctionExecutable; +class Identifier; +class VM; + +class BuiltinExecutables final: private WeakHandleOwner { + WTF_MAKE_FAST_ALLOCATED; +public: + explicit BuiltinExecutables(VM&); + +#define EXPOSE_BUILTIN_EXECUTABLES(name, functionName, length) \ +UnlinkedFunctionExecutable* name##Executable(); \ +const SourceCode& name##Source() { return m_##name##Source; } + + JSC_FOREACH_BUILTIN_CODE(EXPOSE_BUILTIN_EXECUTABLES) +#undef EXPOSE_BUILTIN_SOURCES + + UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name); + +private: + void finalize(Handle<Unknown>, void* context) override; + + VM& m_vm; + + UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode&, const Identifier&, ConstructAbility); + +#define DECLARE_BUILTIN_SOURCE_MEMBERS(name, functionName, length)\ + SourceCode m_##name##Source; \ + Weak<UnlinkedFunctionExecutable> m_##name##Executable; + JSC_FOREACH_BUILTIN_CODE(DECLARE_BUILTIN_SOURCE_MEMBERS) +#undef DECLARE_BUILTIN_SOURCE_MEMBERS +}; + +} + +#endif diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h new file mode 100644 index 000000000..75fc848e2 --- /dev/null +++ b/Source/JavaScriptCore/builtins/BuiltinNames.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BuiltinNames_h +#define BuiltinNames_h + +#include "BuiltinUtils.h" +#include "CommonIdentifiers.h" +#include "JSCBuiltins.h" + +namespace JSC { + +#define INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY(name) m_privateToPublicMap.add(m_##name##PrivateName.impl(), &m_##name); +#define INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY(name) m_publicToPrivateMap.add(m_##name.impl(), &m_##name##PrivateName); + +class BuiltinNames { + WTF_MAKE_NONCOPYABLE(BuiltinNames); WTF_MAKE_FAST_ALLOCATED; + +public: + BuiltinNames(VM* vm, CommonIdentifiers* commonIdentifiers) + : m_emptyIdentifier(commonIdentifiers->emptyIdentifier) + JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_BUILTIN_NAMES) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_BUILTIN_NAMES) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_BUILTIN_SYMBOLS) + { + JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY) + JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY) + } + + bool isPrivateName(SymbolImpl& uid) const; + bool isPrivateName(UniquedStringImpl& uid) const; + bool isPrivateName(const Identifier&) const; + const Identifier* lookUpPrivateName(const Identifier&) const; + const Identifier& lookUpPublicName(const Identifier&) const; + + void appendExternalName(const Identifier& publicName, const Identifier& privateName); + + JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOL_ACCESSOR) + +private: + Identifier m_emptyIdentifier; + JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_BUILTIN_NAMES) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_NAMES) + JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOLS) + typedef HashMap<RefPtr<UniquedStringImpl>, const Identifier*, IdentifierRepHash> BuiltinNamesMap; + BuiltinNamesMap m_publicToPrivateMap; + BuiltinNamesMap m_privateToPublicMap; +}; + +inline bool BuiltinNames::isPrivateName(SymbolImpl& uid) const +{ + return m_privateToPublicMap.contains(&uid); +} + +inline bool BuiltinNames::isPrivateName(UniquedStringImpl& uid) const +{ + if (!uid.isSymbol()) + return false; + return m_privateToPublicMap.contains(&uid); +} + +inline bool BuiltinNames::isPrivateName(const Identifier& ident) const +{ + if (ident.isNull()) + return false; + return isPrivateName(*ident.impl()); +} + +inline const Identifier* BuiltinNames::lookUpPrivateName(const Identifier& ident) const +{ + auto iter = m_publicToPrivateMap.find(ident.impl()); + if (iter != m_publicToPrivateMap.end()) + return iter->value; + return 0; +} + +inline const Identifier& BuiltinNames::lookUpPublicName(const Identifier& ident) const +{ + auto iter = m_privateToPublicMap.find(ident.impl()); + if (iter != m_privateToPublicMap.end()) + return *iter->value; + return m_emptyIdentifier; +} + +inline void BuiltinNames::appendExternalName(const Identifier& publicName, const Identifier& privateName) +{ +#ifndef NDEBUG + for (const auto& key : m_publicToPrivateMap.keys()) + ASSERT(publicName.string() != *key); +#endif + + m_privateToPublicMap.add(privateName.impl(), &publicName); + m_publicToPrivateMap.add(publicName.impl(), &privateName); +} + +} + +#endif diff --git a/Source/JavaScriptCore/builtins/BuiltinUtils.h b/Source/JavaScriptCore/builtins/BuiltinUtils.h new file mode 100644 index 000000000..45c3e6a85 --- /dev/null +++ b/Source/JavaScriptCore/builtins/BuiltinUtils.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2015 Canon Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BuiltinUtils_h +#define BuiltinUtils_h + +#include "ConstructAbility.h" + +namespace JSC { + +#define INITIALIZE_BUILTIN_NAMES(name) , m_##name(JSC::Identifier::fromString(vm, #name)), m_##name##PrivateName(JSC::Identifier::fromUid(JSC::PrivateName(JSC::PrivateName::Description, ASCIILiteral("PrivateSymbol." #name)))) +#define DECLARE_BUILTIN_NAMES(name) const JSC::Identifier m_##name; const JSC::Identifier m_##name##PrivateName; +#define DECLARE_BUILTIN_IDENTIFIER_ACCESSOR(name) \ + const JSC::Identifier& name##PublicName() const { return m_##name; } \ + const JSC::Identifier& name##PrivateName() const { return m_##name##PrivateName; } + +#define INITIALIZE_BUILTIN_SYMBOLS(name) , m_##name##Symbol(JSC::Identifier::fromUid(JSC::PrivateName(JSC::PrivateName::Description, ASCIILiteral("Symbol." #name)))) +#define DECLARE_BUILTIN_SYMBOLS(name) const JSC::Identifier m_##name##Symbol; +#define DECLARE_BUILTIN_SYMBOL_ACCESSOR(name) \ + const JSC::Identifier& name##Symbol() const { return m_##name##Symbol; } + +class Identifier; +class SourceCode; +class UnlinkedFunctionExecutable; +class VM; + +JS_EXPORT_PRIVATE UnlinkedFunctionExecutable* createBuiltinExecutable(VM&, const SourceCode&, const Identifier&, ConstructAbility); + +} + +#endif diff --git a/Source/JavaScriptCore/builtins/DatePrototype.js b/Source/JavaScriptCore/builtins/DatePrototype.js new file mode 100644 index 000000000..2c82508f9 --- /dev/null +++ b/Source/JavaScriptCore/builtins/DatePrototype.js @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2015 Andy VanWagoner <thetalecrafter@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// @conditional=ENABLE(INTL) + +function toLocaleString(/* locales, options */) +{ + "use strict"; + + function toDateTimeOptionsAnyAll(opts) + { + // ToDateTimeOptions(options, "any", "all") + // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat + + var options; + if (opts === @undefined) + options = null; + else if (opts === null) + throw new @TypeError("null is not an object"); + else + options = @Object(opts); + + // Check original instead of descendant to reduce lookups up the prototype chain. + var needsDefaults = !options || ( + options.weekday === @undefined && + options.year === @undefined && + options.month === @undefined && + options.day === @undefined && + options.hour === @undefined && + options.minute === @undefined && + options.second === @undefined + ); + + // Only create descendant if it will have own properties. + if (needsDefaults) { + options = @Object.create(options) + options.year = "numeric"; + options.month = "numeric"; + options.day = "numeric"; + options.hour = "numeric"; + options.minute = "numeric"; + options.second = "numeric"; + } + + // 9. Return options. + return options; + } + + // 13.3.1 Date.prototype.toLocaleString ([locales [, options ]]) (ECMA-402 2.0) + // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleString + + var value = @thisTimeValue.@call(this); + if (@isNaN(value)) + return "Invalid Date"; + + var options = toDateTimeOptionsAnyAll(arguments[1]); + var locales = arguments[0]; + + var dateFormat = new @DateTimeFormat(locales, options); + return dateFormat.format(value); +} + +function toLocaleDateString(/* locales, options */) +{ + "use strict"; + + function toDateTimeOptionsDateDate(opts) + { + // ToDateTimeOptions(options, "date", "date") + // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat + + var options; + if (opts === @undefined) + options = null; + else if (opts === null) + throw new @TypeError("null is not an object"); + else + options = @Object(opts); + + // Check original instead of descendant to reduce lookups up the prototype chain. + var needsDefaults = !options || ( + options.weekday === @undefined && + options.year === @undefined && + options.month === @undefined && + options.day === @undefined + ); + + // Only create descendant if it will have own properties. + if (needsDefaults) { + options = @Object.create(options) + options.year = "numeric"; + options.month = "numeric"; + options.day = "numeric"; + } + + return options; + } + + // 13.3.2 Date.prototype.toLocaleDateString ([locales [, options ]]) (ECMA-402 2.0) + // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleDateString + + var value = @thisTimeValue.@call(this); + if (@isNaN(value)) + return "Invalid Date"; + + var options = toDateTimeOptionsDateDate(arguments[1]); + var locales = arguments[0]; + + var dateFormat = new @DateTimeFormat(locales, options); + return dateFormat.format(value); +} + +function toLocaleTimeString(/* locales, options */) +{ + "use strict"; + + function toDateTimeOptionsTimeTime(opts) + { + // ToDateTimeOptions(options, "time", "time") + // http://www.ecma-international.org/ecma-402/2.0/#sec-InitializeDateTimeFormat + + var options; + if (opts === @undefined) + options = null; + else if (opts === null) + throw new @TypeError("null is not an object"); + else + options = @Object(opts); + + // Check original instead of descendant to reduce lookups up the prototype chain. + var needsDefaults = !options || ( + options.hour === @undefined && + options.minute === @undefined && + options.second === @undefined + ); + + // Only create descendant if it will have own properties. + if (needsDefaults) { + options = @Object.create(options) + options.hour = "numeric"; + options.minute = "numeric"; + options.second = "numeric"; + } + + return options; + } + + // 13.3.3 Date.prototype.toLocaleTimeString ([locales [, options ]]) (ECMA-402 2.0) + // http://www.ecma-international.org/ecma-402/2.0/#sec-Date.prototype.toLocaleTimeString + + var value = @thisTimeValue.@call(this); + if (@isNaN(value)) + return "Invalid Date"; + + var options = toDateTimeOptionsTimeTime(arguments[1]); + var locales = arguments[0]; + + var dateFormat = new @DateTimeFormat(locales, options); + return dateFormat.format(value); +} diff --git a/Source/JavaScriptCore/builtins/FunctionPrototype.js b/Source/JavaScriptCore/builtins/FunctionPrototype.js new file mode 100644 index 000000000..364bc4328 --- /dev/null +++ b/Source/JavaScriptCore/builtins/FunctionPrototype.js @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function call(thisArgument) +{ + "use strict"; + + return this.@call(...arguments); +} + +function apply(thisValue, argumentValues) +{ + "use strict"; + + return this.@apply(thisValue, argumentValues); +} + +// FIXME: this should have a different name: https://bugs.webkit.org/show_bug.cgi?id=151363 +function symbolHasInstance(value) +{ + "use strict"; + + if (typeof this !== "function") + return false; + + if (@isBoundFunction(this)) + return @hasInstanceBoundFunction(this, value); + + let target = this.prototype; + return @instanceOf(value, target); +} diff --git a/Source/JavaScriptCore/builtins/GeneratorPrototype.js b/Source/JavaScriptCore/builtins/GeneratorPrototype.js new file mode 100644 index 000000000..597a8821d --- /dev/null +++ b/Source/JavaScriptCore/builtins/GeneratorPrototype.js @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// 25.3.3.3 GeneratorResume ( generator, value ) +// 25.3.3.4 GeneratorResumeAbrupt(generator, abruptCompletion) +function generatorResume(generator, sentValue, resumeMode) +{ + "use strict"; + + // GeneratorState. + const Completed = -1; + const Executing = -2; + + // ResumeMode. + const NormalMode = 0; + const ReturnMode = 1; + const ThrowMode = 2; + + let state = generator.@generatorState; + let done = false; + let value = @undefined; + + if (typeof state !== 'number') + throw new @TypeError("|this| should be a generator"); + + if (state === Executing) + throw new @TypeError("Generator is executing"); + + if (state === Completed) { + if (resumeMode === ThrowMode) + throw sentValue; + + done = true; + if (resumeMode === ReturnMode) + value = sentValue; + } else { + try { + generator.@generatorState = Executing; + value = generator.@generatorNext.@call(generator.@generatorThis, generator, state, sentValue, resumeMode); + if (generator.@generatorState === Executing) { + generator.@generatorState = Completed; + done = true; + } + } catch (error) { + generator.@generatorState = Completed; + throw error; + } + } + return { done, value }; +} + +function next(value) +{ + "use strict"; + + return @generatorResume(this, value, /* NormalMode */ 0); +} + +function return(value) +{ + "use strict"; + + return @generatorResume(this, value, /* ReturnMode */ 1); +} + +function throw(exception) +{ + "use strict"; + + return @generatorResume(this, exception, /* ThrowMode */ 2); +} diff --git a/Source/JavaScriptCore/builtins/GlobalObject.js b/Source/JavaScriptCore/builtins/GlobalObject.js new file mode 100644 index 000000000..db53c397b --- /dev/null +++ b/Source/JavaScriptCore/builtins/GlobalObject.js @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// @internal + +function toInteger(target) +{ + "use strict"; + + var numberValue = @Number(target); + + // isNaN(numberValue) + if (numberValue !== numberValue) + return 0; + + if (numberValue === 0 || !@isFinite(numberValue)) + return numberValue; + + return (numberValue > 0 ? 1 : -1) * @floor(@abs(numberValue)); +} + +function toLength(target) +{ + "use strict"; + + var maxSafeInteger = 0x1FFFFFFFFFFFFF; + var length = @toInteger(target); + // originally Math.min(Math.max(length, 0), maxSafeInteger)); + return length > 0 ? (length < maxSafeInteger ? length : maxSafeInteger) : 0; +} + +function isDictionary(object) +{ + "use strict"; + + return object === @undefined || object == null || typeof object === "object"; +} + +// FIXME: this needs to have it's name changed to "get [Symbol.species]". +// see: https://bugs.webkit.org/show_bug.cgi?id=151363 +function speciesGetter() +{ + return this; +} diff --git a/Source/JavaScriptCore/builtins/InspectorInstrumentationObject.js b/Source/JavaScriptCore/builtins/InspectorInstrumentationObject.js new file mode 100644 index 000000000..fb7d9eae6 --- /dev/null +++ b/Source/JavaScriptCore/builtins/InspectorInstrumentationObject.js @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function promiseFulfilled(promise, value, reactions) +{ + "use strict"; + + if (!this.isEnabled) + return; +} + +function promiseRejected(promise, reason, reactions) +{ + "use strict"; + + if (!this.isEnabled) + return; +} diff --git a/Source/JavaScriptCore/builtins/InternalPromiseConstructor.js b/Source/JavaScriptCore/builtins/InternalPromiseConstructor.js new file mode 100644 index 000000000..d01f5f7e5 --- /dev/null +++ b/Source/JavaScriptCore/builtins/InternalPromiseConstructor.js @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function internalAll(array) +{ + // This function is intended to be used in the JSC internals. + // The implementation should take care not to perform the user + // observable / trappable operations. + // + // 1. Don't use for-of and iterables. This function only accepts + // the dense array of the promises. + // 2. Don't look up this.constructor / @@species. Always construct + // the plain Promise object. + + "use strict"; + + var promiseCapability = @newPromiseCapability(@InternalPromise); + + var values = []; + var index = 0; + var remainingElementsCount = 0; + + function newResolveElement(index) + { + var alreadyCalled = false; + return function (argument) + { + if (alreadyCalled) + return @undefined; + alreadyCalled = true; + + @putByValDirect(values, index, argument); + + --remainingElementsCount; + if (remainingElementsCount === 0) + return promiseCapability.@resolve.@call(@undefined, values); + + return @undefined; + } + } + + try { + if (array.length === 0) + promiseCapability.@resolve.@call(@undefined, values); + else { + for (var index = 0, length = array.length; index < length; ++index) { + var value = array[index]; + @putByValDirect(values, index, @undefined); + + var nextPromiseCapability = @newPromiseCapability(@InternalPromise); + nextPromiseCapability.@resolve.@call(@undefined, value); + var nextPromise = nextPromiseCapability.@promise; + + var resolveElement = newResolveElement(index); + ++remainingElementsCount; + nextPromise.then(resolveElement, promiseCapability.@reject); + } + } + } catch (error) { + promiseCapability.@reject.@call(@undefined, error); + } + + return promiseCapability.@promise; +} diff --git a/Source/JavaScriptCore/builtins/IteratorPrototype.js b/Source/JavaScriptCore/builtins/IteratorPrototype.js new file mode 100644 index 000000000..5c1691a3d --- /dev/null +++ b/Source/JavaScriptCore/builtins/IteratorPrototype.js @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function symbolIteratorGetter() +{ + "use strict"; + + return this; +} diff --git a/Source/JavaScriptCore/builtins/MapPrototype.js b/Source/JavaScriptCore/builtins/MapPrototype.js new file mode 100644 index 000000000..620a015d3 --- /dev/null +++ b/Source/JavaScriptCore/builtins/MapPrototype.js @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function forEach(callback /*, thisArg */) +{ + "use strict"; + + if (!@isMap(this)) + throw new @TypeError("Map operation called on non-Map object"); + + if (typeof callback !== 'function') + throw new @TypeError("Map.prototype.forEach callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + var iterator = @MapIterator(this); + + // To avoid object allocations for iterator result objects, we pass the placeholder to the special "next" function in order to fill the results. + var value = [ @undefined, @undefined ]; + for (;;) { + if (@mapIteratorNext.@call(iterator, value)) + break; + callback.@call(thisArg, value[1], value[0], this); + } +} diff --git a/Source/JavaScriptCore/builtins/ModuleLoaderObject.js b/Source/JavaScriptCore/builtins/ModuleLoaderObject.js new file mode 100644 index 000000000..568a307b7 --- /dev/null +++ b/Source/JavaScriptCore/builtins/ModuleLoaderObject.js @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// https://whatwg.github.io/loader/#loader-object +// Module Loader has several hooks that can be customized by the platform. +// For example, the [[Fetch]] hook can be provided by the JavaScriptCore shell +// as fetching the payload from the local file system. +// Currently, there are 4 hooks. +// 1. Loader.resolve +// 2. Loader.fetch +// 3. Loader.translate +// 4. Loader.instantiate + +function setStateToMax(entry, newState) +{ + // https://whatwg.github.io/loader/#set-state-to-max + + "use strict"; + + if (entry.state < newState) + entry.state = newState; +} + +function newRegistryEntry(key) +{ + // https://whatwg.github.io/loader/#registry + // + // Each registry entry becomes one of the 5 states. + // 1. Fetch + // Ready to fetch (or now fetching) the resource of this module. + // Typically, we fetch the source code over the network or from the file system. + // a. If the status is Fetch and there is no entry.fetch promise, the entry is ready to fetch. + // b. If the status is Fetch and there is the entry.fetch promise, the entry is just fetching the resource. + // + // 2. Translate + // Ready to translate (or now translating) the raw fetched resource to the ECMAScript source code. + // We can insert the hook that translates the resources e.g. transpilers. + // a. If the status is Translate and there is no entry.translate promise, the entry is ready to translate. + // b. If the status is Translate and there is the entry.translate promise, the entry is just translating + // the payload to the source code. + // + // 3. Instantiate (AnalyzeModule) + // Ready to instantiate (or now instantiating) the module record from the fetched (and translated) + // source code. + // Typically, we parse the module code, extract the dependencies and binding information. + // a. If the status is Instantiate and there is no entry.instantiate promise, the entry is ready to instantiate. + // b. If the status is Instantiate and there is the entry.translate promise, the entry is just instantiating + // the module record. + // + // 4. ResolveDependencies (not in the draft) https://github.com/whatwg/loader/issues/68 + // Ready to request the dependent modules (or now requesting & resolving). + // Without this state, the current draft causes infinite recursion when there is circular dependency. + // a. If the status is ResolveDependencies and there is no entry.resolveDependencies promise, the entry is ready to resolve the dependencies. + // b. If the status is ResolveDependencies and there is the entry.resolveDependencies promise, the entry is just resolving + // the dependencies. + // + // 5. Link + // Ready to link the module with the other modules. + // Linking means that the module imports and exports the bindings from/to the other modules. + // + // 6. Ready + // The module is linked, so the module is ready to be executed. + // + // Each registry entry has the 4 promises; "fetch", "translate", "instantiate" and "resolveDependencies". + // They are assigned when starting the each phase. And they are fulfilled when the each phase is completed. + // + // In the current module draft, linking will be performed after the whole modules are instantiated and the dependencies are resolved. + // And execution is also done after the all modules are linked. + // + // TODO: We need to exploit the way to execute the module while fetching non-related modules. + // One solution; introducing the ready promise chain to execute the modules concurrently while keeping + // the execution order. + + "use strict"; + + return { + key: key, + state: this.Fetch, + metadata: @undefined, + fetch: @undefined, + translate: @undefined, + instantiate: @undefined, + resolveDependencies: @undefined, + dependencies: [], // To keep the module order, we store the module keys in the array. + dependenciesMap: @undefined, + module: @undefined, // JSModuleRecord + error: @undefined, + }; +} + +function ensureRegistered(key) +{ + // https://whatwg.github.io/loader/#ensure-registered + + "use strict"; + + var entry = this.registry.@get(key); + if (entry) + return entry; + + entry = this.newRegistryEntry(key); + this.registry.@set(key, entry); + + return entry; +} + +function forceFulfillPromise(promise, value) +{ + "use strict"; + + if (promise.@promiseState === @promiseStatePending) + @fulfillPromise(promise, value); +} + +function fulfillFetch(entry, payload) +{ + // https://whatwg.github.io/loader/#fulfill-fetch + + "use strict"; + + if (!entry.fetch) + entry.fetch = @newPromiseCapability(@InternalPromise).@promise; + this.forceFulfillPromise(entry.fetch, payload); + this.setStateToMax(entry, this.Translate); +} + +function fulfillTranslate(entry, source) +{ + // https://whatwg.github.io/loader/#fulfill-translate + + "use strict"; + + if (!entry.translate) + entry.translate = @newPromiseCapability(@InternalPromise).@promise; + this.forceFulfillPromise(entry.translate, source); + this.setStateToMax(entry, this.Instantiate); +} + +function fulfillInstantiate(entry, optionalInstance, source) +{ + // https://whatwg.github.io/loader/#fulfill-instantiate + + "use strict"; + + if (!entry.instantiate) + entry.instantiate = @newPromiseCapability(@InternalPromise).@promise; + this.commitInstantiated(entry, optionalInstance, source); + + // FIXME: The draft fulfills the promise in the CommitInstantiated operation. + // But it CommitInstantiated is also used in the requestInstantiate and + // we should not "force fulfill" there. + // So we separate "force fulfill" operation from the CommitInstantiated operation. + // https://github.com/whatwg/loader/pull/67 + this.forceFulfillPromise(entry.instantiate, entry); +} + +function commitInstantiated(entry, optionalInstance, source) +{ + // https://whatwg.github.io/loader/#commit-instantiated + + "use strict"; + + var moduleRecord = this.instantiation(optionalInstance, source, entry); + + // FIXME: Described in the draft, + // 4. Fulfill entry.[[Instantiate]] with instance. + // But, instantiate promise should be fulfilled with the entry. + // We remove this statement because instantiate promise will be + // fulfilled without this "force fulfill" operation. + // https://github.com/whatwg/loader/pull/67 + + var dependencies = []; + var dependenciesMap = moduleRecord.dependenciesMap; + moduleRecord.registryEntry = entry; + var requestedModules = this.requestedModules(moduleRecord); + for (var i = 0, length = requestedModules.length; i < length; ++i) { + var depKey = requestedModules[i]; + var pair = { + key: depKey, + value: @undefined + }; + @putByValDirect(dependencies, i, pair); + dependenciesMap.@set(depKey, pair); + } + entry.dependencies = dependencies; + entry.dependenciesMap = dependenciesMap; + entry.module = moduleRecord; + this.setStateToMax(entry, this.ResolveDependencies); +} + +function instantiation(result, source, entry) +{ + // https://whatwg.github.io/loader/#instantiation + // FIXME: Current implementation does not support optionalInstance. + // https://bugs.webkit.org/show_bug.cgi?id=148171 + + "use strict"; + + return this.parseModule(entry.key, source); +} + +// Loader. + +function requestFetch(key) +{ + // https://whatwg.github.io/loader/#request-fetch + + "use strict"; + + var entry = this.ensureRegistered(key); + if (entry.state > this.Link) { + var deferred = @newPromiseCapability(@InternalPromise); + deferred.@reject.@call(@undefined, new @TypeError("Requested module is already ready to be executed.")); + return deferred.@promise; + } + + if (entry.fetch) + return entry.fetch; + + var loader = this; + + // Hook point. + // 2. Loader.fetch + // https://whatwg.github.io/loader/#browser-fetch + // Take the key and fetch the resource actually. + // For example, JavaScriptCore shell can provide the hook fetching the resource + // from the local file system. + var fetchPromise = this.fetch(key).then(function (payload) { + loader.setStateToMax(entry, loader.Translate); + return payload; + }); + entry.fetch = fetchPromise; + return fetchPromise; +} + +function requestTranslate(key) +{ + // https://whatwg.github.io/loader/#request-translate + + "use strict"; + + var entry = this.ensureRegistered(key); + if (entry.state > this.Link) { + var deferred = @newPromiseCapability(@InternalPromise); + deferred.@reject.@call(@undefined, new @TypeError("Requested module is already ready to be executed.")); + return deferred.@promise; + } + + if (entry.translate) + return entry.translate; + + var loader = this; + var translatePromise = this.requestFetch(key).then(function (payload) { + // Hook point. + // 3. Loader.translate + // https://whatwg.github.io/loader/#browser-translate + // Take the key and the fetched source code and translate it to the ES6 source code. + // Typically it is used by the transpilers. + return loader.translate(key, payload).then(function (source) { + loader.setStateToMax(entry, loader.Instantiate); + return source; + }); + }); + entry.translate = translatePromise; + return translatePromise; +} + +function requestInstantiate(key) +{ + // https://whatwg.github.io/loader/#request-instantiate + + "use strict"; + + var entry = this.ensureRegistered(key); + if (entry.state > this.Link) { + var deferred = @newPromiseCapability(@InternalPromise); + deferred.@reject.@call(@undefined, new @TypeError("Requested module is already ready to be executed.")); + return deferred.@promise; + } + + if (entry.instantiate) + return entry.instantiate; + + var loader = this; + var instantiatePromise = this.requestTranslate(key).then(function (source) { + // Hook point. + // 4. Loader.instantiate + // https://whatwg.github.io/loader/#browser-instantiate + // Take the key and the translated source code, and instantiate the module record + // by parsing the module source code. + // It has the chance to provide the optional module instance that is different from + // the ordinary one. + return loader.instantiate(key, source).then(function (optionalInstance) { + loader.commitInstantiated(entry, optionalInstance, source); + return entry; + }); + }); + entry.instantiate = instantiatePromise; + return instantiatePromise; +} + +function requestResolveDependencies(key) +{ + // FIXME: In the spec, after requesting instantiation, we will resolve + // the dependencies without any status change. As a result, when there + // is circular dependencies, instantiation is done only once, but + // repeatedly resolving the dependencies. This means that infinite + // recursion occur when the given modules have circular dependency. To + // avoid this situation, we introduce new state, "ResolveDependencies". This means + // "Now the module is instantiated, so ready to resolve the dependencies + // or now resolving them". + // https://github.com/whatwg/loader/issues/68 + + "use strict"; + + var entry = this.ensureRegistered(key); + if (entry.state > this.Link) { + var deferred = @newPromiseCapability(@InternalPromise); + deferred.@reject.@call(@undefined, new @TypeError("Requested module is already ready to be executed.")); + return deferred.@promise; + } + + if (entry.resolveDependencies) + return entry.resolveDependencies; + + var loader = this; + var resolveDependenciesPromise = this.requestInstantiate(key).then(function (entry) { + var depLoads = []; + for (var i = 0, length = entry.dependencies.length; i < length; ++i) { + let pair = entry.dependencies[i]; + + // Hook point. + // 1. Loader.resolve. + // https://whatwg.github.io/loader/#browser-resolve + // Take the name and resolve it to the unique identifier for the resource location. + // For example, take the "jquery" and return the URL for the resource. + var promise = loader.resolve(pair.key, key).then(function (depKey) { + var depEntry = loader.ensureRegistered(depKey); + + // Recursive resolving. The dependencies of this entry is being resolved or already resolved. + // Stop tracing the circular dependencies. + // But to retrieve the instantiated module record correctly, + // we need to wait for the instantiation for the dependent module. + // For example, reaching here, the module is starting resolving the dependencies. + // But the module may or may not reach the instantiation phase in the loader's pipeline. + // If we wait for the ResolveDependencies for this module, it construct the circular promise chain and + // rejected by the Promises runtime. Since only we need is the instantiated module, instead of waiting + // the ResolveDependencies for this module, we just wait Instantiate for this. + if (depEntry.resolveDependencies) { + return depEntry.instantiate.then(function (entry) { + pair.value = entry.module; + return entry; + }); + } + + return loader.requestResolveDependencies(depKey).then(function (entry) { + pair.value = entry.module; + return entry; + }); + }); + @putByValDirect(depLoads, i, promise); + } + + return @InternalPromise.internalAll(depLoads).then(function (modules) { + loader.setStateToMax(entry, loader.Link); + return entry; + }); + }); + + entry.resolveDependencies = resolveDependenciesPromise; + return resolveDependenciesPromise; +} + +function requestInstantiateAll(key) +{ + // https://whatwg.github.io/loader/#request-instantiate-all + + "use strict"; + + return this.requestResolveDependencies(key); +} + +function requestLink(key) +{ + // https://whatwg.github.io/loader/#request-link + + "use strict"; + + var entry = this.ensureRegistered(key); + if (entry.state > this.Link) { + var deferred = @newPromiseCapability(@InternalPromise); + deferred.@resolve.@call(@undefined, entry.module); + return deferred.@promise; + } + + var loader = this; + return this.requestInstantiateAll(key).then(function (entry) { + loader.link(entry); + return entry; + }); +} + +function requestReady(key) +{ + // https://whatwg.github.io/loader/#request-ready + + "use strict"; + + var loader = this; + return this.requestLink(key).then(function (entry) { + loader.moduleEvaluation(entry.module); + }); +} + +// Linking semantics. + +function link(entry) +{ + // https://whatwg.github.io/loader/#link + + "use strict"; + + // FIXME: Current implementation does not support optionalInstance. + // So Link's step 3 is skipped. + // https://bugs.webkit.org/show_bug.cgi?id=148171 + + if (entry.state === this.Ready) + return; + this.setStateToMax(entry, this.Ready); + + // Since we already have the "dependencies" field, + // we can call moduleDeclarationInstantiation with the correct order + // without constructing the dependency graph by calling dependencyGraph. + var dependencies = entry.dependencies; + for (var i = 0, length = dependencies.length; i < length; ++i) { + var pair = dependencies[i]; + this.link(pair.value.registryEntry); + } + + this.moduleDeclarationInstantiation(entry.module); +} + +// Module semantics. + +function moduleEvaluation(moduleRecord) +{ + // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation + + "use strict"; + + if (moduleRecord.evaluated) + return; + moduleRecord.evaluated = true; + + var entry = moduleRecord.registryEntry; + + // The contents of the [[RequestedModules]] is cloned into entry.dependencies. + var dependencies = entry.dependencies; + for (var i = 0, length = dependencies.length; i < length; ++i) { + var pair = dependencies[i]; + var requiredModuleRecord = pair.value; + this.moduleEvaluation(requiredModuleRecord); + } + this.evaluate(entry.key, moduleRecord); +} + +// APIs to control the module loader. + +function provide(key, stage, value) +{ + "use strict"; + + var entry = this.ensureRegistered(key); + + if (stage === this.Fetch) { + if (entry.status > this.Fetch) + throw new @TypeError("Requested module is already fetched."); + this.fulfillFetch(entry, value); + return; + } + + if (stage === this.Translate) { + if (entry.status > this.Translate) + throw new @TypeError("Requested module is already translated."); + this.fulfillFetch(entry, @undefined); + this.fulfillTranslate(entry, value); + return; + } + + if (stage === this.Instantiate) { + if (entry.status > this.Instantiate) + throw new @TypeError("Requested module is already instantiated."); + this.fulfillFetch(entry, @undefined); + this.fulfillTranslate(entry, value); + var loader = this; + entry.translate.then(function (source) { + loader.fulfillInstantiate(entry, value, source); + }); + return; + } + + throw new @TypeError("Requested module is already ready to be executed."); +} + +function loadAndEvaluateModule(moduleName, referrer) +{ + "use strict"; + + var loader = this; + // Loader.resolve hook point. + // resolve: moduleName => Promise(moduleKey) + // Take the name and resolve it to the unique identifier for the resource location. + // For example, take the "jquery" and return the URL for the resource. + return this.resolve(moduleName, referrer).then(function (key) { + return loader.requestReady(key); + }); +} + +function loadModule(moduleName, referrer) +{ + "use strict"; + + var loader = this; + // Loader.resolve hook point. + // resolve: moduleName => Promise(moduleKey) + // Take the name and resolve it to the unique identifier for the resource location. + // For example, take the "jquery" and return the URL for the resource. + return this.resolve(moduleName, referrer).then(function (key) { + return loader.requestInstantiateAll(key); + }).then(function (entry) { + return entry.key; + }); +} + +function linkAndEvaluateModule(key) +{ + "use strict"; + + return this.requestReady(key); +} diff --git a/Source/JavaScriptCore/builtins/NumberPrototype.js b/Source/JavaScriptCore/builtins/NumberPrototype.js new file mode 100644 index 000000000..49a1a8b8a --- /dev/null +++ b/Source/JavaScriptCore/builtins/NumberPrototype.js @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Andy VanWagoner <thetalecrafter@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// @conditional=ENABLE(INTL) + +function toLocaleString(/* locales, options */) +{ + "use strict"; + + // 13.2.1 Number.prototype.toLocaleString ([locales [, options ]]) (ECMA-402 2.0) + // http://ecma-international.org/publications/standards/Ecma-402.htm + + // 1. Let x be thisNumberValue(this value). + // 2. ReturnIfAbrupt(x). + var number = this; + if (!(typeof number === "number" || number instanceof @Number)) + throw new @TypeError("Number.prototype.toLocaleString called on incompatible " + typeof number); + + // 3. Let numberFormat be Construct(%NumberFormat%, «locales, options»). + // 4. ReturnIfAbrupt(numberFormat). + var numberFormat = new @NumberFormat(arguments[0], arguments[1]); + + // 5. Return FormatNumber(numberFormat, x). + return numberFormat.format(number); +} diff --git a/Source/JavaScriptCore/builtins/ObjectConstructor.js b/Source/JavaScriptCore/builtins/ObjectConstructor.js new file mode 100644 index 000000000..4fa7ddf18 --- /dev/null +++ b/Source/JavaScriptCore/builtins/ObjectConstructor.js @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Jordan Harband. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function assign(target/*[*/, /*...*/sources/*] */) +{ + "use strict"; + + if (target == null) + throw new @TypeError("can't convert " + target + " to object"); + + var objTarget = @Object(target); + for (var s = 1, argumentsLength = arguments.length; s < argumentsLength; ++s) { + var nextSource = arguments[s]; + if (nextSource != null) { + var from = @Object(nextSource); + var keys = @ownEnumerablePropertyKeys(from); + for (var i = 0, keysLength = keys.length; i < keysLength; ++i) { + var nextKey = keys[i]; + objTarget[nextKey] = from[nextKey]; + } + } + } + return objTarget; +} diff --git a/Source/JavaScriptCore/builtins/PromiseConstructor.js b/Source/JavaScriptCore/builtins/PromiseConstructor.js new file mode 100644 index 000000000..77ce57c83 --- /dev/null +++ b/Source/JavaScriptCore/builtins/PromiseConstructor.js @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function all(iterable) +{ + "use strict"; + + if (!@isObject(this)) + throw new @TypeError("|this| is not a object"); + + // FIXME: Fix this code when @@species well-known symbol is landed. + // https://bugs.webkit.org/show_bug.cgi?id=146624 + var constructor = this; + + var promiseCapability = @newPromiseCapability(constructor); + + var values = []; + var index = 0; + var remainingElementsCount = 1; + + function newResolveElement(index) + { + var alreadyCalled = false; + return function (argument) + { + if (alreadyCalled) + return @undefined; + alreadyCalled = true; + + @putByValDirect(values, index, argument); + + --remainingElementsCount; + if (remainingElementsCount === 0) + return promiseCapability.@resolve.@call(@undefined, values); + + return @undefined; + } + } + + try { + for (var value of iterable) { + @putByValDirect(values, index, @undefined); + var nextPromise = constructor.resolve(value); + var resolveElement = newResolveElement(index); + ++remainingElementsCount; + nextPromise.then(resolveElement, promiseCapability.@reject); + ++index; + } + + --remainingElementsCount; + if (remainingElementsCount === 0) + promiseCapability.@resolve.@call(@undefined, values); + } catch (error) { + promiseCapability.@reject.@call(@undefined, error); + } + + return promiseCapability.@promise; +} + +function race(iterable) +{ + "use strict"; + + if (!@isObject(this)) + throw new @TypeError("|this| is not a object"); + + // FIXME: Fix this code when @@species well-known symbol is landed. + // https://bugs.webkit.org/show_bug.cgi?id=146624 + var constructor = this; + + var promiseCapability = @newPromiseCapability(constructor); + + try { + for (var value of iterable) { + var nextPromise = constructor.resolve(value); + nextPromise.then(promiseCapability.@resolve, promiseCapability.@reject); + } + } catch (error) { + promiseCapability.@reject.@call(@undefined, error); + } + + return promiseCapability.@promise; +} + +function reject(reason) +{ + "use strict"; + + if (!@isObject(this)) + throw new @TypeError("|this| is not a object"); + + var promiseCapability = @newPromiseCapability(this); + + promiseCapability.@reject.@call(@undefined, reason); + + return promiseCapability.@promise; +} + +function resolve(value) +{ + "use strict"; + + if (!@isObject(this)) + throw new @TypeError("|this| is not a object"); + + if (@isPromise(value)) { + var valueConstructor = value.constructor; + if (valueConstructor === this) + return value; + } + + var promiseCapability = @newPromiseCapability(this); + + promiseCapability.@resolve.@call(@undefined, value); + + return promiseCapability.@promise; +} diff --git a/Source/JavaScriptCore/builtins/PromiseOperations.js b/Source/JavaScriptCore/builtins/PromiseOperations.js new file mode 100644 index 000000000..c4e59bb07 --- /dev/null +++ b/Source/JavaScriptCore/builtins/PromiseOperations.js @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// @internal + +function isPromise(promise) +{ + "use strict"; + + return @isObject(promise) && !!promise.@promiseState; +} + +function newPromiseReaction(capability, handler) +{ + "use strict"; + + return { + @capabilities: capability, + @handler: handler + }; +} + +function newPromiseCapability(constructor) +{ + "use strict"; + + // FIXME: Check isConstructor(constructor). + if (typeof constructor !== "function") + throw new @TypeError("promise capability requires a constructor function"); + + var promiseCapability = { + @promise: @undefined, + @resolve: @undefined, + @reject: @undefined + }; + + function executor(resolve, reject) + { + if (promiseCapability.@resolve !== @undefined) + throw new @TypeError("resolve function is already set"); + if (promiseCapability.@reject !== @undefined) + throw new @TypeError("reject function is already set"); + + promiseCapability.@resolve = resolve; + promiseCapability.@reject = reject; + } + + var promise = new constructor(executor); + + if (typeof promiseCapability.@resolve !== "function") + throw new @TypeError("executor did not take a resolve function"); + + if (typeof promiseCapability.@reject !== "function") + throw new @TypeError("executor did not take a reject function"); + + promiseCapability.@promise = promise; + + return promiseCapability; +} + +function triggerPromiseReactions(reactions, argument) +{ + "use strict"; + + for (var index = 0, length = reactions.length; index < length; ++index) + @enqueueJob(@promiseReactionJob, [reactions[index], argument]); +} + +function rejectPromise(promise, reason) +{ + "use strict"; + + var reactions = promise.@promiseRejectReactions; + promise.@promiseResult = reason; + promise.@promiseFulfillReactions = @undefined; + promise.@promiseRejectReactions = @undefined; + promise.@promiseState = @promiseStateRejected; + + @InspectorInstrumentation.promiseRejected(promise, reason, reactions); + + @triggerPromiseReactions(reactions, reason); +} + +function fulfillPromise(promise, value) +{ + "use strict"; + + var reactions = promise.@promiseFulfillReactions; + promise.@promiseResult = value; + promise.@promiseFulfillReactions = @undefined; + promise.@promiseRejectReactions = @undefined; + promise.@promiseState = @promiseStateFulfilled; + + @InspectorInstrumentation.promiseFulfilled(promise, value, reactions); + + @triggerPromiseReactions(reactions, value); +} + +function createResolvingFunctions(promise) +{ + "use strict"; + + var alreadyResolved = false; + + var resolve = function (resolution) { + if (alreadyResolved) + return @undefined; + alreadyResolved = true; + + if (resolution === promise) + return @rejectPromise(promise, new @TypeError("Resolve a promise with itself")); + + if (!@isObject(resolution)) + return @fulfillPromise(promise, resolution); + + var then; + try { + then = resolution.then; + } catch (error) { + return @rejectPromise(promise, error); + } + + if (typeof then !== 'function') + return @fulfillPromise(promise, resolution); + + @enqueueJob(@promiseResolveThenableJob, [promise, resolution, then]); + + return @undefined; + }; + + var reject = function (reason) { + if (alreadyResolved) + return @undefined; + alreadyResolved = true; + + return @rejectPromise(promise, reason); + }; + + return { + @resolve: resolve, + @reject: reject + }; +} + +function promiseReactionJob(reaction, argument) +{ + "use strict"; + + var promiseCapability = reaction.@capabilities; + + var result; + try { + result = reaction.@handler.@call(@undefined, argument); + } catch (error) { + return promiseCapability.@reject.@call(@undefined, error); + } + + return promiseCapability.@resolve.@call(@undefined, result); +} + +function promiseResolveThenableJob(promiseToResolve, thenable, then) +{ + "use strict"; + + var resolvingFunctions = @createResolvingFunctions(promiseToResolve); + + try { + return then.@call(thenable, resolvingFunctions.@resolve, resolvingFunctions.@reject); + } catch (error) { + return resolvingFunctions.@reject.@call(@undefined, error); + } +} + +function initializePromise(executor) +{ + "use strict"; + + if (typeof executor !== 'function') + throw new @TypeError("Promise constructor takes a function argument"); + + this.@promiseState = @promiseStatePending; + this.@promiseFulfillReactions = []; + this.@promiseRejectReactions = []; + + var resolvingFunctions = @createResolvingFunctions(this); + try { + executor(resolvingFunctions.@resolve, resolvingFunctions.@reject); + } catch (error) { + return resolvingFunctions.@reject.@call(@undefined, error); + } + + return this; +} diff --git a/Source/JavaScriptCore/builtins/PromisePrototype.js b/Source/JavaScriptCore/builtins/PromisePrototype.js new file mode 100644 index 000000000..ec604b828 --- /dev/null +++ b/Source/JavaScriptCore/builtins/PromisePrototype.js @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +function catch(onRejected) +{ + "use strict"; + + return this.then(@undefined, onRejected); +} + +function then(onFulfilled, onRejected) +{ + "use strict"; + + if (!@isPromise(this)) + throw new @TypeError("|this| is not a object"); + + // FIXME: Fix this code when @@species well-known symbol is landed. + // https://bugs.webkit.org/show_bug.cgi?id=146624 + var constructor = this.constructor; + + var resultCapability = @newPromiseCapability(constructor); + + if (typeof onFulfilled !== "function") + onFulfilled = function (argument) { return argument; }; + + if (typeof onRejected !== "function") + onRejected = function (argument) { throw argument; }; + + var fulfillReaction = @newPromiseReaction(resultCapability, onFulfilled); + var rejectReaction = @newPromiseReaction(resultCapability, onRejected); + + var state = this.@promiseState; + + if (state === @promiseStatePending) { + @putByValDirect(this.@promiseFulfillReactions, this.@promiseFulfillReactions.length, fulfillReaction) + @putByValDirect(this.@promiseRejectReactions, this.@promiseRejectReactions.length, rejectReaction) + } else if (state === @promiseStateFulfilled) + @enqueueJob(@promiseReactionJob, [fulfillReaction, this.@promiseResult]); + else if (state === @promiseStateRejected) + @enqueueJob(@promiseReactionJob, [rejectReaction, this.@promiseResult]); + + return resultCapability.@promise; +} diff --git a/Source/JavaScriptCore/builtins/ReflectObject.js b/Source/JavaScriptCore/builtins/ReflectObject.js new file mode 100644 index 000000000..69c982850 --- /dev/null +++ b/Source/JavaScriptCore/builtins/ReflectObject.js @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.apply +function apply(target, thisArgument, argumentsList) +{ + "use strict"; + + if (typeof target !== "function") + throw new @TypeError("Reflect.apply requires the first argument be a function"); + + if (!@isObject(argumentsList)) + throw new @TypeError("Reflect.apply requires the third argument be an object"); + + return target.@apply(thisArgument, argumentsList); +} + +// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.deleteproperty +function deleteProperty(target, propertyKey) +{ + // Intentionally keep the code the sloppy mode to suppress the TypeError + // raised by the delete operator under the strict mode. + + if (!@isObject(target)) + throw new @TypeError("Reflect.deleteProperty requires the first argument be an object"); + + return delete target[propertyKey]; +} + +// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.has +function has(target, propertyKey) +{ + "use strict"; + + if (!@isObject(target)) + throw new @TypeError("Reflect.has requires the first argument be an object"); + + return propertyKey in target; +} diff --git a/Source/JavaScriptCore/builtins/SetPrototype.js b/Source/JavaScriptCore/builtins/SetPrototype.js new file mode 100644 index 000000000..55271b529 --- /dev/null +++ b/Source/JavaScriptCore/builtins/SetPrototype.js @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function forEach(callback /*, thisArg */) +{ + "use strict"; + + if (!@isSet(this)) + throw new @TypeError("Set operation called on non-Set object"); + + if (typeof callback !== 'function') + throw new @TypeError("Set.prototype.forEach callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + var iterator = @SetIterator(this); + + // To avoid object allocations for iterator result objects, we pass the placeholder to the special "next" function in order to fill the results. + var value = [ @undefined ]; + for (;;) { + if (@setIteratorNext.@call(iterator, value)) + break; + callback.@call(thisArg, value[0], value[0], this); + } +} diff --git a/Source/JavaScriptCore/builtins/StringConstructor.js b/Source/JavaScriptCore/builtins/StringConstructor.js new file mode 100644 index 000000000..90b435fce --- /dev/null +++ b/Source/JavaScriptCore/builtins/StringConstructor.js @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function raw(template) +{ + "use strict"; + + if (template === null || template === @undefined) + throw new @TypeError("String.raw requires template not be null or undefined"); + var cookedSegments = @Object(template); + + var rawValue = cookedSegments.raw; + if (rawValue === null || rawValue === @undefined) + throw new @TypeError("String.raw requires template.raw not be null or undefined"); + var rawSegments = @Object(rawValue); + + var numberOfSubstitutions = arguments.length - 1; + + var segmentCount = @toLength(rawSegments.length); + + if (segmentCount <= 0) + return ''; + + var stringElements = ''; + for (var i = 0; ; ++i) { + var segment = @toString(rawSegments[i]); + stringElements += segment; + + if ((i + 1) === segmentCount) + return stringElements; + + if (i < numberOfSubstitutions) { + var substitutionIndexInArguments = i + 1; + var next = @toString(arguments[substitutionIndexInArguments]); + stringElements += next; + } + } +} diff --git a/Source/JavaScriptCore/builtins/StringIteratorPrototype.js b/Source/JavaScriptCore/builtins/StringIteratorPrototype.js new file mode 100644 index 000000000..f774ec47a --- /dev/null +++ b/Source/JavaScriptCore/builtins/StringIteratorPrototype.js @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function next() +{ + "use strict"; + + if (this == null) + throw new @TypeError("%StringIteratorPrototype%.next requires that |this| not be null or undefined"); + + var position = this.@stringIteratorNextIndex; + if (position === @undefined) + throw new @TypeError("%StringIteratorPrototype%.next requires that |this| be a String Iterator instance"); + + var done = true; + var value = @undefined; + + var string = this.@iteratedString; + if (string !== @undefined) { + var length = string.length >>> 0; + if (position >= length) { + this.@iteratedString = @undefined; + } else { + done = false; + + var first = string.@charCodeAt(position); + if (first < 0xD800 || first > 0xDBFF || position + 1 === length) + value = string[position]; + else { + var second = string.@charCodeAt(position + 1); + if (second < 0xDC00 || second > 0xDFFF) + value = string[position]; + else + value = string[position] + string[position + 1]; + } + + this.@stringIteratorNextIndex = position + value.length; + } + } + + return {done, value}; +} diff --git a/Source/JavaScriptCore/builtins/StringPrototype.js b/Source/JavaScriptCore/builtins/StringPrototype.js new file mode 100644 index 000000000..9a3049ba1 --- /dev/null +++ b/Source/JavaScriptCore/builtins/StringPrototype.js @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015 Andy VanWagoner <thetalecrafter@gmail.com>. + * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// @conditional=ENABLE(INTL) + +function localeCompare(that/*, locales, options */) +{ + "use strict"; + + // 13.1.1 String.prototype.localeCompare (that [, locales [, options ]]) (ECMA-402 2.0) + // http://ecma-international.org/publications/standards/Ecma-402.htm + + // 1. Let O be RequireObjectCoercible(this value). + if (this === null) + throw new @TypeError("String.prototype.localeCompare requires that |this| not be null"); + + if (this === @undefined) + throw new @TypeError("String.prototype.localeCompare requires that |this| not be undefined"); + + // 2. Let S be ToString(O). + // 3. ReturnIfAbrupt(S). + var thisString = @toString(this); + + // 4. Let That be ToString(that). + // 5. ReturnIfAbrupt(That). + var thatString = @toString(that); + + // Avoid creating a collator for defaults. + if (arguments[1] === @undefined && arguments[2] === @undefined) + return @Collator.prototype.compare(thisString, thatString); + + // 6. Let collator be Construct(%Collator%, «locales, options»). + // 7. ReturnIfAbrupt(collator). + var collator = new @Collator(arguments[1], arguments[2]); + + // 8. Return CompareStrings(collator, S, That). + return collator.compare(thisString, thatString); +} + +function search(regexp) +{ + "use strict"; + + if (this == null) { + if (this === null) + throw new @TypeError("String.prototype.search requires that |this| not be null"); + throw new @TypeError("String.prototype.search requires that |this| not be undefined"); + } + + if (regexp != null) { + var searcher = regexp[@symbolSearch]; + if (searcher !== @undefined) + return searcher.@call(regexp, this); + } + + var thisString = @toString(this); + var createdRegExp = new @RegExp(regexp, @undefined); + return createdRegExp[@symbolSearch](thisString); +} diff --git a/Source/JavaScriptCore/builtins/TypedArrayConstructor.js b/Source/JavaScriptCore/builtins/TypedArrayConstructor.js new file mode 100644 index 000000000..a83d745fd --- /dev/null +++ b/Source/JavaScriptCore/builtins/TypedArrayConstructor.js @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// According to the spec we are supposed to crawl the prototype chain looking +// for the a TypedArray constructor. The way we implement this is with a +// private function, @alloctateTypedArray, on each of the prototypes. +// This enables us to optimize this lookup in the inline cache. + +function of(/* items... */) +{ + "use strict"; + let len = arguments.length; + let constructFunction = this.@allocateTypedArray; + if (constructFunction === @undefined) + throw new @TypeError("TypedArray.from requires its this argument to subclass a TypedArray constructor"); + + let result = constructFunction(len); + + for (let i = 0; i < len; i++) + result[i] = arguments[i]; + + return result; +} + +function from(items /* [ , mapfn [ , thisArg ] ] */) +{ + "use strict"; + + let mapFn = arguments[1]; + + let thisArg; + + if (mapFn !== @undefined) { + if (typeof mapFn !== "function") + throw new @TypeError("TypedArray.from requires that the second argument, when provided, be a function"); + + if (arguments.length > 2) + thisArg = arguments[2]; + } + + if (items == null) + throw new @TypeError("TypedArray.from requires an array-like object - not null or undefined"); + + let iteratorMethod = items[@symbolIterator]; + if (iteratorMethod != null) { + if (typeof iteratorMethod !== "function") + throw new @TypeError("TypedArray.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function"); + + let accumulator = []; + + let k = 0; + let iterator = iteratorMethod.@call(items); + + // Since for-of loop once more looks up the @@iterator property of a given iterable, + // it could be observable if the user defines a getter for @@iterator. + // To avoid this situation, we define a wrapper object that @@iterator just returns a given iterator. + let wrapper = { + [@symbolIterator]() { + return iterator; + } + }; + + + for (let value of wrapper) { + if (mapFn) + @putByValDirect(accumulator, k, thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k)); + else + @putByValDirect(accumulator, k, value); + k++; + } + + let constructFunction = this.@allocateTypedArray; + if (constructFunction === @undefined) + throw new @TypeError("TypedArray.from requires its this argument subclass a TypedArray constructor"); + + let result = constructFunction(k); + + for (let i = 0; i < k; i++) + result[i] = accumulator[i]; + + + return result; + } + + let arrayLike = @Object(items); + let arrayLikeLength = @toLength(arrayLike.length); + + let constructFunction = this.@allocateTypedArray; + if (constructFunction === @undefined) + throw new @TypeError("this does not subclass a TypedArray constructor"); + + let result = constructFunction(arrayLikeLength); + + let k = 0; + while (k < arrayLikeLength) { + let value = arrayLike[k]; + if (mapFn) + result[k] = thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k); + else + result[k] = value; + k++; + } + + return result; +} + +function allocateInt8Array(length) { + + return new @Int8Array(length); + +} + +function allocateInt16Array(length) { + + return new @Int16Array(length); + +} + +function allocateInt32Array(length) { + + return new @Int32Array(length); + +} + +function allocateUint32Array(length) { + + return new @Uint32Array(length); + +} + +function allocateUint16Array(length) { + + return new @Uint16Array(length); + +} + +function allocateUint8Array(length) { + + return new @Uint8Array(length); + +} + +function allocateUint8ClampedArray(length) { + + return new @Uint8ClampedArray(length); + +} + +function allocateFloat32Array(length) { + + return new @Float32Array(length); + +} + +function allocateFloat64Array(length) { + + return new @Float64Array(length); + +} diff --git a/Source/JavaScriptCore/builtins/TypedArrayPrototype.js b/Source/JavaScriptCore/builtins/TypedArrayPrototype.js new file mode 100644 index 000000000..f68bb43bd --- /dev/null +++ b/Source/JavaScriptCore/builtins/TypedArrayPrototype.js @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// Note that the intrisic @typedArrayLength checks the that the argument passed is a typed array +// and throws if it is not. + +function every(callback /*, thisArg */) +{ + "use strict"; + var length = @typedArrayLength(this); + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.every callback must be a function"); + + for (var i = 0; i < length; i++) { + if (!callback.@call(thisArg, this[i], i, this)) + return false; + } + + return true; +} + +function find(callback /* [, thisArg] */) +{ + "use strict"; + var length = @typedArrayLength(this); + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.find callback must be a function"); + + for (var i = 0; i < length; i++) { + let elem = this[i]; + if (callback.@call(thisArg, elem, i, this)) + return elem; + } + return @undefined; +} + +function findIndex(callback /* [, thisArg] */) +{ + "use strict"; + var length = @typedArrayLength(this); + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.findIndex callback must be a function"); + + for (var i = 0; i < length; i++) { + if (callback.@call(thisArg, this[i], i, this)) + return i; + } + return -1; +} + +function forEach(callback /* [, thisArg] */) +{ + "use strict"; + var length = @typedArrayLength(this); + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.forEach callback must be a function"); + + for (var i = 0; i < length; i++) + callback.@call(thisArg, this[i], i, this); +} + +function some(callback /* [, thisArg] */) +{ + // 22.2.3.24 + "use strict"; + var length = @typedArrayLength(this); + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.some callback must be a function"); + + for (var i = 0; i < length; i++) { + if (callback.@call(thisArg, this[i], i, this)) + return true; + } + + return false; +} + +function sort(comparator) +{ + // 22.2.3.25 + "use strict"; + + function min(a, b) + { + return a < b ? a : b; + } + + function merge(dst, src, srcIndex, srcEnd, width, comparator) + { + var left = srcIndex; + var leftEnd = min(left + width, srcEnd); + var right = leftEnd; + var rightEnd = min(right + width, srcEnd); + + for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) { + if (right < rightEnd) { + if (left >= leftEnd || comparator(src[right], src[left]) < 0) { + dst[dstIndex] = src[right++]; + continue; + } + } + + dst[dstIndex] = src[left++]; + } + } + + function mergeSort(array, valueCount, comparator) + { + var buffer = [ ]; + buffer.length = valueCount; + + var dst = buffer; + var src = array; + + for (var width = 1; width < valueCount; width *= 2) { + for (var srcIndex = 0; srcIndex < valueCount; srcIndex += 2 * width) + merge(dst, src, srcIndex, valueCount, width, comparator); + + var tmp = src; + src = dst; + dst = tmp; + } + + if (src != array) { + for(var i = 0; i < valueCount; i++) + array[i] = src[i]; + } + } + + var length = @typedArrayLength(this); + + if (length < 2) + return; + + if (typeof comparator == "function") + mergeSort(this, length, comparator); + else + @typedArraySort(this); + + return this; +} + +function reduce(callback /* [, initialValue] */) +{ + // 22.2.3.19 + "use strict"; + + var length = @typedArrayLength(this); + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.reduce callback must be a function"); + + if (length === 0 && arguments.length < 2) + throw new @TypeError("TypedArray.prototype.reduce of empty array with no initial value"); + + var accumulator, k = 0; + if (arguments.length > 1) + accumulator = arguments[1]; + else + accumulator = this[k++]; + + for (; k < length; k++) + accumulator = callback.@call(@undefined, accumulator, this[k], k, this); + + return accumulator; +} + +function reduceRight(callback /* [, initialValue] */) +{ + // 22.2.3.20 + "use strict"; + + var length = @typedArrayLength(this); + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.reduceRight callback must be a function"); + + if (length === 0 && arguments.length < 2) + throw new @TypeError("TypedArray.prototype.reduceRight of empty array with no initial value"); + + var accumulator, k = length - 1; + if (arguments.length > 1) + accumulator = arguments[1]; + else + accumulator = this[k--]; + + for (; k >= 0; k--) + accumulator = callback.@call(@undefined, accumulator, this[k], k, this); + + return accumulator; +} + +function map(callback /*, thisArg */) +{ + // 22.2.3.18 + "use strict"; + + var length = @typedArrayLength(this); + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.map callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + // FIXME: This should be a species constructor. + var result = new this.constructor(length); + for (var i = 0; i < length; i++) { + var mappedValue = callback.@call(thisArg, this[i], i, this); + result[i] = mappedValue; + } + return result; +} + +function filter(callback /*, thisArg */) +{ + "use strict"; + + var length = @typedArrayLength(this); + + if (typeof callback !== "function") + throw new @TypeError("TypedArray.prototype.filter callback must be a function"); + + var thisArg = arguments.length > 1 ? arguments[1] : @undefined; + + var kept = []; + + for (var i = 0; i < length; i++) { + var value = this[i]; + if (callback.@call(thisArg, value, i, this)) + kept.@push(value); + } + + // FIXME: This should be a species constructor. + var result = new this.constructor(kept.length); + + for (var i = 0; i < kept.length; i++) + result[i] = kept[i]; + + return result; +} + +function toLocaleString() +{ + "use strict"; + + var length = @typedArrayLength(this); + + if (length == 0) + return ""; + + var string = this[0].toLocaleString(); + for (var i = 1; i < length; i++) + string += "," + this[i].toLocaleString(); + + return string; +} |