Top Description Fields Constructors Methods
org.jruby.runtime.ivars

public Class VariableTableManager

extends Object
Class Inheritance
Imports
java.io.IOException, .ObjectInputStream, .ObjectOutputStream, java.lang.invoke.MethodHandle, java.util.ArrayList, .Arrays, .Collections, .LinkedHashMap, .Map, java.util.function.Function, org.jruby.Ruby, .RubyBasicObject, .RubyClass, org.jruby.java.codegen.Reified, org.jruby.javasupport.util.JavaClassConfiguration, .JavaClassConfiguration.DirectFieldConfiguration, org.jruby.runtime.ObjectSpace, org.jruby.runtime.builtin.IRubyObject, org.jruby.specialized.RubyObjectSpecializer, org.jruby.util.ArraySupport

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:

Field Summary

Modifier and TypeField and Description
private final VariableAccessorField
ffiHandleVariableAccessorField

a lazy accessor for FFI handle

private volatile int
fieldVariables

whether objects associated with this table use fields

private volatile int
hasFFI

whether a slot has been allocated to ffi

private volatile int
hasObjectID

whether a slot has been allocated to object_id

private volatile int
hasObjectspaceGroup

whether a slot has been allocated to objectspace_group

private final VariableAccessorField
objectGroupVariableAccessorField

a lazy accessor for object group

private final VariableAccessorField
objectIdVariableAccessorField

a lazy accessor for object_id

private final RubyClass
realClass

the "real" class associated with this table

private Map<String, VariableAccessor>
variableAccessors

a map from strings to accessors for this table

private volatile String[]
variableNames

an array of all registered variable names

Constructor Summary

AccessConstructor and Description
public
VariableTableManager(RubyClass
the "real" class associated with this table
realClass
)

Construct a new VariableTable Manager for the given "real" class.

pack-priv
VariableTableManager(VariableTableManager
VariableTableManager to copy
original
)

Copy constructor with deep cloning.

Method Summary

Modifier and TypeMethod and Description
pack-priv final VariableAccessor

Returns:

the new VariableAccessor
allocateVariableAccessor
(String
the name of the variable
name
)

Allocate a new VariableAccessor for the named variable.

pack-priv final synchronized VariableAccessor
allocateVariableAccessors(String name, Function<Integer, VariableAccessor> builder)

Allocation helper to map variables to names

public Object
private static Map<String, VariableAccessor>
private static Map<String, VariableAccessor>
copyVariableAccessors(Map<String, VariableAccessor> myVariableAccessors, String name, VariableAccessor ivarAccessor)

public void
public VariableTableManager
public final Object

Returns:

the object's FFI handle
getFFIHandle
(RubyBasicObject
the object
self
)

Retrieve the FFI ext handle for the given object.

public VariableAccessorField

Returns:

the lazy accessor for FFI handle
getFFIHandleAccessorField
()

Retrieve the lazy accessor (VariableAccessorField) for FFI handle.

public VariableAccessor

Returns:

the read accessor for FFI handle
getFFIHandleAccessorForRead
()

Retrieve the read accessor for FFI handle.

public VariableAccessor

Returns:

the write accessor for FFI handle
getFFIHandleAccessorForWrite
()

Retrieve the write accessor for FFI handle.

public VariableAccessorField

Returns:

the lazy accessor for object group
getObjectGroupAccessorField
()

Retrieve the lazy accessor (VariableAccessorField) for object group.

public VariableAccessor

Returns:

the read accessor for object group
getObjectGroupAccessorForRead
()

Retrieve the read accessor for object group.

public VariableAccessor

Returns:

the write accessor for object group
getObjectGroupAccessorForWrite
()

Retrieve the write accessor for object group.

public long

Returns:

the object's object_id (possibly new)
getObjectId
(RubyBasicObject
the object from which to get object_id
self
)

Get the object_id from a given RubyBasicObject, possibly allocating space for it.

public VariableAccessorField

Returns:

the lazy accessor for object_id
getObjectIdAccessorField
()

Retrieve the lazy accessor (VariableAccessorField) for object_id.

public VariableAccessor

Returns:

the read accessor for object_id
getObjectIdAccessorForRead
()

Retrieve the read accessor for object_id for reads.

public VariableAccessor

Returns:

the write accessor for object_id
getObjectIdAccessorForWrite
()

Retrieve the write accessor for object_id.

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

public VariableAccessor

Returns:

an accessor appropriate for reading
getVariableAccessorForRead
(String
the name of the variable
name
)

Get the variable accessor for the given name with intent to use it for reading.

public VariableAccessor
public VariableAccessor

Returns:

an accessor appropriate for writing
getVariableAccessorForWrite
(String
the name of the variable
name
)

Get the variable accessor for the given name with intent to use it for writing.

public Map<String, VariableAccessor>

Returns:

a map of current variable accessors
getVariableAccessorsForRead
()

Get the map of all current variable accessors with intent to read from it.

pack-priv VariableAccessor

Returns:

an accessor
getVariableAccessorWithBuilder
(String
the name of the variable
name
,
Function<Integer, VariableAccessor>
a builder to use if the accessor doesn't exist yet
defaultAccessorBuilder
)

Get the variable accessor for the given name, or if it doesn't exist, create it with the provided builder.

public String[]

Returns:

a copy of the array of known instance variable names
getVariableNames
()

Get an array of all the known instance variable names.

public Map<String, VariableAccessor>

Returns:

a map of names to accessors for all variables
getVariableTableCopy
()

Get a Map representing all variables registered in the variable table.

public int

Returns:

the variable table's size, excluding extras
getVariableTableSize
()

Get the size of the variable table, excluding extra vars (object_id, etc).

public int
getVariableTableSizeWithExtras()

Get the size of the variable table, including extra vars (object_etc, etc).

public boolean
public boolean

Returns:

true if object_id has been allocated; false otherwise
hasObjectID
()

Whether this table has been used to allocate space for an object_id.

public boolean

Returns:

true if object has any variables, else false
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
private long

Returns:

The generated object ID
initObjectId
(RubyBasicObject self, VariableAccessor
The variable accessor to use for storing the generated object ID
objectIdAccessor
)

We lazily stand up the object ID since it forces us to stand up per-object state for a given object.

pack-priv 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.

pack-priv final Function<Integer, VariableAccessor>
makeRubyFieldAccessorBuilder(String name, MethodHandle getter, MethodHandle setter)

Makes an IRubyObject field accessor builder for reified classes.

private static Object[]

Returns:

a new table formed by combining the given tables
makeSyncedTable
(Object[]
the current table
currentTable
,
Object[]
the other (incoming) table
otherTable
,
int
the index of object_id to exclude
objectIdIdx
)

Make a new variable table based on the values in a current and other (incoming) table, excluding object_id at specified index.

pack-priv final Function<Integer, VariableAccessor>
makeTableVariableAccessorBuilder(String name)

Makes a standard table accessor builder.

public synchronized 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

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

public void
public final void
setFFIHandle(RubyBasicObject
  • the object
  • the object's FFI handle
self
,
Object value)

Set the FFI handle for the given object.

private static void
setObjectId(RubyClass realClass, RubyBasicObject
the object into which to set object_id
self
,
int
the index allocated to store object_id
index
,
long
the value of object_id
value
)

Update object_id with the given value.

public void
setVariableInternal(RubyBasicObject
the object into which to set the value
self
,
int
the index allocated for the value
index
,
Object
the value
value
)

Virtual entry point for setting a variable into an object.

public static void
setVariableInternal(RubyClass
the "real" class of the object
realClass
,
RubyBasicObject
the object into which to set the variable
self
,
int
the index allocated for the variable
index
,
Object
the value of the variable
value
)

Static entry point for setting a variable in an object.

public void
syncVariables(RubyBasicObject
the object into which to sync variables
self
,
IRubyObject
the object from which to sync variables
other
)

Sync one this object's variables with other's - this is used to make rbClone work correctly.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

ffiHandleVariableAccessorFieldback to summary
private final VariableAccessorField ffiHandleVariableAccessorField

a lazy accessor for FFI handle

fieldVariablesback to summary
private volatile int fieldVariables

whether objects associated with this table use fields

hasFFIback to summary
private volatile int hasFFI

whether a slot has been allocated to ffi

hasObjectIDback to summary
private volatile int hasObjectID

whether a slot has been allocated to object_id

hasObjectspaceGroupback to summary
private volatile int hasObjectspaceGroup

whether a slot has been allocated to objectspace_group

objectGroupVariableAccessorFieldback to summary
private final VariableAccessorField objectGroupVariableAccessorField

a lazy accessor for object group

objectIdVariableAccessorFieldback to summary
private final VariableAccessorField objectIdVariableAccessorField

a lazy accessor for object_id

realClassback to summary
private final RubyClass realClass

the "real" class associated with this table

variableAccessorsback to summary
private Map<String, VariableAccessor> variableAccessors

a map from strings to accessors for this table

Annotations
@SuppressWarnings:unchecked
variableNamesback to summary
private volatile String[] variableNames

an array of all registered variable names

Constructor Detail

VariableTableManagerback to summary
public VariableTableManager(RubyClass realClass)

Construct a new VariableTable Manager for the given "real" class.

Parameters
realClass:RubyClass

the "real" class associated with this table

VariableTableManagerback to summary
pack-priv VariableTableManager(VariableTableManager original)

Copy constructor with deep cloning.

Parameters
original:VariableTableManager

VariableTableManager to copy

Method Detail

allocateVariableAccessorback to summary
pack-priv final VariableAccessor allocateVariableAccessor(String name)

Allocate a new VariableAccessor for the named variable.

Parameters
name:String

the name of the variable

Returns:VariableAccessor

the new VariableAccessor

allocateVariableAccessorsback to summary
pack-priv final synchronized VariableAccessor allocateVariableAccessors(String name, Function<Integer, VariableAccessor> builder)

Allocation helper to map variables to names

clearVariableback to summary
public Object clearVariable(RubyBasicObject object, String name)
copyVariableAccessorsback to summary
private static Map<String, VariableAccessor> copyVariableAccessors(Map<String, VariableAccessor> myVariableAccessors)
copyVariableAccessorsback to summary
private static Map<String, VariableAccessor> copyVariableAccessors(Map<String, VariableAccessor> myVariableAccessors, String name, VariableAccessor ivarAccessor)
deserializeVariablesback to summary
public void deserializeVariables(RubyBasicObject object, ObjectInputStream ois) throws IOException, ClassNotFoundException
duplicateback to summary
public VariableTableManager duplicate()
getFFIHandleback to summary
public final Object getFFIHandle(RubyBasicObject self)

Retrieve the FFI ext handle for the given object.

Parameters
self:RubyBasicObject

the object

Returns:Object

the object's FFI handle

getFFIHandleAccessorFieldback to summary
public VariableAccessorField getFFIHandleAccessorField()

Retrieve the lazy accessor (VariableAccessorField) for FFI handle.

Returns:VariableAccessorField

the lazy accessor for FFI handle

Annotations
@Deprecated
since:9.4-
getFFIHandleAccessorForReadback to summary
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:VariableAccessor

the read accessor for FFI handle

getFFIHandleAccessorForWriteback to summary
public VariableAccessor getFFIHandleAccessorForWrite()

Retrieve the write accessor for FFI handle.

Returns:VariableAccessor

the write accessor for FFI handle

getObjectGroupAccessorFieldback to summary
public VariableAccessorField getObjectGroupAccessorField()

Retrieve the lazy accessor (VariableAccessorField) for object group.

Returns:VariableAccessorField

the lazy accessor for object group

Annotations
@Deprecated
since:9.4-
getObjectGroupAccessorForReadback to summary
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:VariableAccessor

the read accessor for object group

getObjectGroupAccessorForWriteback to summary
public VariableAccessor getObjectGroupAccessorForWrite()

Retrieve the write accessor for object group.

Returns:VariableAccessor

the write accessor for object group

getObjectIdback to summary
public long getObjectId(RubyBasicObject self)

Get the object_id from a given RubyBasicObject, possibly allocating space for it.

Parameters
self:RubyBasicObject

the object from which to get object_id

Returns:long

the object's object_id (possibly new)

getObjectIdAccessorFieldback to summary
public VariableAccessorField getObjectIdAccessorField()

Retrieve the lazy accessor (VariableAccessorField) for object_id.

Returns:VariableAccessorField

the lazy accessor for object_id

Annotations
@Deprecated
since:9.4-
getObjectIdAccessorForReadback to summary
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:VariableAccessor

the read accessor for object_id

getObjectIdAccessorForWriteback to summary
public VariableAccessor getObjectIdAccessorForWrite()

Retrieve the write accessor for object_id.

Returns:VariableAccessor

the write accessor for object_id

getRealClassback to summary
public RubyClass getRealClass()
getVariableAccessorForJavaMappedVarback to summary
public VariableAccessor getVariableAccessorForJavaMappedVar(String name, boolean unwrap, Class<?> unwrapType, Class<?> fieldType, MethodHandle getter, MethodHandle setter)
getVariableAccessorForReadback to summary
public VariableAccessor getVariableAccessorForRead(String name)

Get the variable accessor for the given name with intent to use it for reading.

Parameters
name:String

the name of the variable

Returns:VariableAccessor

an accessor appropriate for reading

getVariableAccessorForRubyVarback to summary
public VariableAccessor getVariableAccessorForRubyVar(String name, MethodHandle getter, MethodHandle setter)
getVariableAccessorForWriteback to summary
public VariableAccessor getVariableAccessorForWrite(String name)

Get the variable accessor for the given name with intent to use it for writing.

Parameters
name:String

the name of the variable

Returns:VariableAccessor

an accessor appropriate for writing

getVariableAccessorsForReadback to summary
public Map<String, VariableAccessor> getVariableAccessorsForRead()

Get the map of all current variable accessors with intent to read from it.

Returns:Map<String, VariableAccessor>

a map of current variable accessors

getVariableAccessorWithBuilderback to summary
pack-priv 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:String

the name of the variable

defaultAccessorBuilder:Function<Integer, VariableAccessor>

a builder to use if the accessor doesn't exist yet

Returns:VariableAccessor

an accessor

getVariableNamesback to summary
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:String[]

a copy of the array of known instance variable names

getVariableTableCopyback to summary
public Map<String, VariableAccessor> getVariableTableCopy()

Get a Map representing all variables registered in the variable table.

Returns:Map<String, VariableAccessor>

a map of names to accessors for all variables

getVariableTableSizeback to summary
public int getVariableTableSize()

Get the size of the variable table, excluding extra vars (object_id, etc).

Returns:int

the variable table's size, excluding extras

getVariableTableSizeWithExtrasback to summary
public int getVariableTableSizeWithExtras()

Get the size of the variable table, including extra vars (object_etc, etc).

hasInstanceVariablesback to summary
public boolean hasInstanceVariables(RubyBasicObject object)
hasObjectIDback to summary
public boolean hasObjectID()

Whether this table has been used to allocate space for an object_id.

Returns:boolean

true if object_id has been allocated; false otherwise

hasVariablesback to summary
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:boolean

true if object has any variables, else false

initObjectIdback to summary
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:VariableAccessor

The variable accessor to use for storing the generated object ID

Returns:long

The generated object ID

makeRawFieldAccessorBuilderback to summary
pack-priv 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

makeRubyFieldAccessorBuilderback to summary
pack-priv final Function<Integer, VariableAccessor> makeRubyFieldAccessorBuilder(String name, MethodHandle getter, MethodHandle setter)

Makes an IRubyObject field accessor builder for reified classes. Pass this into getVariableAccessorWithBuilder

makeSyncedTableback to summary
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:Object[]

the current table

otherTable:Object[]

the other (incoming) table

objectIdIdx:int

the index of object_id to exclude

Returns:Object[]

a new table formed by combining the given tables

makeTableVariableAccessorBuilderback to summary
pack-priv final Function<Integer, VariableAccessor> makeTableVariableAccessorBuilder(String name)

Makes a standard table accessor builder. Pass this into getVariableAccessorWithBuilder

requestFieldStorageback to summary
public synchronized 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

requestFieldStorageback to summary
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

serializeVariablesback to summary
public void serializeVariables(RubyBasicObject object, ObjectOutputStream oos) throws IOException
setFFIHandleback to summary
public final void setFFIHandle(RubyBasicObject self, Object value)

Set the FFI handle for the given object.

Parameters
self:RubyBasicObject

  • the object
  • the object's FFI handle
setObjectIdback to summary
private static void setObjectId(RubyClass realClass, RubyBasicObject self, int index, long value)

Update object_id with the given value.

Parameters
self:RubyBasicObject

the object into which to set object_id

index:int

the index allocated to store object_id

value:long

the value of object_id

setVariableInternalback to summary
public void setVariableInternal(RubyBasicObject self, int index, Object value)

Virtual entry point for setting a variable into an object.

Parameters
self:RubyBasicObject

the object into which to set the value

index:int

the index allocated for the value

value:Object

the value

setVariableInternalback to summary
public static void setVariableInternal(RubyClass realClass, RubyBasicObject self, int index, Object value)

Static entry point for setting a variable in an object.

Parameters
realClass:RubyClass

the "real" class of the object

self:RubyBasicObject

the object into which to set the variable

index:int

the index allocated for the variable

value:Object

the value of the variable

syncVariablesback to summary
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:RubyBasicObject

the object into which to sync variables

other:IRubyObject

the object from which to sync variables