summaryrefslogtreecommitdiff
path: root/variable.c
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2021-10-18 17:01:40 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2021-10-20 18:19:43 -0400
commitb74d6563a665f225f182c4921db68852bbb7e1f1 (patch)
tree14a7131d423549cf1ffc661048e7501d5ce5ae24 /variable.c
parent2e2430564aa32b68f9e2d99e1f1e273bee3defda (diff)
Extract yjit_force_iv_index and make it work when object is frozen
In an effort to simplify the logic YJIT generates for accessing instance variable, YJIT ensures that a given name-to-index mapping exists at compile time. In the case that the mapping doesn't exist, it was created by using rb_ivar_set() with Qundef on the sample object we see at compile time. This hack isn't fine if the sample object happens to be frozen, in which case YJIT would raise a FrozenError unexpectedly. To deal with this, make a new function that only reserves the mapping but doesn't touch the object. This is rb_obj_ensure_iv_index_mapping(). This new function superceeds the functionality of rb_iv_index_tbl_lookup() so it was removed. Reported by and includes a test case from John Hawthorn <john@hawthorn.email> Fixes: GH-282
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/variable.c b/variable.c
index 5712ccf0ba..6cfc3f68f2 100644
--- a/variable.c
+++ b/variable.c
@@ -1446,12 +1446,13 @@ rb_init_iv_list(VALUE obj)
init_iv_list(obj, len, newsize, index_tbl);
}
-static VALUE
-obj_ivar_set(VALUE obj, ID id, VALUE val)
+// Retreive or create the id-to-index mapping for a given object and an
+// instance variable name.
+static struct ivar_update
+obj_ensure_iv_index_mapping(VALUE obj, ID id)
{
VALUE klass = rb_obj_class(obj);
struct ivar_update ivup;
- uint32_t len;
ivup.iv_extended = 0;
ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass);
@@ -1461,6 +1462,32 @@ obj_ivar_set(VALUE obj, ID id, VALUE val)
}
RB_VM_LOCK_LEAVE();
+ return ivup;
+}
+
+// Return the instance variable index for a given name and T_OBJECT object. The
+// mapping between name and index lives on `rb_obj_class(obj)` and is created
+// if not already present.
+//
+// @note May raise when there are too many instance variables.
+// @note YJIT uses this function at compile time to simplify the work needed to
+// access the variable at runtime.
+uint32_t
+rb_obj_ensure_iv_index_mapping(VALUE obj, ID id)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT));
+ // This uint32_t cast shouldn't lose information as it's checked in
+ // iv_index_tbl_extend(). The index is stored as an uint32_t in
+ // struct rb_iv_index_tbl_entry.
+ return (uint32_t)obj_ensure_iv_index_mapping(obj, id).index;
+}
+
+static VALUE
+obj_ivar_set(VALUE obj, ID id, VALUE val)
+{
+ uint32_t len;
+ struct ivar_update ivup = obj_ensure_iv_index_mapping(obj, id);
+
len = ROBJECT_NUMIV(obj);
if (len <= ivup.index) {
uint32_t newsize = iv_index_tbl_newsize(&ivup);