@@ -1446,118 +1446,56 @@ enum {
1446
1446
SEND_MAX_DEPTH = 5 , // up to 5 different classes
1447
1447
};
1448
1448
1449
- /*
1450
- // Codegen for setting an instance variable.
1451
- // Preconditions:
1452
- // - receiver is in REG0
1453
- // - receiver has the same class as CLASS_OF(comptime_receiver)
1454
- // - no stack push or pops to ctx since the entry to the codegen of the instruction being compiled
1455
- static codegen_status_t
1456
- gen_set_ivar(jitstate_t *jit, ctx_t *ctx, const int max_chain_depth, VALUE comptime_receiver, ID ivar_name, insn_opnd_t reg0_opnd, uint8_t *side_exit)
1449
+ static uint32_t
1450
+ yjit_force_iv_index (VALUE comptime_receiver , VALUE klass , ID name )
1457
1451
{
1458
- VALUE comptime_val_klass = CLASS_OF(comptime_receiver);
1459
- const ctx_t starting_context = *ctx; // make a copy for use with jit_chain_guard
1460
-
1461
- // If the class uses the default allocator, instances should all be T_OBJECT
1462
- // NOTE: This assumes nobody changes the allocator of the class after allocation.
1463
- // Eventually, we can encode whether an object is T_OBJECT or not
1464
- // inside object shapes.
1465
- if (rb_get_alloc_func(comptime_val_klass) != rb_class_allocate_instance) {
1466
- GEN_COUNTER_INC(cb, setivar_not_object);
1467
- return YJIT_CANT_COMPILE;
1468
- }
1469
- RUBY_ASSERT(BUILTIN_TYPE(comptime_receiver) == T_OBJECT); // because we checked the allocator
1470
-
1471
- // ID for the name of the ivar
1472
- ID id = ivar_name;
1452
+ ID id = name ;
1473
1453
struct rb_iv_index_tbl_entry * ent ;
1474
1454
struct st_table * iv_index_tbl = ROBJECT_IV_INDEX_TBL (comptime_receiver );
1475
1455
1476
- // Lookup index for the ivar the instruction loads
1477
- if (iv_index_tbl && rb_iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
1478
- uint32_t ivar_index = ent->index;
1479
-
1480
- val_type_t val_type = ctx_get_opnd_type(ctx, OPND_STACK(0));
1481
- x86opnd_t val_to_write = ctx_stack_opnd(ctx, 0);
1482
- mov(cb, REG1, val_to_write);
1483
-
1484
- // Bail if the value to write is a heap object, because this needs a write barrier
1485
- if (!val_type.is_imm) {
1486
- ADD_COMMENT(cb, "guard value is immediate");
1487
- test(cb, REG1, imm_opnd(RUBY_IMMEDIATE_MASK));
1488
- jz_ptr(cb, COUNTED_EXIT(side_exit, setivar_val_heapobject));
1489
- ctx_upgrade_opnd_type(ctx, OPND_STACK(0), TYPE_IMM);
1490
- }
1491
-
1492
- // Pop the value to write
1493
- ctx_stack_pop(ctx, 1);
1494
-
1495
- // Bail if this object is frozen
1496
- ADD_COMMENT(cb, "guard self is not frozen");
1497
- x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
1498
- test(cb, flags_opnd, imm_opnd(RUBY_FL_FREEZE));
1499
- jnz_ptr(cb, COUNTED_EXIT(side_exit, setivar_frozen));
1500
-
1501
- // Pop receiver if it's on the temp stack
1502
- if (!reg0_opnd.is_self) {
1503
- (void)ctx_stack_pop(ctx, 1);
1504
- }
1456
+ // Make sure there is a mapping for this ivar in the index table
1457
+ if (!iv_index_tbl || !rb_iv_index_tbl_lookup (iv_index_tbl , id , & ent )) {
1458
+ rb_ivar_set (comptime_receiver , id , Qundef );
1459
+ iv_index_tbl = ROBJECT_IV_INDEX_TBL (comptime_receiver );
1460
+ RUBY_ASSERT (iv_index_tbl );
1461
+ // Redo the lookup
1462
+ RUBY_ASSERT_ALWAYS (rb_iv_index_tbl_lookup (iv_index_tbl , id , & ent ));
1463
+ }
1505
1464
1506
- // Compile time self is embedded and the ivar index lands within the object
1507
- if (RB_FL_TEST_RAW(comptime_receiver, ROBJECT_EMBED) && ivar_index < ROBJECT_EMBED_LEN_MAX) {
1508
- // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
1465
+ return ent -> index ;
1466
+ }
1509
1467
1510
- // Guard that self is embedded
1511
- // TODO: BT and JC is shorter
1512
- ADD_COMMENT(cb, "guard embedded setivar");
1513
- test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED));
1514
- jit_chain_guard(JCC_JZ, jit, &starting_context, max_chain_depth, side_exit);
1468
+ VALUE rb_vm_set_ivar_idx (VALUE obj , uint32_t idx , VALUE val );
1515
1469
1516
- // Store the ivar on the object
1517
- x86opnd_t ivar_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.ary) + ivar_index * SIZEOF_VALUE);
1518
- mov(cb, ivar_opnd, REG1);
1470
+ // Codegen for setting an instance variable.
1471
+ // Preconditions:
1472
+ // - receiver is in REG0
1473
+ // - receiver has the same class as CLASS_OF(comptime_receiver)
1474
+ // - no stack push or pops to ctx since the entry to the codegen of the instruction being compiled
1475
+ static codegen_status_t
1476
+ gen_set_ivar (jitstate_t * jit , ctx_t * ctx , VALUE recv , VALUE klass , ID ivar_name )
1477
+ {
1478
+ // Save the PC and SP because the callee may allocate
1479
+ // Note that this modifies REG_SP, which is why we do it first
1480
+ jit_prepare_routine_call (jit , ctx , REG0 );
1519
1481
1520
- // Push the ivar on the stack
1521
- // For attr_writer we'll need to push the value on the stack
1522
- //x86opnd_t out_opnd = ctx_stack_push(ctx, TYPE_UNKNOWN);
1523
- }
1524
- else {
1525
- // Compile time value is *not* embeded.
1526
-
1527
- // Guard that value is *not* embedded
1528
- // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h
1529
- ADD_COMMENT(cb, "guard extended setivar");
1530
- x86opnd_t flags_opnd = member_opnd(REG0, struct RBasic, flags);
1531
- test(cb, flags_opnd, imm_opnd(ROBJECT_EMBED));
1532
- jit_chain_guard(JCC_JNZ, jit, &starting_context, max_chain_depth, side_exit);
1533
-
1534
- // check that the extended table is big enough
1535
- if (ivar_index >= ROBJECT_EMBED_LEN_MAX + 1) {
1536
- // Check that the slot is inside the extended table (num_slots > index)
1537
- ADD_COMMENT(cb, "check index in extended table");
1538
- x86opnd_t num_slots = mem_opnd(32, REG0, offsetof(struct RObject, as.heap.numiv));
1539
- cmp(cb, num_slots, imm_opnd(ivar_index));
1540
- jle_ptr(cb, COUNTED_EXIT(side_exit, setivar_idx_out_of_range));
1541
- }
1482
+ // Get the operands from the stack
1483
+ x86opnd_t val_opnd = ctx_stack_pop (ctx , 1 );
1484
+ x86opnd_t recv_opnd = ctx_stack_pop (ctx , 1 );
1542
1485
1543
- // Get a pointer to the extended table
1544
- x86opnd_t tbl_opnd = mem_opnd(64, REG0, offsetof(struct RObject, as.heap.ivptr));
1545
- mov(cb, REG0, tbl_opnd);
1486
+ uint32_t ivar_index = yjit_force_iv_index (recv , klass , ivar_name );
1546
1487
1547
- // Write the ivar to the extended table
1548
- x86opnd_t ivar_opnd = mem_opnd(64, REG0, sizeof(VALUE) * ivar_index);
1549
- mov(cb, ivar_opnd, REG1);
1550
- }
1488
+ // Call rb_vm_set_ivar_idx with the receiver, the index of the ivar, and the value
1489
+ mov (cb , C_ARG_REGS [0 ], recv_opnd );
1490
+ mov (cb , C_ARG_REGS [1 ], imm_opnd (ivar_index ));
1491
+ mov (cb , C_ARG_REGS [2 ], val_opnd );
1492
+ call_ptr (cb , REG0 , (void * )rb_vm_set_ivar_idx );
1551
1493
1552
- // Jump to next instruction. This allows guard chains to share the same successor.
1553
- jit_jump_to_next_insn(jit, ctx);
1554
- return YJIT_END_BLOCK;
1555
- }
1494
+ x86opnd_t out_opnd = ctx_stack_push (ctx , TYPE_UNKNOWN );
1495
+ mov (cb , out_opnd , RAX );
1556
1496
1557
- GEN_COUNTER_INC(cb, setivar_name_not_mapped);
1558
- return YJIT_CANT_COMPILE;
1497
+ return YJIT_KEEP_COMPILING ;
1559
1498
}
1560
- */
1561
1499
1562
1500
// Codegen for getting an instance variable.
1563
1501
// Preconditions:
@@ -1616,21 +1554,7 @@ gen_get_ivar(jitstate_t *jit, ctx_t *ctx, const int max_chain_depth, VALUE compt
1616
1554
jit_chain_guard(JCC_JNE, jit, &starting_context, max_chain_depth, side_exit);
1617
1555
*/
1618
1556
1619
- // ID for the name of the ivar
1620
- ID id = ivar_name ;
1621
- struct rb_iv_index_tbl_entry * ent ;
1622
- struct st_table * iv_index_tbl = ROBJECT_IV_INDEX_TBL (comptime_receiver );
1623
-
1624
- // Make sure there is a mapping for this ivar in the index table
1625
- if (!iv_index_tbl || !rb_iv_index_tbl_lookup (iv_index_tbl , id , & ent )) {
1626
- rb_ivar_set (comptime_receiver , id , Qundef );
1627
- iv_index_tbl = ROBJECT_IV_INDEX_TBL (comptime_receiver );
1628
- RUBY_ASSERT (iv_index_tbl );
1629
- // Redo the lookup
1630
- RUBY_ASSERT_ALWAYS (rb_iv_index_tbl_lookup (iv_index_tbl , id , & ent ));
1631
- }
1632
-
1633
- uint32_t ivar_index = ent -> index ;
1557
+ uint32_t ivar_index = yjit_force_iv_index (comptime_receiver , CLASS_OF (comptime_receiver ), ivar_name );
1634
1558
1635
1559
// Pop receiver if it's on the temp stack
1636
1560
if (!reg0_opnd .is_self ) {
@@ -3564,7 +3488,13 @@ gen_send_general(jitstate_t *jit, ctx_t *ctx, struct rb_call_data *cd, rb_iseq_t
3564
3488
}
3565
3489
case VM_METHOD_TYPE_ATTRSET :
3566
3490
GEN_COUNTER_INC (cb , send_ivar_set_method );
3567
- return YJIT_CANT_COMPILE ;
3491
+
3492
+ if (argc != 1 || !RB_TYPE_P (comptime_recv , T_OBJECT )) {
3493
+ return YJIT_CANT_COMPILE ;
3494
+ } else {
3495
+ ID ivar_name = cme -> def -> body .attr .id ;
3496
+ return gen_set_ivar (jit , ctx , comptime_recv , comptime_recv_klass , ivar_name );
3497
+ }
3568
3498
case VM_METHOD_TYPE_BMETHOD :
3569
3499
GEN_COUNTER_INC (cb , send_bmethod );
3570
3500
return YJIT_CANT_COMPILE ;
0 commit comments