Class VariableTableManager

java.lang.Object
org.jruby.runtime.ivars.VariableTableManager

public class VariableTableManager extends Object
This class encapculates all logic relating to the management of instance variable tables in RubyBasicObject instances. The logic originally lived in both RubyBasicObject and RubyClass, tightly coupled to each and difficult to follow as it bounced back and forth. We moved the logic here for a couple reasons:
  • To have a single place from which we could follow ivar logic.
  • To make it easier to swap in new implementations of instance variable logic as we work toward reifying ivars into fields.
  • To remove rather noisy logic from RubyBasicObject and RubyClass.
    • Field Details

      • realClass

        private final RubyClass realClass
        the "real" class associated with this table
      • variableAccessors

        private Map<String,VariableAccessor> variableAccessors
        a map from strings to accessors for this table
      • variableNames

        private volatile String[] variableNames
        an array of all registered variable names
      • hasObjectID

        private volatile int hasObjectID
        whether a slot has been allocated to object_id
      • hasFFI

        private volatile int hasFFI
        whether a slot has been allocated to ffi
      • hasObjectspaceGroup

        private volatile int hasObjectspaceGroup
        whether a slot has been allocated to objectspace_group
      • fieldVariables

        private volatile int fieldVariables
        whether objects associated with this table use fields
      • objectIdVariableAccessorField

        private final VariableAccessorField objectIdVariableAccessorField
        a lazy accessor for object_id
      • ffiHandleVariableAccessorField

        private final VariableAccessorField ffiHandleVariableAccessorField
        a lazy accessor for FFI handle
      • objectGroupVariableAccessorField

        private final VariableAccessorField objectGroupVariableAccessorField
        a lazy accessor for object group
    • Constructor Details

      • VariableTableManager

        public VariableTableManager(RubyClass realClass)
        Construct a new VariableTable Manager for the given "real" class.
        Parameters:
        realClass - the "real" class associated with this table
    • Method Details

      • getVariableAccessorsForRead

        public Map<String,VariableAccessor> getVariableAccessorsForRead()
        Get the map of all current variable accessors with intent to read from it.
        Returns:
        a map of current variable accessors
      • hasObjectID

        public boolean hasObjectID()
        Whether this table has been used to allocate space for an object_id.
        Returns:
        true if object_id has been allocated; false otherwise
      • getObjectId

        public long getObjectId(RubyBasicObject self)
        Get the object_id from a given RubyBasicObject, possibly allocating space for it.
        Parameters:
        self - the object from which to get object_id
        Returns:
        the object's object_id (possibly new)
      • setVariableInternal

        public void setVariableInternal(RubyBasicObject self, int index, Object value)
        Virtual entry point for setting a variable into an object.
        Parameters:
        self - the object into which to set the value
        index - the index allocated for the value
        value - the value
      • setVariableInternal

        public static void setVariableInternal(RubyClass realClass, RubyBasicObject self, int index, Object value)
        Static entry point for setting a variable in an object.
        Parameters:
        realClass - the "real" class of the object
        self - the object into which to set the variable
        index - the index allocated for the variable
        value - the value of the variable
      • requestFieldStorage

        public void requestFieldStorage(String name, Class<?> fieldType, Boolean unwrap, Class<?> toType)
        This is internal API, don't call this directly if you aren't in the JRuby codebase, it may change Request that the listed ivars (no @ in name) have field storage when we are reified
      • requestFieldStorage

        public void requestFieldStorage(JavaClassConfiguration.DirectFieldConfiguration config)
        Actually requests field storage for the ivar once we are reified This is internal API, don't call this directly if you aren't in the JRuby codebase, it may change
      • getVariableAccessorForWrite

        public VariableAccessor getVariableAccessorForWrite(String name)
        Get the variable accessor for the given name with intent to use it for writing.
        Parameters:
        name - the name of the variable
        Returns:
        an accessor appropriate for writing
      • getVariableAccessorForRubyVar

        public VariableAccessor getVariableAccessorForRubyVar(String name, MethodHandle getter, MethodHandle setter)
      • getVariableAccessorForJavaMappedVar

        public VariableAccessor getVariableAccessorForJavaMappedVar(String name, boolean unwrap, Class<?> unwrapType, Class<?> fieldType, MethodHandle getter, MethodHandle setter)
      • getVariableAccessorWithBuilder

        VariableAccessor getVariableAccessorWithBuilder(String name, Function<Integer,VariableAccessor> defaultAccessorBuilder)
        Get the variable accessor for the given name, or if it doesn't exist, create it with the provided builder.
        Parameters:
        name - the name of the variable
        defaultAccessorBuilder - a builder to use if the accessor doesn't exist yet
        Returns:
        an accessor
      • getVariableAccessorForRead

        public VariableAccessor getVariableAccessorForRead(String name)
        Get the variable accessor for the given name with intent to use it for reading.
        Parameters:
        name - the name of the variable
        Returns:
        an accessor appropriate for reading
      • getObjectIdAccessorForRead

        public VariableAccessor getObjectIdAccessorForRead()
        Retrieve the read accessor for object_id for reads. If no object_id has been prepared, this will return a dummy accessor that just returns null.
        Returns:
        the read accessor for object_id
      • getObjectIdAccessorForWrite

        public VariableAccessor getObjectIdAccessorForWrite()
        Retrieve the write accessor for object_id.
        Returns:
        the write accessor for object_id
      • getFFIHandleAccessorForRead

        public VariableAccessor getFFIHandleAccessorForRead()
        Retrieve the read accessor for FFI handle. If no object_id has been prepared, this will return a dummy accessor that just returns null.
        Returns:
        the read accessor for FFI handle
      • getFFIHandleAccessorForWrite

        public VariableAccessor getFFIHandleAccessorForWrite()
        Retrieve the write accessor for FFI handle.
        Returns:
        the write accessor for FFI handle
      • getObjectGroupAccessorForRead

        public VariableAccessor getObjectGroupAccessorForRead()
        Retrieve the read accessor for object group. If no object_id has been prepared, this will return a dummy accessor that just returns null.
        Returns:
        the read accessor for object group
      • getObjectGroupAccessorForWrite

        public VariableAccessor getObjectGroupAccessorForWrite()
        Retrieve the write accessor for object group.
        Returns:
        the write accessor for object group
      • getFFIHandle

        public final Object getFFIHandle(RubyBasicObject self)
        Retrieve the FFI ext handle for the given object.
        Parameters:
        self - the object
        Returns:
        the object's FFI handle
      • setFFIHandle

        public final void setFFIHandle(RubyBasicObject self, Object value)
        Set the FFI handle for the given object.
        Parameters:
        self - the object
        self - the object's FFI handle
      • getVariableTableSize

        public int getVariableTableSize()
        Get the size of the variable table, excluding extra vars (object_id, etc).
        Returns:
        the variable table's size, excluding extras
      • getVariableTableSizeWithExtras

        public int getVariableTableSizeWithExtras()
        Get the size of the variable table, including extra vars (object_etc, etc).
        Returns:
      • getVariableTableCopy

        public Map<String,VariableAccessor> getVariableTableCopy()
        Get a Map representing all variables registered in the variable table.
        Returns:
        a map of names to accessors for all variables
      • getVariableNames

        public String[] getVariableNames()
        Get an array of all the known instance variable names. The offset into the array indicates the offset of the variable's value in the per-object variable array.
        Returns:
        a copy of the array of known instance variable names
      • syncVariables

        public void syncVariables(RubyBasicObject self, IRubyObject other)
        Sync one this object's variables with other's - this is used to make rbClone work correctly.
        Parameters:
        self - the object into which to sync variables
        other - the object from which to sync variables
      • hasVariables

        public boolean hasVariables(RubyBasicObject object)
        Returns true if object has any variables, defined as:
        • instance variables
        • class variables
        • constants
        • internal variables, such as those used when marshaling Ranges and Exceptions
        Returns:
        true if object has any variables, else false
      • hasInstanceVariables

        public boolean hasInstanceVariables(RubyBasicObject object)
      • serializeVariables

        public void serializeVariables(RubyBasicObject object, ObjectOutputStream oos) throws IOException
        Throws:
        IOException
      • deserializeVariables

        public void deserializeVariables(RubyBasicObject object, ObjectInputStream ois) throws IOException, ClassNotFoundException
        Throws:
        IOException
        ClassNotFoundException
      • clearVariable

        public Object clearVariable(RubyBasicObject object, String name)
      • initObjectId

        private long initObjectId(RubyBasicObject self, VariableAccessor objectIdAccessor)
        We lazily stand up the object ID since it forces us to stand up per-object state for a given object. We also check for ObjectSpace here, and normally we do not register a given object ID into ObjectSpace due to the high cost associated with constructing the related weakref. Most uses of id/object_id will only ever need it to be a unique identifier, and the id2ref behavior provided by ObjectSpace is considered internal and not generally supported. Note that this method does not need to be synchronized, since it is only called from #getObjectId, which synchronizes against the target object. The accessor is already present, and variable accesses are thread-safe (albeit not atomic, which necessitates the synchronization in getObjectId). Synchronization here ends up being a bottleneck for every object created from the class that contains this VariableTableManager. See GH #1400.
        Parameters:
        objectIdAccessor - The variable accessor to use for storing the generated object ID
        Returns:
        The generated object ID
      • setObjectId

        private static void setObjectId(RubyClass realClass, RubyBasicObject self, int index, long value)
        Update object_id with the given value.
        Parameters:
        self - the object into which to set object_id
        index - the index allocated to store object_id
        value - the value of object_id
      • makeSyncedTable

        private static Object[] makeSyncedTable(Object[] currentTable, Object[] otherTable, int objectIdIdx)
        Make a new variable table based on the values in a current and other (incoming) table, excluding object_id at specified index.
        Parameters:
        currentTable - the current table
        otherTable - the other (incoming) table
        objectIdIdx - the index of object_id to exclude
        Returns:
        a new table formed by combining the given tables
      • allocateVariableAccessor

        final VariableAccessor allocateVariableAccessor(String name)
        Allocate a new VariableAccessor for the named variable.
        Parameters:
        name - the name of the variable
        Returns:
        the new VariableAccessor
      • makeTableVariableAccessorBuilder

        final Function<Integer,VariableAccessor> makeTableVariableAccessorBuilder(String name)
        Makes a standard table accessor builder. Pass this into getVariableAccessorWithBuilder
      • makeRawFieldAccessorBuilder

        final Function<Integer,VariableAccessor> makeRawFieldAccessorBuilder(String name, boolean unwrap, Class<?> unwrapType, Class<?> fieldType, MethodHandle getter, MethodHandle setter)
        Makes a raw field accessor builder for reified classes with java_field. Pass this into getVariableAccessorWithBuilder
      • makeRubyFieldAccessorBuilder

        final Function<Integer,VariableAccessor> makeRubyFieldAccessorBuilder(String name, MethodHandle getter, MethodHandle setter)
        Makes an IRubyObject field accessor builder for reified classes. Pass this into getVariableAccessorWithBuilder
      • allocateVariableAccessors

        final VariableAccessor allocateVariableAccessors(String name, Function<Integer,VariableAccessor> builder)
        Allocation helper to map variables to names
      • getObjectIdAccessorField

        public VariableAccessorField getObjectIdAccessorField()
        Retrieve the lazy accessor (VariableAccessorField) for object_id.
        Returns:
        the lazy accessor for object_id
      • getFFIHandleAccessorField

        public VariableAccessorField getFFIHandleAccessorField()
        Retrieve the lazy accessor (VariableAccessorField) for FFI handle.
        Returns:
        the lazy accessor for FFI handle
      • getObjectGroupAccessorField

        public VariableAccessorField getObjectGroupAccessorField()
        Retrieve the lazy accessor (VariableAccessorField) for object group.
        Returns:
        the lazy accessor for object group