Package org.jruby.runtime.ivars
Class VariableTableManager
java.lang.Object
org.jruby.runtime.ivars.VariableTableManager
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 Summary
FieldsModifier and TypeFieldDescriptionprivate final VariableAccessorFielda lazy accessor for FFI handleprivate intwhether objects associated with this table use fieldsprivate intwhether a slot has been allocated to ffiprivate intwhether a slot has been allocated to object_idprivate intwhether a slot has been allocated to objectspace_groupprivate final VariableAccessorFielda lazy accessor for object groupprivate final VariableAccessorFielda lazy accessor for object_idprivate final RubyClassthe "real" class associated with this tableprivate Map<String,VariableAccessor> a map from strings to accessors for this tableprivate String[]an array of all registered variable names -
Constructor Summary
ConstructorsConstructorDescriptionVariableTableManager(RubyClass realClass) Construct a new VariableTable Manager for the given "real" class. -
Method Summary
Modifier and TypeMethodDescription(package private) final VariableAccessorAllocate a new VariableAccessor for the named variable.(package private) final VariableAccessorallocateVariableAccessors(String name, Function<Integer, VariableAccessor> builder) Allocation helper to map variables to namesclearVariable(RubyBasicObject object, String name) voiddeserializeVariables(RubyBasicObject object, ObjectInputStream ois) final ObjectgetFFIHandle(RubyBasicObject self) Retrieve the FFI ext handle for the given object.Deprecated.Retrieve the read accessor for FFI handle.Retrieve the write accessor for FFI handle.Deprecated.Retrieve the read accessor for object group.Retrieve the write accessor for object group.longgetObjectId(RubyBasicObject self) Get the object_id from a given RubyBasicObject, possibly allocating space for it.Deprecated.Retrieve the read accessor for object_id for reads.Retrieve the write accessor for object_id.getVariableAccessorForJavaMappedVar(String name, boolean unwrap, Class<?> unwrapType, Class<?> fieldType, MethodHandle getter, MethodHandle setter) Get the variable accessor for the given name with intent to use it for reading.getVariableAccessorForRubyVar(String name, MethodHandle getter, MethodHandle setter) Get the variable accessor for the given name with intent to use it for writing.Get the map of all current variable accessors with intent to read from it.(package private) VariableAccessorgetVariableAccessorWithBuilder(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.String[]Get an array of all the known instance variable names.Get a Map representing all variables registered in the variable table.intGet the size of the variable table, excluding extra vars (object_id, etc).intGet the size of the variable table, including extra vars (object_etc, etc).booleanhasInstanceVariables(RubyBasicObject object) booleanWhether this table has been used to allocate space for an object_id.booleanhasVariables(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 Exceptionsprivate longinitObjectId(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.(package private) 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.(package private) final Function<Integer,VariableAccessor> makeRubyFieldAccessorBuilder(String name, MethodHandle getter, MethodHandle setter) Makes an IRubyObject field accessor builder for reified classes.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.(package private) final Function<Integer,VariableAccessor> Makes a standard table accessor builder.voidrequestFieldStorage(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 reifiedvoidActually 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 changevoidserializeVariables(RubyBasicObject object, ObjectOutputStream oos) final voidsetFFIHandle(RubyBasicObject self, Object value) Set the FFI handle for the given object.private static voidsetObjectId(RubyClass realClass, RubyBasicObject self, int index, long value) Update object_id with the given value.voidsetVariableInternal(RubyBasicObject self, int index, Object value) Virtual entry point for setting a variable into an object.static voidsetVariableInternal(RubyClass realClass, RubyBasicObject self, int index, Object value) Static entry point for setting a variable in an object.voidsyncVariables(RubyBasicObject self, IRubyObject other) Sync one this object's variables with other's - this is used to make rbClone work correctly.
-
Field Details
-
realClass
the "real" class associated with this table -
variableAccessors
a map from strings to accessors for this table -
variableNames
an array of all registered variable names -
hasObjectID
private volatile int hasObjectIDwhether a slot has been allocated to object_id -
hasFFI
private volatile int hasFFIwhether a slot has been allocated to ffi -
hasObjectspaceGroup
private volatile int hasObjectspaceGroupwhether a slot has been allocated to objectspace_group -
fieldVariables
private volatile int fieldVariableswhether objects associated with this table use fields -
objectIdVariableAccessorField
a lazy accessor for object_id -
ffiHandleVariableAccessorField
a lazy accessor for FFI handle -
objectGroupVariableAccessorField
a lazy accessor for object group
-
-
Constructor Details
-
VariableTableManager
Construct a new VariableTable Manager for the given "real" class.- Parameters:
realClass- the "real" class associated with this table
-
-
Method Details
-
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
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
Virtual entry point for setting a variable into an object.- Parameters:
self- the object into which to set the valueindex- the index allocated for the valuevalue- 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 objectself- the object into which to set the variableindex- the index allocated for the variablevalue- the value of the variable
-
requestFieldStorage
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
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
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 variabledefaultAccessorBuilder- a builder to use if the accessor doesn't exist yet- Returns:
- an accessor
-
getVariableAccessorForRead
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
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
Retrieve the write accessor for object_id.- Returns:
- the write accessor for object_id
-
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
Retrieve the write accessor for FFI handle.- Returns:
- the write accessor for FFI handle
-
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
Retrieve the write accessor for object group.- Returns:
- the write accessor for object group
-
getFFIHandle
Retrieve the FFI ext handle for the given object.- Parameters:
self- the object- Returns:
- the object's FFI handle
-
setFFIHandle
Set the FFI handle for the given object.- Parameters:
self- the objectself- 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
Get a Map representing all variables registered in the variable table.- Returns:
- a map of names to accessors for all variables
-
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
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 variablesother- the object from which to sync variables
-
hasVariables
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
-
serializeVariables
- Throws:
IOException
-
deserializeVariables
public void deserializeVariables(RubyBasicObject object, ObjectInputStream ois) throws IOException, ClassNotFoundException - Throws:
IOExceptionClassNotFoundException
-
clearVariable
-
initObjectId
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
Update object_id with the given value.- Parameters:
self- the object into which to set object_idindex- the index allocated to store object_idvalue- 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 tableotherTable- the other (incoming) tableobjectIdIdx- the index of object_id to exclude- Returns:
- a new table formed by combining the given tables
-
allocateVariableAccessor
Allocate a new VariableAccessor for the named variable.- Parameters:
name- the name of the variable- Returns:
- the new VariableAccessor
-
makeTableVariableAccessorBuilder
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
Deprecated.Retrieve the lazy accessor (VariableAccessorField) for object_id.- Returns:
- the lazy accessor for object_id
-
getFFIHandleAccessorField
Deprecated.Retrieve the lazy accessor (VariableAccessorField) for FFI handle.- Returns:
- the lazy accessor for FFI handle
-
getObjectGroupAccessorField
Deprecated.Retrieve the lazy accessor (VariableAccessorField) for object group.- Returns:
- the lazy accessor for object group
-
getFFIHandleAccessorForRead()orgetFFIHandleAccessorForWrite()