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

com.oracle.truffle.api.staticobject.FieldBasedShapeGenerator Maven / Gradle / Ivy

Go to download

Truffle is a multi-language framework for executing dynamic languages that achieves high performance when combined with Graal.

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2021, 2021, 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.api.staticobject;

import com.oracle.truffle.api.impl.asm.ClassVisitor;
import com.oracle.truffle.api.impl.asm.ClassWriter;
import com.oracle.truffle.api.impl.asm.MethodVisitor;
import com.oracle.truffle.api.impl.asm.Type;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;

import static com.oracle.truffle.api.impl.asm.Opcodes.ACC_FINAL;
import static com.oracle.truffle.api.impl.asm.Opcodes.ACC_PUBLIC;
import static com.oracle.truffle.api.impl.asm.Opcodes.ACC_SUPER;
import static com.oracle.truffle.api.impl.asm.Opcodes.ACC_SYNTHETIC;
import static com.oracle.truffle.api.impl.asm.Opcodes.ALOAD;
import static com.oracle.truffle.api.impl.asm.Opcodes.ARETURN;
import static com.oracle.truffle.api.impl.asm.Opcodes.DUP;
import static com.oracle.truffle.api.impl.asm.Opcodes.ILOAD;
import static com.oracle.truffle.api.impl.asm.Opcodes.INVOKESPECIAL;
import static com.oracle.truffle.api.impl.asm.Opcodes.NEW;
import static com.oracle.truffle.api.impl.asm.Opcodes.RETURN;
import static com.oracle.truffle.api.impl.asm.Opcodes.V1_8;

final class FieldBasedShapeGenerator extends ShapeGenerator {
    private final GeneratorClassLoaders gcls;
    private final Class storageSuperClass;
    private final Class storageFactoryInterface;

    private FieldBasedShapeGenerator(GeneratorClassLoaders gcls, Class storageSuperClass, Class storageFactoryInterface) {
        this.gcls = gcls;
        this.storageSuperClass = storageSuperClass;
        this.storageFactoryInterface = storageFactoryInterface;
    }

    @SuppressWarnings("unchecked")
    static  FieldBasedShapeGenerator getShapeGenerator(GeneratorClassLoaders gcls, Class storageSuperClass, Class storageFactoryInterface) {
        return new FieldBasedShapeGenerator<>(gcls, storageSuperClass, storageFactoryInterface);
    }

    @Override
    StaticShape generateShape(StaticShape parentShape, Map staticProperties, boolean safetyChecks, String storageClassName) {
        Class generatedStorageClass = generateStorage(gcls, storageSuperClass, staticProperties, storageClassName);
        Class generatedFactoryClass = generateFactory(gcls, generatedStorageClass, storageFactoryInterface);
        for (Entry entry : staticProperties.entrySet()) {
            // We need to resolve field types so that loads are stamped with the proper type
            int offset = getObjectFieldOffset(generatedStorageClass, entry.getKey());
            entry.getValue().initOffset(offset);
        }
        return FieldBasedStaticShape.create(generatedStorageClass, generatedFactoryClass, safetyChecks);
    }

    @SuppressWarnings("deprecation"/* JDK-8277863 */)
    private static int getObjectFieldOffset(Class c, String fieldName) {
        try {
            return Math.toIntExact(UNSAFE.objectFieldOffset(c.getField(fieldName)));
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    private static String getStorageConstructorDescriptor(Constructor superConstructor) {
        return Type.getConstructorDescriptor(superConstructor);
    }

    private static void addStorageConstructors(ClassVisitor cv, Class storageSuperClass, String storageSuperName) {
        for (Constructor superConstructor : storageSuperClass.getDeclaredConstructors()) {
            String storageConstructorDescriptor = getStorageConstructorDescriptor(superConstructor);
            String superConstructorDescriptor = storageConstructorDescriptor;
            MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", storageConstructorDescriptor, null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            int var = 1;
            for (Class constructorParameter : superConstructor.getParameterTypes()) {
                Type parameterType = Type.getType(constructorParameter);
                int loadOpcode = parameterType.getOpcode(ILOAD);
                mv.visitVarInsn(loadOpcode, var);
                var += parameterType.getSize();
            }
            mv.visitMethodInsn(INVOKESPECIAL, storageSuperName, "", superConstructorDescriptor, false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(var + 1, var);
            mv.visitEnd();
        }
    }

    private static void addFactoryConstructor(ClassVisitor cv) {
        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }

    private static void addFactoryMethods(ClassVisitor cv, Class storageClass, Class storageFactoryInterface) {
        for (Method m : storageFactoryInterface.getMethods()) {
            MethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_FINAL, m.getName(), Type.getMethodDescriptor(m), null, null);
            mv.visitCode();
            mv.visitTypeInsn(NEW, Type.getInternalName(storageClass));
            mv.visitInsn(DUP);
            int maxStack = 2;  // DUP
            int maxLocals = 1; // this
            StringBuilder constructorDescriptor = new StringBuilder();
            constructorDescriptor.append('(');
            Class[] params = m.getParameterTypes();
            for (Class param : params) {
                Type paramType = Type.getType(param);
                int loadOpcode = paramType.getOpcode(ILOAD);
                mv.visitVarInsn(loadOpcode, maxLocals);
                constructorDescriptor.append(Type.getDescriptor(param));
                maxStack += paramType.getSize();
                maxLocals += paramType.getSize();
            }
            constructorDescriptor.append(")V");
            String storageName = Type.getInternalName(storageClass);
            mv.visitMethodInsn(INVOKESPECIAL, storageName, "", constructorDescriptor.toString(), false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(maxStack, maxLocals);
            mv.visitEnd();
        }
    }

    private static Class generateStorage(GeneratorClassLoaders gcls, Class storageSuperClass, Map staticProperties, String storageClassName) {
        String storageSuperName = Type.getInternalName(storageSuperClass);
        ClassWriter storageWriter = new ClassWriter(0);
        int storageAccess = ACC_PUBLIC | ACC_SUPER | ACC_SYNTHETIC;
        storageWriter.visit(V1_8, storageAccess, storageClassName, null, storageSuperName, null);
        addStorageConstructors(storageWriter, storageSuperClass, storageSuperName);
        addStorageFields(storageWriter, staticProperties);
        storageWriter.visitEnd();
        return load(gcls, storageClassName, storageWriter.toByteArray(), true);
    }

    @SuppressWarnings("unchecked")
    private static  Class generateFactory(GeneratorClassLoaders gcls, Class storageClass, Class storageFactoryInterface) {
        ClassWriter factoryWriter = new ClassWriter(0);
        int factoryAccess = ACC_PUBLIC | ACC_SUPER | ACC_SYNTHETIC | ACC_FINAL;
        String factoryName = generateFactoryName(storageClass);
        factoryWriter.visit(V1_8, factoryAccess, factoryName, null, Type.getInternalName(Object.class), new String[]{Type.getInternalName(storageFactoryInterface)});
        addFactoryConstructor(factoryWriter);
        addFactoryMethods(factoryWriter, storageClass, storageFactoryInterface);
        factoryWriter.visitEnd();
        return (Class) load(gcls, factoryName, factoryWriter.toByteArray(), false);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy