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

com.oracle.truffle.api.object.dsl.Layout 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: 1.0.0-rc7
Show newest version
/*
 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.truffle.api.object.dsl;

import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
import com.oracle.truffle.api.object.HiddenKey;
import com.oracle.truffle.api.object.ObjectType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Annotate an interface with {@link Layout} to generate an implementation of the interface which
 * uses object-model properties. {@link Layout} allows you to use the object-model in a similar way
 * to writing a normal Java class for statically declared and implementation-specific fields. Most
 * methods generated from an {@link Layout}-annotated interface are suitable for use on the
 * fast-path.
 *
 * The name of the interface should end with 'Layout'.
 *
 * {@codesnippet rectlayout}
 *
 * The generated class is named with the name of the interface and then {@code -Impl}. A singleton
 * instance of the interface, {@code -Impl.INSTANCE} is available as a static field in the class.
 *
 * {@codesnippet rectlayoutimpl}
 *
 * 

Factory method

* * A factory method named {@code create-} and then the name of the layout creates instances of the * layout. It returns a {@link DynamicObject}, not an instance of the interface. * * {@codesnippet rectlayoutcreate} * *

Guards

* * Guards can tell you if an object is using layout. Guards are defined for {@link DynamicObject}, * the more general {@link Object} which first checks if the arguments is a {@link DynamicObject}, * and {@link ObjectType}, which you can get through the shape of a {@link DynamicObject}. To add a * guard, define the method in your interface. * * * {@codesnippet rectlayoutguards} * *

Properties

* * To add properties, define a getter and setter, and add a parameter to the factory method. * * {@codesnippet rectlayoutprops} * * If you don't define a setter, the property will be final. This may improve the performance of the * property. * *

Nullable Properties

* * By default, properties are non-nullable, which means that they always need an instance of an * object and they cannot be assigned the value {@code null}. This has performance benefits in the * implementation of the object-model. * * To make a property nullable so that you can assign {@code null} to it, annotate the constructor * parameter with {@link Nullable}. * * {@codesnippet nullable} * *

Volatile Properties

* * To define a property with volatile semantics, in the sense of the Java Language Specification * section 8.3.1.4, annotate the constructor parameter with {@link Volatile}. A property annotated * as volatile also allows you to define atomic operation methods in your layout interface for that * property. Methods available are {@code compareAndSet}, in the sense of * {@link AtomicReference#compareAndSet}, and {@code getAndSet}, in the sense of * {@link AtomicReference#getAndSet}. * * {@codesnippet volatile} * * Volatile properties generally have lower performance than the default non-volatile properties. * *

Semi-Final Properties

* * It is possible to define a 'back-door' and unsafe setter for otherwise-final properties by * appending {@code -Unsafe} to the setter name. * * {@codesnippet semifinal} * * Final and semi-final properties may be assumed by a dynamic compiler to not change for a given * instance of an object after it is constructed. Unsafe setters are therefore unsafe as a * modification to the property could be ignored by the dynamic compiler. You should only use unsafe * setters if you have reasoned that it is not possible for the dynamic compiler to compile a * reference to the object and the property before the unsafe setter is used. One use-case is * closing cycles in class graphs, such as the classic class-of-class-is-class problem, where you * normally want the class property to be final for performance but just as the graph is created * this one cycle needs to be closed. * * Errors due to the incorrect use of unsafe getters are likely to be non-deterministic and * difficult to isolate. Consider making properties temporarily non-final with a conventional getter * if stale value are experienced in dynamically compiled code. * *

Shape Properties

* * A shape property is a property that is shared between many objects and does not frequently * change. One intended use-case is a property to store the class of an object, which is likely * shared between many objects and likely does not change after the object is created. * * Shape properties should be cached against an object's shape as there is an extra level of * indirection used to look up their value for an object. They may save space as they are not stored * for all instances. * * It is important to note that changing a shape-property for an existing object is both not a * fast-path operation, and depending on the design of your interpreter is likely ot invalidate * caches. * * When shape properties are used there is an extra level of indirection, in that a * {@link DynamicObjectFactory} (referred to as the shape, because it is the shape that the factory * object contains that is used to look up shape properties) is created by the layout and then used * when creating new instances. As shape properties are set and changed, multiple factories will be * created and it is up to the user to store and supply these as needed. * * Consider the example of a Java-style object, with a class and a hash code. The class would be a * shape property, as many objects will share the same class, and the hash code will be a normal * property. * * Shape properties are created by parameters in the method that creates the shape. The factory * method then accepts an instance of a factory when creating the object, which is how the instance * knows the value of the class property to use. A getter for a shape property can be defined as * normal. * * {@codesnippet javaobject} * * When we load our Java interpreter we need to set the class property of the {@code Class} object * to be itself. This means in this one isolated, slow-path, case we need to change a shape property * for an object that is already allocated. Getters for shape properties can be defined for the * {@link DynamicObjectFactory}, and for the {@link ObjectType}. * * Setters for shape properties are more complex, and they are not intended to be used in the fast * path. Setters can be defined on a {@link DynamicObjectFactory}, in which case they return a new * factory, or on a {@link DynamicObject}, in which they they change the shape of the object. This * is a slow-path operation and is likely to invalidate caches in your interpreter. * * {@codesnippet shapesetters} * * Apply this to our example with Java classes: * * {@codesnippet closecycle} * *

Layout Inheritance

* * Inheritance of layout interfaces allows you to model classical class inheritance, such as in a * language like Java. Use normal interface inheritance to make one layout inherit from another. You * then need to add the parameters for super-layouts at the beginning of sub-layout constructor * methods. * * Inherited shape properties work in a similar way. * * {@codesnippet inheritanceinterfaces} * * {@codesnippet inheritanceuse} * *

Custom Object-Type Superclass

* * Generated layouts use custom {@link ObjectType} subclasses internally. The default base class * that is inherited from is simply {@link ObjectType}. You can change this with the * {@link #objectTypeSuperclass} property on the {@link Layout} annotation. * *

Implicit Casts

* * {@code IntToLong} and {@code IntToDouble} implicit cast flags can be set in the generated layout * by setting {@link #implicitCastIntToLong} or {@link #implicitCastIntToDouble}. This can only be * done in base layouts, not subclassed layouts. * *

Custom Identifiers

* * By default, internal {@link HiddenKey} identifiers with descriptive names will be created for * your properties automatically. You can also specify the identifiers to use by defining them as * public static final fields in the interface. * * {@codesnippet customid} * * @since 0.12 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface Layout { Class objectTypeSuperclass() default ObjectType.class; boolean implicitCastIntToLong() default false; boolean implicitCastIntToDouble() default false; } class Snippets { // BEGIN: rectlayout @Layout private interface RectLayout { } // END: rectlayout private static class RectLayoutImpl { public static final RectLayoutImpl INSTANCE = new RectLayoutImpl(); } static Object rectLayoutImpl() { return // BEGIN: rectlayoutimpl RectLayoutImpl.INSTANCE; // END: rectlayoutimpl } interface InterfaceSnippets { // BEGIN: rectlayoutcreate DynamicObject createRect(); // END: rectlayoutcreate // BEGIN: rectlayoutguards boolean isRect(DynamicObject object); boolean isRect(Object object); boolean isRect(ObjectType objectType); // END: rectlayoutguards // BEGIN: rectlayoutprops DynamicObject createRect(int x, int y, int width, int height); int getX(DynamicObject object); void setX(DynamicObject object, int value); int getWidth(DynamicObject object); void setWidth(DynamicObject object, int value); // END: rectlayoutprops // BEGIN: nullable DynamicObject createObject(@Nullable Object nullableProperty); // END: nullable // BEGIN: volatile boolean compareAndSetWidth(DynamicObject object, int expectedValue, int newValue); int getAndSet(DynamicObject object, int value); // END: volatile // BEGIN: semifinal void setValueUnsafe(DynamicObject object, Object value); // END: semifinal class JavaClass { } // BEGIN: javaobject @Layout interface JavaObjectLayout { DynamicObjectFactory createJavaObjectShape(JavaClass klass); DynamicObject createJavaObject(DynamicObjectFactory factory, int hashCode); JavaClass getKlass(DynamicObjectFactory factory); JavaClass getKlass(ObjectType objectType); JavaClass getKlass(DynamicObject object); int getHashCode(DynamicObject object); } // END: javaobject // BEGIN: shapesetters DynamicObjectFactory setKlass(DynamicObjectFactory factory, JavaClass value); void setKlass(DynamicObject object, JavaClass value); // END: shapesetters } static class JavaObjectImpl { static final JavaObjectImpl INSTANCE = new JavaObjectImpl(); @SuppressWarnings("unused") Object createJavaObject(Object x, Object y) { return null; } @SuppressWarnings("unused") Object createJavaObjectShape(Object x) { return null; } @SuppressWarnings("unused") void setKlass(Object x, Object y) { } } Object defaultHashCode() { return null; } void closeCycle() { Object // BEGIN: closecycle javaClassObject = JavaObjectImpl.INSTANCE.createJavaObject( JavaObjectImpl.INSTANCE.createJavaObjectShape(null), defaultHashCode()); JavaObjectImpl.INSTANCE.setKlass(javaClassObject, javaClassObject); // END: closecycle } // BEGIN: inheritanceinterfaces @Layout interface BaseLayout { DynamicObject createBase(int a); boolean isBase(DynamicObject object); int getA(DynamicObject object); void setA(DynamicObject object, int value); } @Layout interface SuperLayout extends BaseLayout { DynamicObject createSuper(int a, int b); int getB(DynamicObject object); void setB(DynamicObject object, int value); } // END: inheritanceinterfaces static class BaseImpl { static final BaseImpl INSTANCE = new BaseImpl(); @SuppressWarnings("unused") boolean isBase(Object x) { return false; } @SuppressWarnings("unused") Object getA(Object x) { return null; } } static class SuperImpl { static final SuperImpl INSTANCE = new SuperImpl(); @SuppressWarnings("unused") DynamicObject createSuper(int x, int y) { return null; } } void inheritanceUse() { // BEGIN: inheritanceuse DynamicObject object = SuperImpl.INSTANCE.createSuper(14, 2); BaseImpl.INSTANCE.isBase(object); BaseImpl.INSTANCE.getA(object); // END: inheritanceuse } // Checkstyle: stop // BEGIN: customid @Layout interface CustomIdentifierLayout { public static final String A_IDENTIFIER = "A"; DynamicObject createCustomIdentifier(int a); } // END: customid // Checkstyle: resume }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy