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

io.apigee.trireme.node12.modules.Smalloc Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2015 Apigee Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall 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 io.apigee.trireme.node12.modules;

import io.apigee.trireme.core.InternalNodeModule;
import io.apigee.trireme.core.NodeRuntime;
import io.apigee.trireme.core.Utils;
import io.apigee.trireme.core.internal.AbstractIdObject;
import io.apigee.trireme.core.internal.IdPropertyMap;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ExternalArrayData;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.typedarrays.NativeArrayBufferView;
import org.mozilla.javascript.typedarrays.NativeFloat32Array;
import org.mozilla.javascript.typedarrays.NativeFloat64Array;
import org.mozilla.javascript.typedarrays.NativeInt16Array;
import org.mozilla.javascript.typedarrays.NativeInt32Array;
import org.mozilla.javascript.typedarrays.NativeInt8Array;
import org.mozilla.javascript.typedarrays.NativeTypedArrayView;
import org.mozilla.javascript.typedarrays.NativeUint16Array;
import org.mozilla.javascript.typedarrays.NativeUint32Array;
import org.mozilla.javascript.typedarrays.NativeUint8Array;
import org.mozilla.javascript.typedarrays.NativeUint8ClampedArray;

import static io.apigee.trireme.core.ArgUtils.*;

import java.lang.reflect.InvocationTargetException;

public class Smalloc
    implements InternalNodeModule
{
    public static final int MAX_ARRAY_LEN = 1 << 30;

    @Override
    public String getModuleName() {
        return "smalloc";
    }

    @Override
    public Scriptable registerExports(Context cx, Scriptable global, NodeRuntime runtime)
        throws InvocationTargetException, IllegalAccessException, InstantiationException
    {
        new SmallocImpl().exportAsClass(global);
        SmallocImpl exports = (SmallocImpl)cx.newObject(global, SmallocImpl.CLASS_NAME);
        ScriptableObject.defineProperty(exports, "kMaxLength", MAX_ARRAY_LEN,
                                        ScriptableObject.CONST);
        return exports;
    }

    public static class SmallocImpl
        extends AbstractIdObject
    {
        public static final String CLASS_NAME = "_triremeSmallocBinding";

        private static final IdPropertyMap props = new IdPropertyMap(CLASS_NAME);

        private static final int
            Id_alloc = 2,
            Id_dispose = 3,
            Id_hasExternalArray = 4,
            Id_isTypedArray = 5,
            Id_copyOnto = 6,
            Id_sliceOnto = 7;

        static {
            props.addMethod("alloc", Id_alloc, 3);
            props.addMethod("dispose", Id_dispose, 1);
            props.addMethod("hasExternalData", Id_hasExternalArray, 1);
            props.addMethod("isTypedArray", Id_isTypedArray, 1);
            props.addMethod("copyOnto", Id_copyOnto, 5);
            props.addMethod("sliceOnto", Id_sliceOnto, 4);
        }

        public SmallocImpl()
        {
            super(props);
        }

        @Override
        protected SmallocImpl defaultConstructor()
        {
            return new SmallocImpl();
        }

        @Override
        protected Object anonymousCall(int id, Context cx, Scriptable scope,
                                       Object thisObj, Object[] args)
        {
            switch (id) {
            case Id_alloc:
                return alloc(cx, args);
            case Id_dispose:
                dispose(args);
                break;
            case Id_hasExternalArray:
                return hasExternalData(args);
            case Id_isTypedArray:
                return isTypedArray(args);
            case Id_copyOnto:
                copyOnto(cx, args);
                break;
            case Id_sliceOnto:
                return sliceOnto(cx, args);
            default:
                return super.anonymousCall(id, cx, scope, thisObj, args);
            }
            return Undefined.instance;
        }

        private Scriptable alloc(Context cx, Object[] args)
        {
            ScriptableObject obj = objArg(args, 0, ScriptableObject.class, true);
            int size = intArg(args, 1);
            Object typeObj = objArg(args, 2, Object.class, false);
            int type;

            if ((typeObj == null) || Undefined.instance.equals(typeObj)) {
                type = 2;
            } else {
                type = ScriptRuntime.toInt32(typeObj);
            }

            if (obj.getExternalArrayData() != null) {
                throw Utils.makeTypeError(cx, this, "object already has external array data");
            }

            ExternalArrayData array;
            // Switch needs to match constants in smalloc.js
            switch (type) {
            case 1:
                array = new NativeInt8Array(size);
                break;
            case 2:
                array = new NativeUint8Array(size);
                break;
            case 3:
                array = new NativeInt16Array(size);
                break;
            case 4:
                array = new NativeUint16Array(size);
                break;
            case 5:
                array = new NativeInt32Array(size);
                break;
            case 6:
                array = new NativeUint32Array(size);
                break;
            case 7:
                array = new NativeFloat32Array(size);
                break;
            case 8:
                array = new NativeFloat64Array(size);
                break;
            case 9:
                array = new NativeUint8ClampedArray(size);
                break;
            default:
                throw Utils.makeError(cx, this, "Invalid array type");
            }

            obj.setExternalArrayData(array);
            return obj;
        }

        /**
         * As implemented in Node, "copyOnto" works with arrays of different types, and copies at the byte
         * level from one to another. So here we do a lot of work to calculate and test various offsets.
         */
        private void copyOnto(Context cx, Object[] args)
        {
            ScriptableObject src = objArg(args, 0, ScriptableObject.class, true);
            int srcStart = intArg(args, 1);
            ScriptableObject dest = objArg(args, 2, ScriptableObject.class, true);
            int destStart = intArg(args, 3);
            int copyLength = intArg(args, 4);

            NativeTypedArrayView srcView;
            try {
                srcView = (NativeTypedArrayView)src.getExternalArrayData();
            } catch (ClassCastException cce) {
                throw Utils.makeTypeError(cx, this, "unknown source external array type");
            }
            if (srcView == null) {
                throw Utils.makeTypeError(cx, this, "source has no external array data");
            }

            NativeTypedArrayView destView;
            try {
                destView = (NativeTypedArrayView)dest.getExternalArrayData();
            } catch (ClassCastException cce) {
                throw Utils.makeTypeError(cx, this, "unknown dest external array type");
            }
            if (destView == null) {
                throw Utils.makeTypeError(cx, this, "dest has no external array data");
            }

            int copyByteLen = copyLength * srcView.getBytesPerElement();

            if (copyByteLen > srcView.getByteLength()) {
                throw Utils.makeRangeError(cx, this, "copy_length > source_length");
            }
            if (copyByteLen > destView.getByteLength()) {
                throw Utils.makeRangeError(cx, this, "copy_length > dest_length");
            }
            if (srcStart > srcView.getByteLength()) {
                throw Utils.makeRangeError(cx, this, "source_start > source_length");
            }
            if (destStart > destView.getByteLength()) {
                throw Utils.makeRangeError(cx, this, "dest_start > dest_length");
            }

            if ((srcStart + copyByteLen) > srcView.getByteLength()) {
                throw Utils.makeRangeError(cx, this, "source_start + copy_length > source_length");
            }
            if ((destStart + copyByteLen) > destView.getByteLength()) {
                throw Utils.makeRangeError(cx, this, "dest_start + copy_length > dest_length");
            }

            System.arraycopy(srcView.getBuffer().getBuffer(), srcStart,
                             destView.getBuffer().getBuffer(), destStart,
                             copyByteLen);
        }

        private Scriptable sliceOnto(Context cx, Object[] args)
        {
            ScriptableObject src = objArg(args, 0, ScriptableObject.class, true);
            ScriptableObject dest = objArg(args, 1, ScriptableObject.class, true);
            int start = intArg(args, 2);
            int end = intArg(args, 3);

            ExternalArrayData srcArray = src.getExternalArrayData();
            if (srcArray == null) {
                throw Utils.makeError(cx, this, "source has no external array data");
            }
            if (dest.getExternalArrayData() != null) {
                throw Utils.makeError(cx, this, "dest already has external array data");
            }

            NativeArrayBufferView srcView;
            try {
                srcView = (NativeArrayBufferView)srcArray;
            } catch (ClassCastException cce) {
                throw Utils.makeError(cx, this, "source does not have the right kind of external data");
            }

            ExternalArrayData destData;
            if (srcArray instanceof NativeInt8Array) {
                destData = new NativeInt8Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeUint8Array) {
                destData = new NativeUint8Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeUint8ClampedArray) {
                destData = new NativeUint8ClampedArray(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeInt16Array) {
                destData = new NativeInt16Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeUint16Array) {
               destData = new NativeUint16Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeInt32Array) {
                destData = new NativeInt32Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeUint32Array) {
                destData = new NativeUint32Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeFloat32Array) {
                destData = new NativeFloat32Array(srcView.getBuffer(), start, end - start);
            } else if (srcArray instanceof NativeFloat64Array) {
                destData = new NativeFloat64Array(srcView.getBuffer(), start, end - start);
            } else {
                throw Utils.makeError(cx, this, "source array does not have a compatible type");
            }

            dest.setExternalArrayData(destData);

            return src;
        }

        private void dispose(Object[] args)
        {
            ScriptableObject obj = objArg(args, 0, ScriptableObject.class, true);
            obj.setExternalArrayData(null);
        }

        private boolean hasExternalData(Object[] args)
        {
            if (args.length == 0) {
                return false;
            }
            if (args[0] instanceof ScriptableObject) {
                ScriptableObject obj = objArg(args, 0, ScriptableObject.class, true);
                return (obj.getExternalArrayData() != null);
            }
            return false;
        }

        private boolean isTypedArray(Object[] args)
        {
            ensureArg(args, 0);
            return (args[0] instanceof NativeTypedArrayView);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy