void PackedObject::Info::visit(Object* obj, ObjectVisitor& visit) { PackedObject* po = reinterpret_cast<PackedObject*>(obj); size_t fields = to_fields(object_size(obj)); Object** body = po->body_as_array(); for(size_t i = 0; i < fields; i++) { visit.call(body[i]); } }
void PackedObject::Info::mark(Object* obj, ObjectMark& mark) { PackedObject* po = reinterpret_cast<PackedObject*>(obj); size_t fields = to_fields(object_size(obj)); Object** body = po->body_as_array(); for(size_t i = 0; i < fields; i++) { if(Object* tmp = mark.call(body[i])) { mark.set(obj, &body[i], tmp); } } }
Object* Class::allocate(STATE) { if(type_info_->type == PackedObject::type) { assert(packed_size_ > 0); PackedObject* obj = reinterpret_cast<PackedObject*>( state->om->new_object_fast(this, packed_size_, type_info_->type)); uintptr_t body = reinterpret_cast<uintptr_t>(obj->body_as_array()); for(size_t i = 0; i < packed_size_ - sizeof(ObjectHeader); i += sizeof(Object*)) { Object** pos = reinterpret_cast<Object**>(body + i); *pos = Qundef; } return obj; } else { return state->om->new_object_fast(this, type_info_->instance_size, type_info_->type); } }
Object* Class::allocate(STATE, CallFrame* calling_environment) { if(type_info_->type == PackedObject::type) { use_packed: assert(packed_size_ > 0); // Pull the size out into a local to deal with this moving later on. uint32_t size = packed_size_; PackedObject* obj = state->local_slab().allocate(size).as<PackedObject>(); if(likely(obj)) { obj->init_header(this, YoungObjectZone, PackedObject::type); } else { if(state->shared.om->refill_slab(state, state->local_slab())) { obj = state->local_slab().allocate(size).as<PackedObject>(); if(likely(obj)) { obj->init_header(this, YoungObjectZone, PackedObject::type); } else { obj = reinterpret_cast<PackedObject*>( state->om->new_object_fast(state, this, size, PackedObject::type)); } } else { state->shared.om->collect_young_now = true; Class* self = this; OnStack<1> os(state, self); state->collect_maybe(calling_environment); // Don't use 'this' after here! it's been moved! use 'self'! obj = state->local_slab().allocate(size).as<PackedObject>(); if(likely(obj)) { obj->init_header(self, YoungObjectZone, PackedObject::type); } else { obj = reinterpret_cast<PackedObject*>( state->om->new_object_fast(state, self, size, PackedObject::type)); } } } // Don't use 'this' !!! The above code might have GC'd uintptr_t body = reinterpret_cast<uintptr_t>(obj->body_as_array()); for(size_t i = 0; i < size - sizeof(ObjectHeader); i += sizeof(Object*)) { Object** pos = reinterpret_cast<Object**>(body + i); *pos = Qundef; } return obj; } else if(!type_info_->allow_user_allocate || kind_of<SingletonClass>(this)) { Exception::type_error(state, "direct allocation disabled"); return Qnil; } else if(type_info_->type == Object::type) { // transition all normal object classes to PackedObject auto_pack(state); goto use_packed; } // type_info_->type is neither PackedObject nor Object, so use the // generic path. return state->new_object_typed(this, type_info_->instance_size, type_info_->type); }