Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

better ivar slot system for RubyObject + misc fixes/cleanup

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@4119 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
commit 8c550867fe0cab089862df65070282a4983bd1ea 1 parent c3ef296
Laurent Sansonetti authored
View
17 class.c
@@ -21,6 +21,7 @@
#include "class.h"
extern st_table *rb_class_tbl;
+extern VALUE rb_cRubyObject;
void
rb_objc_class_sync_version(Class ocklass, Class ocsuper)
@@ -28,11 +29,7 @@ rb_objc_class_sync_version(Class ocklass, Class ocsuper)
const long super_version = RCLASS_VERSION(ocsuper);
long klass_version = RCLASS_VERSION(ocklass);
- if ((super_version & RCLASS_NO_IV_SLOTS) == RCLASS_NO_IV_SLOTS) {
- klass_version |= RCLASS_NO_IV_SLOTS;
- }
-
- if (ocsuper == (Class)rb_cObject
+ if (ocsuper == (Class)rb_cRubyObject
|| (super_version & RCLASS_IS_OBJECT_SUBCLASS)
== RCLASS_IS_OBJECT_SUBCLASS) {
klass_version |= RCLASS_IS_OBJECT_SUBCLASS;
@@ -139,8 +136,6 @@ rb_define_object_special_methods(VALUE klass)
(IMP)rb_obj_imp_copyWithZone, method_getTypeEncoding(m));
}
-extern VALUE rb_cRubyObject;
-
static VALUE
rb_objc_alloc_class(const char *name, VALUE super, VALUE flags, VALUE klass)
{
@@ -349,7 +344,7 @@ rb_singleton_class_clone(VALUE obj)
}
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
- if (RCLASS_SUPER(clone) == rb_cNSObject) {
+ if (RCLASS_SUPER(clone) == rb_cRubyObject) {
long v = RCLASS_VERSION(clone) ^ RCLASS_IS_OBJECT_SUBCLASS;
RCLASS_SET_VERSION(clone, v);
}
@@ -376,7 +371,7 @@ rb_make_singleton_class(VALUE super)
{
VALUE klass = rb_objc_create_class(NULL, super);
long v = RCLASS_VERSION(klass);
- if (super == rb_cNSObject) {
+ if (super == rb_cRubyObject) {
v ^= RCLASS_IS_OBJECT_SUBCLASS;
}
v |= RCLASS_IS_RUBY_CLASS;
@@ -1320,10 +1315,6 @@ rb_objc_type(VALUE obj)
type = T_SYMBOL;
goto done;
}
- if (k == (Class)rb_cFixnum) {
- type = T_FIXNUM;
- goto done;
- }
if ((type = foundation_type(k)) != 0) {
goto done;
}
View
3  class.h
@@ -11,7 +11,7 @@
extern "C" {
#endif
-#define RCLASS_IS_OBJECT_SUBCLASS (1<<1) /* class is a true RBObject subclass */
+#define RCLASS_IS_OBJECT_SUBCLASS (1<<1) /* class is a true RubyObject subclass */
#define RCLASS_IS_RUBY_CLASS (1<<2) /* class was created from Ruby */
#define RCLASS_IS_MODULE (1<<3) /* class represents a Ruby Module */
#define RCLASS_IS_SINGLETON (1<<4) /* class represents a singleton */
@@ -23,7 +23,6 @@ extern "C" {
#define RCLASS_SCOPE_PROTECTED (1<<13) /* class opened for protected methods */
#define RCLASS_SCOPE_MOD_FUNC (1<<14) /* class opened for module_function methods */
#define RCLASS_KVO_CHECK_DONE (1<<15) /* class created by KVO and flags merged */
-#define RCLASS_NO_IV_SLOTS (1<<16) /* class cannot hold ivar slots (T_DATA & friends) */
unsigned long rb_class_get_flags(Class k);
void rb_class_set_flags(Class k, unsigned long flags);
View
209 compiler.cpp
@@ -1112,64 +1112,57 @@ RoxorCompiler::compile_binding(void)
"", bb);
}
-Value *
-RoxorCompiler::gen_slot_cache(ID id)
-{
- int *slot = (int *)malloc(sizeof(int));
- *slot = -1;
- return compile_const_pointer(slot, Int32PtrTy);
-}
-
-Value *
-RoxorAOTCompiler::gen_slot_cache(ID id)
+extern "C"
+struct icache *
+rb_vm_ivar_slot_allocate(void)
{
- GlobalVariable *gvar = new GlobalVariable(*RoxorCompiler::module,
- Int32PtrTy, false, GlobalValue::InternalLinkage,
- Constant::getNullValue(Int32PtrTy), "");
- ivar_slots.push_back(gvar);
- return new LoadInst(gvar, "");
+ struct icache *icache = (struct icache *)malloc(sizeof(struct icache));
+ icache->klass = 0;
+ icache->slot = SLOT_CACHE_VIRGIN;
+ return icache;
}
Value *
RoxorCompiler::compile_slot_cache(ID id)
{
- if (inside_eval || current_block || !current_instance_method
- || current_module) {
- return compile_const_pointer(NULL, Int32PtrTy);
- }
-
- std::map<ID, Value *>::iterator iter = ivar_slots_cache.find(id);
- Value *slot;
- if (iter == ivar_slots_cache.end()) {
-#if ROXOR_COMPILER_DEBUG
- printf("allocating a new slot for ivar %s\n", rb_id2name(id));
-#endif
- slot = gen_slot_cache(id);
- ivar_slots_cache[id] = slot;
+ std::map<ID, void *>::iterator iter = ivars_slots_cache.find(id);
+ void *cache = NULL;
+ if (iter == ivars_slots_cache.end()) {
+ cache = rb_vm_ivar_slot_allocate();
+ ivars_slots_cache[id] = cache;
}
else {
- slot = iter->second;
+ cache = iter->second;
}
+ return compile_const_pointer(cache);
+}
- Instruction *slot_insn = dyn_cast<Instruction>(slot);
- if (slot_insn != NULL) {
- Instruction *insn = slot_insn->clone();
- BasicBlock::InstListType &list = bb->getInstList();
- list.insert(list.end(), insn);
- return insn;
+Value *
+RoxorAOTCompiler::compile_slot_cache(ID id)
+{
+ std::map<ID, void *>::iterator iter = ivars_slots_cache.find(id);
+ GlobalVariable *gvar = NULL;
+ if (iter == ivars_slots_cache.end()) {
+ gvar = new GlobalVariable(*RoxorCompiler::module,
+ PtrTy, false, GlobalValue::InternalLinkage,
+ compile_const_pointer(NULL), "");
+ ivar_slots.push_back(gvar);
+ ivars_slots_cache[id] = gvar;
}
else {
- return slot;
+ gvar = (GlobalVariable *)iter->second;
}
+ return new LoadInst(gvar, "", bb);
}
Value *
RoxorCompiler::compile_ivar_read(ID vid)
{
if (getIvarFunc == NULL) {
- // VALUE rb_vm_ivar_get(VALUE obj, ID name, int *slot_cache);
- getIvarFunc = cast<Function>(module->getOrInsertFunction("rb_vm_ivar_get",
- RubyObjTy, RubyObjTy, IntTy, Int32PtrTy, NULL));
+ // VALUE rb_vm_ivar_get(VALUE obj, ID name, struct icache *cache);
+ getIvarFunc = cast<Function>(module->getOrInsertFunction(
+ "rb_vm_ivar_get",
+ RubyObjTy, RubyObjTy, IntTy, PtrTy, NULL));
}
std::vector<Value *> params;
@@ -1185,11 +1178,11 @@ Value *
RoxorCompiler::compile_ivar_assignment(ID vid, Value *val)
{
if (setIvarFunc == NULL) {
- // void rb_vm_ivar_set(VALUE obj, ID name, VALUE val, int *slot_cache);
+ // void rb_vm_ivar_set(VALUE obj, ID name, VALUE val,
+ // struct icache *cache);
setIvarFunc =
cast<Function>(module->getOrInsertFunction("rb_vm_ivar_set",
- VoidTy, RubyObjTy, IntTy, RubyObjTy, Int32PtrTy,
- NULL));
+ VoidTy, RubyObjTy, IntTy, RubyObjTy, PtrTy, NULL));
}
std::vector<Value *> params;
@@ -3000,57 +2993,6 @@ RoxorCompiler::compile_set_current_scope(Value *klass, Value *scope)
}
void
-RoxorCompiler::compile_ivar_slots(Value *klass,
- BasicBlock::InstListType &list,
- BasicBlock::InstListType::iterator list_iter)
-{
- if (ivar_slots_cache.size() > 0) {
- if (prepareIvarSlotFunc == NULL) {
- // void rb_vm_prepare_class_ivar_slot(VALUE klass, ID name,
- // int *slot_cache);
- prepareIvarSlotFunc = cast<Function>(
- module->getOrInsertFunction(
- "rb_vm_prepare_class_ivar_slot",
- VoidTy, RubyObjTy, IntTy, Int32PtrTy, NULL));
- }
- for (std::map<ID, Value *>::iterator iter
- = ivar_slots_cache.begin();
- iter != ivar_slots_cache.end();
- ++iter) {
-
- ID ivar_name = iter->first;
- Value *ivar_slot = iter->second;
- std::vector<Value *> params;
-
- params.push_back(klass);
-
- Value *id_val = compile_id(ivar_name);
- if (Instruction::classof(id_val)) {
- Instruction *insn = cast<Instruction>(id_val);
- insn->removeFromParent();
- list.insert(list_iter, insn);
- }
- params.push_back(id_val);
-
- Instruction *slot_insn = dyn_cast<Instruction>(ivar_slot);
- if (slot_insn != NULL) {
- Instruction *insn = slot_insn->clone();
- list.insert(list_iter, insn);
- params.push_back(insn);
- }
- else {
- params.push_back(ivar_slot);
- }
-
- CallInst *call = CallInst::Create(prepareIvarSlotFunc,
- params.begin(), params.end(), "");
-
- list.insert(list_iter, call);
- }
- }
-}
-
-void
RoxorCompiler::compile_node_error(const char *msg, NODE *node)
{
int t = nd_type(node);
@@ -4115,10 +4057,6 @@ RoxorCompiler::compile_node(NODE *node)
current_block_chain = false;
dynamic_class = false;
- std::map<ID, Value *> old_ivar_slots_cache
- = ivar_slots_cache;
- ivar_slots_cache.clear();
-
new StoreInst(classVal, current_opened_class, bb);
current_module = nd_type(node) == NODE_MODULE;
@@ -4128,6 +4066,10 @@ RoxorCompiler::compile_node(NODE *node)
bool old_block_declaration = block_declaration;
block_declaration = false;
+ std::map<ID, void *> old_ivars_slots_cache
+ = ivars_slots_cache;
+ old_ivars_slots_cache.clear();
+
DEBUG_LEVEL_INC();
Value *val = compile_node(body);
assert(Function::classof(val));
@@ -4135,6 +4077,8 @@ RoxorCompiler::compile_node(NODE *node)
GET_CORE()->optimize(f);
DEBUG_LEVEL_DEC();
+ ivars_slots_cache = old_ivars_slots_cache;
+
block_declaration = old_block_declaration;
std::vector<Value *> params;
@@ -4147,16 +4091,11 @@ RoxorCompiler::compile_node(NODE *node)
dynamic_class = old_dynamic_class;
compile_set_current_scope(classVal, defaultScope);
- BasicBlock::InstListType &list = bb->getInstList();
- compile_ivar_slots(classVal, list, list.end());
-
current_self = old_self;
current_opened_class = old_class;
current_module = old_current_module;
current_block_chain = old_current_block_chain;
- ivar_slots_cache = old_ivar_slots_cache;
-
return val;
}
}
@@ -5575,15 +5514,7 @@ RoxorCompiler::compile_main_function(NODE *node)
Value *val = compile_node(node);
assert(Function::classof(val));
- Function *function = cast<Function>(val);
-
- Value *klass = ConstantInt::get(RubyObjTy, (long)rb_cTopLevel);
- BasicBlock::InstListType &list =
- function->getEntryBlock().getInstList();
- compile_ivar_slots(klass, list, list.begin());
- ivar_slots_cache.clear();
-
- return function;
+ return cast<Function>(val);
}
Function *
@@ -5979,33 +5910,11 @@ RoxorAOTCompiler::compile_main_function(NODE *node)
list.insert(list.begin(), load);
}
- // Compile ivar slots.
-
- if (!ivar_slots_cache.empty()) {
- GlobalVariable *toplevel = compile_const_global_string("TopLevel");
-
- std::vector<Value *> idxs;
- idxs.push_back(ConstantInt::get(Int32Ty, 0));
- idxs.push_back(ConstantInt::get(Int32Ty, 0));
- Instruction *load = GetElementPtrInst::Create(toplevel,
- idxs.begin(), idxs.end(), "");
-
- std::vector<Value *> params;
- params.push_back(load);
-
- Instruction *call = CallInst::Create(objcGetClassFunc, params.begin(),
- params.end(), "");
-
- compile_ivar_slots(call, list, list.begin());
- ivar_slots_cache.clear();
-
- list.insert(list.begin(), call);
- list.insert(list.begin(), load);
- }
+ // Instance variable slots.
Function *ivarSlotAlloc = cast<Function>(module->getOrInsertFunction(
"rb_vm_ivar_slot_allocate",
- Int32PtrTy, NULL));
+ PtrTy, NULL));
for (std::vector<GlobalVariable *>::iterator i = ivar_slots.begin();
i != ivar_slots.end();
@@ -6014,12 +5923,9 @@ RoxorAOTCompiler::compile_main_function(NODE *node)
GlobalVariable *gvar = *i;
Instruction *call = CallInst::Create(ivarSlotAlloc, "");
- Instruction *assign1 =
- new StoreInst(ConstantInt::getSigned(Int32Ty, -1), call, "");
- Instruction *assign2 = new StoreInst(call, gvar, "");
+ Instruction *assign = new StoreInst(call, gvar, "");
- list.insert(list.begin(), assign2);
- list.insert(list.begin(), assign1);
+ list.insert(list.begin(), assign);
list.insert(list.begin(), call);
}
@@ -6039,15 +5945,8 @@ RoxorCompiler::compile_read_attr(ID name)
bb = BasicBlock::Create(context, "EntryBlock", f);
- // This disables ivar slot generation.
- // TODO: make it work
- const bool old_current_instance_method = current_instance_method;
- current_instance_method = false;
-
Value *val = compile_ivar_read(name);
- current_instance_method = old_current_instance_method;
-
ReturnInst::Create(context, val, bb);
return f;
@@ -6066,19 +5965,21 @@ RoxorCompiler::compile_write_attr(ID name)
bb = BasicBlock::Create(context, "EntryBlock", f);
- std::vector<Value *> params;
- params.push_back(current_self);
- params.push_back(compile_id(name));
- params.push_back(new_val);
-
if (setKVOIvarFunc == NULL) {
setKVOIvarFunc =
cast<Function>(module->getOrInsertFunction("rb_vm_set_kvo_ivar",
- RubyObjTy, RubyObjTy, RubyObjTy, RubyObjTy, NULL));
+ RubyObjTy, RubyObjTy, RubyObjTy, RubyObjTy, Int32PtrTy,
+ NULL));
}
+ std::vector<Value *> params;
+ params.push_back(current_self);
+ params.push_back(compile_id(name));
+ params.push_back(new_val);
+ params.push_back(compile_slot_cache(name));
+
Value *val = CallInst::Create(setKVOIvarFunc,
- params.begin(), params.end(), "", bb);
+ params.begin(), params.end(), "", bb);
ReturnInst::Create(context, val, bb);
View
8 compiler.h
@@ -78,7 +78,7 @@ class RoxorCompiler {
std::map<ID, Value *> lvars;
std::vector<ID> dvars;
- std::map<ID, Value *> ivar_slots_cache;
+ std::map<ID, void *> ivars_slots_cache;
std::map<std::string, GlobalVariable *> static_strings;
std::map<CFHashCode, GlobalVariable *> static_ustrings;
@@ -358,8 +358,7 @@ class RoxorCompiler {
const Type *llvm_type, Value *val);
void compile_debug_trap(void);
- Value *compile_slot_cache(ID id);
- virtual Value *gen_slot_cache(ID id);
+ virtual Value *compile_slot_cache(ID id);
ICmpInst *is_value_a_fixnum(Value *val);
void compile_ivar_slots(Value *klass, BasicBlock::InstListType &list,
BasicBlock::InstListType::iterator iter);
@@ -413,8 +412,7 @@ class RoxorAOTCompiler : public RoxorCompiler {
Value *compile_id(ID id);
Value *compile_immutable_literal(VALUE val);
Value *compile_global_entry(NODE *node);
-
- Value *gen_slot_cache(ID id);
+ Value *compile_slot_cache(ID id);
Constant *
compile_const_pointer(void *ptr, const PointerType *type=NULL) {
View
2  dispatcher.cpp
@@ -670,7 +670,7 @@ __rb_vm_dispatch(RoxorVM *vm, struct mcache *cache, VALUE top, VALUE self,
// Enable helpers for classes which are not RubyObject based.
if ((RCLASS_VERSION(klass) & RCLASS_IS_OBJECT_SUBCLASS)
- != RCLASS_IS_OBJECT_SUBCLASS) {
+ != RCLASS_IS_OBJECT_SUBCLASS) {
// Let's try to see if we are not given a helper selector.
SEL new_sel = helper_sel(selname, selname_len);
if (new_sel != NULL) {
View
1  objc.h
@@ -21,7 +21,6 @@ bool rb_objc_get_types(VALUE recv, Class klass, SEL sel, Method m,
bool rb_objc_supports_forwarding(VALUE recv, SEL sel);
void rb_objc_define_kvo_setter(VALUE klass, ID mid);
-VALUE rb_vm_set_kvo_ivar(VALUE obj, ID name, VALUE val);
static inline IMP
rb_objc_install_method(Class klass, SEL sel, IMP imp)
View
14 objc.m
@@ -538,17 +538,19 @@ - (VMURange)addressRange;
}
VALUE
-rb_vm_set_kvo_ivar(VALUE obj, ID name, VALUE val)
+rb_vm_set_kvo_ivar(VALUE obj, ID name, VALUE val, void *cache)
{
- NSString *key = NULL;
if (enable_kvo_notifications) {
- key = [(NSString *)rb_id2str(name) substringFromIndex:1]; // skip '@' prefix
+ NSString *key = [(NSString *)rb_id2str(name) substringFromIndex:1]; // skip '@' prefix
[(id)obj willChangeValueForKey:key];
- }
- rb_ivar_set(obj, name, val);
- if (enable_kvo_notifications) {
+
+ rb_vm_ivar_set(obj, name, val, cache);
+
[(id)obj didChangeValueForKey:key];
}
+ else {
+ rb_vm_ivar_set(obj, name, val, cache);
+ }
return val;
}
View
44 object.c
@@ -196,23 +196,16 @@ init_copy(VALUE dest, VALUE obj)
rb_gc_copy_finalizer(dest, obj);
switch (TYPE(obj)) {
case T_OBJECT:
- if (ROBJECT(obj)->tbl != NULL) {
- CFMutableDictionaryRef new_tbl;
- new_tbl = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)ROBJECT(obj)->tbl);
- assert(new_tbl != NULL);
- GC_WB(&ROBJECT(dest)->tbl, new_tbl);
- CFMakeCollectable(new_tbl);
- }
- else {
- ROBJECT(dest)->tbl = NULL;
- }
if (ROBJECT(obj)->num_slots > 0) {
if (ROBJECT(dest)->num_slots < ROBJECT(obj)->num_slots) {
rb_vm_regrow_robject_slots(ROBJECT(dest),
ROBJECT(obj)->num_slots);
}
for (int i = 0; i < ROBJECT(obj)->num_slots; i++) {
- GC_WB(&ROBJECT(dest)->slots[i], ROBJECT(obj)->slots[i]);
+ rb_object_ivar_slot_t *dest_sl = &ROBJECT(dest)->slots[i];
+ rb_object_ivar_slot_t *orig_sl = &ROBJECT(obj)->slots[i];
+ dest_sl->name = orig_sl->name;
+ GC_WB(&dest_sl->value, orig_sl->value);
}
}
ROBJECT(dest)->num_slots = ROBJECT(obj)->num_slots;
@@ -293,8 +286,9 @@ rb_obj_clone_imp(VALUE obj, SEL sel)
}
init_copy(clone, obj);
- if (OBJ_FROZEN(obj))
+ if (OBJ_FROZEN(obj)) {
OBJ_FREEZE(clone);
+ }
return clone;
}
@@ -464,26 +458,14 @@ static VALUE
rb_obj_inspect(VALUE obj, SEL sel)
{
if (TYPE(obj) == T_OBJECT) {
- bool has_ivar = false;
-
- if (ROBJECT(obj)->tbl != NULL
- && CFDictionaryGetCount(ROBJECT(obj)->tbl) > 0) {
- has_ivar = true;
- }
- else {
- for (int i = 0; i < ROBJECT(obj)->num_slots; i++) {
- if (ROBJECT(obj)->slots[i] != Qundef) {
- has_ivar = true;
- break;
- }
+ for (int i = 0; i < ROBJECT(obj)->num_slots; i++) {
+ if (ROBJECT(obj)->slots[i].value != Qundef) {
+ // There is at least an ivar.
+ const char *c = rb_obj_classname(obj);
+ VALUE str = rb_sprintf("#<%s:%p", c, (void*)obj);
+ return rb_exec_recursive(inspect_obj, obj, str);
}
}
-
- if (has_ivar) {
- const char *c = rb_obj_classname(obj);
- VALUE str = rb_sprintf("#<%s:%p", c, (void*)obj);
- return rb_exec_recursive(inspect_obj, obj, str);
- }
}
return rb_funcall(obj, rb_intern("to_s"), 0, 0);
}
@@ -2960,10 +2942,8 @@ Init_Object(void)
"BasicObject", 0);
rb_const_set(rb_cObject, rb_intern("BasicObject"), rb_cBasicObject);
rb_cModule = boot_defclass("Module", rb_cNSObject);
- RCLASS_SET_VERSION_FLAG(rb_cModule, RCLASS_NO_IV_SLOTS);
rb_define_object_special_methods(rb_cModule);
rb_cClass = boot_defclass("Class", rb_cModule);
- RCLASS_SET_VERSION_FLAG(rb_cClass, RCLASS_NO_IV_SLOTS);
rb_cRubyObject = boot_defclass("RubyObject", rb_cObject);
RCLASS_SET_VERSION_FLAG(rb_cRubyObject, RCLASS_IS_SINGLETON);
RCLASS_SET_VERSION_FLAG(rb_cRubyObject, RCLASS_IS_OBJECT_SUBCLASS);
View
1  parse.y
@@ -10085,7 +10085,6 @@ void
Init_ripper(void)
{
VALUE Ripper = rb_define_class("Ripper", rb_cObject);
- RCLASS_SET_VERSION_FLAG(Ripper, RCLASS_NO_IV_SLOTS);
rb_define_const(Ripper, "Version", rb_usascii_str_new2(RIPPER_VERSION));
rb_objc_define_method(*(VALUE *)Ripper, "alloc", ripper_s_allocate, 0);
rb_objc_define_method(Ripper, "initialize", ripper_initialize, -1);
View
127 variable.c
@@ -980,7 +980,7 @@ rb_class_ivar_dict(VALUE mod)
}
return generic_ivar_dict(mod, false);
}
-
+
void
rb_class_ivar_set_dict(VALUE mod, CFMutableDictionaryRef dict)
{
@@ -1018,31 +1018,16 @@ ivar_get(VALUE obj, ID id, bool warn, bool undef)
{
VALUE val;
- const int slot = rb_vm_find_class_ivar_slot(CLASS_OF(obj), id);
- if (slot != -1) {
- val = rb_vm_get_ivar_from_slot(obj, slot);
- if (val != Qundef) {
- return val;
- }
- }
-
switch (TYPE(obj)) {
case T_OBJECT:
{
- val = Qundef;
-
- if (ROBJECT(obj)->tbl != NULL) {
- if (!CFDictionaryGetValueIfPresent(
- (CFDictionaryRef)ROBJECT(obj)->tbl,
- (const void *)id,
- (const void **)&val)) {
- val = Qundef;
+ const int slot = rb_vm_get_ivar_slot(obj, id, false);
+ if (slot != -1) {
+ val = rb_vm_get_ivar_from_slot(obj, slot);
+ if (val != Qundef) {
+ return val;
}
}
-
- if (val != Qundef) {
- return val;
- }
}
break;
@@ -1090,27 +1075,13 @@ rb_ivar_set(VALUE obj, ID id, VALUE val)
rb_error_frozen("object");
}
- const int slot = rb_vm_find_class_ivar_slot(CLASS_OF(obj), id);
- if (slot != -1) {
- rb_vm_set_ivar_from_slot(obj, val, slot);
- return val;
- }
-
switch (TYPE(obj)) {
case T_OBJECT:
{
- if (ROBJECT(obj)->tbl == NULL) {
- CFMutableDictionaryRef tbl;
-
- tbl = CFDictionaryCreateMutable(NULL, 0, NULL,
- &rb_cfdictionary_value_cb);
-
- GC_WB(&ROBJECT(obj)->tbl, tbl);
- CFMakeCollectable(tbl);
- }
-
- CFDictionarySetValue(ROBJECT(obj)->tbl,
- (const void *)id, (const void *)val);
+ const int slot = rb_vm_get_ivar_slot(obj, id, true);
+ assert(slot >= 0);
+ rb_vm_set_ivar_from_slot(obj, val, slot);
+ return val;
}
break;
@@ -1133,31 +1104,15 @@ rb_ivar_set(VALUE obj, ID id, VALUE val)
VALUE
rb_ivar_defined(VALUE obj, ID id)
{
- VALUE val;
-
- const int slot = rb_vm_find_class_ivar_slot(CLASS_OF(obj), id);
- if (slot != -1) {
- if (rb_vm_get_ivar_from_slot(obj, slot) != Qundef) {
- return Qtrue;
- }
- }
-
switch (TYPE(obj)) {
case T_OBJECT:
{
- val = Qundef;
-
- if (ROBJECT(obj)->tbl != NULL) {
- if (CFDictionaryGetValueIfPresent(
- (CFDictionaryRef)ROBJECT(obj)->tbl,
- (const void *)id, NULL)) {
- val = Qtrue;
+ const int slot = rb_vm_get_ivar_slot(obj, id, false);
+ if (slot != -1) {
+ if (rb_vm_get_ivar_from_slot(obj, slot) != Qundef) {
+ return Qtrue;
}
}
-
- if (val != Qundef) {
- return Qtrue;
- }
}
break;
@@ -1182,33 +1137,36 @@ void
rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
{
switch (TYPE(obj)) {
- case T_OBJECT:
- rb_vm_each_ivar_slot(obj, func, (void *)arg);
- if (ROBJECT(obj)->tbl != NULL) {
- CFDictionaryApplyFunction(ROBJECT(obj)->tbl,
- (CFDictionaryApplierFunction)func, (void *)arg);
- }
- return;
+ case T_OBJECT:
+ for (unsigned int i = 0; i < ROBJECT(obj)->num_slots; i++) {
+ ID name = ROBJECT(obj)->slots[i].name;
+ VALUE value = ROBJECT(obj)->slots[i].value;
+ if (name != 0 && value != Qundef) {
+ func(name, value, arg);
+ }
+ }
+ break;
case T_CLASS:
case T_MODULE:
- {
- CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(obj);
- if (iv_dict != NULL) {
- ivar_dict_foreach(iv_dict, func, arg);
- }
- }
- return;
+ {
+ CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(obj);
+ if (iv_dict != NULL) {
+ ivar_dict_foreach(iv_dict, func, arg);
+ }
+ }
+ break;
case T_NATIVE:
default:
- {
- CFDictionaryRef obj_dict = generic_ivar_dict(obj, false);
- if (obj_dict != NULL) {
- CFDictionaryApplyFunction(obj_dict, (CFDictionaryApplierFunction)func,
- (void *)arg);
- }
- }
+ {
+ CFDictionaryRef obj_dict = generic_ivar_dict(obj, false);
+ if (obj_dict != NULL) {
+ CFDictionaryApplyFunction(obj_dict,
+ (CFDictionaryApplierFunction)func, (void *)arg);
+ }
+ }
+ break;
}
}
@@ -1288,14 +1246,7 @@ rb_obj_remove_instance_variable(VALUE obj, SEL sel, VALUE name)
switch (TYPE(obj)) {
case T_OBJECT:
- // TODO support slots
- if (ROBJECT(obj)->tbl != NULL) {
- if (CFDictionaryGetValueIfPresent(ROBJECT(obj)->tbl, (const void *)id, (const void **)val)) {
- CFDictionaryRemoveValue(ROBJECT(obj)->tbl,
- (const void *)id);
- return val;
- }
- }
+ // TODO
break;
case T_CLASS:
View
217 vm.cpp
@@ -1044,76 +1044,6 @@ RoxorCore::const_defined(ID path)
}
}
-inline int
-RoxorCore::find_ivar_slot(VALUE klass, ID name, bool create)
-{
- VALUE k = klass;
- int slot = 0;
-
- while (k != 0) {
- std::map <ID, int> *slots = get_ivar_slots((Class)k);
- std::map <ID, int>::iterator iter = slots->find(name);
- if (iter != slots->end()) {
-#if ROXOR_VM_DEBUG
- printf("prepare ivar %s slot as %d (already prepared in class %s)\n",
- rb_id2name(name), iter->second, class_getName((Class)k));
-#endif
- return iter->second;
- }
- slot += slots->size();
- k = RCLASS_SUPER(k);
- }
-
- if (create) {
-#if ROXOR_VM_DEBUG
- printf("prepare ivar %s slot as %d (new in class %s)\n",
- rb_id2name(name), slot, class_getName((Class)klass));
-#endif
- get_ivar_slots((Class)klass)->insert(std::pair<ID, int>(name, slot));
- return slot;
- }
- else {
- return -1;
- }
-}
-
-void
-RoxorCore::each_ivar_slot(VALUE obj, int (*func)(ANYARGS),
- void *ctx)
-{
- VALUE k = *(VALUE *)obj;
-
- while (k != 0) {
- std::map <ID, int> *slots = get_ivar_slots((Class)k, false);
- if (slots != NULL) {
- for (std::map <ID, int>::iterator iter = slots->begin();
- iter != slots->end();
- ++iter) {
- ID name = iter->first;
- int slot = iter->second;
- VALUE value = rb_vm_get_ivar_from_slot(obj, slot);
- if (value != Qundef) {
- func(name, value, ctx);
- }
- }
- }
- k = RCLASS_SUPER(k);
- }
-}
-
-inline bool
-RoxorCore::class_can_have_ivar_slots(VALUE klass)
-{
- const long klass_version = RCLASS_VERSION(klass);
- if ((klass_version & RCLASS_IS_RUBY_CLASS) != RCLASS_IS_RUBY_CLASS
- || (klass_version & RCLASS_IS_OBJECT_SUBCLASS)
- != RCLASS_IS_OBJECT_SUBCLASS
- || (klass_version & RCLASS_NO_IV_SLOTS) == RCLASS_NO_IV_SLOTS) {
- return false;
- }
- return true;
-}
-
extern "C"
bool
rb_vm_running(void)
@@ -1494,47 +1424,125 @@ rb_vm_define_class(ID path, VALUE outer, VALUE super, int flags,
return klass;
}
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+
extern "C"
-int *
-rb_vm_ivar_slot_allocate(void)
-{
- return (int *)malloc(sizeof(int));
+int
+rb_vm_get_ivar_slot(VALUE obj, ID name, bool create)
+{
+ if (TYPE(obj) == T_OBJECT) {
+ unsigned int i;
+ for (i = 0; i < ROBJECT(obj)->num_slots; i++) {
+ if (ROBJECT(obj)->slots[i].name == name) {
+ return i;
+ }
+ }
+ if (create) {
+ for (i = 0; i < ROBJECT(obj)->num_slots; i++) {
+ if (ROBJECT(obj)->slots[i].value == Qundef) {
+ ROBJECT(obj)->slots[i].name = name;
+ return i;
+ }
+ }
+ const int new_slot = ROBJECT(obj)->num_slots;
+ rb_vm_regrow_robject_slots(ROBJECT(obj), new_slot + 1);
+ ROBJECT(obj)->slots[new_slot].name = name;
+ return new_slot;
+ }
+ }
+ return -1;
}
extern "C"
VALUE
-rb_vm_ivar_get(VALUE obj, ID name, int *slot_cache)
+rb_vm_ivar_get(VALUE obj, ID name, struct icache *cache)
{
#if ROXOR_VM_DEBUG
- printf("get ivar <%s %p>.%s slot %d\n",
+ printf("get ivar <%s %p>.%s cache klass %p slot %d\n",
class_getName((Class)CLASS_OF(obj)), (void *)obj,
- rb_id2name(name), slot_cache == NULL ? -1 : *slot_cache);
+ rb_id2name(name), (void *)cache->klass, cache->slot);
#endif
- if (slot_cache == NULL || *slot_cache == -1) {
- return rb_ivar_get(obj, name);
+
+ VALUE klass = CLASS_OF(obj);
+ if (LIKELY(klass == cache->klass)) {
+use_slot:
+ VALUE val = Qundef;
+ if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) {
+ rb_object_ivar_slot_t *slot = &ROBJECT(obj)->slots[cache->slot];
+ if (slot->name == name) {
+ val = slot->value;
+ }
+ else {
+ goto recache;
+ }
+ }
+ return val == Qundef ? Qnil : val;
}
else {
- VALUE val = rb_vm_get_ivar_from_slot(obj, *slot_cache);
- return val == Qundef ? Qnil : val;
+ goto recache;
}
+
+ if (cache->slot == SLOT_CACHE_VIRGIN) {
+recache:
+ const int slot = rb_vm_get_ivar_slot(obj, name, true);
+ if (slot >= 0) {
+ cache->klass = klass;
+ cache->slot = slot;
+ goto use_slot;
+ }
+ cache->klass = 0;
+ cache->slot = SLOT_CACHE_CANNOT;
+ }
+
+ assert(cache->slot == SLOT_CACHE_CANNOT);
+ return rb_ivar_get(obj, name);
}
extern "C"
void
-rb_vm_ivar_set(VALUE obj, ID name, VALUE val, int *slot_cache)
+rb_vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache_ptr)
{
+ struct icache *cache = (struct icache *)cache_ptr;
+
#if ROXOR_VM_DEBUG
- printf("set ivar %p.%s slot %d new_val %p\n", (void *)obj,
- rb_id2name(name),
- slot_cache == NULL ? -1 : *slot_cache,
- (void *)val);
+ printf("set ivar <%s %p>.%s cache klass %p slot %d val %p\n",
+ class_getName((Class)CLASS_OF(obj)), (void *)obj,
+ rb_id2name(name), (void *)cache->klass, cache->slot, (void *)val);
#endif
- if (slot_cache == NULL || *slot_cache == -1) {
- rb_ivar_set(obj, name, val);
+
+ VALUE klass = CLASS_OF(obj);
+ if (LIKELY(klass == cache->klass)) {
+use_slot:
+ if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) {
+ rb_object_ivar_slot_t *slot = &ROBJECT(obj)->slots[cache->slot];
+ if (slot->name == name) {
+ if ((ROBJECT(obj)->basic.flags & FL_FREEZE) == FL_FREEZE) {
+ rb_error_frozen("object");
+ }
+ GC_WB(&slot->value, val);
+ return;
+ }
+ }
+ goto recache;
}
else {
- rb_vm_set_ivar_from_slot(obj, val, *slot_cache);
+ goto recache;
}
+
+ if (cache->slot == SLOT_CACHE_VIRGIN) {
+recache:
+ const int slot = rb_vm_get_ivar_slot(obj, name, true);
+ if (slot >= 0) {
+ cache->klass = klass;
+ cache->slot = slot;
+ goto use_slot;
+ }
+ cache->slot = SLOT_CACHE_CANNOT;
+ }
+
+ assert(cache->slot == SLOT_CACHE_CANNOT);
+ rb_ivar_set(obj, name, val);
}
extern "C"
@@ -1777,37 +1785,6 @@ rb_vm_defined(VALUE self, int type, VALUE what, VALUE what2)
return str == NULL ? Qnil : rb_str_new2(str);
}
-extern "C"
-void
-rb_vm_prepare_class_ivar_slot(VALUE klass, ID name, int *slot_cache)
-{
- assert(slot_cache != NULL);
- assert(*slot_cache == -1);
-
- if (GET_CORE()->class_can_have_ivar_slots(klass)) {
- *slot_cache = GET_CORE()->find_ivar_slot(klass, name, true);
- }
-}
-
-extern "C"
-int
-rb_vm_find_class_ivar_slot(VALUE klass, ID name)
-{
- if (GET_CORE()->class_can_have_ivar_slots(klass)) {
- return GET_CORE()->find_ivar_slot(klass, name, false);
- }
- return -1;
-}
-
-extern "C"
-void
-rb_vm_each_ivar_slot(VALUE obj, int (*func)(ANYARGS), void *ctx)
-{
- if (GET_CORE()->class_can_have_ivar_slots(CLASS_OF(obj))) {
- GET_CORE()->each_ivar_slot(obj, func, ctx);
- }
-}
-
static bool
kvo_sel(Class klass, const char *selname, const size_t selsize,
const char *begin, const char *end)
View
122 vm.h
@@ -13,15 +13,6 @@
extern "C" {
#endif
-typedef struct rb_object {
- struct RBasic basic;
- CFMutableDictionaryRef tbl; /* dynamic ivars (runtime) */
- unsigned int num_slots;
- VALUE *slots; /* static ivars (compilation) */
-} rb_object_t;
-
-#define ROBJECT(o) ((rb_object_t *)o)
-
typedef struct {
short min; // min number of args that we accept
short max; // max number of args that we accept (-1 if rest)
@@ -338,48 +329,79 @@ bool rb_vm_respond_to2(VALUE obj, VALUE klass, SEL sel, bool priv, bool check_ov
VALUE rb_vm_method_missing(VALUE obj, int argc, const VALUE *argv);
void rb_vm_push_methods(VALUE ary, VALUE mod, bool include_objc_methods,
int (*filter) (VALUE, ID, VALUE));
-int rb_vm_find_class_ivar_slot(VALUE klass, ID name);
-void rb_vm_each_ivar_slot(VALUE obj, int (*func)(ANYARGS), void *ctx);
+void rb_vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache);
void rb_vm_set_outer(VALUE klass, VALUE under);
VALUE rb_vm_get_outer(VALUE klass);
VALUE rb_vm_catch(VALUE tag);
VALUE rb_vm_throw(VALUE tag, VALUE value);
+typedef struct {
+ ID name;
+ VALUE value;
+} rb_object_ivar_slot_t;
+
+#define SLOT_CACHE_VIRGIN -2
+#define SLOT_CACHE_CANNOT -1
+
+typedef struct {
+ struct RBasic basic;
+ rb_object_ivar_slot_t *slots;
+ unsigned int num_slots;
+} rb_object_t;
+
+#define ROBJECT(o) ((rb_object_t *)o)
+
static inline void
rb_vm_regrow_robject_slots(rb_object_t *obj, unsigned int new_num_slot)
{
- unsigned int i;
- VALUE *new_slots = (VALUE *)xrealloc(obj->slots,
- sizeof(VALUE) * (new_num_slot + 1));
+ rb_object_ivar_slot_t *new_slots =
+ (rb_object_ivar_slot_t *)xrealloc(obj->slots,
+ sizeof(rb_object_ivar_slot_t) * (new_num_slot + 1));
if (new_slots != obj->slots) {
GC_WB(&obj->slots, new_slots);
}
+
+ unsigned int i;
for (i = obj->num_slots; i <= new_num_slot; i++) {
- obj->slots[i] = Qundef;
+ obj->slots[i].name = 0;
+ obj->slots[i].value = Qundef;
}
obj->num_slots = new_num_slot + 1;
}
+int rb_vm_get_ivar_slot(VALUE obj, ID name, bool create);
+
static inline VALUE
rb_vm_get_ivar_from_slot(VALUE obj, int slot)
{
rb_object_t *robj = ROBJECT(obj);
- assert(slot >= 0);
- if ((unsigned int)slot >= robj->num_slots) {
- return Qnil;
- }
- return robj->slots[slot];
+ return robj->slots[slot].value;
}
static inline void
rb_vm_set_ivar_from_slot(VALUE obj, VALUE val, int slot)
{
rb_object_t *robj = ROBJECT(obj);
- assert(slot >= 0);
- if ((unsigned int)slot >= robj->num_slots) {
- rb_vm_regrow_robject_slots(robj, (unsigned int)slot);
+ GC_WB(&robj->slots[slot].value, val);
+}
+
+static inline VALUE
+rb_robject_allocate_instance(VALUE klass)
+{
+ const int num_slots = 10;
+
+ rb_object_t *obj = (rb_object_t *)rb_objc_newobj(sizeof(rb_object_t));
+ GC_WB(&obj->slots, xmalloc(sizeof(rb_object_ivar_slot_t) * num_slots));
+
+ OBJSETUP(obj, klass, T_OBJECT);
+ obj->num_slots = num_slots;
+
+ int i;
+ for (i = 0; i < num_slots; i++) {
+ obj->slots[i].name = 0;
+ obj->slots[i].value = Qundef;
}
- GC_WB(&robj->slots[slot], val);
+ return (VALUE)obj;
}
// Defined in proc.c
@@ -446,26 +468,6 @@ Class rb_vm_get_current_class(void);
bool rb_vm_aot_feature_load(const char *name);
-static inline VALUE
-rb_robject_allocate_instance(VALUE klass)
-{
- const int num_slots = 10;
-
- rb_object_t *obj = (rb_object_t *)rb_objc_newobj(sizeof(rb_object_t));
- GC_WB(&obj->slots, xmalloc_ptrs(num_slots * sizeof(VALUE)));
-
- OBJSETUP(obj, klass, T_OBJECT);
-
- ROBJECT(obj)->tbl = NULL;
- ROBJECT(obj)->num_slots = num_slots;
-
- int i;
- for (i = 0; i < num_slots; i++) {
- ROBJECT(obj)->slots[i] = Qundef;
- }
- return (VALUE)obj;
-}
-
void rb_vm_raise(VALUE exception);
void rb_vm_raise_current_exception(void);
VALUE rb_vm_current_exception(void);
@@ -525,6 +527,11 @@ void rb_vm_call_finalizer(rb_vm_finalizer_t *finalizer);
#include "bridgesupport.h"
+struct icache {
+ VALUE klass;
+ int slot;
+};
+
typedef struct {
Function *func;
rb_vm_arity_t arity;
@@ -532,12 +539,11 @@ typedef struct {
} rb_vm_method_source_t;
typedef VALUE rb_vm_objc_stub_t(IMP imp, id self, SEL sel, int argc,
- const VALUE *argv);
+ const VALUE *argv);
typedef VALUE rb_vm_c_stub_t(IMP imp, int argc, const VALUE *argv);
#define rb_vm_long_arity_stub_t rb_vm_objc_stub_t
typedef VALUE rb_vm_long_arity_bstub_t(IMP imp, id self, SEL sel,
- VALUE dvars, rb_vm_block_t *b,
- int argc, const VALUE *argv);
+ VALUE dvars, rb_vm_block_t *b, int argc, const VALUE *argv);
struct mcache {
#define MCACHE_RCALL 0x1 // Ruby call
@@ -636,9 +642,6 @@ class RoxorCore {
std::map<SEL, struct mcache *> mcache;
std::map<ID, struct ccache *> ccache;
- // Instance variable slots cache.
- std::map<Class, std::map<ID, int> *> ivar_slots;
-
// Optimized selectors redefinition cache.
std::map<SEL, GlobalVariable *> redefined_ops_gvars;
@@ -803,25 +806,6 @@ class RoxorCore {
struct ccache *constant_cache_get(ID path);
void const_defined(ID path);
- std::map<ID, int> *get_ivar_slots(Class klass, bool create=true) {
- std::map<Class, std::map<ID, int> *>::iterator iter =
- ivar_slots.find(klass);
- if (iter == ivar_slots.end()) {
- if (create) {
- std::map<ID, int> *map = new std::map<ID, int>;
- ivar_slots[klass] = map;
- return map;
- }
- else {
- return NULL;
- }
- }
- return iter->second;
- }
- int find_ivar_slot(VALUE klass, ID name, bool create);
- void each_ivar_slot(VALUE obj, int (*func)(ANYARGS), void *ctx);
- bool class_can_have_ivar_slots(VALUE klass);
-
struct rb_vm_outer *get_outer(Class klass);
void set_outer(Class klass, Class mod);
View
14 vm_eval.c
@@ -511,20 +511,6 @@ rb_obj_instance_eval(VALUE self, SEL sel, VALUE top, int argc, VALUE *argv)
}
else {
switch (TYPE(self)) {
-#if 0
- case T_CLASS:
- case T_MODULE:
- if (RCLASS_RUBY(self)) {
- VALUE sself = rb_make_singleton_class(RCLASS_SUPER(self));
- RCLASS_SET_SUPER(self, sself);
- self = sself;
- }
- else {
- klass = rb_singleton_class(self);
- break;
- }
- // fall through
-#endif
default:
klass = rb_singleton_class(self);
switch (TYPE(top)) {
Please sign in to comment.
Something went wrong with that request. Please try again.