com.oracle.truffle.js.runtime.builtins.JSArray Maven / Gradle / Ivy
/*
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.truffle.js.runtime.builtins;
import java.util.ArrayList;
import java.util.List;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.js.builtins.ArrayFunctionBuiltins;
import com.oracle.truffle.js.builtins.ArrayPrototypeBuiltins;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSConfig;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.Strings;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.array.ArrayAllocationSite;
import com.oracle.truffle.js.runtime.array.ScriptArray;
import com.oracle.truffle.js.runtime.array.SparseArray;
import com.oracle.truffle.js.runtime.array.dyn.ConstantByteArray;
import com.oracle.truffle.js.runtime.array.dyn.ConstantDoubleArray;
import com.oracle.truffle.js.runtime.array.dyn.ConstantEmptyPrototypeArray;
import com.oracle.truffle.js.runtime.array.dyn.ConstantIntArray;
import com.oracle.truffle.js.runtime.array.dyn.ConstantObjectArray;
import com.oracle.truffle.js.runtime.array.dyn.HolesObjectArray;
import com.oracle.truffle.js.runtime.array.dyn.LazyArray;
import com.oracle.truffle.js.runtime.array.dyn.LazyRegexResultArray;
import com.oracle.truffle.js.runtime.array.dyn.LazyRegexResultIndicesArray;
import com.oracle.truffle.js.runtime.array.dyn.ZeroBasedDoubleArray;
import com.oracle.truffle.js.runtime.array.dyn.ZeroBasedIntArray;
import com.oracle.truffle.js.runtime.array.dyn.ZeroBasedJSObjectArray;
import com.oracle.truffle.js.runtime.array.dyn.ZeroBasedObjectArray;
import com.oracle.truffle.js.runtime.objects.JSAttributes;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.JSObjectUtil;
import com.oracle.truffle.js.runtime.objects.JSProperty;
import com.oracle.truffle.js.runtime.objects.JSShape;
import com.oracle.truffle.js.runtime.objects.PropertyProxy;
public final class JSArray extends JSAbstractArray implements JSConstructorFactory.Default.WithFunctionsAndSpecies, PrototypeSupplier {
public static final TruffleString CLASS_NAME = Strings.UC_ARRAY;
public static final TruffleString PROTOTYPE_NAME = Strings.constant("Array.prototype");
public static final JSArray INSTANCE = new JSArray();
static final ArrayLengthProxyProperty ARRAY_LENGTH_PROPERTY_PROXY = new ArrayLengthProxyProperty();
private JSArray() {
}
public static JSArrayObject createConstant(JSContext context, JSRealm realm, Object[] elements) {
return create(context, realm, ScriptArray.createConstantArray(elements), elements, elements.length);
}
public static JSArrayObject createEmpty(JSContext context, JSRealm realm, int length) {
if (length < 0) {
throw Errors.createRangeErrorInvalidArrayLength();
}
return createEmptyChecked(context, realm, length);
}
/**
* Creates an empty array of a certain size. The size is expected to be within the valid range
* of JavaScript array sizes.
*/
private static JSArrayObject createEmptyChecked(JSContext context, JSRealm realm, int length) {
return createConstantEmptyArray(context, realm, length);
}
/**
* Creates an empty array of a certain size. The size is expected to be within the valid range
* of JavaScript array sizes.
*/
public static JSArrayObject createEmptyChecked(JSContext context, JSRealm realm, long length) {
assert 0 <= length && length <= Integer.MAX_VALUE;
return createConstantEmptyArray(context, realm, (int) length);
}
public static JSArrayObject createEmptyChecked(JSContext context, JSRealm realm, JSDynamicObject proto, long length) {
assert 0 <= length && length <= Integer.MAX_VALUE;
return createConstantEmptyArray(context, realm, proto, null, (int) length);
}
public static JSArrayObject createEmptyZeroLength(JSContext context, JSRealm realm) {
return createConstantEmptyArray(context, realm);
}
public static JSArrayObject create(JSContext context, JSRealm realm, ScriptArray arrayType, Object array, long length) {
return create(context, realm, arrayType, array, length, 0);
}
public static JSArrayObject create(JSContext context, JSRealm realm, ScriptArray arrayType, Object array, long length, int usedLength) {
return create(context, realm, arrayType, array, length, usedLength, 0, 0);
}
public static JSArrayObject create(JSContext context, JSRealm realm, ScriptArray arrayType, Object array, long length, int usedLength, int indexOffset, int arrayOffset) {
return create(context, realm, arrayType, array, length, usedLength, indexOffset, arrayOffset, 0);
}
public static JSArrayObject create(JSContext context, JSRealm realm, ScriptArray arrayType, Object array, long length, int usedLength, int indexOffset, int arrayOffset, int holeCount) {
return createDefaultProto(context, realm, arrayType, array, null, length, usedLength, indexOffset, arrayOffset, holeCount);
}
public static JSArrayObject create(JSContext context, JSRealm realm, JSDynamicObject proto, ScriptArray arrayType, Object array, long length) {
return create(context, realm, proto, arrayType, array, length, 0);
}
public static JSArrayObject create(JSContext context, JSRealm realm, JSDynamicObject proto, ScriptArray arrayType, Object array, long length, int usedLength) {
return create(context, realm, proto, arrayType, array, length, usedLength, 0, 0);
}
public static JSArrayObject create(JSContext context, JSRealm realm, JSDynamicObject proto, ScriptArray arrayType, Object array, long length, int usedLength, int indexOffset, int arrayOffset) {
return create(context, realm, proto, arrayType, array, length, usedLength, indexOffset, arrayOffset, 0);
}
public static JSArrayObject create(JSContext context, JSRealm realm, JSDynamicObject proto, ScriptArray arrayType, Object array, long length, int usedLength, int indexOffset, int arrayOffset,
int holeCount) {
return createWithProto(context, realm, proto, arrayType, array, null, length, usedLength, indexOffset, arrayOffset, holeCount);
}
@InliningCutoff
public static JSArrayObject createDefaultProto(JSContext context, JSRealm realm,
ScriptArray arrayType, Object array, ArrayAllocationSite site, long length, int usedLength, int indexOffset, int arrayOffset, int holeCount) {
JSObjectFactory factory = context.getArrayFactory();
return createImpl(factory, realm, INSTANCE.getIntrinsicDefaultProto(realm), arrayType, array, site, length, usedLength, indexOffset, arrayOffset, holeCount);
}
@InliningCutoff
public static JSArrayObject createWithProto(JSContext context, JSRealm realm, JSDynamicObject prototype,
ScriptArray arrayType, Object array, ArrayAllocationSite site, long length, int usedLength, int indexOffset, int arrayOffset, int holeCount) {
JSObjectFactory factory = context.getArrayFactory();
return createImpl(factory, realm, prototype, arrayType, array, site, length, usedLength, indexOffset, arrayOffset, holeCount);
}
private static JSArrayObject createImpl(JSObjectFactory factory, JSRealm realm, JSDynamicObject prototype,
ScriptArray arrayType, Object array, ArrayAllocationSite site, long length, int usedLength, int indexOffset, int arrayOffset, int holeCount) {
assert JSRuntime.isRepresentableAsUnsignedInt(length);
var shape = factory.getShape(realm, prototype);
var newObj = factory.initProto(new JSArrayObject(shape, prototype, arrayType, array, site, length, usedLength, indexOffset, arrayOffset, holeCount), realm, prototype);
return factory.trackAllocation(newObj);
}
public static boolean isJSArray(Object obj) {
return obj instanceof JSArrayObject;
}
public static boolean isJSFastArray(Object obj) {
return isJSArray(obj) && isJSFastArray((JSArrayObject) obj);
}
public static boolean isJSFastArray(JSDynamicObject obj) {
return isInstance(obj, INSTANCE);
}
@Override
public TruffleString getClassName() {
return CLASS_NAME;
}
@Override
public JSDynamicObject createPrototype(JSRealm realm, JSFunctionObject ctor) {
JSContext ctx = realm.getContext();
Shape protoShape = JSShape.createPrototypeShape(ctx, INSTANCE, realm.getObjectPrototype());
JSObject arrayPrototype = JSArrayObject.createEmpty(protoShape, realm.getObjectPrototype(), ConstantEmptyPrototypeArray.createConstantEmptyPrototypeArray());
JSObjectUtil.setOrVerifyPrototype(ctx, arrayPrototype, realm.getObjectPrototype());
// Mark as an Array prototype
JSDynamicObject.setObjectFlags(arrayPrototype, JSDynamicObject.getObjectFlags(arrayPrototype) | JSShape.ARRAY_PROTOTYPE_FLAG);
assert isArrayPrototype(arrayPrototype);
JSObjectUtil.putConstructorProperty(arrayPrototype, ctor);
JSObjectUtil.putFunctionsFromContainer(realm, arrayPrototype, ArrayPrototypeBuiltins.BUILTINS);
// sets the length just for the prototype
// putProxyProperty(arrayPrototype, ARRAY_LENGTH_PROXY_PROPERTY);
JSObjectUtil.putProxyProperty(arrayPrototype, LENGTH, ARRAY_LENGTH_PROPERTY_PROXY, JSAttributes.notConfigurableNotEnumerableWritable());
if (ctx.getEcmaScriptVersion() >= 6) {
// The initial value of the @@iterator property is the same function object as the
// initial value of the Array.prototype.values property.
JSObjectUtil.putDataProperty(arrayPrototype, Symbol.SYMBOL_ITERATOR, JSDynamicObject.getOrNull(arrayPrototype, Strings.VALUES), JSAttributes.getDefaultNotEnumerable());
JSObjectUtil.putDataProperty(arrayPrototype, Symbol.SYMBOL_UNSCOPABLES, createUnscopables(ctx, unscopableNameList(ctx)), JSAttributes.configurableNotEnumerableNotWritable());
}
return arrayPrototype;
}
private static List unscopableNameList(JSContext context) {
List names = new ArrayList<>();
if (context.getEcmaScriptVersion() >= JSConfig.ECMAScript2022) {
names.add(Strings.AT);
}
names.add(Strings.COPY_WITHIN);
names.add(Strings.ENTRIES);
names.add(Strings.FILL);
names.add(Strings.FIND);
names.add(Strings.FIND_INDEX);
if (context.getEcmaScriptVersion() >= JSConfig.ECMAScript2023) {
names.add(Strings.FIND_LAST);
names.add(Strings.FIND_LAST_INDEX);
}
if (context.getEcmaScriptVersion() >= JSConfig.ECMAScript2019) {
names.add(Strings.FLAT);
names.add(Strings.FLAT_MAP);
}
if (context.getEcmaScriptVersion() >= JSConfig.ECMAScript2016) {
names.add(Strings.INCLUDES);
}
names.add(Strings.KEYS);
if (context.getEcmaScriptVersion() >= JSConfig.ECMAScript2023) {
names.add(Strings.TO_REVERSED);
names.add(Strings.TO_SORTED);
names.add(Strings.TO_SPLICED);
}
names.add(Strings.VALUES);
assert isSorted(names);
return names;
}
private static boolean isSorted(List list) {
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i).compareCharsUTF16Uncached(list.get(i + 1)) > 0) {
return false;
}
}
return true;
}
private static JSObject createUnscopables(JSContext context, List unscopableNames) {
JSObject unscopables = JSOrdinary.createWithNullPrototypeInit(context);
for (Object name : unscopableNames) {
JSObjectUtil.putDataProperty(unscopables, name, true, JSAttributes.getDefault());
}
return unscopables;
}
@Override
public Shape makeInitialShape(JSContext context, JSDynamicObject prototype) {
Shape initialShape = JSObjectUtil.getProtoChildShape(prototype, INSTANCE, context);
initialShape = Shape.newBuilder(initialShape).addConstantProperty(LENGTH, ARRAY_LENGTH_PROPERTY_PROXY, JSAttributes.notConfigurableNotEnumerableWritable() | JSProperty.PROXY).build();
return initialShape;
}
@Override
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy