All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.js.builtins.testing.TestV8Builtins 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.builtins.testing;

import java.util.ArrayList;
import java.util.List;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.js.builtins.AtomicsBuiltins;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNameNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugContinueInInterpreterNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugStringCompareNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugTypedArrayDetachBufferNodeGen;
import com.oracle.truffle.js.builtins.JSBuiltinsContainer;
import com.oracle.truffle.js.builtins.helper.GCNodeGen;
import com.oracle.truffle.js.builtins.helper.SharedMemorySync;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8AtomicsNumNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ConstructDoubleNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8CreateAsyncFromSyncIteratorNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8CreatePrivateSymbolNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8DoublePartNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8EnqueueJobNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ReferenceEqualNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8RunMicrotasksNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8SetAllowAtomicsWaitNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8SetTimeoutNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8SymbolIsPrivateNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ToLengthNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ToNameNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ToNumberNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ToPrimitiveNodeGen;
import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ToStringNodeGen;
import com.oracle.truffle.js.nodes.access.PropertyGetNode;
import com.oracle.truffle.js.nodes.cast.JSToBooleanNode;
import com.oracle.truffle.js.nodes.cast.JSToIndexNode;
import com.oracle.truffle.js.nodes.cast.JSToLengthNode;
import com.oracle.truffle.js.nodes.cast.JSToNumberNode;
import com.oracle.truffle.js.nodes.cast.JSToPrimitiveNode;
import com.oracle.truffle.js.nodes.cast.JSToStringNode;
import com.oracle.truffle.js.nodes.function.JSBuiltin;
import com.oracle.truffle.js.nodes.function.JSBuiltinNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSAgent;
import com.oracle.truffle.js.runtime.JSAgentWaiterList.JSAgentWaiterListEntry;
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.JobCallback;
import com.oracle.truffle.js.runtime.Strings;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.builtins.BuiltinEnum;
import com.oracle.truffle.js.runtime.builtins.JSArrayBufferView;
import com.oracle.truffle.js.runtime.builtins.JSAsyncFromSyncIteratorObject;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSFunctionObject;
import com.oracle.truffle.js.runtime.builtins.JSSharedArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSTestV8;
import com.oracle.truffle.js.runtime.builtins.JSTypedArrayObject;
import com.oracle.truffle.js.runtime.objects.IteratorRecord;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.Undefined;

/**
 * Contains builtins to support special behavior used by TestV8.
 */
public final class TestV8Builtins extends JSBuiltinsContainer.SwitchEnum {

    public static final JSBuiltinsContainer BUILTINS = new TestV8Builtins();

    protected TestV8Builtins() {
        super(JSTestV8.CLASS_NAME, TestV8.class);
    }

    public enum TestV8 implements BuiltinEnum {
        class_(1),
        className(1),
        createAsyncFromSyncIterator(1),
        runMicrotasks(0),
        enqueueJob(1),
        setTimeout(1),
        stringCompare(2),
        typedArrayDetachBuffer(1),

        constructDouble(2),
        doubleHi(1),
        doubleLo(1),
        deoptimize(0),
        gc(0),
        referenceEqual(2),
        toLength(1),
        toStringConv(1),
        toName(1),
        toNumber(1),
        toPrimitive(1),
        toPrimitiveString(1),
        toPrimitiveNumber(1),

        atomicsNumWaitersForTesting(2),
        atomicsNumUnresolvedAsyncPromisesForTesting(2),
        setAllowAtomicsWait(1),

        createPrivateSymbol(1),
        symbolIsPrivate(1);

        private final int length;

        TestV8(int length) {
            this.length = length;
        }

        @Override
        public int getLength() {
            return length;
        }
    }

    @Override
    protected Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget, TestV8 builtinEnum) {
        switch (builtinEnum) {
            case class_:
                return DebugClassNodeGen.create(context, builtin, true, args().fixedArgs(1).createArgumentNodes(context));
            case className:
                return DebugClassNameNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case createAsyncFromSyncIterator:
                return TestV8CreateAsyncFromSyncIteratorNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case runMicrotasks:
                return TestV8RunMicrotasksNodeGen.create(context, builtin, args().createArgumentNodes(context));
            case enqueueJob:
                return TestV8EnqueueJobNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case setTimeout:
                return TestV8SetTimeoutNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case stringCompare:
                return DebugStringCompareNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
            case typedArrayDetachBuffer:
                return DebugTypedArrayDetachBufferNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));

            case constructDouble:
                return TestV8ConstructDoubleNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
            case doubleHi:
                return TestV8DoublePartNodeGen.create(context, builtin, true, args().fixedArgs(1).createArgumentNodes(context));
            case doubleLo:
                return TestV8DoublePartNodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context));
            case deoptimize:
                return DebugContinueInInterpreterNodeGen.create(context, builtin, true, args().createArgumentNodes(context));
            case gc:
                return GCNodeGen.create(context, builtin, args().createArgumentNodes(context));
            case referenceEqual:
                return TestV8ReferenceEqualNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
            case toStringConv:
                return TestV8ToStringNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case toName:
                return TestV8ToNameNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case toPrimitive:
                return TestV8ToPrimitiveNodeGen.create(context, builtin, JSToPrimitiveNode.Hint.Default, args().fixedArgs(1).createArgumentNodes(context));
            case toPrimitiveString:
                return TestV8ToPrimitiveNodeGen.create(context, builtin, JSToPrimitiveNode.Hint.String, args().fixedArgs(1).createArgumentNodes(context));
            case toPrimitiveNumber:
                return TestV8ToPrimitiveNodeGen.create(context, builtin, JSToPrimitiveNode.Hint.Number, args().fixedArgs(1).createArgumentNodes(context));
            case toNumber:
                return TestV8ToNumberNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case toLength:
                return TestV8ToLengthNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case atomicsNumWaitersForTesting:
            case atomicsNumUnresolvedAsyncPromisesForTesting:
                return TestV8AtomicsNumNodeGen.create(context, builtin, builtinEnum, args().fixedArgs(2).createArgumentNodes(context));
            case setAllowAtomicsWait:
                return TestV8SetAllowAtomicsWaitNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case createPrivateSymbol:
                return TestV8CreatePrivateSymbolNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
            case symbolIsPrivate:
                return TestV8SymbolIsPrivateNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
        }
        return null;
    }

    /**
     * Constructs a double from two 32bit ints. Used by V8ConstructDouble (v8mockup.js).
     */
    public abstract static class TestV8ConstructDoubleNode extends JSBuiltinNode {

        public TestV8ConstructDoubleNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @TruffleBoundary
        @Specialization
        protected double constructDouble(Object hiObj, Object loObj) {
            long hi = JSRuntime.toUInt32(hiObj);
            long lo = JSRuntime.toUInt32(loObj);
            return Double.longBitsToDouble((hi << 32) | lo);
        }
    }

    /**
     * Gets the upper (hi) or lower (lo) 32 bits of a double. Used by V8DoubleHi, V8DoubleLo
     * (v8mockup.js).
     */
    public abstract static class TestV8DoublePartNode extends JSBuiltinNode {
        private final boolean upper;

        public TestV8DoublePartNode(JSContext context, JSBuiltin builtin, boolean upper) {
            super(context, builtin);
            this.upper = upper;
        }

        @Specialization
        protected int doublePart(Object value) {
            long bits = Double.doubleToRawLongBits((double) value);
            return upper ? (int) (bits >>> 32L) : (int) (bits & 0xFFFF_FFFFL);
        }
    }

    /**
     * Calls [[ToString]], used by v8mockup.js.
     */
    public abstract static class TestV8ToStringNode extends JSBuiltinNode {
        @Child private JSToStringNode toStringNode;

        public TestV8ToStringNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toStringNode = JSToStringNode.create();
        }

        @Specialization
        protected TruffleString toStringConv(Object obj) {
            return toStringNode.executeString(obj);
        }
    }

    /**
     * Calls [[ToNumber]], used by v8mockup.js.
     */
    public abstract static class TestV8ToNumberNode extends JSBuiltinNode {
        @Child private JSToNumberNode toNumberNode;

        public TestV8ToNumberNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toNumberNode = JSToNumberNode.create();
        }

        @Specialization
        protected Number toNumberOp(Object obj) {
            return toNumberNode.executeNumber(obj);
        }
    }

    /**
     * Calls [[ToPrimitive]], used by v8mockup.js .
     */
    public abstract static class TestV8ToPrimitiveNode extends JSBuiltinNode {
        @Child private JSToPrimitiveNode toPrimitiveNode;

        public TestV8ToPrimitiveNode(JSContext context, JSBuiltin builtin, JSToPrimitiveNode.Hint hint) {
            super(context, builtin);
            toPrimitiveNode = JSToPrimitiveNode.create(hint);
        }

        @Specialization
        protected Object toPrimitive(Object obj) {
            return toPrimitiveNode.execute(obj);
        }
    }

    /**
     * Calls [[ToName]], used by v8mockup.js.
     */
    public abstract static class TestV8ToNameNode extends JSBuiltinNode {
        @Child private JSToStringNode toStringNode;

        public TestV8ToNameNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toStringNode = JSToStringNode.create();
        }

        @Specialization
        protected Object toName(Object obj) {
            if (obj instanceof Symbol) {
                return obj;
            } else {
                return toStringNode.executeString(obj);
            }
        }
    }

    /**
     * Executes all pending jobs, used by v8mockup.js.
     */
    public abstract static class TestV8RunMicrotasksNode extends JSBuiltinNode {

        public TestV8RunMicrotasksNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        protected Object runMicrotasks() {
            getContext().processAllPendingPromiseJobs(getRealm());
            return Undefined.instance;
        }
    }

    public abstract static class TestV8EnqueueJobNode extends JSBuiltinNode {

        public TestV8EnqueueJobNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        protected Object enqueueJob(Object function) {
            if (JSFunction.isJSFunction(function)) {
                getContext().enqueuePromiseJob(getRealm(), (JSFunctionObject) function);
            }
            return 0;
        }
    }

    /**
     * Calls CreateAsyncFromSyncIterator, used by v8mockup.js.
     */
    public abstract static class TestV8CreateAsyncFromSyncIterator extends JSBuiltinNode {
        @Child private PropertyGetNode getNextMethodNode;

        public TestV8CreateAsyncFromSyncIterator(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            this.getNextMethodNode = PropertyGetNode.create(Strings.NEXT, context);
        }

        @Specialization
        protected Object createAsyncFromSyncIterator(JSObject syncIterator) {
            Object nextMethod = getNextMethodNode.getValue(syncIterator);
            IteratorRecord syncIteratorRecord = IteratorRecord.create(syncIterator, nextMethod, false);
            return JSAsyncFromSyncIteratorObject.create(getContext(), getRealm(), syncIteratorRecord);
        }

        @Specialization(guards = "!isJSObject(syncIterator)")
        protected Object notObject(Object syncIterator) {
            throw Errors.createTypeErrorNotAnObject(syncIterator, this);
        }
    }

    /**
     * Calls [[ToLength]].
     */
    public abstract static class TestV8ToLengthNode extends JSBuiltinNode {
        @Child private JSToLengthNode toLengthNode;

        public TestV8ToLengthNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            toLengthNode = JSToLengthNode.create();
        }

        @Specialization
        protected Object toLengthOp(Object obj) {
            long value = toLengthNode.executeLong(obj);
            double d = value;
            if (JSRuntime.doubleIsRepresentableAsInt(d)) {
                return (int) d;
            } else {
                return d;
            }
        }
    }

    public abstract static class TestV8ReferenceEqualNode extends JSBuiltinNode {

        public TestV8ReferenceEqualNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        protected boolean referenceEqual(Object arg1, Object arg2) {
            return arg1 == arg2;
        }
    }

    public abstract static class TestV8SetTimeoutNode extends JSBuiltinNode {

        public TestV8SetTimeoutNode(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        @TruffleBoundary
        @SuppressWarnings("unchecked")
        protected Object setTimeout(Object callback) {
            assert JSRuntime.isCallable(callback);
            JSRealm realm = getRealm();
            List embedderData = (List) realm.getEmbedderData();
            if (embedderData == null) {
                embedderData = new ArrayList<>();
                realm.setEmbedderData(embedderData);
            }
            embedderData.add(realm.getAgent().hostMakeJobCallback(callback));
            return Undefined.instance;
        }
    }

    public abstract static class TestV8AtomicsNumNode extends AtomicsBuiltins.AtomicsOperationNode {

        private final TestV8 getter;

        public TestV8AtomicsNumNode(JSContext context, JSBuiltin builtin, TestV8 getter) {
            super(context, builtin);
            this.getter = getter;
        }

        private JSTypedArrayObject ensureSharedArray(Object maybeTarget) {
            if (maybeTarget instanceof JSTypedArrayObject typedArrayObj) {
                JSDynamicObject buffer = JSArrayBufferView.getArrayBuffer(typedArrayObj);
                if (JSSharedArrayBuffer.isJSSharedArrayBuffer(buffer)) {
                    return typedArrayObj;
                }
            }
            throw createTypeErrorNotSharedArray();
        }

        @Specialization
        protected int num(Object maybeTarget, Object index,
                        @Cached JSToIndexNode toIndexNode) {
            JSTypedArrayObject target = ensureSharedArray(maybeTarget);
            int i = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index));
            return switch (getter) {
                case atomicsNumWaitersForTesting -> numWaiters(target, i);
                case atomicsNumUnresolvedAsyncPromisesForTesting -> numUnresolvedAsyncPromises(target, i);
                default -> throw Errors.shouldNotReachHereUnexpectedValue(getter);
            };
        }

        @TruffleBoundary
        private int numWaiters(JSTypedArrayObject target, int i) {
            JSAgentWaiterListEntry wl = SharedMemorySync.getWaiterList(getContext(), target, i);
            return wl.size();
        }

        @TruffleBoundary
        private int numUnresolvedAsyncPromises(JSTypedArrayObject target, int i) {
            JSAgent agent = getRealm().getAgent();
            JSAgentWaiterListEntry wl = SharedMemorySync.getWaiterList(getContext(), target, i);
            return agent.getAsyncWaitersToBeResolved(wl);
        }
    }

    public abstract static class TestV8SetAllowAtomicsWait extends JSBuiltinNode {
        @Child JSToBooleanNode toBooleanNode;

        public TestV8SetAllowAtomicsWait(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
            this.toBooleanNode = JSToBooleanNode.create();
        }

        @Specialization
        protected Object setAllowAtomicsWait(Object allow) {
            getRealm().getAgent().setCanBlock(toBooleanNode.executeBoolean(allow));
            return Undefined.instance;
        }

    }

    public abstract static class TestV8CreatePrivateSymbol extends JSBuiltinNode {

        public TestV8CreatePrivateSymbol(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        protected Object doCreate(Object description,
                        @Cached JSToStringNode toStringNode) {
            return Symbol.createPrivate(toStringNode.executeString(description));
        }

    }

    public abstract static class TestV8SymbolIsPrivate extends JSBuiltinNode {

        public TestV8SymbolIsPrivate(JSContext context, JSBuiltin builtin) {
            super(context, builtin);
        }

        @Specialization
        protected boolean isPrivate(Object symbol) {
            return JSRuntime.isPrivateSymbol(symbol);
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy