I'm working on an implementation of the RubyVM and I've searched all over for some documentation on the opcodes, but to no avail.
If anyone knows specifically how the putspecialobject
opcode works, or even just a link to some fullish documentation I'd much appreciate it!
From insns.def:
DEFINE_INSN putspecialobject (rb_num_t value_type) () (VALUE val) { switch (value_type) { case VM_SPECIAL_OBJECT_VMCORE: val = rb_mRubyVMFrozenCore; break; case VM_SPECIAL_OBJECT_CBASE: val = vm_get_cbase(GET_ISEQ(), GET_LFP(), GET_DFP()); break; default: rb_bug("putspecialobject insn: unknown value_type"); } }
where:
VM_SPECIAL_OBJECT_VMCORE = 1 VM_SPECIAL_OBJECT_CBASE = 2
In other words, if the argument is 1, rb_mRubyVMFrozenCore
is pushed on the stack, which is an object created early in VM startup that implements some language features as methods:
set_method_alias(klass,:new,:old) alias new old set_variable_alias(:$new,:$old) alias $new $old undef_method(klass,:foo) undef foo define_method(klass,:foo,&block) def foo ... end define_singleton_method(obj,:foo,&block) def obj.foo ... end set_postexe(&block) END { ... }
If the argument is 2, the class/module for the current class context is pushed on the stack. That's the lexical scope in which constants are resolved and def
and alias
take effect. It's also the class passed as 'klass' to the methods above.
So
def foo ... end
compiles to this:
[:putspecialobject, 1], [:putspecialobject, 2], [:putobject, :foo], [:putiseq, [...]], [:send, :"core#define_method", 3, nil, 0, nil]
This is as much as I could reverse engineer, which isn't easy with this code.